mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Upgrade to v1.4.0-beta.3 (#4862)
## Issue Addressed Makes lighthouse compliant with new kzg changes in https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0-beta.3 ## Proposed Changes 1. Adds new official trusted setup 2. Refactors kzg to match upstream changes in https://github.com/ethereum/c-kzg-4844/pull/377 3. Updates pre-generated `BlobBundle` to work with official trusted setup. ~~Using json here instead of ssz to account for different value of `MaxBlobCommitmentsPerBlock` in minimal and mainnet. By using json, we can just use one pre generated bundle for both minimal and mainnet. Size of 2 separate ssz bundles is approximately equal to one json bundle cc @jimmygchen~~ Dunno what I was doing, ssz works without any issues 4. Stores trusted_setup as just bytes in eth2_network_config so that we don't have kzg dependency in that lib and in lcli. Co-authored-by: realbigsean <seananderson33@gmail.com> Co-authored-by: realbigsean <seananderson33@GMAIL.com>
This commit is contained in:
@@ -16,10 +16,4 @@ serde = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
ethereum_hashing = { workspace = true }
|
||||
c-kzg = { git = "https://github.com/ethereum/c-kzg-4844", rev = "f5f6f863d475847876a2bd5ee252058d37c3a15d" , features = ["mainnet-spec", "serde"]}
|
||||
c_kzg_min = { package = "c-kzg", git = "https://github.com/ethereum//c-kzg-4844", rev = "f5f6f863d475847876a2bd5ee252058d37c3a15d", features = ["minimal-spec", "serde"], optional = true }
|
||||
|
||||
[features]
|
||||
# TODO(deneb): enabled by default for convenience, would need more cfg magic to disable
|
||||
default = ["c_kzg_min"]
|
||||
minimal-spec = ["c_kzg_min"]
|
||||
c-kzg = { git = "https://github.com/ethereum/c-kzg-4844", rev = "748283cced543c486145d5f3f38684becdfe3e1b"}
|
||||
@@ -34,12 +34,6 @@ impl From<KzgCommitment> for c_kzg::Bytes48 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KzgCommitment> for c_kzg_min::Bytes48 {
|
||||
fn from(value: KzgCommitment) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for KzgCommitment {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", serde_utils::hex::encode(self.0))
|
||||
|
||||
@@ -17,12 +17,6 @@ impl From<KzgProof> for c_kzg::Bytes48 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KzgProof> for c_kzg_min::Bytes48 {
|
||||
fn from(value: KzgProof) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl KzgProof {
|
||||
/// Creates a valid proof using `G1_POINT_AT_INFINITY`.
|
||||
pub fn empty() -> Self {
|
||||
|
||||
@@ -2,297 +2,54 @@ mod kzg_commitment;
|
||||
mod kzg_proof;
|
||||
mod trusted_setup;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use crate::{kzg_commitment::KzgCommitment, kzg_proof::KzgProof, trusted_setup::TrustedSetup};
|
||||
pub use c_kzg::{Bytes32, Bytes48, BYTES_PER_COMMITMENT, BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
InvalidTrustedSetup(CryptoError),
|
||||
InvalidKzgProof(CryptoError),
|
||||
InvalidBytes(CryptoError),
|
||||
KzgProofComputationFailed(CryptoError),
|
||||
InvalidBlob(CryptoError),
|
||||
InvalidBytesForBlob(CryptoError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CryptoError {
|
||||
CKzg(c_kzg::Error),
|
||||
CKzgMin(c_kzg_min::Error),
|
||||
/// Trusted setup is for the incorrect kzg preset.
|
||||
InconsistentTrustedSetup,
|
||||
}
|
||||
|
||||
impl From<c_kzg::Error> for CryptoError {
|
||||
fn from(e: c_kzg::Error) -> Self {
|
||||
Self::CKzg(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c_kzg_min::Error> for CryptoError {
|
||||
fn from(e: c_kzg_min::Error) -> Self {
|
||||
Self::CKzgMin(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BlobTrait: Sized + Clone {
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
pub enum KzgPresetId {
|
||||
Mainnet,
|
||||
Minimal,
|
||||
}
|
||||
|
||||
impl FromStr for KzgPresetId {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"mainnet" => Ok(KzgPresetId::Mainnet),
|
||||
"minimal" => Ok(KzgPresetId::Minimal),
|
||||
_ => Err(format!("Unknown eth spec: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait KzgPreset:
|
||||
'static + Default + Sync + Send + Clone + Debug + PartialEq + Eq + for<'a> arbitrary::Arbitrary<'a>
|
||||
{
|
||||
type KzgSettings: Debug + Sync + Send;
|
||||
type Blob: BlobTrait;
|
||||
type Bytes32: From<[u8; 32]> + Deref<Target = [u8; 32]>;
|
||||
type Bytes48: From<KzgCommitment> + From<KzgProof>;
|
||||
type Error: Into<CryptoError>;
|
||||
|
||||
const BYTES_PER_BLOB: usize;
|
||||
const FIELD_ELEMENTS_PER_BLOB: usize;
|
||||
|
||||
fn spec_name() -> KzgPresetId;
|
||||
|
||||
fn bytes32_in(bytes: Bytes32) -> Self::Bytes32 {
|
||||
let bytes: [u8; 32] = *bytes;
|
||||
Self::Bytes32::from(bytes)
|
||||
}
|
||||
|
||||
fn bytes32_out(bytes: Self::Bytes32) -> Bytes32 {
|
||||
let bytes: [u8; 32] = *bytes;
|
||||
Bytes32::from(bytes)
|
||||
}
|
||||
|
||||
fn load_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self::KzgSettings, CryptoError>;
|
||||
|
||||
fn compute_blob_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<KzgProof, CryptoError>;
|
||||
|
||||
fn verify_blob_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
kzg_proof: KzgProof,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError>;
|
||||
|
||||
fn verify_blob_kzg_proof_batch(
|
||||
blobs: &[Self::Blob],
|
||||
commitments_bytes: &[Self::Bytes48],
|
||||
proofs_bytes: &[Self::Bytes48],
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError>;
|
||||
|
||||
fn blob_to_kzg_commitment(
|
||||
blob: &Self::Blob,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<KzgCommitment, CryptoError>;
|
||||
|
||||
fn compute_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
z: &Self::Bytes32,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<(KzgProof, Self::Bytes32), CryptoError>;
|
||||
|
||||
fn verify_kzg_proof(
|
||||
kzg_commitment: KzgCommitment,
|
||||
z: &Self::Bytes32,
|
||||
y: &Self::Bytes32,
|
||||
kzg_proof: KzgProof,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError>;
|
||||
}
|
||||
|
||||
macro_rules! implement_kzg_preset {
|
||||
($preset_type:ident, $module_name:ident, $preset_id:ident) => {
|
||||
impl KzgPreset for $preset_type {
|
||||
type KzgSettings = $module_name::KzgSettings;
|
||||
type Blob = $module_name::Blob;
|
||||
type Bytes32 = $module_name::Bytes32;
|
||||
type Bytes48 = $module_name::Bytes48;
|
||||
type Error = $module_name::Error;
|
||||
|
||||
const BYTES_PER_BLOB: usize = $module_name::BYTES_PER_BLOB;
|
||||
const FIELD_ELEMENTS_PER_BLOB: usize = $module_name::FIELD_ELEMENTS_PER_BLOB;
|
||||
|
||||
fn spec_name() -> KzgPresetId {
|
||||
KzgPresetId::$preset_id
|
||||
}
|
||||
|
||||
fn load_trusted_setup(
|
||||
trusted_setup: TrustedSetup,
|
||||
) -> Result<Self::KzgSettings, CryptoError> {
|
||||
if trusted_setup.g1_len() != Self::FIELD_ELEMENTS_PER_BLOB {
|
||||
return Err(CryptoError::InconsistentTrustedSetup);
|
||||
}
|
||||
$module_name::KzgSettings::load_trusted_setup(
|
||||
&trusted_setup.g1_points(),
|
||||
&trusted_setup.g2_points(),
|
||||
)
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn compute_blob_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<KzgProof, CryptoError> {
|
||||
$module_name::KzgProof::compute_blob_kzg_proof(
|
||||
blob,
|
||||
&kzg_commitment.into(),
|
||||
trusted_setup,
|
||||
)
|
||||
.map(|proof| KzgProof(proof.to_bytes().into_inner()))
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn verify_blob_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
kzg_proof: KzgProof,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError> {
|
||||
$module_name::KzgProof::verify_blob_kzg_proof(
|
||||
blob,
|
||||
&kzg_commitment.into(),
|
||||
&kzg_proof.into(),
|
||||
trusted_setup,
|
||||
)
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn verify_blob_kzg_proof_batch(
|
||||
blobs: &[Self::Blob],
|
||||
commitments_bytes: &[Self::Bytes48],
|
||||
proofs_bytes: &[Self::Bytes48],
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError> {
|
||||
$module_name::KzgProof::verify_blob_kzg_proof_batch(
|
||||
blobs,
|
||||
commitments_bytes,
|
||||
proofs_bytes,
|
||||
trusted_setup,
|
||||
)
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn blob_to_kzg_commitment(
|
||||
blob: &Self::Blob,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<KzgCommitment, CryptoError> {
|
||||
$module_name::KzgCommitment::blob_to_kzg_commitment(blob, trusted_setup)
|
||||
.map(|com| KzgCommitment(com.to_bytes().into_inner()))
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn compute_kzg_proof(
|
||||
blob: &Self::Blob,
|
||||
z: &Self::Bytes32,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<(KzgProof, Self::Bytes32), CryptoError> {
|
||||
$module_name::KzgProof::compute_kzg_proof(blob, z, trusted_setup)
|
||||
.map(|(proof, y)| (KzgProof(proof.to_bytes().into_inner()), y))
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
fn verify_kzg_proof(
|
||||
kzg_commitment: KzgCommitment,
|
||||
z: &Self::Bytes32,
|
||||
y: &Self::Bytes32,
|
||||
kzg_proof: KzgProof,
|
||||
trusted_setup: &Self::KzgSettings,
|
||||
) -> Result<bool, CryptoError> {
|
||||
$module_name::KzgProof::verify_kzg_proof(
|
||||
&kzg_commitment.into(),
|
||||
z,
|
||||
y,
|
||||
&kzg_proof.into(),
|
||||
trusted_setup,
|
||||
)
|
||||
.map_err(CryptoError::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl BlobTrait for $module_name::Blob {
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
|
||||
Self::from_bytes(bytes)
|
||||
.map_err(CryptoError::from)
|
||||
.map_err(Error::InvalidBlob)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
pub struct MainnetKzgPreset;
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
pub struct MinimalKzgPreset;
|
||||
|
||||
implement_kzg_preset!(MainnetKzgPreset, c_kzg, Mainnet);
|
||||
implement_kzg_preset!(MinimalKzgPreset, c_kzg_min, Minimal);
|
||||
pub use c_kzg::{
|
||||
Blob, Bytes32, Bytes48, Error, KzgSettings, BYTES_PER_BLOB, BYTES_PER_COMMITMENT,
|
||||
BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, FIELD_ELEMENTS_PER_BLOB,
|
||||
};
|
||||
|
||||
/// A wrapper over a kzg library that holds the trusted setup parameters.
|
||||
#[derive(Debug)]
|
||||
pub struct Kzg<P: KzgPreset> {
|
||||
trusted_setup: P::KzgSettings,
|
||||
pub struct Kzg {
|
||||
trusted_setup: KzgSettings,
|
||||
}
|
||||
|
||||
impl<P: KzgPreset> Kzg<P> {
|
||||
impl Kzg {
|
||||
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
|
||||
///
|
||||
/// The number of G1 points should be equal to FIELD_ELEMENTS_PER_BLOB
|
||||
/// Note: this number changes based on the preset values.
|
||||
/// The number of G2 points should be equal to 65.
|
||||
pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
trusted_setup: P::load_trusted_setup(trusted_setup)
|
||||
.map_err(Error::InvalidTrustedSetup)?,
|
||||
trusted_setup: KzgSettings::load_trusted_setup(
|
||||
&trusted_setup.g1_points(),
|
||||
&trusted_setup.g2_points(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute the kzg proof given a blob and its kzg commitment.
|
||||
pub fn compute_blob_kzg_proof(
|
||||
&self,
|
||||
blob: &P::Blob,
|
||||
blob: &Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
) -> Result<KzgProof, Error> {
|
||||
P::compute_blob_kzg_proof(blob, kzg_commitment, &self.trusted_setup)
|
||||
.map_err(Error::KzgProofComputationFailed)
|
||||
c_kzg::KzgProof::compute_blob_kzg_proof(blob, &kzg_commitment.into(), &self.trusted_setup)
|
||||
.map(|proof| KzgProof(proof.to_bytes().into_inner()))
|
||||
}
|
||||
|
||||
/// Verify a kzg proof given the blob, kzg commitment and kzg proof.
|
||||
pub fn verify_blob_kzg_proof(
|
||||
&self,
|
||||
blob: &P::Blob,
|
||||
blob: &Blob,
|
||||
kzg_commitment: KzgCommitment,
|
||||
kzg_proof: KzgProof,
|
||||
) -> Result<bool, Error> {
|
||||
P::verify_blob_kzg_proof(blob, kzg_commitment, kzg_proof, &self.trusted_setup)
|
||||
.map_err(Error::InvalidKzgProof)
|
||||
c_kzg::KzgProof::verify_blob_kzg_proof(
|
||||
blob,
|
||||
&kzg_commitment.into(),
|
||||
&kzg_proof.into(),
|
||||
&self.trusted_setup,
|
||||
)
|
||||
}
|
||||
|
||||
/// Verify a batch of blob commitment proof triplets.
|
||||
@@ -301,43 +58,42 @@ impl<P: KzgPreset> Kzg<P> {
|
||||
/// TODO(pawan): test performance against a parallelized rayon impl.
|
||||
pub fn verify_blob_kzg_proof_batch(
|
||||
&self,
|
||||
blobs: &[P::Blob],
|
||||
blobs: &[Blob],
|
||||
kzg_commitments: &[KzgCommitment],
|
||||
kzg_proofs: &[KzgProof],
|
||||
) -> Result<bool, Error> {
|
||||
let commitments_bytes = kzg_commitments
|
||||
.iter()
|
||||
.map(|comm| P::Bytes48::from(*comm))
|
||||
.map(|comm| Bytes48::from(*comm))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let proofs_bytes = kzg_proofs
|
||||
.iter()
|
||||
.map(|proof| P::Bytes48::from(*proof))
|
||||
.map(|proof| Bytes48::from(*proof))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
P::verify_blob_kzg_proof_batch(
|
||||
c_kzg::KzgProof::verify_blob_kzg_proof_batch(
|
||||
blobs,
|
||||
&commitments_bytes,
|
||||
&proofs_bytes,
|
||||
&self.trusted_setup,
|
||||
)
|
||||
.map_err(Error::InvalidKzgProof)
|
||||
}
|
||||
|
||||
/// Converts a blob to a kzg commitment.
|
||||
pub fn blob_to_kzg_commitment(&self, blob: &P::Blob) -> Result<KzgCommitment, Error> {
|
||||
P::blob_to_kzg_commitment(blob, &self.trusted_setup).map_err(Error::InvalidBlob)
|
||||
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()))
|
||||
}
|
||||
|
||||
/// Computes the kzg proof for a given `blob` and an evaluation point `z`
|
||||
pub fn compute_kzg_proof(
|
||||
&self,
|
||||
blob: &P::Blob,
|
||||
blob: &Blob,
|
||||
z: &Bytes32,
|
||||
) -> Result<(KzgProof, Bytes32), Error> {
|
||||
P::compute_kzg_proof(blob, &P::bytes32_in(*z), &self.trusted_setup)
|
||||
.map_err(Error::KzgProofComputationFailed)
|
||||
.map(|(proof, y)| (proof, P::bytes32_out(y)))
|
||||
c_kzg::KzgProof::compute_kzg_proof(blob, z, &self.trusted_setup)
|
||||
.map(|(proof, y)| (KzgProof(proof.to_bytes().into_inner()), y))
|
||||
}
|
||||
|
||||
/// Verifies a `kzg_proof` for a `kzg_commitment` that evaluating a polynomial at `z` results in `y`
|
||||
@@ -348,13 +104,12 @@ impl<P: KzgPreset> Kzg<P> {
|
||||
y: &Bytes32,
|
||||
kzg_proof: KzgProof,
|
||||
) -> Result<bool, Error> {
|
||||
P::verify_kzg_proof(
|
||||
kzg_commitment,
|
||||
&P::bytes32_in(*z),
|
||||
&P::bytes32_in(*y),
|
||||
kzg_proof,
|
||||
c_kzg::KzgProof::verify_kzg_proof(
|
||||
&kzg_commitment.into(),
|
||||
z,
|
||||
y,
|
||||
&kzg_proof.into(),
|
||||
&self.trusted_setup,
|
||||
)
|
||||
.map_err(Error::InvalidKzgProof)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ struct G2Point([u8; BYTES_PER_G2_POINT]);
|
||||
/// The serialize/deserialize implementations are written according to
|
||||
/// the format specified in the the ethereum consensus specs trusted setup files.
|
||||
///
|
||||
/// See https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/trusted_setups/testing_trusted_setups.json
|
||||
/// 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 = "setup_G1_lagrange")]
|
||||
#[serde(rename = "g1_lagrange")]
|
||||
g1_points: Vec<G1Point>,
|
||||
#[serde(rename = "setup_G2")]
|
||||
#[serde(rename = "g2_monomial")]
|
||||
g2_points: Vec<G2Point>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user