diff --git a/encoding/serialization.go b/encoding/serialization.go index 830d29a773..bd9daed58b 100644 --- a/encoding/serialization.go +++ b/encoding/serialization.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "encoding/json" + "errors" "fmt" "github.com/consensys/gnark-crypto/ecc/bn254" @@ -22,6 +23,41 @@ func (c *Frame) Deserialize(data []byte) (*Frame, error) { return c, err } +func (c *Frame) SerializeGnark() ([]byte, error) { + coded := make([]byte, 0, bn254.SizeOfG1AffineCompressed+BYTES_PER_SYMBOL*len(c.Coeffs)) + // This is compressed format with just 32 bytes. + proofBytes := c.Proof.Bytes() + coded = append(coded, proofBytes[:]...) + for _, coeff := range c.Coeffs { + coded = append(coded, coeff.Marshal()...) + } + return coded, nil +} + +func (c *Frame) DeserializeGnark(data []byte) (*Frame, error) { + var f Frame + buf := data + err := f.Proof.Unmarshal(buf[:bn254.SizeOfG1AffineCompressed]) + if err != nil { + return nil, err + } + buf = buf[bn254.SizeOfG1AffineCompressed:] + if len(buf)%BYTES_PER_SYMBOL != 0 { + return nil, errors.New("invalid chunk length") + } + f.Coeffs = make([]Symbol, len(buf)/BYTES_PER_SYMBOL) + i := 0 + for len(buf) > 0 { + if len(buf) < BYTES_PER_SYMBOL { + return nil, errors.New("invalid chunk length") + } + f.Coeffs[i].Unmarshal(buf[:BYTES_PER_SYMBOL]) + i++ + buf = buf[BYTES_PER_SYMBOL:] + } + return &f, nil +} + func (f *Frame) Encode() ([]byte, error) { var buf bytes.Buffer enc := gob.NewEncoder(&buf) diff --git a/encoding/serialization_test.go b/encoding/serialization_test.go new file mode 100644 index 0000000000..ffc3d98958 --- /dev/null +++ b/encoding/serialization_test.go @@ -0,0 +1,47 @@ +package encoding_test + +import ( + "testing" + + "github.com/Layr-Labs/eigenda/encoding" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/stretchr/testify/assert" +) + +func TestSerDeserGnark(t *testing.T) { + var XCoord, YCoord fp.Element + _, err := XCoord.SetString("21661178944771197726808973281966770251114553549453983978976194544185382599016") + assert.NoError(t, err) + _, err = YCoord.SetString("9207254729396071334325696286939045899948985698134704137261649190717970615186") + assert.NoError(t, err) + + numCoeffs := 64 + var f encoding.Frame + f.Proof = encoding.Proof{ + X: XCoord, + Y: YCoord, + } + for i := 0; i < numCoeffs; i++ { + f.Coeffs = append(f.Coeffs, fr.NewElement(uint64(i))) + } + + gnark, err := f.SerializeGnark() + assert.Nil(t, err) + // The gnark encoding via f.Serialize() will generate less bytes + // than gob. + assert.Equal(t, 32*(1+numCoeffs), len(gnark)) + gob, err := f.Serialize() + assert.Nil(t, err) + // 2080 with gnark v.s. 2574 with gob + assert.Equal(t, 2574, len(gob)) + + // Verify the deserialization can get back original data + c, err := new(encoding.Frame).DeserializeGnark(gnark) + assert.Nil(t, err) + assert.True(t, f.Proof.Equal(&c.Proof)) + assert.Equal(t, len(f.Coeffs), len(c.Coeffs)) + for i := 0; i < len(f.Coeffs); i++ { + assert.True(t, f.Coeffs[i].Equal(&c.Coeffs[i])) + } +}