|
| 1 | +package kzg |
| 2 | + |
| 3 | +import ( |
| 4 | + "github.com/pkg/errors" |
| 5 | + |
| 6 | + ckzg4844 "github.com/ethereum/c-kzg-4844/v2/bindings/go" |
| 7 | + "github.com/ethereum/go-ethereum/crypto/kzg4844" |
| 8 | +) |
| 9 | + |
| 10 | +// BytesPerBlob is the number of bytes in a single blob. |
| 11 | +const BytesPerBlob = ckzg4844.BytesPerBlob |
| 12 | + |
| 13 | +// Blob represents a serialized chunk of data. |
| 14 | +type Blob [BytesPerBlob]byte |
| 15 | + |
| 16 | +// BytesPerCell is the number of bytes in a single cell. |
| 17 | +const BytesPerCell = ckzg4844.BytesPerCell |
| 18 | + |
| 19 | +// Cell represents a chunk of an encoded Blob. |
| 20 | +type Cell [BytesPerCell]byte |
| 21 | + |
| 22 | +// Commitment represent a KZG commitment to a Blob. |
| 23 | +type Commitment [48]byte |
| 24 | + |
| 25 | +// Proof represents a KZG proof that attests to the validity of a Blob or parts of it. |
| 26 | +type Proof [48]byte |
| 27 | + |
| 28 | +// Bytes48 is a 48-byte array. |
| 29 | +type Bytes48 = ckzg4844.Bytes48 |
| 30 | + |
| 31 | +// Bytes32 is a 32-byte array. |
| 32 | +type Bytes32 = ckzg4844.Bytes32 |
| 33 | + |
| 34 | +// CellsAndProofs represents the Cells and Proofs corresponding to a single blob. |
| 35 | +type CellsAndProofs struct { |
| 36 | + Cells []Cell |
| 37 | + Proofs []Proof |
| 38 | +} |
| 39 | + |
| 40 | +// BlobToKZGCommitment computes a KZG commitment from a given blob. |
| 41 | +func BlobToKZGCommitment(blob *Blob) (Commitment, error) { |
| 42 | + var kzgBlob kzg4844.Blob |
| 43 | + copy(kzgBlob[:], blob[:]) |
| 44 | + |
| 45 | + commitment, err := kzg4844.BlobToCommitment(&kzgBlob) |
| 46 | + if err != nil { |
| 47 | + return Commitment{}, err |
| 48 | + } |
| 49 | + |
| 50 | + return Commitment(commitment), nil |
| 51 | +} |
| 52 | + |
| 53 | +// ComputeCells computes the (extended) cells from a given blob. |
| 54 | +func ComputeCells(blob *Blob) ([]Cell, error) { |
| 55 | + var ckzgBlob ckzg4844.Blob |
| 56 | + copy(ckzgBlob[:], blob[:]) |
| 57 | + |
| 58 | + ckzgCells, err := ckzg4844.ComputeCells(&ckzgBlob) |
| 59 | + if err != nil { |
| 60 | + return nil, errors.Wrap(err, "compute cells") |
| 61 | + } |
| 62 | + |
| 63 | + cells := make([]Cell, len(ckzgCells)) |
| 64 | + for i := range ckzgCells { |
| 65 | + cells[i] = Cell(ckzgCells[i]) |
| 66 | + } |
| 67 | + |
| 68 | + return cells, nil |
| 69 | +} |
| 70 | + |
| 71 | +// ComputeBlobKZGProof computes the blob KZG proof from a given blob and its commitment. |
| 72 | +func ComputeBlobKZGProof(blob *Blob, commitment Commitment) (Proof, error) { |
| 73 | + var kzgBlob kzg4844.Blob |
| 74 | + copy(kzgBlob[:], blob[:]) |
| 75 | + |
| 76 | + proof, err := kzg4844.ComputeBlobProof(&kzgBlob, kzg4844.Commitment(commitment)) |
| 77 | + if err != nil { |
| 78 | + return [48]byte{}, err |
| 79 | + } |
| 80 | + return Proof(proof), nil |
| 81 | +} |
| 82 | + |
| 83 | +// ComputeCellsAndKZGProofs computes the cells and cells KZG proofs from a given blob. |
| 84 | +func ComputeCellsAndKZGProofs(blob *Blob) (CellsAndProofs, error) { |
| 85 | + var ckzgBlob ckzg4844.Blob |
| 86 | + copy(ckzgBlob[:], blob[:]) |
| 87 | + |
| 88 | + ckzgCells, ckzgProofs, err := ckzg4844.ComputeCellsAndKZGProofs(&ckzgBlob) |
| 89 | + if err != nil { |
| 90 | + return CellsAndProofs{}, err |
| 91 | + } |
| 92 | + |
| 93 | + return makeCellsAndProofs(ckzgCells[:], ckzgProofs[:]) |
| 94 | +} |
| 95 | + |
| 96 | +// VerifyCellKZGProofBatch verifies the KZG proofs for a given slice of commitments, cells indices, cells and proofs. |
| 97 | +// Note: It is way more efficient to call once this function with big slices than calling it multiple times with small slices. |
| 98 | +func VerifyCellKZGProofBatch(commitmentsBytes []Bytes48, cellIndices []uint64, cells []Cell, proofsBytes []Bytes48) (bool, error) { |
| 99 | + // Convert `Cell` type to `ckzg4844.Cell` |
| 100 | + ckzgCells := make([]ckzg4844.Cell, len(cells)) |
| 101 | + |
| 102 | + for i := range cells { |
| 103 | + ckzgCells[i] = ckzg4844.Cell(cells[i]) |
| 104 | + } |
| 105 | + |
| 106 | + return ckzg4844.VerifyCellKZGProofBatch(commitmentsBytes, cellIndices, ckzgCells, proofsBytes) |
| 107 | +} |
| 108 | + |
| 109 | +// RecoverCellsAndKZGProofs recovers the complete cells and KZG proofs from a given set of cell indices and partial cells. |
| 110 | +func RecoverCellsAndKZGProofs(cellIndices []uint64, partialCells []Cell) (CellsAndProofs, error) { |
| 111 | + // Convert `Cell` type to `ckzg4844.Cell` |
| 112 | + ckzgPartialCells := make([]ckzg4844.Cell, len(partialCells)) |
| 113 | + for i := range partialCells { |
| 114 | + ckzgPartialCells[i] = ckzg4844.Cell(partialCells[i]) |
| 115 | + } |
| 116 | + |
| 117 | + ckzgCells, ckzgProofs, err := ckzg4844.RecoverCellsAndKZGProofs(cellIndices, ckzgPartialCells) |
| 118 | + if err != nil { |
| 119 | + return CellsAndProofs{}, errors.Wrap(err, "recover cells and KZG proofs") |
| 120 | + } |
| 121 | + |
| 122 | + return makeCellsAndProofs(ckzgCells[:], ckzgProofs[:]) |
| 123 | +} |
| 124 | + |
| 125 | +// makeCellsAndProofs converts cells/proofs to the CellsAndProofs type defined in this package. |
| 126 | +func makeCellsAndProofs(ckzgCells []ckzg4844.Cell, ckzgProofs []ckzg4844.KZGProof) (CellsAndProofs, error) { |
| 127 | + if len(ckzgCells) != len(ckzgProofs) { |
| 128 | + return CellsAndProofs{}, errors.New("different number of cells/proofs") |
| 129 | + } |
| 130 | + |
| 131 | + cells := make([]Cell, 0, len(ckzgCells)) |
| 132 | + proofs := make([]Proof, 0, len(ckzgProofs)) |
| 133 | + |
| 134 | + for i := range ckzgCells { |
| 135 | + cells = append(cells, Cell(ckzgCells[i])) |
| 136 | + proofs = append(proofs, Proof(ckzgProofs[i])) |
| 137 | + } |
| 138 | + |
| 139 | + return CellsAndProofs{ |
| 140 | + Cells: cells, |
| 141 | + Proofs: proofs, |
| 142 | + }, nil |
| 143 | +} |
0 commit comments