Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upgrade crypto package #790

Merged
merged 8 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crypto/bn256/cloudflare/gfp12.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
}

func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
e.x.Mul(&e.x, b)
e.y.Mul(&e.y, b)
e.x.Mul(&a.x, b)
e.y.Mul(&a.y, b)
return e
}

Expand Down
51 changes: 51 additions & 0 deletions crypto/bn256/gnark/g1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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) {
g.inner.Add(&a.inner, &b.inner)
}

// 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)
}

// Unmarshal deserializes `buf` into `g`
//
// 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.
//
// 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)
}

// Marshal serializes the point into a byte slice.
//
// Note: The point is serialized as uncompressed.
func (p *G1) Marshal() []byte {
return p.inner.Marshal()
}
38 changes: 38 additions & 0 deletions crypto/bn256/gnark/g2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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 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.
type G2 struct {
inner bn254.G2Affine
}

// Unmarshal deserializes `buf` into `g`
//
// 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.
//
// 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)
}

// Marshal serializes the point into a byte slice.
//
// Note: The point is serialized as uncompressed.
func (g *G2) Marshal() []byte {
return g.inner.Marshal()
}
65 changes: 65 additions & 0 deletions crypto/bn256/gnark/gt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
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 &GT{
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 raises `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
}
73 changes: 73 additions & 0 deletions crypto/bn256/gnark/pairing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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_)

// 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
}

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
}
2 changes: 1 addition & 1 deletion crypto/bn256/google/bn256.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
)

// BUG(agl): this implementation is not constant time.
// TODO(agl): keep GF(p²) elements in Mongomery form.
// TODO(agl): keep GF(p²) elements in Montgomery form.

// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
Expand Down
4 changes: 2 additions & 2 deletions crypto/bn256/google/gfp12.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
}

func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
e.x.Mul(e.x, b, pool)
e.y.Mul(e.y, b, pool)
e.x.Mul(a.x, b, pool)
e.y.Mul(a.y, b, pool)
return e
}

Expand Down
21 changes: 14 additions & 7 deletions crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,21 @@ const RecoveryIDOffset = 64
const DigestLength = 32

var (
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1N = S256().Params().N
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
)

var errInvalidPubkey = errors.New("invalid secp256k1 public key")

// EllipticCurve contains curve operations.
type EllipticCurve interface {
elliptic.Curve

// Point marshaling/unmarshaing.
Marshal(x, y *big.Int) []byte
Unmarshal(data []byte) (x, y *big.Int)
}

// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
Expand Down Expand Up @@ -148,7 +157,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
return nil, errors.New("invalid private key, zero or negative")
}

priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(d)
if priv.PublicKey.X == nil {
return nil, errors.New("invalid private key")
}
Expand All @@ -165,7 +174,7 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {

// UnmarshalPubkey converts bytes to a secp256k1 public key.
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
x, y := elliptic.Unmarshal(S256(), pub)
x, y := S256().Unmarshal(pub)
if x == nil {
return nil, errInvalidPubkey
}
Expand All @@ -176,7 +185,7 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(S256(), pub.X, pub.Y)
return S256().Marshal(pub.X, pub.Y)
}

// HexToECDSA parses a secp256k1 private key.
Expand Down Expand Up @@ -278,7 +287,5 @@ func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
}

func zeroBytes(bytes []byte) {
for i := range bytes {
bytes[i] = 0
}
clear(bytes)
}
Loading
Loading