Skip to content

Commit

Permalink
Add decode flag for GetBlob() by reworking codec layer (#592)
Browse files Browse the repository at this point in the history
  • Loading branch information
teddyknox authored Jun 6, 2024
1 parent b344eb2 commit e90cb74
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 146 deletions.
20 changes: 19 additions & 1 deletion api/clients/codecs/blob_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,26 @@ type BlobCodec interface {
func BlobEncodingVersionToCodec(version BlobEncodingVersion) (BlobCodec, error) {
switch version {
case DefaultBlobEncoding:
return DefaultBlobEncodingCodec{}, nil
return DefaultBlobCodec{}, nil
default:
return nil, fmt.Errorf("unsupported blob encoding version: %x", version)
}
}

func GenericDecodeBlob(data []byte) ([]byte, error) {
if len(data) <= 32 {
return nil, fmt.Errorf("data is not of length greater than 32 bytes: %d", len(data))
}
version := BlobEncodingVersion(data[1])
codec, err := BlobEncodingVersionToCodec(version)
if err != nil {
return nil, err
}

data, err = codec.DecodeBlob(data)
if err != nil {
return nil, err
}

return data, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,45 @@ func randomByteSlice(length int64) []byte {
return b
}

// TestDefaultBlobEncodingCodec tests the encoding and decoding of random byte streams
func TestDefaultBlobEncodingCodec(t *testing.T) {
// TestIFFTCodec tests the encoding and decoding of random byte streams
func TestIFFTCodec(t *testing.T) {
// Create an instance of the DefaultBlobEncodingCodec
codec := codecs.DefaultBlobEncodingCodec{}
codec := codecs.NewIFFTCodec(codecs.NewDefaultBlobCodec())

// Number of test iterations
const iterations = 100

for i := 0; i < iterations; i++ {
// Generate a random length for the byte slice
length, err := rand.Int(rand.Reader, big.NewInt(1024)) // Random length between 0 and 1023
if err != nil {
panic(err)
}
originalData := randomByteSlice(length.Int64() + 1) // ensure it's not length 0

// Encode the original data
encodedData, err := codec.EncodeBlob(originalData)
if err != nil {
t.Fatalf("Iteration %d: failed to encode blob: %v", i, err)
}

// Decode the encoded data
decodedData, err := codec.DecodeBlob(encodedData)
if err != nil {
t.Fatalf("Iteration %d: failed to decode blob: %v", i, err)
}

// Compare the original data with the decoded data
if !bytes.Equal(originalData, decodedData) {
t.Fatalf("Iteration %d: original and decoded data do not match\nOriginal: %v\nDecoded: %v", i, originalData, decodedData)
}
}
}

// TestIFFTCodec tests the encoding and decoding of random byte streams
func TestNoIFFTCodec(t *testing.T) {
// Create an instance of the DefaultBlobEncodingCodec
codec := codecs.NewNoIFFTCodec(codecs.NewDefaultBlobCodec())

// Number of test iterations
const iterations = 100
Expand Down
59 changes: 59 additions & 0 deletions api/clients/codecs/default_blob_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package codecs

import (
"bytes"
"encoding/binary"
"fmt"

"github.com/Layr-Labs/eigenda/encoding/utils/codec"
)

type DefaultBlobCodec struct{}

var _ BlobCodec = DefaultBlobCodec{}

func NewDefaultBlobCodec() DefaultBlobCodec {
return DefaultBlobCodec{}
}

func (v DefaultBlobCodec) EncodeBlob(rawData []byte) ([]byte, error) {
codecBlobHeader := make([]byte, 32)
// first byte is always 0 to ensure the codecBlobHeader is a valid bn254 element
// encode version byte
codecBlobHeader[1] = byte(DefaultBlobEncoding)

// encode length as uint32
binary.BigEndian.PutUint32(codecBlobHeader[2:6], uint32(len(rawData))) // uint32 should be more than enough to store the length (approx 4gb)

// encode raw data modulo bn254
rawDataPadded := codec.ConvertByPaddingEmptyByte(rawData)

// append raw data
encodedData := append(codecBlobHeader, rawDataPadded...)

return encodedData, nil
}

func (v DefaultBlobCodec) DecodeBlob(data []byte) ([]byte, error) {
if len(data) < 32 {
return nil, fmt.Errorf("blob does not contain 32 header bytes, meaning it is malformed")
}

length := binary.BigEndian.Uint32(data[2:6])

// decode raw data modulo bn254
decodedData := codec.RemoveEmptyByteFromPaddedBytes(data[32:])

// get non blob header data
reader := bytes.NewReader(decodedData)
rawData := make([]byte, length)
n, err := reader.Read(rawData)
if err != nil {
return nil, fmt.Errorf("failed to copy unpadded data into final buffer, length: %d, bytes read: %d", length, n)
}
if uint32(n) != length {
return nil, fmt.Errorf("data length does not match length prefix")
}

return rawData, nil
}
49 changes: 0 additions & 49 deletions api/clients/codecs/default_blob_encoding_codec.go

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package clients
package codecs

import (
"fmt"
Expand Down
38 changes: 38 additions & 0 deletions api/clients/codecs/ifft_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package codecs

import "fmt"

type IFFTCodec struct {
writeCodec BlobCodec
}

var _ BlobCodec = IFFTCodec{}

func NewIFFTCodec(writeCodec BlobCodec) IFFTCodec {
return IFFTCodec{
writeCodec: writeCodec,
}
}

func (v IFFTCodec) EncodeBlob(data []byte) ([]byte, error) {
var err error
data, err = v.writeCodec.EncodeBlob(data)
if err != nil {
return nil, fmt.Errorf("error encoding data: %w", err)
}

return IFFT(data)
}

func (v IFFTCodec) DecodeBlob(data []byte) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("blob has length 0, meaning it is malformed")
}
var err error
data, err = FFT(data)
if err != nil {
return nil, fmt.Errorf("error FFTing data: %w", err)
}

return GenericDecodeBlob(data)
}
21 changes: 21 additions & 0 deletions api/clients/codecs/no_ifft_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package codecs

type NoIFFTCodec struct {
writeCodec BlobCodec
}

var _ BlobCodec = NoIFFTCodec{}

func NewNoIFFTCodec(writeCodec BlobCodec) NoIFFTCodec {
return NoIFFTCodec{
writeCodec: writeCodec,
}
}

func (v NoIFFTCodec) EncodeBlob(data []byte) ([]byte, error) {
return v.writeCodec.EncodeBlob(data)
}

func (v NoIFFTCodec) DecodeBlob(data []byte) ([]byte, error) {
return GenericDecodeBlob(data)
}
30 changes: 0 additions & 30 deletions api/clients/codecs/utils.go

This file was deleted.

Loading

0 comments on commit e90cb74

Please sign in to comment.