Skip to content

Commit ab5505e

Browse files
Implement all needed KZG wrappers for peerDAS in the kzg package. (#15186)
* Implement all needed KZG wrappers for peerDAS in the `kzg` package. This way, If we need to change the KZG backend, the only package to modify is the `kzg` package. * `.bazelrc`: Add `build --compilation_mode=opt` * Remove --compilation_mode=opt, use supranational blst headers. * Fix Terence's comment. * Fix Terence`s comments. --------- Co-authored-by: Preston Van Loon <[email protected]>
1 parent 9c00b06 commit ab5505e

File tree

9 files changed

+4310
-16
lines changed

9 files changed

+4310
-16
lines changed

beacon-chain/blockchain/kzg/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
33
go_library(
44
name = "go_default_library",
55
srcs = [
6+
"kzg.go",
67
"trusted_setup.go",
78
"validation.go",
89
],
9-
embedsrcs = ["trusted_setup.json"],
10+
embedsrcs = ["trusted_setup_4096.json"],
1011
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg",
1112
visibility = ["//visibility:public"],
1213
deps = [
1314
"//consensus-types/blocks:go_default_library",
1415
"@com_github_crate_crypto_go_kzg_4844//:go_default_library",
16+
"@com_github_ethereum_c_kzg_4844//bindings/go:go_default_library",
17+
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
18+
"@com_github_ethereum_go_ethereum//crypto/kzg4844:go_default_library",
1519
"@com_github_pkg_errors//:go_default_library",
1620
],
1721
)

beacon-chain/blockchain/kzg/kzg.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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+
}

beacon-chain/blockchain/kzg/trusted_setup.go

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,69 @@ import (
55
"encoding/json"
66

77
GoKZG "github.com/crate-crypto/go-kzg-4844"
8+
CKZG "github.com/ethereum/c-kzg-4844/v2/bindings/go"
9+
"github.com/ethereum/go-ethereum/common/hexutil"
810
"github.com/pkg/errors"
911
)
1012

1113
var (
12-
//go:embed trusted_setup.json
14+
// https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/trusted_setups/trusted_setup_4096.json
15+
//go:embed trusted_setup_4096.json
1316
embeddedTrustedSetup []byte // 1.2Mb
1417
kzgContext *GoKZG.Context
18+
kzgLoaded bool
1519
)
1620

21+
type TrustedSetup struct {
22+
G1Monomial [GoKZG.ScalarsPerBlob]GoKZG.G1CompressedHexStr `json:"g1_monomial"`
23+
G1Lagrange [GoKZG.ScalarsPerBlob]GoKZG.G1CompressedHexStr `json:"g1_lagrange"`
24+
G2Monomial [65]GoKZG.G2CompressedHexStr `json:"g2_monomial"`
25+
}
26+
1727
func Start() error {
18-
parsedSetup := GoKZG.JSONTrustedSetup{}
19-
err := json.Unmarshal(embeddedTrustedSetup, &parsedSetup)
28+
trustedSetup := &TrustedSetup{}
29+
err := json.Unmarshal(embeddedTrustedSetup, trustedSetup)
2030
if err != nil {
2131
return errors.Wrap(err, "could not parse trusted setup JSON")
2232
}
23-
kzgContext, err = GoKZG.NewContext4096(&parsedSetup)
33+
34+
kzgContext, err = GoKZG.NewContext4096(&GoKZG.JSONTrustedSetup{
35+
SetupG2: trustedSetup.G2Monomial[:],
36+
SetupG1Lagrange: trustedSetup.G1Lagrange,
37+
})
2438
if err != nil {
2539
return errors.Wrap(err, "could not initialize go-kzg context")
2640
}
41+
42+
// Length of a G1 point, converted from hex to binary.
43+
g1MonomialBytes := make([]byte, len(trustedSetup.G1Monomial)*(len(trustedSetup.G1Monomial[0])-2)/2)
44+
for i, g1 := range &trustedSetup.G1Monomial {
45+
copy(g1MonomialBytes[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
46+
}
47+
48+
// Length of a G1 point, converted from hex to binary.
49+
g1LagrangeBytes := make([]byte, len(trustedSetup.G1Lagrange)*(len(trustedSetup.G1Lagrange[0])-2)/2)
50+
for i, g1 := range &trustedSetup.G1Lagrange {
51+
copy(g1LagrangeBytes[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
52+
}
53+
54+
// Length of a G2 point, converted from hex to binary.
55+
g2MonomialBytes := make([]byte, len(trustedSetup.G2Monomial)*(len(trustedSetup.G2Monomial[0])-2)/2)
56+
for i, g2 := range &trustedSetup.G2Monomial {
57+
copy(g2MonomialBytes[i*(len(g2)-2)/2:], hexutil.MustDecode(g2))
58+
}
59+
60+
if !kzgLoaded {
61+
const precompute uint = 8
62+
63+
kzgLoaded = true
64+
65+
// Free the current trusted setup before running this method.
66+
// CKZG panics if the same setup is run multiple times.
67+
if err = CKZG.LoadTrustedSetup(g1MonomialBytes, g1LagrangeBytes, g2MonomialBytes, precompute); err != nil {
68+
return errors.Wrap(err, "load trust setup")
69+
}
70+
}
71+
2772
return nil
2873
}

0 commit comments

Comments
 (0)