mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 23:47:55 -05:00
* chore bring over changes from other branch * chore: blocks as byte arrays not lists; tx.S <- 1 * build: update compressor lib release script by jpnovais * docs and go generate --------- Co-authored-by: Arya Tabaie <15056835+Tabaie@users.noreply.github.com>
349 lines
9.5 KiB
Go
349 lines
9.5 KiB
Go
package blobsubmission
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/consensys/linea-monorepo/prover/lib/compressor/blob/encode"
|
|
|
|
fr381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
|
"github.com/consensys/linea-monorepo/prover/utils"
|
|
gokzg4844 "github.com/crate-crypto/go-kzg-4844"
|
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const (
|
|
_inFile = "./samples/sample0.json"
|
|
_outFile = "./samples/sample0-response.json"
|
|
_inFileEIP4844 = "./samples/sample1.json"
|
|
_outFileEIP4844 = "./samples/sample1-response.json"
|
|
_inFileEIP4844MaxSize = "./samples/sample-max-size.json"
|
|
_outFileEIP4844MaxSize = "./samples/sample-max-size-response.json"
|
|
_inFileEIP4844Empty = "./samples/sample-empty.json"
|
|
_outFileEIP4844Empty = "./samples/sample-empty-response.json"
|
|
_inFileEIP4844TooLarge = "./samples/sample-too-large.json"
|
|
)
|
|
|
|
// blobsubmission with callData
|
|
// eip4844Enabled=false
|
|
func TestBlobSubmission(t *testing.T) {
|
|
fIn, err := os.Open(_inFile)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _inFile, err)
|
|
}
|
|
defer fIn.Close()
|
|
|
|
fOut, err := os.Open(_outFile)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _outFile, err)
|
|
}
|
|
defer fOut.Close()
|
|
|
|
var (
|
|
inp Request
|
|
outExpected Response
|
|
)
|
|
|
|
if err = json.NewDecoder(fIn).Decode(&inp); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", inp, err)
|
|
}
|
|
|
|
if err = json.NewDecoder(fOut).Decode(&outExpected); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", outExpected, err)
|
|
}
|
|
|
|
// call CraftResponseCalldata()
|
|
out, err := CraftResponse(&inp)
|
|
|
|
ok := assert.NoErrorf(t, err, "could not craft the response: %v", err)
|
|
if ok {
|
|
assert.Equal(t, outExpected, *out, "the response file should be the same")
|
|
}
|
|
|
|
// Stop the test after the first failed file to not overwhelm the
|
|
// logs.
|
|
if t.Failed() {
|
|
t.Fatalf("Got errors for file %s, stopping the test", _outFile)
|
|
}
|
|
}
|
|
|
|
// eip4844 blob submission
|
|
// eip4844Enabled = true
|
|
func TestBlobSubmissionEIP4844(t *testing.T) {
|
|
fIn, err := os.Open(_inFileEIP4844)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _inFileEIP4844, err)
|
|
}
|
|
defer fIn.Close()
|
|
|
|
fOut, err := os.Open(_outFileEIP4844)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _outFileEIP4844, err)
|
|
}
|
|
defer fOut.Close()
|
|
|
|
var (
|
|
inp Request
|
|
outExpected Response
|
|
)
|
|
|
|
if err = json.NewDecoder(fIn).Decode(&inp); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", inp, err)
|
|
}
|
|
|
|
if err = json.NewDecoder(fOut).Decode(&outExpected); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", outExpected, err)
|
|
}
|
|
|
|
out, err := CraftResponse(&inp)
|
|
|
|
ok := assert.NoErrorf(t, err, "could not craft the response: %v", err)
|
|
if ok {
|
|
assert.Equal(t, outExpected, *out, "the response file should be the same")
|
|
}
|
|
|
|
// Stop the test after the first failed file to not overwhelm the
|
|
// logs.
|
|
if t.Failed() {
|
|
t.Fatalf("Got errors for file %s, stopping the test", _outFileEIP4844)
|
|
}
|
|
}
|
|
|
|
// empty blob
|
|
func TestBlobSubmissionEIP4844EmptyBlob(t *testing.T) {
|
|
fIn, err := os.Open(_inFileEIP4844Empty)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _inFileEIP4844Empty, err)
|
|
}
|
|
defer fIn.Close()
|
|
|
|
fOut, err := os.Open(_outFileEIP4844Empty)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _outFileEIP4844Empty, err)
|
|
}
|
|
defer fOut.Close()
|
|
|
|
var (
|
|
inp Request
|
|
outExpected Response
|
|
)
|
|
|
|
if err = json.NewDecoder(fIn).Decode(&inp); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", inp, err)
|
|
}
|
|
|
|
if err = json.NewDecoder(fOut).Decode(&outExpected); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", outExpected, err)
|
|
}
|
|
|
|
compressedStream, _ := b64.DecodeString(inp.CompressedData)
|
|
// Check if len(compressedStream) is equal to 0
|
|
expectedLength := 0
|
|
actualLength := len(compressedStream)
|
|
assert.Equal(t, expectedLength, actualLength, "compressed stream length mismatch")
|
|
|
|
out, err := CraftResponse(&inp)
|
|
|
|
ok := assert.NoErrorf(t, err, "could not craft the response: %v", err)
|
|
if ok {
|
|
assert.Equal(t, outExpected, *out, "the response file should be the same")
|
|
}
|
|
|
|
// Stop the test after the first failed file to not overwhelm the
|
|
// logs.
|
|
if t.Failed() {
|
|
t.Fatalf("Got errors for file %s, stopping the test", _outFileEIP4844)
|
|
}
|
|
}
|
|
|
|
// random blob with [131072] bytes
|
|
func TestBlobSubmissionEIP4844MaxSize(t *testing.T) {
|
|
fIn, err := os.Open(_inFileEIP4844MaxSize)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _inFileEIP4844MaxSize, err)
|
|
}
|
|
defer fIn.Close()
|
|
|
|
fOut, err := os.Open(_outFileEIP4844MaxSize)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _outFileEIP4844MaxSize, err)
|
|
}
|
|
defer fOut.Close()
|
|
|
|
var (
|
|
inp Request
|
|
outExpected Response
|
|
)
|
|
|
|
if err = json.NewDecoder(fIn).Decode(&inp); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", inp, err)
|
|
}
|
|
|
|
if err = json.NewDecoder(fOut).Decode(&outExpected); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", _outFileEIP4844MaxSize, err)
|
|
}
|
|
|
|
compressedStream, _ := b64.DecodeString(inp.CompressedData)
|
|
// Check if len(compressedStream) is equal to 131072
|
|
expectedLength := 131072
|
|
actualLength := len(compressedStream)
|
|
assert.Equal(t, expectedLength, actualLength, "compressed stream length mismatch")
|
|
|
|
out, err := CraftResponse(&inp)
|
|
|
|
ok := assert.NoErrorf(t, err, "could not craft the response: %v", err)
|
|
if ok {
|
|
assert.Equal(t, outExpected, *out, "the response file should be the same")
|
|
}
|
|
|
|
// Stop the test after the first failed file to not overwhelm the
|
|
// logs.
|
|
if t.Failed() {
|
|
t.Fatalf("Got errors for file %s, stopping the test", _outFileEIP4844MaxSize)
|
|
}
|
|
}
|
|
|
|
// blob too large error with [131072 + 32] bytes
|
|
func TestBlobSubmissionEIP4844BlobTooLarge(t *testing.T) {
|
|
|
|
var blob kzg4844.Blob
|
|
fIn, err := os.Open(_inFileEIP4844TooLarge)
|
|
if err != nil {
|
|
t.Fatalf("could not open %s: %v", _inFileEIP4844TooLarge, err)
|
|
}
|
|
defer fIn.Close()
|
|
|
|
var (
|
|
inp Request
|
|
)
|
|
|
|
if err = json.NewDecoder(fIn).Decode(&inp); err != nil {
|
|
t.Fatalf("could not decode %++v: %v", inp, err)
|
|
}
|
|
|
|
_, err = CraftResponse(&inp)
|
|
|
|
// Check if err is not nil
|
|
if err == nil {
|
|
t.Errorf("expected an error `compressedStream length exceeds blob length (131072)`, but got nil")
|
|
return
|
|
}
|
|
|
|
compressedStream, _ := b64.DecodeString(inp.CompressedData)
|
|
// Check if the error message contains the expected substring
|
|
expectedErrorMsg := fmt.Sprintf("compressedStream length (%d) exceeds blob length (%d)", len(compressedStream), len(blob))
|
|
if !strings.Contains(err.Error(), expectedErrorMsg) {
|
|
t.Errorf("expected error message to contain %q, got %q", expectedErrorMsg, err.Error())
|
|
}
|
|
|
|
}
|
|
|
|
// a random blob from kzg4844 package and xPoint from evaluationChallenge()
|
|
func TestKZGWithPoint(t *testing.T) {
|
|
|
|
blobBytes := randBlob()
|
|
|
|
// Also zeroize all the bytes that are at position multiples of 32. This
|
|
// ensures that we will not have overflow when casting to the bls12 scalar
|
|
// field.
|
|
n := len(blobBytes)
|
|
n = utils.DivCeil(n, 32) * 32 // round up to the next multiple of 32
|
|
for i := 0; i < n; i += 32 {
|
|
blobBytes[i] = 0
|
|
}
|
|
|
|
commitment, err := kzg4844.BlobToCommitment(&blobBytes)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG commitment from blob: %v", err)
|
|
}
|
|
|
|
// blobHash
|
|
blobHash := kzg4844.CalcBlobHashV1(sha256.New(), &commitment)
|
|
if !kzg4844.IsValidVersionedHash(blobHash[:]) {
|
|
t.Fatalf("crafting response: invalid versionedHash (blobHash, dataHash): %v", err)
|
|
}
|
|
|
|
// Compute all the prover fields
|
|
snarkHash, err := encode.MiMCChecksumPackedData(blobBytes[:], fr381.Bits-1, encode.NoTerminalSymbol())
|
|
assert.NoError(t, err)
|
|
|
|
xUnreduced := evaluationChallenge(snarkHash, blobHash[:])
|
|
var tmp fr381.Element
|
|
tmp.SetBytes(xUnreduced[:])
|
|
xPoint := kzg4844.Point(tmp.Bytes())
|
|
|
|
proof, claim, err := kzg4844.ComputeProof(&blobBytes, xPoint)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG proof at point: %v", err)
|
|
}
|
|
if err := kzg4844.VerifyProof(commitment, xPoint, claim, proof); err != nil {
|
|
t.Fatalf("failed to verify KZG proof at point: %v", err)
|
|
}
|
|
}
|
|
|
|
// a random blob and xPoint from kzg4844 package
|
|
func TestKZGWithPointSimple(t *testing.T) {
|
|
|
|
blob := randBlob()
|
|
|
|
commitment, err := kzg4844.BlobToCommitment(&blob)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG commitment from blob: %v", err)
|
|
}
|
|
xPoint := randFieldElement()
|
|
proof, claim, err := kzg4844.ComputeProof(&blob, xPoint)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG proof at point: %v", err)
|
|
}
|
|
if err := kzg4844.VerifyProof(commitment, xPoint, claim, proof); err != nil {
|
|
t.Fatalf("failed to verify KZG proof at point: %v", err)
|
|
}
|
|
}
|
|
|
|
// simple kzg from kzg4844 package
|
|
func TestKZGWithBlob(t *testing.T) {
|
|
|
|
blob := randBlob()
|
|
|
|
commitment, err := kzg4844.BlobToCommitment(&blob)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG commitment from blob: %v", err)
|
|
}
|
|
proof, err := kzg4844.ComputeBlobProof(&blob, commitment)
|
|
if err != nil {
|
|
t.Fatalf("failed to create KZG proof for blob: %v", err)
|
|
}
|
|
if err := kzg4844.VerifyBlobProof(&blob, commitment, proof); err != nil {
|
|
t.Fatalf("failed to verify KZG proof for blob: %v", err)
|
|
}
|
|
}
|
|
|
|
// randFieldElement() from kzg4844 package
|
|
func randFieldElement() [32]byte {
|
|
bytes := make([]byte, 32)
|
|
_, err := rand.Read(bytes)
|
|
if err != nil {
|
|
panic("failed to get random field element")
|
|
}
|
|
var r fr381.Element
|
|
r.SetBytes(bytes)
|
|
|
|
return gokzg4844.SerializeScalar(r)
|
|
}
|
|
|
|
// randBlob() from kzg4844 package
|
|
func randBlob() kzg4844.Blob {
|
|
var blob kzg4844.Blob
|
|
for i := 0; i < len(blob); i += gokzg4844.SerializedScalarSize {
|
|
fieldElementBytes := randFieldElement()
|
|
copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:])
|
|
}
|
|
return blob
|
|
}
|