mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
add: add cell kzg functions
This commit is contained in:
parent
b05fe4aa64
commit
0ba527f46c
5 changed files with 296 additions and 1 deletions
|
|
@ -34,10 +34,21 @@ var (
|
||||||
blobT = reflect.TypeFor[Blob]()
|
blobT = reflect.TypeFor[Blob]()
|
||||||
commitmentT = reflect.TypeFor[Commitment]()
|
commitmentT = reflect.TypeFor[Commitment]()
|
||||||
proofT = reflect.TypeFor[Proof]()
|
proofT = reflect.TypeFor[Proof]()
|
||||||
|
cellT = reflect.TypeFor[Cell]()
|
||||||
)
|
)
|
||||||
|
|
||||||
const CellProofsPerBlob = 128
|
const CellProofsPerBlob = 128
|
||||||
|
|
||||||
|
type Cell [2048]byte
|
||||||
|
|
||||||
|
func (c *Cell) UnmarshalJSON(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedJSON(cellT, input, c[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cell) MarshalText() ([]byte, error) {
|
||||||
|
return hexutil.Bytes(c[:]).MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
// Blob represents a 4844 data blob.
|
// Blob represents a 4844 data blob.
|
||||||
type Blob [131072]byte
|
type Blob [131072]byte
|
||||||
|
|
||||||
|
|
@ -86,6 +97,10 @@ type Claim [32]byte
|
||||||
// useCKZG controls whether the cryptography should use the Go or C backend.
|
// useCKZG controls whether the cryptography should use the Go or C backend.
|
||||||
var useCKZG atomic.Bool
|
var useCKZG atomic.Bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UseCKZG(true)
|
||||||
|
}
|
||||||
|
|
||||||
// UseCKZG can be called to switch the default Go implementation of KZG to the C
|
// UseCKZG can be called to switch the default Go implementation of KZG to the C
|
||||||
// library if for some reason the user wishes to do so (e.g. consensus bug in one
|
// library if for some reason the user wishes to do so (e.g. consensus bug in one
|
||||||
// or the other).
|
// or the other).
|
||||||
|
|
@ -189,3 +204,27 @@ func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) {
|
||||||
func IsValidVersionedHash(h []byte) bool {
|
func IsValidVersionedHash(h []byte) bool {
|
||||||
return len(h) == 32 && h[0] == 0x01
|
return len(h) == 32 && h[0] == 0x01
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyCellProof verifies a batch of proofs corresponding to the cells and commitments.
|
||||||
|
// Expects length of proofs, cells and cellIndices, flattened
|
||||||
|
func VerifyCells(cells []Cell, commitments []Commitment, proofs []Proof, cellIndices []uint64) error {
|
||||||
|
if useCKZG.Load() {
|
||||||
|
return ckzgVerifyCells(cells, commitments, proofs, cellIndices)
|
||||||
|
}
|
||||||
|
return gokzgVerifyCells(cells, commitments, proofs, cellIndices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ComputeCells(blobs []Blob) ([]Cell, error) {
|
||||||
|
if useCKZG.Load() {
|
||||||
|
return ckzgComputeCells(blobs)
|
||||||
|
}
|
||||||
|
return gokzgComputeCells(blobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverBlob(cells []Cell, cellIndices []uint64) (Blob, error) {
|
||||||
|
if useCKZG.Load() {
|
||||||
|
return ckzgRecoverBlob(cells, cellIndices)
|
||||||
|
}
|
||||||
|
return gokzgRecoverBlob(cells, cellIndices)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,3 +190,74 @@ func ckzgVerifyCellProofBatch(blobs []Blob, commitments []Commitment, cellProofs
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ckzgVerifyCells(cells []Cell, commitments []Commitment, cellProofs []Proof, cellIndices []uint64) error {
|
||||||
|
ckzgIniter.Do(ckzgInit)
|
||||||
|
var (
|
||||||
|
proofs = make([]ckzg4844.Bytes48, len(cellProofs))
|
||||||
|
commits = make([]ckzg4844.Bytes48, 0, len(cellProofs))
|
||||||
|
kzgcells = make([]ckzg4844.Cell, 0, len(cellProofs))
|
||||||
|
)
|
||||||
|
// Copy over the cell proofs and cells
|
||||||
|
for i := range cellProofs {
|
||||||
|
proofs[i] = (ckzg4844.Bytes48)(cellProofs[i])
|
||||||
|
kzgcells = append(kzgcells, (ckzg4844.Cell)(cells[i]))
|
||||||
|
}
|
||||||
|
if len(cellProofs)%len(commitments) != 0 {
|
||||||
|
return errors.New("wrong cell proofs and commitments length")
|
||||||
|
}
|
||||||
|
cellCounts := len(cellProofs) / len(commitments)
|
||||||
|
// Blow up the commitments to be the same length as the proofs
|
||||||
|
for _, commitment := range commitments {
|
||||||
|
for j := 0; j < cellCounts; j++ {
|
||||||
|
commits = append(commits, (ckzg4844.Bytes48)(commitment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valid, err := ckzg4844.VerifyCellKZGProofBatch(commits, cellIndices, kzgcells, proofs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
return errors.New("invalid proof")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ckzgComputeCells(blobs []Blob) ([]Cell, error) {
|
||||||
|
ckzgIniter.Do(ckzgInit)
|
||||||
|
var cells = make([]Cell, 0, ckzg4844.CellsPerExtBlob*len(blobs))
|
||||||
|
|
||||||
|
for i := range blobs {
|
||||||
|
cellsI, err := ckzg4844.ComputeCells((*ckzg4844.Blob)(&blobs[i]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, c := range cellsI {
|
||||||
|
cells = append(cells, Cell(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cells, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ckzgRecoverBlob(cells []Cell, cellIndices []uint64) (Blob, error) {
|
||||||
|
ckzgIniter.Do(ckzgInit)
|
||||||
|
|
||||||
|
var kzgcells = make([]ckzg4844.Cell, 0, len(cells))
|
||||||
|
|
||||||
|
for _, cell := range cells {
|
||||||
|
kzgcells = append(kzgcells, ckzg4844.Cell(cell))
|
||||||
|
}
|
||||||
|
|
||||||
|
extCells, _, err := ckzg4844.RecoverCellsAndKZGProofs(cellIndices, kzgcells)
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Blob
|
||||||
|
offset := 0
|
||||||
|
for _, cell := range extCells[:64] {
|
||||||
|
copy(result[offset:], cell[:])
|
||||||
|
offset += len(cell)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,15 @@ func ckzgVerifyCellProofBatch(blobs []Blob, commitments []Commitment, proof []Pr
|
||||||
func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) {
|
func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) {
|
||||||
panic("unsupported platform")
|
panic("unsupported platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ckzgVerifyCells(cells []Cell, commitments []Commitment, cellProofs []Proof, cellIndices []uint64) error {
|
||||||
|
panic("unsupported platform")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ckzgComputeCells(blobs []Blob) ([]Cell, error) {
|
||||||
|
panic("unsupported platform")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ckzgRecoverBlob(cells []Cell, cellIndices []uint64) (Blob, error) {
|
||||||
|
panic("unsupported platform")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package kzg4844
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
gokzg4844 "github.com/crate-crypto/go-eth-kzg"
|
gokzg4844 "github.com/crate-crypto/go-eth-kzg"
|
||||||
|
|
@ -115,7 +116,7 @@ func gokzgComputeCellProofs(blob *Blob) ([]Proof, error) {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// gokzgVerifyCellProofBatch verifies that the blob data corresponds to the provided commitment.
|
// gokzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment.
|
||||||
func gokzgVerifyCellProofBatch(blobs []Blob, commitments []Commitment, cellProofs []Proof) error {
|
func gokzgVerifyCellProofBatch(blobs []Blob, commitments []Commitment, cellProofs []Proof) error {
|
||||||
gokzgIniter.Do(gokzgInit)
|
gokzgIniter.Do(gokzgInit)
|
||||||
|
|
||||||
|
|
@ -148,3 +149,74 @@ func gokzgVerifyCellProofBatch(blobs []Blob, commitments []Commitment, cellProof
|
||||||
}
|
}
|
||||||
return context.VerifyCellKZGProofBatch(commits, cellIndices, cells[:], proofs)
|
return context.VerifyCellKZGProofBatch(commits, cellIndices, cells[:], proofs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gokzgVerifyCell verifies that the cell data corresponds to the provided commitment.
|
||||||
|
func gokzgVerifyCells(cells []Cell, commitments []Commitment, cellProofs []Proof, cellIndices []uint64) error {
|
||||||
|
gokzgIniter.Do(gokzgInit)
|
||||||
|
var (
|
||||||
|
proofs = make([]gokzg4844.KZGProof, len(cellProofs))
|
||||||
|
commits = make([]gokzg4844.KZGCommitment, 0, len(cellProofs))
|
||||||
|
kzgcells = make([]*gokzg4844.Cell, 0, len(cellProofs))
|
||||||
|
)
|
||||||
|
// Copy over the cell proofs and cells
|
||||||
|
for i := range cellProofs {
|
||||||
|
proofs[i] = gokzg4844.KZGProof(cellProofs[i])
|
||||||
|
gc := gokzg4844.Cell(cells[i])
|
||||||
|
kzgcells = append(kzgcells, &gc)
|
||||||
|
}
|
||||||
|
if len(cellProofs)%len(commitments) != 0 {
|
||||||
|
return errors.New("wrong cell proofs and commitments length")
|
||||||
|
}
|
||||||
|
cellCounts := len(cellProofs) / len(commitments)
|
||||||
|
// Blow up the commitments to be the same length as the proofs
|
||||||
|
for _, commitment := range commitments {
|
||||||
|
for j := 0; j < cellCounts; j++ {
|
||||||
|
commits = append(commits, gokzg4844.KZGCommitment(commitment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context.VerifyCellKZGProofBatch(commits, cellIndices, kzgcells, proofs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// gokzgComputeCells computes cells from blobs.
|
||||||
|
func gokzgComputeCells(blobs []Blob) ([]Cell, error) {
|
||||||
|
gokzgIniter.Do(gokzgInit)
|
||||||
|
var cells = make([]Cell, 0, gokzg4844.CellsPerExtBlob*len(blobs))
|
||||||
|
|
||||||
|
// Compute the cell and cell indices
|
||||||
|
for i := range blobs {
|
||||||
|
cellsI, err := context.ComputeCells((*gokzg4844.Blob)(&blobs[i]), 2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, c := range cellsI {
|
||||||
|
if c != nil {
|
||||||
|
cells = append(cells, Cell(*c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cells, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gokzgRecoverBlob(cells []Cell, cellIndices []uint64) (Blob, error) {
|
||||||
|
gokzgIniter.Do(gokzgInit)
|
||||||
|
|
||||||
|
var kzgcells = make([]*gokzg4844.Cell, 0, len(cells))
|
||||||
|
|
||||||
|
for _, cell := range cells {
|
||||||
|
gc := gokzg4844.Cell(cell)
|
||||||
|
kzgcells = append(kzgcells, &gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
extCells, _, err := context.RecoverCellsAndComputeKZGProofs(cellIndices, kzgcells, 2) // todo
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Blob
|
||||||
|
offset := 0
|
||||||
|
for _, cell := range extCells[:64] {
|
||||||
|
copy(result[offset:], cell[:])
|
||||||
|
offset += len(cell)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -230,3 +230,104 @@ func testKZGCells(t *testing.T, ckzg bool) {
|
||||||
t.Fatalf("failed to verify KZG proof at point: %v", err)
|
t.Fatalf("failed to verify KZG proof at point: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestCKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, true) }
|
||||||
|
func TestGoKZGVerifyPartialCells(t *testing.T) { testVerifyPartialCells(t, false) }
|
||||||
|
|
||||||
|
func testVerifyPartialCells(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
|
||||||
|
var blobs []*Blob
|
||||||
|
var commitments []Commitment
|
||||||
|
for range blobCount {
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
for bi, blob := range blobs {
|
||||||
|
proofs, err := ComputeCellProofs(blob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute cell proofs: %v", err)
|
||||||
|
}
|
||||||
|
cells, err := ComputeCells([]Blob{*blob})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute cells: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample 0, 31, 63, 95 cells
|
||||||
|
step := len(cells) / 4
|
||||||
|
|
||||||
|
sampleIdx := []int{0, step - 1, 2*step - 1, 3*step - 1}
|
||||||
|
for _, idx := range sampleIdx {
|
||||||
|
partialCells = append(partialCells, cells[idx])
|
||||||
|
partialProofs = append(partialProofs, proofs[idx])
|
||||||
|
commits = append(commits, commitments[bi])
|
||||||
|
indices = append(indices, uint64(idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := VerifyCells(partialCells, commits, partialProofs, indices); err != nil {
|
||||||
|
t.Fatalf("failed to verify partial cell proofs: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCKZGRecoverBlob(t *testing.T) { testRecoverBlob(t, true) }
|
||||||
|
func TestGoKZGRecoverBlob(t *testing.T) { testRecoverBlob(t, false) }
|
||||||
|
|
||||||
|
func testRecoverBlob(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)
|
||||||
|
|
||||||
|
var blob = randBlob()
|
||||||
|
cells, err := ComputeCells([]Blob{*blob})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute cells: %v", err)
|
||||||
|
}
|
||||||
|
proof, err := ComputeCellProofs(blob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute proof: %v", err)
|
||||||
|
}
|
||||||
|
commitment, err := BlobToCommitment(blob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compute commitment: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
partialCells []Cell
|
||||||
|
indices []uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
for ci, cell := range cells {
|
||||||
|
partialCells = append(partialCells, cell)
|
||||||
|
indices = append(indices, uint64(ci))
|
||||||
|
}
|
||||||
|
|
||||||
|
recoverBlob, err := RecoverBlob(partialCells, indices)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to recover blob: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := VerifyCellProofs([]Blob{recoverBlob}, []Commitment{commitment}, proof); err != nil {
|
||||||
|
t.Fatalf("failed to verify recovered blob: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue