Files
lighthouse/crypto/kzg/src/lib.rs
kevaundray 5e9cc60dd7 chore!: Update rust_eth_kzg to v0.5.1 (formally known as peerdas-kzg) (#6309)
* update rust_eth_kzg

Co-authored-by: Eitan Seri-Levi <eserilev@ucsc.edu>

* Update kzg module

Co-authored-by: Eitan Seri-Levi <eserilev@ucsc.edu>

* update benchmark code

Co-authored-by: Eitan Seri-Levi <eserilev@ucsc.edu>

* Add note on trusted setup configuration.
2024-08-28 06:43:14 +00:00

259 lines
8.3 KiB
Rust

mod kzg_commitment;
mod kzg_proof;
mod trusted_setup;
use rust_eth_kzg::{CellIndex, DASContext};
use std::fmt::Debug;
pub use crate::{
kzg_commitment::{KzgCommitment, VERSIONED_HASH_VERSION_KZG},
kzg_proof::KzgProof,
trusted_setup::TrustedSetup,
};
pub use c_kzg::{
Blob, Bytes32, Bytes48, KzgSettings, BYTES_PER_BLOB, BYTES_PER_COMMITMENT,
BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, FIELD_ELEMENTS_PER_BLOB,
};
pub use rust_eth_kzg::{
constants::{BYTES_PER_CELL, CELLS_PER_EXT_BLOB},
Cell, CellIndex as CellID, CellRef, TrustedSetup as PeerDASTrustedSetup,
};
pub type CellsAndKzgProofs = ([Cell; CELLS_PER_EXT_BLOB], [KzgProof; CELLS_PER_EXT_BLOB]);
pub type KzgBlobRef<'a> = &'a [u8; BYTES_PER_BLOB];
#[derive(Debug)]
pub enum Error {
/// An error from the underlying kzg library.
Kzg(c_kzg::Error),
/// A prover/verifier error from the rust-eth-kzg library.
PeerDASKZG(rust_eth_kzg::Error),
/// The kzg verification failed
KzgVerificationFailed,
/// Misc indexing error
InconsistentArrayLength(String),
/// Error reconstructing data columns.
ReconstructFailed(String),
/// Kzg was not initialized with PeerDAS enabled.
DASContextUninitialized,
}
impl From<c_kzg::Error> for Error {
fn from(value: c_kzg::Error) -> Self {
Error::Kzg(value)
}
}
/// A wrapper over a kzg library that holds the trusted setup parameters.
#[derive(Debug)]
pub struct Kzg {
trusted_setup: KzgSettings,
context: Option<DASContext>,
}
impl Kzg {
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self, Error> {
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
)?,
context: None,
})
}
pub fn new_from_trusted_setup_das_enabled(trusted_setup: TrustedSetup) -> Result<Self, Error> {
// Initialize the trusted setup using default parameters
//
// Note: One can also use `from_json` to initialize it from the consensus-specs
// json string.
let peerdas_trusted_setup = PeerDASTrustedSetup::from(&trusted_setup);
// 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
// starts to become sublinear.
let context = DASContext::new(
&peerdas_trusted_setup,
rust_eth_kzg::UsePrecomp::Yes {
width: rust_eth_kzg::constants::RECOMMENDED_PRECOMP_WIDTH,
},
);
Ok(Self {
trusted_setup: KzgSettings::load_trusted_setup(
&trusted_setup.g1_points(),
&trusted_setup.g2_points(),
)?,
context: Some(context),
})
}
fn context(&self) -> Result<&DASContext, Error> {
self.context.as_ref().ok_or(Error::DASContextUninitialized)
}
/// Compute the kzg proof given a blob and its kzg commitment.
pub fn compute_blob_kzg_proof(
&self,
blob: &Blob,
kzg_commitment: KzgCommitment,
) -> Result<KzgProof, Error> {
c_kzg::KzgProof::compute_blob_kzg_proof(blob, &kzg_commitment.into(), &self.trusted_setup)
.map(|proof| KzgProof(proof.to_bytes().into_inner()))
.map_err(Into::into)
}
/// Verify a kzg proof given the blob, kzg commitment and kzg proof.
pub fn verify_blob_kzg_proof(
&self,
blob: &Blob,
kzg_commitment: KzgCommitment,
kzg_proof: KzgProof,
) -> Result<(), Error> {
if !c_kzg::KzgProof::verify_blob_kzg_proof(
blob,
&kzg_commitment.into(),
&kzg_proof.into(),
&self.trusted_setup,
)? {
Err(Error::KzgVerificationFailed)
} else {
Ok(())
}
}
/// Verify a batch of blob commitment proof triplets.
///
/// Note: This method is slightly faster than calling `Self::verify_blob_kzg_proof` in a loop sequentially.
/// TODO(pawan): test performance against a parallelized rayon impl.
pub fn verify_blob_kzg_proof_batch(
&self,
blobs: &[Blob],
kzg_commitments: &[KzgCommitment],
kzg_proofs: &[KzgProof],
) -> Result<(), Error> {
let commitments_bytes = kzg_commitments
.iter()
.map(|comm| Bytes48::from(*comm))
.collect::<Vec<_>>();
let proofs_bytes = kzg_proofs
.iter()
.map(|proof| Bytes48::from(*proof))
.collect::<Vec<_>>();
if !c_kzg::KzgProof::verify_blob_kzg_proof_batch(
blobs,
&commitments_bytes,
&proofs_bytes,
&self.trusted_setup,
)? {
Err(Error::KzgVerificationFailed)
} else {
Ok(())
}
}
/// 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)
.map(|commitment| KzgCommitment(commitment.to_bytes().into_inner()))
.map_err(Into::into)
}
/// Computes the kzg proof for a given `blob` and an evaluation point `z`
pub fn compute_kzg_proof(
&self,
blob: &Blob,
z: &Bytes32,
) -> Result<(KzgProof, Bytes32), Error> {
c_kzg::KzgProof::compute_kzg_proof(blob, z, &self.trusted_setup)
.map(|(proof, y)| (KzgProof(proof.to_bytes().into_inner()), y))
.map_err(Into::into)
}
/// Verifies a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y`
pub fn verify_kzg_proof(
&self,
kzg_commitment: KzgCommitment,
z: &Bytes32,
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)
}
/// Computes the cells and associated proofs for a given `blob` at index `index`.
pub fn compute_cells_and_proofs(
&self,
blob: KzgBlobRef<'_>,
) -> Result<CellsAndKzgProofs, Error> {
let (cells, proofs) = self
.context()?
.compute_cells_and_kzg_proofs(blob)
.map_err(Error::PeerDASKZG)?;
// Convert the proof type to a c-kzg proof type
let c_kzg_proof = proofs.map(KzgProof);
Ok((cells, c_kzg_proof))
}
/// Verifies a batch of cell-proof-commitment triplets.
///
/// Here, `coordinates` correspond to the (row, col) coordinate of the cell in the extended
/// blob "matrix". In the 1D extension, row corresponds to the blob index, and col corresponds
/// to the data column index.
pub fn verify_cell_proof_batch(
&self,
cells: &[CellRef<'_>],
kzg_proofs: &[Bytes48],
columns: Vec<CellIndex>,
kzg_commitments: &[Bytes48],
) -> Result<(), Error> {
let proofs: Vec<_> = kzg_proofs.iter().map(|proof| proof.as_ref()).collect();
let commitments: Vec<_> = kzg_commitments
.iter()
.map(|commitment| commitment.as_ref())
.collect();
let verification_result = self.context()?.verify_cell_kzg_proof_batch(
commitments.to_vec(),
columns,
cells.to_vec(),
proofs.to_vec(),
);
// Modify the result so it matches roughly what the previous method was doing.
match verification_result {
Ok(_) => Ok(()),
Err(e) if e.invalid_proof() => Err(Error::KzgVerificationFailed),
Err(e) => Err(Error::PeerDASKZG(e)),
}
}
pub fn recover_cells_and_compute_kzg_proofs(
&self,
cell_ids: &[u64],
cells: &[CellRef<'_>],
) -> Result<CellsAndKzgProofs, Error> {
let (cells, proofs) = self
.context()?
.recover_cells_and_kzg_proofs(cell_ids.to_vec(), cells.to_vec())
.map_err(Error::PeerDASKZG)?;
// Convert the proof type to a c-kzg proof type
let c_kzg_proof = proofs.map(KzgProof);
Ok((cells, c_kzg_proof))
}
}