From afb1c812f1133edfeb8466dee6bcb01c8001e1f7 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Fri, 13 Sep 2019 11:30:54 +0900 Subject: [PATCH] support mulVec --- include/mcl/bn.hpp | 111 +++++++++++++++++++++++----- include/mcl/ec.hpp | 151 ++++++++++++++++++++------------------- include/mcl/gmp_util.hpp | 4 +- include/mcl/operator.hpp | 22 +++++- include/mcl/util.hpp | 57 ++++++++++++++- test/bls12_test.cpp | 2 +- test/bn384_test.cpp | 2 +- test/bn512_test.cpp | 2 +- test/bn_test.cpp | 2 +- test/common_test.hpp | 75 ++++++++++++++++--- test/ec_test.cpp | 6 +- test/fp_util_test.cpp | 42 +++++++++++ test/glv_test.cpp | 6 +- test/she_test.cpp | 2 +- 14 files changed, 370 insertions(+), 114 deletions(-) diff --git a/include/mcl/bn.hpp b/include/mcl/bn.hpp index 3a4489a..461eb19 100644 --- a/include/mcl/bn.hpp +++ b/include/mcl/bn.hpp @@ -560,14 +560,13 @@ struct MapTo { } }; -typedef mcl::FixedArray NafArray; /* Software implementation of Attribute-Based Encryption: Appendixes GLV for G1 on BN/BLS12 */ -struct GLV1 : mcl::GLV1T { +struct GLV1 : mcl::GLV1T { static bool usePrecomputedTable(int curveType) { if (curveType < 0) return false; @@ -577,7 +576,6 @@ struct GLV1 : mcl::GLV1T { size_t rBitSize; const char *v0, *v1; const char *B[2][2]; - const char *r; } tbl[] = { { MCL_BN254, @@ -595,7 +593,6 @@ struct GLV1 : mcl::GLV1T { "-61818000000000020400000000000003", }, }, - "2523648240000001ba344d8000000007ff9f800000000010a10000000000000d", }, }; for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { @@ -609,20 +606,18 @@ struct GLV1 : mcl::GLV1T { 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; } - static void initForBN(const mpz_class& _r, const mpz_class& z, bool isBLS12 = false, int curveType = -1) + static void initForBN(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; - r = _r; - rBitSize = gmp::getBitSize(r); + rBitSize = Fr::getOp().bitSize; rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);// a little better size if (isBLS12) { /* @@ -648,6 +643,7 @@ struct GLV1 : mcl::GLV1T { B[1][1] = -6 * z * z - 4 * z - 1; } // [v0 v1] = [r 0] * B^(-1) + const mpz_class& r = Fr::getOp().mp; v0 = ((-B[1][1]) << rBitSize) / r; v1 = ((B[1][0]) << rBitSize) / r; } @@ -656,22 +652,24 @@ struct GLV1 : mcl::GLV1T { /* GLV method for G2 and GT on BN/BLS12 */ +template struct GLV2 { + typedef _Fr Fr; + typedef mcl::FixedArray NafArray; size_t rBitSize; mpz_class B[4][4]; - mpz_class r; mpz_class v[4]; mpz_class z; mpz_class abs_z; bool isBLS12; GLV2() : rBitSize(0), isBLS12(false) {} - void init(const mpz_class& r, const mpz_class& z, bool isBLS12 = false) + void init(const mpz_class& z, bool isBLS12 = false) { - this->r = r; + const mpz_class& r = Fr::getOp().mp; this->z = z; this->abs_z = z < 0 ? -z : z; this->isBLS12 = isBLS12; - rBitSize = gmp::getBitSize(r); + rBitSize = Fr::getOp().bitSize; 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; @@ -758,6 +756,11 @@ struct GLV2 { template void mul(T& Q, const T& P, mpz_class x, bool constTime = false) const { +#if 1 + (void)constTime; + mulVecNGLV(Q, &P, &x, 1); +#else + const mpz_class& r = Fr::getOp().mp; const int w = 5; const size_t tblSize = 1 << (w - 2); const size_t splitN = 4; @@ -805,8 +808,65 @@ struct GLV2 { mcl::local::addTbl(Q, tbl[2], naf[2], maxBit - 1 - i); mcl::local::addTbl(Q, tbl[3], naf[3], maxBit - 1 - i); } +#endif } - void pow(Fp12& z, const Fp12& x, mpz_class y, bool constTime = false) const + template + size_t mulVecNGLV(T& z, const T *xVec, const mpz_class *yVec, size_t n) const + { + const mpz_class& r = Fr::getOp().mp; + const size_t N = 16; + if (n > N) n = N; + const int w = 5; + const size_t tblSize = 1 << (w - 2); + const int splitN = 4; + NafArray naf[N][splitN]; + T tbl[N][splitN][tblSize]; + bool b; + mpz_class u[splitN], y; + size_t maxBit = 0; + + for (size_t i = 0; i < n; i++) { + y = yVec[i]; + y %= r; + if (y < 0) { + y += r; + } + split(u, y); + + for (int j = 0; j < splitN; j++) { + gmp::getNAFwidth(&b, naf[i][j], u[j], w); + assert(b); (void)b; + if (naf[i][j].size() > maxBit) maxBit = naf[i][j].size(); + } + + T P2; + T::dbl(P2, xVec[i]); + tbl[i][0][0] = xVec[i]; + Frobenius(tbl[i][1][0], tbl[i][0][0]); + Frobenius(tbl[i][2][0], tbl[i][1][0]); + Frobenius(tbl[i][3][0], tbl[i][2][0]); + for (size_t j = 1; j < tblSize; j++) { + T::add(tbl[i][0][j], tbl[i][0][j - 1], P2); + Frobenius(tbl[i][1][j], tbl[i][0][j]); + Frobenius(tbl[i][2][j], tbl[i][1][j]); + Frobenius(tbl[i][3][j], tbl[i][2][j]); + } + } + z.clear(); + for (size_t i = 0; i < maxBit; i++) { + const size_t bit = maxBit - 1 - i; + T::dbl(z, z); + for (size_t j = 0; j < n; j++) { + mcl::local::addTbl(z, tbl[j][0], naf[j][0], bit); + mcl::local::addTbl(z, tbl[j][1], naf[j][1], bit); + mcl::local::addTbl(z, tbl[j][2], naf[j][2], bit); + mcl::local::addTbl(z, tbl[j][3], naf[j][3], bit); + } + } + return n; + + } + void pow(Fp12& z, const Fp12& x, const mpz_class& y, bool constTime = false) const { typedef GroupMtoA AG; // as additive group AG& _z = static_cast(z); @@ -824,7 +884,7 @@ struct Param { mpz_class p; mpz_class r; local::MapTo mapTo; - local::GLV2 glv2; + local::GLV2 glv2; // for G2 Frobenius Fp2 g2; Fp2 g3; @@ -939,8 +999,8 @@ struct Param { } else { mapTo.init(2 * p - r, z, cp.curveType); } - GLV1::initForBN(r, z, isBLS12, cp.curveType); - glv2.init(r, z, isBLS12); + GLV1::initForBN(z, isBLS12, cp.curveType); + glv2.init(z, isBLS12); basePoint.clear(); *pb = true; } @@ -1007,6 +1067,19 @@ inline void powArrayGLV2(Fp12& z, const Fp12& x, const mcl::fp::Unit *y, size_t BN::param.glv2.pow(z, x, s, constTime); } +inline size_t mulVecNGLV2(G2& z, const G2 *xVec, const mpz_class *yVec, size_t n) +{ + return BN::param.glv2.mulVecNGLV(z, xVec, yVec, n); +} + +inline size_t powVecNGLV2(Fp12& z, const Fp12 *xVec, const mpz_class *yVec, size_t n) +{ + typedef GroupMtoA AG; // as additive group + AG& _z = static_cast(z); + const AG *_xVec = static_cast(xVec); + return BN::param.glv2.mulVecNGLV(_z, _xVec, yVec, n); +} + /* Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions Robert Granger, Michael Scott @@ -2099,9 +2172,9 @@ 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::GLV1::mulArrayGLV); - G2::setMulArrayGLV(local::mulArrayGLV2); - Fp12::setPowArrayGLV(local::powArrayGLV2); + G1::setMulArrayGLV(local::GLV1::mulArrayGLV, local::GLV1::mulVecNGLV); + G2::setMulArrayGLV(local::mulArrayGLV2, local::mulVecNGLV2); + Fp12::setPowArrayGLV(local::powArrayGLV2, local::powVecNGLV2); G1::setCompressedExpression(); G2::setCompressedExpression(); *pb = true; diff --git a/include/mcl/ec.hpp b/include/mcl/ec.hpp index 7a64868..4adc9ec 100644 --- a/include/mcl/ec.hpp +++ b/include/mcl/ec.hpp @@ -30,6 +30,9 @@ enum Mode { namespace local { +const size_t maxMulVecN = 32; // inner loop of mulVec +const size_t maxMulVecNGLV = 16; // inner loop of mulVec with GLV + // x is negative <=> x < half(:=(p+1)/2) <=> a = 1 template bool get_a_flag(const Fp& x) @@ -98,6 +101,7 @@ public: static bool verifyOrder_; static mpz_class order_; static void (*mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime); + static size_t (*mulVecNGLV)(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t yn); /* default constructor is undefined value */ EcT() {} EcT(const Fp& _x, const Fp& _y) @@ -211,6 +215,7 @@ public: verifyOrder_ = false; order_ = 0; mulArrayGLV = 0; + mulVecNGLV = 0; #ifdef MCL_EC_USE_AFFINE cybozu::disable_warning_unused_variable(mode); #else @@ -232,9 +237,10 @@ public: // don't clear order_ because it is used for isValidOrder() } } - static void setMulArrayGLV(void f(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime)) + static void setMulArrayGLV(void f(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime), size_t g(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t yn) = 0) { mulArrayGLV = f; + mulVecNGLV = g; } static inline void init(bool *pb, const char *astr, const char *bstr, int mode = ec::Jacobi) { @@ -1001,10 +1007,11 @@ public: static inline void mulArray(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime = false, bool useGLV = true) { if (!constTime) { - while (yn > 0) { - if (y[yn - 1]) break; - yn--; + if (yn == 0) { + z.clear(); + return; } + yn = fp::getNonZeroArraySize(y, yn); if (yn <= 1 && mulSmallInt(z, x, *y, isNegative)) return; } if (useGLV && mulArrayGLV && (yn * sizeof(fp::Unit) > 8)) { @@ -1136,12 +1143,12 @@ public: } static inline void mulArrayBase(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime) { -#if 1 (void)constTime; mpz_class v; bool b; gmp::setArray(&b, v, y, yn); assert(b); (void)b; + if (isNegative) v = -v; const int maxW = 5; const int maxTblSize = 1 << (maxW - 2); /* @@ -1165,22 +1172,6 @@ public: EcT::dbl(z, z); local::addTbl(z, tbl, naf, naf.size() - 1 - i); } - if (isNegative) { - neg(z, z); - } -#else - EcT tmp; - const EcT *px = &x; - if (&z == &x) { - tmp = x; - px = &tmp; - } - z.clear(); - fp::powGeneric(z, *px, y, yn, EcT::add, EcT::dbl, EcT::normalize, constTime ? Fp::BaseFp::getBitSize() : 0); - if (isNegative) { - neg(z, z); - } -#endif } /* generic mul @@ -1196,19 +1187,19 @@ public: @note &z != xVec[i] */ private: - templateclass FpT> - static inline size_t addMulVecN(EcT& z, const EcT *xVec, const FpT *yVec, size_t n) + static inline size_t mulVecN(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t n) { + const size_t N = mcl::ec::local::maxMulVecN; if (n > N) n = N; const int w = 5; const size_t tblSize = 1 << (w - 2); - typedef mcl::FixedArray NafArray; + typedef mcl::FixedArray NafArray; NafArray naf[N]; EcT tbl[N][tblSize]; size_t maxBit = 0; for (size_t i = 0; i < n; i++) { bool b; - gmp::getNAFwidth(&b, naf[i], yVec[i].getMpz(), w); + gmp::getNAFwidth(&b, naf[i], yVec[i], w); assert(b); (void)b; if (naf[i].size() > maxBit) maxBit = naf[i].size(); EcT P2; @@ -1229,14 +1220,22 @@ private: } public: - templateclass FpT> - static inline void mulVec(EcT& z, const EcT *xVec, const FpT *yVec, size_t n) + static inline void mulVec(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t n) { + size_t (*f)(EcT&, const EcT *, const mpz_class *, size_t n) = mulVecN; + /* + mulVecNGLV is a little slow for large n + */ + if (mulVecNGLV && n < mcl::ec::local::maxMulVecNGLV) { + size_t done = mulVecNGLV(z, xVec, yVec, n); + assert(done == n); (void)done; + return; + } EcT r; r.clear(); while (n > 0) { EcT t; - size_t done = addMulVecN<32>(t, xVec, yVec, n); + size_t done = f(t, xVec, yVec, n); r += t; xVec += done; yVec += done; @@ -1298,18 +1297,20 @@ template int EcT::ioMode_; template bool EcT::verifyOrder_; template mpz_class EcT::order_; template void (*EcT::mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime); +template size_t (*EcT::mulVecNGLV)(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t yn); #ifndef MCL_EC_USE_AFFINE template int EcT::mode_; #endif -template +// r = the order of Ec +template struct GLV1T { typedef typename Ec::Fp Fp; + typedef _Fr Fr; 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) @@ -1323,7 +1324,6 @@ public: dump(v0); dump(v1); dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]); - dump(r); } #endif /* @@ -1346,47 +1346,55 @@ public: 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) + static void mul(Ec& Q, const Ec& P, const mpz_class& x, bool /*constTime*/ = false) { + mulVecNGLV(Q, &P, &x, 1); + } + static inline size_t mulVecNGLV(Ec& z, const Ec *xVec, const mpz_class *yVec, size_t n) + { + const size_t N = mcl::ec::local::maxMulVecNGLV; + if (n > N) n = N; const int w = 5; + const mpz_class& r = Fr::getOp().mp; const size_t tblSize = 1 << (w - 2); - typedef mcl::FixedArray NafArray; - NafArray naf[2]; - mpz_class u[2]; - Ec tbl[2][tblSize]; + typedef mcl::FixedArray NafArray; + NafArray naf[N][2]; + Ec tbl[N][2][tblSize]; bool b; + mpz_class u[2], y; + size_t maxBit = 0; + for (size_t i = 0; i < n; i++) { + y = yVec[i]; + y %= r; + if (y < 0) { + y += r; + } + split(u[0], u[1], y); - 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; + for (int j = 0; j < 2; j++) { + gmp::getNAFwidth(&b, naf[i][j], u[j], w); + assert(b); (void)b; + if (naf[i][j].size() > maxBit) maxBit = naf[i][j].size(); + } - 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]); + Ec::dbl(P2, xVec[i]); + tbl[i][0][0] = xVec[i]; + mulLambda(tbl[i][1][0], tbl[i][0][0]); + for (size_t j = 1; j < tblSize; j++) { + Ec::add(tbl[i][0][j], tbl[i][0][j - 1], P2); + mulLambda(tbl[i][1][j], tbl[i][0][j]); } } - const size_t maxBit = fp::max_(naf[0].size(), naf[1].size()); - Q.clear(); + z.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); + Ec::dbl(z, z); + for (size_t j = 0; j < n; j++) { + local::addTbl(z, tbl[j][0], naf[j][0], maxBit - 1 - i); + local::addTbl(z, tbl[j][1], naf[j][1], maxBit - 1 - i); + } } + return n; } static void mulArrayGLV(Ec& z, const Ec& x, const mcl::fp::Unit *y, size_t yn, bool isNegative, bool constTime) { @@ -1400,14 +1408,13 @@ public: /* initForBN() is defined in bn.hpp */ - static void initForSecp256k1(const mpz_class& _r) + static void initForSecp256k1() { bool b = Fp::squareRoot(rw, -3); assert(b); (void)b; rw = -(rw + 1) / 2; - r = _r; - rBitSize = gmp::getBitSize(r); + rBitSize = Fr::getOp().bitSize; rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1); gmp::setStr(&b, B[0][0], "0x3086d221a7d46bcde86c90e49284eb15"); assert(b); (void)b; @@ -1416,18 +1423,18 @@ public: gmp::setStr(&b, B[1][0], "0x114ca50f7a8e2f3f657c1108d9d44cfd8"); assert(b); (void)b; B[1][1] = B[0][0]; + const mpz_class& r = Fr::getOp().mp; 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; +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]; /* Ec : elliptic curve @@ -1458,8 +1465,8 @@ void initCurve(bool *pb, int curveType, Ec *P = 0, mcl::fp::Mode mode = fp::FP_A if (!*pb) return; } if (curveType == MCL_SECP256K1) { - GLV1T::initForSecp256k1(Zn::getOp().mp); - Ec::setMulArrayGLV(GLV1T::mulArrayGLV); + GLV1T::initForSecp256k1(); + Ec::setMulArrayGLV(GLV1T::mulArrayGLV, GLV1T::mulVecNGLV); } else { Ec::setMulArrayGLV(0); } diff --git a/include/mcl/gmp_util.hpp b/include/mcl/gmp_util.hpp index 42ec6a7..2c7938d 100644 --- a/include/mcl/gmp_util.hpp +++ b/include/mcl/gmp_util.hpp @@ -615,13 +615,14 @@ template void getNAFwidth(bool *pb, Vec& naf, mpz_class x, size_t w) { assert(w > 0); + *pb = true; naf.clear(); - size_t zeroNum = 0; bool negative = false; if (x < 0) { negative = true; x = -x; } + size_t zeroNum = 0; const int signedMaxW = 1 << (w - 1); const int maxW = signedMaxW * 2; const int maskW = maxW - 1; @@ -651,7 +652,6 @@ void getNAFwidth(bool *pb, Vec& naf, mpz_class x, size_t w) naf[i] = -naf[i]; } } - *pb = true; } #ifndef CYBOZU_DONT_USE_EXCEPTION diff --git a/include/mcl/operator.hpp b/include/mcl/operator.hpp index e9bc506..7a1a02c 100644 --- a/include/mcl/operator.hpp +++ b/include/mcl/operator.hpp @@ -84,12 +84,29 @@ struct Operator : public E { { powArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, true); } - static void setPowArrayGLV(void f(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime)) + static void setPowArrayGLV(void f(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime), size_t g(T& z, const T *xVec, const mpz_class *yVec, size_t n) = 0) { powArrayGLV = f; + powVecNGLV = g; + } + static void powVec(T& z, const T* xVec, const mpz_class *yVec, size_t n) + { + assert(powVecNGLV); + T r; + r.setOne(); + while (n > 0) { + T t; + size_t done = powVecNGLV(t, xVec, yVec, n); + r *= t; + xVec += done; + yVec += done; + n -= done; + } + z = r; } private: static void (*powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime); + static size_t (*powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n); static void powArray(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime) { if (powArrayGLV && (constTime || yn > 1)) { @@ -117,6 +134,9 @@ private: template void (*Operator::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime); +template +size_t (*Operator::powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n); + /* T must have save and load */ diff --git a/include/mcl/util.hpp b/include/mcl/util.hpp index a406241..b33b10c 100644 --- a/include/mcl/util.hpp +++ b/include/mcl/util.hpp @@ -157,7 +157,6 @@ void maskArray(T *x, size_t n, size_t bitSize) template size_t getNonZeroArraySize(const T *x, size_t n) { - assert(n > 0); while (n > 0) { if (x[n - 1]) return n; n--; @@ -165,6 +164,62 @@ size_t getNonZeroArraySize(const T *x, size_t n) return 1; } +template +class BitIterator { + const T *x_; + size_t bitPos_; + size_t bitSize_; + static const size_t TbitSize = sizeof(T) * 8; +public: + BitIterator(const T *x, size_t n) + : x_(x) + , bitPos_(0) + { + assert(n > 0); + n = getNonZeroArraySize(x, n); + if (n == 1 && x[0] == 0) { + bitSize_ = 1; + } else { + assert(x_[n - 1]); + bitSize_ = (n - 1) * sizeof(T) * 8 + 1 + cybozu::bsr(x_[n - 1]); + } + } + bool hasNext() const { return bitPos_ < bitSize_; } + T getNext(size_t w) + { + assert(0 < w && w <= TbitSize); + assert(hasNext()); + const size_t q = bitPos_ / TbitSize; + const size_t r = bitPos_ % TbitSize; + const size_t remain = bitSize_ - bitPos_; + if (w > remain) w = remain; + T v = x_[q] >> r; + if (r + w > TbitSize) { + v |= x_[q + 1] << (TbitSize - r); + } + bitPos_ += w; + return v & mask(w); + } + // whethere next bit is 1 or 0 (bitPos is not moved) + bool peekBit() const + { + assert(hasNext()); + const size_t q = bitPos_ / TbitSize; + const size_t r = bitPos_ % TbitSize; + return (x_[q] >> r) & 1; + } + void skipBit() + { + assert(hasNext()); + bitPos_++; + } + T mask(size_t w) const + { + assert(w <= TbitSize); + return (w == TbitSize ? T(0) : (T(1) << w)) - 1; + } +}; + /* @param out [inout] : set element of G ; out = x^y[] @param x [in] diff --git a/test/bls12_test.cpp b/test/bls12_test.cpp index 6aac204..0379693 100644 --- a/test/bls12_test.cpp +++ b/test/bls12_test.cpp @@ -384,7 +384,7 @@ CYBOZU_TEST_AUTO(naive) testPairing(P, Q, ts.e); testPrecomputed(P, Q); testMillerLoop2(P, Q); - testCommon(P, Q); + testCommon(P, Q); testBench(P, Q); } int count = (int)clk.getCount(); diff --git a/test/bn384_test.cpp b/test/bn384_test.cpp index e248d48..13fc077 100644 --- a/test/bn384_test.cpp +++ b/test/bn384_test.cpp @@ -40,7 +40,7 @@ void testCurve(const mcl::CurveParam& cp) pairing(e2, aP, bQ); GT::pow(e1, e1, a * b); CYBOZU_TEST_EQUAL(e1, e2); - testCommon(P, Q); + testCommon(P, Q); testBench(P, Q); testSquareRoot(); testLagrange(); diff --git a/test/bn512_test.cpp b/test/bn512_test.cpp index ebbc7c0..8999bc9 100644 --- a/test/bn512_test.cpp +++ b/test/bn512_test.cpp @@ -34,7 +34,7 @@ void testCurve(const mcl::CurveParam& cp) pairing(e2, aP, bQ); GT::pow(e1, e1, a * b); CYBOZU_TEST_EQUAL(e1, e2); - testCommon(P, Q); + testCommon(P, Q); testBench(P, Q); testSquareRoot(); testLagrange(); diff --git a/test/bn_test.cpp b/test/bn_test.cpp index 397f9a1..b62bc8d 100644 --- a/test/bn_test.cpp +++ b/test/bn_test.cpp @@ -402,7 +402,7 @@ CYBOZU_TEST_AUTO(naive) testPrecomputed(P, Q); testMillerLoop2(P, Q); testMillerLoopVec(); - testCommon(P, Q); + testCommon(P, Q); testBench(P, Q); benchAddDblG1(); benchAddDblG2(); diff --git a/test/common_test.hpp b/test/common_test.hpp index e5378e9..3053038 100644 --- a/test/common_test.hpp +++ b/test/common_test.hpp @@ -1,6 +1,10 @@ -template -void naiveMulVec(G& out, const G *xVec, const F *yVec, size_t n) +template +void naiveMulVec(G& out, const G *xVec, const mpz_class *yVec, size_t n) { + if (n == 1) { + G::mul(out, xVec[0], yVec[0]); + return; + } G r, t; r.clear(); for (size_t i = 0; i < n; i++) { @@ -16,14 +20,13 @@ void testMulVec(const G& P) using namespace mcl::bn; const int N = 33; G xVec[N]; - mcl::bn::Fr yVec[N]; + mpz_class yVec[N]; for (size_t i = 0; i < N; i++) { G::mul(xVec[i], P, i + 3); - yVec[i].setByCSPRNG(); + mcl::gmp::getRand(yVec[i], Fr::getOp().bitSize); } - const size_t nTbl[] = { 1, 2, 3, 5, 30, 31, 32, 33 }; - const int C = 400; + const size_t nTbl[] = { 1, 2, 3, 5, 7, 8, 9, 14, 15, 16, 30, 31, 32, 33 }; for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(nTbl); i++) { const size_t n = nTbl[i]; G Q1, Q2; @@ -31,14 +34,70 @@ void testMulVec(const G& P) naiveMulVec(Q1, xVec, yVec, n); G::mulVec(Q2, xVec, yVec, n); CYBOZU_TEST_EQUAL(Q1, Q2); +#if 0//#ifdef NDEBUG printf("n=%zd\n", n); + const int C = 400; CYBOZU_BENCH_C("naive ", C, naiveMulVec, Q1, xVec, yVec, n); CYBOZU_BENCH_C("mulVec", C, G::mulVec, Q1, xVec, yVec, n); +#endif + } +} + +template +void naivePowVec(G& out, const G *xVec, const mpz_class *yVec, size_t n) +{ + if (n == 1) { + G::pow(out, xVec[0], yVec[0]); + return; + } + G r, t; + r.setOne(); + for (size_t i = 0; i < n; i++) { + G::pow(t, xVec[i], yVec[i]); + r *= t; + } + out = r; +} + +template +inline void testPowVec(const G& e) +{ + using namespace mcl::bn; + const int N = 33; + G xVec[N]; + mpz_class yVec[N]; + + xVec[0] = e; + for (size_t i = 0; i < N; i++) { + if (i > 0) G::mul(xVec[i], xVec[i - 1], e); + mcl::gmp::getRand(yVec[i], Fr::getOp().bitSize); + } + const size_t nTbl[] = { 1, 2, 3, 5, 7, 8, 9, 14, 15, 16, 30, 31, 32, 33 }; + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(nTbl); i++) { + const size_t n = nTbl[i]; + G Q1, Q2; + CYBOZU_TEST_ASSERT(n <= N); + naivePowVec(Q1, xVec, yVec, n); + G::powVec(Q2, xVec, yVec, n); + CYBOZU_TEST_EQUAL(Q1, Q2); +#if 0//#ifdef NDEBUG + printf("n=%zd\n", n); + const int C = 400; + CYBOZU_BENCH_C("naive ", C, naivePowVec, Q1, xVec, yVec, n); + CYBOZU_BENCH_C("mulVec", C, G::powVec, Q1, xVec, yVec, n); +#endif } } -template -void testCommon(const G1& P, const G2&) +template +void testCommon(const G1& P, const G2& Q) { + puts("G1"); testMulVec(P); + puts("G2"); + testMulVec(Q); + GT e; + mcl::bn::pairing(e, P, Q); + puts("GT"); + testPowVec(e); } diff --git a/test/ec_test.cpp b/test/ec_test.cpp index 2beac01..047e2a7 100644 --- a/test/ec_test.cpp +++ b/test/ec_test.cpp @@ -532,7 +532,7 @@ private: void operator=(const Test&); }; -void naiveMulVec(Ec& out, const Ec *xVec, const Zn *yVec, size_t n) +void naiveMulVec(Ec& out, const Ec *xVec, const mpz_class *yVec, size_t n) { Ec r, t; r.clear(); @@ -552,13 +552,13 @@ void mulVec(const mcl::EcParam& para) P += P; const int N = 33; Ec xVec[N]; - Zn yVec[N]; + mpz_class yVec[N]; Ec Q1, Q2; Ec::dbl(P, P); for (size_t i = 0; i < N; i++) { Ec::mul(xVec[i], P, i + 3); - yVec[i].setByCSPRNG(); + mcl::gmp::getRand(yVec[i], Zn::getOp().bitSize); } const size_t nTbl[] = { 1, 2, 3, 5, 30, 31, 32, 33 }; const int C = 400; diff --git a/test/fp_util_test.cpp b/test/fp_util_test.cpp index e8a9f9a..45b1573 100644 --- a/test/fp_util_test.cpp +++ b/test/fp_util_test.cpp @@ -268,3 +268,45 @@ CYBOZU_TEST_AUTO(stream) } } } + +CYBOZU_TEST_AUTO(BitIterator) +{ + const struct Tbl { + uint32_t v[4]; + uint32_t n; + } tbl[] = { + { { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, 4 }, + { { 0 }, 1 }, + { { 0x12345678, 0x9abcdef0, 0xfedcba98, 0 }, 4 }, + { { 0x12345678, 0x9abcdef0, 0xfed,}, 3 }, + }; + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { + const Tbl& t = tbl[i]; + for (size_t w = 1; w <= 32; w++) { + mcl::fp::BitIterator bi(t.v, t.n); + mpz_class x; + mcl::gmp::setArray(x, t.v, t.n); + while (bi.hasNext()) { + uint32_t v1 = bi.getNext(w); + mpz_class v2 = x & bi.mask(w); + CYBOZU_TEST_EQUAL(v1, v2); + x >>= w; + } + CYBOZU_TEST_EQUAL(x, 0); + } + // w = 1 + { + mcl::fp::BitIterator bi(t.v, t.n); + mpz_class x; + mcl::gmp::setArray(x, t.v, t.n); + while (bi.hasNext()) { + uint32_t v1 = bi.peekBit(); + mpz_class v2 = x & 1; + CYBOZU_TEST_EQUAL(v1, v2); + x >>= 1; + bi.skipBit(); + } + CYBOZU_TEST_EQUAL(x, 0); + } + } +} diff --git a/test/glv_test.cpp b/test/glv_test.cpp index e1d4941..78bb821 100644 --- a/test/glv_test.cpp +++ b/test/glv_test.cpp @@ -122,7 +122,7 @@ void testGLV1() } typedef mcl::bn::local::GLV1 GLV1; - GLV1::initForBN(BN::param.r, BN::param.z, BN::param.isBLS12); + GLV1::initForBN(BN::param.z, BN::param.isBLS12); if (!BN::param.isBLS12) { compareLength(oldGlv); } @@ -165,8 +165,8 @@ void testGLV2() G2 Q0, Q1, Q2; mpz_class z = BN::param.z; mpz_class r = BN::param.r; - mcl::bn::local::GLV2 glv2; - glv2.init(r, z, BN::param.isBLS12); + mcl::bn::local::GLV2 glv2; + glv2.init(z, BN::param.isBLS12); mpz_class n; cybozu::XorShift rg; mapToG2(Q0, 1); diff --git a/test/she_test.cpp b/test/she_test.cpp index 0782eda..cec65f2 100644 --- a/test/she_test.cpp +++ b/test/she_test.cpp @@ -586,7 +586,7 @@ void decBench(const char *msg, int C, const SecretKey& sec, const PublicKey& pub } } -#ifndef PAPER +#if !defined(PAPER) && defined(NDEBUG) CYBOZU_TEST_AUTO(hashBench) { SecretKey& sec = g_sec;