Skip to content

Commit

Permalink
Update ckzg4844 to latest version of das branch (#14223)
Browse files Browse the repository at this point in the history
* Update ckzg4844 to latest version

* Run go mod tidy

* Remove unnecessary tests & run goimports

* Remove fieldparams from blockchain/kzg

* Add back blank line

* Avoid large copies

* Run gazelle

* Use trusted setup from the specs & fix issue with struct

* Run goimports

* Fix mistake in makeCellsAndProofs

---------

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>
  • Loading branch information
jtraglia and nalepae committed Jul 17, 2024
1 parent 93b7587 commit 164d743
Show file tree
Hide file tree
Showing 11 changed files with 4,189 additions and 174 deletions.
1 change: 0 additions & 1 deletion beacon-chain/blockchain/kzg/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"kzg_test.go",
"trusted_setup_test.go",
"validation_test.go",
],
Expand Down
145 changes: 38 additions & 107 deletions beacon-chain/blockchain/kzg/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ import (
"github.com/ethereum/go-ethereum/crypto/kzg4844"
)

// BytesPerBlob is the number of bytes in a single blob.
const BytesPerBlob = ckzg4844.BytesPerBlob

// Blob represents a serialized chunk of data.
type Blob [BytesPerBlob]byte

// BytesPerCell is the number of bytes in a single cell.
const BytesPerCell = ckzg4844.BytesPerCell

// Cell represents a chunk of an encoded Blob.
type Cell [BytesPerCell]byte

// Commitment represent a KZG commitment to a Blob.
type Commitment [48]byte

Expand All @@ -22,27 +31,11 @@ type Bytes48 = ckzg4844.Bytes48
// Bytes32 is a 32-byte array.
type Bytes32 = ckzg4844.Bytes32

// BytesPerCell is the number of bytes in a single cell.
const BytesPerCell = ckzg4844.FieldElementsPerCell * ckzg4844.BytesPerFieldElement

// BytesPerBlob is the number of bytes in a single blob.
const BytesPerBlob = ckzg4844.BytesPerBlob

// fieldElementsPerCell is the number of field elements in a single cell.
const fieldElementsPerCell = ckzg4844.FieldElementsPerCell

// CellsPerExtBlob is the number of cells that we generate for a single blob.
// This is equivalent to the number of columns in the data matrix.
const CellsPerExtBlob = ckzg4844.CellsPerExtBlob

// Cell represents a chunk of an encoded Blob.
type Cell [BytesPerCell]byte

// CellsAndProofs represents the Cells and Proofs corresponding to
// a single blob.
type CellsAndProofs struct {
Cells [ckzg4844.CellsPerExtBlob]Cell
Proofs [ckzg4844.CellsPerExtBlob]Proof
Cells []Cell
Proofs []Proof
}

func BlobToKZGCommitment(blob *Blob) (Commitment, error) {
Expand All @@ -62,117 +55,55 @@ func ComputeBlobKZGProof(blob *Blob, commitment Commitment) (Proof, error) {
}

func ComputeCellsAndKZGProofs(blob *Blob) (CellsAndProofs, error) {
ckzgBlob := ckzg4844.Blob(*blob)
_cells, _proofs, err := ckzg4844.ComputeCellsAndKZGProofs(&ckzgBlob)
ckzgBlob := (*ckzg4844.Blob)(blob)
ckzgCells, ckzgProofs, err := ckzg4844.ComputeCellsAndKZGProofs(ckzgBlob)
if err != nil {
return CellsAndProofs{}, err
}

// Convert Cells and Proofs to types defined in this package
var cells [ckzg4844.CellsPerExtBlob]Cell
for i := range _cells {
cells[i] = ckzgCellToCell(&_cells[i])
}

var proofs [ckzg4844.CellsPerExtBlob]Proof
for i := range _proofs {
proofs[i] = Proof(_proofs[i])
}

return CellsAndProofs{
Cells: cells,
Proofs: proofs,
}, nil
return makeCellsAndProofs(ckzgCells[:], ckzgProofs[:])
}

// VerifyCellKZGProof is unused. TODO: We can check when the batch size for `VerifyCellKZGProofBatch` is 1
// and call this, though I think its better if the cryptography library handles this.
func VerifyCellKZGProof(commitmentBytes Bytes48, cellId uint64, cell *Cell, proofBytes Bytes48) (bool, error) {
return ckzg4844.VerifyCellKZGProof(commitmentBytes, cellId, cellToCKZGCell(cell), proofBytes)
}

func VerifyCellKZGProofBatch(commitmentsBytes []Bytes48, rowIndices, columnIndices []uint64, _cells []Cell, proofsBytes []Bytes48) (bool, error) {
func VerifyCellKZGProofBatch(commitmentsBytes []Bytes48, cellIndices []uint64, cells []Cell, proofsBytes []Bytes48) (bool, error) {
// Convert `Cell` type to `ckzg4844.Cell`
ckzgCells := make([]ckzg4844.Cell, len(_cells))
for i := range _cells {
ckzgCells[i] = cellToCKZGCell(&_cells[i])
ckzgCells := make([]ckzg4844.Cell, len(cells))
for i := range cells {
ckzgCells[i] = ckzg4844.Cell(cells[i])
}

return ckzg4844.VerifyCellKZGProofBatch(commitmentsBytes, rowIndices, columnIndices, ckzgCells, proofsBytes)
return ckzg4844.VerifyCellKZGProofBatch(commitmentsBytes, cellIndices, ckzgCells, proofsBytes)
}

func recoverAllCells(cellIds []uint64, _cells []Cell) ([ckzg4844.CellsPerExtBlob]Cell, error) {
func RecoverCellsAndKZGProofs(cellIndices []uint64, partialCells []Cell) (CellsAndProofs, error) {
// Convert `Cell` type to `ckzg4844.Cell`
ckzgCells := make([]ckzg4844.Cell, len(_cells))
for i := range _cells {
ckzgCells[i] = cellToCKZGCell(&_cells[i])
ckzgPartialCells := make([]ckzg4844.Cell, len(partialCells))
for i := range partialCells {
ckzgPartialCells[i] = ckzg4844.Cell(partialCells[i])
}

recoveredCells, err := ckzg4844.RecoverAllCells(cellIds, ckzgCells)
if err != nil {
return [ckzg4844.CellsPerExtBlob]Cell{}, err
}

// This should never happen, we return an error instead of panicking.
if len(recoveredCells) != ckzg4844.CellsPerExtBlob {
return [ckzg4844.CellsPerExtBlob]Cell{}, errors.New("recovered cells length is not equal to CellsPerExtBlob")
}

// Convert `ckzg4844.Cell` type to `Cell`
var ret [ckzg4844.CellsPerExtBlob]Cell
for i := range recoveredCells {
ret[i] = ckzgCellToCell(&recoveredCells[i])
}
return ret, nil
}

// RecoverCellsAndKZGProofs recovers the cells and compute the KZG Proofs associated with the cells.
func RecoverCellsAndKZGProofs(cellIds []uint64, _cells []Cell) (CellsAndProofs, error) {
// First recover all of the cells
recoveredCells, err := recoverAllCells(cellIds, _cells)
ckzgCells, ckzgProofs, err := ckzg4844.RecoverCellsAndKZGProofs(cellIndices, ckzgPartialCells)
if err != nil {
return CellsAndProofs{}, err
}

// Extract the Blob from all of the Cells
blob, err := cellsToBlob(&recoveredCells)
if err != nil {
return CellsAndProofs{}, err
}

// Compute all of the cells and KZG proofs
return ComputeCellsAndKZGProofs(&blob)
return makeCellsAndProofs(ckzgCells[:], ckzgProofs[:])
}

func cellsToBlob(_cells *[ckzg4844.CellsPerExtBlob]Cell) (Blob, error) {
// Convert `Cell` type to `ckzg4844.Cell`
var ckzgCells [ckzg4844.CellsPerExtBlob]ckzg4844.Cell
for i := range _cells {
ckzgCells[i] = cellToCKZGCell(&_cells[i])
// Convert cells/proofs to the CellsAndProofs type defined in this package.
func makeCellsAndProofs(ckzgCells []ckzg4844.Cell, ckzgProofs []ckzg4844.KZGProof) (CellsAndProofs, error) {
if len(ckzgCells) != len(ckzgProofs) {
return CellsAndProofs{}, errors.New("different number of cells/proofs")
}

blob, err := ckzg4844.CellsToBlob(ckzgCells)
if err != nil {
return Blob{}, err
var cells []Cell
var proofs []Proof
for i := range ckzgCells {
cells = append(cells, Cell(ckzgCells[i]))
proofs = append(proofs, Proof(ckzgProofs[i]))
}

return Blob(blob), nil
}

// The correct type for Cell is [BytesPerCell]byte
// c-kzg currently uses [BytesPerFieldElement]Bytes32
// so we have these helper methods to convert between the two.
func cellToCKZGCell(flattened *Cell) ckzg4844.Cell {
var cell ckzg4844.Cell
for i := 0; i < fieldElementsPerCell; i++ {
copy(cell[i][:], flattened[i*32:(i+1)*32])
}
return cell
}
func ckzgCellToCell(cell *ckzg4844.Cell) Cell {
var flattened Cell
for i, fieldElement := range cell {
copy(flattened[i*32:(i+1)*32], fieldElement[:])
}
return flattened
return CellsAndProofs{
Cells: cells,
Proofs: proofs,
}, nil
}
21 changes: 0 additions & 21 deletions beacon-chain/blockchain/kzg/kzg_test.go

This file was deleted.

37 changes: 26 additions & 11 deletions beacon-chain/blockchain/kzg/trusted_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,47 @@ var (
kzgLoaded bool
)

type TrustedSetup struct {
G1Monomial [GoKZG.ScalarsPerBlob]GoKZG.G1CompressedHexStr `json:"g1_monomial"`
G1Lagrange [GoKZG.ScalarsPerBlob]GoKZG.G1CompressedHexStr `json:"g1_lagrange"`
G2Monomial [65]GoKZG.G2CompressedHexStr `json:"g2_monomial"`
}

func Start() error {
parsedSetup := &GoKZG.JSONTrustedSetup{}
err := json.Unmarshal(embeddedTrustedSetup, parsedSetup)
trustedSetup := &TrustedSetup{}
err := json.Unmarshal(embeddedTrustedSetup, trustedSetup)
if err != nil {
return errors.Wrap(err, "could not parse trusted setup JSON")
}
kzgContext, err = GoKZG.NewContext4096(parsedSetup)
kzgContext, err = GoKZG.NewContext4096(&GoKZG.JSONTrustedSetup{
SetupG2: trustedSetup.G2Monomial[:],
SetupG1Lagrange: trustedSetup.G1Lagrange})
if err != nil {
return errors.Wrap(err, "could not initialize go-kzg context")
}
g1Lagrange := &parsedSetup.SetupG1Lagrange

// Length of a G1 point, converted from hex to binary.
g1s := make([]byte, len(g1Lagrange)*(len(g1Lagrange[0])-2)/2)
for i, g1 := range g1Lagrange {
copy(g1s[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
g1MonomialBytes := make([]byte, len(trustedSetup.G1Monomial)*(len(trustedSetup.G1Monomial[0])-2)/2)
for i, g1 := range &trustedSetup.G1Monomial {
copy(g1MonomialBytes[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
}
// Length of a G1 point, converted from hex to binary.
g1LagrangeBytes := make([]byte, len(trustedSetup.G1Lagrange)*(len(trustedSetup.G1Lagrange[0])-2)/2)
for i, g1 := range &trustedSetup.G1Lagrange {
copy(g1LagrangeBytes[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
}
// Length of a G2 point, converted from hex to binary.
g2s := make([]byte, len(parsedSetup.SetupG2)*(len(parsedSetup.SetupG2[0])-2)/2)
for i, g2 := range parsedSetup.SetupG2 {
copy(g2s[i*(len(g2)-2)/2:], hexutil.MustDecode(g2))
g2MonomialBytes := make([]byte, len(trustedSetup.G2Monomial)*(len(trustedSetup.G2Monomial[0])-2)/2)
for i, g2 := range &trustedSetup.G2Monomial {
copy(g2MonomialBytes[i*(len(g2)-2)/2:], hexutil.MustDecode(g2))
}
if !kzgLoaded {
// TODO: Provide a configuration option for this.
var precompute uint = 0

// Free the current trusted setup before running this method. CKZG
// panics if the same setup is run multiple times.
if err = CKZG.LoadTrustedSetup(g1s, g2s); err != nil {
if err = CKZG.LoadTrustedSetup(g1MonomialBytes, g1LagrangeBytes, g2MonomialBytes, precompute); err != nil {
panic(err)
}
}
Expand Down
Loading

0 comments on commit 164d743

Please sign in to comment.