go-ethereum/crypto/bn256/gnark/g1.go
cui 88922d2bf5
Some checks are pending
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
crypto/bn256: refactor to use bitutil.TestBytes (#32435)
2025-08-15 15:12:22 +08:00

85 lines
2.1 KiB
Go

package bn256
import (
"errors"
"math/big"
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/common/bitutil"
)
// 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`
//
// The input is expected to be in the EVM format:
// 64 bytes: [32-byte x coordinate][32-byte y coordinate]
// where each coordinate is in big-endian format.
//
// 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) {
if len(buf) < 64 {
return 0, errors.New("invalid G1 point size")
}
if !bitutil.TestBytes(buf[:64]) {
// point at infinity
g.inner.X.SetZero()
g.inner.Y.SetZero()
return 64, nil
}
if err := g.inner.X.SetBytesCanonical(buf[:32]); err != nil {
return 0, err
}
if err := g.inner.Y.SetBytesCanonical(buf[32:64]); err != nil {
return 0, err
}
if !g.inner.IsOnCurve() {
return 0, errors.New("point is not on curve")
}
if !g.inner.IsInSubGroup() {
return 0, errors.New("point is not in correct subgroup")
}
return 64, nil
}
// Marshal serializes the point into a byte slice.
//
// The output is in EVM format: 64 bytes total.
// [32-byte x coordinate][32-byte y coordinate]
// where each coordinate is a big-endian integer padded to 32 bytes.
func (p *G1) Marshal() []byte {
output := make([]byte, 64)
xBytes := p.inner.X.Bytes()
copy(output[:32], xBytes[:])
yBytes := p.inner.Y.Bytes()
copy(output[32:64], yBytes[:])
return output
}