diff --git a/include/mcl/mapto_wb19.hpp b/include/mcl/mapto_wb19.hpp index 2663fe2..180c824 100644 --- a/include/mcl/mapto_wb19.hpp +++ b/include/mcl/mapto_wb19.hpp @@ -314,12 +314,101 @@ struct MapToG2_WB19 { if (!x.b.isZero()) return false; return false; } + /* + z = sqrt(u/v) = (uv^7) (uv^15)^((p^2-9)/16) * root4 + return true if found + */ + bool sqr_div(Fp2& z, const Fp2& u, const Fp2& v) const + { + Fp2 gamma, t1, t2; + Fp2::sqr(gamma, v); // v^2 + Fp2::sqr(t2, gamma); // v^4 + Fp2::mul(t1, u, v); // uv + t1 *= gamma; // uv^3 + t1 *= t2; // uv^7 + Fp2::sqr(t2, t2); // v^8 + t2 *= t1; + Fp2::pow(gamma, t2, sqrtConst); + gamma *= t1; + Fp2 candi; + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(root4); i++) { + Fp2::mul(candi, gamma, root4[i]); + Fp2::sqr(t1, candi); + t1 *= v; + if (t1 == u) { + z = candi; + return true; + } + } + z = gamma; + return false; + } + // https://github.com/ethereum/py_ecc + void optimized_swu_G2(Point& P, const Fp2& t) const + { + Fp2 t2, t2xi, t2xi2; + Fp2::sqr(t2, t); + mul_xi(t2xi, t2); + Fp2::sqr(t2xi2, t2xi); + Fp2 nume, deno; + // (t^2 * xi)^2 + (t^2 * xi) + Fp2::add(deno, t2xi2, t2xi); + Fp2::add(nume, deno, 1); + nume *= Ell2p_b; + if (deno.isZero()) { + Fp2::mul(deno, Ell2p_a, xi); + } else { + deno *= -Ell2p_a; + } + Fp2 u, v; + { + Fp2 deno2, tmp, tmp1, tmp2; + Fp2::sqr(deno2, deno); + Fp2::mul(v, deno2, deno); + + Fp2::mul(u, Ell2p_b, v); + Fp2::mul(tmp, Ell2p_a, nume); + tmp *= deno2; + u += tmp; + Fp2::sqr(tmp, nume); + tmp *= nume; + u += tmp; + } + Fp2 candi; + bool success = sqr_div(candi, u, v); + P.y = candi; + candi *= t2; + candi *= t; + u *= t2xi2; + u *= t2xi; + bool success2 = false; + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(etas); i++) { + Fp2 t1; + Fp2::mul(t1, etas[i], candi); + Fp2::sqr(t2, t1); + t2 *= v; + if (t2 == u && !success && !success2) { + P.y = t1; + success2 = true; + } + } + assert(success || success2); + if (!success) { + nume *= t2xi; + } + if (isNegSign(t) != isNegSign(P.y)) { + Fp2::neg(P.y, P.y); + } + P.y *= deno; + P.x = nume; + P.z = deno; + } + // https://github.com/algorand/bls_sigs_ref void osswu2_help(Point& P, const Fp2& t) const { Fp2 t2, t2xi; Fp2::sqr(t2, t); Fp2 den, den2; -// Fp2::mul(t2xi, t2, xi); mul_xi(t2xi, t2); den = t2xi; Fp2::sqr(den2, den); @@ -473,13 +562,23 @@ struct MapToG2_WB19 { add(Q, work, work2); #endif } + template + void put(const T& P) const + { + const int base = 10; + printf("x=%s\n", P.x.getStr(base).c_str()); + printf("y=%s\n", P.y.getStr(base).c_str()); + printf("z=%s\n", P.z.getStr(base).c_str()); + } void opt_swu2_map(G2& P, const Fp2& t, const Fp2 *t2 = 0) const { Point Pp; osswu2_help(Pp, t); +//put(Pp); if (t2) { Point P2; osswu2_help(P2, *t2); +//put(P2); add(Pp, Pp, P2); } iso3(P, Pp); diff --git a/test/mapto_wb19_test.cpp b/test/mapto_wb19_test.cpp index 60e1955..32ba4a0 100644 --- a/test/mapto_wb19_test.cpp +++ b/test/mapto_wb19_test.cpp @@ -1,3 +1,4 @@ +#define PUT(x) std::cout << #x "=" << (x) << std::endl; #include #include #include @@ -6,8 +7,6 @@ #include #include -#define PUT(x) std::cout << #x "=" << (x) << std::endl; - using namespace mcl; using namespace mcl::bn; @@ -172,8 +171,10 @@ void ethMsgToG2test() CYBOZU_TEST_EQUAL(out, ok); } -void test2() +template +void test2(const T& mapto) { + (void)mapto; /* testHashToBaseFP2 https://github.com/status-im/nim-blscurve/blob/de64516a5933a6e8ebb01a346430e61a201b5775/blscurve/hash_to_curve.nim#L492 @@ -219,14 +220,38 @@ void test2() { // https://media.githubusercontent.com/media/ethereum/eth2.0-spec-tests/v0.10.1/tests/general/phase0/bls/sign/small/sign_case_11b8c7cad5238946/data.yaml const char *secs = "47b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138"; - const char msg[32] = {}; + const char msg[33] = {}; const char *expect = "b2deb7c656c86cb18c43dae94b21b107595486438e0b906f3bdb29fa316d0fc3cab1fc04c6ec9879c773849f2564d39317bfa948b4a35fc8509beafd3a2575c25c077ba8bca4df06cb547fe7ca3b107d49794b7132ef3b5493a6ffb2aad2a441"; Fr sec; sec.deserializeHexStr(secs); G2 Q; Q.deserializeHexStr(expect); Q *= (1/sec); + G2 P; + const char *dst = "BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_"; +std::cout << std::hex; + ethMsgToG2(P, msg, 33, dst, strlen(dst)); + printf("P=%s\n", P.serializeToHexStr().c_str()); printf("Q=%s\n", Q.serializeToHexStr().c_str()); + mapto.put(P); + printf("equal %d\n", P == Q); +PointStr ss = { +{ + "3257676086538823567761244186080544403330427395946948635449582231233180442322077484215757257097813156392664917178234", + "228537154970146118588036771068753907531432250550232803895899422656339347346840810590265440478956079727608969412311", +}, +{ + "2211656311977487430400091470761449132135875543285725344573261083165139360734602590585740129428161178745780787382986", + "40258781102313547933704047733645277081466097003572358028270922475602169023300010845551344432311507156784289541037", +}, +{ + "3554635405737095173231135338330740471713348364117258010850826274365262386961694608537862757803628655357449929362973", + "3305133470803621861948711123350198492693369595391902116552614265910644738630055172693143208260379598437272858586799", +}, +}; + Point RR; + set(RR, ss); + mapto.put(RR); } } @@ -509,13 +534,46 @@ void testVec(const char *file) } } +template +void test3(const T& mapto) +{ + Fp2Str ts = { + "1918231859236664604157448091070531325862162392395253569013354101088957561890652491757605826252839368362075816084620", + "1765592454498940438559713185757713516213027777891663285362602185795653989012303939547547418058658378320847225866857", + }; + PointStr out1s = { + { + "3927184272261705576225284664838663573624313247854459615864888213007837227449093837336748448846489186151562481034580", + "1903293468617299241460799312855927163610998535569367868293984916087966126786510088134190993502241498025510393259948", + }, + { + "3991322739214666504999201807778913642377537002372597995520099276113880862779909709825029178857593814896063515454176", + "2999367925154329126226224834594837693635617675385117964685771461463180146028553717562548600391126160503718637741311", + }, + { + "2578853905647618145305524664579860566455691148296386065391659245709237478565628968511959291772795541098532647163712", + "3910188857576114167072883940429120413632909260968721432280195359371907407125083761682822023489835923188989938783197", + }, + }; + Fp2 t; + set(t, ts); + Point P, Q; + mapto.optimized_swu_G2(P, t); + set(Q, out1s); + CYBOZU_TEST_EQUAL(P.x, Q.x); + CYBOZU_TEST_EQUAL(P.y, Q.y); + CYBOZU_TEST_EQUAL(P.z, Q.z); +} + CYBOZU_TEST_AUTO(test) { initPairing(mcl::BLS12_381); Fp::setETHserialization(true); bn::setMapToMode(MCL_MAP_TO_MODE_WB19); const mcl::bn::local::MapToG2_WB19& mapto = BN::param.mapTo.mapToG2_WB19_; - test2(); + test3(mapto); +return; + test2(mapto); osswu2_helpTest(mapto); addTest(mapto); iso3Test(mapto);