From 8d02a7e8d93cff7dde2c688a6c4665448033c3fd Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 27 Jul 2022 22:15:56 +0100 Subject: [PATCH] batch point conversion: explicitly overwrite (0,0) when point at inf + test (#225) * test(all): test Batch aff conv. + explicitly out (0,0) when point at inf * fix: avoid out-of-bounds access in batch point conversion * fix: since results is allocated in BatchJacobianToAffine, inf -> inf is implicit Co-authored-by: Gautam Botrel --- ecc/bls12-377/g1.go | 17 ++++++----- ecc/bls12-377/g1_test.go | 15 +++++++++- ecc/bls12-377/g2_test.go | 2 +- ecc/bls12-378/g1.go | 17 ++++++----- ecc/bls12-378/g1_test.go | 15 +++++++++- ecc/bls12-378/g2_test.go | 2 +- ecc/bls12-381/g1.go | 17 ++++++----- ecc/bls12-381/g1_test.go | 15 +++++++++- ecc/bls12-381/g2_test.go | 2 +- ecc/bls24-315/g1.go | 17 ++++++----- ecc/bls24-315/g1_test.go | 15 +++++++++- ecc/bls24-315/g2_test.go | 2 +- ecc/bls24-317/g1.go | 17 ++++++----- ecc/bls24-317/g1_test.go | 15 +++++++++- ecc/bls24-317/g2_test.go | 2 +- ecc/bn254/g1.go | 17 ++++++----- ecc/bn254/g1_test.go | 15 +++++++++- ecc/bn254/g2_test.go | 2 +- ecc/bw6-633/g1.go | 28 +++++++++---------- ecc/bw6-633/g1_test.go | 15 +++++++++- ecc/bw6-633/g2_test.go | 2 +- ecc/bw6-633/pairing.go | 6 ++-- ecc/bw6-756/g1.go | 28 +++++++++---------- ecc/bw6-756/g1_test.go | 15 +++++++++- ecc/bw6-756/g2_test.go | 2 +- ecc/bw6-756/pairing.go | 6 ++-- ecc/bw6-761/g1.go | 28 +++++++++---------- ecc/bw6-761/g1_test.go | 15 +++++++++- ecc/bw6-761/g2_test.go | 2 +- ecc/bw6-761/pairing.go | 6 ++-- internal/generator/ecc/template/point.go.tmpl | 28 +++++++++---------- .../ecc/template/tests/point.go.tmpl | 18 +++++++++++- 32 files changed, 262 insertions(+), 141 deletions(-) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index d6fb2bf3cc..f93ed7e3ee 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -822,9 +822,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -844,7 +844,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -855,7 +855,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -867,6 +867,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -930,8 +931,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -973,7 +973,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index 946a918e73..3209de0cd2 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BLS12-377] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls12-377/g2_test.go b/ecc/bls12-377/g2_test.go index 74c30f7531..d3b0af12be 100644 --- a/ecc/bls12-377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -99,7 +99,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 780c078869..52624acb85 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -822,9 +822,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -844,7 +844,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -855,7 +855,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -867,6 +867,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -930,8 +931,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -973,7 +973,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bls12-378/g1_test.go b/ecc/bls12-378/g1_test.go index 07a7397936..dccaca15c7 100644 --- a/ecc/bls12-378/g1_test.go +++ b/ecc/bls12-378/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BLS12-378] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls12-378/g2_test.go b/ecc/bls12-378/g2_test.go index bac94d78a4..21e79d7238 100644 --- a/ecc/bls12-378/g2_test.go +++ b/ecc/bls12-378/g2_test.go @@ -99,7 +99,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index f7c8835fec..1c2daaa560 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -822,9 +822,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -844,7 +844,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -855,7 +855,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -867,6 +867,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -930,8 +931,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -973,7 +973,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index 34b5d86d53..9aa3311f05 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BLS12-381] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls12-381/g2_test.go b/ecc/bls12-381/g2_test.go index 3e5d329a18..c259606622 100644 --- a/ecc/bls12-381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -99,7 +99,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index 0f0149b9da..c5d5ccd8b0 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -824,9 +824,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -846,7 +846,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -857,7 +857,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -869,6 +869,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -932,8 +933,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -975,7 +975,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index 4b57336182..5eba73ee93 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BLS24-315] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls24-315/g2_test.go b/ecc/bls24-315/g2_test.go index 8da325caff..bab8fbad10 100644 --- a/ecc/bls24-315/g2_test.go +++ b/ecc/bls24-315/g2_test.go @@ -99,7 +99,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E4) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 65e965ba73..29bfa471b3 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -824,9 +824,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -846,7 +846,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -857,7 +857,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -869,6 +869,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -932,8 +933,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -975,7 +975,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index 672a3d5dad..2c08510b14 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BLS24-317] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bls24-317/g2_test.go b/ecc/bls24-317/g2_test.go index 98104ff5a5..376b469347 100644 --- a/ecc/bls24-317/g2_test.go +++ b/ecc/bls24-317/g2_test.go @@ -99,7 +99,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E4) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 0807f6297d..f9f94fa01d 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -794,9 +794,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -816,7 +816,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -827,7 +827,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -839,6 +839,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -902,8 +903,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -945,7 +945,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index 5e4e7a4049..8ee025d787 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BN254] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bn254/g2_test.go b/ecc/bn254/g2_test.go index 7146775ab0..17c09d95ba 100644 --- a/ecc/bn254/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -98,7 +98,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index afe13b63d2..c74faf1d84 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -881,9 +881,9 @@ func (p *g1Proj) FromAffine(Q *G1Affine) *g1Proj { } // BatchProjectiveToAffineG1 converts points in Projective coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchProjectiveToAffineG1(points []g1Proj) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -903,7 +903,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -914,7 +914,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } a := result[i].X @@ -922,12 +922,13 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { result[i].Y.Mul(&points[i].y, &a) } }) + return result } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -947,7 +948,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -958,7 +959,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -970,6 +971,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -1033,8 +1035,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -1076,7 +1077,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index c07a047119..6caf91227c 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BW6-633] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-633/g2_test.go b/ecc/bw6-633/g2_test.go index 419a44f56f..32773e9718 100644 --- a/ecc/bw6-633/g2_test.go +++ b/ecc/bw6-633/g2_test.go @@ -85,7 +85,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 7b9422fa89..337b104b51 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -202,8 +202,6 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // precomputations pProj0 := make([]g1Proj, n) p1 := make([]G1Affine, n) - p01 := make([]G1Affine, n) - p10 := make([]G1Affine, n) pProj01 := make([]g1Proj, n) // P0+P1 pProj10 := make([]g1Proj, n) // P0-P1 l01 := make([]lineEvaluation, n) @@ -226,8 +224,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } - BatchProjectiveToAffineG1(pProj01, p01) - BatchProjectiveToAffineG1(pProj10, p10) + p01 := BatchProjectiveToAffineG1(pProj01) + p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+\lambda*a1,P}(Q) var result, ss GT diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 87f721d013..5ffaa9a826 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -881,9 +881,9 @@ func (p *g1Proj) FromAffine(Q *G1Affine) *g1Proj { } // BatchProjectiveToAffineG1 converts points in Projective coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchProjectiveToAffineG1(points []g1Proj) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -903,7 +903,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -914,7 +914,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } a := result[i].X @@ -922,12 +922,13 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { result[i].Y.Mul(&points[i].y, &a) } }) + return result } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -947,7 +948,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -958,7 +959,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -970,6 +971,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -1033,8 +1035,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -1076,7 +1077,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bw6-756/g1_test.go b/ecc/bw6-756/g1_test.go index 838865fcd9..81ecf81553 100644 --- a/ecc/bw6-756/g1_test.go +++ b/ecc/bw6-756/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BW6-756] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-756/g2_test.go b/ecc/bw6-756/g2_test.go index 3b72643fe8..ecfc973322 100644 --- a/ecc/bw6-756/g2_test.go +++ b/ecc/bw6-756/g2_test.go @@ -85,7 +85,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index c52d4dda51..e4b1f3ad9b 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -180,8 +180,6 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // precomputations pProj1 := make([]g1Proj, n) p1 := make([]G1Affine, n) - p01 := make([]G1Affine, n) - p10 := make([]G1Affine, n) pProj01 := make([]g1Proj, n) // P0+P1 pProj10 := make([]g1Proj, n) // P0-P1 l01 := make([]lineEvaluation, n) @@ -203,8 +201,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } - BatchProjectiveToAffineG1(pProj01, p01) - BatchProjectiveToAffineG1(pProj10, p10) + p01 := BatchProjectiveToAffineG1(pProj01) + p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+lambda*a1,P}(Q) var result, ss GT diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index cfacbe0997..8e68f70406 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -892,9 +892,9 @@ func (p *g1Proj) FromAffine(Q *G1Affine) *g1Proj { } // BatchProjectiveToAffineG1 converts points in Projective coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchProjectiveToAffineG1(points []g1Proj) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -914,7 +914,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -925,7 +925,7 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } a := result[i].X @@ -933,12 +933,13 @@ func BatchProjectiveToAffineG1(points []g1Proj, result []G1Affine) { result[i].Y.Mul(&points[i].y, &a) } }) + return result } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -958,7 +959,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -969,7 +970,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -981,6 +982,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } // BatchScalarMultiplicationG1 multiplies the same base by all scalars @@ -1044,8 +1046,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin selectors[chunk] = d } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) // for each digit, take value in the base table, double it c time, voilà. @@ -1087,7 +1088,6 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index 1c77aa2d6f..6ace718ac2 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -85,7 +85,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) - op2.FromJacobian(&g1Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -220,6 +220,19 @@ func TestG1AffineConversions(t *testing.T) { GenFp(), GenFp(), )) + properties.Property("[BW6-761] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b fp.Element) bool { + g1 := fuzzG1Jac(&g1Gen, a) + g2 := fuzzG1Jac(&g1Gen, b) + var op1, op2 G1Affine + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) properties.TestingRun(t, gopter.ConsoleReporter(false)) } diff --git a/ecc/bw6-761/g2_test.go b/ecc/bw6-761/g2_test.go index 55fead4f7f..9630dbf178 100644 --- a/ecc/bw6-761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -85,7 +85,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { func(a fp.Element) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) - op2.FromJacobian(&g2Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index 8cdddd9ce3..4e5dcfa8d0 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -179,8 +179,6 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // precomputations pProj1 := make([]g1Proj, n) p1 := make([]G1Affine, n) - p01 := make([]G1Affine, n) - p10 := make([]G1Affine, n) pProj01 := make([]g1Proj, n) // P0+P1 pProj10 := make([]g1Proj, n) // P0-P1 l01 := make([]lineEvaluation, n) @@ -202,8 +200,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } - BatchProjectiveToAffineG1(pProj01, p01) - BatchProjectiveToAffineG1(pProj10, p10) + p01 := BatchProjectiveToAffineG1(pProj01) + p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+\lambda*a1,P}(Q) var result, ss GT diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index de3a5a7ff0..fef054f5a1 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -1323,9 +1323,9 @@ func (p *{{ $TProjective }}) FromAffine(Q *{{ $TAffine }}) *{{ $TProjective }} { {{- if eq .PointName "g1"}} // BatchProjectiveToAffine{{ toUpper .PointName }} converts points in Projective coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }}, result []{{ $TAffine }}) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }}) []{{ $TAffine }} { + result := make([]{{ $TAffine }}, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -1345,7 +1345,7 @@ func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }} for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -1356,7 +1356,7 @@ func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }} parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } a := result[i].X @@ -1364,6 +1364,7 @@ func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }} result[i].Y.Mul(&points[i].y, &a) } }) + return result } {{end }} {{end }} @@ -1373,9 +1374,9 @@ func BatchProjectiveToAffine{{ toUpper .PointName }}(points []{{ $TProjective }} {{- if eq .PointName "g1"}} // BatchJacobianToAffine{{ toUpper .PointName }} converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}, result []{{ $TAffine }}) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}) []{{ $TAffine }} { + result := make([]{{ $TAffine }}, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -1395,7 +1396,7 @@ func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}, re for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -1406,7 +1407,7 @@ func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}, re parallel.Execute( len(points), func(start, end int) { for i:=start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -1418,6 +1419,7 @@ func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}, re } }) + return result } {{- end}} @@ -1485,8 +1487,7 @@ func BatchScalarMultiplication{{ toUpper .PointName }}(base *{{ $TAffine }}, sca {{- if eq .PointName "g1"}} // convert our base exp table into affine to use AddMixed - baseTableAff := make([]{{ $TAffine }}, (1<<(c-1))) - BatchJacobianToAffine{{ toUpper .PointName}}(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffine{{ toUpper .PointName}}(baseTable) toReturn := make([]{{ $TJacobian }}, len(scalars)) {{- else}} toReturn := make([]{{ $TAffine }}, len(scalars)) @@ -1547,8 +1548,7 @@ func BatchScalarMultiplication{{ toUpper .PointName }}(base *{{ $TAffine }}, sca }) {{- if eq .PointName "g1"}} - toReturnAff := make([]{{ $TAffine }}, len(scalars)) - BatchJacobianToAffine{{ toUpper .PointName}}(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffine{{ toUpper .PointName}}(toReturn) return toReturnAff {{- else}} return toReturn diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index 1df791c30c..556d9befc3 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -111,7 +111,7 @@ func Test{{ $TAffine }}IsOnCurve(t *testing.T) { func(a {{ .CoordType}}) bool { var op1, op2 {{ $TAffine }} op1.FromJacobian(&{{.PointName}}Gen) - op2.FromJacobian(&{{.PointName}}Gen) + op2.Set(&op1) op2.Y.Mul(&op2.Y, &a) return op1.IsOnCurve() && !op2.IsOnCurve() }, @@ -250,6 +250,22 @@ func Test{{ $TAffine }}Conversions(t *testing.T) { {{$fuzzer}}, )) + {{- if eq .PointName "g1" }} + properties.Property("[{{ toUpper .Name }}] BatchJacobianToAffineG1 and FromJacobian should output the same result", prop.ForAll( + func(a, b {{ .CoordType}}) bool { + g1 := fuzz{{ $TJacobian }}(&{{ toLower .PointName }}Gen, a) + g2 := fuzz{{ $TJacobian }}(&{{ toLower .PointName }}Gen, b) + var op1, op2 {{ $TAffine }} + op1.FromJacobian(&g1) + op2.FromJacobian(&g2) + baseTableAff := BatchJacobianToAffineG1([]G1Jac{g1, g2}) + return op1.Equal(&baseTableAff[0]) && op2.Equal(&baseTableAff[1]) + }, + GenFp(), + GenFp(), + )) + {{- end }} + properties.TestingRun(t, gopter.ConsoleReporter(false)) }