mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
initial commit
This commit is contained in:
parent
3a5313f3f3
commit
db226c0680
4 changed files with 259 additions and 0 deletions
74
crypto/bn256/gnark/g1.go
Normal file
74
crypto/bn256/gnark/g1.go
Normal file
|
|
@ -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()
|
||||||
|
}
|
||||||
73
crypto/bn256/gnark/g1_aff.go
Normal file
73
crypto/bn256/gnark/g1_aff.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
48
crypto/bn256/gnark/g2.go
Normal file
48
crypto/bn256/gnark/g2.go
Normal file
|
|
@ -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()
|
||||||
|
}
|
||||||
64
crypto/bn256/gnark/pairing.go
Normal file
64
crypto/bn256/gnark/pairing.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue