mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-04-01 07:35:58 +00:00
85 lines
2.1 KiB
Go
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
|
|
}
|