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/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/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 5d7e5f4..6b39758 100644 --- a/src/ceno_binding/mod.rs +++ b/src/ceno_binding/mod.rs @@ -1,41 +1,50 @@ +mod merkle_config; mod pcs; +pub use ark_crypto_primitives::merkle_tree::Config; +pub use pcs::{DefaultHash, InnerDigestOf, Whir, WhirDefaultSpec, WhirSpec}; use ark_ff::FftField; 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}; +pub use nimue::ProofResult; + +#[derive(Debug, Clone, thiserror::Error)] pub enum Error { #[error(transparent)] ProofError(#[from] nimue::ProofError), + #[error("CommitmentMismatchFromDigest")] + 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; - type CommitmentWithData; - type Proof: Clone + CanonicalSerialize + CanonicalDeserialize; - type Poly: Clone; - type Transcript; + 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; fn setup(poly_size: usize) -> Self::Param; - fn commit_and_write( - pp: &Self::Param, - poly: &Self::Poly, - transcript: &mut Self::Transcript, - ) -> Result; + fn commit(pp: &Self::Param, poly: &Self::Poly) -> 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, ) -> Result; /// This is a simple version of batch open: @@ -45,18 +54,17 @@ 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, ) -> Result; fn verify( vp: &Self::Param, + comm: &Self::Commitment, point: &[E], eval: &E, proof: &Self::Proof, - transcript: &Self::Transcript, ) -> Result<(), Error>; fn batch_verify( @@ -64,6 +72,5 @@ pub trait PolynomialCommitmentScheme: Clone { point: &[E], evals: &[E], proof: &Self::Proof, - transcript: &mut Self::Transcript, ) -> Result<(), Error>; } diff --git a/src/ceno_binding/pcs.rs b/src/ceno_binding/pcs.rs index 12d1496..4c8b991 100644 --- a/src/ceno_binding/pcs.rs +++ b/src/ceno_binding/pcs.rs @@ -1,136 +1,326 @@ +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::{ committer::{Committer, Witness}, - iopattern::WhirIOPattern, parameters::WhirConfig, prover::Prover, verifier::Verifier, Statement, WhirProof, }; +use ark_crypto_primitives::merkle_tree::Config; use ark_ff::FftField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use nimue::{DefaultHash, IOPattern, Merlin}; +use ark_std::log2; +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; -use std::fmt::Debug; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; -#[derive(Debug, Clone)] -pub struct Whir(PhantomData); +pub trait WhirSpec: Default + std::fmt::Debug + Clone { + type MerkleConfigWrapper: WhirMerkleConfigWrapper; + fn get_parameters( + num_variables: usize, + ) -> WhirParameters, PowOf>; -type MerkleConfig = MerkleTreeParams; -type PowStrategy = Blake3PoW; -type WhirPCSConfig = WhirConfig, PowStrategy>; + fn prepare_whir_config( + num_variables: usize, + ) -> WhirConfig, PowOf> { + let whir_params = Self::get_parameters(num_variables); + let mv_params = MultivariateParameters::new(num_variables); + ConfigOf::::new(mv_params, whir_params) + } -impl PolynomialCommitmentScheme for Whir -where - E: FftField + CanonicalSerialize + CanonicalDeserialize, -{ - type Param = WhirPCSConfig; - type CommitmentWithData = Witness>; - type Proof = WhirProof, E>; - // TODO: support both base and extension fields - type Poly = CoefficientList; - type Transcript = Merlin; + fn prepare_io_pattern(num_variables: usize) -> IOPattern { + let params = Self::prepare_whir_config(num_variables); - 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 io = IOPattern::::new("🌪️"); + let io = >::commit_statement_to_io_pattern( + io, ¶ms, + ); + let io = + >::add_whir_proof_to_io_pattern( + io, ¶ms, + ); - let (leaf_hash_params, two_to_one_params) = mt::default_config::(&mut rng); + io + } +} + +type MerkleConfigOf = + <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::MerkleConfig; +type ConfigOf = WhirConfig, PowOf>; - let whir_params = WhirParameters::, PowStrategy> { +pub type InnerDigestOf = as Config>::InnerDigest; + +type PowOf = + <>::MerkleConfigWrapper as WhirMerkleConfigWrapper>::PowStrategy; + +#[derive(Debug, Clone, Default)] +pub struct WhirDefaultSpec; + +impl WhirSpec for WhirDefaultSpec { + type MerkleConfigWrapper = Blake3ConfigWrapper; + 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::, Blake3PoW> { initial_statement: true, security_level: 100, - pow_bits, + 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: starting_rate, - }; - WhirConfig::, PowStrategy>::new(mv_params, whir_params) + starting_log_inv_rate: 1, + } } +} - fn commit_and_write( - pp: &Self::Param, - poly: &Self::Poly, - transcript: &mut Self::Transcript, - ) -> Result { - let committer = Committer::new(pp.clone()); - let witness = committer.commit(transcript, poly.clone())?; - Ok(witness) +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WhirSetupParams { + pub num_variables: usize, + _phantom: PhantomData, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Whir>(PhantomData<(E, Spec)>); + +// Wrapper for WhirProof +#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] +pub struct WhirProofWrapper +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + pub proof: WhirProof, + pub transcript: Vec, +} + +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.proof.0; + // Create a buffer that implements the `Write` trait + let mut buffer = Vec::new(); + proof.serialize_compressed(&mut buffer).unwrap(); + 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) + } +} + +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>, + { + 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 }) + } +} + +impl Debug for WhirProofWrapper +where + MerkleConfig: Config, + F: Sized + Clone + CanonicalSerialize + CanonicalDeserialize, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("WhirProofWrapper") + } +} + +#[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, + E::BasePrimeField: Serialize + DeserializeOwned + Debug, +{ + type Param = WhirSetupParams; + type Commitment = as Config>::InnerDigest; + type CommitmentWithWitness = CommitmentWithWitness>; + type Proof = WhirProofWrapper, E>; + type Poly = CoefficientList; + + fn setup(poly_size: usize) -> Self::Param { + WhirSetupParams { + num_variables: log2(poly_size) as usize, + _phantom: PhantomData, + } + } + + 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, &mut merlin, poly.clone())?; + + Ok(CommitmentWithWitness { + commitment: witness.merkle_tree.root(), + 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.clone()); + 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 { points: vec![MultilinearPoint(point.to_vec())], evaluations: vec![eval.clone()], }; - let proof = prover.prove(transcript, statement, witness)?; - Ok(proof) + let proof = Spec::MerkleConfigWrapper::prove_with_merlin( + &prover, + &mut merlin, + statement, + witness.witness, + )?; + + Ok(WhirProofWrapper { + proof, + transcript: merlin.transcript().to_vec(), + }) } fn batch_open( _pp: &Self::Param, _polys: &[Self::Poly], - _comm: Self::CommitmentWithData, + _comm: Self::CommitmentWithWitness, _point: &[E], _evals: &[E], - _transcript: &mut Self::Transcript, ) -> Result { todo!() } fn verify( vp: &Self::Param, + comm: &Self::Commitment, point: &[E], eval: &E, proof: &Self::Proof, - transcript: &Self::Transcript, ) -> Result<(), Error> { - // TODO: determine reps by security bits - let reps = 1000; - let verifier = Verifier::new(vp.clone()); - let io = IOPattern::::new("🌪️") - .commit_statement(&vp) - .add_whir_proof(&vp); + 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())], evaluations: vec![eval.clone()], }; - for _ in 0..reps { - let mut arthur = io.to_arthur(transcript.transcript()); - verifier.verify(&mut arthur, &statement, proof)?; + let digest = Spec::MerkleConfigWrapper::verify_with_arthur( + &verifier, + &mut arthur, + &statement, + &proof.proof, + )?; + + if &digest != comm { + return Err(Error::CommitmentMismatchFromDigest); } + Ok(()) } @@ -139,44 +329,7 @@ where _point: &[E], _evals: &[E], _proof: &Self::Proof, - _transcript: &mut Self::Transcript, ) -> Result<(), Error> { todo!() } } - -#[cfg(test)] -mod tests { - use ark_ff::Field; - use rand::Rng; - - use super::*; - use crate::crypto::fields::Field64_2 as F; - - #[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/crypto/merkle_tree/blake3.rs b/src/crypto/merkle_tree/blake3.rs index ddcce8f..c2b3952 100644 --- a/src/crypto/merkle_tree/blake3.rs +++ b/src/crypto/merkle_tree/blake3.rs @@ -12,6 +12,7 @@ use ark_ff::Field; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; 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 +107,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 { @@ -138,13 +139,13 @@ 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) } } -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)?; 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..dd1d532 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,11 +17,13 @@ use crate::whir::fs_utils::DigestWriter; #[cfg(feature = "parallel")] use rayon::prelude::*; +#[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/mod.rs b/src/whir/mod.rs index 7db951b..6033eeb 100644 --- a/src/whir/mod.rs +++ b/src/whir/mod.rs @@ -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; diff --git a/src/whir/parameters.rs b/src/whir/parameters.rs index 7a9d711..777ecfa 100644 --- a/src/whir/parameters.rs +++ b/src/whir/parameters.rs @@ -1,8 +1,10 @@ -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}; use ark_ff::FftField; +use serde::{Deserialize, Serialize}; use crate::{ crypto::fields::FieldWithSize, @@ -10,7 +12,7 @@ use crate::{ parameters::{FoldType, MultivariateParameters, SoundnessType, WhirParameters}, }; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct WhirConfig where F: FftField, @@ -41,11 +43,13 @@ 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, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct RoundConfig { pub(crate) pow_bits: f64, pub(crate) folding_pow_bits: f64, @@ -437,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, @@ -451,7 +455,7 @@ where self.starting_folding_pow_bits )?; for r in &self.round_parameters { - r.fmt(f)?; + fmt::Display::fmt(&r, f)?; } writeln!( diff --git a/src/whir/verifier.rs b/src/whir/verifier.rs index 115cfdb..1ea17d7 100644 --- a/src/whir/verifier.rs +++ b/src/whir/verifier.rs @@ -467,7 +467,7 @@ where arthur: &mut Arthur, statement: &Statement, whir_proof: &WhirProof, - ) -> ProofResult<()> + ) -> ProofResult where Arthur: FieldChallenges + FieldReader + ByteChallenges + ByteReader + PoWChallenge + DigestReader, { @@ -602,6 +602,6 @@ where return Err(ProofError::InvalidProof); } - Ok(()) + Ok(parsed_commitment.root) } }