diff --git a/include/mcl/bn.hpp b/include/mcl/bn.hpp index 02f58f2..147f8bb 100644 --- a/include/mcl/bn.hpp +++ b/include/mcl/bn.hpp @@ -561,30 +561,14 @@ struct MapTo { }; typedef mcl::FixedArray NafArray; -template -void addTbl(G& Q, const G *tbl, const NafArray& naf, size_t i) -{ - if (i >= naf.size()) return; - int n = naf[i]; - if (n > 0) { - Q += tbl[(n - 1) >> 1]; - } else if (n < 0) { - Q -= tbl[(-n - 1) >> 1]; - } -} /* Software implementation of Attribute-Based Encryption: Appendixes GLV for G1 on BN/BLS12 */ -struct GLV1 { - Fp rw; // rw = 1 / w = (-1 - sqrt(-3)) / 2 - size_t rBitSize; - mpz_class v0, v1; - mpz_class B[2][2]; - mpz_class r; -private: - bool usePrecomputedTable(int curveType) + +struct GLV1 : mcl::GLV1T { + static bool usePrecomputedTable(int curveType) { if (curveType < 0) return false; const struct Tbl { @@ -619,48 +603,25 @@ private: bool b; rw.setStr(&b, tbl[i].rw, 16); if (!b) continue; rBitSize = tbl[i].rBitSize; - mcl::gmp::setStr(&b, v0, tbl[i].v0, 16); if (!b) continue; - mcl::gmp::setStr(&b, v1, tbl[i].v1, 16); if (!b) continue; - mcl::gmp::setStr(&b, B[0][0], tbl[i].B[0][0], 16); if (!b) continue; - mcl::gmp::setStr(&b, B[0][1], tbl[i].B[0][1], 16); if (!b) continue; - mcl::gmp::setStr(&b, B[1][0], tbl[i].B[1][0], 16); if (!b) continue; - mcl::gmp::setStr(&b, B[1][1], tbl[i].B[1][1], 16); if (!b) continue; - mcl::gmp::setStr(&b, r, tbl[i].r, 16); if (!b) continue; + gmp::setStr(&b, v0, tbl[i].v0, 16); if (!b) continue; + gmp::setStr(&b, v1, tbl[i].v1, 16); if (!b) continue; + gmp::setStr(&b, B[0][0], tbl[i].B[0][0], 16); if (!b) continue; + gmp::setStr(&b, B[0][1], tbl[i].B[0][1], 16); if (!b) continue; + gmp::setStr(&b, B[1][0], tbl[i].B[1][0], 16); if (!b) continue; + gmp::setStr(&b, B[1][1], tbl[i].B[1][1], 16); if (!b) continue; + gmp::setStr(&b, r, tbl[i].r, 16); if (!b) continue; return true; } return false; } -public: - bool operator==(const GLV1& rhs) const - { - return rw == rhs.rw && rBitSize == rhs.rBitSize && v0 == rhs.v0 && v1 == rhs.v1 - && B[0][0] == rhs.B[0][0] && B[0][1] == rhs.B[0][1] && B[1][0] == rhs.B[1][0] - && B[1][1] == rhs.B[1][1] && r == rhs.r; - } - bool operator!=(const GLV1& rhs) const { return !operator==(rhs); } -#ifndef CYBOZU_DONT_USE_STRING - void dump(const mpz_class& x) const - { - printf("\"%s\",\n", mcl::gmp::getStr(x, 16).c_str()); - } - void dump() const - { - printf("\"%s\",\n", rw.getStr(16).c_str()); - printf("%d,\n", (int)rBitSize); - dump(v0); - dump(v1); - dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]); - dump(r); - } -#endif - void init(const mpz_class& r, const mpz_class& z, bool isBLS12 = false, int curveType = -1) + static void initForBN(const mpz_class& _r, const mpz_class& z, bool isBLS12 = false, int curveType = -1) { if (usePrecomputedTable(curveType)) return; bool b = Fp::squareRoot(rw, -3); assert(b); (void)b; rw = -(rw + 1) / 2; - this->r = r; + r = _r; rBitSize = gmp::getBitSize(r); rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);// a little better size if (isBLS12) { @@ -690,68 +651,6 @@ public: v0 = ((-B[1][1]) << rBitSize) / r; v1 = ((B[1][0]) << rBitSize) / r; } - /* - L = lambda = p^4 - L (x, y) = (rw x, y) - */ - void mulLambda(G1& Q, const G1& P) const - { - Fp::mul(Q.x, P.x, rw); - Q.y = P.y; - Q.z = P.z; - } - /* - x = a + b * lambda mod r - */ - void split(mpz_class& a, mpz_class& b, const mpz_class& x) const - { - mpz_class t; - t = (x * v0) >> rBitSize; - b = (x * v1) >> rBitSize; - a = x - (t * B[0][0] + b * B[1][0]); - b = - (t * B[0][1] + b * B[1][1]); - } - void mul(G1& Q, const G1& P, mpz_class x, bool constTime = false) const - { - const int w = 5; - const size_t tblSize = 1 << (w - 2); - NafArray naf[2]; - mpz_class u[2]; - G1 tbl[2][tblSize]; - bool b; - - x %= r; - if (x == 0) { - Q.clear(); - if (!constTime) return; - } - if (x < 0) { - x += r; - } - split(u[0], u[1], x); - gmp::getNAFwidth(&b, naf[0], u[0], w); - assert(b); (void)b; - gmp::getNAFwidth(&b, naf[1], u[1], w); - assert(b); (void)b; - - tbl[0][0] = P; - mulLambda(tbl[1][0], tbl[0][0]); - { - G1 P2; - G1::dbl(P2, P); - for (size_t i = 1; i < tblSize; i++) { - G1::add(tbl[0][i], tbl[0][i - 1], P2); - mulLambda(tbl[1][i], tbl[0][i]); - } - } - const size_t maxBit = fp::max_(naf[0].size(), naf[1].size()); - Q.clear(); - for (size_t i = 0; i < maxBit; i++) { - G1::dbl(Q, Q); - addTbl(Q, tbl[0], naf[0], maxBit - 1 - i); - addTbl(Q, tbl[1], naf[1], maxBit - 1 - i); - } - } }; /* @@ -772,7 +671,7 @@ struct GLV2 { this->z = z; this->abs_z = z < 0 ? -z : z; this->isBLS12 = isBLS12; - rBitSize = mcl::gmp::getBitSize(r); + rBitSize = gmp::getBitSize(r); rBitSize = (rBitSize + mcl::fp::UnitBitSize - 1) & ~(mcl::fp::UnitBitSize - 1);// a little better size mpz_class z2p1 = z * 2 + 1; B[0][0] = z + 1; @@ -859,7 +758,6 @@ struct GLV2 { template void mul(T& Q, const T& P, mpz_class x, bool constTime = false) const { -#if 1 const int w = 5; const size_t tblSize = 1 << (w - 2); const size_t splitN = 4; @@ -902,120 +800,11 @@ struct GLV2 { Q.clear(); for (size_t i = 0; i < maxBit; i++) { T::dbl(Q, Q); - addTbl(Q, tbl[0], naf[0], maxBit - 1 - i); - addTbl(Q, tbl[1], naf[1], maxBit - 1 - i); - addTbl(Q, tbl[2], naf[2], maxBit - 1 - i); - addTbl(Q, tbl[3], naf[3], maxBit - 1 - i); - } -#else -#if 0 // #ifndef NDEBUG - { - T R; - T::mulGeneric(R, P, r); - assert(R.isZero()); - } -#endif - typedef mcl::fp::Unit Unit; - const size_t maxUnit = 512 / 2 / mcl::fp::UnitBitSize; - const int splitN = 4; - mpz_class u[splitN]; - T in[splitN]; - T tbl[16]; - int bitTbl[splitN]; // bit size of u[i] - Unit w[splitN][maxUnit]; // unit array of u[i] - int maxBit = 0; // max bit of u[i] - int maxN = 0; - int remainBit = 0; - - x %= r; - if (x == 0) { - Q.clear(); - if (constTime) goto DummyLoop; - return; - } - if (x < 0) { - x += r; - } - split(u, x); - in[0] = P; - Frobenius(in[1], in[0]); - Frobenius(in[2], in[1]); - Frobenius(in[3], in[2]); - for (int i = 0; i < splitN; i++) { - if (u[i] < 0) { - u[i] = -u[i]; - T::neg(in[i], in[i]); - } -// in[i].normalize(); // slow - } -#if 0 - for (int i = 0; i < splitN; i++) { - T::mulGeneric(in[i], in[i], u[i]); + mcl::local::addTbl(Q, tbl[0], naf[0], maxBit - 1 - i); + mcl::local::addTbl(Q, tbl[1], naf[1], maxBit - 1 - i); + mcl::local::addTbl(Q, tbl[2], naf[2], maxBit - 1 - i); + mcl::local::addTbl(Q, tbl[3], naf[3], maxBit - 1 - i); } - T::add(Q, in[0], in[1]); - Q += in[2]; - Q += in[3]; - return; -#else - tbl[0] = in[0]; - for (size_t i = 1; i < 16; i++) { - tbl[i].clear(); - if (i & 1) { - tbl[i] += in[0]; - } - if (i & 2) { - tbl[i] += in[1]; - } - if (i & 4) { - tbl[i] += in[2]; - } - if (i & 8) { - tbl[i] += in[3]; - } -// tbl[i].normalize(); - } - for (int i = 0; i < splitN; i++) { - bool b; - mcl::gmp::getArray(&b, w[i], maxUnit, u[i]); - assert(b); - bitTbl[i] = (int)mcl::gmp::getBitSize(u[i]); - maxBit = fp::max_(maxBit, bitTbl[i]); - } - maxBit--; - /* - maxBit = maxN * UnitBitSize + remainBit - 0 < remainBit <= UnitBitSize - */ - maxN = maxBit / mcl::fp::UnitBitSize; - remainBit = maxBit % mcl::fp::UnitBitSize; - remainBit++; - Q.clear(); - for (int i = maxN; i >= 0; i--) { - for (int j = remainBit - 1; j >= 0; j--) { - T::dbl(Q, Q); - uint32_t b0 = (w[0][i] >> j) & 1; - uint32_t b1 = (w[1][i] >> j) & 1; - uint32_t b2 = (w[2][i] >> j) & 1; - uint32_t b3 = (w[3][i] >> j) & 1; - uint32_t c = b3 * 8 + b2 * 4 + b1 * 2 + b0; - if (c == 0) { - if (constTime) tbl[0] += tbl[1]; - } else { - Q += tbl[c]; - } - } - remainBit = (int)mcl::fp::UnitBitSize; - } -#endif - DummyLoop: - if (!constTime) return; - const int limitBit = (int)rBitSize / splitN; - T D = tbl[0]; - for (int i = maxBit + 1; i < limitBit; i++) { - T::dbl(D, D); - D += tbl[0]; - } -#endif } void pow(Fp12& z, const Fp12& x, mpz_class y, bool constTime = false) const { @@ -1035,7 +824,6 @@ struct Param { mpz_class p; mpz_class r; local::MapTo mapTo; - local::GLV1 glv1; local::GLV2 glv2; // for G2 Frobenius Fp2 g2; @@ -1151,7 +939,7 @@ struct Param { } else { mapTo.init(2 * p - r, z, cp.curveType); } - glv1.init(r, z, isBLS12, cp.curveType); + GLV1::initForBN(r, z, isBLS12, cp.curveType); glv2.init(r, z, isBLS12); basePoint.clear(); *pb = true; @@ -1200,15 +988,6 @@ static const local::Param& param = local::StaticVar<>::param; namespace local { -inline void mulArrayGLV1(G1& z, const G1& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime) -{ - mpz_class s; - bool b; - mcl::gmp::setArray(&b, s, y, yn); - assert(b); - if (isNegative) s = -s; - BN::param.glv1.mul(z, x, s, constTime); -} inline void mulArrayGLV2(G2& z, const G2& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime) { mpz_class s; @@ -2227,7 +2006,7 @@ inline void init(bool *pb, const mcl::CurveParam& cp = mcl::BN254, fp::Mode mode { local::StaticVar<>::param.init(pb, cp, mode); if (!*pb) return; - G1::setMulArrayGLV(local::mulArrayGLV1); + G1::setMulArrayGLV(local::GLV1::mulArray); G2::setMulArrayGLV(local::mulArrayGLV2); Fp12::setPowArrayGLV(local::powArrayGLV2); G1::setCompressedExpression(); diff --git a/include/mcl/ec.hpp b/include/mcl/ec.hpp index ad6e6db..1d0ad49 100644 --- a/include/mcl/ec.hpp +++ b/include/mcl/ec.hpp @@ -1068,6 +1068,149 @@ template void (*EcT::mulArrayGLV)(EcT& z, const EcT& x, const fp:: template int EcT::mode_; #endif +namespace local { + +template +void addTbl(Ec& Q, const Ec *tbl, const Vec& naf, size_t i) +{ + if (i >= naf.size()) return; + int n = naf[i]; + if (n > 0) { + Q += tbl[(n - 1) >> 1]; + } else if (n < 0) { + Q -= tbl[(-n - 1) >> 1]; + } +} + +} // mcl::local + +template +struct GLV1T { + typedef typename Ec::Fp Fp; + static Fp rw; // rw = 1 / w = (-1 - sqrt(-3)) / 2 + static size_t rBitSize; + static mpz_class v0, v1; + static mpz_class B[2][2]; + static mpz_class r; +public: +#ifndef CYBOZU_DONT_USE_STRING + static void dump(const mpz_class& x) + { + printf("\"%s\",\n", mcl::gmp::getStr(x, 16).c_str()); + } + static void dump() + { + printf("\"%s\",\n", rw.getStr(16).c_str()); + printf("%d,\n", (int)rBitSize); + dump(v0); + dump(v1); + dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]); + dump(r); + } +#endif + /* + L (x, y) = (rw x, y) + */ + static void mulLambda(Ec& Q, const Ec& P) + { + Fp::mul(Q.x, P.x, rw); + Q.y = P.y; + Q.z = P.z; + } + /* + x = a + b * lambda mod r + */ + static void split(mpz_class& a, mpz_class& b, const mpz_class& x) + { + mpz_class t; + t = (x * v0) >> rBitSize; + b = (x * v1) >> rBitSize; + a = x - (t * B[0][0] + b * B[1][0]); + b = - (t * B[0][1] + b * B[1][1]); + } + static void mul(Ec& Q, const Ec& P, mpz_class x, bool constTime = false) + { + const int w = 5; + const size_t tblSize = 1 << (w - 2); + typedef mcl::FixedArray NafArray; + NafArray naf[2]; + mpz_class u[2]; + Ec tbl[2][tblSize]; + bool b; + + x %= r; + if (x == 0) { + Q.clear(); + if (!constTime) return; + } + if (x < 0) { + x += r; + } + split(u[0], u[1], x); + gmp::getNAFwidth(&b, naf[0], u[0], w); + assert(b); (void)b; + gmp::getNAFwidth(&b, naf[1], u[1], w); + assert(b); (void)b; + + tbl[0][0] = P; + mulLambda(tbl[1][0], tbl[0][0]); + { + Ec P2; + Ec::dbl(P2, P); + for (size_t i = 1; i < tblSize; i++) { + Ec::add(tbl[0][i], tbl[0][i - 1], P2); + mulLambda(tbl[1][i], tbl[0][i]); + } + } + const size_t maxBit = fp::max_(naf[0].size(), naf[1].size()); + Q.clear(); + for (size_t i = 0; i < maxBit; i++) { + Ec::dbl(Q, Q); + local::addTbl(Q, tbl[0], naf[0], maxBit - 1 - i); + local::addTbl(Q, tbl[1], naf[1], maxBit - 1 - i); + } + } + static void mulArray(Ec& z, const Ec& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime) + { + mpz_class s; + bool b; + mcl::gmp::setArray(&b, s, y, yn); + assert(b); + if (isNegative) s = -s; + mul(z, x, s, constTime); + } + /* + initForBN() is defined in bn.hpp + */ + static void initForSecp256k1(const mpz_class& _r) + { + bool b = Fp::squareRoot(rw, -3); + assert(b); + (void)b; + rw = -(rw + 1) / 2; + r = _r; + rBitSize = gmp::getBitSize(r); + rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1); + gmp::setStr(&b, B[0][0], "0x3086d221a7d46bcde86c90e49284eb15"); + assert(b); (void)b; + gmp::setStr(&b, B[0][1], "-0xe4437ed6010e88286f547fa90abfe4c3"); + assert(b); (void)b; + gmp::setStr(&b, B[1][0], "0x114ca50f7a8e2f3f657c1108d9d44cfd8"); + assert(b); (void)b; + B[1][1] = B[0][0]; + v0 = ((B[1][1]) << rBitSize) / r; + v1 = ((-B[0][1]) << rBitSize) / r; + } +}; + +// rw = 1 / w = (-1 - sqrt(-3)) / 2 +template typename Ec::Fp GLV1T::rw; +template size_t GLV1T::rBitSize; +template mpz_class GLV1T::v0; +template mpz_class GLV1T::v1; +template mpz_class GLV1T::B[2][2]; +template mpz_class GLV1T::r; + struct EcParam { const char *name; const char *p; diff --git a/include/mcl/ecdsa.hpp b/include/mcl/ecdsa.hpp index cf3ed3f..6540c19 100644 --- a/include/mcl/ecdsa.hpp +++ b/include/mcl/ecdsa.hpp @@ -99,6 +99,8 @@ inline void init(bool *pb) p.P.set(pb, x, y); if (!*pb) return; p.Pbase.init(pb, p.P, ecParam.bitSize, local::winSize); + mcl::GLV1T::initForSecp256k1(Zn::getOp().mp); + Ec::setMulArrayGLV(mcl::GLV1T::mulArray); } #ifndef CYBOZU_DONT_USE_EXCEPTION diff --git a/include/mcl/gmp_util.hpp b/include/mcl/gmp_util.hpp index 0eeeb9c..42ec6a7 100644 --- a/include/mcl/gmp_util.hpp +++ b/include/mcl/gmp_util.hpp @@ -642,7 +642,7 @@ void getNAFwidth(bool *pb, Vec& naf, mpz_class x, size_t w) x++; v -= maxW; } - naf.push(pb, Vec::value_type(v)); + naf.push(pb, typename Vec::value_type(v)); if (!*pb) return; zeroNum = w - 1; } diff --git a/include/mcl/op.hpp b/include/mcl/op.hpp index c31b7d1..a8b47e5 100644 --- a/include/mcl/op.hpp +++ b/include/mcl/op.hpp @@ -23,7 +23,7 @@ namespace mcl { -static const int version = 0x095; /* 0xABC = A.BC */ +static const int version = 0x096; /* 0xABC = A.BC */ /* specifies available string format mode for X::setIoMode() diff --git a/include/mcl/she.hpp b/include/mcl/she.hpp index 282f2fe..84f3e55 100644 --- a/include/mcl/she.hpp +++ b/include/mcl/she.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace mcl { namespace she { @@ -588,6 +589,10 @@ public: useDecG2ViaGT_ = false; isG1only_ = true; setTryNum(tryNum); + if (std::string(para.name) == mcl::ecparam::secp256k1.name) { + mcl::GLV1T::initForSecp256k1(Fr::getOp().mp); + G1::setMulArrayGLV(mcl::GLV1T::mulArray); + } } /* set range for G1-DLP diff --git a/readme.md b/readme.md index 40ae5a8..0510f1f 100644 --- a/readme.md +++ b/readme.md @@ -10,6 +10,7 @@ mcl is a library for pairing-based cryptography. The current version supports the optimal Ate pairing over BN curves and BLS12-381 curves. # News +* v0.96 improved scalar multiplication * mclBn_setETHserialization(true) (de)serialize acoording to [ETH2.0 serialization of BLS12-381](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/bls_signature.md#point-representations) when BLS12-381 is used. * (Break backward compatibility) libmcl_dy.a is renamed to libmcl.a * The option SHARE_BASENAME_SUF is removed diff --git a/test/ecdsa_test.cpp b/test/ecdsa_test.cpp index 332c9ee..80de88a 100644 --- a/test/ecdsa_test.cpp +++ b/test/ecdsa_test.cpp @@ -1,4 +1,4 @@ -#define PUT(x) std::cout << #x "=" << x << std::endl; +#define PUT(x) std::cout << #x "=" << (x) << std::endl; #include #include void put(const void *buf, size_t bufSize) diff --git a/test/glv_test.cpp b/test/glv_test.cpp index 0e6fccd..61f2062 100644 --- a/test/glv_test.cpp +++ b/test/glv_test.cpp @@ -77,7 +77,7 @@ struct oldGLV { }; template -void compareLength(const GLV1& rhs, const GLV2& lhs) +void compareLength(const GLV2& lhs) { cybozu::XorShift rg; int lt = 0; @@ -88,7 +88,7 @@ void compareLength(const GLV1& rhs, const GLV2& lhs) for (int i = 1; i < 1000; i++) { r.setRand(rg); x = r.getMpz(); - rhs.split(R0, R1, x); + mcl::bn::local::GLV1::split(R0, R1, x); lhs.split(L0, L1, x); size_t R0n = mcl::gmp::getBitSize(R0); @@ -121,10 +121,10 @@ void testGLV1() oldGlv.init(BN::param.r, BN::param.z); } - mcl::bn::local::GLV1 glv; - glv.init(BN::param.r, BN::param.z, BN::param.isBLS12); + typedef mcl::bn::local::GLV1 GLV1; + GLV1::initForBN(BN::param.r, BN::param.z, BN::param.isBLS12); if (!BN::param.isBLS12) { - compareLength(glv, oldGlv); + compareLength(oldGlv); } for (int i = 1; i < 100; i++) { @@ -133,9 +133,9 @@ void testGLV1() s.setRand(rg); mpz_class ss = s.getMpz(); G1::mulGeneric(P1, P0, ss); - glv.mul(P2, P0, ss); + GLV1::mul(P2, P0, ss); CYBOZU_TEST_EQUAL(P1, P2); - glv.mul(P2, P0, ss, true); + GLV1::mul(P2, P0, ss, true); CYBOZU_TEST_EQUAL(P1, P2); if (!BN::param.isBLS12) { oldGlv.mul(P2, P0, ss); @@ -145,15 +145,15 @@ void testGLV1() for (int i = -100; i < 100; i++) { mpz_class ss = i; G1::mulGeneric(P1, P0, ss); - glv.mul(P2, P0, ss); + GLV1::mul(P2, P0, ss); CYBOZU_TEST_EQUAL(P1, P2); - glv.mul(P2, P0, ss, true); + GLV1::mul(P2, P0, ss, true); CYBOZU_TEST_EQUAL(P1, P2); } Fr s; mapToG1(P0, 123); CYBOZU_BENCH_C("Ec::mul", 100, P1 = P0; s.setRand(rg); G1::mulGeneric, P2, P1, s.getMpz()); - CYBOZU_BENCH_C("Ec::glv", 100, P1 = P0; s.setRand(rg); glv.mul, P2, P1, s.getMpz()); + CYBOZU_BENCH_C("Ec::glv", 100, P1 = P0; s.setRand(rg); GLV1::mul, P2, P1, s.getMpz()); } /* diff --git a/test/she_test.cpp b/test/she_test.cpp index cb64478..0782eda 100644 --- a/test/she_test.cpp +++ b/test/she_test.cpp @@ -716,8 +716,9 @@ CYBOZU_TEST_AUTO(hashBench) CYBOZU_TEST_AUTO(liftedElGamal) { const size_t hashSize = 1024; - initG1only(mcl::ecparam::secp192k1, hashSize); - const size_t byteSize = 192 / 8; + const mcl::EcParam& param = mcl::ecparam::secp256k1; + initG1only(param, hashSize); + const size_t byteSize = (param.bitSize + 7) / 8; SecretKey sec; sec.setByCSPRNG(); PublicKey pub;