support mulVec

update-fork
MITSUNARI Shigeo 5 years ago
parent 72c8c830e2
commit afb1c812f1
  1. 111
      include/mcl/bn.hpp
  2. 151
      include/mcl/ec.hpp
  3. 4
      include/mcl/gmp_util.hpp
  4. 22
      include/mcl/operator.hpp
  5. 57
      include/mcl/util.hpp
  6. 2
      test/bls12_test.cpp
  7. 2
      test/bn384_test.cpp
  8. 2
      test/bn512_test.cpp
  9. 2
      test/bn_test.cpp
  10. 75
      test/common_test.hpp
  11. 6
      test/ec_test.cpp
  12. 42
      test/fp_util_test.cpp
  13. 6
      test/glv_test.cpp
  14. 2
      test/she_test.cpp

@ -560,14 +560,13 @@ struct MapTo {
} }
}; };
typedef mcl::FixedArray<int8_t, MCL_MAX_FR_BIT_SIZE / 2 + 2> NafArray;
/* /*
Software implementation of Attribute-Based Encryption: Appendixes Software implementation of Attribute-Based Encryption: Appendixes
GLV for G1 on BN/BLS12 GLV for G1 on BN/BLS12
*/ */
struct GLV1 : mcl::GLV1T<G1> { struct GLV1 : mcl::GLV1T<G1, Fr> {
static bool usePrecomputedTable(int curveType) static bool usePrecomputedTable(int curveType)
{ {
if (curveType < 0) return false; if (curveType < 0) return false;
@ -577,7 +576,6 @@ struct GLV1 : mcl::GLV1T<G1> {
size_t rBitSize; size_t rBitSize;
const char *v0, *v1; const char *v0, *v1;
const char *B[2][2]; const char *B[2][2];
const char *r;
} tbl[] = { } tbl[] = {
{ {
MCL_BN254, MCL_BN254,
@ -595,7 +593,6 @@ struct GLV1 : mcl::GLV1T<G1> {
"-61818000000000020400000000000003", "-61818000000000020400000000000003",
}, },
}, },
"2523648240000001ba344d8000000007ff9f800000000010a10000000000000d",
}, },
}; };
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
@ -609,20 +606,18 @@ struct GLV1 : mcl::GLV1T<G1> {
gmp::setStr(&b, B[0][1], tbl[i].B[0][1], 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][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, 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 true;
} }
return false; 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; if (usePrecomputedTable(curveType)) return;
bool b = Fp::squareRoot(rw, -3); bool b = Fp::squareRoot(rw, -3);
assert(b); assert(b);
(void)b; (void)b;
rw = -(rw + 1) / 2; rw = -(rw + 1) / 2;
r = _r; rBitSize = Fr::getOp().bitSize;
rBitSize = gmp::getBitSize(r);
rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);// a little better size rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);// a little better size
if (isBLS12) { if (isBLS12) {
/* /*
@ -648,6 +643,7 @@ struct GLV1 : mcl::GLV1T<G1> {
B[1][1] = -6 * z * z - 4 * z - 1; B[1][1] = -6 * z * z - 4 * z - 1;
} }
// [v0 v1] = [r 0] * B^(-1) // [v0 v1] = [r 0] * B^(-1)
const mpz_class& r = Fr::getOp().mp;
v0 = ((-B[1][1]) << rBitSize) / r; v0 = ((-B[1][1]) << rBitSize) / r;
v1 = ((B[1][0]) << rBitSize) / r; v1 = ((B[1][0]) << rBitSize) / r;
} }
@ -656,22 +652,24 @@ struct GLV1 : mcl::GLV1T<G1> {
/* /*
GLV method for G2 and GT on BN/BLS12 GLV method for G2 and GT on BN/BLS12
*/ */
template<class _Fr>
struct GLV2 { struct GLV2 {
typedef _Fr Fr;
typedef mcl::FixedArray<int8_t, sizeof(Fr) * 8 / 4 + 4> NafArray;
size_t rBitSize; size_t rBitSize;
mpz_class B[4][4]; mpz_class B[4][4];
mpz_class r;
mpz_class v[4]; mpz_class v[4];
mpz_class z; mpz_class z;
mpz_class abs_z; mpz_class abs_z;
bool isBLS12; bool isBLS12;
GLV2() : rBitSize(0), isBLS12(false) {} 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->z = z;
this->abs_z = z < 0 ? -z : z; this->abs_z = z < 0 ? -z : z;
this->isBLS12 = isBLS12; 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 rBitSize = (rBitSize + mcl::fp::UnitBitSize - 1) & ~(mcl::fp::UnitBitSize - 1);// a little better size
mpz_class z2p1 = z * 2 + 1; mpz_class z2p1 = z * 2 + 1;
B[0][0] = z + 1; B[0][0] = z + 1;
@ -758,6 +756,11 @@ struct GLV2 {
template<class T> template<class T>
void mul(T& Q, const T& P, mpz_class x, bool constTime = false) const 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 int w = 5;
const size_t tblSize = 1 << (w - 2); const size_t tblSize = 1 << (w - 2);
const size_t splitN = 4; 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[2], naf[2], maxBit - 1 - i);
mcl::local::addTbl(Q, tbl[3], naf[3], 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<class T>
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<Fp12> AG; // as additive group typedef GroupMtoA<Fp12> AG; // as additive group
AG& _z = static_cast<AG&>(z); AG& _z = static_cast<AG&>(z);
@ -824,7 +884,7 @@ struct Param {
mpz_class p; mpz_class p;
mpz_class r; mpz_class r;
local::MapTo mapTo; local::MapTo mapTo;
local::GLV2 glv2; local::GLV2<Fr> glv2;
// for G2 Frobenius // for G2 Frobenius
Fp2 g2; Fp2 g2;
Fp2 g3; Fp2 g3;
@ -939,8 +999,8 @@ struct Param {
} else { } else {
mapTo.init(2 * p - r, z, cp.curveType); mapTo.init(2 * p - r, z, cp.curveType);
} }
GLV1::initForBN(r, z, isBLS12, cp.curveType); GLV1::initForBN(z, isBLS12, cp.curveType);
glv2.init(r, z, isBLS12); glv2.init(z, isBLS12);
basePoint.clear(); basePoint.clear();
*pb = true; *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); 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<Fp12> AG; // as additive group
AG& _z = static_cast<AG&>(z);
const AG *_xVec = static_cast<const AG*>(xVec);
return BN::param.glv2.mulVecNGLV(_z, _xVec, yVec, n);
}
/* /*
Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions
Robert Granger, Michael Scott 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); local::StaticVar<>::param.init(pb, cp, mode);
if (!*pb) return; if (!*pb) return;
G1::setMulArrayGLV(local::GLV1::mulArrayGLV); G1::setMulArrayGLV(local::GLV1::mulArrayGLV, local::GLV1::mulVecNGLV);
G2::setMulArrayGLV(local::mulArrayGLV2); G2::setMulArrayGLV(local::mulArrayGLV2, local::mulVecNGLV2);
Fp12::setPowArrayGLV(local::powArrayGLV2); Fp12::setPowArrayGLV(local::powArrayGLV2, local::powVecNGLV2);
G1::setCompressedExpression(); G1::setCompressedExpression();
G2::setCompressedExpression(); G2::setCompressedExpression();
*pb = true; *pb = true;

@ -30,6 +30,9 @@ enum Mode {
namespace local { 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 // x is negative <=> x < half(:=(p+1)/2) <=> a = 1
template<class Fp> template<class Fp>
bool get_a_flag(const Fp& x) bool get_a_flag(const Fp& x)
@ -98,6 +101,7 @@ public:
static bool verifyOrder_; static bool verifyOrder_;
static mpz_class order_; static mpz_class order_;
static void (*mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime); 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 */ /* default constructor is undefined value */
EcT() {} EcT() {}
EcT(const Fp& _x, const Fp& _y) EcT(const Fp& _x, const Fp& _y)
@ -211,6 +215,7 @@ public:
verifyOrder_ = false; verifyOrder_ = false;
order_ = 0; order_ = 0;
mulArrayGLV = 0; mulArrayGLV = 0;
mulVecNGLV = 0;
#ifdef MCL_EC_USE_AFFINE #ifdef MCL_EC_USE_AFFINE
cybozu::disable_warning_unused_variable(mode); cybozu::disable_warning_unused_variable(mode);
#else #else
@ -232,9 +237,10 @@ public:
// don't clear order_ because it is used for isValidOrder() // 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; mulArrayGLV = f;
mulVecNGLV = g;
} }
static inline void init(bool *pb, const char *astr, const char *bstr, int mode = ec::Jacobi) 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) 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) { if (!constTime) {
while (yn > 0) { if (yn == 0) {
if (y[yn - 1]) break; z.clear();
yn--; return;
} }
yn = fp::getNonZeroArraySize(y, yn);
if (yn <= 1 && mulSmallInt(z, x, *y, isNegative)) return; if (yn <= 1 && mulSmallInt(z, x, *y, isNegative)) return;
} }
if (useGLV && mulArrayGLV && (yn * sizeof(fp::Unit) > 8)) { 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) static inline void mulArrayBase(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime)
{ {
#if 1
(void)constTime; (void)constTime;
mpz_class v; mpz_class v;
bool b; bool b;
gmp::setArray(&b, v, y, yn); gmp::setArray(&b, v, y, yn);
assert(b); (void)b; assert(b); (void)b;
if (isNegative) v = -v;
const int maxW = 5; const int maxW = 5;
const int maxTblSize = 1 << (maxW - 2); const int maxTblSize = 1 << (maxW - 2);
/* /*
@ -1165,22 +1172,6 @@ public:
EcT::dbl(z, z); EcT::dbl(z, z);
local::addTbl(z, tbl, naf, naf.size() - 1 - i); 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 generic mul
@ -1196,19 +1187,19 @@ public:
@note &z != xVec[i] @note &z != xVec[i]
*/ */
private: private:
template<size_t N, class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT> static inline size_t mulVecN(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t n)
static inline size_t addMulVecN(EcT& z, const EcT *xVec, const FpT<tag, maxBitSize> *yVec, size_t n)
{ {
const size_t N = mcl::ec::local::maxMulVecN;
if (n > N) n = N; if (n > N) n = N;
const int w = 5; const int w = 5;
const size_t tblSize = 1 << (w - 2); const size_t tblSize = 1 << (w - 2);
typedef mcl::FixedArray<int8_t, maxBitSize + 1> NafArray; typedef mcl::FixedArray<int8_t, sizeof(EcT::Fp) * 8 + 1> NafArray;
NafArray naf[N]; NafArray naf[N];
EcT tbl[N][tblSize]; EcT tbl[N][tblSize];
size_t maxBit = 0; size_t maxBit = 0;
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
bool b; bool b;
gmp::getNAFwidth(&b, naf[i], yVec[i].getMpz(), w); gmp::getNAFwidth(&b, naf[i], yVec[i], w);
assert(b); (void)b; assert(b); (void)b;
if (naf[i].size() > maxBit) maxBit = naf[i].size(); if (naf[i].size() > maxBit) maxBit = naf[i].size();
EcT P2; EcT P2;
@ -1229,14 +1220,22 @@ private:
} }
public: public:
template<class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT> static inline void mulVec(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t n)
static inline void mulVec(EcT& z, const EcT *xVec, const FpT<tag, maxBitSize> *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; EcT r;
r.clear(); r.clear();
while (n > 0) { while (n > 0) {
EcT t; EcT t;
size_t done = addMulVecN<32>(t, xVec, yVec, n); size_t done = f(t, xVec, yVec, n);
r += t; r += t;
xVec += done; xVec += done;
yVec += done; yVec += done;
@ -1298,18 +1297,20 @@ template<class Fp> int EcT<Fp>::ioMode_;
template<class Fp> bool EcT<Fp>::verifyOrder_; template<class Fp> bool EcT<Fp>::verifyOrder_;
template<class Fp> mpz_class EcT<Fp>::order_; template<class Fp> mpz_class EcT<Fp>::order_;
template<class Fp> void (*EcT<Fp>::mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime); template<class Fp> void (*EcT<Fp>::mulArrayGLV)(EcT& z, const EcT& x, const fp::Unit *y, size_t yn, bool isNegative, bool constTime);
template<class Fp> size_t (*EcT<Fp>::mulVecNGLV)(EcT& z, const EcT *xVec, const mpz_class *yVec, size_t yn);
#ifndef MCL_EC_USE_AFFINE #ifndef MCL_EC_USE_AFFINE
template<class Fp> int EcT<Fp>::mode_; template<class Fp> int EcT<Fp>::mode_;
#endif #endif
template<class Ec> // r = the order of Ec
template<class Ec, class _Fr>
struct GLV1T { struct GLV1T {
typedef typename Ec::Fp Fp; typedef typename Ec::Fp Fp;
typedef _Fr Fr;
static Fp rw; // rw = 1 / w = (-1 - sqrt(-3)) / 2 static Fp rw; // rw = 1 / w = (-1 - sqrt(-3)) / 2
static size_t rBitSize; static size_t rBitSize;
static mpz_class v0, v1; static mpz_class v0, v1;
static mpz_class B[2][2]; static mpz_class B[2][2];
static mpz_class r;
public: public:
#ifndef CYBOZU_DONT_USE_STRING #ifndef CYBOZU_DONT_USE_STRING
static void dump(const mpz_class& x) static void dump(const mpz_class& x)
@ -1323,7 +1324,6 @@ public:
dump(v0); dump(v0);
dump(v1); dump(v1);
dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]); dump(B[0][0]); dump(B[0][1]); dump(B[1][0]); dump(B[1][1]);
dump(r);
} }
#endif #endif
/* /*
@ -1346,47 +1346,55 @@ public:
a = x - (t * B[0][0] + b * B[1][0]); a = x - (t * B[0][0] + b * B[1][0]);
b = - (t * B[0][1] + b * B[1][1]); 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 int w = 5;
const mpz_class& r = Fr::getOp().mp;
const size_t tblSize = 1 << (w - 2); const size_t tblSize = 1 << (w - 2);
typedef mcl::FixedArray<int8_t, sizeof(Fp) * 8 / 2 + 2> NafArray; typedef mcl::FixedArray<int8_t, sizeof(Fr) * 8 / 2 + 2> NafArray;
NafArray naf[2]; NafArray naf[N][2];
mpz_class u[2]; Ec tbl[N][2][tblSize];
Ec tbl[2][tblSize];
bool b; 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; for (int j = 0; j < 2; j++) {
if (x == 0) { gmp::getNAFwidth(&b, naf[i][j], u[j], w);
Q.clear(); assert(b); (void)b;
if (!constTime) return; if (naf[i][j].size() > maxBit) maxBit = naf[i][j].size();
} }
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 P2;
Ec::dbl(P2, P); Ec::dbl(P2, xVec[i]);
for (size_t i = 1; i < tblSize; i++) { tbl[i][0][0] = xVec[i];
Ec::add(tbl[0][i], tbl[0][i - 1], P2); mulLambda(tbl[i][1][0], tbl[i][0][0]);
mulLambda(tbl[1][i], tbl[0][i]); 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()); z.clear();
Q.clear();
for (size_t i = 0; i < maxBit; i++) { for (size_t i = 0; i < maxBit; i++) {
Ec::dbl(Q, Q); Ec::dbl(z, z);
local::addTbl(Q, tbl[0], naf[0], maxBit - 1 - i); for (size_t j = 0; j < n; j++) {
local::addTbl(Q, tbl[1], naf[1], maxBit - 1 - i); 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) 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 initForBN() is defined in bn.hpp
*/ */
static void initForSecp256k1(const mpz_class& _r) static void initForSecp256k1()
{ {
bool b = Fp::squareRoot(rw, -3); bool b = Fp::squareRoot(rw, -3);
assert(b); assert(b);
(void)b; (void)b;
rw = -(rw + 1) / 2; rw = -(rw + 1) / 2;
r = _r; rBitSize = Fr::getOp().bitSize;
rBitSize = gmp::getBitSize(r);
rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1); rBitSize = (rBitSize + fp::UnitBitSize - 1) & ~(fp::UnitBitSize - 1);
gmp::setStr(&b, B[0][0], "0x3086d221a7d46bcde86c90e49284eb15"); gmp::setStr(&b, B[0][0], "0x3086d221a7d46bcde86c90e49284eb15");
assert(b); (void)b; assert(b); (void)b;
@ -1416,18 +1423,18 @@ public:
gmp::setStr(&b, B[1][0], "0x114ca50f7a8e2f3f657c1108d9d44cfd8"); gmp::setStr(&b, B[1][0], "0x114ca50f7a8e2f3f657c1108d9d44cfd8");
assert(b); (void)b; assert(b); (void)b;
B[1][1] = B[0][0]; B[1][1] = B[0][0];
const mpz_class& r = Fr::getOp().mp;
v0 = ((B[1][1]) << rBitSize) / r; v0 = ((B[1][1]) << rBitSize) / r;
v1 = ((-B[0][1]) << rBitSize) / r; v1 = ((-B[0][1]) << rBitSize) / r;
} }
}; };
// rw = 1 / w = (-1 - sqrt(-3)) / 2 // rw = 1 / w = (-1 - sqrt(-3)) / 2
template<class Ec> typename Ec::Fp GLV1T<Ec>::rw; template<class Ec, class Fr> typename Ec::Fp GLV1T<Ec, Fr>::rw;
template<class Ec> size_t GLV1T<Ec>::rBitSize; template<class Ec, class Fr> size_t GLV1T<Ec, Fr>::rBitSize;
template<class Ec> mpz_class GLV1T<Ec>::v0; template<class Ec, class Fr> mpz_class GLV1T<Ec, Fr>::v0;
template<class Ec> mpz_class GLV1T<Ec>::v1; template<class Ec, class Fr> mpz_class GLV1T<Ec, Fr>::v1;
template<class Ec> mpz_class GLV1T<Ec>::B[2][2]; template<class Ec, class Fr> mpz_class GLV1T<Ec, Fr>::B[2][2];
template<class Ec> mpz_class GLV1T<Ec>::r;
/* /*
Ec : elliptic curve 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 (!*pb) return;
} }
if (curveType == MCL_SECP256K1) { if (curveType == MCL_SECP256K1) {
GLV1T<Ec>::initForSecp256k1(Zn::getOp().mp); GLV1T<Ec, Zn>::initForSecp256k1();
Ec::setMulArrayGLV(GLV1T<Ec>::mulArrayGLV); Ec::setMulArrayGLV(GLV1T<Ec, Zn>::mulArrayGLV, GLV1T<Ec, Zn>::mulVecNGLV);
} else { } else {
Ec::setMulArrayGLV(0); Ec::setMulArrayGLV(0);
} }

@ -615,13 +615,14 @@ template<class Vec>
void getNAFwidth(bool *pb, Vec& naf, mpz_class x, size_t w) void getNAFwidth(bool *pb, Vec& naf, mpz_class x, size_t w)
{ {
assert(w > 0); assert(w > 0);
*pb = true;
naf.clear(); naf.clear();
size_t zeroNum = 0;
bool negative = false; bool negative = false;
if (x < 0) { if (x < 0) {
negative = true; negative = true;
x = -x; x = -x;
} }
size_t zeroNum = 0;
const int signedMaxW = 1 << (w - 1); const int signedMaxW = 1 << (w - 1);
const int maxW = signedMaxW * 2; const int maxW = signedMaxW * 2;
const int maskW = maxW - 1; 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]; naf[i] = -naf[i];
} }
} }
*pb = true;
} }
#ifndef CYBOZU_DONT_USE_EXCEPTION #ifndef CYBOZU_DONT_USE_EXCEPTION

@ -84,12 +84,29 @@ struct Operator : public E {
{ {
powArray(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0, true); 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; 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: private:
static void (*powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime); 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) static void powArray(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime)
{ {
if (powArrayGLV && (constTime || yn > 1)) { if (powArrayGLV && (constTime || yn > 1)) {
@ -117,6 +134,9 @@ private:
template<class T, class E> template<class T, class E>
void (*Operator<T, E>::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime); void (*Operator<T, E>::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);
template<class T, class E>
size_t (*Operator<T, E>::powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n);
/* /*
T must have save and load T must have save and load
*/ */

@ -157,7 +157,6 @@ void maskArray(T *x, size_t n, size_t bitSize)
template<class T> template<class T>
size_t getNonZeroArraySize(const T *x, size_t n) size_t getNonZeroArraySize(const T *x, size_t n)
{ {
assert(n > 0);
while (n > 0) { while (n > 0) {
if (x[n - 1]) return n; if (x[n - 1]) return n;
n--; n--;
@ -165,6 +164,62 @@ size_t getNonZeroArraySize(const T *x, size_t n)
return 1; return 1;
} }
template<class T>
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<T>(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 out [inout] : set element of G ; out = x^y[]
@param x [in] @param x [in]

@ -384,7 +384,7 @@ CYBOZU_TEST_AUTO(naive)
testPairing(P, Q, ts.e); testPairing(P, Q, ts.e);
testPrecomputed(P, Q); testPrecomputed(P, Q);
testMillerLoop2(P, Q); testMillerLoop2(P, Q);
testCommon(P, Q); testCommon<G1, G2, GT>(P, Q);
testBench(P, Q); testBench(P, Q);
} }
int count = (int)clk.getCount(); int count = (int)clk.getCount();

@ -40,7 +40,7 @@ void testCurve(const mcl::CurveParam& cp)
pairing(e2, aP, bQ); pairing(e2, aP, bQ);
GT::pow(e1, e1, a * b); GT::pow(e1, e1, a * b);
CYBOZU_TEST_EQUAL(e1, e2); CYBOZU_TEST_EQUAL(e1, e2);
testCommon(P, Q); testCommon<G1, G2, GT>(P, Q);
testBench(P, Q); testBench(P, Q);
testSquareRoot(); testSquareRoot();
testLagrange(); testLagrange();

@ -34,7 +34,7 @@ void testCurve(const mcl::CurveParam& cp)
pairing(e2, aP, bQ); pairing(e2, aP, bQ);
GT::pow(e1, e1, a * b); GT::pow(e1, e1, a * b);
CYBOZU_TEST_EQUAL(e1, e2); CYBOZU_TEST_EQUAL(e1, e2);
testCommon(P, Q); testCommon<G1, G2, GT>(P, Q);
testBench(P, Q); testBench(P, Q);
testSquareRoot(); testSquareRoot();
testLagrange(); testLagrange();

@ -402,7 +402,7 @@ CYBOZU_TEST_AUTO(naive)
testPrecomputed(P, Q); testPrecomputed(P, Q);
testMillerLoop2(P, Q); testMillerLoop2(P, Q);
testMillerLoopVec(); testMillerLoopVec();
testCommon(P, Q); testCommon<G1, G2, GT>(P, Q);
testBench(P, Q); testBench(P, Q);
benchAddDblG1(); benchAddDblG1();
benchAddDblG2(); benchAddDblG2();

@ -1,6 +1,10 @@
template<class G, class F> template<class G>
void naiveMulVec(G& out, const G *xVec, const F *yVec, size_t n) 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; G r, t;
r.clear(); r.clear();
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
@ -16,14 +20,13 @@ void testMulVec(const G& P)
using namespace mcl::bn; using namespace mcl::bn;
const int N = 33; const int N = 33;
G xVec[N]; G xVec[N];
mcl::bn::Fr yVec[N]; mpz_class yVec[N];
for (size_t i = 0; i < N; i++) { for (size_t i = 0; i < N; i++) {
G::mul(xVec[i], P, i + 3); 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 size_t nTbl[] = { 1, 2, 3, 5, 7, 8, 9, 14, 15, 16, 30, 31, 32, 33 };
const int C = 400;
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(nTbl); i++) { for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(nTbl); i++) {
const size_t n = nTbl[i]; const size_t n = nTbl[i];
G Q1, Q2; G Q1, Q2;
@ -31,14 +34,70 @@ void testMulVec(const G& P)
naiveMulVec(Q1, xVec, yVec, n); naiveMulVec(Q1, xVec, yVec, n);
G::mulVec(Q2, xVec, yVec, n); G::mulVec(Q2, xVec, yVec, n);
CYBOZU_TEST_EQUAL(Q1, Q2); CYBOZU_TEST_EQUAL(Q1, Q2);
#if 0//#ifdef NDEBUG
printf("n=%zd\n", n); printf("n=%zd\n", n);
const int C = 400;
CYBOZU_BENCH_C("naive ", C, naiveMulVec, Q1, xVec, yVec, n); CYBOZU_BENCH_C("naive ", C, naiveMulVec, Q1, xVec, yVec, n);
CYBOZU_BENCH_C("mulVec", C, G::mulVec, Q1, xVec, yVec, n); CYBOZU_BENCH_C("mulVec", C, G::mulVec, Q1, xVec, yVec, n);
#endif
}
}
template<class G>
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<class G>
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<class G1, class G2> template<class G1, class G2, class GT>
void testCommon(const G1& P, const G2&) void testCommon(const G1& P, const G2& Q)
{ {
puts("G1");
testMulVec(P); testMulVec(P);
puts("G2");
testMulVec(Q);
GT e;
mcl::bn::pairing(e, P, Q);
puts("GT");
testPowVec(e);
} }

@ -532,7 +532,7 @@ private:
void operator=(const Test&); 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; Ec r, t;
r.clear(); r.clear();
@ -552,13 +552,13 @@ void mulVec(const mcl::EcParam& para)
P += P; P += P;
const int N = 33; const int N = 33;
Ec xVec[N]; Ec xVec[N];
Zn yVec[N]; mpz_class yVec[N];
Ec Q1, Q2; Ec Q1, Q2;
Ec::dbl(P, P); Ec::dbl(P, P);
for (size_t i = 0; i < N; i++) { for (size_t i = 0; i < N; i++) {
Ec::mul(xVec[i], P, i + 3); 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 size_t nTbl[] = { 1, 2, 3, 5, 30, 31, 32, 33 };
const int C = 400; const int C = 400;

@ -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<uint32_t> 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<uint32_t> 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);
}
}
}

@ -122,7 +122,7 @@ void testGLV1()
} }
typedef mcl::bn::local::GLV1 GLV1; 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) { if (!BN::param.isBLS12) {
compareLength<GLV1>(oldGlv); compareLength<GLV1>(oldGlv);
} }
@ -165,8 +165,8 @@ void testGLV2()
G2 Q0, Q1, Q2; G2 Q0, Q1, Q2;
mpz_class z = BN::param.z; mpz_class z = BN::param.z;
mpz_class r = BN::param.r; mpz_class r = BN::param.r;
mcl::bn::local::GLV2 glv2; mcl::bn::local::GLV2<Fr> glv2;
glv2.init(r, z, BN::param.isBLS12); glv2.init(z, BN::param.isBLS12);
mpz_class n; mpz_class n;
cybozu::XorShift rg; cybozu::XorShift rg;
mapToG2(Q0, 1); mapToG2(Q0, 1);

@ -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) CYBOZU_TEST_AUTO(hashBench)
{ {
SecretKey& sec = g_sec; SecretKey& sec = g_sec;

Loading…
Cancel
Save