Skip to content

Commit ff65508

Browse files
karalabeholiman
authored andcommitted
crypto/kzg4844: pull in the C and Go libs for KZG cryptography (ethereum#27155)
* cryto/kzg4844: pull in the C and Go libs for KZG cryptography * go.mod: pull in the KZG libraries * crypto/kzg4844: add basic becnhmarks for ballpark numbers * cmd, crypto: integrate both CKZG and GoKZG all the time, add flag * cmd/utils, crypto/kzg4844: run library init on startup * crypto/kzg4844: make linter happy * crypto/kzg4844: push missing file * crypto/kzg4844: fully disable CKZG but leave in the sources * build, crypto/kzg4844, internal: link CKZG by default and with portable mode * crypto/kzg4844: drop verifying the trusted setup in gokzg * internal/build: yolo until it works? * cmd/utils: make flag description friendlier Co-authored-by: Martin Holst Swende <[email protected]> * crypto/ckzg: no need for double availability check * build: tiny flag cleanup nitpick --------- Co-authored-by: Martin Holst Swende <[email protected]>
1 parent a7cc4ba commit ff65508

File tree

12 files changed

+8890
-39
lines changed

12 files changed

+8890
-39
lines changed

build/ci.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,9 @@ func doInstall(cmdline []string) {
207207
csdb := build.MustLoadChecksums("build/checksums.txt")
208208
tc.Root = build.DownloadGo(csdb, dlgoVersion)
209209
}
210-
211-
// Disable CLI markdown doc generation in release builds.
212-
buildTags := []string{"urfave_cli_no_docs"}
210+
// Disable CLI markdown doc generation in release builds and enable linking
211+
// the CKZG library since we can make it portable here.
212+
buildTags := []string{"urfave_cli_no_docs", "ckzg"}
213213

214214
// Configure the build.
215215
env := build.Env()
@@ -221,7 +221,6 @@ func doInstall(cmdline []string) {
221221
if env.CI && runtime.GOARCH == "arm64" {
222222
gobuild.Args = append(gobuild.Args, "-p", "1")
223223
}
224-
225224
// We use -trimpath to avoid leaking local paths into the built executables.
226225
gobuild.Args = append(gobuild.Args, "-trimpath")
227226

@@ -299,7 +298,7 @@ func doTest(cmdline []string) {
299298
csdb := build.MustLoadChecksums("build/checksums.txt")
300299
tc.Root = build.DownloadGo(csdb, dlgoVersion)
301300
}
302-
gotest := tc.Go("test")
301+
gotest := tc.Go("test", "-tags=ckzg")
303302

304303
// Test a single package at a time. CI builders are slow
305304
// and some tests run into timeouts under load.

cmd/geth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ var (
107107
utils.CachePreimagesFlag,
108108
utils.CacheLogSizeFlag,
109109
utils.FDLimitFlag,
110+
utils.CryptoKZGFlag,
110111
utils.ListenPortFlag,
111112
utils.DiscoveryPortFlag,
112113
utils.MaxPeersFlag,

cmd/utils/flags.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"github.com/ethereum/go-ethereum/core/types"
4646
"github.com/ethereum/go-ethereum/core/vm"
4747
"github.com/ethereum/go-ethereum/crypto"
48+
"github.com/ethereum/go-ethereum/crypto/kzg4844"
4849
"github.com/ethereum/go-ethereum/eth"
4950
ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst"
5051
"github.com/ethereum/go-ethereum/eth/downloader"
@@ -454,6 +455,12 @@ var (
454455
Usage: "Raise the open file descriptor resource limit (default = system fd limit)",
455456
Category: flags.PerfCategory,
456457
}
458+
CryptoKZGFlag = &cli.StringFlag{
459+
Name: "crypto.kzg",
460+
Usage: "KZG library implementation to use; gokzg (recommended) or ckzg",
461+
Value: "gokzg",
462+
Category: flags.PerfCategory,
463+
}
457464

458465
// Miner settings
459466
MiningEnabledFlag = &cli.BoolFlag{
@@ -1747,7 +1754,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
17471754
cfg.EthDiscoveryURLs = SplitAndTrim(urls)
17481755
}
17491756
}
1750-
17511757
// Override any default configs for hard coded networks.
17521758
switch {
17531759
case ctx.Bool(MainnetFlag.Name):
@@ -1857,6 +1863,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
18571863
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
18581864
}
18591865
}
1866+
// Set any dangling config values
1867+
if ctx.String(CryptoKZGFlag.Name) != "gokzg" && ctx.String(CryptoKZGFlag.Name) != "ckzg" {
1868+
Fatalf("--%s flag must be 'gokzg' or 'ckzg'", CryptoKZGFlag.Name)
1869+
}
1870+
log.Info("Initializing the KZG library", "backend", ctx.String(CryptoKZGFlag.Name))
1871+
if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil {
1872+
Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err)
1873+
}
18601874
}
18611875

18621876
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if

crypto/kzg4844/kzg4844.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2023 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
// Package kzg4844 implements the KZG crypto for EIP-4844.
18+
package kzg4844
19+
20+
import (
21+
"embed"
22+
"errors"
23+
"sync/atomic"
24+
)
25+
26+
//go:embed trusted_setup.json
27+
var content embed.FS
28+
29+
// Blob represents a 4844 data blob.
30+
type Blob [131072]byte
31+
32+
// Commitment is a serialized commitment to a polynomial.
33+
type Commitment [48]byte
34+
35+
// Proof is a serialized commitment to the quotient polynomial.
36+
type Proof [48]byte
37+
38+
// Point is a BLS field element.
39+
type Point [32]byte
40+
41+
// Claim is a claimed evaluation value in a specific point.
42+
type Claim [32]byte
43+
44+
// useCKZG controls whether the cryptography should use the Go or C backend.
45+
var useCKZG atomic.Bool
46+
47+
// UseCKZG can be called to switch the default Go implementation of KZG to the C
48+
// library if fo some reason the user wishes to do so (e.g. consensus bug in one
49+
// or the other).
50+
func UseCKZG(use bool) error {
51+
if use && !ckzgAvailable {
52+
return errors.New("CKZG unavailable on your platform")
53+
}
54+
useCKZG.Store(use)
55+
56+
// Initializing the library can take 2-4 seconds - and can potentially crash
57+
// on CKZG and non-ADX CPUs - so might as well so it now and don't wait until
58+
// a crpyto operation is actually needed live.
59+
if use {
60+
ckzgIniter.Do(ckzgInit)
61+
} else {
62+
gokzgIniter.Do(gokzgInit)
63+
}
64+
return nil
65+
}
66+
67+
// BlobToCommitment creates a small commitment out of a data blob.
68+
func BlobToCommitment(blob Blob) (Commitment, error) {
69+
if useCKZG.Load() {
70+
return ckzgBlobToCommitment(blob)
71+
}
72+
return gokzgBlobToCommitment(blob)
73+
}
74+
75+
// ComputeProof computes the KZG proof at the given point for the polynomial
76+
// represented by the blob.
77+
func ComputeProof(blob Blob, point Point) (Proof, Claim, error) {
78+
if useCKZG.Load() {
79+
return ckzgComputeProof(blob, point)
80+
}
81+
return gokzgComputeProof(blob, point)
82+
}
83+
84+
// VerifyProof verifies the KZG proof that the polynomial represented by the blob
85+
// evaluated at the given point is the claimed value.
86+
func VerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error {
87+
if useCKZG.Load() {
88+
return ckzgVerifyProof(commitment, point, claim, proof)
89+
}
90+
return gokzgVerifyProof(commitment, point, claim, proof)
91+
}
92+
93+
// ComputeBlobProof returns the KZG proof that is used to verify the blob against
94+
// the commitment.
95+
//
96+
// This method does not verify that the commitment is correct with respect to blob.
97+
func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
98+
if useCKZG.Load() {
99+
return ckzgComputeBlobProof(blob, commitment)
100+
}
101+
return gokzgComputeBlobProof(blob, commitment)
102+
}
103+
104+
// VerifyBlobProof verifies that the blob data corresponds to the provided commitment.
105+
func VerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error {
106+
if useCKZG.Load() {
107+
return ckzgVerifyBlobProof(blob, commitment, proof)
108+
}
109+
return gokzgVerifyBlobProof(blob, commitment, proof)
110+
}

crypto/kzg4844/kzg4844_ckzg_cgo.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2023 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
//go:build ckzg && !nacl && !js && cgo && !gofuzz
18+
19+
package kzg4844
20+
21+
import (
22+
"encoding/json"
23+
"errors"
24+
"sync"
25+
26+
gokzg4844 "github.com/crate-crypto/go-kzg-4844"
27+
ckzg4844 "github.com/ethereum/c-kzg-4844/bindings/go"
28+
"github.com/ethereum/go-ethereum/common/hexutil"
29+
)
30+
31+
// ckzgAvailable signals whether the library was compiled into Geth.
32+
const ckzgAvailable = true
33+
34+
// ckzgIniter ensures that we initialize the KZG library once before using it.
35+
var ckzgIniter sync.Once
36+
37+
// ckzgInit initializes the KZG library with the provided trusted setup.
38+
func ckzgInit() {
39+
config, err := content.ReadFile("trusted_setup.json")
40+
if err != nil {
41+
panic(err)
42+
}
43+
params := new(gokzg4844.JSONTrustedSetup)
44+
if err = json.Unmarshal(config, params); err != nil {
45+
panic(err)
46+
}
47+
if err = gokzg4844.CheckTrustedSetupIsWellFormed(params); err != nil {
48+
panic(err)
49+
}
50+
g1s := make([]byte, len(params.SetupG1)*(len(params.SetupG1[0])-2)/2)
51+
for i, g1 := range params.SetupG1 {
52+
copy(g1s[i*(len(g1)-2)/2:], hexutil.MustDecode(g1))
53+
}
54+
g2s := make([]byte, len(params.SetupG2)*(len(params.SetupG2[0])-2)/2)
55+
for i, g2 := range params.SetupG2 {
56+
copy(g2s[i*(len(g2)-2)/2:], hexutil.MustDecode(g2))
57+
}
58+
if err = ckzg4844.LoadTrustedSetup(g1s, g2s); err != nil {
59+
panic(err)
60+
}
61+
}
62+
63+
// ckzgBlobToCommitment creates a small commitment out of a data blob.
64+
func ckzgBlobToCommitment(blob Blob) (Commitment, error) {
65+
ckzgIniter.Do(ckzgInit)
66+
67+
commitment, err := ckzg4844.BlobToKZGCommitment((ckzg4844.Blob)(blob))
68+
if err != nil {
69+
return Commitment{}, err
70+
}
71+
return (Commitment)(commitment), nil
72+
}
73+
74+
// ckzgComputeProof computes the KZG proof at the given point for the polynomial
75+
// represented by the blob.
76+
func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) {
77+
proof, claim, err := ckzg4844.ComputeKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point))
78+
if err != nil {
79+
return Proof{}, Claim{}, err
80+
}
81+
return (Proof)(proof), (Claim)(claim), nil
82+
}
83+
84+
// ckzgVerifyProof verifies the KZG proof that the polynomial represented by the blob
85+
// evaluated at the given point is the claimed value.
86+
func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error {
87+
valid, err := ckzg4844.VerifyKZGProof((ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes32)(point), (ckzg4844.Bytes32)(claim), (ckzg4844.Bytes48)(proof))
88+
if err != nil {
89+
return err
90+
}
91+
if !valid {
92+
return errors.New("invalid proof")
93+
}
94+
return nil
95+
}
96+
97+
// ckzgComputeBlobProof returns the KZG proof that is used to verify the blob against
98+
// the commitment.
99+
//
100+
// This method does not verify that the commitment is correct with respect to blob.
101+
func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
102+
proof, err := ckzg4844.ComputeBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment))
103+
if err != nil {
104+
return Proof{}, err
105+
}
106+
return (Proof)(proof), nil
107+
}
108+
109+
// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment.
110+
func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error {
111+
valid, err := ckzg4844.VerifyBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof))
112+
if err != nil {
113+
return err
114+
}
115+
if !valid {
116+
return errors.New("invalid proof")
117+
}
118+
return nil
119+
}

crypto/kzg4844/kzg4844_ckzg_nocgo.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2023 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
//go:build !ckzg || nacl || js || !cgo || gofuzz
18+
19+
package kzg4844
20+
21+
import "sync"
22+
23+
// ckzgAvailable signals whether the library was compiled into Geth.
24+
const ckzgAvailable = false
25+
26+
// ckzgIniter ensures that we initialize the KZG library once before using it.
27+
var ckzgIniter sync.Once
28+
29+
// ckzgInit initializes the KZG library with the provided trusted setup.
30+
func ckzgInit() {
31+
panic("unsupported platform")
32+
}
33+
34+
// ckzgBlobToCommitment creates a small commitment out of a data blob.
35+
func ckzgBlobToCommitment(blob Blob) (Commitment, error) {
36+
panic("unsupported platform")
37+
}
38+
39+
// ckzgComputeProof computes the KZG proof at the given point for the polynomial
40+
// represented by the blob.
41+
func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) {
42+
panic("unsupported platform")
43+
}
44+
45+
// ckzgVerifyProof verifies the KZG proof that the polynomial represented by the blob
46+
// evaluated at the given point is the claimed value.
47+
func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error {
48+
panic("unsupported platform")
49+
}
50+
51+
// ckzgComputeBlobProof returns the KZG proof that is used to verify the blob against
52+
// the commitment.
53+
//
54+
// This method does not verify that the commitment is correct with respect to blob.
55+
func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) {
56+
panic("unsupported platform")
57+
}
58+
59+
// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment.
60+
func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error {
61+
panic("unsupported platform")
62+
}

0 commit comments

Comments
 (0)