mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
modify gnark marshal and unmarshal
This commit is contained in:
parent
65d77c5129
commit
bfbfa39eb9
3 changed files with 178 additions and 16 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/consensys/gnark-crypto/ecc/bn254"
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
|
|
@ -31,21 +32,68 @@ func (g *G1) ScalarMult(a *G1, scalar *big.Int) {
|
||||||
|
|
||||||
// Unmarshal deserializes `buf` into `g`
|
// Unmarshal deserializes `buf` into `g`
|
||||||
//
|
//
|
||||||
// Note: whether the deserialization is of a compressed
|
// The input is expected to be in the EVM format:
|
||||||
// or an uncompressed point, is encoded in the bytes.
|
// 64 bytes: [32-byte x coordinate][32-byte y coordinate]
|
||||||
//
|
// where each coordinate is in big-endian format.
|
||||||
// For our purpose, the point will always be serialized
|
|
||||||
// as uncompressed, ie 64 bytes.
|
|
||||||
//
|
//
|
||||||
// This method also checks whether the point is on the
|
// This method also checks whether the point is on the
|
||||||
// curve and in the prime order subgroup.
|
// curve and in the prime order subgroup.
|
||||||
func (g *G1) Unmarshal(buf []byte) (int, error) {
|
func (g *G1) Unmarshal(buf []byte) (int, error) {
|
||||||
return g.inner.SetBytes(buf)
|
if len(buf) < 64 {
|
||||||
|
return 0, errors.New("invalid G1 point size")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if both coordinates are zero (point at infinity)
|
||||||
|
isZero := true
|
||||||
|
for i := 0; i < 64; i++ {
|
||||||
|
if buf[i] != 0 {
|
||||||
|
isZero = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isZero {
|
||||||
|
g.inner.X.SetZero()
|
||||||
|
g.inner.Y.SetZero()
|
||||||
|
return 64, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := g.inner.X.SetBytesCanonical(buf[:32])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = g.inner.Y.SetBytesCanonical(buf[32:64])
|
||||||
|
if 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.
|
// Marshal serializes the point into a byte slice.
|
||||||
//
|
//
|
||||||
// Note: The point is serialized as uncompressed.
|
// 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 {
|
func (p *G1) Marshal() []byte {
|
||||||
return p.inner.Marshal()
|
output := make([]byte, 64)
|
||||||
|
|
||||||
|
// Handle point at infinity
|
||||||
|
if p.inner.X.IsZero() && p.inner.Y.IsZero() {
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
xBytes := p.inner.X.Bytes()
|
||||||
|
copy(output[:32], xBytes[:])
|
||||||
|
|
||||||
|
yBytes := p.inner.Y.Bytes()
|
||||||
|
copy(output[32:64], yBytes[:])
|
||||||
|
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/consensys/gnark-crypto/ecc/bn254"
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,21 +20,86 @@ type G2 struct {
|
||||||
|
|
||||||
// Unmarshal deserializes `buf` into `g`
|
// Unmarshal deserializes `buf` into `g`
|
||||||
//
|
//
|
||||||
// Note: whether the deserialization is of a compressed
|
// The input is expected to be in the EVM format:
|
||||||
// or an uncompressed point, is encoded in the bytes.
|
// 128 bytes: [32-byte x.real][32-byte x.imag][32-byte y.real][32-byte y.imag]
|
||||||
//
|
// where each value is a big-endian integer.
|
||||||
// For our purpose, the point will always be serialized
|
|
||||||
// as uncompressed, ie 128 bytes.
|
|
||||||
//
|
//
|
||||||
// This method also checks whether the point is on the
|
// This method also checks whether the point is on the
|
||||||
// curve and in the prime order subgroup.
|
// curve and in the prime order subgroup.
|
||||||
func (g *G2) Unmarshal(buf []byte) (int, error) {
|
func (g *G2) Unmarshal(buf []byte) (int, error) {
|
||||||
return g.inner.SetBytes(buf)
|
if len(buf) < 128 {
|
||||||
|
return 0, errors.New("invalid G2 point size")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all coordinates are zero (point at infinity)
|
||||||
|
isZero := true
|
||||||
|
for i := 0; i < 128; i++ {
|
||||||
|
if buf[i] != 0 {
|
||||||
|
isZero = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isZero {
|
||||||
|
g.inner.X.A0.SetZero()
|
||||||
|
g.inner.X.A1.SetZero()
|
||||||
|
g.inner.Y.A0.SetZero()
|
||||||
|
g.inner.Y.A1.SetZero()
|
||||||
|
return 128, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := g.inner.X.A0.SetBytesCanonical(buf[0:32])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = g.inner.X.A1.SetBytesCanonical(buf[32:64])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = g.inner.Y.A0.SetBytesCanonical(buf[64:96])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = g.inner.Y.A1.SetBytesCanonical(buf[96:128])
|
||||||
|
if 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 128, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal serializes the point into a byte slice.
|
// Marshal serializes the point into a byte slice.
|
||||||
//
|
//
|
||||||
// Note: The point is serialized as uncompressed.
|
// The output is in EVM format: 128 bytes total.
|
||||||
|
// [32-byte x.real][32-byte x.imag][32-byte y.real][32-byte y.imag]
|
||||||
|
// where each value is a big-endian integer padded to 32 bytes.
|
||||||
func (g *G2) Marshal() []byte {
|
func (g *G2) Marshal() []byte {
|
||||||
return g.inner.Marshal()
|
output := make([]byte, 128)
|
||||||
|
|
||||||
|
// Handle point at infinity
|
||||||
|
if g.inner.X.A0.IsZero() && g.inner.X.A1.IsZero() &&
|
||||||
|
g.inner.Y.A0.IsZero() && g.inner.Y.A1.IsZero() {
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
xA0Bytes := g.inner.X.A0.Bytes()
|
||||||
|
copy(output[:32], xA0Bytes[:])
|
||||||
|
|
||||||
|
xA1Bytes := g.inner.X.A1.Bytes()
|
||||||
|
copy(output[32:64], xA1Bytes[:])
|
||||||
|
|
||||||
|
yA0Bytes := g.inner.Y.A0.Bytes()
|
||||||
|
copy(output[64:96], yA0Bytes[:])
|
||||||
|
|
||||||
|
yA1Bytes := g.inner.Y.A1.Bytes()
|
||||||
|
copy(output[96:128], yA1Bytes[:])
|
||||||
|
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
crypto/bn256/gnark/native_format_test.go
Normal file
47
crypto/bn256/gnark/native_format_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNativeGnarkFormatIncompatibility(t *testing.T) {
|
||||||
|
// Use official gnark serialization
|
||||||
|
_, _, g1Gen, _ := bn254.Generators()
|
||||||
|
wrongSer := g1Gen.Bytes()
|
||||||
|
|
||||||
|
// This should fail since the evm serializes points in a different format
|
||||||
|
var evmG1 G1
|
||||||
|
_, err := evmG1.Unmarshal(wrongSer[:])
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Points serialized using the official bn254 serialization algorithm, should not work with the evm format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSerRoundTrip(t *testing.T) {
|
||||||
|
_, _, g1Gen, g2Gen := bn254.Generators()
|
||||||
|
|
||||||
|
expectedG1 := G1{
|
||||||
|
inner: g1Gen,
|
||||||
|
}
|
||||||
|
bytesG1 := expectedG1.Marshal()
|
||||||
|
|
||||||
|
expectedG2 := G2{
|
||||||
|
inner: g2Gen,
|
||||||
|
}
|
||||||
|
bytesG2 := expectedG2.Marshal()
|
||||||
|
|
||||||
|
var gotG1 G1
|
||||||
|
gotG1.Unmarshal(bytesG1)
|
||||||
|
|
||||||
|
var gotG2 G2
|
||||||
|
gotG2.Unmarshal(bytesG2)
|
||||||
|
|
||||||
|
if !expectedG1.inner.Equal(&gotG1.inner) {
|
||||||
|
t.Errorf("serialization roundtrip failed for G1")
|
||||||
|
}
|
||||||
|
if !expectedG2.inner.Equal(&gotG2.inner) {
|
||||||
|
t.Errorf("serialization roundtrip failed for G2")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue