github.com/ethereum/go-ethereum@v1.16.1/crypto/bn256/gnark/g1.go (about)

     1  package bn256
     2  
     3  import (
     4  	"errors"
     5  	"math/big"
     6  
     7  	"github.com/consensys/gnark-crypto/ecc/bn254"
     8  )
     9  
    10  // G1 is the affine representation of a G1 group element.
    11  //
    12  // Since this code is used for precompiles, using Jacobian
    13  // points are not beneficial because there are no intermediate
    14  // points to allow us to save on inversions.
    15  //
    16  // Note: We also use this struct so that we can conform to the existing API
    17  // that the precompiles want.
    18  type G1 struct {
    19  	inner bn254.G1Affine
    20  }
    21  
    22  // Add adds `a` and `b` together, storing the result in `g`
    23  func (g *G1) Add(a, b *G1) {
    24  	g.inner.Add(&a.inner, &b.inner)
    25  }
    26  
    27  // ScalarMult computes the scalar multiplication between `a` and
    28  // `scalar`, storing the result in `g`
    29  func (g *G1) ScalarMult(a *G1, scalar *big.Int) {
    30  	g.inner.ScalarMultiplication(&a.inner, scalar)
    31  }
    32  
    33  // Unmarshal deserializes `buf` into `g`
    34  //
    35  // The input is expected to be in the EVM format:
    36  // 64 bytes: [32-byte x coordinate][32-byte y coordinate]
    37  // where each coordinate is in big-endian format.
    38  //
    39  // This method also checks whether the point is on the
    40  // curve and in the prime order subgroup.
    41  func (g *G1) Unmarshal(buf []byte) (int, error) {
    42  	if len(buf) < 64 {
    43  		return 0, errors.New("invalid G1 point size")
    44  	}
    45  
    46  	if allZeroes(buf[:64]) {
    47  		// point at infinity
    48  		g.inner.X.SetZero()
    49  		g.inner.Y.SetZero()
    50  		return 64, nil
    51  	}
    52  
    53  	if err := g.inner.X.SetBytesCanonical(buf[:32]); err != nil {
    54  		return 0, err
    55  	}
    56  	if err := g.inner.Y.SetBytesCanonical(buf[32:64]); err != nil {
    57  		return 0, err
    58  	}
    59  
    60  	if !g.inner.IsOnCurve() {
    61  		return 0, errors.New("point is not on curve")
    62  	}
    63  	if !g.inner.IsInSubGroup() {
    64  		return 0, errors.New("point is not in correct subgroup")
    65  	}
    66  	return 64, nil
    67  }
    68  
    69  // Marshal serializes the point into a byte slice.
    70  //
    71  // The output is in EVM format: 64 bytes total.
    72  // [32-byte x coordinate][32-byte y coordinate]
    73  // where each coordinate is a big-endian integer padded to 32 bytes.
    74  func (p *G1) Marshal() []byte {
    75  	output := make([]byte, 64)
    76  
    77  	xBytes := p.inner.X.Bytes()
    78  	copy(output[:32], xBytes[:])
    79  
    80  	yBytes := p.inner.Y.Bytes()
    81  	copy(output[32:64], yBytes[:])
    82  
    83  	return output
    84  }
    85  
    86  func allZeroes(buf []byte) bool {
    87  	for i := range buf {
    88  		if buf[i] != 0 {
    89  			return false
    90  		}
    91  	}
    92  	return true
    93  }