diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 17ea4160f..eadc78c0b 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 @@ -421,8 +428,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 e455a648d..064e120d2 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 0f06e46fa..990d7e85d 100644 --- a/ecc/bls12-377/g2.go +++ b/ecc/bls12-377/g2.go @@ -403,8 +403,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 529dcc76a..2c11f06a2 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 d2de48d6b..450562473 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 cd9a00d5f..5df0961a2 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 a1e14cf60..691130592 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 @@ -421,8 +428,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 672b3f9fa..cec6e3fb3 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 ba6437496..3764ea0b3 100644 --- a/ecc/bls12-378/g2.go +++ b/ecc/bls12-378/g2.go @@ -403,8 +403,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 2d360a2d8..fea205aa1 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 536837999..a90486611 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 c25370465..b5b97a56f 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 8eb803c3b..d24561f77 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 @@ -421,8 +428,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 586d9d683..6214372cd 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 798337382..d975486e5 100644 --- a/ecc/bls12-381/g2.go +++ b/ecc/bls12-381/g2.go @@ -404,8 +404,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 4905c7b91..d42bab005 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 1ccfa6c70..095a79a4c 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 b864d1c79..04ebbbf57 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 26f0c28fe..768a64db6 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 @@ -423,8 +430,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 7251a9e2e..a2c861037 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 4b6062206..f82a90e73 100644 --- a/ecc/bls24-315/g2.go +++ b/ecc/bls24-315/g2.go @@ -405,8 +405,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 6a98aa51e..a9d4d67fc 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 5a7af0fdf..3cefb7194 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 a197a7490..cb773a214 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 c6dd46698..2cc50343e 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 @@ -423,8 +430,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 8f62e1fb8..6e539ce9b 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 728ec59b1..9671b794d 100644 --- a/ecc/bls24-317/g2.go +++ b/ecc/bls24-317/g2.go @@ -405,8 +405,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 94026ccfc..d19a699a0 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 85af0a8cd..e2a9a0946 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 8d98e93ca..c7a8c4bf1 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 c03823d25..e854d5071 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 @@ -411,8 +418,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 b7a17b61d..92b0c5d73 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 bb57fe175..2d7dfc62c 100644 --- a/ecc/bn254/g2.go +++ b/ecc/bn254/g2.go @@ -410,8 +410,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 0690bf900..8d8dba872 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 29093174b..a9f6d28e9 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 050e4e50b..b6a7e4349 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 5bb8d1f9e..6c8932457 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 @@ -426,8 +433,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 7bdf11483..1e4dc1e46 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 cce9c360c..f53f6a9df 100644 --- a/ecc/bw6-633/g2.go +++ b/ecc/bw6-633/g2.go @@ -405,8 +405,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 5b5b9a59a..8028e3856 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 c04aedc07..fe757a19c 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 d4809517f..18be2657d 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 5cad95ab9..fa25b8d41 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 @@ -430,8 +437,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 b8e6964a8..abb6358cc 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 40be72f49..6b2d7dd70 100644 --- a/ecc/bw6-756/g2.go +++ b/ecc/bw6-756/g2.go @@ -409,8 +409,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 0c5699b79..7264c7bd7 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 530287414..06f572ea8 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 0ea87f0de..9a3a4d7b4 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 3f00288a0..7c0e5a685 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 @@ -430,8 +437,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 6f342aa51..079c25533 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 9f6ccbf13..2909a1ee6 100644 --- a/ecc/bw6-761/g2.go +++ b/ecc/bw6-761/g2.go @@ -409,8 +409,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 55f053a3d..215d3a582 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 09c1e52a8..76e63b34e 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 c1fb3ee88..023a840b0 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 862e9c6ac..4eaa0577a 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 @@ -411,8 +418,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 252e46aef..a08ab7879 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 d4e0fe760..9a9c95a91 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}} @@ -626,8 +637,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 932221628..bed43788e 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 6f875e675..d57110303 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 6a5eb4912..721ba961b 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)