diff --git a/src/backends/plonky2/circuits/mainpod.rs b/src/backends/plonky2/circuits/mainpod.rs index 50db6ee..de8b06e 100644 --- a/src/backends/plonky2/circuits/mainpod.rs +++ b/src/backends/plonky2/circuits/mainpod.rs @@ -492,10 +492,14 @@ impl MainPodVerifyTarget { self.statements[i].set_targets(pw, &self.params, st)?; self.operations[i].set_targets(pw, &self.params, op)?; } - assert_eq!(input.merkle_proofs.len(), self.params.max_merkle_proofs); + assert!(input.merkle_proofs.len() <= self.params.max_merkle_proofs); for (i, mp) in input.merkle_proofs.iter().enumerate() { - assert_eq!(mp.proof.siblings.len(), self.params.max_depth_mt_gadget); - self.merkle_proofs[i].set_targets(pw, mp)?; + self.merkle_proofs[i].set_targets(pw, true, mp)?; + } + // Padding + let pad_mp = MerkleClaimAndProof::empty(); + for i in input.merkle_proofs.len()..self.params.max_merkle_proofs { + self.merkle_proofs[i].set_targets(pw, false, &pad_mp)?; } Ok(()) } @@ -579,7 +583,7 @@ mod tests { for (merkle_proof_target, merkle_proof) in merkle_proofs_target.iter().zip(merkle_proofs.iter()) { - merkle_proof_target.set_targets(&mut pw, &merkle_proof)? + merkle_proof_target.set_targets(&mut pw, true, &merkle_proof)? } // generate & verify proof @@ -707,12 +711,11 @@ mod tests { ); let merkle_proofs = vec![MerkleClaimAndProof::new( - params.max_depth_mt_gadget, Hash::from(root.raw()), key, None, - &no_key_pf, - )?]; + no_key_pf, + )]; let prev_statements = vec![root_st, key_st]; operation_verify(st, op, prev_statements, merkle_proofs.clone())?; diff --git a/src/backends/plonky2/circuits/signedpod.rs b/src/backends/plonky2/circuits/signedpod.rs index e421f9c..1bd9c6d 100644 --- a/src/backends/plonky2/circuits/signedpod.rs +++ b/src/backends/plonky2/circuits/signedpod.rs @@ -134,13 +134,8 @@ impl SignedPodVerifyTarget { let (v, proof) = pod.dict.prove(k)?; self.mt_proofs[i].set_targets( pw, - &MerkleClaimAndProof::new( - self.params.max_depth_mt_gadget, - pod.dict.commitment(), - k.raw(), - Some(v.raw()), - &proof, - )?, + true, + &MerkleClaimAndProof::new(pod.dict.commitment(), k.raw(), Some(v.raw()), proof), )?; Ok(v) }) @@ -160,13 +155,8 @@ impl SignedPodVerifyTarget { self.mt_proofs[curr].set_targets( pw, - &MerkleClaimAndProof::new( - self.params.max_depth_mt_gadget, - pod.dict.commitment(), - k.raw(), - Some(v.raw()), - &proof, - )?, + true, + &MerkleClaimAndProof::new(pod.dict.commitment(), k.raw(), Some(v.raw()), proof), )?; curr += 1; } @@ -174,10 +164,10 @@ impl SignedPodVerifyTarget { assert!(curr <= self.params.max_signed_pod_values); // add the proofs of empty leaves (if needed), till the max_signed_pod_values - let mut mp = MerkleClaimAndProof::empty(self.params.max_depth_mt_gadget); + let mut mp = MerkleClaimAndProof::empty(); mp.root = pod.dict.commitment(); for i in curr..self.params.max_signed_pod_values { - self.mt_proofs[i].set_targets(pw, &mp)?; + self.mt_proofs[i].set_targets(pw, false, &mp)?; } // get the signer pk diff --git a/src/backends/plonky2/mainpod/mod.rs b/src/backends/plonky2/mainpod/mod.rs index 2093f3b..d372e10 100644 --- a/src/backends/plonky2/mainpod/mod.rs +++ b/src/backends/plonky2/mainpod/mod.rs @@ -19,7 +19,7 @@ use crate::{ backends::plonky2::{ basetypes::{C, D}, circuits::mainpod::{MainPodVerifyCircuit, MainPodVerifyInput}, - primitives::{merkletree, merkletree::MerkleClaimAndProof}, + primitives::merkletree::MerkleClaimAndProof, signedpod::SignedPod, }, middleware::{ @@ -42,7 +42,7 @@ pub(crate) fn extract_merkle_proofs( params: &Params, operations: &[middleware::Operation], ) -> Result> { - let mut merkle_proofs = operations + let merkle_proofs: Vec<_> = operations .iter() .flat_map(|op| match op { middleware::Operation::ContainsFromEntries( @@ -51,40 +51,32 @@ pub(crate) fn extract_merkle_proofs( middleware::Statement::ValueOf(_, value), pf, ) => Some(MerkleClaimAndProof::new( - params.max_depth_mt_gadget, Hash::from(root.raw()), key.raw(), Some(value.raw()), - pf, + pf.clone(), )), middleware::Operation::NotContainsFromEntries( middleware::Statement::ValueOf(_, root), middleware::Statement::ValueOf(_, key), pf, ) => Some(MerkleClaimAndProof::new( - params.max_depth_mt_gadget, Hash::from(root.raw()), key.raw(), None, - pf, + pf.clone(), )), _ => None, }) - .collect::>>()?; + .collect(); if merkle_proofs.len() > params.max_merkle_proofs { - Err(anyhow!( + return Err(anyhow!( "The number of required Merkle proofs ({}) exceeds the maximum number ({}).", merkle_proofs.len(), params.max_merkle_proofs - )) - } else { - fill_pad( - &mut merkle_proofs, - MerkleClaimAndProof::empty(params.max_depth_mt_gadget), - params.max_merkle_proofs, - ); - Ok(merkle_proofs) + )); } + Ok(merkle_proofs) } /// Find the operation argument statement in the list of previous statements and return the index. @@ -115,12 +107,7 @@ fn find_op_aux( middleware::OperationAux::MerkleProof(pf_arg) => merkle_proofs .iter() .enumerate() - .find_map(|(i, pf)| { - pf.clone() - .try_into() - .ok() - .and_then(|mid_pf: merkletree::MerkleProof| (&mid_pf == pf_arg).then_some(i)) - }) + .find_map(|(i, pf)| (pf.proof == *pf_arg).then_some(i)) .map(OperationAux::MerkleProofIndex) .ok_or(anyhow!( "Merkle proof corresponding to op arg {} not found", @@ -293,7 +280,6 @@ pub(crate) fn process_public_statements_operations( pub struct Prover {} impl PodProver for Prover { - // TODO: Be consistent on where we apply the padding, here, or in the set_targets? fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result> { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); diff --git a/src/backends/plonky2/mainpod/operation.rs b/src/backends/plonky2/mainpod/operation.rs index f3e3579..4ec408e 100644 --- a/src/backends/plonky2/mainpod/operation.rs +++ b/src/backends/plonky2/mainpod/operation.rs @@ -74,16 +74,15 @@ impl Operation { }) .collect::>>()?; let deref_aux = match self.2 { - OperationAux::None => Ok(crate::middleware::OperationAux::None), - OperationAux::MerkleProofIndex(i) => merkle_proofs - .get(i) - .cloned() - .ok_or(anyhow!("Missing Merkle proof index {}", i)) - .and_then(|mp| { - mp.try_into() - .map(crate::middleware::OperationAux::MerkleProof) - }), - }?; + OperationAux::None => crate::middleware::OperationAux::None, + OperationAux::MerkleProofIndex(i) => crate::middleware::OperationAux::MerkleProof( + merkle_proofs + .get(i) + .ok_or(anyhow!("Missing Merkle proof index {}", i))? + .proof + .clone(), + ), + }; middleware::Operation::op(self.0.clone(), &deref_args, &deref_aux) } } diff --git a/src/backends/plonky2/primitives/merkletree.rs b/src/backends/plonky2/primitives/merkletree.rs index c070e30..af0e5f5 100644 --- a/src/backends/plonky2/primitives/merkletree.rs +++ b/src/backends/plonky2/primitives/merkletree.rs @@ -1,10 +1,6 @@ //! Module that implements the MerkleTree specified at //! https://0xparc.github.io/pod2/merkletree.html . -use std::{ - collections::HashMap, - fmt, - iter::{self, IntoIterator}, -}; +use std::{collections::HashMap, fmt, iter::IntoIterator}; use anyhow::{anyhow, Result}; use plonky2::field::types::Field; @@ -266,94 +262,38 @@ impl MerkleProof { #[derive(Clone, Debug, PartialEq)] pub struct MerkleClaimAndProof { - /// `enabled` determines if the merkleproof verification is enabled - pub enabled: bool, pub root: Hash, pub key: RawValue, pub value: RawValue, - /// The siblings in this proof are padded to max_depth pub proof: MerkleProof, } impl MerkleClaimAndProof { - pub fn empty(max_depth: usize) -> Self { + pub fn empty() -> Self { Self { - enabled: false, root: EMPTY_HASH, key: EMPTY_VALUE, value: EMPTY_VALUE, proof: MerkleProof { existence: true, - siblings: iter::repeat(EMPTY_HASH).take(max_depth).collect(), + siblings: vec![], other_leaf: None, }, } } - pub fn new( - max_depth: usize, - root: Hash, - key: RawValue, - value: Option, - proof: &MerkleProof, - ) -> Result { - if proof.siblings.len() > max_depth { - Err(anyhow!( - "Number of siblings ({}) exceeds maximum depth ({})", - proof.siblings.len(), - max_depth - )) - } else { - Ok(Self { - enabled: true, - root, - key, - value: value.unwrap_or(EMPTY_VALUE), - proof: MerkleProof { - existence: proof.existence, - siblings: proof - .siblings - .iter() - .cloned() - .chain(iter::repeat(EMPTY_HASH)) - .take(max_depth) - .collect(), - other_leaf: proof.other_leaf, - }, - }) + pub fn new(root: Hash, key: RawValue, value: Option, proof: MerkleProof) -> Self { + Self { + root, + key, + value: value.unwrap_or(EMPTY_VALUE), + proof, } } } -impl TryFrom for MerkleProof { - type Error = anyhow::Error; - fn try_from(mp: MerkleClaimAndProof) -> Result { - if !mp.enabled { - return Err(anyhow!("Not a valid Merkle proof.")); - } - Ok(MerkleProof { - existence: mp.proof.existence, - // Trim padding (if any). - siblings: mp - .proof - .siblings - .into_iter() - .rev() - .skip_while(|s| s == &EMPTY_HASH) - .collect::>() - .into_iter() - .rev() - .collect(), - other_leaf: mp.proof.other_leaf, - }) - } -} - impl fmt::Display for MerkleClaimAndProof { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match MerkleProof::try_from(self.clone()) { - Err(_) => write!(f, "∅"), - Ok(mp) => mp.fmt(f), - } + self.proof.fmt(f) } } diff --git a/src/backends/plonky2/primitives/merkletree_circuit.rs b/src/backends/plonky2/primitives/merkletree_circuit.rs index ffbd896..68a24ba 100644 --- a/src/backends/plonky2/primitives/merkletree_circuit.rs +++ b/src/backends/plonky2/primitives/merkletree_circuit.rs @@ -158,15 +158,28 @@ impl MerkleProofGadget { impl MerkleClaimAndProofTarget { /// assigns the given values to the targets #[allow(clippy::too_many_arguments)] - pub fn set_targets(&self, pw: &mut PartialWitness, mp: &MerkleClaimAndProof) -> Result<()> { - pw.set_bool_target(self.enabled, mp.enabled)?; + pub fn set_targets( + &self, + pw: &mut PartialWitness, + enabled: bool, + mp: &MerkleClaimAndProof, + ) -> Result<()> { + pw.set_bool_target(self.enabled, enabled)?; pw.set_hash_target(self.root, HashOut::from_vec(mp.root.0.to_vec()))?; pw.set_target_arr(&self.key.elements, &mp.key.0)?; pw.set_target_arr(&self.value.elements, &mp.value.0)?; pw.set_bool_target(self.existence, mp.proof.existence)?; - assert_eq!(mp.proof.siblings.len(), self.max_depth); - for (i, sibling) in mp.proof.siblings.iter().enumerate() { + // pad siblings with zeros to length max_depth + assert!(mp.proof.siblings.len() <= self.max_depth); + for (i, sibling) in mp + .proof + .siblings + .iter() + .chain(iter::repeat(&EMPTY_HASH)) + .take(self.max_depth) + .enumerate() + { pw.set_hash_target(self.siblings[i], HashOut::from_vec(sibling.0.to_vec()))?; } @@ -250,18 +263,29 @@ impl MerkleProofExistenceGadget { impl MerkleProofExistenceTarget { /// assigns the given values to the targets - pub fn set_targets(&self, pw: &mut PartialWitness, mp: &MerkleClaimAndProof) -> Result<()> { + pub fn set_targets( + &self, + pw: &mut PartialWitness, + enabled: bool, + mp: &MerkleClaimAndProof, + ) -> Result<()> { assert!(mp.proof.existence); // sanity check - pw.set_bool_target(self.enabled, mp.enabled)?; + pw.set_bool_target(self.enabled, enabled)?; pw.set_hash_target(self.root, HashOut::from_vec(mp.root.0.to_vec()))?; pw.set_target_arr(&self.key.elements, &mp.key.0)?; pw.set_target_arr(&self.value.elements, &mp.value.0)?; // pad siblings with zeros to length max_depth - assert_eq!(mp.proof.siblings.len(), self.max_depth); - - for (i, sibling) in mp.proof.siblings.iter().enumerate() { + assert!(mp.proof.siblings.len() <= self.max_depth); + for (i, sibling) in mp + .proof + .siblings + .iter() + .chain(iter::repeat(&EMPTY_HASH)) + .take(self.max_depth) + .enumerate() + { pw.set_hash_target(self.siblings[i], HashOut::from_vec(sibling.0.to_vec()))?; } @@ -515,7 +539,8 @@ pub mod tests { let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; targets.set_targets( &mut pw, - &MerkleClaimAndProof::new(max_depth, tree.root(), key, Some(value), &proof)?, + true, + &MerkleClaimAndProof::new(tree.root(), key, Some(value), proof), )?; // generate & verify proof @@ -560,7 +585,8 @@ pub mod tests { let targets = MerkleProofExistenceGadget { max_depth }.eval(&mut builder)?; targets.set_targets( &mut pw, - &MerkleClaimAndProof::new(max_depth, tree.root(), key, Some(value), &proof)?, + true, + &MerkleClaimAndProof::new(tree.root(), key, Some(value), proof), )?; // generate & verify proof @@ -634,7 +660,8 @@ pub mod tests { let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; targets.set_targets( &mut pw, - &MerkleClaimAndProof::new(max_depth, tree.root(), key, Some(value), &proof)?, + true, + &MerkleClaimAndProof::new(tree.root(), key, Some(value), proof), )?; // generate & verify proof @@ -677,8 +704,8 @@ pub mod tests { let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; // verification enabled & proof of existence - let mut mp = MerkleClaimAndProof::new(max_depth, tree2.root(), key, Some(value), &proof)?; - targets.set_targets(&mut pw, &mp)?; + let mp = MerkleClaimAndProof::new(tree2.root(), key, Some(value), proof); + targets.set_targets(&mut pw, true, &mp)?; // generate proof, expecting it to fail (since we're using the wrong // root) @@ -693,8 +720,7 @@ pub mod tests { let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; // verification disabled & proof of existence - mp.enabled = false; - targets.set_targets(&mut pw, &mp)?; + targets.set_targets(&mut pw, false, &mp)?; // generate proof, should pass despite using wrong witness, since the // `enabled=false` diff --git a/src/backends/plonky2/primitives/signature_circuit.rs b/src/backends/plonky2/primitives/signature_circuit.rs index 82e2d76..f25ee43 100644 --- a/src/backends/plonky2/primitives/signature_circuit.rs +++ b/src/backends/plonky2/primitives/signature_circuit.rs @@ -176,7 +176,7 @@ pub mod tests { use crate::{backends::plonky2::primitives::signature::SecretKey, middleware::Hash}; #[test] - fn test_signature_gadget() -> Result<()> { + fn test_signature_gadget_enabled() -> Result<()> { // generate a valid signature let sk = SecretKey::new_rand(); let pk = sk.public_key();