From db226c0680f65e5af3d0437ae57535a4ddb7ea12 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Sat, 12 Oct 2024 16:21:06 +0100 Subject: [PATCH 1/9] initial commit --- crypto/bn256/gnark/g1.go | 74 +++++++++++++++++++++++++++++++++++ crypto/bn256/gnark/g1_aff.go | 73 ++++++++++++++++++++++++++++++++++ crypto/bn256/gnark/g2.go | 48 +++++++++++++++++++++++ crypto/bn256/gnark/pairing.go | 64 ++++++++++++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 crypto/bn256/gnark/g1.go create mode 100644 crypto/bn256/gnark/g1_aff.go create mode 100644 crypto/bn256/gnark/g2.go create mode 100644 crypto/bn256/gnark/pairing.go diff --git a/crypto/bn256/gnark/g1.go b/crypto/bn256/gnark/g1.go new file mode 100644 index 000000000000..2db24e5b16e9 --- /dev/null +++ b/crypto/bn256/gnark/g1.go @@ -0,0 +1,74 @@ +package bn256 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// G1 is the affine representation of a G1 group element. +// +// Since this code is used for precompiles, using Jacobian +// points are not beneficial because there are no intermediate +// points to allow us to save on inversions. +// +// Note: We also use this struct so that we can conform to the existing API +// that the precompiles want. +type G1 struct { + inner bn254.G1Affine +} + +// Add adds `a` and `b` together storing the result in `g` +func (g *G1) Add(a, b *G1) { + // TODO(Decision to be made): There are three ways to + // TODO do this addition. Each with different performance + // TODO: characteristics. + // + // Option 1: This just calls a method in gnark + // g.inner.Add(&a.inner, &b.inner) + + // Option 2: This calls multiple methods in gnark + // but is faster. + // + // var res bn254.G1Jac + // res.FromAffine(&a.inner) + // res.AddMixed(&b.inner) + // g.inner.FromJacobian(&res) + + // Option 3: This calls a method that I created that + // we can upstream to gnark. + // This should be the fastest, I can write the same for G2 + g.addAffine(a, b) +} + +// ScalarMult computes the scalar multiplication between `a` and +// `scalar` storing the result in `g` +func (g *G1) ScalarMult(a *G1, scalar *big.Int) { + g.inner.ScalarMultiplication(&a.inner, scalar) +} + +// Double adds `a` to itself, storing the result in `g` +func (g *G1) Double(a *G1) { + g.inner.Double(&a.inner) +} + +// Unmarshal deserializes `buf` into `g` +// +// Note: whether the serialization is of a compressed +// or an uncompressed point, is encoding in the bytes. +// +// For our purpose, the point will always be serialized as uncompressed +// ie 64 bytes. +// +// This method checks whether the point is on the curve and +// in the subgroup. +func (g *G1) Unmarshal(buf []byte) (int, error) { + return g.inner.SetBytes(buf) +} + +// Marshal serializes the point into a byte slice. +// +// Note: The point is serialized as uncompressed. +func (p *G1) Marshal() []byte { + return p.inner.Marshal() +} diff --git a/crypto/bn256/gnark/g1_aff.go b/crypto/bn256/gnark/g1_aff.go new file mode 100644 index 000000000000..d92eb8000980 --- /dev/null +++ b/crypto/bn256/gnark/g1_aff.go @@ -0,0 +1,73 @@ +package bn256 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fp" +) + +// This is just the addition formula +// but given we know that we do not need Jacobian +// coordinates, we use the naive implementation. +// +// Ideally, we push this into gnark +func (g *G1) addAffine(a_, b_ *G1) { + + // Get the gnark specific points + var a = a_.inner + var b = b_.inner + + // If a is 0, then return b + if a.IsInfinity() { + g.inner.Set(&b) + return + } + + // If b is 0, then return a + if b.IsInfinity() { + g.inner.Set(&a) + return + } + + // If a == -b, then return 0 + g.inner.Neg(&b) + if a.Equal(&g.inner) { + g.inner.X.SetZero() + g.inner.Y.SetZero() + return + } + + // Compute lambda based on whether we + // are doing a point addition or a point doubling + // + // Check if points are equal + var pointsAreEqual = a.Equal(&b) + + var denominator fp.Element + var lambda fp.Element + + // If a == b, then we need to compute lambda for double + // else we need to compute lambda for addition + if pointsAreEqual { + // Compute numerator + lambda.Square(&a.X) + fp.MulBy3(&lambda) + + denominator.Add(&a.Y, &a.Y) + } else { + // Compute numerator + lambda.Sub(&b.Y, &a.Y) + + denominator.Sub(&b.X, &a.X) + } + denominator.Inverse(&denominator) + lambda.Mul(&lambda, &denominator) + + // Compute x_3 as lambda^2 - a_x - b_x + g.inner.X.Square(&lambda) + g.inner.X.Sub(&g.inner.X, &a.X) + g.inner.X.Sub(&g.inner.X, &b.X) + + // Compute y as lambda * (a_x - x_3) - a_y + g.inner.Y.Sub(&a.X, &g.inner.X) + g.inner.Y.Mul(&g.inner.Y, &lambda) + g.inner.Y.Sub(&g.inner.Y, &a.Y) +} diff --git a/crypto/bn256/gnark/g2.go b/crypto/bn256/gnark/g2.go new file mode 100644 index 000000000000..86b1a8d7476e --- /dev/null +++ b/crypto/bn256/gnark/g2.go @@ -0,0 +1,48 @@ +package bn256 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// G2 is the affine representation of a G2 group element. +// +// Since this code is used for precompiles, using Jacobian +// points are not beneficial because there are no intermediate +// points. +// +// Note: We also use this struct so that we can conform to the existing API +// that the precompiles want. +type G2 struct { + inner bn254.G2Affine +} + +// Add adds `a` and `b` together storing the result in `g` +func (g *G2) Add(a, b *G2) { + g.inner.Add(&a.inner, &b.inner) +} + +// Double adds `a` to itself, storing the result in `g` +func (g *G2) Double(a *G2) { + g.inner.Double(&a.inner) +} + +// Unmarshal deserializes `buf` into `g` +// +// Note: whether the serialization is of a compressed +// or an uncompressed point, is encoding in the bytes. +// +// For our purpose, the point will always be serialized as uncompressed +// ie 128 bytes. +// +// This method checks whether the point is on the curve and +// in the subgroup. +func (g *G2) Unmarshal(buf []byte) (int, error) { + return g.inner.SetBytes(buf) +} + +// Marshal serializes the point into a byte slice. +// +// Note: The point is serialized as uncompressed. +func (g *G2) Marshal() []byte { + return g.inner.Marshal() +} diff --git a/crypto/bn256/gnark/pairing.go b/crypto/bn256/gnark/pairing.go new file mode 100644 index 000000000000..a9e049111d28 --- /dev/null +++ b/crypto/bn256/gnark/pairing.go @@ -0,0 +1,64 @@ +package bn256 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// Computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// To explain why gnark returns a (bool, error): +// +// - If the function `e` does not return a result then internally +// an error is returned. +// - If `e` returns a result, then error will be nil, +// but if this value is not `1` then the boolean value will be false +// +// We therefore check for an error, and return false if its non-nil and +// then return the value of the boolean if not. +func PairingCheck(a_ []*G1, b_ []*G2) bool { + a := getInnerG1s(a_) + b := getInnerG2s(b_) + + // Check if input is empty + if len(a) == 0 { + return true + } + + ok, err := bn254.PairingCheck(a, b) + if err != nil { + return false + } + return ok +} + +// getInnerG1s gets the inner gnark G1 elements. +// +// These methods are used for two reasons: +// +// - We use a new type `G1`, so we need to convert from +// []*G1 to []*bn254.G1Affine +// - The gnark API accepts slices of values and not slices of +// pointers to values, so we need to return []bn254.G1Affine +// instead of []*bn254.G1Affine. +func getInnerG1s(pointerSlice []*G1) []bn254.G1Affine { + gnarkValues := make([]bn254.G1Affine, 0, len(pointerSlice)) + for _, ptr := range pointerSlice { + if ptr != nil { + gnarkValues = append(gnarkValues, ptr.inner) + } + } + return gnarkValues +} + +// getInnerG2s gets the inner gnark G2 elements. +// +// The rationale for this method is the same as getInnerG1s. +func getInnerG2s(pointerSlice []*G2) []bn254.G2Affine { + gnarkValues := make([]bn254.G2Affine, 0, len(pointerSlice)) + for _, ptr := range pointerSlice { + if ptr != nil { + gnarkValues = append(gnarkValues, ptr.inner) + } + } + return gnarkValues +} From a65fe3184298c52e84f6338cbabb0198f5a3877a Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Sat, 12 Oct 2024 16:36:11 +0100 Subject: [PATCH 2/9] add note on zero check --- crypto/bn256/gnark/pairing.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crypto/bn256/gnark/pairing.go b/crypto/bn256/gnark/pairing.go index a9e049111d28..b9b640553416 100644 --- a/crypto/bn256/gnark/pairing.go +++ b/crypto/bn256/gnark/pairing.go @@ -19,8 +19,17 @@ func PairingCheck(a_ []*G1, b_ []*G2) bool { a := getInnerG1s(a_) b := getInnerG2s(b_) - // Check if input is empty - if len(a) == 0 { + // Assume that len(a) == len(b) + // + // The pairing function will return + // false, if this is not the case. + size := len(a) + + // Check if input is empty -- gnark will + // return false on an empty input, however + // the ossified behavior is to return true + // on an empty input, so we add this if statement. + if size == 0 { return true } From 8eecf9fdad68e52ebe9c404d8d926e58c284838a Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 14:51:18 +0100 Subject: [PATCH 3/9] use gnark API for Add --- crypto/bn256/gnark/g1.go | 20 +--------- crypto/bn256/gnark/g1_aff.go | 73 ------------------------------------ 2 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 crypto/bn256/gnark/g1_aff.go diff --git a/crypto/bn256/gnark/g1.go b/crypto/bn256/gnark/g1.go index 2db24e5b16e9..bb25d7b83424 100644 --- a/crypto/bn256/gnark/g1.go +++ b/crypto/bn256/gnark/g1.go @@ -20,25 +20,7 @@ type G1 struct { // Add adds `a` and `b` together storing the result in `g` func (g *G1) Add(a, b *G1) { - // TODO(Decision to be made): There are three ways to - // TODO do this addition. Each with different performance - // TODO: characteristics. - // - // Option 1: This just calls a method in gnark - // g.inner.Add(&a.inner, &b.inner) - - // Option 2: This calls multiple methods in gnark - // but is faster. - // - // var res bn254.G1Jac - // res.FromAffine(&a.inner) - // res.AddMixed(&b.inner) - // g.inner.FromJacobian(&res) - - // Option 3: This calls a method that I created that - // we can upstream to gnark. - // This should be the fastest, I can write the same for G2 - g.addAffine(a, b) + g.inner.Add(&a.inner, &b.inner) } // ScalarMult computes the scalar multiplication between `a` and diff --git a/crypto/bn256/gnark/g1_aff.go b/crypto/bn256/gnark/g1_aff.go deleted file mode 100644 index d92eb8000980..000000000000 --- a/crypto/bn256/gnark/g1_aff.go +++ /dev/null @@ -1,73 +0,0 @@ -package bn256 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fp" -) - -// This is just the addition formula -// but given we know that we do not need Jacobian -// coordinates, we use the naive implementation. -// -// Ideally, we push this into gnark -func (g *G1) addAffine(a_, b_ *G1) { - - // Get the gnark specific points - var a = a_.inner - var b = b_.inner - - // If a is 0, then return b - if a.IsInfinity() { - g.inner.Set(&b) - return - } - - // If b is 0, then return a - if b.IsInfinity() { - g.inner.Set(&a) - return - } - - // If a == -b, then return 0 - g.inner.Neg(&b) - if a.Equal(&g.inner) { - g.inner.X.SetZero() - g.inner.Y.SetZero() - return - } - - // Compute lambda based on whether we - // are doing a point addition or a point doubling - // - // Check if points are equal - var pointsAreEqual = a.Equal(&b) - - var denominator fp.Element - var lambda fp.Element - - // If a == b, then we need to compute lambda for double - // else we need to compute lambda for addition - if pointsAreEqual { - // Compute numerator - lambda.Square(&a.X) - fp.MulBy3(&lambda) - - denominator.Add(&a.Y, &a.Y) - } else { - // Compute numerator - lambda.Sub(&b.Y, &a.Y) - - denominator.Sub(&b.X, &a.X) - } - denominator.Inverse(&denominator) - lambda.Mul(&lambda, &denominator) - - // Compute x_3 as lambda^2 - a_x - b_x - g.inner.X.Square(&lambda) - g.inner.X.Sub(&g.inner.X, &a.X) - g.inner.X.Sub(&g.inner.X, &b.X) - - // Compute y as lambda * (a_x - x_3) - a_y - g.inner.Y.Sub(&a.X, &g.inner.X) - g.inner.Y.Mul(&g.inner.Y, &lambda) - g.inner.Y.Sub(&g.inner.Y, &a.Y) -} From 6d04721a9a8450cf8a162887062381565505a5ff Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 14:53:23 +0100 Subject: [PATCH 4/9] add wrapper for GT --- crypto/bn256/gnark/gt.go | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 crypto/bn256/gnark/gt.go diff --git a/crypto/bn256/gnark/gt.go b/crypto/bn256/gnark/gt.go new file mode 100644 index 000000000000..dea843041f00 --- /dev/null +++ b/crypto/bn256/gnark/gt.go @@ -0,0 +1,66 @@ +package bn256 + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// GT is the affine representation of a GT field element. +// +// Note: GT is not explicitly used in mainline code. +// It is needed for fuzzing. +type GT struct { + inner bn254.GT +} + +// Pair compute the optimal Ate pairing between a G1 and +// G2 element. +// +// Note: This method is not explicitly used in mainline code. +// It is needed for fuzzing. It should also be noted, +// that the output of this function may not match other +func Pair(a_ *G1, b_ *G2) *GT { + + a := a_.inner + b := b_.inner + + pairingOutput, err := bn254.Pair([]bn254.G1Affine{a}, []bn254.G2Affine{b}) + + if err != nil { + // Since this method is only called during fuzzing, it is okay to panic here. + // We do not return an error to match the interface of the other bn256 libraries. + panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err)) + } + + return >{ + inner: pairingOutput, + } +} + +// Unmarshal deserializes `buf` into `g` +// +// Note: This method is not explicitly used in mainline code. +// It is needed for fuzzing. +func (g *GT) Unmarshal(buf []byte) error { + return g.inner.SetBytes(buf) +} + +// Marshal serializes the point into a byte slice. +// +// Note: This method is not explicitly used in mainline code. +// It is needed for fuzzing. +func (g *GT) Marshal() []byte { + bytes := g.inner.Bytes() + return bytes[:] +} + +// Exp exponentiates `base` to the power of `exponent` +// +// Note: This method is not explicitly used in mainline code. +// It is needed for fuzzing. +func (g *GT) Exp(base GT, exponent *big.Int) *GT { + g.inner.Exp(base.inner, exponent) + return g +} From dce736e6bf72b5c866ca5a0fda877045c0520e6c Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 14:53:57 +0100 Subject: [PATCH 5/9] modify fuzzing --- tests/fuzzers/bn256/bn256_fuzz.go | 65 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/tests/fuzzers/bn256/bn256_fuzz.go b/tests/fuzzers/bn256/bn256_fuzz.go index 75f7d59deeef..4383559dc06c 100644 --- a/tests/fuzzers/bn256/bn256_fuzz.go +++ b/tests/fuzzers/bn256/bn256_fuzz.go @@ -22,12 +22,12 @@ import ( "io" "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" + gnark "github.com/ethereum/go-ethereum/crypto/bn256/gnark" google "github.com/ethereum/go-ethereum/crypto/bn256/google" ) -func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *bn254.G1Affine) { +func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *gnark.G1) { _, xc, err := cloudflare.RandomG1(input) if err != nil { // insufficient input @@ -37,14 +37,14 @@ func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *bn254.G1Affine) if _, err := xg.Unmarshal(xc.Marshal()); err != nil { panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err)) } - xs := new(bn254.G1Affine) - if err := xs.Unmarshal(xc.Marshal()); err != nil { + xs := new(gnark.G1) + if _, err := xs.Unmarshal(xc.Marshal()); err != nil { panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err)) } return xc, xg, xs } -func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *bn254.G2Affine) { +func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *gnark.G2) { _, xc, err := cloudflare.RandomG2(input) if err != nil { // insufficient input @@ -54,14 +54,14 @@ func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *bn254.G2Affine) if _, err := xg.Unmarshal(xc.Marshal()); err != nil { panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err)) } - xs := new(bn254.G2Affine) - if err := xs.Unmarshal(xc.Marshal()); err != nil { + xs := new(gnark.G2) + if _, err := xs.Unmarshal(xc.Marshal()); err != nil { panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err)) } return xc, xg, xs } -// fuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries. +// fuzzAdd fuzzes bn256 addition between the Google, Cloudflare and Gnark libraries. func fuzzAdd(data []byte) int { input := bytes.NewReader(data) xc, xg, xs := getG1Points(input) @@ -72,7 +72,7 @@ func fuzzAdd(data []byte) int { if yc == nil { return 0 } - // Ensure both libs can parse the second curve point + // Ensure libs can parse the second curve point // Add the two points and ensure they result in the same output rc := new(cloudflare.G1) rc.Add(xc, yc) @@ -80,9 +80,8 @@ func fuzzAdd(data []byte) int { rg := new(google.G1) rg.Add(xg, yg) - tmpX := new(bn254.G1Jac).FromAffine(xs) - tmpY := new(bn254.G1Jac).FromAffine(ys) - rs := new(bn254.G1Affine).FromJacobian(tmpX.AddAssign(tmpY)) + rs := new(gnark.G1) + rs.Add(xs, ys) if !bytes.Equal(rc.Marshal(), rg.Marshal()) { panic("add mismatch: cloudflare/google") @@ -94,8 +93,8 @@ func fuzzAdd(data []byte) int { return 1 } -// fuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare -// libraries. +// fuzzMul fuzzes bn256 scalar multiplication between the Google, Cloudflare +// and Gnark libraries. func fuzzMul(data []byte) int { input := bytes.NewReader(data) pc, pg, ps := getG1Points(input) @@ -122,15 +121,13 @@ func fuzzMul(data []byte) int { rg := new(google.G1) rg.ScalarMult(pg, new(big.Int).SetBytes(buf)) - rs := new(bn254.G1Jac) - psJac := new(bn254.G1Jac).FromAffine(ps) - rs.ScalarMultiplication(psJac, new(big.Int).SetBytes(buf)) - rsAffine := new(bn254.G1Affine).FromJacobian(rs) + rs := new(gnark.G1) + rs.ScalarMult(ps, new(big.Int).SetBytes(buf)) if !bytes.Equal(rc.Marshal(), rg.Marshal()) { panic("scalar mul mismatch: cloudflare/google") } - if !bytes.Equal(rc.Marshal(), rsAffine.Marshal()) { + if !bytes.Equal(rc.Marshal(), rs.Marshal()) { panic("scalar mul mismatch: cloudflare/gnark") } return 1 @@ -150,17 +147,27 @@ func fuzzPair(data []byte) int { // Pair the two points and ensure they result in the same output clPair := cloudflare.Pair(pc, tc).Marshal() gPair := google.Pair(pg, tg).Marshal() + sPair := gnark.Pair(ps, ts).Marshal() + if !bytes.Equal(clPair, gPair) { panic("pairing mismatch: cloudflare/google") } - cPair, err := bn254.Pair([]bn254.G1Affine{*ps}, []bn254.G2Affine{*ts}) - if err != nil { - panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err)) + + normalizedClPair := normalizeGTToGnark(clPair).Marshal() + if !bytes.Equal(normalizedClPair, sPair) { + panic("pairing mismatch: cloudflare/gnark") } - // gnark uses a different pairing algorithm which might produce - // different but also correct outputs, we need to scale the output by s + return 1 +} + +// normalizeGTToGnark scales a Cloudflare/Google GT element by `s` +// so that it can be compared with a gnark GT point. +// +// For the definition of `s` see 3.5 in https://eprint.iacr.org/2015/192.pdf +func normalizeGTToGnark(cloudflareOrGoogleGT []byte) *gnark.GT { + // Compute s = 2*u(6*u^2 + 3*u + 1) u, _ := new(big.Int).SetString("0x44e992b44a6909f1", 0) u_exp2 := new(big.Int).Exp(u, big.NewInt(2), nil) // u^2 u_6_exp2 := new(big.Int).Mul(big.NewInt(6), u_exp2) // 6*u^2 @@ -170,14 +177,12 @@ func fuzzPair(data []byte) int { u_2 := new(big.Int).Mul(big.NewInt(2), u) // 2*u s := u_2.Mul(u_2, inner) // 2*u(6*u^2 + 3*u + 1) - gRes := new(bn254.GT) - if err := gRes.SetBytes(clPair); err != nil { + // Scale the Cloudflare/Google GT element by `s` + gRes := new(gnark.GT) + if err := gRes.Unmarshal(cloudflareOrGoogleGT); err != nil { panic(err) } gRes = gRes.Exp(*gRes, s) - if !bytes.Equal(cPair.Marshal(), gRes.Marshal()) { - panic("pairing mismatch: cloudflare/gnark") - } - return 1 + return gRes } From 3c03b0cbbc22b0a3601fb2aa72a469435ed5bcbe Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 14:55:07 +0100 Subject: [PATCH 6/9] remove `Double` --- crypto/bn256/gnark/g1.go | 5 ----- crypto/bn256/gnark/g2.go | 5 ----- 2 files changed, 10 deletions(-) diff --git a/crypto/bn256/gnark/g1.go b/crypto/bn256/gnark/g1.go index bb25d7b83424..cc80e06cc4f9 100644 --- a/crypto/bn256/gnark/g1.go +++ b/crypto/bn256/gnark/g1.go @@ -29,11 +29,6 @@ func (g *G1) ScalarMult(a *G1, scalar *big.Int) { g.inner.ScalarMultiplication(&a.inner, scalar) } -// Double adds `a` to itself, storing the result in `g` -func (g *G1) Double(a *G1) { - g.inner.Double(&a.inner) -} - // Unmarshal deserializes `buf` into `g` // // Note: whether the serialization is of a compressed diff --git a/crypto/bn256/gnark/g2.go b/crypto/bn256/gnark/g2.go index 86b1a8d7476e..c79d8604e06e 100644 --- a/crypto/bn256/gnark/g2.go +++ b/crypto/bn256/gnark/g2.go @@ -21,11 +21,6 @@ func (g *G2) Add(a, b *G2) { g.inner.Add(&a.inner, &b.inner) } -// Double adds `a` to itself, storing the result in `g` -func (g *G2) Double(a *G2) { - g.inner.Double(&a.inner) -} - // Unmarshal deserializes `buf` into `g` // // Note: whether the serialization is of a compressed From 177c7a15329ccf1a489aa930a96ab42750507d73 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 15:05:07 +0100 Subject: [PATCH 7/9] [multi] - cleanup comments and remove Add from g2 since there is no Add precompile for G2 --- crypto/bn256/gnark/g1.go | 16 ++++++++-------- crypto/bn256/gnark/g2.go | 19 +++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/crypto/bn256/gnark/g1.go b/crypto/bn256/gnark/g1.go index cc80e06cc4f9..2f933dd53601 100644 --- a/crypto/bn256/gnark/g1.go +++ b/crypto/bn256/gnark/g1.go @@ -18,27 +18,27 @@ type G1 struct { inner bn254.G1Affine } -// Add adds `a` and `b` together storing the result in `g` +// Add adds `a` and `b` together, storing the result in `g` func (g *G1) Add(a, b *G1) { g.inner.Add(&a.inner, &b.inner) } // ScalarMult computes the scalar multiplication between `a` and -// `scalar` storing the result in `g` +// `scalar`, storing the result in `g` func (g *G1) ScalarMult(a *G1, scalar *big.Int) { g.inner.ScalarMultiplication(&a.inner, scalar) } // Unmarshal deserializes `buf` into `g` // -// Note: whether the serialization is of a compressed -// or an uncompressed point, is encoding in the bytes. +// Note: whether the deserialization is of a compressed +// or an uncompressed point, is encoded in the bytes. // -// For our purpose, the point will always be serialized as uncompressed -// ie 64 bytes. +// For our purpose, the point will always be serialized +// as uncompressed, ie 64 bytes. // -// This method checks whether the point is on the curve and -// in the subgroup. +// This method also checks whether the point is on the +// curve and in the prime order subgroup. func (g *G1) Unmarshal(buf []byte) (int, error) { return g.inner.SetBytes(buf) } diff --git a/crypto/bn256/gnark/g2.go b/crypto/bn256/gnark/g2.go index c79d8604e06e..205373a59194 100644 --- a/crypto/bn256/gnark/g2.go +++ b/crypto/bn256/gnark/g2.go @@ -8,7 +8,7 @@ import ( // // Since this code is used for precompiles, using Jacobian // points are not beneficial because there are no intermediate -// points. +// points and G2 in particular is only used for the pairing input. // // Note: We also use this struct so that we can conform to the existing API // that the precompiles want. @@ -16,21 +16,16 @@ type G2 struct { inner bn254.G2Affine } -// Add adds `a` and `b` together storing the result in `g` -func (g *G2) Add(a, b *G2) { - g.inner.Add(&a.inner, &b.inner) -} - // Unmarshal deserializes `buf` into `g` // -// Note: whether the serialization is of a compressed -// or an uncompressed point, is encoding in the bytes. +// Note: whether the deserialization is of a compressed +// or an uncompressed point, is encoded in the bytes. // -// For our purpose, the point will always be serialized as uncompressed -// ie 128 bytes. +// For our purpose, the point will always be serialized +// as uncompressed, ie 128 bytes. // -// This method checks whether the point is on the curve and -// in the subgroup. +// This method also checks whether the point is on the +// curve and in the prime order subgroup. func (g *G2) Unmarshal(buf []byte) (int, error) { return g.inner.SetBytes(buf) } From dbf770342ac34de1a2c50acf28502240e135ee56 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 15:07:57 +0100 Subject: [PATCH 8/9] formatting --- crypto/bn256/gnark/gt.go | 2 +- crypto/bn256/gnark/pairing.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crypto/bn256/gnark/gt.go b/crypto/bn256/gnark/gt.go index dea843041f00..8a14fbe5c0f4 100644 --- a/crypto/bn256/gnark/gt.go +++ b/crypto/bn256/gnark/gt.go @@ -56,7 +56,7 @@ func (g *GT) Marshal() []byte { return bytes[:] } -// Exp exponentiates `base` to the power of `exponent` +// Exp raises `base` to the power of `exponent` // // Note: This method is not explicitly used in mainline code. // It is needed for fuzzing. diff --git a/crypto/bn256/gnark/pairing.go b/crypto/bn256/gnark/pairing.go index b9b640553416..39e8a657f466 100644 --- a/crypto/bn256/gnark/pairing.go +++ b/crypto/bn256/gnark/pairing.go @@ -44,11 +44,11 @@ func PairingCheck(a_ []*G1, b_ []*G2) bool { // // These methods are used for two reasons: // -// - We use a new type `G1`, so we need to convert from -// []*G1 to []*bn254.G1Affine -// - The gnark API accepts slices of values and not slices of -// pointers to values, so we need to return []bn254.G1Affine -// instead of []*bn254.G1Affine. +// - We use a new type `G1`, so we need to convert from +// []*G1 to []*bn254.G1Affine +// - The gnark API accepts slices of values and not slices of +// pointers to values, so we need to return []bn254.G1Affine +// instead of []*bn254.G1Affine. func getInnerG1s(pointerSlice []*G1) []bn254.G1Affine { gnarkValues := make([]bn254.G1Affine, 0, len(pointerSlice)) for _, ptr := range pointerSlice { @@ -61,7 +61,7 @@ func getInnerG1s(pointerSlice []*G1) []bn254.G1Affine { // getInnerG2s gets the inner gnark G2 elements. // -// The rationale for this method is the same as getInnerG1s. +// The rationale for this method is the same as `getInnerG1s`. func getInnerG2s(pointerSlice []*G2) []bn254.G2Affine { gnarkValues := make([]bn254.G2Affine, 0, len(pointerSlice)) for _, ptr := range pointerSlice { From 9eb68f23eb3f2bcf036a9c6237883cf1fbdf383e Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 14 Oct 2024 19:53:57 +0100 Subject: [PATCH 9/9] formatting --- crypto/bn256/gnark/gt.go | 1 - tests/fuzzers/bn256/bn256_fuzz.go | 1 - 2 files changed, 2 deletions(-) diff --git a/crypto/bn256/gnark/gt.go b/crypto/bn256/gnark/gt.go index 8a14fbe5c0f4..c30022c5f898 100644 --- a/crypto/bn256/gnark/gt.go +++ b/crypto/bn256/gnark/gt.go @@ -22,7 +22,6 @@ type GT struct { // It is needed for fuzzing. It should also be noted, // that the output of this function may not match other func Pair(a_ *G1, b_ *G2) *GT { - a := a_.inner b := b_.inner diff --git a/tests/fuzzers/bn256/bn256_fuzz.go b/tests/fuzzers/bn256/bn256_fuzz.go index 4383559dc06c..4521f6b0dbca 100644 --- a/tests/fuzzers/bn256/bn256_fuzz.go +++ b/tests/fuzzers/bn256/bn256_fuzz.go @@ -166,7 +166,6 @@ func fuzzPair(data []byte) int { // // For the definition of `s` see 3.5 in https://eprint.iacr.org/2015/192.pdf func normalizeGTToGnark(cloudflareOrGoogleGT []byte) *gnark.GT { - // Compute s = 2*u(6*u^2 + 3*u + 1) u, _ := new(big.Int).SetString("0x44e992b44a6909f1", 0) u_exp2 := new(big.Int).Exp(u, big.NewInt(2), nil) // u^2