|
|
|
@ -96,6 +96,154 @@ std::string toHexStr(const G2& P) |
|
|
|
|
return toHexStr(xy, 96); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
z = sqrt(u/v) = (uv^7) (uv^15)^((p^2-9)/16) * root4 |
|
|
|
|
return true if found |
|
|
|
|
*/ |
|
|
|
|
bool sqr_div(const MapTo& mapto, Fp2& z, const Fp2& u, const Fp2& v) |
|
|
|
|
{ |
|
|
|
|
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, mapto.sqrtConst); |
|
|
|
|
gamma *= t1; |
|
|
|
|
Fp2 candi; |
|
|
|
|
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(mapto.root4); i++) { |
|
|
|
|
Fp2::mul(candi, gamma, mapto.root4[i]); |
|
|
|
|
Fp2::sqr(t1, candi); |
|
|
|
|
t1 *= v; |
|
|
|
|
if (t1 == u) { |
|
|
|
|
z = candi; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
z = gamma; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Proj
|
|
|
|
|
void py_ecc_iso_map_G2(const MapTo& mapto, G2& Q, const Point& P) |
|
|
|
|
{ |
|
|
|
|
Fp2 zpows[3]; |
|
|
|
|
zpows[0] = P.z; |
|
|
|
|
Fp2::sqr(zpows[1], zpows[0]); |
|
|
|
|
Fp2::mul(zpows[2], zpows[1], zpows[0]); |
|
|
|
|
Fp2 mapvals[4]; |
|
|
|
|
mapto.evalPoly(mapvals[0], P.x, zpows, mapto.xnum); |
|
|
|
|
mapto.evalPoly(mapvals[1], P.x, zpows, mapto.xden); |
|
|
|
|
mapto.evalPoly(mapvals[2], P.x, zpows, mapto.ynum); |
|
|
|
|
mapto.evalPoly(mapvals[3], P.x, zpows, mapto.yden); |
|
|
|
|
mapvals[1] *= P.z; |
|
|
|
|
mapvals[2] *= P.y; |
|
|
|
|
mapvals[3] *= P.z; |
|
|
|
|
Fp2::mul(Q.z, mapvals[1], mapvals[3]); |
|
|
|
|
Fp2::mul(Q.x, mapvals[0], mapvals[3]); |
|
|
|
|
Fp2::mul(Q.y, mapvals[1], mapvals[2]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// https://github.com/ethereum/py_ecc
|
|
|
|
|
void py_ecc_optimized_swu_G2(const MapTo& mapto, Point& P, const Fp2& t) |
|
|
|
|
{ |
|
|
|
|
Fp2 t2, t2xi, t2xi2; |
|
|
|
|
Fp2::sqr(t2, t); |
|
|
|
|
mapto.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 *= Point::b_; |
|
|
|
|
if (deno.isZero()) { |
|
|
|
|
Fp2::mul(deno, Point::a_, mapto.xi); |
|
|
|
|
} else { |
|
|
|
|
deno *= -Point::a_; |
|
|
|
|
} |
|
|
|
|
Fp2 u, v; |
|
|
|
|
{ |
|
|
|
|
Fp2 deno2, tmp, tmp1, tmp2; |
|
|
|
|
Fp2::sqr(deno2, deno); |
|
|
|
|
Fp2::mul(v, deno2, deno); |
|
|
|
|
|
|
|
|
|
Fp2::mul(u, Point::b_, v); |
|
|
|
|
Fp2::mul(tmp, Point::a_, nume); |
|
|
|
|
tmp *= deno2; |
|
|
|
|
u += tmp; |
|
|
|
|
Fp2::sqr(tmp, nume); |
|
|
|
|
tmp *= nume; |
|
|
|
|
u += tmp; |
|
|
|
|
} |
|
|
|
|
Fp2 candi; |
|
|
|
|
bool success = sqr_div(mapto, 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(mapto.etas); i++) { |
|
|
|
|
Fp2 t1; |
|
|
|
|
Fp2::mul(t1, mapto.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 (mapto.isNegSign(t) != mapto.isNegSign(P.y)) { |
|
|
|
|
Fp2::neg(P.y, P.y); |
|
|
|
|
} |
|
|
|
|
P.y *= deno; |
|
|
|
|
P.x = nume; |
|
|
|
|
P.z = deno; |
|
|
|
|
} |
|
|
|
|
// Proj
|
|
|
|
|
void py_ecc_map_to_curve_G2(const MapTo& mapto, G2& out, const Fp2& t) |
|
|
|
|
{ |
|
|
|
|
Point P; |
|
|
|
|
py_ecc_optimized_swu_G2(mapto, P, t); |
|
|
|
|
py_ecc_iso_map_G2(mapto, out, P); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
in : Proj [X:Y:Z] |
|
|
|
|
out : Jacobi [A:B:C] |
|
|
|
|
[X:Y:Z] as Proj |
|
|
|
|
= (X/Z, Y/Z) as Affine |
|
|
|
|
= [X/Z:Y/Z:1] as Jacobi |
|
|
|
|
= [XZ:YZ^2:Z] as Jacobi |
|
|
|
|
*/ |
|
|
|
|
void toJacobi(G2& out, const G2& in) |
|
|
|
|
{ |
|
|
|
|
Fp2 z2; |
|
|
|
|
Fp2::sqr(z2, in.z); |
|
|
|
|
Fp2::mul(out.x, in.x, in.z); |
|
|
|
|
Fp2::mul(out.y, in.y, z2); |
|
|
|
|
out.z = in.z; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void py_ecc_hash_to_G2(const MapTo& mapto, G2& out, const void *msg, size_t msgSize, const void *dst, size_t dstSize) |
|
|
|
|
{ |
|
|
|
|
Fp2 t1, t2; |
|
|
|
|
hashToFp2(t1, msg, msgSize, 0, dst, dstSize); |
|
|
|
|
hashToFp2(t2, msg, msgSize, 1, dst, dstSize); |
|
|
|
|
G2 P1, P2; |
|
|
|
|
py_ecc_map_to_curve_G2(mapto, P1, t1); |
|
|
|
|
py_ecc_map_to_curve_G2(mapto, P2, t2); |
|
|
|
|
toJacobi(P1, P1); |
|
|
|
|
toJacobi(P2, P2); |
|
|
|
|
P1 += P2; |
|
|
|
|
mapto.clear_h2(out, P1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ethMsgToG2test(const std::string& fileName) |
|
|
|
|
{ |
|
|
|
|
const char *dst = "\x02"; |
|
|
|
@ -247,8 +395,8 @@ void py_eccTest(const T& mapto) |
|
|
|
|
Fp2 t1, t2; |
|
|
|
|
ethMsgToFp2(t1, msg, msgSize, 0, dst, dstSize); |
|
|
|
|
ethMsgToFp2(t2, msg, msgSize, 1, dst, dstSize); |
|
|
|
|
mapto.py_ecc_map_to_curve_G2(P1, t1); |
|
|
|
|
mapto.py_ecc_map_to_curve_G2(P2, t2); |
|
|
|
|
py_ecc_map_to_curve_G2(mapto, P1, t1); |
|
|
|
|
py_ecc_map_to_curve_G2(mapto, P2, t2); |
|
|
|
|
const PointStr ss = { |
|
|
|
|
{ |
|
|
|
|
"1972340536407012813644167184956896760015950618902823780657111692209122974250648595689834944711427684709284318183285", |
|
|
|
@ -263,12 +411,12 @@ void py_eccTest(const T& mapto) |
|
|
|
|
"3253481872910728113595595353980041952789112074899014850028493351493155577726278005524067083458491999010934020984031", |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
mapto.toJacobi(P1, P1); |
|
|
|
|
mapto.toJacobi(P2, P2); |
|
|
|
|
toJacobi(P1, P1); |
|
|
|
|
toJacobi(P2, P2); |
|
|
|
|
P1 += P2; |
|
|
|
|
G2 P11; |
|
|
|
|
set(P11, ss); |
|
|
|
|
mapto.toJacobi(P11, P11); |
|
|
|
|
toJacobi(P11, P11); |
|
|
|
|
CYBOZU_TEST_EQUAL(P1, P11); |
|
|
|
|
const PointStr clears = { |
|
|
|
|
{ |
|
|
|
@ -286,14 +434,14 @@ void py_eccTest(const T& mapto) |
|
|
|
|
}; |
|
|
|
|
set(P11, clears); |
|
|
|
|
mapto.clear_h2(P1, P1); |
|
|
|
|
mapto.toJacobi(P11, P11); |
|
|
|
|
toJacobi(P11, P11); |
|
|
|
|
CYBOZU_TEST_EQUAL(P1, P11); |
|
|
|
|
mapto.py_ecc_hash_to_G2(P1, msg, msgSize, dst, dstSize); |
|
|
|
|
py_ecc_hash_to_G2(mapto, P1, msg, msgSize, dst, dstSize); |
|
|
|
|
CYBOZU_TEST_EQUAL(P1, P11); |
|
|
|
|
ethMsgToG2(P1, msg, msgSize, dst, dstSize); |
|
|
|
|
CYBOZU_TEST_EQUAL(P1, P11); |
|
|
|
|
set(P11, sigs); |
|
|
|
|
mapto.toJacobi(P11, P11); |
|
|
|
|
toJacobi(P11, P11); |
|
|
|
|
P1 *= sec; |
|
|
|
|
CYBOZU_TEST_EQUAL(P1, P11); |
|
|
|
|
CYBOZU_TEST_EQUAL(P1.serializeToHexStr(), expect); |
|
|
|
@ -618,14 +766,14 @@ void py_eccTest2(const T& mapto) |
|
|
|
|
Fp2 t; |
|
|
|
|
set(t, ts); |
|
|
|
|
Point p, q; |
|
|
|
|
mapto.py_ecc_optimized_swu_G2(p, t); |
|
|
|
|
py_ecc_optimized_swu_G2(mapto, 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); |
|
|
|
|
G2 P, Q; |
|
|
|
|
set(P, out2s); |
|
|
|
|
mapto.py_ecc_map_to_curve_G2(Q, t); |
|
|
|
|
py_ecc_map_to_curve_G2(mapto, Q, t); |
|
|
|
|
CYBOZU_TEST_EQUAL(P, Q); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|