Commit 2624af45 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Fix uploading blob preimages (#9441)

parent 7e44e7c3
......@@ -5,8 +5,8 @@ import (
"encoding/binary"
"errors"
"fmt"
"math/big"
gokzg4844 "github.com/crate-crypto/go-kzg-4844"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/eth"
......@@ -19,6 +19,7 @@ import (
const (
fieldElemKeyLength = 80
commitmentLength = 48
lengthPrefixSize = 8
)
var (
......@@ -51,10 +52,6 @@ func (l *preimageLoader) LoadPreimage(proof *proofData) (*types.PreimageOracleDa
}
func (l *preimageLoader) loadBlobPreimage(proof *proofData) (*types.PreimageOracleData, error) {
if len(proof.OracleValue) != gokzg4844.SerializedScalarSize {
return nil, fmt.Errorf("%w, expected length %v but was %v", ErrInvalidScalarValue, gokzg4844.SerializedScalarSize, len(proof.OracleValue))
}
// The key for a blob field element is a keccak hash of commitment++fieldElementIndex.
// First retrieve the preimage of the key as a keccak hash so we have the commitment and required field element
inputsKey := preimage.Keccak256Key(proof.OracleKey).PreimageKey()
......@@ -87,12 +84,20 @@ func (l *preimageLoader) loadBlobPreimage(proof *proofData) (*types.PreimageOrac
if err != nil || !bytes.Equal(blobCommitment[:], commitment[:]) {
return nil, fmt.Errorf("invalid blob commitment: %w", err)
}
// Compute the KZG proof for the required field element
kzgProof, _, err := kzg4844.ComputeProof(kzg4844.Blob(blob), kzg4844.Point(proof.OracleValue))
var point kzg4844.Point
new(big.Int).SetUint64(requiredFieldElement).FillBytes(point[:])
kzgProof, claim, err := kzg4844.ComputeProof(kzg4844.Blob(blob), point)
if err != nil {
return nil, fmt.Errorf("failed to compute kzg proof: %w", err)
}
err = kzg4844.VerifyProof(kzg4844.Commitment(commitment), point, claim, kzgProof)
if err != nil {
return nil, fmt.Errorf("failed to verify proof: %w", err)
}
return types.NewPreimageOracleBlobData(proof.OracleKey, proof.OracleValue, proof.OracleOffset, requiredFieldElement, commitment, kzgProof[:]), nil
claimWithLength := make([]byte, len(claim)+lengthPrefixSize)
binary.BigEndian.PutUint64(claimWithLength[:lengthPrefixSize], uint64(len(claim)))
copy(claimWithLength[lengthPrefixSize:], claim[:])
return types.NewPreimageOracleBlobData(proof.OracleKey, claimWithLength, proof.OracleOffset, requiredFieldElement, commitment, kzgProof[:]), nil
}
......@@ -4,6 +4,7 @@ import (
"crypto/sha256"
"encoding/binary"
"fmt"
"math/big"
"testing"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
......@@ -68,8 +69,13 @@ func TestPreimageLoader_BlobPreimage(t *testing.T) {
fieldIndex := uint64(24)
elementData := blob[fieldIndex<<5 : (fieldIndex+1)<<5]
kzgProof, _, err := kzg4844.ComputeProof(kzg4844.Blob(blob), kzg4844.Point(elementData))
var point kzg4844.Point
new(big.Int).SetUint64(fieldIndex).FillBytes(point[:])
kzgProof, claim, err := kzg4844.ComputeProof(kzg4844.Blob(blob), point)
require.NoError(t, err)
elementDataWithLengthPrefix := make([]byte, len(elementData)+lengthPrefixSize)
binary.BigEndian.PutUint64(elementDataWithLengthPrefix[:lengthPrefixSize], uint64(len(elementData)))
copy(elementDataWithLengthPrefix[lengthPrefixSize:], elementData)
keyBuf := make([]byte, 80)
copy(keyBuf[:48], commitment[:])
......@@ -78,22 +84,10 @@ func TestPreimageLoader_BlobPreimage(t *testing.T) {
proof := &proofData{
OracleKey: key[:],
OracleValue: elementData,
OracleValue: elementDataWithLengthPrefix,
OracleOffset: 4,
}
t.Run("RejectInvalidValueLength", func(t *testing.T) {
kv := kvstore.NewMemKV()
loader := newPreimageLoader(kv.Get)
proof := &proofData{
OracleKey: proof.OracleKey,
OracleValue: []byte{1, 2, 3},
OracleOffset: proof.OracleOffset,
}
_, err := loader.LoadPreimage(proof)
require.ErrorIs(t, err, ErrInvalidScalarValue)
})
t.Run("NoKeyPreimage", func(t *testing.T) {
kv := kvstore.NewMemKV()
loader := newPreimageLoader(kv.Get)
......@@ -138,9 +132,23 @@ func TestPreimageLoader_BlobPreimage(t *testing.T) {
storeBlob(t, kv, gokzg4844.KZGCommitment(commitment), blob)
actual, err := loader.LoadPreimage(proof)
require.NoError(t, err)
expected := types.NewPreimageOracleBlobData(proof.OracleKey, proof.OracleValue, proof.OracleOffset, fieldIndex, commitment[:], kzgProof[:])
claimWithLength := make([]byte, len(claim)+lengthPrefixSize)
binary.BigEndian.PutUint64(claimWithLength[:lengthPrefixSize], uint64(len(claim)))
copy(claimWithLength[lengthPrefixSize:], claim[:])
expected := types.NewPreimageOracleBlobData(proof.OracleKey, claimWithLength, proof.OracleOffset, fieldIndex, commitment[:], kzgProof[:])
require.Equal(t, expected, actual)
require.False(t, actual.IsLocal)
// Check the KZG proof is valid
var actualPoint kzg4844.Point
new(big.Int).SetUint64(actual.BlobFieldIndex).FillBytes(actualPoint[:])
actualClaim := kzg4844.Claim(actual.GetPreimageWithoutSize())
actualCommitment := kzg4844.Commitment(actual.BlobCommitment)
actualProof := kzg4844.Proof(actual.BlobProof)
err = kzg4844.VerifyProof(actualCommitment, actualPoint, actualClaim, actualProof)
require.NoError(t, err)
})
}
......
......@@ -273,11 +273,12 @@ func PreimageLargerThan(size int) PreimageOpt {
func NewTraceProviderForTest(logger log.Logger, m CannonMetricer, cfg *config.Config, localInputs LocalGameInputs, dir string, gameDepth types.Depth) *CannonTraceProviderForTest {
p := &CannonTraceProvider{
logger: logger,
dir: dir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, m, cfg, localInputs),
gameDepth: gameDepth,
logger: logger,
dir: dir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, m, cfg, localInputs),
gameDepth: gameDepth,
preimageLoader: newPreimageLoader(kvstore.NewDiskKV(preimageDir(dir)).Get),
}
return &CannonTraceProviderForTest{p}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment