From a67f95dca069fcc32014e1e9cf2c7d6200f4cec8 Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Mon, 12 May 2025 19:45:30 +0200 Subject: [PATCH 1/2] crypto/kzg4844: verify cell proofs --- core/txpool/validation.go | 15 +++++++------- crypto/kzg4844/kzg4844.go | 7 +++++++ crypto/kzg4844/kzg4844_ckzg_cgo.go | 27 ++++++++++++++++++++++++++ crypto/kzg4844/kzg4844_ckzg_nocgo.go | 5 +++++ crypto/kzg4844/kzg4844_gokzg.go | 29 ++++++++++++++++++++++++++++ crypto/kzg4844/kzg4844_test.go | 29 ++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 8 deletions(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 64e85a0e6e7c..59707c2bdc01 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -210,14 +210,13 @@ func validateBlobSidecarOsaka(hashes []common.Hash, sidecar *types.BlobTxSidecar } // Blob commitments match with the hashes in the transaction, verify the // blobs themselves via KZG - for i := range sidecar.Blobs { - // TODO verify the cell proof here - _ = i - /* - if err := kzg4844.VerifyBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { - return fmt.Errorf("invalid blob %d: %v", i, err) - } - */ + var blobs []*kzg4844.Blob + for _, blob := range sidecar.Blobs { + blobs = append(blobs, &blob) + } + + if err := kzg4844.VerifyCellProofs(blobs, sidecar.Commitments, sidecar.Proofs); err != nil { + return err } return nil } diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 5e14fbbd5e08..030eb563416f 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -155,6 +155,13 @@ func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { return gokzgVerifyBlobProof(blob, commitment, proof) } +func VerifyCellProofs(blobs []*Blob, commitments []Commitment, proofs []Proof) error { + if useCKZG.Load() { + return ckzgVerifyCellProofBatch(blobs, commitments, proofs) + } + return gokzgVerifyCellProofBatch(blobs, commitments, proofs) +} + // ComputeCellProofs returns the KZG cell proofs that are used to verify the blob against // the commitment. // diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 49a7046fe0d7..621974d17f81 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -149,3 +149,30 @@ func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) { } return p, nil } + +// ckzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proofs []Proof) error { + ckzgIniter.Do(ckzgInit) + + cells, err := ckzg.ComputeCells(blob) + if err != nil { + return err + } + cellIndices := make([]uint64, 0, len(cells)) + for range len(cells) { + cellIndices = append(cellIndices, 0) + } + kzgProofs := make([]ckzg4844.Bytes48, len(proofs)) + for _, proof := range proofs { + kzgProofs = append(kzgProofs, (ckzg4844.Bytes48)(proof)) + } + + valid, err := ckzg4844.VerifyCellKZGProofBatch(([]ckzg4844.Bytes48)(commitment), cells, cellIndices, kzgProofs) + if err != nil { + return err + } + if !valid { + return errors.New("invalid proof") + } + return nil +} diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go index 6f4bd3b8236f..3b12e1c2ad0a 100644 --- a/crypto/kzg4844/kzg4844_ckzg_nocgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -61,6 +61,11 @@ func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { panic("unsupported platform") } +// ckzgVerifyCellProofBatch verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proof []Proof) error { + panic("unsupported platform") +} + // ckzgComputeCellProofs returns the KZG cell proofs that are used to verify the blob against // the commitment. // diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go index 46a38a89136d..487d65da1dcc 100644 --- a/crypto/kzg4844/kzg4844_gokzg.go +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -114,3 +114,32 @@ func gokzgComputeCellProofs(blob *Blob) ([]Proof, error) { } return p, nil } + +// gokzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. +func gokzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proofs []Proof) error { + gokzgIniter.Do(gokzgInit) + + var cellIndices []uint64 + var cells []*gokzg4844.Cell + for i, blob := range blobs { + cellsI, err := context.ComputeCells((*gokzg4844.Blob)(blob), 2) + if err != nil { + return err + } + cells = append(cells, cellsI[:]...) + for range len(cellsI) { + cellIndices = append(cellIndices, uint64(i)) + } + } + + comms := make([]gokzg4844.KZGCommitment, len(commitments)) + for i, commitment := range commitments { + comms[i] = gokzg4844.KZGCommitment(commitment) + } + pr := make([]gokzg4844.KZGProof, len(proofs)) + for i, proof := range proofs { + pr[i] = gokzg4844.KZGProof(proof) + } + + return context.VerifyCellKZGProofBatch(comms, cellIndices, cells[:], pr) +} diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go index a6782d4768ad..96f56fdfd19a 100644 --- a/crypto/kzg4844/kzg4844_test.go +++ b/crypto/kzg4844/kzg4844_test.go @@ -193,3 +193,32 @@ func benchmarkVerifyBlobProof(b *testing.B, ckzg bool) { VerifyBlobProof(blob, commitment, proof) } } + +func TestCKZGCells(t *testing.T) { testKZGCells(t, true) } +func TestGoKZGCells(t *testing.T) { testKZGCells(t, false) } +func testKZGCells(t *testing.T, ckzg bool) { + if ckzg && !ckzgAvailable { + t.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + blob := randBlob() + + commitment, err := BlobToCommitment(blob) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + proof, err := ComputeCellProofs(blob) + if err != nil { + t.Fatalf("failed to create KZG proof at point: %v", err) + } + + var commitments []Commitment + for range len(proof) { + commitments = append(commitments, commitment) + } + if err := VerifyCellProofs([]*Blob{blob}, commitments, proof); err != nil { + t.Fatalf("failed to verify KZG proof at point: %v", err) + } +} From 24c18d58afd7160ad7c69a984cd55e298523779f Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Mon, 12 May 2025 20:53:38 +0200 Subject: [PATCH 2/2] crypto/kzg4844: verify cell proofs --- core/txpool/validation.go | 3 ++ crypto/kzg4844/kzg4844.go | 3 ++ crypto/kzg4844/kzg4844_ckzg_cgo.go | 46 +++++++++++++++++++----------- crypto/kzg4844/kzg4844_gokzg.go | 39 ++++++++++++++----------- crypto/kzg4844/kzg4844_test.go | 21 +++++++++----- 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 59707c2bdc01..ab6d93af8da3 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -202,6 +202,9 @@ func validateBlobSidecarOsaka(hashes []common.Hash, sidecar *types.BlobTxSidecar if len(sidecar.Blobs) != len(hashes) { return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) } + if len(sidecar.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) + } if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob { return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes)*kzg4844.CellProofsPerBlob) } diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 030eb563416f..6637a589c62f 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -155,6 +155,9 @@ func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { return gokzgVerifyBlobProof(blob, commitment, proof) } +// VerifyCellProofs verifies a batch of proofs corresponding to the blobs and commitments. +// Expects length of blobs and commitments to be equal. +// Expects length of proofs be 128 * length of blobs. func VerifyCellProofs(blobs []*Blob, commitments []Commitment, proofs []Proof) error { if useCKZG.Load() { return ckzgVerifyCellProofBatch(blobs, commitments, proofs) diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 621974d17f81..2404a1a9a52d 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -151,23 +151,37 @@ func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) { } // ckzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. -func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proofs []Proof) error { +func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, cellProofs []Proof) error { ckzgIniter.Do(ckzgInit) - - cells, err := ckzg.ComputeCells(blob) - if err != nil { - return err - } - cellIndices := make([]uint64, 0, len(cells)) - for range len(cells) { - cellIndices = append(cellIndices, 0) - } - kzgProofs := make([]ckzg4844.Bytes48, len(proofs)) - for _, proof := range proofs { - kzgProofs = append(kzgProofs, (ckzg4844.Bytes48)(proof)) - } - - valid, err := ckzg4844.VerifyCellKZGProofBatch(([]ckzg4844.Bytes48)(commitment), cells, cellIndices, kzgProofs) + var ( + proofs = make([]ckzg4844.Bytes48, len(cellProofs)) + commits = make([]ckzg4844.Bytes48, 0, len(cellProofs)) + cellIndices = make([]uint64, 0, len(cellProofs)) + cells = make([]ckzg4844.Cell, 0, len(cellProofs)) + ) + // Copy over the cell proofs + for i, proof := range cellProofs { + proofs[i] = (ckzg4844.Bytes48)(proof) + } + // Blow up the commitments to be the same length as the proofs + for _, commitment := range commitments { + for range gokzg4844.CellsPerExtBlob { + commits = append(commits, (ckzg4844.Bytes48)(commitment)) + } + } + // Compute the cells and cell indices + for _, blob := range blobs { + cellsI, err := ckzg4844.ComputeCells((*ckzg4844.Blob)(blob)) + if err != nil { + return err + } + cells = append(cells, cellsI[:]...) + for idx := range len(cellsI) { + cellIndices = append(cellIndices, uint64(idx)) + } + } + + valid, err := ckzg4844.VerifyCellKZGProofBatch(commits, cellIndices, cells, proofs) if err != nil { return err } diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go index 487d65da1dcc..9fbd6f654af3 100644 --- a/crypto/kzg4844/kzg4844_gokzg.go +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -116,30 +116,35 @@ func gokzgComputeCellProofs(blob *Blob) ([]Proof, error) { } // gokzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. -func gokzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proofs []Proof) error { +func gokzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, cellProofs []Proof) error { gokzgIniter.Do(gokzgInit) - var cellIndices []uint64 - var cells []*gokzg4844.Cell - for i, blob := range blobs { + var ( + proofs = make([]gokzg4844.KZGProof, len(cellProofs)) + commits = make([]gokzg4844.KZGCommitment, 0, len(cellProofs)) + cellIndices = make([]uint64, 0, len(cellProofs)) + cells = make([]*gokzg4844.Cell, 0, len(cellProofs)) + ) + // Copy over the cell proofs + for i, proof := range cellProofs { + proofs[i] = gokzg4844.KZGProof(proof) + } + // Blow up the commitments to be the same length as the proofs + for _, commitment := range commitments { + for range gokzg4844.CellsPerExtBlob { + commits = append(commits, gokzg4844.KZGCommitment(commitment)) + } + } + // Compute the cell and cell indices + for _, blob := range blobs { cellsI, err := context.ComputeCells((*gokzg4844.Blob)(blob), 2) if err != nil { return err } cells = append(cells, cellsI[:]...) - for range len(cellsI) { - cellIndices = append(cellIndices, uint64(i)) + for idx := range len(cellsI) { + cellIndices = append(cellIndices, uint64(idx)) } } - - comms := make([]gokzg4844.KZGCommitment, len(commitments)) - for i, commitment := range commitments { - comms[i] = gokzg4844.KZGCommitment(commitment) - } - pr := make([]gokzg4844.KZGProof, len(proofs)) - for i, proof := range proofs { - pr[i] = gokzg4844.KZGProof(proof) - } - - return context.VerifyCellKZGProofBatch(comms, cellIndices, cells[:], pr) + return context.VerifyCellKZGProofBatch(commits, cellIndices, cells[:], proofs) } diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go index 96f56fdfd19a..868d7fb868ba 100644 --- a/crypto/kzg4844/kzg4844_test.go +++ b/crypto/kzg4844/kzg4844_test.go @@ -203,22 +203,29 @@ func testKZGCells(t *testing.T, ckzg bool) { defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) useCKZG.Store(ckzg) - blob := randBlob() + blob1 := randBlob() + blob2 := randBlob() - commitment, err := BlobToCommitment(blob) + commitment1, err := BlobToCommitment(blob1) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + commitment2, err := BlobToCommitment(blob2) if err != nil { t.Fatalf("failed to create KZG commitment from blob: %v", err) } - proof, err := ComputeCellProofs(blob) + + proofs1, err := ComputeCellProofs(blob1) if err != nil { t.Fatalf("failed to create KZG proof at point: %v", err) } - var commitments []Commitment - for range len(proof) { - commitments = append(commitments, commitment) + proofs2, err := ComputeCellProofs(blob2) + if err != nil { + t.Fatalf("failed to create KZG proof at point: %v", err) } - if err := VerifyCellProofs([]*Blob{blob}, commitments, proof); err != nil { + proofs := append(proofs1, proofs2...) + if err := VerifyCellProofs([]*Blob{blob1, blob2}, []Commitment{commitment1, commitment2}, proofs); err != nil { t.Fatalf("failed to verify KZG proof at point: %v", err) } }