parent
a972724e7f
commit
7bd601d26f
@ -0,0 +1,190 @@ |
|||||||
|
#pragma once |
||||||
|
/**
|
||||||
|
@file |
||||||
|
@brief optimal ate pairing |
||||||
|
@author MITSUNARI Shigeo(@herumi) |
||||||
|
@license modified new BSD license |
||||||
|
http://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*/ |
||||||
|
#include <mcl/fp_tower.hpp> |
||||||
|
#include <mcl/ec.hpp> |
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
namespace mcl { namespace bn { |
||||||
|
|
||||||
|
struct bnFpTag; |
||||||
|
|
||||||
|
typedef mcl::FpT<mcl::bn::bnFpTag, 256> Fp; |
||||||
|
typedef mcl::Fp2T<Fp> Fp2; |
||||||
|
typedef mcl::FpDblT<Fp> FpDbl; |
||||||
|
typedef mcl::Fp6T<Fp> Fp6; |
||||||
|
typedef mcl::Fp12T<Fp> Fp12; |
||||||
|
|
||||||
|
struct CurveParam { |
||||||
|
/*
|
||||||
|
y^2 = x^3 + b |
||||||
|
i^2 = -1 |
||||||
|
xi = xi_a + i |
||||||
|
v^3 = xi |
||||||
|
w^2 = v |
||||||
|
*/ |
||||||
|
int64_t z; |
||||||
|
int b; // y^2 = x^3 + b
|
||||||
|
int xi_a; // xi = xi_a + i
|
||||||
|
bool operator==(const CurveParam& rhs) const { return z == rhs.z && b == rhs.b && xi_a == rhs.xi_a; } |
||||||
|
bool operator!=(const CurveParam& rhs) const { return !operator==(rhs); } |
||||||
|
}; |
||||||
|
|
||||||
|
const CurveParam CurveSNARK1 = { 4965661367192848881, 3, 9 }; |
||||||
|
const CurveParam CurveSNARK2 = { 4965661367192848881, 82, 9 }; |
||||||
|
const CurveParam CurveFp254BNb = { -((1LL << 62) + (1LL << 55) + (1LL << 0)), 2, 1 }; |
||||||
|
|
||||||
|
template<class Vec> |
||||||
|
void convertToBinary(Vec& v, const mpz_class& x) |
||||||
|
{ |
||||||
|
const size_t len = mcl::gmp::getBitSize(x); |
||||||
|
v.clear(); |
||||||
|
for (size_t i = 0; i < len; i++) { |
||||||
|
v.push_back(mcl::gmp::testBit(x, len - 1 - i) ? 1 : 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template<class Vec> |
||||||
|
size_t getContinuousVal(const Vec& v, size_t pos, int val) |
||||||
|
{ |
||||||
|
while (pos >= 2) { |
||||||
|
if (v[pos] != val) break; |
||||||
|
pos--; |
||||||
|
} |
||||||
|
return pos; |
||||||
|
} |
||||||
|
|
||||||
|
template<class Vec> |
||||||
|
void convertToNAF(Vec& v, const Vec& in) |
||||||
|
{ |
||||||
|
v = in; |
||||||
|
size_t pos = v.size() - 1; |
||||||
|
for (;;) { |
||||||
|
size_t p = getContinuousVal(v, pos, 0); |
||||||
|
if (p == 1) return; |
||||||
|
assert(v[p] == 1); |
||||||
|
size_t q = getContinuousVal(v, p, 1); |
||||||
|
if (q == 1) return; |
||||||
|
assert(v[q] == 0); |
||||||
|
if (p - q <= 1) { |
||||||
|
pos = p - 1; |
||||||
|
continue; |
||||||
|
} |
||||||
|
v[q] = 1; |
||||||
|
for (size_t i = q + 1; i < p; i++) { |
||||||
|
v[i] = 0; |
||||||
|
} |
||||||
|
v[p] = -1; |
||||||
|
pos = q; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template<class Vec> |
||||||
|
size_t getNumOfNonZeroElement(const Vec& v) |
||||||
|
{ |
||||||
|
size_t w = 0; |
||||||
|
for (size_t i = 0; i < v.size(); i++) { |
||||||
|
if (v[i]) w++; |
||||||
|
} |
||||||
|
return w; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
compute a repl of x which has smaller Hamming weights. |
||||||
|
return true if naf is selected |
||||||
|
*/ |
||||||
|
template<class Vec> |
||||||
|
bool getGoodRepl(Vec& v, const mpz_class& x) |
||||||
|
{ |
||||||
|
Vec bin; |
||||||
|
convertToBinary(bin, x); |
||||||
|
Vec naf; |
||||||
|
convertToNAF(naf, bin); |
||||||
|
const size_t binW = getNumOfNonZeroElement(bin); |
||||||
|
const size_t nafW = getNumOfNonZeroElement(naf); |
||||||
|
if (nafW < binW) { |
||||||
|
v.swap(naf); |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
v.swap(bin); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
struct Param { |
||||||
|
mpz_class z; |
||||||
|
mpz_class p; |
||||||
|
mpz_class r; |
||||||
|
mpz_class t; /* trace of Frobenius */ |
||||||
|
Fp Z; |
||||||
|
Fp2 W2p; |
||||||
|
Fp2 W3p; |
||||||
|
static const size_t gammarN = 5; |
||||||
|
Fp2 gammar[gammarN]; |
||||||
|
Fp2 gammar2[gammarN]; |
||||||
|
Fp2 gammar3[gammarN]; |
||||||
|
Fp i0; // 0
|
||||||
|
Fp i1; // 1
|
||||||
|
int b; |
||||||
|
Fp2 b_invxi; // b_invxi = b/xi of twist E' : Y^2 = X^3 + b/xi
|
||||||
|
Fp half; |
||||||
|
|
||||||
|
// Loop parameter for the Miller loop part of opt. ate pairing.
|
||||||
|
typedef std::vector<int8_t> SignVec; |
||||||
|
SignVec siTbl; |
||||||
|
bool useNAF; |
||||||
|
SignVec zReplTbl; // QQQ : snark
|
||||||
|
|
||||||
|
void init(const CurveParam& cp = CurveFp254BNb, fp::Mode mode = fp::FP_AUTO) |
||||||
|
{ |
||||||
|
z = cp.z; |
||||||
|
Fp::setModulo(z.get_str(), 10, mode); |
||||||
|
const int pCoff[] = { 1, 6, 24, 36, 36 }; |
||||||
|
const int rCoff[] = { 1, 6, 18, 36, 36 }; |
||||||
|
const int tCoff[] = { 1, 0, 6, 0, 0 }; |
||||||
|
eval(p, z, pCoff); |
||||||
|
eval(r, z, rCoff); |
||||||
|
eval(t, z, tCoff); |
||||||
|
b = cp.b; // set b before calling Fp::setModulo
|
||||||
|
half = Fp(1) / Fp(2); |
||||||
|
Fp2 xi(cp.xi_a, 1); |
||||||
|
b_invxi = Fp2(b) / xi; |
||||||
|
Fp2::power(gammar[0], xi, (p - 1) / 6); |
||||||
|
|
||||||
|
for (size_t i = 1; i < gammarN; ++i) { |
||||||
|
gammar[i] = gammar[i - 1] * gammar[0]; |
||||||
|
} |
||||||
|
|
||||||
|
for (size_t i = 0; i < gammarN; ++i) { |
||||||
|
gammar2[i] = Fp2(gammar[i].a, -gammar[i].b) * gammar[i]; |
||||||
|
} |
||||||
|
|
||||||
|
for (size_t i = 0; i < gammarN; ++i) { |
||||||
|
gammar3[i] = gammar[i] * gammar2[i]; |
||||||
|
} |
||||||
|
|
||||||
|
Fp2::power(W2p, xi, (p - 1) / 3); |
||||||
|
Fp2::power(W3p, xi, (p - 1) / 2); |
||||||
|
Fp2 tmp; |
||||||
|
Fp2::power(tmp, xi, (p * p - 1) / 6); |
||||||
|
assert(tmp.b.isZero()); |
||||||
|
Fp::sqr(Z, tmp.a); |
||||||
|
i0 = 0; |
||||||
|
i1 = 1; |
||||||
|
const mpz_class largest_c = abs(6 * z + 2); |
||||||
|
useNAF = getGoodRepl(siTbl, largest_c); |
||||||
|
getGoodRepl(zReplTbl, abs(z)); // QQQ : snark
|
||||||
|
} |
||||||
|
void eval(mpz_class& y, const mpz_class& x, const int c[5]) const |
||||||
|
{ |
||||||
|
y = (((c[4] * x + c[3]) * x + c[2]) * x + c[1]) * x + c[0]; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} } // mcl::bn
|
||||||
|
|
Loading…
Reference in new issue