diff --git a/README.md b/README.md index dcb1ee0..409be31 100644 --- a/README.md +++ b/README.md @@ -68,40 +68,40 @@ Chia Network's [bls-signatures](https://github.com/Chia-Network/bls-signatures) ``` Chia Network's library: This library (cpu-ext-ct, asm): This library (cpu-ext-rt, asm): This library (no cpu-ext, asm): This library (no cpu-ext, cpp): Signing Signing Signing Signing Signing -Total: 5000 runs in 5447 ms Total: 5000 runs in 4623 ms Total: 5000 runs in 4806 ms Total: 5000 runs in 6266 ms Total: 5000 runs in 15713 ms -Avg: 1.0894 ms Avg: 0.9246 ms Avg: 0.9612 ms Avg: 1.2532 ms Avg: 3.1426 ms +Total: 5000 runs in 5447 ms Total: 5000 runs in 4535 ms Total: 5000 runs in 4726 ms Total: 5000 runs in 6160 ms Total: 5000 runs in 8344 ms +Avg: 1.0894 ms Avg: 0.907 ms Avg: 0.9452 ms Avg: 1.232 ms Avg: 1.6688 ms Verification Verification Verification Verification Verification -Total: 10000 runs in 32285 ms Total: 10000 runs in 24605 ms Total: 10000 runs in 24773 ms Total: 10000 runs in 30844 ms Total: 10000 runs in 77720 ms -Avg: 3.2285 ms Avg: 2.4605 ms Avg: 2.4773 ms Avg: 3.0844 ms Avg: 7.772 ms +Total: 10000 runs in 32285 ms Total: 10000 runs in 19259 ms Total: 10000 runs in 19727 ms Total: 10000 runs in 24561 ms Total: 10000 runs in 33982 ms +Avg: 3.2285 ms Avg: 1.9259 ms Avg: 1.9727 ms Avg: 2.4561 ms Avg: 3.3982 ms Public key validation Public key validation Public key validation Public key validation Public key validation -Total: 100000 runs in 26464 ms Total: 100000 runs in 2066 ms Total: 100000 runs in 2092 ms Total: 100000 runs in 3071 ms Total: 100000 runs in 8318 ms -Avg: 0.26464 ms Avg: 0.02066 ms Avg: 0.02092 ms Avg: 0.03071 ms Avg: 0.08318 ms +Total: 100000 runs in 26464 ms Total: 100000 runs in 2066 ms Total: 100000 runs in 2092 ms Total: 100000 runs in 3071 ms Total: 100000 runs in 4146 ms +Avg: 0.26464 ms Avg: 0.02066 ms Avg: 0.02092 ms Avg: 0.03071 ms Avg: 0.04146 ms Signature validation Signature validation Signature validation Signature validation Signature validation -Total: 100000 runs in 28818 ms Total: 100000 runs in 12575 ms Total: 100000 runs in 12665 ms Total: 100000 runs in 17622 ms Total: 100000 runs in 45040 ms -Avg: 0.28818 ms Avg: 0.12575 ms Avg: 0.12665 ms Avg: 0.17622 ms Avg: 0.4504 ms +Total: 100000 runs in 28818 ms Total: 100000 runs in 12474 ms Total: 100000 runs in 12665 ms Total: 100000 runs in 17622 ms Total: 100000 runs in 24255 ms +Avg: 0.28818 ms Avg: 0.12474 ms Avg: 0.12665 ms Avg: 0.17622 ms Avg: 0.24255 ms Aggregation Aggregation Aggregation Aggregation Aggregation -Total: 100000 runs in 287 ms Total: 100000 runs in 224 ms Total: 100000 runs in 226 ms Total: 100000 runs in 299 ms Total: 100000 runs in 746 ms -Avg: 0.00287 ms Avg: 0.00224 ms Avg: 0.00226 ms Avg: 0.00299 ms Avg: 0.00746 ms +Total: 100000 runs in 287 ms Total: 100000 runs in 224 ms Total: 100000 runs in 226 ms Total: 100000 runs in 299 ms Total: 100000 runs in 410 ms +Avg: 0.00287 ms Avg: 0.00224 ms Avg: 0.00226 ms Avg: 0.00299 ms Avg: 0.0041 ms Batch verification Batch verification Batch verification Batch verification Batch verification -Total: 100000 runs in 138664 ms Total: 100000 runs in 101991 ms Total: 100000 runs in 105088 ms Total: 100000 runs in 132992 ms Total: 100000 runs in 313394 ms -Avg: 1.38664 ms Avg: 1.01991 ms Avg: 1.05088 ms Avg: 1.32992 ms Avg: 3.13394 ms +Total: 100000 runs in 138664 ms Total: 100000 runs in 91959 ms Total: 100000 runs in 95714 ms Total: 100000 runs in 121560 ms Total: 100000 runs in 164145 ms +Avg: 1.38664 ms Avg: 0.91959 ms Avg: 0.95714 ms Avg: 1.2156 ms Avg: 1.64145 ms PopScheme Aggregation PopScheme Aggregation PopScheme Aggregation PopScheme Aggregation PopScheme Aggregation -Total: 5000 runs in 14 ms Total: 5000 runs in 11 ms Total: 5000 runs in 11 ms Total: 5000 runs in 14 ms Total: 5000 runs in 37 ms -Avg: 0.0028 ms Avg: 0.0022 ms Avg: 0.0022 ms Avg: 0.0028 ms Avg: 0.0074 ms +Total: 5000 runs in 14 ms Total: 5000 runs in 11 ms Total: 5000 runs in 11 ms Total: 5000 runs in 14 ms Total: 5000 runs in 21 ms +Avg: 0.0028 ms Avg: 0.0022 ms Avg: 0.0022 ms Avg: 0.0028 ms Avg: 0.0042 ms PopScheme Proofs verification PopScheme Proofs verification PopScheme Proofs verification PopScheme Proofs verification PopScheme Proofs verification -Total: 5000 runs in 16567 ms Total: 5000 runs in 13017 ms Total: 5000 runs in 13231 ms Total: 5000 runs in 16729 ms Total: 5000 runs in 41583 ms -Avg: 3.3134 ms Avg: 2.6034 ms Avg: 2.6462 ms Avg: 3.3458 ms Avg: 8.3166 ms +Total: 5000 runs in 16567 ms Total: 5000 runs in 10315 ms Total: 5000 runs in 10531 ms Total: 5000 runs in 13400 ms Total: 5000 runs in 18593 ms +Avg: 3.3134 ms Avg: 2.0630 ms Avg: 2.1062 ms Avg: 2.6800 ms Avg: 3.7186 ms PopScheme verification PopScheme verification PopScheme verification PopScheme verification PopScheme verification -Total: 5000 runs in 10 ms Total: 5000 runs in 5 ms Total: 5000 runs in 6 ms Total: 5000 runs in 8 ms Total: 5000 runs in 20 ms -Avg: 0.0020 ms Avg: 0.0010 ms Avg: 0.0012 ms Avg: 0.0016 ms Avg: 0.0040 ms +Total: 5000 runs in 10 ms Total: 5000 runs in 5 ms Total: 5000 runs in 6 ms Total: 5000 runs in 7 ms Total: 5000 runs in 10 ms +Avg: 0.0020 ms Avg: 0.0010 ms Avg: 0.0012 ms Avg: 0.0014 ms Avg: 0.0020 ms ``` ## Clean diff --git a/include/fp.hpp b/include/fp.hpp index ed0e3fd..5b8cce2 100644 --- a/include/fp.hpp +++ b/include/fp.hpp @@ -40,6 +40,7 @@ class fp uint64_t mul2(); fp toMont() const; fp fromMont() const; + fp phi() const; template fp exp(const std::array& s) const; fp inverse() const; bool sqrt(fp& c) const; @@ -53,7 +54,8 @@ class fp static const fp R2; // fp identity squared: R2 = 2^(384*2) mod p static const fp B; // B coefficient from cure equation: y^2 = x^3 + B static const fp twoInv; - static const std::array Q; // scalar field modulus: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 or 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 + static const fp glvPhi1; // glvPhi1 ^ 3 = 1 + static const std::array Q; // scalar field modulus: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 or 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 static const std::array pPlus1Over4; static const std::array pMinus1Over2; static const std::array pMinus3Over4; @@ -92,6 +94,7 @@ class fp2 fp2 sub(const fp2& e) const; void subAssign(const fp2& e); fp2 neg() const; + fp2 conj() const; fp2 mul(const fp2& e) const; void mulAssign(const fp2& e); fp2 square() const; @@ -109,6 +112,8 @@ class fp2 static const fp2 negativeOne2; static const fp2 B; + static const fp2 psiX; + static const fp2 psiY; }; // element representation of 'fp6' field which is cubic extension of 'fp2' field diff --git a/include/g.hpp b/include/g.hpp index 9f42c52..93d1214 100644 --- a/include/g.hpp +++ b/include/g.hpp @@ -54,6 +54,7 @@ class g1 g1 sub(const g1& e) const; template g1 mulScalar(const std::array& s) const; g1 clearCofactor() const; + g1 glvEndomorphism() const; static g1 multiExp(const std::vector& points, const std::vector>& scalars); static g1 mapToCurve(const fp& e); static std::tuple swuMapG1(const fp& e); @@ -104,12 +105,12 @@ class g2 g2 dbl() const; g2 neg() const; g2 sub(const g2& e) const; + g2 psi() const; template g2 mulScalar(const std::array& s) const; g2 clearCofactor() const; g2 frobeniusMap(int64_t power) const; static g2 multiExp(const std::vector& points, const std::vector>& scalars); static g2 mapToCurve(const fp2& e); - static g2 fromMessage(const std::vector& msg, const std::string& dst); static std::tuple swuMapG2(const fp2& e); //static void isogenyMapG2(fp2& x, fp2& y); g2 isogenyMap() const; diff --git a/include/scalar.hpp b/include/scalar.hpp index 8bef0b1..9fb0676 100644 --- a/include/scalar.hpp +++ b/include/scalar.hpp @@ -162,6 +162,20 @@ int64_t cmp(const std::array& a, const std::array& b) return 0; } +// checks two std::arrays for equality: returns true if a == b, false otherwise. +template +bool equal(const std::array& a, const std::array& b) +{ + for(uint64_t i = 0; i < N; i++) + { + if(a[i] != b[i]) + { + return false; + } + } + return true; +} + // returns the length of the absolute value of s in bits. The bit length of 0 is 0. template uint64_t bitLength(const std::array& s) diff --git a/include/signatures.hpp b/include/signatures.hpp index 9ad1de8..f2ce39b 100644 --- a/include/signatures.hpp +++ b/include/signatures.hpp @@ -89,7 +89,7 @@ std::array derive_child_sk_unhardened( uint32_t index ); -g1 derive_shild_g1_unhardened( +g1 derive_child_g1_unhardened( const g1& pk, uint32_t index ); @@ -105,6 +105,11 @@ std::array secret_key(const std::vector& seed); // Derive public key from a BLS private key g1 public_key(const std::array& sk); +g2 fromMessage( + const std::vector& msg, + const std::string& dst +); + // Sign message with a private key g2 sign( const std::array& sk, diff --git a/src/arithmetic.cpp b/src/arithmetic.cpp index a1338e4..37dd6cf 100644 --- a/src/arithmetic.cpp +++ b/src/arithmetic.cpp @@ -1,5 +1,7 @@ -#include "../include/bls12_381.hpp" +#include +#ifdef __x86_64__ #include +#endif using namespace std; @@ -2054,11 +2056,8 @@ tuple Add64( const uint64_t& carry ) { - uint64_t sum = x + y + carry; - // The sum will overflow if both top bits are set (x & y) or if one of them - // is (x | y), and a carry from the lower place happened. If such a carry - // happens, the top bit will be 1 + 0 + 1 = 0 (&^ sum). - uint64_t carryOut = ((x & y) | ((x | y) & ~sum)) >> 63; + uint64_t sum = (x + y) + carry; + uint64_t carryOut = (sum < x); return {sum, carryOut}; } @@ -2073,10 +2072,8 @@ tuple Sub64( const uint64_t& borrow ) { - uint64_t diff, borrowOut; - diff = x - y - borrow; - // See Sub32 for the bit logic. - borrowOut = ((~x & y) | (~(x ^ y) & diff)) >> 63; + uint64_t diff = x - y - borrow; + uint64_t borrowOut = (diff > x); return {diff, borrowOut}; } diff --git a/src/fp.cpp b/src/fp.cpp index 9e794e7..8dccbbb 100644 --- a/src/fp.cpp +++ b/src/fp.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include using namespace std; @@ -143,6 +143,13 @@ fp fp::fromMont() const return c; } +fp fp::phi() const +{ + fp c; + _mul(&c, this, &glvPhi1); + return c; +} + fp fp::inverse() const { if(isZero()) @@ -304,6 +311,15 @@ const fp fp::twoInv = fp({ 0x17fb'b857'1a00'6596 }); +const fp fp::glvPhi1 = fp({ + 0xcd03'c9e4'8671'f071, + 0x5dab'2246'1fcd'a5d2, + 0x5870'42af'd385'1b95, + 0x8eb6'0ebe'01ba'cb9e, + 0x03f9'7d6e'83d0'50d2, + 0x18f0'2065'5463'8741 +}); + const array fp::Q = { 0xffff'ffff'0000'0001, 0x53bd'a402'fffe'5bfe, @@ -491,6 +507,14 @@ fp2 fp2::neg() const return c; } +fp2 fp2::conj() const +{ + fp2 c; + c.c0 = c0; + _neg(&c.c1, &c1); + return c; +} + fp2 fp2::mul(const fp2& e) const { fp t[4]; @@ -521,7 +545,7 @@ void fp2::mulAssign(const fp2& e) fp2 fp2::square() const { - fp t[4]; + fp t[3]; fp2 c; _ladd(&t[0], &c0, &c1); _sub(&t[1], &c0, &c1); @@ -533,7 +557,7 @@ fp2 fp2::square() const void fp2::squareAssign() { - fp t[4]; + fp t[3]; _ladd(&t[0], &c0, &c1); _sub(&t[1], &c0, &c1); _ldouble(&t[2], &c0); @@ -543,17 +567,17 @@ void fp2::squareAssign() fp2 fp2::mulByNonResidue() const { - fp t[4]; + fp t; fp2 c; - _sub(&t[0], &c0, &c1); + _sub(&t, &c0, &c1); _add(&c.c1, &c0, &c1); - c.c0 = t[0]; + c.c0 = t; return c; } fp2 fp2::mulByB() const { - fp t[4]; + fp t[2]; fp2 c; _double(&t[0], &c0); _double(&t[1], &c1); @@ -566,7 +590,7 @@ fp2 fp2::mulByB() const fp2 fp2::inverse() const { - fp t[4]; + fp t[2]; fp2 c; _square(&t[0], &c0); _square(&t[1], &c1); @@ -682,6 +706,44 @@ const fp2 fp2::B = fp2({ }), }); +const fp2 fp2::psiX = fp2({ + fp({ + 0x0000'0000'0000'0000, + 0x0000'0000'0000'0000, + 0x0000'0000'0000'0000, + 0x0000'0000'0000'0000, + 0x0000'0000'0000'0000, + 0x0000'0000'0000'0000, + }), + fp({ + 0x890d'c9e4'8675'45c3, + 0x2af3'2253'3285'a5d5, + 0x5088'0866'309b'7e2c, + 0xa20d'1b8c'7e88'1024, + 0x14e4'f04f'e2db'9068, + 0x14e5'6d3f'1564'853a, + }), +}); + +const fp2 fp2::psiY = fp2({ + fp({ + 0x3e2f'585d'a55c'9ad1, + 0x4294'213d'86c1'8183, + 0x3828'44c8'8b62'3732, + 0x92ad'2afd'1910'3e18, + 0x1d79'4e4f'ac7c'f0b9, + 0x0bd5'92fc'7d82'5ec8, + }), + fp({ + 0x7bcf'a7a2'5aa3'0fda, + 0xdc17'dec1'2a92'7e7c, + 0x2f08'8dd8'6b4e'bef1, + 0xd1ca'2087'da74'd4a7, + 0x2da2'5966'96ce'bc1d, + 0x0e2b'7eed'bbfd'87d2, + }), +}); + fp6::fp6() : c0(fp2()), c1(fp2()), c2(fp2()) { } @@ -927,7 +989,7 @@ void fp6::mulBy01Assign(const fp2& e0, const fp2& e1) fp6 fp6::mulBy01(const fp2& e0, const fp2& e1) const { - fp2 t[6]; + fp2 t[5]; fp6 c; t[0] = c0.mul(e0); t[1] = c1.mul(e1); @@ -950,23 +1012,21 @@ fp6 fp6::mulBy01(const fp2& e0, const fp2& e1) const fp6 fp6::mulBy1(const fp2& e1) const { - fp2 t[6]; + fp2 t; fp6 c; - t[0] = c2.mul(e1); + t = c2.mul(e1); c.c2 = c1.mul(e1); c.c1 = c0.mul(e1); - c.c0 = t[0].mulByNonResidue(); + c.c0 = t.mulByNonResidue(); return c; } fp6 fp6::mulByNonResidue() const { - fp2 t[6]; fp6 c; - t[0] = c0; c.c0 = c2.mulByNonResidue(); c.c2 = c1; - c.c1 = t[0]; + c.c1 = c0; return c; } @@ -981,7 +1041,7 @@ fp6 fp6::mulByBaseField(const fp2& e) const fp6 fp6::inverse() const { - fp2 t[6]; + fp2 t[5]; fp6 c; t[0] = c0.square(); t[1] = c1.mul(c2); @@ -1041,7 +1101,7 @@ void fp6::frobeniusMapAssign(const uint64_t& power) c0.frobeniusMapAssign(power); c1.frobeniusMapAssign(power); c2.frobeniusMapAssign(power); - fp2 t[6]; + fp2 t; switch(power % 6) { case 0: @@ -1050,9 +1110,9 @@ void fp6::frobeniusMapAssign(const uint64_t& power) } case 3: { - _neg(&t[0].c0, &c1.c1); + _neg(&t.c0, &c1.c1); c1.c1 = c1.c0; - c1.c0 = t[0].c0; + c1.c0 = t.c0; c2 = c2.neg(); break; } @@ -1244,7 +1304,7 @@ fp12 fp12::conjugate() const fp12 fp12::square() const { - fp6 t[5]; + fp6 t[4]; fp12 c; t[0] = c0.add(c1); t[2] = c0.mul(c1); @@ -1260,7 +1320,7 @@ fp12 fp12::square() const fp12 fp12::cyclotomicSquare() const { - fp2 t[9]; + fp2 t[7]; fp12 c; tie(t[3], t[4]) = fp4Square(c0.c0, c1.c1); t[2] = t[3].sub(c0.c0); @@ -1289,7 +1349,7 @@ fp12 fp12::cyclotomicSquare() const fp12 fp12::mul(const fp12& e) const { - fp6 t[5]; + fp6 t[4]; fp12 c; t[1] = c0.mul(e.c0); t[2] = c1.mul(e.c1); @@ -1306,7 +1366,7 @@ fp12 fp12::mul(const fp12& e) const void fp12::mulAssign(const fp12& e) { - fp6 t[5]; + fp6 t[4]; t[1] = c0.mul(e.c0); t[2] = c1.mul(e.c1); t[0] = t[1].add(t[2]); @@ -1321,7 +1381,7 @@ void fp12::mulAssign(const fp12& e) tuple fp12::fp4Square(const fp2& e0, const fp2& e1) { - fp2 t[9]; + fp2 t[3]; fp2 c0, c1; t[0] = e0.square(); t[1] = e1.square(); @@ -1336,7 +1396,7 @@ tuple fp12::fp4Square(const fp2& e0, const fp2& e1) fp12 fp12::inverse() const { - fp6 t[5]; + fp6 t[2]; fp12 c; t[0] = c0.square(); t[1] = c1.square(); @@ -1351,7 +1411,7 @@ fp12 fp12::inverse() const void fp12::mulBy014Assign(const fp2& e0, const fp2& e1, const fp2& e4) { - fp6 t[5]; + fp6 t[3]; fp2 t2; t[0] = c0.mulBy01(e0, e1); t[1] = c1.mulBy1(e4); diff --git a/src/g.cpp b/src/g.cpp index 87afbcb..54690a8 100644 --- a/src/g.cpp +++ b/src/g.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include using namespace std; @@ -245,7 +245,7 @@ bool g1::equal(const g1& e) const { return isZero(); } - fp t[9]; + fp t[4]; _square(&t[0], &z); _square(&t[1], &b.z); _mul(&t[2], &t[0], &b.x); @@ -259,7 +259,18 @@ bool g1::equal(const g1& e) const bool g1::inCorrectSubgroup() const { - return mulScalar(fp::Q).isZero(); + // Faster Subgroup Checks for BLS12-381 + // S. Bowe (https://eprint.iacr.org/2019/814.pdf) + // [(x^2 − 1)/3](2σ(P) − P − σ^2(P)) − σ^2(P) ?= O + g1 t0 = this->glvEndomorphism(); + g1 t1 = t0; + t0 = t0.glvEndomorphism(); + t1 = t1.dbl(); + t1 = t1.sub(*this); + t1 = t1.sub(t0); + t1 = t1.mulScalar<2>({0x0000000055555555, 0x396c8c005555e156}); + t1 = t1.sub(t0); + return t1.isZero(); } bool g1::isOnCurve() const @@ -268,7 +279,7 @@ bool g1::isOnCurve() const { return true; } - fp t[9], _b = fp::B; + fp t[4], _b = fp::B; _square(&t[0], &y); _square(&t[1], &x); _mul(&t[1], &t[1], &x); @@ -292,7 +303,7 @@ g1 g1::affine() const return *this; } g1 r = *this; - fp t[9]; + fp t[2]; t[0] = r.z.inverse(); _square(&t[1], &t[0]); _mul(&r.x, &r.x, &t[1]); @@ -362,7 +373,7 @@ g1 g1::dbl() const { return *this; } - fp t[9]; + fp t[5]; g1 r; _square(&t[0], &x); _square(&t[1], &y); @@ -411,6 +422,17 @@ g1 g1::clearCofactor() const return this->mulScalar(cofactorEFF); } +g1 g1::glvEndomorphism() const +{ + if(this->isZero()) + { + return zero(); + } + g1 t = this->affine(); + t.x = t.x.phi(); + return t; +} + // MultiExp calculates multi exponentiation. Given pairs of G1 point and scalar values // (P_0, e_0), (P_1, e_1), ... (P_n, e_n) calculates r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n // Length of points and scalars are expected to be equal, otherwise an error is thrown. @@ -911,7 +933,21 @@ bool g2::equal(const g2& e) const bool g2::inCorrectSubgroup() const { - return mulScalar(fp::Q).isZero(); + // Faster Subgroup Checks for BLS12-381 + // S. Bowe (https://eprint.iacr.org/2019/814.pdf) + // [z]ψ^3(P) − ψ^2(P) + P = O + g2 t0, t1; + t0 = this->psi(); + t0 = t0.psi(); + t1 = t0.neg(); // - ψ^2(P) + t0 = t0.psi(); // ψ^3(P) + t0 = t0.mulScalar(cofactorEFF); // - x ψ^3(P) + t0 = t0.neg(); + + t0 = t0.add(t1); + t0 = t0.add(*this); + + return t0.isZero(); } bool g2::isOnCurve() const @@ -1058,6 +1094,17 @@ g2 g2::sub(const g2& e) const return c; } +g2 g2::psi() const +{ + g2 p; + p.x = this->x.conj(); + p.y = this->y.conj(); + p.z = this->z.conj(); + p.x = p.x.mul(fp2::psiX); + p.y = p.y.mul(fp2::psiY); + return p; +} + g2 g2::clearCofactor() const { g2 t0, t1, t2, t3; @@ -1177,35 +1224,6 @@ g2 g2::mapToCurve(const fp2& e) return p; } -g2 g2::fromMessage(const vector& msg, const string& dst) -{ - uint8_t buf[4 * 64]; - xmd_sh256(buf, 4 * 64, msg.data(), msg.size(), reinterpret_cast(dst.c_str()), dst.length()); - - array k = {0}; - fp2 t = fp2::zero(); - fp2 x, y, z = fp2::one(); - g2 p, q; - - k = scalar::fromBytesBE<8>(span(buf, buf + 64)); - t.c0 = fp::modPrime(k); - k = scalar::fromBytesBE<8>(span(buf + 64, buf + 2*64)); - t.c1 = fp::modPrime(k); - - tie(x, y) = swuMapG2(t); - p = g2({x, y, z}).isogenyMap(); - - k = scalar::fromBytesBE<8>(span(buf + 2*64, buf + 3*64)); - t.c0 = fp::modPrime(k); - k = scalar::fromBytesBE<8>(span(buf + 3*64, buf + 4*64)); - t.c1 = fp::modPrime(k); - - tie(x, y) = swuMapG2(t); - q = g2({x, y, z}).isogenyMap(); - - return p.add(q).clearCofactor(); -} - tuple g2::swuMapG2(const fp2& e) { struct swuParamsForG2 diff --git a/src/groth16.cpp b/src/groth16.cpp index 803203e..64a9c07 100644 --- a/src/groth16.cpp +++ b/src/groth16.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include using namespace std; diff --git a/src/pairing.cpp b/src/pairing.cpp index e68a9c0..daa3b98 100644 --- a/src/pairing.cpp +++ b/src/pairing.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include using namespace std; diff --git a/src/scalar.cpp b/src/scalar.cpp index 98e255e..4c74e48 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include using namespace std; diff --git a/src/signatures.cpp b/src/signatures.cpp index 728f78e..c69c2f2 100644 --- a/src/signatures.cpp +++ b/src/signatures.cpp @@ -1,4 +1,4 @@ -#include "../include/bls12_381.hpp" +#include #include "sha256.hpp" #include @@ -173,7 +173,8 @@ array secret_key(const vector& seed) } // "BLS-SIG-KEYGEN-SALT-" in ascii - const uint8_t saltHkdf[20] = {66, 76, 83, 45, 83, 73, 71, 45, 75, 69, 89, 71, 69, 78, 45, 83, 65, 76, 84, 45}; + uint8_t saltHkdf[32] = {66, 76, 83, 45, 83, 73, 71, 45, 75, 69, 89, 71, 69, 78, 45, 83, 65, 76, 84, 45}; + uint8_t saltLen = 20; uint8_t *ikmHkdf = reinterpret_cast(malloc(seed.size() + 1)); memcpy(ikmHkdf, &seed[0], seed.size()); @@ -188,30 +189,44 @@ array secret_key(const vector& seed) keyInfoHkdf[infoLen] = 0; // Two bytes for L, 0 and 48 keyInfoHkdf[infoLen + 1] = L; - hkdf256_extract_expand( - okmHkdf.data(), - L, - ikmHkdf, - seed.size() + 1, - saltHkdf, - 20, - keyInfoHkdf, - infoLen + 2 - ); - - // Make sure private key is less than the curve order - array skBn = scalar::fromBytesBE<6>(span(okmHkdf.begin(), okmHkdf.end())); - array quotient = {0, 0, 0, 0, 0, 0}; - array remainder = {0, 0, 0, 0, 0, 0}; - // be conservative with scratch memory (https://github.com/relic-toolkit/relic/blob/ddd1984a76aa9c96a12ebdf5c6786b0ee6a26ef8/src/bn/relic_bn_div.c#L79) - // with gcc array q = fp::Q works fine but clang needs the two extra words - array q = {fp::Q[0], fp::Q[1], fp::Q[2], fp::Q[3], 0, 0}; - bn_divn_low(quotient.data(), remainder.data(), skBn.data(), 6, q.data(), 4); - array k = {remainder[0], remainder[1], remainder[2], remainder[3]}; + array sk; + while(true) + { + hkdf256_extract_expand( + okmHkdf.data(), + L, + ikmHkdf, + seed.size() + 1, + saltHkdf, + saltLen, + keyInfoHkdf, + infoLen + 2 + ); + + // Make sure private key is less than the curve order + array skBn = scalar::fromBytesBE<6>(span(okmHkdf.begin(), okmHkdf.end())); + array quotient = {0, 0, 0, 0, 0, 0}; + array remainder = {0, 0, 0, 0, 0, 0}; + // be conservative with scratch memory (https://github.com/relic-toolkit/relic/blob/ddd1984a76aa9c96a12ebdf5c6786b0ee6a26ef8/src/bn/relic_bn_div.c#L79) + // with gcc array q = fp::Q works fine but clang needs the two extra words + array q = {fp::Q[0], fp::Q[1], fp::Q[2], fp::Q[3], 0, 0}; + bn_divn_low(quotient.data(), remainder.data(), skBn.data(), 6, q.data(), 4); + sk = {remainder[0], remainder[1], remainder[2], remainder[3]}; + + if(!scalar::equal<4>(sk, {0, 0, 0, 0})) + { + break; + } + + sha256 sha; + sha.update(saltHkdf, saltLen); + sha.digest(saltHkdf); + saltLen = sizeof(saltHkdf); + } free(ikmHkdf); - return k; + return sk; } void ikm_to_lamport_sk( @@ -307,7 +322,7 @@ array derive_child_sk_unhardened( return ret; } -g1 derive_shild_g1_unhardened( +g1 derive_child_g1_unhardened( const g1& pk, uint32_t index ) @@ -470,12 +485,45 @@ void xmd_sh256( } } + +g2 fromMessage( + const vector& msg, + const string& dst +) +{ + uint8_t buf[4 * 64]; + xmd_sh256(buf, 4 * 64, msg.data(), msg.size(), reinterpret_cast(dst.c_str()), dst.length()); + + array k = {0}; + fp2 t = fp2::zero(); + fp2 x, y, z = fp2::one(); + g2 p, q; + + k = scalar::fromBytesBE<8>(span(buf, buf + 64)); + t.c0 = fp::modPrime(k); + k = scalar::fromBytesBE<8>(span(buf + 64, buf + 2*64)); + t.c1 = fp::modPrime(k); + + tie(x, y) = g2::swuMapG2(t); + p = g2({x, y, z}).isogenyMap(); + + k = scalar::fromBytesBE<8>(span(buf + 2*64, buf + 3*64)); + t.c0 = fp::modPrime(k); + k = scalar::fromBytesBE<8>(span(buf + 3*64, buf + 4*64)); + t.c1 = fp::modPrime(k); + + tie(x, y) = g2::swuMapG2(t); + q = g2({x, y, z}).isogenyMap(); + + return p.add(q).clearCofactor(); +} + g2 sign( const array& sk, const vector& msg ) { - g2 p = g2::fromMessage(msg, CIPHERSUITE_ID); + g2 p = fromMessage(msg, CIPHERSUITE_ID); return p.mulScalar(sk); } @@ -487,7 +535,7 @@ bool verify( { vector> v; pairing::add_pair(v, g1::one().neg(), signature); - const g2 hashedPoint = g2::fromMessage(message, CIPHERSUITE_ID); + const g2 hashedPoint = fromMessage(message, CIPHERSUITE_ID); pairing::add_pair(v, pubkey, hashedPoint); if(!pubkey.isOnCurve() || !pubkey.inCorrectSubgroup()) @@ -564,7 +612,7 @@ bool aggregate_verify( { return false; } - pairing::add_pair(v, pubkeys[i], g2::fromMessage(messages[i], CIPHERSUITE_ID)); + pairing::add_pair(v, pubkeys[i], fromMessage(messages[i], CIPHERSUITE_ID)); } // 1 =? prod e(pubkey[i], hash[i]) * e(-g1, aggSig) @@ -575,7 +623,7 @@ g2 pop_prove(const array& sk) { g1 pk = public_key(sk); array msg = pk.toCompressedBytesBE(); - g2 hashed_key = g2::fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); + g2 hashed_key = fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); return hashed_key.mulScalar(sk); } @@ -585,7 +633,7 @@ bool pop_verify( ) { array msg = pubkey.toCompressedBytesBE(); - const g2 hashedPoint = g2::fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); + const g2 hashedPoint = fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); if(!pubkey.isOnCurve() || !pubkey.inCorrectSubgroup()) { diff --git a/test/unittests.cpp b/test/unittests.cpp index 9c282d0..e2f3932 100644 --- a/test/unittests.cpp +++ b/test/unittests.cpp @@ -1283,7 +1283,7 @@ void TestUnhardenedHDKeys() g1 pk = public_key(sk); array childSk = derive_child_sk_unhardened(sk, 42); - g1 childPk = derive_shild_g1_unhardened(pk, 42); + g1 childPk = derive_child_g1_unhardened(pk, 42); if(!public_key(childSk).equal(childPk)) { @@ -1291,7 +1291,7 @@ void TestUnhardenedHDKeys() } array grandchildSk = derive_child_sk_unhardened(childSk, 12142); - g1 grandcihldPk = derive_shild_g1_unhardened(childPk, 12142); + g1 grandcihldPk = derive_child_g1_unhardened(childPk, 12142); if(!public_key(grandchildSk).equal(grandcihldPk)) { @@ -1305,7 +1305,7 @@ void TestUnhardenedHDKeys() g1 pk = public_key(sk); array childSk = derive_child_sk_unhardened(sk, 42); - g1 childPk = derive_shild_g1_unhardened(pk, 42); + g1 childPk = derive_child_g1_unhardened(pk, 42); array childSkHardened = derive_child_sk(sk, 42); if(!public_key(childSk).equal(childPk))