diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 43410258db..fe15a31d9b 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -434,8 +441,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index fa77d44d54..0ec94c0c80 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-377-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bls12-377/g2.go b/ecc/bls12-377/g2.go index 8e00397996..a7594cfc6d 100644 --- a/ecc/bls12-377/g2.go +++ b/ecc/bls12-377/g2.go @@ -416,8 +416,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-377/g2_test.go b/ecc/bls12-377/g2_test.go index e5425aa87a..3702b58a50 100644 --- a/ecc/bls12-377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -248,6 +248,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-377-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E2) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bls12-377/internal/fptower/e12.go b/ecc/bls12-377/internal/fptower/e12.go index d2de48d6b3..4505624732 100644 --- a/ecc/bls12-377/internal/fptower/e12.go +++ b/ecc/bls12-377/internal/fptower/e12.go @@ -610,8 +610,14 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bls12-377/pairing_test.go b/ecc/bls12-377/pairing_test.go index cd9a00d5f9..5df0961a24 100644 --- a/ecc/bls12-377/pairing_test.go +++ b/ecc/bls12-377/pairing_test.go @@ -45,7 +45,6 @@ func TestPairing(t *testing.T) { genA := GenE12() genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BLS12-377] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -64,28 +63,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS12-377] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BLS12-377] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BLS12-377] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 03f555f7c2..ba42cd1584 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -434,8 +441,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-378/g1_test.go b/ecc/bls12-378/g1_test.go index 473fa6206f..ebd0bc648d 100644 --- a/ecc/bls12-378/g1_test.go +++ b/ecc/bls12-378/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-378-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-378] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bls12-378/g2.go b/ecc/bls12-378/g2.go index c0bf26edc6..960c787300 100644 --- a/ecc/bls12-378/g2.go +++ b/ecc/bls12-378/g2.go @@ -416,8 +416,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-378/g2_test.go b/ecc/bls12-378/g2_test.go index 65ac23a1ac..be2ab68608 100644 --- a/ecc/bls12-378/g2_test.go +++ b/ecc/bls12-378/g2_test.go @@ -248,6 +248,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-378-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-378] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E2) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bls12-378/internal/fptower/e12.go b/ecc/bls12-378/internal/fptower/e12.go index 536837999c..a904866113 100644 --- a/ecc/bls12-378/internal/fptower/e12.go +++ b/ecc/bls12-378/internal/fptower/e12.go @@ -610,8 +610,14 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bls12-378/pairing_test.go b/ecc/bls12-378/pairing_test.go index c253704653..b5b97a56f3 100644 --- a/ecc/bls12-378/pairing_test.go +++ b/ecc/bls12-378/pairing_test.go @@ -45,7 +45,6 @@ func TestPairing(t *testing.T) { genA := GenE12() genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BLS12-378] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -64,28 +63,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS12-378] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BLS12-378] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BLS12-378] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index 5ba2d93d81..c5be10ed8a 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -434,8 +441,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index 9f226fd4ac..05f2f7e25f 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-381-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bls12-381/g2.go b/ecc/bls12-381/g2.go index d40cf1a6f7..c6d0fafa89 100644 --- a/ecc/bls12-381/g2.go +++ b/ecc/bls12-381/g2.go @@ -417,8 +417,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls12-381/g2_test.go b/ecc/bls12-381/g2_test.go index 34dfa1ece6..1babf7ec8c 100644 --- a/ecc/bls12-381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -248,6 +248,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS12-381-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS12-381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E2) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bls12-381/internal/fptower/e12.go b/ecc/bls12-381/internal/fptower/e12.go index 1ccfa6c70a..095a79a4c0 100644 --- a/ecc/bls12-381/internal/fptower/e12.go +++ b/ecc/bls12-381/internal/fptower/e12.go @@ -610,8 +610,14 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bls12-381/pairing_test.go b/ecc/bls12-381/pairing_test.go index b864d1c798..04ebbbf577 100644 --- a/ecc/bls12-381/pairing_test.go +++ b/ecc/bls12-381/pairing_test.go @@ -45,7 +45,6 @@ func TestPairing(t *testing.T) { genA := GenE12() genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BLS12-381] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -64,28 +63,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS12-381] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BLS12-381] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BLS12-381] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index 903fbad19a..5da6c2e134 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -436,8 +443,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index eb0e8693c6..b84a440f8c 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS24-315-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS24-315] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bls24-315/g2.go b/ecc/bls24-315/g2.go index 541a06ef28..5ad43d49eb 100644 --- a/ecc/bls24-315/g2.go +++ b/ecc/bls24-315/g2.go @@ -418,8 +418,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls24-315/g2_test.go b/ecc/bls24-315/g2_test.go index 6ad91794f4..ed6f46d545 100644 --- a/ecc/bls24-315/g2_test.go +++ b/ecc/bls24-315/g2_test.go @@ -248,6 +248,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS24-315-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS24-315] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E4) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bls24-315/internal/fptower/e24.go b/ecc/bls24-315/internal/fptower/e24.go index 5a7af0fdf4..3cefb71948 100644 --- a/ecc/bls24-315/internal/fptower/e24.go +++ b/ecc/bls24-315/internal/fptower/e24.go @@ -599,8 +599,14 @@ func (z *E24) ExpGLV(x E24, k *big.Int) *E24 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1)/2 + 1; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bls24-315/pairing_test.go b/ecc/bls24-315/pairing_test.go index a197a7490b..cb773a2145 100644 --- a/ecc/bls24-315/pairing_test.go +++ b/ecc/bls24-315/pairing_test.go @@ -46,7 +46,6 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BLS24-315] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -65,29 +64,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS24-315] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(24) - - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BLS24-315] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BLS24-315] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 76a8ccabe9..689f962005 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -436,8 +443,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index 371e3e47a2..e624076b1d 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS24-317-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS24-317] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bls24-317/g2.go b/ecc/bls24-317/g2.go index 7fde5e070b..29bad5b099 100644 --- a/ecc/bls24-317/g2.go +++ b/ecc/bls24-317/g2.go @@ -418,8 +418,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bls24-317/g2_test.go b/ecc/bls24-317/g2_test.go index 23d6e154c6..c46c57716b 100644 --- a/ecc/bls24-317/g2_test.go +++ b/ecc/bls24-317/g2_test.go @@ -248,6 +248,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BLS24-317-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BLS24-317] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E4) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bls24-317/internal/fptower/e24.go b/ecc/bls24-317/internal/fptower/e24.go index 85af0a8cd1..e2a9a09462 100644 --- a/ecc/bls24-317/internal/fptower/e24.go +++ b/ecc/bls24-317/internal/fptower/e24.go @@ -521,8 +521,14 @@ func (z *E24) ExpGLV(x E24, k *big.Int) *E24 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1)/2 + 1; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bls24-317/pairing_test.go b/ecc/bls24-317/pairing_test.go index 8d98e93cab..c7a8c4bf18 100644 --- a/ecc/bls24-317/pairing_test.go +++ b/ecc/bls24-317/pairing_test.go @@ -46,7 +46,6 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BLS24-317] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -65,28 +64,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS24-317] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BLS24-317] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BLS24-317] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index eff9e13cc0..4c0a294980 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -424,8 +431,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index 75b9187557..c973e4cbdd 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BN254-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BN254] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bn254/g2.go b/ecc/bn254/g2.go index f9de9cf7cf..d0da8e60ea 100644 --- a/ecc/bn254/g2.go +++ b/ecc/bn254/g2.go @@ -423,8 +423,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bn254/g2_test.go b/ecc/bn254/g2_test.go index c4567c018c..14646d4bbc 100644 --- a/ecc/bn254/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -247,6 +247,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BN254-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BN254] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fptower.E2) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bn254/internal/fptower/e12.go b/ecc/bn254/internal/fptower/e12.go index 29093174b5..a9f6d28e9b 100644 --- a/ecc/bn254/internal/fptower/e12.go +++ b/ecc/bn254/internal/fptower/e12.go @@ -610,8 +610,14 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bn254/pairing_test.go b/ecc/bn254/pairing_test.go index 050e4e50b2..b6a7e43496 100644 --- a/ecc/bn254/pairing_test.go +++ b/ecc/bn254/pairing_test.go @@ -45,7 +45,6 @@ func TestPairing(t *testing.T) { genA := GenE12() genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BN254] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -64,28 +63,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BN254] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BN254] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BN254] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index e9d45e8a39..05a610276c 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -439,8 +446,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index 4d5fa5c93b..51576b39f0 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-633-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-633] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bw6-633/g2.go b/ecc/bw6-633/g2.go index 5854962950..ed44d59d4f 100644 --- a/ecc/bw6-633/g2.go +++ b/ecc/bw6-633/g2.go @@ -418,8 +418,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-633/g2_test.go b/ecc/bw6-633/g2_test.go index c50010d060..d47bac2f56 100644 --- a/ecc/bw6-633/g2_test.go +++ b/ecc/bw6-633/g2_test.go @@ -234,6 +234,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-633-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-633] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bw6-633/internal/fptower/e6.go b/ecc/bw6-633/internal/fptower/e6.go index c04aedc072..fe757a19c0 100644 --- a/ecc/bw6-633/internal/fptower/e6.go +++ b/ecc/bw6-633/internal/fptower/e6.go @@ -599,8 +599,14 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bw6-633/pairing_test.go b/ecc/bw6-633/pairing_test.go index d4809517f7..18be2657d8 100644 --- a/ecc/bw6-633/pairing_test.go +++ b/ecc/bw6-633/pairing_test.go @@ -46,7 +46,6 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BW6-633] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -65,29 +64,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BW6-633] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(6) - - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BW6-633] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BW6-633] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index b31c1e4645..045b384c65 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -443,8 +450,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-756/g1_test.go b/ecc/bw6-756/g1_test.go index da3edfaf1a..81c0eab486 100644 --- a/ecc/bw6-756/g1_test.go +++ b/ecc/bw6-756/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-756-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-756] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bw6-756/g2.go b/ecc/bw6-756/g2.go index 1826664a6b..fdeb5e14c4 100644 --- a/ecc/bw6-756/g2.go +++ b/ecc/bw6-756/g2.go @@ -422,8 +422,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-756/g2_test.go b/ecc/bw6-756/g2_test.go index fe33bc2e2c..6c79825c53 100644 --- a/ecc/bw6-756/g2_test.go +++ b/ecc/bw6-756/g2_test.go @@ -234,6 +234,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-756-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-756] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bw6-756/internal/fptower/e6.go b/ecc/bw6-756/internal/fptower/e6.go index 5302874149..06f572ea8c 100644 --- a/ecc/bw6-756/internal/fptower/e6.go +++ b/ecc/bw6-756/internal/fptower/e6.go @@ -522,8 +522,14 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bw6-756/pairing_test.go b/ecc/bw6-756/pairing_test.go index 0ea87f0de9..9a3a4d7b4f 100644 --- a/ecc/bw6-756/pairing_test.go +++ b/ecc/bw6-756/pairing_test.go @@ -46,7 +46,6 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BW6-756] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -65,28 +64,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BW6-756] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BW6-756] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BW6-756] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index ffa552d0b5..04d23cc9d4 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -443,8 +450,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index 0637db0c46..d15ae3a9f4 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-761-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/ecc/bw6-761/g2.go b/ecc/bw6-761/g2.go index 2d52afa5db..5aa68749ae 100644 --- a/ecc/bw6-761/g2.go +++ b/ecc/bw6-761/g2.go @@ -422,8 +422,15 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/bw6-761/g2_test.go b/ecc/bw6-761/g2_test.go index 634a91e1ea..563aec5081 100644 --- a/ecc/bw6-761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -234,6 +234,37 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[BW6-761-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g2GenAff + var gj G2Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G2Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G2Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[BW6-761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG2Jac(&g2Gen, a) diff --git a/ecc/bw6-761/internal/fptower/e6.go b/ecc/bw6-761/internal/fptower/e6.go index 09c1e52a89..76e63b34ef 100644 --- a/ecc/bw6-761/internal/fptower/e6.go +++ b/ecc/bw6-761/internal/fptower/e6.go @@ -522,8 +522,14 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res) diff --git a/ecc/bw6-761/pairing_test.go b/ecc/bw6-761/pairing_test.go index c1fb3ee884..023a840b03 100644 --- a/ecc/bw6-761/pairing_test.go +++ b/ecc/bw6-761/pairing_test.go @@ -46,7 +46,6 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[BW6-761] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -65,29 +64,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BW6-761] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - - k := new(big.Int).SetUint64(6) - - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[BW6-761] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[BW6-761] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index cc5ce27b41..8631a67672 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -23,8 +23,15 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" "math/big" "runtime" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // G1Affine point in affine coordinates type G1Affine struct { X, Y fp.Element @@ -424,8 +431,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/ecc/secp256k1/g1_test.go b/ecc/secp256k1/g1_test.go index fe2bae69d8..aa2fbb832d 100644 --- a/ecc/secp256k1/g1_test.go +++ b/ecc/secp256k1/g1_test.go @@ -247,6 +247,37 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() + properties.Property("[SECP256K1-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := g1GenAff + var gj G1Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 G1Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 G1Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[SECP256K1] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzG1Jac(&g1Gen, a) diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index 5ae345f67c..8736632ec6 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -8,6 +8,9 @@ import ( "math/big" "runtime" + {{- if eq .PointName "g1"}} + "sync" + {{- end }} {{- if .GLV}} "github.com/consensys/gnark-crypto/ecc" @@ -21,6 +24,14 @@ import ( {{- end}} ) +{{- if eq .PointName "g1"}} +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} +{{- end}} + // {{ $TAffine }} point in affine coordinates type {{ $TAffine }} struct { X, Y {{.CoordType}} @@ -639,8 +650,15 @@ func (p *{{ $TJacobian }}) mulWindowed(a *{{ $TJacobian }}, s *big.Int) *{{ $TJa var res {{ $TJacobian }} var ops [3]{{ $TJacobian }} - res.Set(&{{ toLower .PointName}}Infinity) ops[0].Set(a) + e := s + if s.Sign() == -1 { + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(s) + ops[0].Neg(&ops[0]) + } + res.Set(&{{ toLower .PointName}}Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index ccb1384a0f..07626858dc 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -282,6 +282,37 @@ func Test{{ $TAffine }}Ops(t *testing.T) { genScalar := GenFr() + properties.Property("[{{ toUpper .Name }}-381] [-s]G = -[s]G", prop.ForAll( + func(s fr.Element) bool { + g := {{ toLower .PointName }}GenAff + var gj {{ toUpper .PointName }}Jac + var nbs, bs big.Int + s.BigInt(&bs) + nbs.Neg(&bs) + + var res = true + + // mulGLV + { + var op1, op2 {{ toUpper .PointName }}Affine + op1.ScalarMultiplication(&g, &bs).Neg(&op1) + op2.ScalarMultiplication(&g, &nbs) + res = res && op1.Equal(&op2) + } + + // mulWindowed + { + var op1, op2 {{ toUpper .PointName }}Jac + op1.mulWindowed(&gj, &bs).Neg(&op1) + op2.mulWindowed(&gj, &nbs) + res = res && op1.Equal(&op2) + } + + return res + }, + GenFr(), + )) + properties.Property("[{{ toUpper .Name }}] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b {{ .CoordType}}) bool { fop1 := fuzz{{ $TJacobian }}(&{{ toLower .PointName }}Gen, a) diff --git a/internal/generator/pairing/template/tests/pairing.go.tmpl b/internal/generator/pairing/template/tests/pairing.go.tmpl index 6f875e6751..d57110303d 100644 --- a/internal/generator/pairing/template/tests/pairing.go.tmpl +++ b/internal/generator/pairing/template/tests/pairing.go.tmpl @@ -33,7 +33,6 @@ func TestPairing(t *testing.T) { {{- end}} genR1 := GenFr() genR2 := GenFr() - genP := GenFp() properties.Property("[{{ toUpper .Name}}] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a GT) bool { @@ -52,33 +51,39 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[{{ toUpper .Name}}] Exp, CyclotomicExp and ExpGLV results must be the same in GT", prop.ForAll( - func(a GT, e fp.Element) bool { - a = FinalExponentiation(&a) - - var _e, ne big.Int - {{if or (eq .Name "bw6-761") (eq .Name "bw6-633")}} - k := new(big.Int).SetUint64(6) - {{else if eq .Name "bls24-315"}} - k := new(big.Int).SetUint64(24) - {{ else }} - k := new(big.Int).SetUint64(12) - {{- end}} - e.Exp(e, k) - e.BigInt(&_e) - ne.Neg(&_e) + properties.Property("[{{ toUpper .Name}}] Exp, CyclotomicExp and ExpGLV results must be the same in GT (small and big exponents)", prop.ForAll( + func(a GT, e fr.Element, ) bool { + + var res bool + + // exponent > r + { + a = FinalExponentiation(&a) + var _e big.Int + _e.SetString("169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073169893631828481842931290008859743243489098146141979830311893424751855271950692001433356165550548410610101138388623573573742608490725625288296502860183437011025036209791574001140592327223981416956942076610555083128655330944007957223952510233203018053264066056080064687038560794652180979019775788172491868553073", 10) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = b.Equal(&c) && c.Equal(&d) + } - var b, c, d GT - b.Exp(a, &ne) - b.Inverse(&b) - c.ExpGLV(a, &ne) - c.Conjugate(&c) - d.CyclotomicExp(a, &_e) + // exponent < r + { + a = FinalExponentiation(&a) + var _e big.Int + e.BigInt(&_e) + var b, c, d GT + b.Exp(a, &_e) + c.ExpGLV(a, &_e) + d.CyclotomicExp(a, &_e) + res = res && b.Equal(&c) && c.Equal(&d) + } - return b.Equal(&c) && c.Equal(&d) + return res }, genA, - genP, + genR1, )) properties.Property("[{{ toUpper .Name}}] Expt(Expt) and Exp(t^2) should output the same result in the cyclotomic subgroup", prop.ForAll( diff --git a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl index 6a5eb49124..721ba961b1 100644 --- a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl @@ -587,8 +587,14 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { s1 = s1.SetBigInt(&s[0]).Bits() s2 = s2.SetBigInt(&s[1]).Bits() + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + // loop starts from len(s1)/2 due to the bounds - for i := len(s1) / 2; i >= 0; i-- { + for i := hiWordIndex ; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.CyclotomicSquare(&res).CyclotomicSquare(&res)