Merge remote-tracking branch 'origin/unstable' into tree-states

This commit is contained in:
Michael Sproul
2023-11-12 22:19:07 +03:00
161 changed files with 3635 additions and 2227 deletions

View File

@@ -101,9 +101,8 @@ pub fn verify_signature_sets<'a>(
// Aggregate all the public keys.
// Public keys have already been checked for subgroup and infinity
let agg_pk = match blst_core::AggregatePublicKey::aggregate(&signing_keys, false) {
Ok(agg_pk) => agg_pk,
Err(_) => return false,
let Ok(agg_pk) = blst_core::AggregatePublicKey::aggregate(&signing_keys, false) else {
return false;
};
pks.push(agg_pk.to_public_key());
}

View File

@@ -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"}

View File

@@ -34,15 +34,17 @@ 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))
write!(f, "0x")?;
for i in &self.0[0..2] {
write!(f, "{:02x}", i)?;
}
write!(f, "")?;
for i in &self.0[BYTES_PER_COMMITMENT - 2..BYTES_PER_COMMITMENT] {
write!(f, "{:02x}", i)?;
}
Ok(())
}
}
@@ -69,7 +71,7 @@ impl Serialize for KzgCommitment {
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
serializer.serialize_str(&format!("{:?}", self))
}
}
@@ -119,3 +121,24 @@ impl arbitrary::Arbitrary<'_> for KzgCommitment {
Ok(KzgCommitment(bytes))
}
}
#[test]
fn kzg_commitment_display() {
let display_commitment_str = "0x53fa…adac";
let display_commitment = KzgCommitment::from_str(
"0x53fa09af35d1d1a9e76f65e16112a9064ce30d1e4e2df98583f0f5dc2e7dd13a4f421a9c89f518fafd952df76f23adac",
)
.unwrap()
.to_string();
assert_eq!(display_commitment, display_commitment_str);
}
#[test]
fn kzg_commitment_debug() {
let debug_commitment_str =
"0x53fa09af35d1d1a9e76f65e16112a9064ce30d1e4e2df98583f0f5dc2e7dd13a4f421a9c89f518fafd952df76f23adac";
let debug_commitment = KzgCommitment::from_str(debug_commitment_str).unwrap();
assert_eq!(format!("{debug_commitment:?}"), debug_commitment_str);
}

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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>,
}