From 2fa2efc422d92cbef65d190875781917668892b3 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Wed, 11 Dec 2024 11:01:35 +0800 Subject: [PATCH 01/21] Implement Serialize and Deserialize for ceno --- src/ceno_binding/mod.rs | 8 +- src/ceno_binding/pcs.rs | 409 +++++++++++++++++++++++++++++-- src/crypto/merkle_tree/blake3.rs | 11 +- src/parameters.rs | 6 +- src/poly_utils/coeffs.rs | 3 +- src/whir/committer.rs | 3 +- src/whir/parameters.rs | 3 +- 7 files changed, 413 insertions(+), 30 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 5d7e5f4..9d33310 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,7 +1,9 @@ mod pcs; +pub use pcs::Whir; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; #[derive(Debug, thiserror::Error)] @@ -11,10 +13,10 @@ pub enum Error { } pub trait PolynomialCommitmentScheme: Clone { - type Param: Clone; - type CommitmentWithData; + type Param: Clone + Debug + Serialize + DeserializeOwned; + type CommitmentWithData: Clone + Debug + Serialize + DeserializeOwned; type Proof: Clone + CanonicalSerialize + CanonicalDeserialize; - type Poly: Clone; + type Poly: Clone + Debug + Serialize + DeserializeOwned; type Transcript; fn setup(poly_size: usize) -> Self::Param; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 12d1496..9234732 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -13,30 +13,402 @@ use crate::whir::{ Statement, WhirProof, }; +use ark_crypto_primitives::merkle_tree::{Config, MerkleTree}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use nimue::{DefaultHash, IOPattern, Merlin}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; -use std::fmt::Debug; +#[cfg(feature = "parallel")] +use rayon::slice::ParallelSlice; +use serde::ser::SerializeStruct; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; - -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Whir(PhantomData); type MerkleConfig = MerkleTreeParams; type PowStrategy = Blake3PoW; type WhirPCSConfig = WhirConfig, PowStrategy>; +// Wrapper for WhirConfig +pub struct WhirConfigWrapper { + inner: WhirConfig, PowStrategy>, +} + +impl Serialize for WhirConfigWrapper { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("WhirConfigWrapper", 17)?; + s.serialize_field( + "num_variables", + &(self.inner.mv_parameters.num_variables as u32), + )?; + s.serialize_field("initial_statement", &self.inner.initial_statement)?; + s.serialize_field("starting_log_inv_rate", &self.inner.starting_log_inv_rate)?; + s.serialize_field("folding_factor", &self.inner.folding_factor)?; + s.serialize_field("soundness_type", &self.inner.soundness_type)?; + s.serialize_field("security_level", &self.inner.security_level)?; + s.serialize_field("pow_bits", &self.inner.max_pow_bits)?; + s.serialize_field("fold_optimisation", &self.inner.fold_optimisation)?; + + s.end() + } +} + +impl<'de, E: FftField> Deserialize<'de> for WhirConfigWrapper { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Visitor { + marker: PhantomData, + } + + impl<'de, E: FftField> serde::de::Visitor<'de> for Visitor { + type Value = WhirConfig, PowStrategy>; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct WhirConfigWrapper") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut num_variables = None; + let mut soundness_type = None; + let mut security_level = None; + let mut pow_bits = None; + let mut initial_statement = None; + let mut starting_log_inv_rate = None; + let mut folding_factor = None; + let mut fold_optimisation = None; + + while let Some(key) = map.next_key()? { + match key { + "num_variables" => { + if num_variables.is_some() { + return Err(serde::de::Error::duplicate_field("num_variables")); + } + num_variables = Some(map.next_value()?); + } + "soundness_type" => { + if soundness_type.is_some() { + return Err(serde::de::Error::duplicate_field("soundness_type")); + } + soundness_type = Some(map.next_value()?); + } + "security_level" => { + if security_level.is_some() { + return Err(serde::de::Error::duplicate_field("security_level")); + } + security_level = Some(map.next_value()?); + } + "pow_bits" => { + if pow_bits.is_some() { + return Err(serde::de::Error::duplicate_field("pow_bits")); + } + pow_bits = Some(map.next_value()?); + } + "initial_statement" => { + if initial_statement.is_some() { + return Err(serde::de::Error::duplicate_field("initial_statement")); + } + initial_statement = Some(map.next_value()?); + } + "starting_log_inv_rate" => { + if starting_log_inv_rate.is_some() { + return Err(serde::de::Error::duplicate_field( + "starting_log_inv_rate", + )); + } + starting_log_inv_rate = Some(map.next_value()?); + } + "folding_factor" => { + if folding_factor.is_some() { + return Err(serde::de::Error::duplicate_field("folding_factor")); + } + folding_factor = Some(map.next_value()?); + } + "fold_optimisation" => { + if fold_optimisation.is_some() { + return Err(serde::de::Error::duplicate_field("fold_optimisation")); + } + fold_optimisation = Some(map.next_value()?); + } + _ => { + return Err(serde::de::Error::unknown_field( + key, + &[ + "num_variables", + "soundness_type", + "security_level", + "pow_bits", + "initial_statement", + "starting_log_inv_rate", + "folding_factor", + "fold_optimisation", + ], + )); + } + } + } + + let num_variables = num_variables + .ok_or_else(|| serde::de::Error::missing_field("num_variables"))?; + let soundness_type = soundness_type + .ok_or_else(|| serde::de::Error::missing_field("soundness_type"))?; + let security_level = security_level + .ok_or_else(|| serde::de::Error::missing_field("security_level"))?; + let pow_bits = + pow_bits.ok_or_else(|| serde::de::Error::missing_field("pow_bits"))?; + let initial_statement = initial_statement + .ok_or_else(|| serde::de::Error::missing_field("initial_statement"))?; + let starting_log_inv_rate = starting_log_inv_rate + .ok_or_else(|| serde::de::Error::missing_field("starting_log_inv_rate"))?; + let folding_factor = folding_factor + .ok_or_else(|| serde::de::Error::missing_field("folding_factor"))?; + let fold_optimisation = fold_optimisation + .ok_or_else(|| serde::de::Error::missing_field("fold_optimisation"))?; + + let mut rng = ChaCha8Rng::from_seed([0u8; 32]); + let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); + Ok(WhirConfig::new( + MultivariateParameters::new(num_variables), + WhirParameters { + initial_statement, + starting_log_inv_rate, + folding_factor, + soundness_type, + security_level, + pow_bits, + fold_optimisation, + _pow_parameters: PhantomData::, + // Merkle tree parameters + leaf_hash_params, + two_to_one_params, + }, + )) + } + } + + let config = deserializer.deserialize_struct( + "WhirConfigWrapper", + &[ + "num_variables", + "soundness_type", + "security_level", + "pow_bits", + "initial_statement", + "starting_log_inv_rate", + "folding_factor", + "fold_optimisation", + ], + Visitor { + marker: PhantomData, + }, + )?; + + Ok(WhirConfigWrapper { inner: config }) + } +} + +impl Debug for WhirConfigWrapper { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str("WhirConfigWrapper") + } +} + +impl Clone for WhirConfigWrapper { + fn clone(&self) -> Self { + WhirConfigWrapper { + inner: self.inner.clone(), + } + } +} + +// Wrapper for Witness +pub struct WitnessWrapper { + inner: Witness>, +} + +impl Serialize for WitnessWrapper +where + F: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("WitnessWrapper", 3)?; + s.serialize_field("polynomial", &self.inner.polynomial)?; + s.serialize_field("merkle_leaves", &self.inner.merkle_leaves)?; + s.serialize_field("ood_points", &self.inner.ood_points)?; + s.serialize_field("ood_answers", &self.inner.ood_answers)?; + s.serialize_field("tree_height", &self.inner.merkle_tree.height())?; + s.end() + } +} + +impl<'de, F> Deserialize<'de> for WitnessWrapper +where + F: Deserialize<'de> + FftField + CanonicalDeserialize + CanonicalSerialize, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Visitor { + marker: PhantomData, + } + + impl<'de, F: FftField> serde::de::Visitor<'de> for Visitor + where + F: FftField + Deserialize<'de> + CanonicalDeserialize + CanonicalSerialize, + { + type Value = WitnessWrapper; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct WitnessWrapper") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut polynomial = None; + let mut merkle_leaves = None; + let mut ood_points = None; + let mut ood_answers = None; + let mut tree_height = None; + + while let Some(key) = map.next_key()? { + match key { + "polynomial" => { + if polynomial.is_some() { + return Err(serde::de::Error::duplicate_field("polynomial")); + } + polynomial = Some(map.next_value()?); + } + "merkle_leaves" => { + if merkle_leaves.is_some() { + return Err(serde::de::Error::duplicate_field("merkle_leaves")); + } + merkle_leaves = Some(map.next_value()?); + } + "ood_points" => { + if ood_points.is_some() { + return Err(serde::de::Error::duplicate_field("ood_points")); + } + ood_points = Some(map.next_value()?); + } + "ood_answers" => { + if ood_answers.is_some() { + return Err(serde::de::Error::duplicate_field("ood_answers")); + } + ood_answers = Some(map.next_value()?); + } + "tree_height" => { + if tree_height.is_some() { + return Err(serde::de::Error::duplicate_field("tree_height")); + } + tree_height = Some(map.next_value()?); + } + _ => { + return Err(serde::de::Error::unknown_field( + key, + &[ + "polynomial", + "merkle_leaves", + "ood_points", + "ood_answers", + "tree_height", + ], + )); + } + } + } + + let polynomial = + polynomial.ok_or_else(|| serde::de::Error::missing_field("polynomial"))?; + let merkle_leaves: Vec = merkle_leaves + .ok_or_else(|| serde::de::Error::missing_field("merkle_leaves"))?; + let ood_points = + ood_points.ok_or_else(|| serde::de::Error::missing_field("ood_points"))?; + let ood_answers = + ood_answers.ok_or_else(|| serde::de::Error::missing_field("ood_answers"))?; + + let mut rng = ChaCha8Rng::from_seed([0u8; 32]); + let (leaf_hash_param, two_to_one_hash_param) = mt::default_config::(&mut rng); + + let tree_height: usize = + tree_height.ok_or_else(|| serde::de::Error::missing_field("tree_height"))?; + let leaf_node_size = 1 << (tree_height - 1); + let fold_size = merkle_leaves.len() / leaf_node_size; + #[cfg(not(feature = "parallel"))] + let leafs_iter = merkle_leaves.chunks_exact(fold_size); + #[cfg(feature = "parallel")] + let leafs_iter = merkle_leaves.par_chunks_exact(fold_size); + let merkle_tree = + MerkleTree::new(&leaf_hash_param, &two_to_one_hash_param, leafs_iter).map_err( + |_| serde::de::Error::custom("Failed to construct the merkle tree"), + )?; + + Ok(WitnessWrapper { + inner: Witness { + polynomial, + merkle_tree, + merkle_leaves, + ood_points, + ood_answers, + }, + }) + } + } + + deserializer.deserialize_struct( + "WitnessWrapper", + &[ + "polynomial", + "merkle_leaves", + "ood_points", + "ood_answers", + "tree_height", + ], + Visitor { + marker: PhantomData, + }, + ) + } +} + +impl Debug for WitnessWrapper { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str("WitnessWrapper") + } +} + +impl Clone for WitnessWrapper { + fn clone(&self) -> Self { + WitnessWrapper { + inner: self.inner.clone(), + } + } +} + impl PolynomialCommitmentScheme for Whir where - E: FftField + CanonicalSerialize + CanonicalDeserialize, + E: FftField + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned + Debug, + E::BasePrimeField: Serialize + DeserializeOwned + Debug, { - type Param = WhirPCSConfig; - type CommitmentWithData = Witness>; + type Param = WhirConfigWrapper; + type CommitmentWithData = WitnessWrapper; type Proof = WhirProof, E>; - // TODO: support both base and extension fields type Poly = CoefficientList; type Transcript = Merlin; @@ -48,7 +420,7 @@ where let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); - let whir_params = WhirParameters::, PowStrategy> { + let whir_params = WhirParameters::, PowStrategy> { initial_statement: true, security_level: 100, pow_bits, @@ -60,7 +432,10 @@ where _pow_parameters: Default::default(), starting_log_inv_rate: starting_rate, }; - WhirConfig::, PowStrategy>::new(mv_params, whir_params) + + WhirConfigWrapper { + inner: WhirConfig::, PowStrategy>::new(mv_params, whir_params), + } } fn commit_and_write( @@ -68,9 +443,10 @@ where poly: &Self::Poly, transcript: &mut Self::Transcript, ) -> Result { - let committer = Committer::new(pp.clone()); + let committer = Committer::new(pp.inner.clone()); let witness = committer.commit(transcript, poly.clone())?; - Ok(witness) + + Ok(WitnessWrapper { inner: witness }) } fn batch_commit( @@ -87,13 +463,13 @@ where eval: &E, transcript: &mut Self::Transcript, ) -> Result { - let prover = Prover(pp.clone()); + let prover = Prover(pp.inner.clone()); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], evaluations: vec![eval.clone()], }; - let proof = prover.prove(transcript, statement, witness)?; + let proof = prover.prove(transcript, statement, witness.inner)?; Ok(proof) } @@ -115,12 +491,11 @@ where proof: &Self::Proof, transcript: &Self::Transcript, ) -> Result<(), Error> { - // TODO: determine reps by security bits let reps = 1000; - let verifier = Verifier::new(vp.clone()); + let verifier = Verifier::new(vp.inner.clone()); let io = IOPattern::::new("🌪️") - .commit_statement(&vp) - .add_whir_proof(&vp); + .commit_statement(&vp.inner) + .add_whir_proof(&vp.inner); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], diff --git a/src/crypto/merkle_tree/blake3.rs b/src/crypto/merkle_tree/blake3.rs index ddcce8f..e47c7e2 100644 --- a/src/crypto/merkle_tree/blake3.rs +++ b/src/crypto/merkle_tree/blake3.rs @@ -10,8 +10,11 @@ use ark_crypto_primitives::{ }; use ark_ff::Field; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use nimue::{Arthur, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError, ProofResult}; +use nimue::{ + Arthur, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError, ProofResult, +}; use rand::RngCore; +use serde::{Deserialize, Serialize}; #[derive( Debug, Default, Clone, Copy, Eq, PartialEq, Hash, CanonicalSerialize, CanonicalDeserialize, @@ -106,7 +109,7 @@ impl TwoToOneCRHScheme for Blake3TwoToOneCRHScheme { pub type LeafH = Blake3LeafHash; pub type CompressH = Blake3TwoToOneCRHScheme; -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct MerkleTreeParams(PhantomData); impl Config for MerkleTreeParams { @@ -144,10 +147,10 @@ impl DigestWriter> for Merlin { } } -impl <'a, F: Field> DigestReader> for Arthur<'a> { +impl<'a, F: Field> DigestReader> for Arthur<'a> { fn read_digest(&mut self) -> ProofResult { let mut digest = [0; 32]; self.fill_next_bytes(&mut digest)?; Ok(Blake3Digest(digest)) } -} \ No newline at end of file +} diff --git a/src/parameters.rs b/src/parameters.rs index 633670d..2464362 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -1,13 +1,13 @@ use std::{fmt::Display, marker::PhantomData, str::FromStr}; use ark_crypto_primitives::merkle_tree::{Config, LeafParam, TwoToOneParam}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; pub fn default_max_pow(num_variables: usize, log_inv_rate: usize) -> usize { num_variables + log_inv_rate - 3 } -#[derive(Debug, Clone, Copy, Serialize)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum SoundnessType { UniqueDecoding, ProvableList, @@ -64,7 +64,7 @@ impl Display for MultivariateParameters { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum FoldType { Naive, ProverHelps, diff --git a/src/poly_utils/coeffs.rs b/src/poly_utils/coeffs.rs index 5fbbea5..991a912 100644 --- a/src/poly_utils/coeffs.rs +++ b/src/poly_utils/coeffs.rs @@ -2,6 +2,7 @@ use super::{evals::EvaluationsList, hypercube::BinaryHypercubePoint, Multilinear use crate::ntt::wavelet_transform; use ark_ff::Field; use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial}; +use serde::{Deserialize, Serialize}; #[cfg(feature = "parallel")] use { rayon::{join, prelude::*}, @@ -19,7 +20,7 @@ use { /// - coeffs[1] is the coefficient of X_2 /// - coeffs[2] is the coefficient of X_1 /// - coeffs[4] is the coefficient of X_0 -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct CoefficientList { coeffs: Vec, // list of coefficients. For multilinear polynomials, we have coeffs.len() == 1 << num_variables. num_variables: usize, // number of variables diff --git a/src/whir/committer.rs b/src/whir/committer.rs index 30d3484..9d298b2 100644 --- a/src/whir/committer.rs +++ b/src/whir/committer.rs @@ -16,6 +16,7 @@ use crate::whir::fs_utils::DigestWriter; #[cfg(feature = "parallel")] use rayon::prelude::*; +#[derive(Clone)] pub struct Witness where MerkleConfig: Config, @@ -35,7 +36,7 @@ where impl Committer where F: FftField, - MerkleConfig: Config + MerkleConfig: Config, { pub fn new(config: WhirConfig) -> Self { Self(config) diff --git a/src/whir/parameters.rs b/src/whir/parameters.rs index 7a9d711..0cb7ca0 100644 --- a/src/whir/parameters.rs +++ b/src/whir/parameters.rs @@ -3,6 +3,7 @@ use std::{f64::consts::LOG2_10, fmt::Display, marker::PhantomData}; use ark_crypto_primitives::merkle_tree::{Config, LeafParam, TwoToOneParam}; use ark_ff::FftField; +use serde::{Deserialize, Serialize}; use crate::{ crypto::fields::FieldWithSize, @@ -45,7 +46,7 @@ where pub(crate) two_to_one_params: TwoToOneParam, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct RoundConfig { pub(crate) pow_bits: f64, pub(crate) folding_pow_bits: f64, From 17f17896994f7d2abcbd1d721fce71dd9af28158 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Thu, 12 Dec 2024 10:12:52 +0800 Subject: [PATCH 02/21] Fix compilation errors (except tests) --- src/ceno_binding/mod.rs | 2 +- src/ceno_binding/pcs.rs | 56 +++++++++++++++++++++++++++++++++++++---- src/whir/mod.rs | 4 +-- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 9d33310..6e64e05 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -15,7 +15,7 @@ pub enum Error { pub trait PolynomialCommitmentScheme: Clone { type Param: Clone + Debug + Serialize + DeserializeOwned; type CommitmentWithData: Clone + Debug + Serialize + DeserializeOwned; - type Proof: Clone + CanonicalSerialize + CanonicalDeserialize; + type Proof: Clone + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned; type Poly: Clone + Debug + Serialize + DeserializeOwned; type Transcript; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 9234732..fb63e2f 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -401,6 +401,47 @@ impl Clone for WitnessWrapper { } } +// Wrapper for WhirProof +#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] +pub struct WhirProofWrapper(WhirProof) +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize; + +impl Serialize for WhirProofWrapper +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let proof = &self.0 .0; + // Create a buffer that implements the `Write` trait + let mut buffer = Vec::new(); + proof.serialize_compressed(&mut buffer).unwrap(); + serializer.serialize_bytes(&buffer) + } +} + +impl<'de, MerkleConfig, F> Deserialize<'de> for WhirProofWrapper +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // Deserialize the bytes into a buffer + let buffer: Vec = Deserialize::deserialize(deserializer)?; + // Deserialize the buffer into a proof + let proof = WhirProof::deserialize_compressed(&buffer[..]).unwrap(); + Ok(WhirProofWrapper(proof)) + } +} + impl PolynomialCommitmentScheme for Whir where E: FftField + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned + Debug, @@ -408,7 +449,7 @@ where { type Param = WhirConfigWrapper; type CommitmentWithData = WitnessWrapper; - type Proof = WhirProof, E>; + type Proof = WhirProofWrapper, E>; type Poly = CoefficientList; type Transcript = Merlin; @@ -470,7 +511,7 @@ where }; let proof = prover.prove(transcript, statement, witness.inner)?; - Ok(proof) + Ok(WhirProofWrapper(proof)) } fn batch_open( @@ -504,7 +545,7 @@ where for _ in 0..reps { let mut arthur = io.to_arthur(transcript.transcript()); - verifier.verify(&mut arthur, &statement, proof)?; + verifier.verify(&mut arthur, &statement, &proof.0)?; } Ok(()) } @@ -522,11 +563,16 @@ where #[cfg(test)] mod tests { - use ark_ff::Field; + use ark_ff::{Field, Fp2, MontBackend, MontConfig}; use rand::Rng; + use crate::crypto::fields::F2Config64; + use super::*; - use crate::crypto::fields::Field64_2 as F; + + type Field64_2 = Fp2; + + type F = Field64_2; #[test] fn single_point_verify() { diff --git a/src/whir/mod.rs b/src/whir/mod.rs index 7db951b..d228a99 100644 --- a/src/whir/mod.rs +++ b/src/whir/mod.rs @@ -4,11 +4,11 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use crate::poly_utils::MultilinearPoint; pub mod committer; +pub mod fs_utils; pub mod iopattern; pub mod parameters; pub mod prover; pub mod verifier; -pub mod fs_utils; #[derive(Debug, Clone, Default)] pub struct Statement { @@ -18,7 +18,7 @@ pub struct Statement { // Only includes the authentication paths #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] -pub struct WhirProof(Vec<(MultiPath, Vec>)>) +pub struct WhirProof(pub(crate) Vec<(MultiPath, Vec>)>) where MerkleConfig: Config, F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize; From 7fc1f3443a0a748d08598759de9567f03681237a Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Fri, 13 Dec 2024 10:12:54 +0800 Subject: [PATCH 03/21] Temp store --- Cargo.lock | 28 +++ Cargo.toml | 1 + src/ceno_binding/mod.rs | 10 +- src/ceno_binding/pcs.rs | 467 ++++++---------------------------------- src/whir/committer.rs | 4 +- src/whir/parameters.rs | 11 +- 6 files changed, 110 insertions(+), 411 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 048ab85..358b44c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -463,6 +463,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -1059,6 +1080,12 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1097,6 +1124,7 @@ dependencies = [ "blake3", "clap", "derivative", + "derive_more", "goldilocks", "lazy_static", "nimue", diff --git a/Cargo.toml b/Cargo.toml index ab8c041..6568081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ rayon = { version = "1.10.0", optional = true } goldilocks = { git = "https://github.com/scroll-tech/ceno-Goldilocks" } thiserror = "1" +derive_more = { version = "1.0.0", features = ["debug"] } [profile.release] debug = true diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 6e64e05..41f6486 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -14,7 +14,7 @@ pub enum Error { pub trait PolynomialCommitmentScheme: Clone { type Param: Clone + Debug + Serialize + DeserializeOwned; - type CommitmentWithData: Clone + Debug + Serialize + DeserializeOwned; + type CommitmentWithWitness: Clone + Debug; type Proof: Clone + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned; type Poly: Clone + Debug + Serialize + DeserializeOwned; type Transcript; @@ -25,16 +25,16 @@ pub trait PolynomialCommitmentScheme: Clone { pp: &Self::Param, poly: &Self::Poly, transcript: &mut Self::Transcript, - ) -> Result; + ) -> Result; fn batch_commit( pp: &Self::Param, polys: &[Self::Poly], - ) -> Result; + ) -> Result; fn open( pp: &Self::Param, - comm: Self::CommitmentWithData, + comm: Self::CommitmentWithWitness, point: &[E], eval: &E, transcript: &mut Self::Transcript, @@ -47,7 +47,7 @@ pub trait PolynomialCommitmentScheme: Clone { fn batch_open( pp: &Self::Param, polys: &[Self::Poly], - comm: Self::CommitmentWithData, + comm: Self::CommitmentWithWitness, point: &[E], evals: &[E], transcript: &mut Self::Transcript, diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index fb63e2f..c0f1df1 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -4,6 +4,7 @@ use crate::parameters::{ default_max_pow, FoldType, MultivariateParameters, SoundnessType, WhirParameters, }; use crate::poly_utils::{coeffs::CoefficientList, MultilinearPoint}; +use crate::whir::fs_utils::DigestWriter; use crate::whir::{ committer::{Committer, Witness}, iopattern::WhirIOPattern, @@ -16,6 +17,8 @@ use crate::whir::{ use ark_crypto_primitives::merkle_tree::{Config, MerkleTree}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::log2; +use core::num; use nimue::{DefaultHash, IOPattern, Merlin}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; @@ -26,380 +29,49 @@ use serde::ser::SerializeStruct; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Whir(PhantomData); -type MerkleConfig = MerkleTreeParams; type PowStrategy = Blake3PoW; -type WhirPCSConfig = WhirConfig, PowStrategy>; - -// Wrapper for WhirConfig -pub struct WhirConfigWrapper { - inner: WhirConfig, PowStrategy>, -} - -impl Serialize for WhirConfigWrapper { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("WhirConfigWrapper", 17)?; - s.serialize_field( - "num_variables", - &(self.inner.mv_parameters.num_variables as u32), - )?; - s.serialize_field("initial_statement", &self.inner.initial_statement)?; - s.serialize_field("starting_log_inv_rate", &self.inner.starting_log_inv_rate)?; - s.serialize_field("folding_factor", &self.inner.folding_factor)?; - s.serialize_field("soundness_type", &self.inner.soundness_type)?; - s.serialize_field("security_level", &self.inner.security_level)?; - s.serialize_field("pow_bits", &self.inner.max_pow_bits)?; - s.serialize_field("fold_optimisation", &self.inner.fold_optimisation)?; - - s.end() - } -} - -impl<'de, E: FftField> Deserialize<'de> for WhirConfigWrapper { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct Visitor { - marker: PhantomData, - } - - impl<'de, E: FftField> serde::de::Visitor<'de> for Visitor { - type Value = WhirConfig, PowStrategy>; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct WhirConfigWrapper") - } - - fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, - { - let mut num_variables = None; - let mut soundness_type = None; - let mut security_level = None; - let mut pow_bits = None; - let mut initial_statement = None; - let mut starting_log_inv_rate = None; - let mut folding_factor = None; - let mut fold_optimisation = None; - - while let Some(key) = map.next_key()? { - match key { - "num_variables" => { - if num_variables.is_some() { - return Err(serde::de::Error::duplicate_field("num_variables")); - } - num_variables = Some(map.next_value()?); - } - "soundness_type" => { - if soundness_type.is_some() { - return Err(serde::de::Error::duplicate_field("soundness_type")); - } - soundness_type = Some(map.next_value()?); - } - "security_level" => { - if security_level.is_some() { - return Err(serde::de::Error::duplicate_field("security_level")); - } - security_level = Some(map.next_value()?); - } - "pow_bits" => { - if pow_bits.is_some() { - return Err(serde::de::Error::duplicate_field("pow_bits")); - } - pow_bits = Some(map.next_value()?); - } - "initial_statement" => { - if initial_statement.is_some() { - return Err(serde::de::Error::duplicate_field("initial_statement")); - } - initial_statement = Some(map.next_value()?); - } - "starting_log_inv_rate" => { - if starting_log_inv_rate.is_some() { - return Err(serde::de::Error::duplicate_field( - "starting_log_inv_rate", - )); - } - starting_log_inv_rate = Some(map.next_value()?); - } - "folding_factor" => { - if folding_factor.is_some() { - return Err(serde::de::Error::duplicate_field("folding_factor")); - } - folding_factor = Some(map.next_value()?); - } - "fold_optimisation" => { - if fold_optimisation.is_some() { - return Err(serde::de::Error::duplicate_field("fold_optimisation")); - } - fold_optimisation = Some(map.next_value()?); - } - _ => { - return Err(serde::de::Error::unknown_field( - key, - &[ - "num_variables", - "soundness_type", - "security_level", - "pow_bits", - "initial_statement", - "starting_log_inv_rate", - "folding_factor", - "fold_optimisation", - ], - )); - } - } - } - - let num_variables = num_variables - .ok_or_else(|| serde::de::Error::missing_field("num_variables"))?; - let soundness_type = soundness_type - .ok_or_else(|| serde::de::Error::missing_field("soundness_type"))?; - let security_level = security_level - .ok_or_else(|| serde::de::Error::missing_field("security_level"))?; - let pow_bits = - pow_bits.ok_or_else(|| serde::de::Error::missing_field("pow_bits"))?; - let initial_statement = initial_statement - .ok_or_else(|| serde::de::Error::missing_field("initial_statement"))?; - let starting_log_inv_rate = starting_log_inv_rate - .ok_or_else(|| serde::de::Error::missing_field("starting_log_inv_rate"))?; - let folding_factor = folding_factor - .ok_or_else(|| serde::de::Error::missing_field("folding_factor"))?; - let fold_optimisation = fold_optimisation - .ok_or_else(|| serde::de::Error::missing_field("fold_optimisation"))?; - - let mut rng = ChaCha8Rng::from_seed([0u8; 32]); - let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); - Ok(WhirConfig::new( - MultivariateParameters::new(num_variables), - WhirParameters { - initial_statement, - starting_log_inv_rate, - folding_factor, - soundness_type, - security_level, - pow_bits, - fold_optimisation, - _pow_parameters: PhantomData::, - // Merkle tree parameters - leaf_hash_params, - two_to_one_params, - }, - )) - } - } - - let config = deserializer.deserialize_struct( - "WhirConfigWrapper", - &[ - "num_variables", - "soundness_type", - "security_level", - "pow_bits", - "initial_statement", - "starting_log_inv_rate", - "folding_factor", - "fold_optimisation", - ], - Visitor { - marker: PhantomData, - }, - )?; - - Ok(WhirConfigWrapper { inner: config }) - } -} - -impl Debug for WhirConfigWrapper { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str("WhirConfigWrapper") - } -} +type WhirPCSConfig = WhirConfig, PowStrategy>; -impl Clone for WhirConfigWrapper { - fn clone(&self) -> Self { - WhirConfigWrapper { - inner: self.inner.clone(), - } - } -} - -// Wrapper for Witness -pub struct WitnessWrapper { - inner: Witness>, -} - -impl Serialize for WitnessWrapper -where - F: Serialize, -{ - fn serialize(&self, serializer: S) -> Result +pub trait WhirSpec: Clone { + type MerkleConfig: Config + Clone where - S: serde::Serializer, - { - let mut s = serializer.serialize_struct("WitnessWrapper", 3)?; - s.serialize_field("polynomial", &self.inner.polynomial)?; - s.serialize_field("merkle_leaves", &self.inner.merkle_leaves)?; - s.serialize_field("ood_points", &self.inner.ood_points)?; - s.serialize_field("ood_answers", &self.inner.ood_answers)?; - s.serialize_field("tree_height", &self.inner.merkle_tree.height())?; - s.end() - } + Merlin: DigestWriter, + IOPattern: WhirIOPattern; + fn get_parameters(num_variables: usize) -> WhirParameters; } -impl<'de, F> Deserialize<'de> for WitnessWrapper -where - F: Deserialize<'de> + FftField + CanonicalDeserialize + CanonicalSerialize, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct Visitor { - marker: PhantomData, - } +#[derive(Debug, Clone)] +pub struct WhirDefaultSpec; - impl<'de, F: FftField> serde::de::Visitor<'de> for Visitor - where - F: FftField + Deserialize<'de> + CanonicalDeserialize + CanonicalSerialize, - { - type Value = WitnessWrapper; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct WitnessWrapper") - } - - fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, - { - let mut polynomial = None; - let mut merkle_leaves = None; - let mut ood_points = None; - let mut ood_answers = None; - let mut tree_height = None; - - while let Some(key) = map.next_key()? { - match key { - "polynomial" => { - if polynomial.is_some() { - return Err(serde::de::Error::duplicate_field("polynomial")); - } - polynomial = Some(map.next_value()?); - } - "merkle_leaves" => { - if merkle_leaves.is_some() { - return Err(serde::de::Error::duplicate_field("merkle_leaves")); - } - merkle_leaves = Some(map.next_value()?); - } - "ood_points" => { - if ood_points.is_some() { - return Err(serde::de::Error::duplicate_field("ood_points")); - } - ood_points = Some(map.next_value()?); - } - "ood_answers" => { - if ood_answers.is_some() { - return Err(serde::de::Error::duplicate_field("ood_answers")); - } - ood_answers = Some(map.next_value()?); - } - "tree_height" => { - if tree_height.is_some() { - return Err(serde::de::Error::duplicate_field("tree_height")); - } - tree_height = Some(map.next_value()?); - } - _ => { - return Err(serde::de::Error::unknown_field( - key, - &[ - "polynomial", - "merkle_leaves", - "ood_points", - "ood_answers", - "tree_height", - ], - )); - } - } - } - - let polynomial = - polynomial.ok_or_else(|| serde::de::Error::missing_field("polynomial"))?; - let merkle_leaves: Vec = merkle_leaves - .ok_or_else(|| serde::de::Error::missing_field("merkle_leaves"))?; - let ood_points = - ood_points.ok_or_else(|| serde::de::Error::missing_field("ood_points"))?; - let ood_answers = - ood_answers.ok_or_else(|| serde::de::Error::missing_field("ood_answers"))?; - - let mut rng = ChaCha8Rng::from_seed([0u8; 32]); - let (leaf_hash_param, two_to_one_hash_param) = mt::default_config::(&mut rng); - - let tree_height: usize = - tree_height.ok_or_else(|| serde::de::Error::missing_field("tree_height"))?; - let leaf_node_size = 1 << (tree_height - 1); - let fold_size = merkle_leaves.len() / leaf_node_size; - #[cfg(not(feature = "parallel"))] - let leafs_iter = merkle_leaves.chunks_exact(fold_size); - #[cfg(feature = "parallel")] - let leafs_iter = merkle_leaves.par_chunks_exact(fold_size); - let merkle_tree = - MerkleTree::new(&leaf_hash_param, &two_to_one_hash_param, leafs_iter).map_err( - |_| serde::de::Error::custom("Failed to construct the merkle tree"), - )?; - - Ok(WitnessWrapper { - inner: Witness { - polynomial, - merkle_tree, - merkle_leaves, - ood_points, - ood_answers, - }, - }) - } +impl WhirSpec for WhirDefaultSpec { + type MerkleConfig = MerkleTreeParams; + fn get_parameters(num_variables: usize) -> WhirParameters { + let mut rng = ChaCha8Rng::from_seed([0u8; 32]); + let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); + WhirParameters:: { + initial_statement: true, + security_level: 100, + pow_bits: default_max_pow(num_variables, 1), + folding_factor: 4, + leaf_hash_params, + two_to_one_params, + soundness_type: SoundnessType::ConjectureList, + fold_optimisation: FoldType::ProverHelps, + _pow_parameters: Default::default(), + starting_log_inv_rate: 1, } - - deserializer.deserialize_struct( - "WitnessWrapper", - &[ - "polynomial", - "merkle_leaves", - "ood_points", - "ood_answers", - "tree_height", - ], - Visitor { - marker: PhantomData, - }, - ) } } -impl Debug for WitnessWrapper { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str("WitnessWrapper") - } +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WhirSetupParams { + pub num_variables: usize, + _phantom: PhantomData, } -impl Clone for WitnessWrapper { - fn clone(&self) -> Self { - WitnessWrapper { - inner: self.inner.clone(), - } - } -} +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Whir>(PhantomData<(E, Spec)>); // Wrapper for WhirProof #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] @@ -442,40 +114,21 @@ where } } -impl PolynomialCommitmentScheme for Whir +impl> PolynomialCommitmentScheme for Whir where E: FftField + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned + Debug, E::BasePrimeField: Serialize + DeserializeOwned + Debug, { - type Param = WhirConfigWrapper; - type CommitmentWithData = WitnessWrapper; - type Proof = WhirProofWrapper, E>; + type Param = WhirSetupParams; + type CommitmentWithWitness = Witness; + type Proof = WhirProofWrapper; type Poly = CoefficientList; type Transcript = Merlin; fn setup(poly_size: usize) -> Self::Param { - let mv_params = MultivariateParameters::::new(poly_size); - let starting_rate = 1; - let pow_bits = default_max_pow(poly_size, starting_rate); - let mut rng = ChaCha8Rng::from_seed([0u8; 32]); - - let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); - - let whir_params = WhirParameters::, PowStrategy> { - initial_statement: true, - security_level: 100, - pow_bits, - folding_factor: 4, - leaf_hash_params, - two_to_one_params, - soundness_type: SoundnessType::ConjectureList, - fold_optimisation: FoldType::ProverHelps, - _pow_parameters: Default::default(), - starting_log_inv_rate: starting_rate, - }; - - WhirConfigWrapper { - inner: WhirConfig::, PowStrategy>::new(mv_params, whir_params), + WhirSetupParams { + num_variables: log2(poly_size) as usize, + _phantom: PhantomData, } } @@ -483,41 +136,49 @@ where pp: &Self::Param, poly: &Self::Poly, transcript: &mut Self::Transcript, - ) -> Result { - let committer = Committer::new(pp.inner.clone()); + ) -> Result { + let whir_params = Spec::get_parameters(pp.num_variables); + let mv_params = MultivariateParameters::new(pp.num_variables); + let params = WhirConfig::::new(mv_params, whir_params); + + let committer = Committer::new(params); let witness = committer.commit(transcript, poly.clone())?; - Ok(WitnessWrapper { inner: witness }) + Ok(witness) } fn batch_commit( _pp: &Self::Param, _polys: &[Self::Poly], - ) -> Result { + ) -> Result { todo!() } fn open( pp: &Self::Param, - witness: Self::CommitmentWithData, + witness: Self::CommitmentWithWitness, point: &[E], eval: &E, transcript: &mut Self::Transcript, ) -> Result { - let prover = Prover(pp.inner.clone()); + let whir_params = Spec::get_parameters(pp.num_variables); + let mv_params = MultivariateParameters::new(pp.num_variables); + let params = WhirConfig::::new(mv_params, whir_params); + + let prover = Prover(params); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], evaluations: vec![eval.clone()], }; - let proof = prover.prove(transcript, statement, witness.inner)?; + let proof = prover.prove(transcript, statement, witness)?; Ok(WhirProofWrapper(proof)) } fn batch_open( _pp: &Self::Param, _polys: &[Self::Poly], - _comm: Self::CommitmentWithData, + _comm: Self::CommitmentWithWitness, _point: &[E], _evals: &[E], _transcript: &mut Self::Transcript, @@ -532,11 +193,15 @@ where proof: &Self::Proof, transcript: &Self::Transcript, ) -> Result<(), Error> { + let whir_params = Spec::get_parameters(vp.num_variables); + let mv_params = MultivariateParameters::new(vp.num_variables); + let params = WhirConfig::::new(mv_params, whir_params); + let reps = 1000; - let verifier = Verifier::new(vp.inner.clone()); + let verifier = Verifier::new(params); let io = IOPattern::::new("🌪️") - .commit_statement(&vp.inner) - .add_whir_proof(&vp.inner); + .commit_statement(¶ms) + .add_whir_proof(¶ms); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], @@ -591,13 +256,13 @@ mod tests { .add_whir_proof(&pp); let mut merlin = io.to_merlin(); - let witness = Whir::::commit_and_write(&pp, &poly, &mut merlin).unwrap(); + let witness = Whir::::commit_and_write(&pp, &poly, &mut merlin).unwrap(); let mut rng = rand::thread_rng(); let point: Vec = (0..poly_size).map(|_| F::from(rng.gen::())).collect(); let eval = poly.evaluate_at_extension(&MultilinearPoint(point.clone())); - let proof = Whir::::open(&pp, witness, &point, &eval, &mut merlin).unwrap(); - Whir::::verify(&pp, &point, &eval, &proof, &merlin).unwrap(); + let proof = Whir::::open(&pp, witness, &point, &eval, &mut merlin).unwrap(); + Whir::::verify(&pp, &point, &eval, &proof, &merlin).unwrap(); } } diff --git a/src/whir/committer.rs b/src/whir/committer.rs index 9d298b2..d7b0932 100644 --- a/src/whir/committer.rs +++ b/src/whir/committer.rs @@ -7,6 +7,7 @@ use crate::{ use ark_crypto_primitives::merkle_tree::{Config, MerkleTree}; use ark_ff::FftField; use ark_poly::EvaluationDomain; +use derive_more::Debug; use nimue::{ plugins::ark::{FieldChallenges, FieldWriter}, ByteWriter, ProofResult, @@ -16,12 +17,13 @@ use crate::whir::fs_utils::DigestWriter; #[cfg(feature = "parallel")] use rayon::prelude::*; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Witness where MerkleConfig: Config, { pub(crate) polynomial: CoefficientList, + #[debug(skip)] pub(crate) merkle_tree: MerkleTree, pub(crate) merkle_leaves: Vec, pub(crate) ood_points: Vec, diff --git a/src/whir/parameters.rs b/src/whir/parameters.rs index 0cb7ca0..777ecfa 100644 --- a/src/whir/parameters.rs +++ b/src/whir/parameters.rs @@ -1,4 +1,5 @@ -use core::panic; +use core::{fmt, panic}; +use derive_more::Debug; use std::{f64::consts::LOG2_10, fmt::Display, marker::PhantomData}; use ark_crypto_primitives::merkle_tree::{Config, LeafParam, TwoToOneParam}; @@ -11,7 +12,7 @@ use crate::{ parameters::{FoldType, MultivariateParameters, SoundnessType, WhirParameters}, }; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct WhirConfig where F: FftField, @@ -42,7 +43,9 @@ where pub(crate) pow_strategy: PhantomData, // Merkle tree parameters + #[debug(skip)] pub(crate) leaf_hash_params: LeafParam, + #[debug(skip)] pub(crate) two_to_one_params: TwoToOneParam, } @@ -438,7 +441,7 @@ where MerkleConfig: Config, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.mv_parameters.fmt(f)?; + fmt::Display::fmt(&self.mv_parameters, f)?; writeln!(f, ", folding factor: {}", self.folding_factor)?; writeln!( f, @@ -452,7 +455,7 @@ where self.starting_folding_pow_bits )?; for r in &self.round_parameters { - r.fmt(f)?; + fmt::Display::fmt(&r, f)?; } writeln!( From e6e54c791ce65c017e7ad54f07aebd4b02e0f695 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Mon, 16 Dec 2024 17:07:46 +0800 Subject: [PATCH 04/21] Temp store --- src/ceno_binding/pcs.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index c0f1df1..55171cb 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -4,7 +4,7 @@ use crate::parameters::{ default_max_pow, FoldType, MultivariateParameters, SoundnessType, WhirParameters, }; use crate::poly_utils::{coeffs::CoefficientList, MultilinearPoint}; -use crate::whir::fs_utils::DigestWriter; +use crate::whir::fs_utils::{DigestReader, DigestWriter}; use crate::whir::{ committer::{Committer, Witness}, iopattern::WhirIOPattern, @@ -19,7 +19,7 @@ use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; use core::num; -use nimue::{DefaultHash, IOPattern, Merlin}; +use nimue::{Arthur, DefaultHash, IOPattern, Merlin}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -31,13 +31,13 @@ use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; type PowStrategy = Blake3PoW; -type WhirPCSConfig = WhirConfig, PowStrategy>; +// type WhirPCSConfig = WhirConfig, PowStrategy>; pub trait WhirSpec: Clone { - type MerkleConfig: Config + Clone - where - Merlin: DigestWriter, - IOPattern: WhirIOPattern; + type MerkleConfig: Config + Clone; + // where + // Merlin: DigestWriter, + // IOPattern: WhirIOPattern; fn get_parameters(num_variables: usize) -> WhirParameters; } @@ -118,6 +118,9 @@ impl> PolynomialCommitmentScheme for Whir where E: FftField + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned + Debug, E::BasePrimeField: Serialize + DeserializeOwned + Debug, + Merlin: DigestWriter, + for<'a> Arthur<'a>: DigestReader, + IOPattern: WhirIOPattern, { type Param = WhirSetupParams; type CommitmentWithWitness = Witness; @@ -198,7 +201,7 @@ where let params = WhirConfig::::new(mv_params, whir_params); let reps = 1000; - let verifier = Verifier::new(params); + let verifier = Verifier::new(params.clone()); let io = IOPattern::::new("🌪️") .commit_statement(¶ms) .add_whir_proof(¶ms); @@ -243,7 +246,7 @@ mod tests { fn single_point_verify() { let poly_size = 10; let num_coeffs = 1 << poly_size; - let pp = Whir::::setup(poly_size); + let pp = Whir::::setup(poly_size); let poly = CoefficientList::new( (0..num_coeffs) From 0530a5eccdb1b0b7168caded7c062c4a0fbd602b Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Mon, 16 Dec 2024 20:04:29 +0800 Subject: [PATCH 05/21] Clear compilation errors --- src/ceno_binding/mod.rs | 2 +- src/ceno_binding/pcs.rs | 59 +++++++++-------------------------------- src/lib.rs | 1 + src/whir/iopattern.rs | 1 + 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 41f6486..b2c454c 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,5 +1,5 @@ mod pcs; -pub use pcs::Whir; +pub use pcs::{DefaultHash, DigestIO, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 55171cb..ba91304 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -19,7 +19,7 @@ use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; use core::num; -use nimue::{Arthur, DefaultHash, IOPattern, Merlin}; +pub use nimue::{Arthur, DefaultHash, IOPattern, Merlin}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -37,6 +37,7 @@ pub trait WhirSpec: Clone { type MerkleConfig: Config + Clone; // where // Merlin: DigestWriter, + // for<'a> Arthur<'a>: DigestReader, // IOPattern: WhirIOPattern; fn get_parameters(num_variables: usize) -> WhirParameters; } @@ -114,13 +115,20 @@ where } } +pub trait DigestIO = where + Self: Config + Sized, + Merlin: DigestWriter, + for<'a> Arthur<'a>: DigestReader, + IOPattern: WhirIOPattern; + impl> PolynomialCommitmentScheme for Whir where - E: FftField + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned + Debug, + E: FftField + Serialize + DeserializeOwned + Debug, E::BasePrimeField: Serialize + DeserializeOwned + Debug, - Merlin: DigestWriter, - for<'a> Arthur<'a>: DigestReader, - IOPattern: WhirIOPattern, + Spec::MerkleConfig: DigestIO, + // Merlin: DigestWriter, + // for<'a> Arthur<'a>: DigestReader, + // IOPattern: WhirIOPattern, { type Param = WhirSetupParams; type CommitmentWithWitness = Witness; @@ -228,44 +236,3 @@ where todo!() } } - -#[cfg(test)] -mod tests { - use ark_ff::{Field, Fp2, MontBackend, MontConfig}; - use rand::Rng; - - use crate::crypto::fields::F2Config64; - - use super::*; - - type Field64_2 = Fp2; - - type F = Field64_2; - - #[test] - fn single_point_verify() { - let poly_size = 10; - let num_coeffs = 1 << poly_size; - let pp = Whir::::setup(poly_size); - - let poly = CoefficientList::new( - (0..num_coeffs) - .map(::BasePrimeField::from) - .collect(), - ); - - let io = IOPattern::::new("🌪️") - .commit_statement(&pp) - .add_whir_proof(&pp); - let mut merlin = io.to_merlin(); - - let witness = Whir::::commit_and_write(&pp, &poly, &mut merlin).unwrap(); - - let mut rng = rand::thread_rng(); - let point: Vec = (0..poly_size).map(|_| F::from(rng.gen::())).collect(); - let eval = poly.evaluate_at_extension(&MultilinearPoint(point.clone())); - - let proof = Whir::::open(&pp, witness, &point, &eval, &mut merlin).unwrap(); - Whir::::verify(&pp, &point, &eval, &proof, &merlin).unwrap(); - } -} diff --git a/src/lib.rs b/src/lib.rs index 9ba03f1..f67017c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(trait_alias)] #[cfg(feature = "ceno")] pub mod ceno_binding; // Connect whir with ceno pub mod cmdline_utils; diff --git a/src/whir/iopattern.rs b/src/whir/iopattern.rs index 649dda8..b31cc5a 100644 --- a/src/whir/iopattern.rs +++ b/src/whir/iopattern.rs @@ -1,6 +1,7 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use nimue::plugins::ark::*; +pub use nimue::{Arthur, IOPattern, Merlin}; use crate::{ fs_utils::{OODIOPattern, WhirPoWIOPattern}, From 3d9731727ced0f048156b2bd1ccdb146db0315ef Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 17 Dec 2024 07:37:33 +0800 Subject: [PATCH 06/21] Clear warnings --- src/ceno_binding/mod.rs | 3 ++- src/ceno_binding/pcs.rs | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index b2c454c..f07060f 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,5 +1,6 @@ mod pcs; -pub use pcs::{DefaultHash, DigestIO, Whir, WhirDefaultSpec, WhirSpec}; +pub use ark_crypto_primitives::merkle_tree::Config; +pub use pcs::{DefaultHash, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index ba91304..532860b 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -14,18 +14,14 @@ use crate::whir::{ Statement, WhirProof, }; -use ark_crypto_primitives::merkle_tree::{Config, MerkleTree}; +use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; -use core::num; pub use nimue::{Arthur, DefaultHash, IOPattern, Merlin}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; -#[cfg(feature = "parallel")] -use rayon::slice::ParallelSlice; -use serde::ser::SerializeStruct; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; @@ -115,20 +111,23 @@ where } } -pub trait DigestIO = where - Self: Config + Sized, - Merlin: DigestWriter, - for<'a> Arthur<'a>: DigestReader, - IOPattern: WhirIOPattern; +impl Debug for WhirProofWrapper +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("WhirProofWrapper") + } +} impl> PolynomialCommitmentScheme for Whir where E: FftField + Serialize + DeserializeOwned + Debug, E::BasePrimeField: Serialize + DeserializeOwned + Debug, - Spec::MerkleConfig: DigestIO, - // Merlin: DigestWriter, - // for<'a> Arthur<'a>: DigestReader, - // IOPattern: WhirIOPattern, + Merlin: DigestWriter, + for<'a> Arthur<'a>: DigestReader, + IOPattern: WhirIOPattern, { type Param = WhirSetupParams; type CommitmentWithWitness = Witness; From 177ffaf7ec22097ef9aee5db41f4c169b0872d72 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Thu, 19 Dec 2024 14:07:48 +0800 Subject: [PATCH 07/21] Temp store --- src/ceno_binding/mod.rs | 5 ++++- src/ceno_binding/pcs.rs | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index f07060f..8cb1d43 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,5 +1,6 @@ mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; +use nimue::plugins::ark; pub use pcs::{DefaultHash, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; @@ -7,7 +8,9 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; -#[derive(Debug, thiserror::Error)] +pub use nimue::plugins::ark::{FieldChallenges, FieldWriter}; + +#[derive(Debug, Clone, thiserror::Error)] pub enum Error { #[error(transparent)] ProofError(#[from] nimue::ProofError), diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 532860b..4b24870 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -121,6 +121,33 @@ where } } +#[derive(Clone)] +pub struct CommitmentWithWitness +where + MerkleConfig: Config, +{ + pub commitment: MerkleConfig::InnerDigest, + pub witness: Witness, +} + +impl CommitmentWithWitness +where + MerkleConfig: Config, +{ + pub fn ood_answers(&self) -> Vec { + self.witness.ood_answers.clone() + } +} + +impl Debug for CommitmentWithWitness +where + MerkleConfig: Config, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("CommitmentWithWitness") + } +} + impl> PolynomialCommitmentScheme for Whir where E: FftField + Serialize + DeserializeOwned + Debug, @@ -130,7 +157,7 @@ where IOPattern: WhirIOPattern, { type Param = WhirSetupParams; - type CommitmentWithWitness = Witness; + type CommitmentWithWitness = CommitmentWithWitness; type Proof = WhirProofWrapper; type Poly = CoefficientList; type Transcript = Merlin; @@ -154,7 +181,10 @@ where let committer = Committer::new(params); let witness = committer.commit(transcript, poly.clone())?; - Ok(witness) + Ok(CommitmentWithWitness { + commitment: witness.merkle_tree.root(), + witness, + }) } fn batch_commit( @@ -181,7 +211,7 @@ where evaluations: vec![eval.clone()], }; - let proof = prover.prove(transcript, statement, witness)?; + let proof = prover.prove(transcript, statement, witness.witness)?; Ok(WhirProofWrapper(proof)) } From 0c402298dd6e5817b43b2cd212780e404dbd53df Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Thu, 19 Dec 2024 14:36:35 +0800 Subject: [PATCH 08/21] Add transcript data to proof --- src/ceno_binding/pcs.rs | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 4b24870..da2f75b 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -72,10 +72,14 @@ pub struct Whir>(PhantomData<(E, Spec)>); // Wrapper for WhirProof #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] -pub struct WhirProofWrapper(WhirProof) +pub struct WhirProofWrapper where MerkleConfig: Config, - F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize; + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + proof: WhirProof, + transcript: Vec, +} impl Serialize for WhirProofWrapper where @@ -86,11 +90,16 @@ where where S: serde::Serializer, { - let proof = &self.0 .0; + let proof = &self.proof.0; // Create a buffer that implements the `Write` trait let mut buffer = Vec::new(); proof.serialize_compressed(&mut buffer).unwrap(); - serializer.serialize_bytes(&buffer) + let proof_size = buffer.len(); + let proof_size_bytes = proof_size.to_le_bytes(); + let mut data = proof_size_bytes.to_vec(); + data.extend_from_slice(&buffer); + data.extend_from_slice(&self.transcript); + serializer.serialize_bytes(&data) } } @@ -103,11 +112,13 @@ where where D: serde::Deserializer<'de>, { - // Deserialize the bytes into a buffer - let buffer: Vec = Deserialize::deserialize(deserializer)?; - // Deserialize the buffer into a proof - let proof = WhirProof::deserialize_compressed(&buffer[..]).unwrap(); - Ok(WhirProofWrapper(proof)) + let data: Vec = Deserialize::deserialize(deserializer)?; + let proof_size_bytes = &data[0..8]; + let proof_size = u64::from_le_bytes(proof_size_bytes.try_into().unwrap()); + let proof_bytes = &data[8..8 + proof_size as usize]; + let proof = WhirProof::deserialize_compressed(&proof_bytes[..]).unwrap(); + let transcript = data[8 + proof_size as usize..].to_vec(); + Ok(WhirProofWrapper { proof, transcript }) } } @@ -212,7 +223,11 @@ where }; let proof = prover.prove(transcript, statement, witness.witness)?; - Ok(WhirProofWrapper(proof)) + + Ok(WhirProofWrapper { + proof, + transcript: transcript.transcript().to_vec(), + }) } fn batch_open( @@ -250,7 +265,7 @@ where for _ in 0..reps { let mut arthur = io.to_arthur(transcript.transcript()); - verifier.verify(&mut arthur, &statement, &proof.0)?; + verifier.verify(&mut arthur, &statement, &proof.proof)?; } Ok(()) } From 25bcae09234b57f783342456681d9f527232ad7c Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Thu, 19 Dec 2024 14:48:13 +0800 Subject: [PATCH 09/21] Add transcript data to proof --- src/ceno_binding/pcs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index da2f75b..7df3164 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -77,8 +77,8 @@ where MerkleConfig: Config, F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, { - proof: WhirProof, - transcript: Vec, + pub proof: WhirProof, + pub transcript: Vec, } impl Serialize for WhirProofWrapper From c8fe0f42b0ca679e907c13d4e75b8a4c6dbe4a99 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Mon, 23 Dec 2024 13:24:20 +0800 Subject: [PATCH 10/21] Update API --- src/ceno_binding/mod.rs | 13 ++++++------- src/ceno_binding/pcs.rs | 21 +++++++-------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 8cb1d43..b90dc8a 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,6 +1,6 @@ mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; -use nimue::plugins::ark; +use nimue::{plugins::ark, Arthur, Merlin}; pub use pcs::{DefaultHash, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; @@ -21,14 +21,13 @@ pub trait PolynomialCommitmentScheme: Clone { type CommitmentWithWitness: Clone + Debug; type Proof: Clone + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned; type Poly: Clone + Debug + Serialize + DeserializeOwned; - type Transcript; fn setup(poly_size: usize) -> Self::Param; fn commit_and_write( pp: &Self::Param, poly: &Self::Poly, - transcript: &mut Self::Transcript, + transcript: &mut Merlin, ) -> Result; fn batch_commit( @@ -41,7 +40,7 @@ pub trait PolynomialCommitmentScheme: Clone { comm: Self::CommitmentWithWitness, point: &[E], eval: &E, - transcript: &mut Self::Transcript, + merlin: &mut Merlin, ) -> Result; /// This is a simple version of batch open: @@ -54,7 +53,7 @@ pub trait PolynomialCommitmentScheme: Clone { comm: Self::CommitmentWithWitness, point: &[E], evals: &[E], - transcript: &mut Self::Transcript, + transcript: &mut Merlin, ) -> Result; fn verify( @@ -62,7 +61,7 @@ pub trait PolynomialCommitmentScheme: Clone { point: &[E], eval: &E, proof: &Self::Proof, - transcript: &Self::Transcript, + transcript: &mut Arthur, ) -> Result<(), Error>; fn batch_verify( @@ -70,6 +69,6 @@ pub trait PolynomialCommitmentScheme: Clone { point: &[E], evals: &[E], proof: &Self::Proof, - transcript: &mut Self::Transcript, + transcript: &mut Arthur, ) -> Result<(), Error>; } diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 7df3164..4a3e094 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -171,7 +171,6 @@ where type CommitmentWithWitness = CommitmentWithWitness; type Proof = WhirProofWrapper; type Poly = CoefficientList; - type Transcript = Merlin; fn setup(poly_size: usize) -> Self::Param { WhirSetupParams { @@ -183,7 +182,7 @@ where fn commit_and_write( pp: &Self::Param, poly: &Self::Poly, - transcript: &mut Self::Transcript, + transcript: &mut Merlin, ) -> Result { let whir_params = Spec::get_parameters(pp.num_variables); let mv_params = MultivariateParameters::new(pp.num_variables); @@ -210,7 +209,7 @@ where witness: Self::CommitmentWithWitness, point: &[E], eval: &E, - transcript: &mut Self::Transcript, + transcript: &mut Merlin, ) -> Result { let whir_params = Spec::get_parameters(pp.num_variables); let mv_params = MultivariateParameters::new(pp.num_variables); @@ -236,7 +235,7 @@ where _comm: Self::CommitmentWithWitness, _point: &[E], _evals: &[E], - _transcript: &mut Self::Transcript, + _transcript: &mut Merlin, ) -> Result { todo!() } @@ -246,27 +245,21 @@ where point: &[E], eval: &E, proof: &Self::Proof, - transcript: &Self::Transcript, + transcript: &mut Arthur, ) -> Result<(), Error> { let whir_params = Spec::get_parameters(vp.num_variables); let mv_params = MultivariateParameters::new(vp.num_variables); let params = WhirConfig::::new(mv_params, whir_params); - let reps = 1000; let verifier = Verifier::new(params.clone()); - let io = IOPattern::::new("🌪️") - .commit_statement(¶ms) - .add_whir_proof(¶ms); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], evaluations: vec![eval.clone()], }; - for _ in 0..reps { - let mut arthur = io.to_arthur(transcript.transcript()); - verifier.verify(&mut arthur, &statement, &proof.proof)?; - } + verifier.verify(transcript, &statement, &proof.proof)?; + Ok(()) } @@ -275,7 +268,7 @@ where _point: &[E], _evals: &[E], _proof: &Self::Proof, - _transcript: &mut Self::Transcript, + _transcript: &mut Arthur, ) -> Result<(), Error> { todo!() } From bc8acd473d3694e3af49304df507393b30d55a1e Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Mon, 23 Dec 2024 14:04:38 +0800 Subject: [PATCH 11/21] Implement Default for WhirSpec --- src/ceno_binding/pcs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 4a3e094..d4b8999 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -38,7 +38,7 @@ pub trait WhirSpec: Clone { fn get_parameters(num_variables: usize) -> WhirParameters; } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct WhirDefaultSpec; impl WhirSpec for WhirDefaultSpec { From ed43e8dc3f25304e0772ed79da9cb79b9ad07594 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 24 Dec 2024 10:03:00 +0800 Subject: [PATCH 12/21] Single point verify pass --- src/ceno_binding/mod.rs | 2 +- src/ceno_binding/pcs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index b90dc8a..cbcd95c 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,7 +1,7 @@ mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; use nimue::{plugins::ark, Arthur, Merlin}; -pub use pcs::{DefaultHash, Whir, WhirDefaultSpec, WhirSpec}; +pub use pcs::{DefaultHash, PowStrategy, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index d4b8999..3fac48b 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -26,7 +26,7 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; -type PowStrategy = Blake3PoW; +pub type PowStrategy = Blake3PoW; // type WhirPCSConfig = WhirConfig, PowStrategy>; pub trait WhirSpec: Clone { From 2d5bf41536654f8ba8b8f26506720c2e205c2779 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 24 Dec 2024 10:43:44 +0800 Subject: [PATCH 13/21] Check comm consistency --- src/ceno_binding/mod.rs | 4 ++++ src/ceno_binding/pcs.rs | 8 +++++++- src/whir/verifier.rs | 22 ++++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index cbcd95c..8e52248 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -14,10 +14,13 @@ pub use nimue::plugins::ark::{FieldChallenges, FieldWriter}; pub enum Error { #[error(transparent)] ProofError(#[from] nimue::ProofError), + #[error("CommitmentMismatchFromDigest")] + CommitmentMismatchFromDigest, } pub trait PolynomialCommitmentScheme: Clone { type Param: Clone + Debug + Serialize + DeserializeOwned; + type Commitment: Clone + Debug; type CommitmentWithWitness: Clone + Debug; type Proof: Clone + CanonicalSerialize + CanonicalDeserialize + Serialize + DeserializeOwned; type Poly: Clone + Debug + Serialize + DeserializeOwned; @@ -58,6 +61,7 @@ pub trait PolynomialCommitmentScheme: Clone { fn verify( vp: &Self::Param, + comm: &Self::Commitment, point: &[E], eval: &E, proof: &Self::Proof, diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 3fac48b..89cf82a 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -168,6 +168,7 @@ where IOPattern: WhirIOPattern, { type Param = WhirSetupParams; + type Commitment = ::InnerDigest; type CommitmentWithWitness = CommitmentWithWitness; type Proof = WhirProofWrapper; type Poly = CoefficientList; @@ -242,6 +243,7 @@ where fn verify( vp: &Self::Param, + comm: &Self::Commitment, point: &[E], eval: &E, proof: &Self::Proof, @@ -258,7 +260,11 @@ where evaluations: vec![eval.clone()], }; - verifier.verify(transcript, &statement, &proof.proof)?; + let digest = verifier.verify(transcript, &statement, &proof.proof)?; + + if &digest != comm { + return Err(Error::CommitmentMismatchFromDigest); + } Ok(()) } diff --git a/src/whir/verifier.rs b/src/whir/verifier.rs index c92e1fe..d89dd77 100644 --- a/src/whir/verifier.rs +++ b/src/whir/verifier.rs @@ -4,8 +4,8 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_poly::EvaluationDomain; use nimue::{ - plugins::ark::{FieldChallenges, FieldReader} - , ByteChallenges, ByteReader, ProofError, ProofResult, + plugins::ark::{FieldChallenges, FieldReader}, + ByteChallenges, ByteReader, ProofError, ProofResult, }; use nimue_pow::{self, PoWChallenge}; @@ -106,7 +106,12 @@ where whir_proof: &WhirProof, ) -> ProofResult> where - Arthur: FieldReader + FieldChallenges + PoWChallenge + ByteReader + ByteChallenges + DigestReader, + Arthur: FieldReader + + FieldChallenges + + PoWChallenge + + ByteReader + + ByteChallenges + + DigestReader, { let mut sumcheck_rounds = Vec::new(); let mut folding_randomness: MultilinearPoint; @@ -468,9 +473,14 @@ where arthur: &mut Arthur, statement: &Statement, whir_proof: &WhirProof, - ) -> ProofResult<()> + ) -> ProofResult where - Arthur: FieldChallenges + FieldReader + ByteChallenges + ByteReader + PoWChallenge + DigestReader, + Arthur: FieldChallenges + + FieldReader + + ByteChallenges + + ByteReader + + PoWChallenge + + DigestReader, { // We first do a pass in which we rederive all the FS challenges // Then we will check the algebraic part (so to optimise inversions) @@ -603,6 +613,6 @@ where return Err(ProofError::InvalidProof); } - Ok(()) + Ok(parsed_commitment.root) } } From 4a85dd687c748438fd1ca491b68e543c1a144453 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Wed, 25 Dec 2024 09:08:46 +0800 Subject: [PATCH 14/21] Prover check intermediate results --- src/sumcheck/prover_single.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sumcheck/prover_single.rs b/src/sumcheck/prover_single.rs index f78c592..ab6cbb8 100644 --- a/src/sumcheck/prover_single.rs +++ b/src/sumcheck/prover_single.rs @@ -101,6 +101,8 @@ where let eval_1 = c0 + c1 + c2; let eval_2 = eval_1 + c1 + c2 + c2.double(); + assert_eq!(self.sum, eval_0 + eval_1); + SumcheckPolynomial::new(vec![eval_0, eval_1, eval_2], 1) } From 7a849e7da2855042182568fc341d4df3be89085b Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 12:53:33 +0800 Subject: [PATCH 15/21] Refactor --- src/ceno_binding/merkle_config.rs | 160 ++++++++++++++++++++++++++++++ src/ceno_binding/mod.rs | 10 +- src/ceno_binding/pcs.rs | 104 +++++++++++++------ 3 files changed, 242 insertions(+), 32 deletions(-) create mode 100644 src/ceno_binding/merkle_config.rs diff --git a/src/ceno_binding/merkle_config.rs b/src/ceno_binding/merkle_config.rs new file mode 100644 index 0000000..5c9cb25 --- /dev/null +++ b/src/ceno_binding/merkle_config.rs @@ -0,0 +1,160 @@ +use ark_crypto_primitives::merkle_tree::Config; +use ark_ff::FftField; +use nimue::{Arthur, DefaultHash, IOPattern, Merlin, ProofResult}; +use nimue_pow::PowStrategy; + +use crate::crypto::merkle_tree::blake3::MerkleTreeParams as Blake3Params; +use crate::crypto::merkle_tree::keccak::MerkleTreeParams as KeccakParams; +use crate::poly_utils::coeffs::CoefficientList; +use crate::whir::committer::{Committer, Witness}; +use crate::whir::fs_utils::DigestWriter; +use crate::whir::iopattern::WhirIOPattern; +use crate::whir::parameters::WhirConfig; +use crate::whir::prover::Prover; +use crate::whir::verifier::Verifier; +use crate::whir::{Statement, WhirProof}; + +pub trait WhirMerkleConfigWrapper { + type MerkleConfig: Config + Clone; + type PowStrategy: PowStrategy; + + fn commit_to_merlin( + committer: &Committer, + merlin: &mut Merlin, + poly: CoefficientList, + ) -> ProofResult>; + + fn prove_with_merlin( + prover: &Prover, + merlin: &mut Merlin, + statement: Statement, + witness: Witness, + ) -> ProofResult>; + + fn verify_with_arthur( + verifier: &Verifier, + arthur: &mut Arthur, + statement: &Statement, + whir_proof: &WhirProof, + ) -> ProofResult<::InnerDigest>; + + fn commit_statement_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern; + + fn add_whir_proof_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern; + + fn add_digest_to_merlin( + merlin: &mut Merlin, + digest: ::InnerDigest, + ) -> ProofResult<()>; +} + +pub struct Blake3ConfigWrapper(Blake3Params); +pub struct KeccakConfigWrapper(KeccakParams); + +impl WhirMerkleConfigWrapper for Blake3ConfigWrapper { + type MerkleConfig = Blake3Params; + type PowStrategy = nimue_pow::blake3::Blake3PoW; + fn commit_to_merlin( + committer: &Committer, + merlin: &mut Merlin, + poly: CoefficientList, + ) -> ProofResult> { + committer.commit(merlin, poly) + } + + fn prove_with_merlin( + prover: &Prover, + merlin: &mut Merlin, + statement: Statement, + witness: Witness, + ) -> ProofResult> { + prover.prove(merlin, statement, witness) + } + + fn verify_with_arthur( + verifier: &Verifier, + arthur: &mut Arthur, + statement: &Statement, + whir_proof: &WhirProof, + ) -> ProofResult<::InnerDigest> { + verifier.verify(arthur, statement, whir_proof) + } + + fn commit_statement_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern { + iopattern.commit_statement(params) + } + + fn add_whir_proof_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern { + iopattern.add_whir_proof(params) + } + + fn add_digest_to_merlin( + merlin: &mut Merlin, + digest: ::InnerDigest, + ) -> ProofResult<()> { + >::add_digest(merlin, digest) + } +} + +impl WhirMerkleConfigWrapper for KeccakConfigWrapper { + type MerkleConfig = KeccakParams; + type PowStrategy = nimue_pow::keccak::KeccakPoW; + fn commit_to_merlin( + committer: &Committer, + merlin: &mut Merlin, + poly: CoefficientList, + ) -> ProofResult> { + committer.commit(merlin, poly) + } + + fn prove_with_merlin( + prover: &Prover, + merlin: &mut Merlin, + statement: Statement, + witness: Witness, + ) -> ProofResult> { + prover.prove(merlin, statement, witness) + } + + fn verify_with_arthur( + verifier: &Verifier, + arthur: &mut Arthur, + statement: &Statement, + whir_proof: &WhirProof, + ) -> ProofResult<::InnerDigest> { + verifier.verify(arthur, statement, whir_proof) + } + + fn commit_statement_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern { + iopattern.commit_statement(params) + } + + fn add_whir_proof_to_io_pattern( + iopattern: IOPattern, + params: &WhirConfig, + ) -> IOPattern { + iopattern.add_whir_proof(params) + } + + fn add_digest_to_merlin( + merlin: &mut Merlin, + digest: ::InnerDigest, + ) -> ProofResult<()> { + >::add_digest(merlin, digest) + } +} diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 8e52248..d1d973a 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,7 +1,12 @@ +mod merkle_config; mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; -use nimue::{plugins::ark, Arthur, Merlin}; -pub use pcs::{DefaultHash, PowStrategy, Whir, WhirDefaultSpec, WhirSpec}; +use nimue::{Arthur, Merlin}; +pub use pcs::{ + add_digest_to_merlin, add_whir_proof_to_io_pattern, commit_statement_to_io_pattern, + DefaultHash, InnerDigestOf, MerkleConfigOf, PowOf, PowStrategy, Whir, WhirDefaultSpec, + WhirSpec, +}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -9,6 +14,7 @@ use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; pub use nimue::plugins::ark::{FieldChallenges, FieldWriter}; +pub use nimue::ProofResult; #[derive(Debug, Clone, thiserror::Error)] pub enum Error { diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 89cf82a..51139d8 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -1,13 +1,12 @@ +use super::merkle_config::{Blake3ConfigWrapper, WhirMerkleConfigWrapper}; use super::{Error, PolynomialCommitmentScheme}; -use crate::crypto::merkle_tree::blake3::{self as mt, MerkleTreeParams}; +use crate::crypto::merkle_tree::blake3::{self as mt}; use crate::parameters::{ default_max_pow, FoldType, MultivariateParameters, SoundnessType, WhirParameters, }; use crate::poly_utils::{coeffs::CoefficientList, MultilinearPoint}; -use crate::whir::fs_utils::{DigestReader, DigestWriter}; use crate::whir::{ committer::{Committer, Witness}, - iopattern::WhirIOPattern, parameters::WhirConfig, prover::Prover, verifier::Verifier, @@ -18,7 +17,8 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; -pub use nimue::{Arthur, DefaultHash, IOPattern, Merlin}; +pub use nimue::{Arthur, DefaultHash, Merlin}; +use nimue::{IOPattern, ProofResult}; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -29,24 +29,57 @@ use std::marker::PhantomData; pub type PowStrategy = Blake3PoW; // type WhirPCSConfig = WhirConfig, PowStrategy>; -pub trait WhirSpec: Clone { - type MerkleConfig: Config + Clone; - // where - // Merlin: DigestWriter, - // for<'a> Arthur<'a>: DigestReader, - // IOPattern: WhirIOPattern; - fn get_parameters(num_variables: usize) -> WhirParameters; +pub trait WhirSpec: Default + std::fmt::Debug + Clone { + type MerkleConfigWrapper: WhirMerkleConfigWrapper; + fn get_parameters( + num_variables: usize, + ) -> WhirParameters, PowOf>; } +pub type MerkleConfigOf = + <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; + +pub fn commit_statement_to_io_pattern>( + iopattern: IOPattern, + params: &WhirConfig, PowOf>, +) -> IOPattern { + >::commit_statement_to_io_pattern( + iopattern, params, + ) +} + +pub fn add_whir_proof_to_io_pattern>( + iopattern: IOPattern, + params: &WhirConfig, PowOf>, +) -> IOPattern { + >::add_whir_proof_to_io_pattern( + iopattern, params, + ) +} + +pub fn add_digest_to_merlin>( + merlin: &mut Merlin, + digest: InnerDigestOf, +) -> ProofResult<()> { + >::add_digest_to_merlin(merlin, digest) +} + +pub type InnerDigestOf = as Config>::InnerDigest; + +pub type PowOf = + <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::PowStrategy; + #[derive(Debug, Clone, Default)] pub struct WhirDefaultSpec; impl WhirSpec for WhirDefaultSpec { - type MerkleConfig = MerkleTreeParams; - fn get_parameters(num_variables: usize) -> WhirParameters { + type MerkleConfigWrapper = Blake3ConfigWrapper; + fn get_parameters( + num_variables: usize, + ) -> WhirParameters, PowStrategy> { let mut rng = ChaCha8Rng::from_seed([0u8; 32]); let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); - WhirParameters:: { + WhirParameters::, PowStrategy> { initial_statement: true, security_level: 100, pow_bits: default_max_pow(num_variables, 1), @@ -163,14 +196,11 @@ impl> PolynomialCommitmentScheme for Whir where E: FftField + Serialize + DeserializeOwned + Debug, E::BasePrimeField: Serialize + DeserializeOwned + Debug, - Merlin: DigestWriter, - for<'a> Arthur<'a>: DigestReader, - IOPattern: WhirIOPattern, { type Param = WhirSetupParams; - type Commitment = ::InnerDigest; - type CommitmentWithWitness = CommitmentWithWitness; - type Proof = WhirProofWrapper; + type Commitment = as Config>::InnerDigest; + type CommitmentWithWitness = CommitmentWithWitness>; + type Proof = WhirProofWrapper, E>; type Poly = CoefficientList; fn setup(poly_size: usize) -> Self::Param { @@ -183,14 +213,16 @@ where fn commit_and_write( pp: &Self::Param, poly: &Self::Poly, - transcript: &mut Merlin, + merlin: &mut Merlin, ) -> Result { let whir_params = Spec::get_parameters(pp.num_variables); let mv_params = MultivariateParameters::new(pp.num_variables); - let params = WhirConfig::::new(mv_params, whir_params); + let params = + WhirConfig::, PowOf>::new(mv_params, whir_params); let committer = Committer::new(params); - let witness = committer.commit(transcript, poly.clone())?; + let witness = + Spec::MerkleConfigWrapper::commit_to_merlin(&committer, merlin, poly.clone())?; Ok(CommitmentWithWitness { commitment: witness.merkle_tree.root(), @@ -210,11 +242,12 @@ where witness: Self::CommitmentWithWitness, point: &[E], eval: &E, - transcript: &mut Merlin, + merlin: &mut Merlin, ) -> Result { let whir_params = Spec::get_parameters(pp.num_variables); let mv_params = MultivariateParameters::new(pp.num_variables); - let params = WhirConfig::::new(mv_params, whir_params); + let params = + WhirConfig::, PowOf>::new(mv_params, whir_params); let prover = Prover(params); let statement = Statement { @@ -222,11 +255,16 @@ where evaluations: vec![eval.clone()], }; - let proof = prover.prove(transcript, statement, witness.witness)?; + let proof = Spec::MerkleConfigWrapper::prove_with_merlin( + &prover, + merlin, + statement, + witness.witness, + )?; Ok(WhirProofWrapper { proof, - transcript: transcript.transcript().to_vec(), + transcript: merlin.transcript().to_vec(), }) } @@ -247,11 +285,12 @@ where point: &[E], eval: &E, proof: &Self::Proof, - transcript: &mut Arthur, + arthur: &mut Arthur, ) -> Result<(), Error> { let whir_params = Spec::get_parameters(vp.num_variables); let mv_params = MultivariateParameters::new(vp.num_variables); - let params = WhirConfig::::new(mv_params, whir_params); + let params = + WhirConfig::, PowOf>::new(mv_params, whir_params); let verifier = Verifier::new(params.clone()); @@ -260,7 +299,12 @@ where evaluations: vec![eval.clone()], }; - let digest = verifier.verify(transcript, &statement, &proof.proof)?; + let digest = Spec::MerkleConfigWrapper::verify_with_arthur( + &verifier, + arthur, + &statement, + &proof.proof, + )?; if &digest != comm { return Err(Error::CommitmentMismatchFromDigest); From 6f9d633b4b8207aa94878fd2dc4b02c2caf7f12e Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 13:51:50 +0800 Subject: [PATCH 16/21] Refactor --- src/ceno_binding/pcs.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 51139d8..713e7c4 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -34,10 +34,23 @@ pub trait WhirSpec: Default + std::fmt::Debug + Clone { fn get_parameters( num_variables: usize, ) -> WhirParameters, PowOf>; + + fn prepare_io_pattern(num_variables: usize) -> IOPattern { + let whir_params = Self::get_parameters(num_variables); + let mv_params = MultivariateParameters::new(num_variables); + let params = ConfigOf::::new(mv_params, whir_params); + + let io = IOPattern::::new("🌪️"); + let io = commit_statement_to_io_pattern::(io, ¶ms); + let io = add_whir_proof_to_io_pattern::(io, ¶ms); + + io + } } pub type MerkleConfigOf = <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; +type ConfigOf = WhirConfig, PowOf>; pub fn commit_statement_to_io_pattern>( iopattern: IOPattern, From 1edf80f6f9944e47c2e4fead63eb907c0c0bab4f Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 14:01:19 +0800 Subject: [PATCH 17/21] Clean some unused exports --- src/ceno_binding/mod.rs | 4 +--- src/ceno_binding/pcs.rs | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index d1d973a..2362037 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -3,9 +3,7 @@ mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; use nimue::{Arthur, Merlin}; pub use pcs::{ - add_digest_to_merlin, add_whir_proof_to_io_pattern, commit_statement_to_io_pattern, - DefaultHash, InnerDigestOf, MerkleConfigOf, PowOf, PowStrategy, Whir, WhirDefaultSpec, - WhirSpec, + add_digest_to_merlin, DefaultHash, InnerDigestOf, PowStrategy, Whir, WhirDefaultSpec, WhirSpec, }; use ark_ff::FftField; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 713e7c4..edacb4b 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -48,11 +48,11 @@ pub trait WhirSpec: Default + std::fmt::Debug + Clone { } } -pub type MerkleConfigOf = +type MerkleConfigOf = <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; type ConfigOf = WhirConfig, PowOf>; -pub fn commit_statement_to_io_pattern>( +fn commit_statement_to_io_pattern>( iopattern: IOPattern, params: &WhirConfig, PowOf>, ) -> IOPattern { @@ -61,7 +61,7 @@ pub fn commit_statement_to_io_pattern>( ) } -pub fn add_whir_proof_to_io_pattern>( +fn add_whir_proof_to_io_pattern>( iopattern: IOPattern, params: &WhirConfig, PowOf>, ) -> IOPattern { @@ -79,7 +79,7 @@ pub fn add_digest_to_merlin>( pub type InnerDigestOf = as Config>::InnerDigest; -pub type PowOf = +type PowOf = <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::PowStrategy; #[derive(Debug, Clone, Default)] From 3086fe243f1af2cd964d86aedf5a1698a9f753dd Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 14:19:39 +0800 Subject: [PATCH 18/21] Refactor --- src/ceno_binding/mod.rs | 4 +--- src/ceno_binding/pcs.rs | 37 ++++++++++++++----------------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 2362037..053e74e 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -2,9 +2,7 @@ mod merkle_config; mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; use nimue::{Arthur, Merlin}; -pub use pcs::{ - add_digest_to_merlin, DefaultHash, InnerDigestOf, PowStrategy, Whir, WhirDefaultSpec, WhirSpec, -}; +pub use pcs::{add_digest_to_merlin, DefaultHash, InnerDigestOf, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index edacb4b..1cbbb8c 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -26,19 +26,22 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; -pub type PowStrategy = Blake3PoW; -// type WhirPCSConfig = WhirConfig, PowStrategy>; - pub trait WhirSpec: Default + std::fmt::Debug + Clone { type MerkleConfigWrapper: WhirMerkleConfigWrapper; fn get_parameters( num_variables: usize, ) -> WhirParameters, PowOf>; - fn prepare_io_pattern(num_variables: usize) -> IOPattern { + fn prepare_whir_config( + num_variables: usize, + ) -> WhirConfig, PowOf> { let whir_params = Self::get_parameters(num_variables); let mv_params = MultivariateParameters::new(num_variables); - let params = ConfigOf::::new(mv_params, whir_params); + ConfigOf::::new(mv_params, whir_params) + } + + fn prepare_io_pattern(num_variables: usize) -> IOPattern { + let params = Self::prepare_whir_config(num_variables); let io = IOPattern::::new("🌪️"); let io = commit_statement_to_io_pattern::(io, ¶ms); @@ -87,12 +90,10 @@ pub struct WhirDefaultSpec; impl WhirSpec for WhirDefaultSpec { type MerkleConfigWrapper = Blake3ConfigWrapper; - fn get_parameters( - num_variables: usize, - ) -> WhirParameters, PowStrategy> { + fn get_parameters(num_variables: usize) -> WhirParameters, Blake3PoW> { let mut rng = ChaCha8Rng::from_seed([0u8; 32]); let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); - WhirParameters::, PowStrategy> { + WhirParameters::, Blake3PoW> { initial_statement: true, security_level: 100, pow_bits: default_max_pow(num_variables, 1), @@ -228,10 +229,7 @@ where poly: &Self::Poly, merlin: &mut Merlin, ) -> Result { - let whir_params = Spec::get_parameters(pp.num_variables); - let mv_params = MultivariateParameters::new(pp.num_variables); - let params = - WhirConfig::, PowOf>::new(mv_params, whir_params); + let params = Spec::prepare_whir_config(pp.num_variables); let committer = Committer::new(params); let witness = @@ -257,10 +255,7 @@ where eval: &E, merlin: &mut Merlin, ) -> Result { - let whir_params = Spec::get_parameters(pp.num_variables); - let mv_params = MultivariateParameters::new(pp.num_variables); - let params = - WhirConfig::, PowOf>::new(mv_params, whir_params); + let params = Spec::prepare_whir_config(pp.num_variables); let prover = Prover(params); let statement = Statement { @@ -300,12 +295,8 @@ where proof: &Self::Proof, arthur: &mut Arthur, ) -> Result<(), Error> { - let whir_params = Spec::get_parameters(vp.num_variables); - let mv_params = MultivariateParameters::new(vp.num_variables); - let params = - WhirConfig::, PowOf>::new(mv_params, whir_params); - - let verifier = Verifier::new(params.clone()); + let params = Spec::prepare_whir_config(vp.num_variables); + let verifier = Verifier::new(params); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], From c2154db6393e322ab28b89fdd4ce8d93ae625ade Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 14:23:15 +0800 Subject: [PATCH 19/21] Refactor --- src/ceno_binding/pcs.rs | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 1cbbb8c..4dac522 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -44,8 +44,13 @@ pub trait WhirSpec: Default + std::fmt::Debug + Clone { let params = Self::prepare_whir_config(num_variables); let io = IOPattern::::new("🌪️"); - let io = commit_statement_to_io_pattern::(io, ¶ms); - let io = add_whir_proof_to_io_pattern::(io, ¶ms); + let io = >::commit_statement_to_io_pattern( + io, ¶ms, + ); + let io = + >::add_whir_proof_to_io_pattern( + io, ¶ms, + ); io } @@ -55,24 +60,6 @@ type MerkleConfigOf = <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; type ConfigOf = WhirConfig, PowOf>; -fn commit_statement_to_io_pattern>( - iopattern: IOPattern, - params: &WhirConfig, PowOf>, -) -> IOPattern { - >::commit_statement_to_io_pattern( - iopattern, params, - ) -} - -fn add_whir_proof_to_io_pattern>( - iopattern: IOPattern, - params: &WhirConfig, PowOf>, -) -> IOPattern { - >::add_whir_proof_to_io_pattern( - iopattern, params, - ) -} - pub fn add_digest_to_merlin>( merlin: &mut Merlin, digest: InnerDigestOf, From d44c99c61d59ddaaee7a5ed2fbe6df2af9c680c9 Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Tue, 31 Dec 2024 14:37:45 +0800 Subject: [PATCH 20/21] Refactor --- src/ceno_binding/mod.rs | 18 +++++------- src/ceno_binding/pcs.rs | 61 +++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/ceno_binding/mod.rs b/src/ceno_binding/mod.rs index 053e74e..6b39758 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,8 +1,7 @@ mod merkle_config; mod pcs; pub use ark_crypto_primitives::merkle_tree::Config; -use nimue::{Arthur, Merlin}; -pub use pcs::{add_digest_to_merlin, DefaultHash, InnerDigestOf, Whir, WhirDefaultSpec, WhirSpec}; +pub use pcs::{DefaultHash, InnerDigestOf, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -20,6 +19,11 @@ pub enum Error { CommitmentMismatchFromDigest, } +/// The trait for a non-interactive polynomial commitment scheme. +/// This trait serves as the intermediate step between WHIR and the +/// trait required in Ceno mpcs. Because Ceno and the WHIR implementation +/// in this crate assume different types of transcripts, to connect +/// them we can provide a non-interactive interface from WHIR. pub trait PolynomialCommitmentScheme: Clone { type Param: Clone + Debug + Serialize + DeserializeOwned; type Commitment: Clone + Debug; @@ -29,11 +33,7 @@ pub trait PolynomialCommitmentScheme: Clone { fn setup(poly_size: usize) -> Self::Param; - fn commit_and_write( - pp: &Self::Param, - poly: &Self::Poly, - transcript: &mut Merlin, - ) -> Result; + fn commit(pp: &Self::Param, poly: &Self::Poly) -> Result; fn batch_commit( pp: &Self::Param, @@ -45,7 +45,6 @@ pub trait PolynomialCommitmentScheme: Clone { comm: Self::CommitmentWithWitness, point: &[E], eval: &E, - merlin: &mut Merlin, ) -> Result; /// This is a simple version of batch open: @@ -58,7 +57,6 @@ pub trait PolynomialCommitmentScheme: Clone { comm: Self::CommitmentWithWitness, point: &[E], evals: &[E], - transcript: &mut Merlin, ) -> Result; fn verify( @@ -67,7 +65,6 @@ pub trait PolynomialCommitmentScheme: Clone { point: &[E], eval: &E, proof: &Self::Proof, - transcript: &mut Arthur, ) -> Result<(), Error>; fn batch_verify( @@ -75,6 +72,5 @@ pub trait PolynomialCommitmentScheme: Clone { point: &[E], evals: &[E], proof: &Self::Proof, - transcript: &mut Arthur, ) -> Result<(), Error>; } diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 4dac522..4c8b991 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -17,8 +17,9 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; -pub use nimue::{Arthur, DefaultHash, Merlin}; -use nimue::{IOPattern, ProofResult}; +use nimue::plugins::ark::{FieldChallenges, FieldWriter}; +pub use nimue::DefaultHash; +use nimue::IOPattern; use nimue_pow::blake3::Blake3PoW; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -60,13 +61,6 @@ type MerkleConfigOf = <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; type ConfigOf = WhirConfig, PowOf>; -pub fn add_digest_to_merlin>( - merlin: &mut Merlin, - digest: InnerDigestOf, -) -> ProofResult<()> { - >::add_digest_to_merlin(merlin, digest) -} - pub type InnerDigestOf = as Config>::InnerDigest; type PowOf = @@ -211,16 +205,18 @@ where } } - fn commit_and_write( - pp: &Self::Param, - poly: &Self::Poly, - merlin: &mut Merlin, - ) -> Result { + fn commit(pp: &Self::Param, poly: &Self::Poly) -> Result { let params = Spec::prepare_whir_config(pp.num_variables); + // The merlin here is just for satisfying the interface of + // WHIR, which only provides a commit_and_write function. + // It will be abandoned once this function finishes. + let io = Spec::prepare_io_pattern(pp.num_variables); + let mut merlin = io.to_merlin(); + let committer = Committer::new(params); let witness = - Spec::MerkleConfigWrapper::commit_to_merlin(&committer, merlin, poly.clone())?; + Spec::MerkleConfigWrapper::commit_to_merlin(&committer, &mut merlin, poly.clone())?; Ok(CommitmentWithWitness { commitment: witness.merkle_tree.root(), @@ -240,9 +236,33 @@ where witness: Self::CommitmentWithWitness, point: &[E], eval: &E, - merlin: &mut Merlin, ) -> Result { let params = Spec::prepare_whir_config(pp.num_variables); + let io = Spec::prepare_io_pattern(pp.num_variables); + let mut merlin = io.to_merlin(); + // In WHIR, the prover writes the commitment to the transcript, then + // the commitment is read from the transcript by the verifier, after + // the transcript is transformed into a arthur transcript. + // Here we repeat whatever the prover does. + // TODO: This is a hack. There should be a better design that does not + // require non-black-box knowledge of the inner working of WHIR. + + >::add_digest_to_merlin( + &mut merlin, + witness.commitment.clone(), + ) + .map_err(Error::ProofError)?; + let ood_answers = witness.ood_answers(); + if ood_answers.len() > 0 { + let mut ood_points = vec![::ZERO; ood_answers.len()]; + merlin + .fill_challenge_scalars(&mut ood_points) + .map_err(Error::ProofError)?; + merlin + .add_scalars(&ood_answers) + .map_err(Error::ProofError)?; + } + // Now the Merlin transcript is ready to pass to the verifier. let prover = Prover(params); let statement = Statement { @@ -252,7 +272,7 @@ where let proof = Spec::MerkleConfigWrapper::prove_with_merlin( &prover, - merlin, + &mut merlin, statement, witness.witness, )?; @@ -269,7 +289,6 @@ where _comm: Self::CommitmentWithWitness, _point: &[E], _evals: &[E], - _transcript: &mut Merlin, ) -> Result { todo!() } @@ -280,10 +299,11 @@ where point: &[E], eval: &E, proof: &Self::Proof, - arthur: &mut Arthur, ) -> Result<(), Error> { let params = Spec::prepare_whir_config(vp.num_variables); let verifier = Verifier::new(params); + let io = Spec::prepare_io_pattern(vp.num_variables); + let mut arthur = io.to_arthur(&proof.transcript); let statement = Statement { points: vec![MultilinearPoint(point.to_vec())], @@ -292,7 +312,7 @@ where let digest = Spec::MerkleConfigWrapper::verify_with_arthur( &verifier, - arthur, + &mut arthur, &statement, &proof.proof, )?; @@ -309,7 +329,6 @@ where _point: &[E], _evals: &[E], _proof: &Self::Proof, - _transcript: &mut Arthur, ) -> Result<(), Error> { todo!() } From 069437dcea224d845872f63ea54242efeb8a181d Mon Sep 17 00:00:00 2001 From: Yuncong Zhang Date: Mon, 6 Jan 2025 10:01:58 +0800 Subject: [PATCH 21/21] Revert some formats --- .gitignore | 1 + src/crypto/merkle_tree/blake3.rs | 8 +++----- src/lib.rs | 1 - src/sumcheck/prover_single.rs | 2 -- src/whir/committer.rs | 2 +- src/whir/iopattern.rs | 1 - src/whir/mod.rs | 2 +- src/whir/verifier.rs | 18 ++++-------------- 8 files changed, 10 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 3825e56..83fff18 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ scripts/__pycache__/ .DS_Store outputs/ .idea +.vscode \ No newline at end of file diff --git a/src/crypto/merkle_tree/blake3.rs b/src/crypto/merkle_tree/blake3.rs index e47c7e2..c2b3952 100644 --- a/src/crypto/merkle_tree/blake3.rs +++ b/src/crypto/merkle_tree/blake3.rs @@ -10,9 +10,7 @@ use ark_crypto_primitives::{ }; use ark_ff::Field; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use nimue::{ - Arthur, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError, ProofResult, -}; +use nimue::{Arthur, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError, ProofResult}; use rand::RngCore; use serde::{Deserialize, Serialize}; @@ -141,7 +139,7 @@ impl DigestIOPattern> for IOPattern { } } -impl DigestWriter> for Merlin { +impl DigestWriter> for Merlin { fn add_digest(&mut self, digest: Blake3Digest) -> ProofResult<()> { self.add_bytes(&digest.0).map_err(ProofError::InvalidIO) } @@ -153,4 +151,4 @@ impl<'a, F: Field> DigestReader> for Arthur<'a> { self.fill_next_bytes(&mut digest)?; Ok(Blake3Digest(digest)) } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f67017c..9ba03f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(trait_alias)] #[cfg(feature = "ceno")] pub mod ceno_binding; // Connect whir with ceno pub mod cmdline_utils; diff --git a/src/sumcheck/prover_single.rs b/src/sumcheck/prover_single.rs index ab6cbb8..f78c592 100644 --- a/src/sumcheck/prover_single.rs +++ b/src/sumcheck/prover_single.rs @@ -101,8 +101,6 @@ where let eval_1 = c0 + c1 + c2; let eval_2 = eval_1 + c1 + c2 + c2.double(); - assert_eq!(self.sum, eval_0 + eval_1); - SumcheckPolynomial::new(vec![eval_0, eval_1, eval_2], 1) } diff --git a/src/whir/committer.rs b/src/whir/committer.rs index d7b0932..dd1d532 100644 --- a/src/whir/committer.rs +++ b/src/whir/committer.rs @@ -38,7 +38,7 @@ where impl Committer where F: FftField, - MerkleConfig: Config, + MerkleConfig: Config { pub fn new(config: WhirConfig) -> Self { Self(config) diff --git a/src/whir/iopattern.rs b/src/whir/iopattern.rs index b31cc5a..649dda8 100644 --- a/src/whir/iopattern.rs +++ b/src/whir/iopattern.rs @@ -1,7 +1,6 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use nimue::plugins::ark::*; -pub use nimue::{Arthur, IOPattern, Merlin}; use crate::{ fs_utils::{OODIOPattern, WhirPoWIOPattern}, diff --git a/src/whir/mod.rs b/src/whir/mod.rs index d228a99..6033eeb 100644 --- a/src/whir/mod.rs +++ b/src/whir/mod.rs @@ -4,11 +4,11 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use crate::poly_utils::MultilinearPoint; pub mod committer; -pub mod fs_utils; pub mod iopattern; pub mod parameters; pub mod prover; pub mod verifier; +pub mod fs_utils; #[derive(Debug, Clone, Default)] pub struct Statement { diff --git a/src/whir/verifier.rs b/src/whir/verifier.rs index 37585e1..1ea17d7 100644 --- a/src/whir/verifier.rs +++ b/src/whir/verifier.rs @@ -4,8 +4,8 @@ use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_poly::EvaluationDomain; use nimue::{ - plugins::ark::{FieldChallenges, FieldReader}, - ByteChallenges, ByteReader, ProofError, ProofResult, + plugins::ark::{FieldChallenges, FieldReader} + , ByteChallenges, ByteReader, ProofError, ProofResult, }; use nimue_pow::{self, PoWChallenge}; @@ -106,12 +106,7 @@ where whir_proof: &WhirProof, ) -> ProofResult> where - Arthur: FieldReader - + FieldChallenges - + PoWChallenge - + ByteReader - + ByteChallenges - + DigestReader, + Arthur: FieldReader + FieldChallenges + PoWChallenge + ByteReader + ByteChallenges + DigestReader, { let mut sumcheck_rounds = Vec::new(); let mut folding_randomness: MultilinearPoint; @@ -474,12 +469,7 @@ where whir_proof: &WhirProof, ) -> ProofResult where - Arthur: FieldChallenges - + FieldReader - + ByteChallenges - + ByteReader - + PoWChallenge - + DigestReader, + Arthur: FieldChallenges + FieldReader + ByteChallenges + ByteReader + PoWChallenge + DigestReader, { // We first do a pass in which we rederive all the FS challenges // Then we will check the algebraic part (so to optimise inversions)