Upgrade to c-kzg 2.1.0 and alloy-primitives 1.0 (#7271)

Update `c-kzg` from `v1` to `v2`. My motivation here is that `alloy-consensus` now uses `c-kzg` in `v2` and this results in a conflict when using lighthouse in combination with latest alloy. I tried also to disable the `czkg` feature in alloy, but the conflict persisted.

See here for the alloy update to `c-kzg v2`:  https://github.com/alloy-rs/alloy/pull/2240

Error:
```
error: failed to select a version for `c-kzg`.
...
versions that meet the requirements `^1` are: 1.0.3, 1.0.2, 1.0.0

the package `c-kzg` links to the native library `ckzg`, but it conflicts with a previous package which links to `ckzg` as well:
package `c-kzg v2.1.0`
... which satisfies dependency `c-kzg = "^2.1"` of package `alloy-consensus v0.13.0`
... which satisfies dependency `alloy-consensus = "^0.13.0"` of package ...
...
```


  - Upgrade `alloy-consensus` to `0.14.0` and disable all default features
- Upgrade `c-kzg` to `v2.1.0`
- Upgrade `alloy-primitives` to `1.0.0`
- Adapt the code to the new API `c-kzg`
- There is now `NO_PRECOMPUTE` as my understand from https://github.com/ethereum/c-kzg-4844/pull/545/files we should use `0` here as `new_from_trusted_setup_no_precomp` does not precomp. But maybe it is misleading. For all other places I used `RECOMMENDED_PRECOMP_WIDTH` because `8` is matching the recommendation.
- `BYTES_PER_G1_POINT` and `BYTES_PER_G2_POINT` are no longer public in `c-kzg`
- I adapted two tests that checking for the `Attestation`  bitfield size. But I could not pinpoint to what has changed and why now 8 bytes less. I would be happy about any hint, and if this is correct. I found related a PR here: https://github.com/sigp/lighthouse/pull/6915
- Use same fields names, in json, as well as `c-kzg` and `rust_eth_kzg` for `g1_monomial`, `g1_lagrange`, and `g2_monomial`
This commit is contained in:
cakevm
2025-07-09 07:02:41 +02:00
committed by GitHub
parent b9c1a2b0c0
commit 734ad90dd8
8 changed files with 650 additions and 520 deletions

View File

@@ -1,6 +1,6 @@
use c_kzg::KzgSettings;
use criterion::{criterion_group, criterion_main, Criterion};
use kzg::{trusted_setup::get_trusted_setup, TrustedSetup};
use kzg::{trusted_setup::get_trusted_setup, TrustedSetup, NO_PRECOMPUTE};
use rust_eth_kzg::{DASContext, TrustedSetup as PeerDASTrustedSetup};
pub fn bench_init_context(c: &mut Criterion) {
@@ -25,8 +25,13 @@ pub fn bench_init_context(c: &mut Criterion) {
serde_json::from_reader(get_trusted_setup().as_slice())
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
.expect("should have trusted setup");
KzgSettings::load_trusted_setup(&trusted_setup.g1_points(), &trusted_setup.g2_points())
.unwrap()
KzgSettings::load_trusted_setup(
&trusted_setup.g1_monomial(),
&trusted_setup.g1_lagrange(),
&trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)
.unwrap()
})
});
}

View File

@@ -21,6 +21,13 @@ pub use rust_eth_kzg::{
Cell, CellIndex as CellID, CellRef, TrustedSetup as PeerDASTrustedSetup,
};
/// Disables the fixed-base multi-scalar multiplication optimization for computing
/// cell KZG proofs, because `rust-eth-kzg` already handles the precomputation.
///
/// Details about `precompute` parameter can be found here:
/// <https://github.com/ethereum/c-kzg-4844/pull/545/files>
pub const NO_PRECOMPUTE: u64 = 0;
// Note: `spec.number_of_columns` is a config and should match `CELLS_PER_EXT_BLOB` - however this
// is a constant in the KZG library - be aware that overriding `number_of_columns` will break KZG
// operations.
@@ -65,8 +72,10 @@ impl Kzg {
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
&trusted_setup.g1_monomial(),
&trusted_setup.g1_lagrange(),
&trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)?,
context,
})
@@ -85,8 +94,10 @@ impl Kzg {
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
&trusted_setup.g1_monomial(),
&trusted_setup.g1_lagrange(),
&trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)?,
context,
})
@@ -111,8 +122,10 @@ impl Kzg {
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
&trusted_setup.g1_monomial(),
&trusted_setup.g1_lagrange(),
&trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)?,
context,
})
@@ -128,7 +141,8 @@ impl Kzg {
blob: &Blob,
kzg_commitment: KzgCommitment,
) -> Result<KzgProof, Error> {
c_kzg::KzgProof::compute_blob_kzg_proof(blob, &kzg_commitment.into(), &self.trusted_setup)
self.trusted_setup
.compute_blob_kzg_proof(blob, &kzg_commitment.into())
.map(|proof| KzgProof(proof.to_bytes().into_inner()))
.map_err(Into::into)
}
@@ -140,11 +154,10 @@ impl Kzg {
kzg_commitment: KzgCommitment,
kzg_proof: KzgProof,
) -> Result<(), Error> {
if !c_kzg::KzgProof::verify_blob_kzg_proof(
if !self.trusted_setup.verify_blob_kzg_proof(
blob,
&kzg_commitment.into(),
&kzg_proof.into(),
&self.trusted_setup,
)? {
Err(Error::KzgVerificationFailed)
} else {
@@ -172,11 +185,10 @@ impl Kzg {
.map(|proof| Bytes48::from(*proof))
.collect::<Vec<_>>();
if !c_kzg::KzgProof::verify_blob_kzg_proof_batch(
if !self.trusted_setup.verify_blob_kzg_proof_batch(
blobs,
&commitments_bytes,
&proofs_bytes,
&self.trusted_setup,
)? {
Err(Error::KzgVerificationFailed)
} else {
@@ -186,7 +198,8 @@ impl Kzg {
/// Converts a blob to a kzg commitment.
pub fn blob_to_kzg_commitment(&self, blob: &Blob) -> Result<KzgCommitment, Error> {
c_kzg::KzgCommitment::blob_to_kzg_commitment(blob, &self.trusted_setup)
self.trusted_setup
.blob_to_kzg_commitment(blob)
.map(|commitment| KzgCommitment(commitment.to_bytes().into_inner()))
.map_err(Into::into)
}
@@ -197,7 +210,8 @@ impl Kzg {
blob: &Blob,
z: &Bytes32,
) -> Result<(KzgProof, Bytes32), Error> {
c_kzg::KzgProof::compute_kzg_proof(blob, z, &self.trusted_setup)
self.trusted_setup
.compute_kzg_proof(blob, z)
.map(|(proof, y)| (KzgProof(proof.to_bytes().into_inner()), y))
.map_err(Into::into)
}
@@ -210,14 +224,9 @@ impl Kzg {
y: &Bytes32,
kzg_proof: KzgProof,
) -> Result<bool, Error> {
c_kzg::KzgProof::verify_kzg_proof(
&kzg_commitment.into(),
z,
y,
&kzg_proof.into(),
&self.trusted_setup,
)
.map_err(Into::into)
self.trusted_setup
.verify_kzg_proof(&kzg_commitment.into(), z, y, &kzg_proof.into())
.map_err(Into::into)
}
/// Computes the cells and associated proofs for a given `blob`.

View File

@@ -1,10 +1,14 @@
use crate::PeerDASTrustedSetup;
use c_kzg::{BYTES_PER_G1_POINT, BYTES_PER_G2_POINT};
use serde::{
de::{self, Deserializer, Visitor},
Deserialize, Serialize,
};
// Number of bytes per G1 point.
const BYTES_PER_G1_POINT: usize = 48;
// Number of bytes per G2 point.
const BYTES_PER_G2_POINT: usize = 96;
pub const TRUSTED_SETUP_BYTES: &[u8] = include_bytes!("../trusted_setup.json");
pub fn get_trusted_setup() -> Vec<u8> {
@@ -23,30 +27,31 @@ struct G2Point([u8; BYTES_PER_G2_POINT]);
/// `c_kzg::KzgSettings` object.
///
/// The serialize/deserialize implementations are written according to
/// the format specified in the the ethereum consensus specs trusted setup files.
/// the format specified in the ethereum consensus specs trusted setup files.
///
/// See https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/trusted_setups/trusted_setup_4096.json
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TrustedSetup {
#[serde(rename = "g1_monomial")]
g1_monomial_points: Vec<G1Point>,
#[serde(rename = "g1_lagrange")]
g1_points: Vec<G1Point>,
#[serde(rename = "g2_monomial")]
g2_points: Vec<G2Point>,
g1_monomial: Vec<G1Point>,
g1_lagrange: Vec<G1Point>,
g2_monomial: Vec<G2Point>,
}
impl TrustedSetup {
pub fn g1_points(&self) -> Vec<[u8; BYTES_PER_G1_POINT]> {
self.g1_points.iter().map(|p| p.0).collect()
pub fn g1_monomial(&self) -> Vec<u8> {
self.g1_monomial.iter().flat_map(|p| p.0).collect()
}
pub fn g2_points(&self) -> Vec<[u8; BYTES_PER_G2_POINT]> {
self.g2_points.iter().map(|p| p.0).collect()
pub fn g1_lagrange(&self) -> Vec<u8> {
self.g1_lagrange.iter().flat_map(|p| p.0).collect()
}
pub fn g2_monomial(&self) -> Vec<u8> {
self.g2_monomial.iter().flat_map(|p| p.0).collect()
}
pub fn g1_len(&self) -> usize {
self.g1_points.len()
self.g1_lagrange.len()
}
}
@@ -54,17 +59,17 @@ impl From<&TrustedSetup> for PeerDASTrustedSetup {
fn from(trusted_setup: &TrustedSetup) -> Self {
Self {
g1_monomial: trusted_setup
.g1_monomial_points
.g1_monomial
.iter()
.map(|g1_point| format!("0x{}", hex::encode(g1_point.0)))
.collect::<Vec<_>>(),
g1_lagrange: trusted_setup
.g1_points
.g1_lagrange
.iter()
.map(|g1_point| format!("0x{}", hex::encode(g1_point.0)))
.collect::<Vec<_>>(),
g2_monomial: trusted_setup
.g2_points
.g2_monomial
.iter()
.map(|g2_point| format!("0x{}", hex::encode(g2_point.0)))
.collect::<Vec<_>>(),