Remove c-kzg (#8930)

#7330


  Removes `c-kzg` from our `kzg` crate and rely fully on the `rust_eth_kzg` crate.

This removes the old `Blob` type entirely and instead handles `rust_eth_kzg::KzgBlobRef`s directly which allows us to avoid some extra stack allocations . Similarly, we make `Bytes32` and `Bytes48` type aliases rather than structs as this fits better with the new `rust_eth_kzg` API.


Co-Authored-By: Mac L <mjladson@pm.me>
This commit is contained in:
Mac L
2026-03-11 07:43:26 +02:00
committed by GitHub
parent 2bb79f43aa
commit 815040dc3c
14 changed files with 129 additions and 188 deletions

1
Cargo.lock generated
View File

@@ -4825,7 +4825,6 @@ name = "kzg"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"c-kzg",
"criterion", "criterion",
"educe", "educe",
"ethereum_hashing", "ethereum_hashing",

View File

@@ -117,9 +117,6 @@ bitvec = "1"
bls = { path = "crypto/bls" } bls = { path = "crypto/bls" }
byteorder = "1" byteorder = "1"
bytes = "1.11.1" bytes = "1.11.1"
# Turn off c-kzg's default features which include `blst/portable`. We can turn on blst's portable
# feature ourselves when desired.
c-kzg = { version = "2.1", default-features = false }
cargo_metadata = "0.19" cargo_metadata = "0.19"
clap = { version = "4.5.4", features = ["derive", "cargo", "wrap_help"] } clap = { version = "4.5.4", features = ["derive", "cargo", "wrap_help"] }
clap_utils = { path = "common/clap_utils" } clap_utils = { path = "common/clap_utils" }

View File

@@ -1,6 +1,5 @@
use kzg::{ use kzg::{
Blob as KzgBlob, Bytes48, Cell as KzgCell, CellRef as KzgCellRef, CellsAndKzgProofs, Cell as KzgCell, CellRef as KzgCellRef, CellsAndKzgProofs, Error as KzgError, Kzg, KzgBlobRef,
Error as KzgError, Kzg, KzgBlobRef,
}; };
use rayon::prelude::*; use rayon::prelude::*;
use ssz_types::{FixedVector, VariableList}; use ssz_types::{FixedVector, VariableList};
@@ -15,18 +14,18 @@ use types::{
SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlindedBeaconBlock, Slot, SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlindedBeaconBlock, Slot,
}; };
/// Converts a blob ssz List object to an array to be used with the kzg /// Converts a blob ssz FixedVector to a reference to a fixed-size array
/// crypto library. /// to be used with `rust_eth_kzg`.
fn ssz_blob_to_crypto_blob<E: EthSpec>(blob: &Blob<E>) -> Result<KzgBlob, KzgError> { fn ssz_blob_to_kzg_blob_ref<E: EthSpec>(blob: &Blob<E>) -> Result<KzgBlobRef<'_>, KzgError> {
KzgBlob::from_bytes(blob.as_ref()).map_err(Into::into) blob.as_ref().try_into().map_err(|e| {
KzgError::InconsistentArrayLength(format!(
"blob should have a guaranteed size due to FixedVector: {e:?}"
))
})
} }
fn ssz_blob_to_crypto_blob_boxed<E: EthSpec>(blob: &Blob<E>) -> Result<Box<KzgBlob>, KzgError> { /// Converts a cell ssz FixedVector to a reference to a fixed-size array
ssz_blob_to_crypto_blob::<E>(blob).map(Box::new) /// to be used with `rust_eth_kzg`.
}
/// Converts a cell ssz List object to an array to be used with the kzg
/// crypto library.
fn ssz_cell_to_crypto_cell<E: EthSpec>(cell: &Cell<E>) -> Result<KzgCellRef<'_>, KzgError> { fn ssz_cell_to_crypto_cell<E: EthSpec>(cell: &Cell<E>) -> Result<KzgCellRef<'_>, KzgError> {
let cell_bytes: &[u8] = cell.as_ref(); let cell_bytes: &[u8] = cell.as_ref();
cell_bytes cell_bytes
@@ -42,8 +41,8 @@ pub fn validate_blob<E: EthSpec>(
kzg_proof: KzgProof, kzg_proof: KzgProof,
) -> Result<(), KzgError> { ) -> Result<(), KzgError> {
let _timer = crate::metrics::start_timer(&crate::metrics::KZG_VERIFICATION_SINGLE_TIMES); let _timer = crate::metrics::start_timer(&crate::metrics::KZG_VERIFICATION_SINGLE_TIMES);
let kzg_blob = ssz_blob_to_crypto_blob_boxed::<E>(blob)?; let kzg_blob = ssz_blob_to_kzg_blob_ref::<E>(blob)?;
kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof) kzg.verify_blob_kzg_proof(kzg_blob, kzg_commitment, kzg_proof)
} }
/// Validate a batch of `DataColumnSidecar`. /// Validate a batch of `DataColumnSidecar`.
@@ -72,7 +71,7 @@ where
} }
for &proof in data_column.kzg_proofs() { for &proof in data_column.kzg_proofs() {
proofs.push(Bytes48::from(proof)); proofs.push(proof.0);
} }
// In Gloas, commitments come from the block's ExecutionPayloadBid, not the sidecar. // In Gloas, commitments come from the block's ExecutionPayloadBid, not the sidecar.
@@ -90,7 +89,7 @@ where
}; };
for &commitment in kzg_commitments.iter() { for &commitment in kzg_commitments.iter() {
commitments.push(Bytes48::from(commitment)); commitments.push(commitment.0);
} }
let expected_len = column_indices.len(); let expected_len = column_indices.len();
@@ -120,7 +119,7 @@ pub fn validate_blobs<E: EthSpec>(
let _timer = crate::metrics::start_timer(&crate::metrics::KZG_VERIFICATION_BATCH_TIMES); let _timer = crate::metrics::start_timer(&crate::metrics::KZG_VERIFICATION_BATCH_TIMES);
let blobs = blobs let blobs = blobs
.into_iter() .into_iter()
.map(|blob| ssz_blob_to_crypto_blob::<E>(blob)) .map(|blob| ssz_blob_to_kzg_blob_ref::<E>(blob))
.collect::<Result<Vec<_>, KzgError>>()?; .collect::<Result<Vec<_>, KzgError>>()?;
kzg.verify_blob_kzg_proof_batch(&blobs, expected_kzg_commitments, kzg_proofs) kzg.verify_blob_kzg_proof_batch(&blobs, expected_kzg_commitments, kzg_proofs)
@@ -132,8 +131,8 @@ pub fn compute_blob_kzg_proof<E: EthSpec>(
blob: &Blob<E>, blob: &Blob<E>,
kzg_commitment: KzgCommitment, kzg_commitment: KzgCommitment,
) -> Result<KzgProof, KzgError> { ) -> Result<KzgProof, KzgError> {
let kzg_blob = ssz_blob_to_crypto_blob_boxed::<E>(blob)?; let kzg_blob = ssz_blob_to_kzg_blob_ref::<E>(blob)?;
kzg.compute_blob_kzg_proof(&kzg_blob, kzg_commitment) kzg.compute_blob_kzg_proof(kzg_blob, kzg_commitment)
} }
/// Compute the kzg commitment for a given blob. /// Compute the kzg commitment for a given blob.
@@ -141,8 +140,8 @@ pub fn blob_to_kzg_commitment<E: EthSpec>(
kzg: &Kzg, kzg: &Kzg,
blob: &Blob<E>, blob: &Blob<E>,
) -> Result<KzgCommitment, KzgError> { ) -> Result<KzgCommitment, KzgError> {
let kzg_blob = ssz_blob_to_crypto_blob_boxed::<E>(blob)?; let kzg_blob = ssz_blob_to_kzg_blob_ref::<E>(blob)?;
kzg.blob_to_kzg_commitment(&kzg_blob) kzg.blob_to_kzg_commitment(kzg_blob)
} }
/// Compute the kzg proof for a given blob and an evaluation point z. /// Compute the kzg proof for a given blob and an evaluation point z.
@@ -151,10 +150,9 @@ pub fn compute_kzg_proof<E: EthSpec>(
blob: &Blob<E>, blob: &Blob<E>,
z: Hash256, z: Hash256,
) -> Result<(KzgProof, Hash256), KzgError> { ) -> Result<(KzgProof, Hash256), KzgError> {
let z = z.0.into(); let kzg_blob = ssz_blob_to_kzg_blob_ref::<E>(blob)?;
let kzg_blob = ssz_blob_to_crypto_blob_boxed::<E>(blob)?; kzg.compute_kzg_proof(kzg_blob, &z.0)
kzg.compute_kzg_proof(&kzg_blob, &z) .map(|(proof, z)| (proof, Hash256::from_slice(&z)))
.map(|(proof, z)| (proof, Hash256::from_slice(&z.to_vec())))
} }
/// Verify a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y` /// Verify a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y`
@@ -165,7 +163,7 @@ pub fn verify_kzg_proof<E: EthSpec>(
z: Hash256, z: Hash256,
y: Hash256, y: Hash256,
) -> Result<bool, KzgError> { ) -> Result<bool, KzgError> {
kzg.verify_kzg_proof(kzg_commitment, &z.0.into(), &y.0.into(), kzg_proof) kzg.verify_kzg_proof(kzg_commitment, &z.0, &y.0, kzg_proof)
} }
/// Build data column sidecars from a signed beacon block and its blobs. /// Build data column sidecars from a signed beacon block and its blobs.

View File

@@ -989,7 +989,7 @@ pub fn generate_pow_block(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use kzg::{Bytes48, CellRef, KzgBlobRef, trusted_setup::get_trusted_setup}; use kzg::{CellRef, KzgBlobRef, trusted_setup::get_trusted_setup};
use types::{MainnetEthSpec, MinimalEthSpec}; use types::{MainnetEthSpec, MinimalEthSpec};
#[test] #[test]
@@ -1015,10 +1015,11 @@ mod test {
fn validate_blob_bundle_v1<E: EthSpec>() -> Result<(), String> { fn validate_blob_bundle_v1<E: EthSpec>() -> Result<(), String> {
let kzg = load_kzg()?; let kzg = load_kzg()?;
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle_v1::<E>()?; let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle_v1::<E>()?;
let kzg_blob = kzg::Blob::from_bytes(blob.as_ref()) let kzg_blob: KzgBlobRef = blob
.map(Box::new) .as_ref()
.map_err(|e| format!("Error converting blob to kzg blob: {e:?}"))?; .try_into()
kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof) .map_err(|e| format!("Error converting blob to kzg blob ref: {e:?}"))?;
kzg.verify_blob_kzg_proof(kzg_blob, kzg_commitment, kzg_proof)
.map_err(|e| format!("Invalid blobs bundle: {e:?}")) .map_err(|e| format!("Invalid blobs bundle: {e:?}"))
} }
@@ -1028,8 +1029,8 @@ mod test {
load_test_blobs_bundle_v2::<E>().map(|(commitment, proofs, blob)| { load_test_blobs_bundle_v2::<E>().map(|(commitment, proofs, blob)| {
let kzg_blob: KzgBlobRef = blob.as_ref().try_into().unwrap(); let kzg_blob: KzgBlobRef = blob.as_ref().try_into().unwrap();
( (
vec![Bytes48::from(commitment); proofs.len()], vec![commitment.0; proofs.len()],
proofs.into_iter().map(|p| p.into()).collect::<Vec<_>>(), proofs.into_iter().map(|p| p.0).collect::<Vec<_>>(),
kzg.compute_cells(kzg_blob).unwrap(), kzg.compute_cells(kzg_blob).unwrap(),
) )
})?; })?;

View File

@@ -3,7 +3,7 @@ use std::{fmt::Debug, hash::Hash, sync::Arc};
use bls::Signature; use bls::Signature;
use context_deserialize::context_deserialize; use context_deserialize::context_deserialize;
use educe::Educe; use educe::Educe;
use kzg::{BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT, Blob as KzgBlob, Kzg, KzgCommitment, KzgProof}; use kzg::{BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT, Kzg, KzgCommitment, KzgProof};
use merkle_proof::{MerkleTreeError, merkle_root_from_branch, verify_merkle_proof}; use merkle_proof::{MerkleTreeError, merkle_root_from_branch, verify_merkle_proof};
use rand::Rng; use rand::Rng;
use safe_arith::ArithError; use safe_arith::ArithError;
@@ -253,14 +253,17 @@ impl<E: EthSpec> BlobSidecar<E> {
let blob = Blob::<E>::new(blob_bytes) let blob = Blob::<E>::new(blob_bytes)
.map_err(|e| format!("error constructing random blob: {:?}", e))?; .map_err(|e| format!("error constructing random blob: {:?}", e))?;
let kzg_blob = KzgBlob::from_bytes(&blob).unwrap(); let kzg_blob: &[u8; BYTES_PER_BLOB] = blob
.as_ref()
.try_into()
.map_err(|e| format!("error converting blob to kzg blob ref: {:?}", e))?;
let commitment = kzg let commitment = kzg
.blob_to_kzg_commitment(&kzg_blob) .blob_to_kzg_commitment(kzg_blob)
.map_err(|e| format!("error computing kzg commitment: {:?}", e))?; .map_err(|e| format!("error computing kzg commitment: {:?}", e))?;
let proof = kzg let proof = kzg
.compute_blob_kzg_proof(&kzg_blob, commitment) .compute_blob_kzg_proof(kzg_blob, commitment)
.map_err(|e| format!("error computing kzg proof: {:?}", e))?; .map_err(|e| format!("error computing kzg proof: {:?}", e))?;
Ok(Self { Ok(Self {

View File

@@ -1,6 +1,6 @@
pub mod consts; pub mod consts;
pub use kzg::{Blob as KzgBlob, Error as KzgError, Kzg, KzgCommitment, KzgProof}; pub use kzg::{Error as KzgError, Kzg, KzgCommitment, KzgProof};
use ssz_types::VariableList; use ssz_types::VariableList;

View File

@@ -12,7 +12,6 @@ fake_crypto = []
[dependencies] [dependencies]
arbitrary = { workspace = true, optional = true } arbitrary = { workspace = true, optional = true }
c-kzg = { workspace = true }
educe = { workspace = true } educe = { workspace = true }
ethereum_hashing = { workspace = true } ethereum_hashing = { workspace = true }
ethereum_serde_utils = { workspace = true } ethereum_serde_utils = { workspace = true }
@@ -28,7 +27,6 @@ tree_hash = { workspace = true }
[dev-dependencies] [dev-dependencies]
criterion = { workspace = true } criterion = { workspace = true }
serde_json = { workspace = true }
[[bench]] [[bench]]
name = "benchmark" name = "benchmark"

View File

@@ -1,6 +1,5 @@
use c_kzg::KzgSettings;
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use kzg::{trusted_setup::get_trusted_setup, TrustedSetup, NO_PRECOMPUTE}; use kzg::trusted_setup::get_trusted_setup;
use rust_eth_kzg::{DASContext, TrustedSetup as PeerDASTrustedSetup}; use rust_eth_kzg::{DASContext, TrustedSetup as PeerDASTrustedSetup};
pub fn bench_init_context(c: &mut Criterion) { pub fn bench_init_context(c: &mut Criterion) {
@@ -20,21 +19,6 @@ pub fn bench_init_context(c: &mut Criterion) {
) )
}) })
}); });
c.bench_function("Initialize context c-kzg (4844)", |b| {
b.iter(|| {
let trusted_setup: TrustedSetup =
serde_json::from_reader(trusted_setup_bytes.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_monomial(),
&trusted_setup.g1_lagrange(),
&trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)
.unwrap()
})
});
} }
criterion_group!(benches, bench_init_context); criterion_group!(benches, bench_init_context);

View File

@@ -1,4 +1,4 @@
use c_kzg::BYTES_PER_COMMITMENT; use crate::{Bytes48, BYTES_PER_COMMITMENT};
use educe::Educe; use educe::Educe;
use ethereum_hashing::hash_fixed; use ethereum_hashing::hash_fixed;
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
@@ -14,7 +14,7 @@ pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
#[derive(Educe, Clone, Copy, Encode, Decode)] #[derive(Educe, Clone, Copy, Encode, Decode)]
#[educe(PartialEq, Eq, Hash)] #[educe(PartialEq, Eq, Hash)]
#[ssz(struct_behaviour = "transparent")] #[ssz(struct_behaviour = "transparent")]
pub struct KzgCommitment(pub [u8; c_kzg::BYTES_PER_COMMITMENT]); pub struct KzgCommitment(pub [u8; BYTES_PER_COMMITMENT]);
impl KzgCommitment { impl KzgCommitment {
pub fn calculate_versioned_hash(&self) -> Hash256 { pub fn calculate_versioned_hash(&self) -> Hash256 {
@@ -24,13 +24,13 @@ impl KzgCommitment {
} }
pub fn empty_for_testing() -> Self { pub fn empty_for_testing() -> Self {
KzgCommitment([0; c_kzg::BYTES_PER_COMMITMENT]) KzgCommitment([0; BYTES_PER_COMMITMENT])
} }
} }
impl From<KzgCommitment> for c_kzg::Bytes48 { impl From<KzgCommitment> for Bytes48 {
fn from(value: KzgCommitment) -> Self { fn from(value: KzgCommitment) -> Self {
value.0.into() value.0
} }
} }

View File

@@ -1,4 +1,4 @@
use c_kzg::BYTES_PER_PROOF; use crate::BYTES_PER_PROOF;
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
@@ -11,12 +11,6 @@ use tree_hash::{PackedEncoding, TreeHash};
#[ssz(struct_behaviour = "transparent")] #[ssz(struct_behaviour = "transparent")]
pub struct KzgProof(pub [u8; BYTES_PER_PROOF]); pub struct KzgProof(pub [u8; BYTES_PER_PROOF]);
impl From<KzgProof> for c_kzg::Bytes48 {
fn from(value: KzgProof) -> Self {
value.0.into()
}
}
impl KzgProof { impl KzgProof {
/// Creates a valid proof using `G1_POINT_AT_INFINITY`. /// Creates a valid proof using `G1_POINT_AT_INFINITY`.
pub fn empty() -> Self { pub fn empty() -> Self {

View File

@@ -12,11 +12,12 @@ pub use crate::{
trusted_setup::TrustedSetup, trusted_setup::TrustedSetup,
}; };
pub use c_kzg::{ pub use rust_eth_kzg::constants::{
Blob, Bytes32, Bytes48, KzgSettings, BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB,
BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, FIELD_ELEMENTS_PER_BLOB,
}; };
pub const BYTES_PER_PROOF: usize = 48;
use crate::trusted_setup::load_trusted_setup; use crate::trusted_setup::load_trusted_setup;
use rayon::prelude::*; use rayon::prelude::*;
pub use rust_eth_kzg::{ pub use rust_eth_kzg::{
@@ -25,13 +26,6 @@ pub use rust_eth_kzg::{
}; };
use tracing::{instrument, Span}; use tracing::{instrument, Span};
/// 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: Both `NUMBER_OF_COLUMNS` and `CELLS_PER_EXT_BLOB` are preset values - however this // Note: Both `NUMBER_OF_COLUMNS` and `CELLS_PER_EXT_BLOB` are preset values - however this
// is a constant in the KZG library - be aware that overriding `NUMBER_OF_COLUMNS` will break KZG // is a constant in the KZG library - be aware that overriding `NUMBER_OF_COLUMNS` will break KZG
// operations. // operations.
@@ -39,14 +33,15 @@ pub type CellsAndKzgProofs = ([Cell; CELLS_PER_EXT_BLOB], [KzgProof; CELLS_PER_E
pub type KzgBlobRef<'a> = &'a [u8; BYTES_PER_BLOB]; pub type KzgBlobRef<'a> = &'a [u8; BYTES_PER_BLOB];
type Bytes32 = [u8; 32];
type Bytes48 = [u8; 48];
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// An error from initialising the trusted setup. /// An error from initialising the trusted setup.
TrustedSetupError(String), TrustedSetupError(String),
/// An error from the underlying kzg library. /// An error from the rust-eth-kzg library.
Kzg(c_kzg::Error), Kzg(rust_eth_kzg::Error),
/// A prover/verifier error from the rust-eth-kzg library.
PeerDASKZG(rust_eth_kzg::Error),
/// The kzg verification failed /// The kzg verification failed
KzgVerificationFailed, KzgVerificationFailed,
/// Misc indexing error /// Misc indexing error
@@ -57,38 +52,29 @@ pub enum Error {
DASContextUninitialized, DASContextUninitialized,
} }
impl From<c_kzg::Error> for Error { impl From<rust_eth_kzg::Error> for Error {
fn from(value: c_kzg::Error) -> Self { fn from(value: rust_eth_kzg::Error) -> Self {
Error::Kzg(value) Error::Kzg(value)
} }
} }
/// A wrapper over a kzg library that holds the trusted setup parameters. /// A wrapper over the rust-eth-kzg library that holds the trusted setup parameters.
#[derive(Debug)] #[derive(Debug)]
pub struct Kzg { pub struct Kzg {
trusted_setup: KzgSettings,
context: DASContext, context: DASContext,
} }
impl Kzg { impl Kzg {
pub fn new_from_trusted_setup_no_precomp(trusted_setup: &[u8]) -> Result<Self, Error> { pub fn new_from_trusted_setup_no_precomp(trusted_setup: &[u8]) -> Result<Self, Error> {
let (ckzg_trusted_setup, rkzg_trusted_setup) = load_trusted_setup(trusted_setup)?; let rkzg_trusted_setup = load_trusted_setup(trusted_setup)?;
let context = DASContext::new(&rkzg_trusted_setup, rust_eth_kzg::UsePrecomp::No); let context = DASContext::new(&rkzg_trusted_setup, rust_eth_kzg::UsePrecomp::No);
Ok(Self { Ok(Self { context })
trusted_setup: KzgSettings::load_trusted_setup(
&ckzg_trusted_setup.g1_monomial(),
&ckzg_trusted_setup.g1_lagrange(),
&ckzg_trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)?,
context,
})
} }
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points. /// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
pub fn new_from_trusted_setup(trusted_setup: &[u8]) -> Result<Self, Error> { pub fn new_from_trusted_setup(trusted_setup: &[u8]) -> Result<Self, Error> {
let (ckzg_trusted_setup, rkzg_trusted_setup) = load_trusted_setup(trusted_setup)?; let rkzg_trusted_setup = load_trusted_setup(trusted_setup)?;
// It's not recommended to change the config parameter for precomputation as storage // It's not recommended to change the config parameter for precomputation as storage
// grows exponentially, but the speedup is exponential - after a while the speedup // grows exponentially, but the speedup is exponential - after a while the speedup
@@ -100,15 +86,7 @@ impl Kzg {
}, },
); );
Ok(Self { Ok(Self { context })
trusted_setup: KzgSettings::load_trusted_setup(
&ckzg_trusted_setup.g1_monomial(),
&ckzg_trusted_setup.g1_lagrange(),
&ckzg_trusted_setup.g2_monomial(),
NO_PRECOMPUTE,
)?,
context,
})
} }
fn context(&self) -> &DASContext { fn context(&self) -> &DASContext {
@@ -118,34 +96,35 @@ impl Kzg {
/// Compute the kzg proof given a blob and its kzg commitment. /// Compute the kzg proof given a blob and its kzg commitment.
pub fn compute_blob_kzg_proof( pub fn compute_blob_kzg_proof(
&self, &self,
blob: &Blob, blob: KzgBlobRef<'_>,
kzg_commitment: KzgCommitment, kzg_commitment: KzgCommitment,
) -> Result<KzgProof, Error> { ) -> Result<KzgProof, Error> {
self.trusted_setup let proof = self
.compute_blob_kzg_proof(blob, &kzg_commitment.into()) .context()
.map(|proof| KzgProof(proof.to_bytes().into_inner())) .compute_blob_kzg_proof(blob, &kzg_commitment.0)
.map_err(Into::into) .map_err(Error::Kzg)?;
Ok(KzgProof(proof))
} }
/// Verify a kzg proof given the blob, kzg commitment and kzg proof. /// Verify a kzg proof given the blob, kzg commitment and kzg proof.
pub fn verify_blob_kzg_proof( pub fn verify_blob_kzg_proof(
&self, &self,
blob: &Blob, blob: KzgBlobRef<'_>,
kzg_commitment: KzgCommitment, kzg_commitment: KzgCommitment,
kzg_proof: KzgProof, kzg_proof: KzgProof,
) -> Result<(), Error> { ) -> Result<(), Error> {
if cfg!(feature = "fake_crypto") { if cfg!(feature = "fake_crypto") {
return Ok(()); return Ok(());
} }
if !self.trusted_setup.verify_blob_kzg_proof( self.context()
blob, .verify_blob_kzg_proof(blob, &kzg_commitment.0, &kzg_proof.0)
&kzg_commitment.into(), .map_err(|e| {
&kzg_proof.into(), if e.is_proof_invalid() {
)? { Error::KzgVerificationFailed
Err(Error::KzgVerificationFailed) } else {
} else { Error::Kzg(e)
Ok(()) }
} })
} }
/// Verify a batch of blob commitment proof triplets. /// Verify a batch of blob commitment proof triplets.
@@ -154,52 +133,48 @@ impl Kzg {
/// TODO(pawan): test performance against a parallelized rayon impl. /// TODO(pawan): test performance against a parallelized rayon impl.
pub fn verify_blob_kzg_proof_batch( pub fn verify_blob_kzg_proof_batch(
&self, &self,
blobs: &[Blob], blobs: &[KzgBlobRef<'_>],
kzg_commitments: &[KzgCommitment], kzg_commitments: &[KzgCommitment],
kzg_proofs: &[KzgProof], kzg_proofs: &[KzgProof],
) -> Result<(), Error> { ) -> Result<(), Error> {
if cfg!(feature = "fake_crypto") { if cfg!(feature = "fake_crypto") {
return Ok(()); return Ok(());
} }
let commitments_bytes = kzg_commitments let blob_refs: Vec<&[u8; BYTES_PER_BLOB]> = blobs.to_vec();
.iter() let commitment_refs: Vec<&[u8; 48]> = kzg_commitments.iter().map(|c| &c.0).collect();
.map(|comm| Bytes48::from(*comm)) let proof_refs: Vec<&[u8; 48]> = kzg_proofs.iter().map(|p| &p.0).collect();
.collect::<Vec<_>>();
let proofs_bytes = kzg_proofs self.context()
.iter() .verify_blob_kzg_proof_batch(blob_refs, commitment_refs, proof_refs)
.map(|proof| Bytes48::from(*proof)) .map_err(|e| {
.collect::<Vec<_>>(); if e.is_proof_invalid() {
Error::KzgVerificationFailed
if !self.trusted_setup.verify_blob_kzg_proof_batch( } else {
blobs, Error::Kzg(e)
&commitments_bytes, }
&proofs_bytes, })
)? {
Err(Error::KzgVerificationFailed)
} else {
Ok(())
}
} }
/// Converts a blob to a kzg commitment. /// Converts a blob to a kzg commitment.
pub fn blob_to_kzg_commitment(&self, blob: &Blob) -> Result<KzgCommitment, Error> { pub fn blob_to_kzg_commitment(&self, blob: KzgBlobRef<'_>) -> Result<KzgCommitment, Error> {
self.trusted_setup let commitment = self
.context()
.blob_to_kzg_commitment(blob) .blob_to_kzg_commitment(blob)
.map(|commitment| KzgCommitment(commitment.to_bytes().into_inner())) .map_err(Error::Kzg)?;
.map_err(Into::into) Ok(KzgCommitment(commitment))
} }
/// Computes the kzg proof for a given `blob` and an evaluation point `z` /// Computes the kzg proof for a given `blob` and an evaluation point `z`
pub fn compute_kzg_proof( pub fn compute_kzg_proof(
&self, &self,
blob: &Blob, blob: KzgBlobRef<'_>,
z: &Bytes32, z: &Bytes32,
) -> Result<(KzgProof, Bytes32), Error> { ) -> Result<(KzgProof, Bytes32), Error> {
self.trusted_setup let (proof, y) = self
.compute_kzg_proof(blob, z) .context()
.map(|(proof, y)| (KzgProof(proof.to_bytes().into_inner()), y)) .compute_kzg_proof(blob, *z)
.map_err(Into::into) .map_err(Error::Kzg)?;
Ok((KzgProof(proof), y))
} }
/// Verifies a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y` /// Verifies a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y`
@@ -213,9 +188,14 @@ impl Kzg {
if cfg!(feature = "fake_crypto") { if cfg!(feature = "fake_crypto") {
return Ok(true); return Ok(true);
} }
self.trusted_setup match self
.verify_kzg_proof(&kzg_commitment.into(), z, y, &kzg_proof.into()) .context()
.map_err(Into::into) .verify_kzg_proof(&kzg_commitment.0, *z, *y, &kzg_proof.0)
{
Ok(()) => Ok(true),
Err(e) if e.is_proof_invalid() => Ok(false),
Err(e) => Err(Error::Kzg(e)),
}
} }
/// Computes the cells and associated proofs for a given `blob`. /// Computes the cells and associated proofs for a given `blob`.
@@ -226,18 +206,15 @@ impl Kzg {
let (cells, proofs) = self let (cells, proofs) = self
.context() .context()
.compute_cells_and_kzg_proofs(blob) .compute_cells_and_kzg_proofs(blob)
.map_err(Error::PeerDASKZG)?; .map_err(Error::Kzg)?;
// Convert the proof type to a c-kzg proof type let kzg_proofs = proofs.map(KzgProof);
let c_kzg_proof = proofs.map(KzgProof); Ok((cells, kzg_proofs))
Ok((cells, c_kzg_proof))
} }
/// Computes the cells for a given `blob`. /// Computes the cells for a given `blob`.
pub fn compute_cells(&self, blob: KzgBlobRef<'_>) -> Result<[Cell; CELLS_PER_EXT_BLOB], Error> { pub fn compute_cells(&self, blob: KzgBlobRef<'_>) -> Result<[Cell; CELLS_PER_EXT_BLOB], Error> {
self.context() self.context().compute_cells(blob).map_err(Error::Kzg)
.compute_cells(blob)
.map_err(Error::PeerDASKZG)
} }
/// Verifies a batch of cell-proof-commitment triplets. /// Verifies a batch of cell-proof-commitment triplets.
@@ -291,8 +268,8 @@ impl Kzg {
for (cell, proof, commitment) in &column_data { for (cell, proof, commitment) in &column_data {
cells.push(*cell); cells.push(*cell);
proofs.push(proof.as_ref()); proofs.push(proof);
commitments.push(commitment.as_ref()); commitments.push(commitment);
} }
// Create per-chunk tracing span for visualizing parallel processing. // Create per-chunk tracing span for visualizing parallel processing.
@@ -319,7 +296,7 @@ impl Kzg {
Err(e) if e.is_proof_invalid() => { Err(e) if e.is_proof_invalid() => {
Err((Some(column_index), Error::KzgVerificationFailed)) Err((Some(column_index), Error::KzgVerificationFailed))
} }
Err(e) => Err((Some(column_index), Error::PeerDASKZG(e))), Err(e) => Err((Some(column_index), Error::Kzg(e))),
} }
}) })
.collect::<Result<Vec<()>, (Option<u64>, Error)>>()?; .collect::<Result<Vec<()>, (Option<u64>, Error)>>()?;
@@ -335,10 +312,9 @@ impl Kzg {
let (cells, proofs) = self let (cells, proofs) = self
.context() .context()
.recover_cells_and_kzg_proofs(cell_ids.to_vec(), cells.to_vec()) .recover_cells_and_kzg_proofs(cell_ids.to_vec(), cells.to_vec())
.map_err(Error::PeerDASKZG)?; .map_err(Error::Kzg)?;
// Convert the proof type to a c-kzg proof type let kzg_proofs = proofs.map(KzgProof);
let c_kzg_proof = proofs.map(KzgProof); Ok((cells, kzg_proofs))
Ok((cells, c_kzg_proof))
} }
} }

View File

@@ -24,7 +24,7 @@ struct G1Point([u8; BYTES_PER_G1_POINT]);
struct G2Point([u8; BYTES_PER_G2_POINT]); struct G2Point([u8; BYTES_PER_G2_POINT]);
/// Contains the trusted setup parameters that are required to instantiate a /// Contains the trusted setup parameters that are required to instantiate a
/// `c_kzg::KzgSettings` object. /// `rust_eth_kzg::TrustedSetup` object.
/// ///
/// The serialize/deserialize implementations are written according to /// The serialize/deserialize implementations are written according to
/// the format specified in the ethereum consensus specs trusted setup files. /// the format specified in the ethereum consensus specs trusted setup files.
@@ -155,19 +155,9 @@ fn strip_prefix(s: &str) -> &str {
} }
} }
/// Loads the trusted setup from JSON. /// Loads the trusted setup from JSON bytes into a `rust_eth_kzg::TrustedSetup`.
/// pub(crate) fn load_trusted_setup(trusted_setup: &[u8]) -> Result<PeerDASTrustedSetup, Error> {
/// ## Note:
/// Currently we load both c-kzg and rust-eth-kzg trusted setup structs, because c-kzg is still being
/// used for 4844. Longer term we're planning to switch all KZG operations to the rust-eth-kzg
/// crate, and we'll be able to maintain a single trusted setup struct.
pub(crate) fn load_trusted_setup(
trusted_setup: &[u8],
) -> Result<(TrustedSetup, PeerDASTrustedSetup), Error> {
let ckzg_trusted_setup: TrustedSetup = serde_json::from_slice(trusted_setup)
.map_err(|e| Error::TrustedSetupError(format!("{e:?}")))?;
let trusted_setup_json = std::str::from_utf8(trusted_setup) let trusted_setup_json = std::str::from_utf8(trusted_setup)
.map_err(|e| Error::TrustedSetupError(format!("{e:?}")))?; .map_err(|e| Error::TrustedSetupError(format!("{e:?}")))?;
let rkzg_trusted_setup = PeerDASTrustedSetup::from_json(trusted_setup_json); Ok(PeerDASTrustedSetup::from_json(trusted_setup_json))
Ok((ckzg_trusted_setup, rkzg_trusted_setup))
} }

View File

@@ -11,6 +11,7 @@ deny = [
{ crate = "derivative", reason = "use educe or derive_more instead" }, { crate = "derivative", reason = "use educe or derive_more instead" },
{ crate = "ark-ff", reason = "present in Cargo.lock but not needed by Lighthouse" }, { crate = "ark-ff", reason = "present in Cargo.lock but not needed by Lighthouse" },
{ crate = "openssl", reason = "non-Rust dependency, use rustls instead" }, { crate = "openssl", reason = "non-Rust dependency, use rustls instead" },
{ crate = "c-kzg", reason = "non-Rust dependency, use rust_eth_kzg instead" },
{ crate = "strum", deny-multiple-versions = true, reason = "takes a long time to compile" }, { crate = "strum", deny-multiple-versions = true, reason = "takes a long time to compile" },
{ crate = "reqwest", deny-multiple-versions = true, reason = "takes a long time to compile" }, { crate = "reqwest", deny-multiple-versions = true, reason = "takes a long time to compile" },
{ crate = "aes", deny-multiple-versions = true, reason = "takes a long time to compile" }, { crate = "aes", deny-multiple-versions = true, reason = "takes a long time to compile" },

View File

@@ -1,6 +1,6 @@
use super::*; use super::*;
use crate::case_result::compare_result; use crate::case_result::compare_result;
use kzg::{Bytes48, Error as KzgError}; use kzg::Error as KzgError;
use serde::Deserialize; use serde::Deserialize;
use std::marker::PhantomData; use std::marker::PhantomData;
@@ -47,8 +47,8 @@ impl<E: EthSpec> Case for KZGVerifyCellKZGProofBatch<E> {
let result = let result =
parse_input(&self.input).and_then(|(cells, proofs, cell_indices, commitments)| { parse_input(&self.input).and_then(|(cells, proofs, cell_indices, commitments)| {
let proofs: Vec<Bytes48> = proofs.iter().map(|&proof| proof.into()).collect(); let proofs = proofs.iter().map(|&proof| proof.0).collect::<Vec<_>>();
let commitments: Vec<Bytes48> = commitments.iter().map(|&c| c.into()).collect(); let commitments = commitments.iter().map(|&c| c.0).collect::<Vec<_>>();
let cells = cells.iter().map(|c| c.as_ref()).collect::<Vec<_>>(); let cells = cells.iter().map(|c| c.as_ref()).collect::<Vec<_>>();
let kzg = get_kzg(); let kzg = get_kzg();
match kzg.verify_cell_proof_batch(&cells, &proofs, cell_indices, &commitments) { match kzg.verify_cell_proof_batch(&cells, &proofs, cell_indices, &commitments) {