mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-16 11:51:35 +00:00
crypto/kzg4844: add more tests
This commit is contained in:
parent
04a6c861d8
commit
5eb2e5e265
1 changed files with 192 additions and 81 deletions
|
|
@ -18,6 +18,8 @@ package kzg4844
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
mrand "math/rand"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
||||||
|
|
@ -254,6 +256,51 @@ func benchmarkComputeCellProofs(b *testing.B, ckzg bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// randCellIndices picks n random unique indices from [0, CellsPerBlob) in sorted order.
|
||||||
|
func randCellIndices(rng *mrand.Rand, n int) []uint64 {
|
||||||
|
perm := rng.Perm(CellsPerBlob)
|
||||||
|
indices := make([]uint64, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
indices[i] = uint64(perm[i])
|
||||||
|
}
|
||||||
|
slices.Sort(indices)
|
||||||
|
return indices
|
||||||
|
}
|
||||||
|
|
||||||
|
// randBlobAndProofs generates random blobs and precomputes their cells, proofs, and commitments.
|
||||||
|
type randBlobAndProofs struct {
|
||||||
|
blobs []Blob
|
||||||
|
commitments []Commitment
|
||||||
|
cells []Cell // flat: blobs[i] cells at [i*CellsPerBlob : (i+1)*CellsPerBlob]
|
||||||
|
proofs []Proof
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBlobs(t *testing.T, blobCount int) *randBlobAndProofs {
|
||||||
|
d := &randBlobAndProofs{
|
||||||
|
blobs: make([]Blob, blobCount),
|
||||||
|
commitments: make([]Commitment, blobCount),
|
||||||
|
}
|
||||||
|
for i := range blobCount {
|
||||||
|
d.blobs[i] = *randBlob()
|
||||||
|
commitment, err := BlobToCommitment(&d.blobs[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute commitment: %v", err)
|
||||||
|
}
|
||||||
|
d.commitments[i] = commitment
|
||||||
|
proofs, err := ComputeCellProofs(&d.blobs[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute cell proofs: %v", err)
|
||||||
|
}
|
||||||
|
d.proofs = append(d.proofs, proofs...)
|
||||||
|
}
|
||||||
|
cells, err := ComputeCells(d.blobs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute cells: %v", err)
|
||||||
|
}
|
||||||
|
d.cells = cells
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func TestCKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, true) }
|
func TestCKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, true) }
|
||||||
func TestGoKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, false) }
|
func TestGoKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, false) }
|
||||||
|
|
||||||
|
|
@ -264,48 +311,101 @@ func testVerifyPartialCells(t *testing.T, ckzg bool) {
|
||||||
defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load())
|
defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load())
|
||||||
useCKZG.Store(ckzg)
|
useCKZG.Store(ckzg)
|
||||||
|
|
||||||
const blobCount = 3
|
const (
|
||||||
var blobs []*Blob
|
iterations = 50
|
||||||
var commitments []Commitment
|
blobCount = 3
|
||||||
for range blobCount {
|
cellsCount = 8
|
||||||
blob := randBlob()
|
|
||||||
commitment, err := BlobToCommitment(blob)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to commit blob: %v", err)
|
|
||||||
}
|
|
||||||
blobs = append(blobs, blob)
|
|
||||||
commitments = append(commitments, commitment)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
partialCells []Cell
|
|
||||||
partialProofs []Proof
|
|
||||||
commits []Commitment
|
|
||||||
indices []uint64
|
|
||||||
)
|
)
|
||||||
|
// Precompute blobs once, vary only cell indices per iteration
|
||||||
|
d := newBlobs(t, blobCount)
|
||||||
|
|
||||||
for bi, blob := range blobs {
|
for iter := range iterations {
|
||||||
proofs, err := ComputeCellProofs(blob)
|
rng := mrand.New(mrand.NewSource(int64(iter)))
|
||||||
if err != nil {
|
indices := randCellIndices(rng, cellsCount)
|
||||||
t.Fatalf("failed to compute cell proofs: %v", err)
|
|
||||||
|
var partialCells []Cell
|
||||||
|
var partialProofs []Proof
|
||||||
|
for i := range blobCount {
|
||||||
|
for _, idx := range indices {
|
||||||
|
partialCells = append(partialCells, d.cells[i*CellsPerBlob+int(idx)])
|
||||||
|
partialProofs = append(partialProofs, d.proofs[i*CellProofsPerBlob+int(idx)])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cells, err := ComputeCells([]Blob{*blob})
|
if err := VerifyCells(partialCells, d.commitments, partialProofs, indices); err != nil {
|
||||||
if err != nil {
|
t.Fatalf("iter %d: failed to verify partial cells: %v", iter, err)
|
||||||
t.Fatalf("failed to compute cells: %v", err)
|
|
||||||
}
|
|
||||||
commits = append(commits, commitments[bi])
|
|
||||||
|
|
||||||
// sample 0, 31, 63, 95 cells
|
|
||||||
step := len(cells) / 4
|
|
||||||
|
|
||||||
indices = []uint64{0, uint64(step - 1), uint64(2*step - 1), uint64(3*step - 1)}
|
|
||||||
for _, idx := range indices {
|
|
||||||
partialCells = append(partialCells, cells[idx])
|
|
||||||
partialProofs = append(partialProofs, proofs[idx])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := VerifyCells(partialCells, commits, partialProofs, indices); err != nil {
|
}
|
||||||
t.Fatalf("failed to verify partial cell proofs: %v", err)
|
|
||||||
|
func TestCKZGVerifyCellsWithCorruptedCells(t *testing.T) {
|
||||||
|
testVerifyCellsWithCorruptedCells(t, true)
|
||||||
|
}
|
||||||
|
func TestGoKZGVerifyCellsWithCorruptedCells(t *testing.T) {
|
||||||
|
testVerifyCellsWithCorruptedCells(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVerifyCellsWithCorruptedCells(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)
|
||||||
|
|
||||||
|
const blobCount = 3
|
||||||
|
d := newBlobs(t, blobCount)
|
||||||
|
indices := []uint64{0, 15, 63, 64, 95, 100, 120, 127}
|
||||||
|
|
||||||
|
var partialCells []Cell
|
||||||
|
var partialProofs []Proof
|
||||||
|
for i := range blobCount {
|
||||||
|
for _, idx := range indices {
|
||||||
|
partialCells = append(partialCells, d.cells[i*CellsPerBlob+int(idx)])
|
||||||
|
partialProofs = append(partialProofs, d.proofs[i*CellProofsPerBlob+int(idx)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Corrupt the first cell
|
||||||
|
corruptedCells := make([]Cell, len(partialCells))
|
||||||
|
copy(corruptedCells, partialCells)
|
||||||
|
corruptedCells[0][0] ^= 0xff
|
||||||
|
|
||||||
|
if err := VerifyCells(corruptedCells, d.commitments, partialProofs, indices); err == nil {
|
||||||
|
t.Fatal("expected verification failure with corrupted cell")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCKZGVerifyCellsWithCorruptedProofs(t *testing.T) {
|
||||||
|
testVerifyCellsWithCorruptedProofs(t, true)
|
||||||
|
}
|
||||||
|
func TestGoKZGVerifyCellsWithCorruptedProofs(t *testing.T) {
|
||||||
|
testVerifyCellsWithCorruptedProofs(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVerifyCellsWithCorruptedProofs(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)
|
||||||
|
|
||||||
|
const blobCount = 3
|
||||||
|
d := newBlobs(t, blobCount)
|
||||||
|
indices := []uint64{0, 15, 63, 64, 95, 100, 120, 127}
|
||||||
|
|
||||||
|
var partialCells []Cell
|
||||||
|
var partialProofs []Proof
|
||||||
|
for i := range blobCount {
|
||||||
|
for _, idx := range indices {
|
||||||
|
partialCells = append(partialCells, d.cells[i*CellsPerBlob+int(idx)])
|
||||||
|
partialProofs = append(partialProofs, d.proofs[i*CellProofsPerBlob+int(idx)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Swap first and last proof
|
||||||
|
wrongProofs := make([]Proof, len(partialProofs))
|
||||||
|
copy(wrongProofs, partialProofs)
|
||||||
|
wrongProofs[0], wrongProofs[len(wrongProofs)-1] = wrongProofs[len(wrongProofs)-1], wrongProofs[0]
|
||||||
|
|
||||||
|
if err := VerifyCells(partialCells, d.commitments, wrongProofs, indices); err == nil {
|
||||||
|
t.Fatal("expected verification failure with swapped proofs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -319,53 +419,64 @@ func testRecoverBlob(t *testing.T, ckzg bool) {
|
||||||
defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load())
|
defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load())
|
||||||
useCKZG.Store(ckzg)
|
useCKZG.Store(ckzg)
|
||||||
|
|
||||||
blobs := []Blob{}
|
// Precompute blobs once, vary only cell indices per iteration
|
||||||
blobs = append(blobs, *randBlob())
|
d := newBlobs(t, 3)
|
||||||
blobs = append(blobs, *randBlob())
|
|
||||||
blobs = append(blobs, *randBlob())
|
|
||||||
|
|
||||||
cells, err := ComputeCells(blobs)
|
for iter := range 50 {
|
||||||
if err != nil {
|
rng := mrand.New(mrand.NewSource(int64(iter)))
|
||||||
t.Fatalf("failed to compute cells: %v", err)
|
numCells := DataPerBlob + rng.Intn(CellsPerBlob-DataPerBlob+1)
|
||||||
}
|
indices := randCellIndices(rng, numCells)
|
||||||
proofs := make([]Proof, 0)
|
|
||||||
commitments := make([]Commitment, len(blobs))
|
var partialCells []Cell
|
||||||
for i, blob := range blobs {
|
for bi := range 3 {
|
||||||
proof, err := ComputeCellProofs(&blob)
|
for _, idx := range indices {
|
||||||
if err != nil {
|
partialCells = append(partialCells, d.cells[bi*CellsPerBlob+int(idx)])
|
||||||
t.Fatalf("failed to compute proof: %v", err)
|
}
|
||||||
}
|
}
|
||||||
proofs = append(proofs, proof...)
|
recovered, err := RecoverBlobs(partialCells, indices)
|
||||||
|
|
||||||
commitment, err := BlobToCommitment(&blob)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to compute commitment: %v", err)
|
t.Fatalf("iter %d: failed to recover blob with %d cells: %v", iter, numCells, err)
|
||||||
|
}
|
||||||
|
if err := VerifyCellProofs(recovered, d.commitments, d.proofs); err != nil {
|
||||||
|
t.Fatalf("iter %d: recovered blobs failed verification: %v", iter, err)
|
||||||
|
}
|
||||||
|
for i := range d.blobs {
|
||||||
|
if recovered[i] != d.blobs[i] {
|
||||||
|
t.Fatalf("iter %d: recovered blob %d does not match original", iter, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
commitments[i] = commitment
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
func TestCKZGRecoverBlobWithInsufficientCells(t *testing.T) {
|
||||||
partialCells []Cell
|
testRecoverBlobWithInsufficientCells(t, true)
|
||||||
indices []uint64
|
}
|
||||||
)
|
func TestGoKZGRecoverBlobWithInsufficientCells(t *testing.T) {
|
||||||
|
testRecoverBlobWithInsufficientCells(t, false)
|
||||||
for ci := 64; ci < 128; ci++ {
|
}
|
||||||
indices = append(indices, uint64(ci))
|
|
||||||
}
|
func testRecoverBlobWithInsufficientCells(t *testing.T, ckzg bool) {
|
||||||
|
if ckzg && !ckzgAvailable {
|
||||||
for i := 0; i < len(cells); i += 128 {
|
t.Skip("CKZG unavailable in this test build")
|
||||||
start := i + 64
|
}
|
||||||
end := i + 128
|
defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load())
|
||||||
partialCells = append(partialCells, cells[start:end]...)
|
useCKZG.Store(ckzg)
|
||||||
}
|
|
||||||
|
const blobCount = 3
|
||||||
recoverBlobs, err := RecoverBlobs(partialCells, indices)
|
d := newBlobs(t, blobCount)
|
||||||
|
|
||||||
if err != nil {
|
// Use DataPerBlob-1 cells (one short of minimum required)
|
||||||
t.Fatalf("failed to recover blob: %v", err)
|
indices := make([]uint64, DataPerBlob-1)
|
||||||
}
|
for i := range indices {
|
||||||
|
indices[i] = uint64(i)
|
||||||
if err := VerifyCellProofs(recoverBlobs, commitments, proofs); err != nil {
|
}
|
||||||
t.Fatalf("failed to verify recovered blob: %v", err)
|
var partialCells []Cell
|
||||||
|
for bi := range blobCount {
|
||||||
|
for _, idx := range indices {
|
||||||
|
partialCells = append(partialCells, d.cells[bi*CellsPerBlob+int(idx)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := RecoverBlobs(partialCells, indices); err == nil {
|
||||||
|
t.Fatalf("expected error with only %d cells, got none", len(indices))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue