diff --git a/src/backends/plonky2/basetypes.rs b/src/backends/plonky2/basetypes.rs index 3144ed4..d2b4850 100644 --- a/src/backends/plonky2/basetypes.rs +++ b/src/backends/plonky2/basetypes.rs @@ -36,3 +36,91 @@ pub type VerifierCircuitData = circuit_data::VerifierCircuitData; pub type CircuitBuilder = circuit_builder::CircuitBuilder; pub type Proof = proof::Proof; pub type ProofWithPublicInputs = proof::ProofWithPublicInputs; + +use std::{collections::HashMap, sync::LazyLock}; + +use itertools::Itertools; +use plonky2::hash::hash_types::HashOut; + +use crate::{ + backends::plonky2::{ + emptypod::STANDARD_EMPTY_POD_DATA, primitives::merkletree::MerkleClaimAndProof, + DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA, + }, + middleware::{containers::Array, Hash, RawValue, Result, Value}, +}; + +pub static DEFAULT_VD_SET: LazyLock = LazyLock::new(|| { + let params = &*DEFAULT_PARAMS; + + let vds = vec![ + STANDARD_REC_MAIN_POD_CIRCUIT_DATA.verifier_only.clone(), + STANDARD_EMPTY_POD_DATA.1.verifier_only.clone(), + ]; + VDSet::new(params.max_depth_mt_vds, &vds).unwrap() +}); + +/// VDSet is the set of the allowed verifier_data hashes. When proving a +/// MainPod, the circuit will enforce that all the used verifier_datas for +/// verifying the recursive proofs of previous PODs appears in the VDSet. +/// The VDSet struct that allows to get the specific merkle proofs for the given +/// verifier_data. +#[derive(Clone, Debug)] +pub struct VDSet { + root: Hash, + // (verifier_data, merkleproof) + proofs_map: HashMap, MerkleClaimAndProof>, +} +impl VDSet { + /// builds the verifier_datas tree, and returns the root and the proofs + pub fn new(tree_depth: usize, vds: &[VerifierOnlyCircuitData]) -> Result { + // first of all, sort the vds, so that each set of verifier_datas gets + // the same root + let vds: Vec<&VerifierOnlyCircuitData> = vds + .iter() + .sorted_by_key(|vd| RawValue(vd.circuit_digest.elements)) + .collect::>(); + + let array = Array::new( + tree_depth, + vds.iter() + .map(|vd| Value::from(RawValue(vd.circuit_digest.elements))) + .collect(), + )?; + + let root = array.commitment(); + let mut proofs_map = HashMap::, MerkleClaimAndProof>::new(); + + for (i, vd) in vds.iter().enumerate() { + let (value, proof) = array.prove(i)?; + let p = MerkleClaimAndProof { + root, + key: RawValue::from(i as i64), + value: value.raw(), + proof, + }; + proofs_map.insert(vd.circuit_digest, p); + } + Ok(Self { root, proofs_map }) + } + pub fn root(&self) -> Hash { + self.root + } + /// returns the vector of merkle proofs corresponding to the given verifier_datas + pub fn get_vds_proofs( + &self, + vds: &[VerifierOnlyCircuitData], + ) -> Result> { + let mut proofs: Vec = vec![]; + for vd in vds { + let p = + self.proofs_map + .get(&vd.circuit_digest) + .ok_or(crate::middleware::Error::custom( + "verifier_data not found in VDSet".to_string(), + ))?; + proofs.push(p.clone()); + } + Ok(proofs) + } +} diff --git a/src/backends/plonky2/circuits/common.rs b/src/backends/plonky2/circuits/common.rs index 1d3ea88..2861e3f 100644 --- a/src/backends/plonky2/circuits/common.rs +++ b/src/backends/plonky2/circuits/common.rs @@ -40,7 +40,7 @@ use crate::{ pub const CODE_SIZE: usize = HASH_SIZE + 2; const NUM_BITS: usize = 32; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct ValueTarget { pub elements: [Target; VALUE_SIZE], } diff --git a/src/backends/plonky2/circuits/mainpod.rs b/src/backends/plonky2/circuits/mainpod.rs index 6bca77c..685f065 100644 --- a/src/backends/plonky2/circuits/mainpod.rs +++ b/src/backends/plonky2/circuits/mainpod.rs @@ -17,7 +17,7 @@ use plonky2::{ use crate::{ backends::plonky2::{ - basetypes::CircuitBuilder, + basetypes::{CircuitBuilder, VDSet}, circuits::{ common::{ CircuitBuilderPod, CustomPredicateBatchTarget, CustomPredicateEntryTarget, @@ -28,7 +28,7 @@ use crate::{ }, signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget}, }, - emptypod::EmptyPod, + emptypod::{EmptyPod, STANDARD_EMPTY_POD_DATA}, error::Result, mainpod::{self, pad_statement}, primitives::merkletree::{ @@ -39,10 +39,9 @@ use crate::{ }, measure_gates_begin, measure_gates_end, middleware::{ - AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Hash, - NativeOperation, NativePredicate, Params, PodType, PredicatePrefix, Statement, - StatementArg, ToFields, Value, WildcardValue, EMPTY_VALUE, F, HASH_SIZE, KEY_TYPE, SELF, - VALUE_SIZE, + AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, NativeOperation, + NativePredicate, Params, PodType, PredicatePrefix, Statement, StatementArg, ToFields, + Value, WildcardValue, EMPTY_VALUE, F, HASH_SIZE, KEY_TYPE, SELF, VALUE_SIZE, }, }; @@ -1220,9 +1219,31 @@ impl MainPodVerifyGadget { } let vds_root = builder.add_virtual_hash(); - // TODO: verify that all input pod proofs use verifier data from the public input VD array - // This requires merkle proofs - // https://github.com/0xPARC/pod2/issues/250 + + // verify that all input pod proofs use verifier data from the public input VD array This + // requires merkle proofs + let mut vd_mt_proofs: Vec = vec![]; + for verified_proof in verified_proofs { + // add target for the vd_mt_proof + let vd_mt_proof = MerkleProofGadget { + max_depth: params.max_depth_mt_vds, + } + .eval(builder); + + // ensure that mt_proof is enabled + let true_targ = builder._true(); + builder.connect(vd_mt_proof.enabled.target, true_targ.target); + // connect the vd_mt_proof's root to the actual vds_root, to ensure that the mt proof + // verifies against the vds_root + builder.connect_hashes(vds_root, vd_mt_proof.root); + // connect vd_mt_proof's value with the verified_proof.verifier_data_hash + builder.connect_hashes( + verified_proof.verifier_data_hash, + HashOutTarget::from_vec(vd_mt_proof.value.elements.to_vec()), + ); + + vd_mt_proofs.push(vd_mt_proof); + } // Verify that VD array that input pod uses is the same we use now. for verified_proof in verified_proofs { @@ -1247,11 +1268,11 @@ impl MainPodVerifyGadget { // Add Merkle claim/proof targets let mp_gadget = MerkleProofGadget { - max_depth: params.max_depth_mt_gadget, + max_depth: params.max_depth_mt_containers, }; - let merkle_proofs: Vec<_> = (0..params.max_merkle_proofs) + let merkle_proofs: Vec<_> = (0..params.max_merkle_proofs_containers) .map(|_| mp_gadget.eval(builder)) - .collect::>()?; + .collect(); let merkle_claims: Vec<_> = merkle_proofs .clone() .into_iter() @@ -1310,6 +1331,7 @@ impl MainPodVerifyGadget { Ok(MainPodVerifyTarget { params: params.clone(), vds_root, + vd_mt_proofs, id, signed_pods, input_pods_self_statements, @@ -1325,6 +1347,7 @@ impl MainPodVerifyGadget { pub struct MainPodVerifyTarget { params: Params, vds_root: HashOutTarget, + vd_mt_proofs: Vec, id: HashOutTarget, signed_pods: Vec, input_pods_self_statements: Vec>, @@ -1344,7 +1367,11 @@ pub struct CustomPredicateVerification { } pub struct MainPodVerifyInput { - pub vds_root: Hash, + pub vds_set: VDSet, + // field containing the `vd_mt_proofs` aside from the `vds_set`, because + // inide the MainPodVerifyTarget circuit, since it is the InnerCircuit for + // the RecursiveCircuit, we don't have access to the used verifier_datas. + pub vd_mt_proofs: Vec, pub signed_pods: Vec, pub recursive_pods_pub_self_statements: Vec>, pub statements: Vec, @@ -1378,13 +1405,58 @@ fn set_targets_input_pods_self_statements( Ok(()) } -impl MainPodVerifyTarget { - pub fn set_targets( +pub struct MainPodVerifyCircuit { + pub params: Params, +} + +// TODO: Remove this type and implement it's logic directly in `impl InnerCircuit for MainPodVerifyTarget` +impl MainPodVerifyCircuit { + pub fn eval( &self, - pw: &mut PartialWitness, - input: &MainPodVerifyInput, - ) -> Result<()> { - pw.set_target_arr(&self.vds_root.elements, &input.vds_root.0)?; + builder: &mut CircuitBuilder, + verified_proofs: &[VerifiedProofTarget], + ) -> Result { + let main_pod = MainPodVerifyGadget { + params: self.params.clone(), + } + .eval(builder, verified_proofs)?; + builder.register_public_inputs(&main_pod.id.elements); + builder.register_public_inputs(&main_pod.vds_root.elements); + Ok(main_pod) + } +} + +impl InnerCircuit for MainPodVerifyTarget { + type Input = MainPodVerifyInput; + type Params = Params; + + fn build( + builder: &mut CircuitBuilder, + params: &Self::Params, + verified_proofs: &[VerifiedProofTarget], + ) -> Result { + MainPodVerifyCircuit { + params: params.clone(), + } + .eval(builder, verified_proofs) + } + + /// assigns the values to the targets + fn set_targets(&self, pw: &mut PartialWitness, input: &Self::Input) -> Result<()> { + let vds_root = input.vds_set.root(); + pw.set_target_arr(&self.vds_root.elements, &vds_root.0)?; + + for (i, vd_mt_proof) in input.vd_mt_proofs.iter().enumerate() { + self.vd_mt_proofs[i].set_targets(pw, true, vd_mt_proof)?; + } + // the rest of vd_mt_proofs set them to the empty_pod vd_mt_proof + let vd_emptypod_mt_proof = input + .vds_set + .get_vds_proofs(&[STANDARD_EMPTY_POD_DATA.1.verifier_only.clone()])?; + let vd_emptypod_mt_proof = vd_emptypod_mt_proof[0].clone(); + for i in input.vd_mt_proofs.len()..self.vd_mt_proofs.len() { + self.vd_mt_proofs[i].set_targets(pw, true, &vd_emptypod_mt_proof)?; + } assert!(input.signed_pods.len() <= self.params.max_input_signed_pods); for (i, signed_pod) in input.signed_pods.iter().enumerate() { @@ -1414,7 +1486,7 @@ impl MainPodVerifyTarget { } // Padding if input.recursive_pods_pub_self_statements.len() != self.params.max_input_recursive_pods { - let empty_pod = EmptyPod::new_boxed(&self.params, input.vds_root); + let empty_pod = EmptyPod::new_boxed(&self.params, input.vds_set.root()); let empty_pod_statements = empty_pod.pub_statements(); for i in input.recursive_pods_pub_self_statements.len()..self.params.max_input_recursive_pods @@ -1434,13 +1506,13 @@ impl MainPodVerifyTarget { self.operations[i].set_targets(pw, &self.params, op)?; } - assert!(input.merkle_proofs.len() <= self.params.max_merkle_proofs); + assert!(input.merkle_proofs.len() <= self.params.max_merkle_proofs_containers); for (i, mp) in input.merkle_proofs.iter().enumerate() { 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 { + for i in input.merkle_proofs.len()..self.params.max_merkle_proofs_containers { self.merkle_proofs[i].set_targets(pw, false, &pad_mp)?; } @@ -1487,48 +1559,6 @@ impl MainPodVerifyTarget { } } -pub struct MainPodVerifyCircuit { - pub params: Params, -} - -// TODO: Remove this type and implement it's logic directly in `impl InnerCircuit for MainPodVerifyTarget` -impl MainPodVerifyCircuit { - pub fn eval( - &self, - builder: &mut CircuitBuilder, - verified_proofs: &[VerifiedProofTarget], - ) -> Result { - let main_pod = MainPodVerifyGadget { - params: self.params.clone(), - } - .eval(builder, verified_proofs)?; - builder.register_public_inputs(&main_pod.id.elements); - builder.register_public_inputs(&main_pod.vds_root.elements); - Ok(main_pod) - } -} - -impl InnerCircuit for MainPodVerifyTarget { - type Input = MainPodVerifyInput; - type Params = Params; - - fn build( - builder: &mut CircuitBuilder, - params: &Self::Params, - verified_proofs: &[VerifiedProofTarget], - ) -> Result { - MainPodVerifyCircuit { - params: params.clone(), - } - .eval(builder, verified_proofs) - } - - /// assigns the values to the targets - fn set_targets(&self, pw: &mut PartialWitness, input: &Self::Input) -> Result<()> { - self.set_targets(pw, input) - } -} - #[cfg(test)] mod tests { use std::{iter, ops::Not}; @@ -1567,7 +1597,7 @@ mod tests { ..Default::default() }; let mp_gadget = MerkleProofGadget { - max_depth: params.max_depth_mt_gadget, + max_depth: params.max_depth_mt_containers, }; let config = CircuitConfig::standard_recursion_config(); @@ -1581,7 +1611,7 @@ mod tests { let merkle_proofs_target: Vec<_> = merkle_proofs .iter() .map(|_| mp_gadget.eval(&mut builder)) - .collect::>()?; + .collect(); let merkle_claims_target: Vec<_> = merkle_proofs_target .clone() .into_iter() @@ -2360,7 +2390,7 @@ mod tests { ] .into_iter() .collect(); - let mt = MerkleTree::new(params.max_depth_mt_gadget, &kvs)?; + let mt = MerkleTree::new(params.max_depth_mt_containers, &kvs)?; let root = Value::from(mt.root()); let root_ak = AnchoredKey::from((PodId(RawValue::from(88).into()), "merkle root")); @@ -2400,7 +2430,7 @@ mod tests { ] .into_iter() .collect(); - let mt = MerkleTree::new(params.max_depth_mt_gadget, &kvs)?; + let mt = MerkleTree::new(params.max_depth_mt_containers, &kvs)?; let root = Value::from(mt.root()); let root_ak = AnchoredKey::from((PodId(RawValue::from(88).into()), "merkle root")); diff --git a/src/backends/plonky2/circuits/signedpod.rs b/src/backends/plonky2/circuits/signedpod.rs index e2889e1..e1ac623 100644 --- a/src/backends/plonky2/circuits/signedpod.rs +++ b/src/backends/plonky2/circuits/signedpod.rs @@ -41,7 +41,7 @@ impl SignedPodVerifyGadget { let mut mt_proofs = Vec::new(); for _ in 0..self.params.max_signed_pod_values { let mt_proof = MerkleProofExistenceGadget { - max_depth: self.params.max_depth_mt_gadget, + max_depth: self.params.max_depth_mt_containers, } .eval(builder)?; builder.connect_hashes(id, mt_proof.root); diff --git a/src/backends/plonky2/emptypod.rs b/src/backends/plonky2/emptypod.rs index 5d617e4..20ff0ef 100644 --- a/src/backends/plonky2/emptypod.rs +++ b/src/backends/plonky2/emptypod.rs @@ -27,7 +27,7 @@ use crate::{ }, middleware::{ self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement, - ToFields, Value, VerifierOnlyCircuitData, EMPTY_HASH, F, HASH_SIZE, KEY_TYPE, SELF, + ToFields, Value, VerifierOnlyCircuitData, F, HASH_SIZE, KEY_TYPE, SELF, }, timed, }; @@ -80,7 +80,7 @@ pub struct EmptyPod { type CircuitData = circuit_data::CircuitData; -static STANDARD_EMPTY_POD_DATA: LazyLock<(EmptyPodVerifyTarget, CircuitData)> = +pub static STANDARD_EMPTY_POD_DATA: LazyLock<(EmptyPodVerifyTarget, CircuitData)> = LazyLock::new(|| build().expect("successful build")); fn build() -> Result<(EmptyPodVerifyTarget, CircuitData)> { @@ -144,7 +144,7 @@ impl EmptyPod { let public_inputs = id .to_fields(&self.params) .iter() - .chain(EMPTY_HASH.0.iter()) // slot for the unused vds root + .chain(self.vds_root.0.iter()) .cloned() .collect_vec(); @@ -222,6 +222,7 @@ impl RecursivePod for EmptyPod { #[cfg(test)] pub mod tests { use super::*; + use crate::middleware::EMPTY_HASH; #[test] fn test_empty_pod() { diff --git a/src/backends/plonky2/mainpod/mod.rs b/src/backends/plonky2/mainpod/mod.rs index 597073e..74126a1 100644 --- a/src/backends/plonky2/mainpod/mod.rs +++ b/src/backends/plonky2/mainpod/mod.rs @@ -28,7 +28,7 @@ use crate::{ middleware::{ self, resolve_wildcard_values, AnchoredKey, CustomPredicateBatch, DynError, Hash, MainPodInputs, NativeOperation, NonePod, OperationType, Params, Pod, PodId, PodProver, - PodType, RecursivePod, StatementArg, ToFields, F, KEY_TYPE, SELF, + PodType, RecursivePod, StatementArg, ToFields, VDSet, F, KEY_TYPE, SELF, }, }; @@ -153,11 +153,11 @@ pub(crate) fn extract_merkle_proofs( _ => None, }) .collect(); - if merkle_proofs.len() > params.max_merkle_proofs { + if merkle_proofs.len() > params.max_merkle_proofs_containers { return Err(Error::custom(format!( "The number of required Merkle proofs ({}) exceeds the maximum number ({}).", merkle_proofs.len(), - params.max_merkle_proofs + params.max_merkle_proofs_containers ))); } Ok(merkle_proofs) @@ -283,7 +283,7 @@ pub(crate) fn layout_statements( // We mocking or we don't need padding so we skip creating an EmptyPod MockEmptyPod::new_boxed(params) } else { - EmptyPod::new_boxed(params, inputs.vds_root) + EmptyPod::new_boxed(params, inputs.vds_set.root()) }; let empty_pod = empty_pod_box.as_ref(); assert!(inputs.recursive_pods.len() <= params.max_input_recursive_pods); @@ -410,7 +410,7 @@ pub(crate) fn process_public_statements_operations( pub struct Prover {} impl Prover { - fn _prove(&self, params: &Params, inputs: MainPodInputs) -> Result { + fn _prove(&self, params: &Params, vd_set: &VDSet, inputs: MainPodInputs) -> Result { let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA; let (main_pod_target, circuit_data) = RecursiveCircuit::::target_and_circuit_data_padded( @@ -445,7 +445,7 @@ impl Prover { // We don't need padding so we skip creating an EmptyPod MockEmptyPod::new_boxed(params) } else { - EmptyPod::new_boxed(params, inputs.vds_root) + EmptyPod::new_boxed(params, inputs.vds_set.root()) }; let inputs = MainPodInputs { recursive_pods: &inputs @@ -492,10 +492,10 @@ impl Prover { .recursive_pods .iter() .map(|pod| { - assert_eq!(inputs.vds_root, pod.vds_root()); + assert_eq!(inputs.vds_set.root(), pod.vds_root()); ProofWithPublicInputs { proof: pod.proof(), - public_inputs: [pod.id().0 .0, inputs.vds_root.0].concat(), + public_inputs: [pod.id().0 .0, inputs.vds_set.root().0].concat(), } }) .collect_vec(); @@ -504,8 +504,12 @@ impl Prover { .iter() .map(|pod| pod.verifier_data()) .collect_vec(); + + let vd_mt_proofs = vd_set.get_vds_proofs(&verifier_datas)?; + let input = MainPodVerifyInput { - vds_root: inputs.vds_root, + vds_set: inputs.vds_set.clone(), + vd_mt_proofs, signed_pods: signed_pods_input, recursive_pods_pub_self_statements, statements: statements[statements.len() - params.max_statements..].to_vec(), @@ -519,7 +523,7 @@ impl Prover { Ok(MainPod { params: params.clone(), id, - vds_root: inputs.vds_root, + vds_root: inputs.vds_set.root(), public_statements, proof: proof_with_pis.proof, }) @@ -530,9 +534,10 @@ impl PodProver for Prover { fn prove( &self, params: &Params, + vd_set: &VDSet, inputs: MainPodInputs, ) -> Result, Box> { - Ok(self._prove(params, inputs).map(Box::new)?) + Ok(self._prove(params, vd_set, inputs).map(Box::new)?) } } @@ -540,6 +545,11 @@ impl PodProver for Prover { pub struct MainPod { params: Params, id: PodId, + /// vds_root is the merkle-root of the `VDSet`, which contains the + /// verifier_data hashes of the allowed set of VerifierOnlyCircuitData, for + /// the succession of recursive MainPods, which when proving the POD, it is + /// proven that all the recursive proofs that are being verified in-circuit + /// use one of the verifier_data's contained in the VDSet. vds_root: Hash, public_statements: Vec, proof: Proof, @@ -696,7 +706,7 @@ pub mod tests { {self}, }, middleware, - middleware::{CustomPredicateRef, NativePredicate as NP}, + middleware::{CustomPredicateRef, NativePredicate as NP, DEFAULT_VD_SET}, op, }; @@ -711,6 +721,7 @@ pub mod tests { ..Default::default() }; println!("{:#?}", params); + let vd_set = &*DEFAULT_VD_SET; let (gov_id_builder, pay_stub_builder, sanction_list_builder) = zu_kyc_sign_pod_builders(¶ms); @@ -720,8 +731,13 @@ pub mod tests { let pay_stub_pod = pay_stub_builder.sign(&mut signer)?; let mut signer = Signer(SecretKey(3u64.into())); let sanction_list_pod = sanction_list_builder.sign(&mut signer)?; - let kyc_builder = - zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?; + let kyc_builder = zu_kyc_pod_builder( + ¶ms, + &vd_set, + &gov_id_pod, + &pay_stub_pod, + &sanction_list_pod, + )?; let mut prover = Prover {}; let kyc_pod = kyc_builder.prove(&mut prover, ¶ms)?; @@ -742,6 +758,7 @@ pub mod tests { max_input_pods_public_statements: 10, ..Default::default() }; + let vd_set = &*DEFAULT_VD_SET; let mut gov_id_builder = frontend::SignedPodBuilder::new(¶ms); gov_id_builder.insert("idNumber", "4242424242"); @@ -750,7 +767,7 @@ pub mod tests { let mut signer = Signer(SecretKey(42u64.into())); let gov_id = gov_id_builder.sign(&mut signer).unwrap(); let now_minus_18y: i64 = 1169909388; - let mut kyc_builder = frontend::MainPodBuilder::new(¶ms); + let mut kyc_builder = frontend::MainPodBuilder::new(¶ms, &vd_set); kyc_builder.add_signed_pod(&gov_id); kyc_builder .pub_op(op!(lt, (&gov_id, "dateOfBirth"), now_minus_18y)) @@ -792,11 +809,13 @@ pub mod tests { max_custom_predicate_arity: 2, max_custom_predicate_wildcards: 2, max_custom_batch_size: 2, - max_merkle_proofs: 2, - max_depth_mt_gadget: 4, + max_merkle_proofs_containers: 2, + max_depth_mt_containers: 4, + max_depth_mt_vds: 6, }; + let vd_set = &*DEFAULT_VD_SET; - let pod_builder = frontend::MainPodBuilder::new(¶ms); + let pod_builder = frontend::MainPodBuilder::new(¶ms, &vd_set); // Mock let mut prover = MockProver {}; @@ -828,6 +847,7 @@ pub mod tests { ..Default::default() }; println!("{:#?}", params); + let vd_set = &*DEFAULT_VD_SET; let mut alice = Signer(SecretKey(1u32.into())); let bob = Signer(SecretKey(2u32.into())); @@ -842,6 +862,7 @@ pub mod tests { let alice_bob_ethdos_builder = eth_dos_pod_builder( ¶ms, + &vd_set, false, &alice_attestation, &charlie_attestation, @@ -878,6 +899,7 @@ pub mod tests { ..Default::default() }; println!("{:#?}", params); + let vd_set = &*DEFAULT_VD_SET; let mut cpb_builder = CustomPredicateBatchBuilder::new(params.clone(), "cpb".into()); let stb0 = STB::new(NP::ValueOf) @@ -898,7 +920,7 @@ pub mod tests { let cpb_and = CustomPredicateRef::new(cpb.clone(), 0); let _cpb_or = CustomPredicateRef::new(cpb.clone(), 1); - let mut pod_builder = MainPodBuilder::new(¶ms); + let mut pod_builder = MainPodBuilder::new(¶ms, &vd_set); let st0 = pod_builder.priv_op(op!(new_entry, ("score", 42)))?; let st1 = pod_builder.priv_op(op!(new_entry, ("foo", 42)))?; diff --git a/src/backends/plonky2/mock/mainpod.rs b/src/backends/plonky2/mock/mainpod.rs index d15f829..5def079 100644 --- a/src/backends/plonky2/mock/mainpod.rs +++ b/src/backends/plonky2/mock/mainpod.rs @@ -19,7 +19,7 @@ use crate::{ }, middleware::{ self, hash_str, AnchoredKey, DynError, Hash, MainPodInputs, NativePredicate, Params, Pod, - PodId, PodProver, PodType, Predicate, RecursivePod, StatementArg, KEY_TYPE, SELF, + PodId, PodProver, PodType, Predicate, RecursivePod, StatementArg, VDSet, KEY_TYPE, SELF, }, }; @@ -29,6 +29,7 @@ impl PodProver for MockProver { fn prove( &self, params: &Params, + _vd_set: &VDSet, inputs: MainPodInputs, ) -> Result, Box> { Ok(Box::new(MockMainPod::new(params, inputs)?)) @@ -176,7 +177,7 @@ impl MockMainPod { Ok(Self { params: params.clone(), id, - vds_root: inputs.vds_root, + vds_root: inputs.vds_set.root(), // input_signed_pods, // input_main_pods, // input_statements, @@ -356,12 +357,13 @@ pub mod tests { zu_kyc_sign_pod_builders, }, frontend, - middleware::{self}, + middleware::{self, DEFAULT_VD_SET}, }; #[test] fn test_mock_main_zu_kyc() -> frontend::Result<()> { let params = middleware::Params::default(); + let vd_set = &*DEFAULT_VD_SET; let (gov_id_builder, pay_stub_builder, sanction_list_builder) = zu_kyc_sign_pod_builders(¶ms); let mut signer = MockSigner { @@ -376,8 +378,13 @@ pub mod tests { pk: "ZooOFAC".into(), }; let sanction_list_pod = sanction_list_builder.sign(&mut signer)?; - let kyc_builder = - zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?; + let kyc_builder = zu_kyc_pod_builder( + ¶ms, + &vd_set, + &gov_id_pod, + &pay_stub_pod, + &sanction_list_pod, + )?; let mut prover = MockProver {}; let kyc_pod = kyc_builder.prove(&mut prover, ¶ms)?; diff --git a/src/backends/plonky2/mock/signedpod.rs b/src/backends/plonky2/mock/signedpod.rs index 77d8fc8..2a1735d 100644 --- a/src/backends/plonky2/mock/signedpod.rs +++ b/src/backends/plonky2/mock/signedpod.rs @@ -27,13 +27,13 @@ impl MockSigner { } impl MockSigner { - fn _sign(&mut self, _params: &Params, kvs: &HashMap) -> Result { + fn _sign(&mut self, params: &Params, kvs: &HashMap) -> Result { let mut kvs = kvs.clone(); let pubkey = self.public_key(); kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey)); kvs.insert(Key::from(KEY_TYPE), Value::from(PodType::MockSigned)); - let dict = Dictionary::new(kvs.clone())?; + let dict = Dictionary::new(params.max_depth_mt_containers, kvs.clone())?; let id = PodId(dict.commitment()); let signature = format!("{}_signed_by_{}", id, pubkey); Ok(MockSignedPod { id, signature, kvs }) diff --git a/src/backends/plonky2/primitives/merkletree/circuit.rs b/src/backends/plonky2/primitives/merkletree/circuit.rs index 0bcced8..f204cf5 100644 --- a/src/backends/plonky2/primitives/merkletree/circuit.rs +++ b/src/backends/plonky2/primitives/merkletree/circuit.rs @@ -42,7 +42,7 @@ pub struct MerkleProofGadget { pub max_depth: usize, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct MerkleClaimAndProofTarget { pub(crate) max_depth: usize, // `enabled` determines if the merkleproof verification is enabled @@ -59,7 +59,7 @@ pub struct MerkleClaimAndProofTarget { impl MerkleProofGadget { /// creates the targets and defines the logic of the circuit - pub fn eval(&self, builder: &mut CircuitBuilder) -> Result { + pub fn eval(&self, builder: &mut CircuitBuilder) -> MerkleClaimAndProofTarget { let measure = measure_gates_begin!(builder, format!("MerkleProof_{}", self.max_depth)); let enabled = builder.add_virtual_bool_target_safe(); let root = builder.add_virtual_hash(); @@ -128,7 +128,7 @@ impl MerkleProofGadget { // (this is for the three cases (existence, non-existence case i, and // non-existence case ii). let obtained_root = - compute_root_from_leaf(self.max_depth, builder, &path, &leaf_hash, &siblings)?; + compute_root_from_leaf(self.max_depth, builder, &path, &leaf_hash, &siblings); // check that obtained_root==root (from inputs), when enabled==true let zero = builder.zero(); @@ -143,7 +143,7 @@ impl MerkleProofGadget { } measure_gates_end!(builder, measure); - Ok(MerkleClaimAndProofTarget { + MerkleClaimAndProofTarget { max_depth: self.max_depth, enabled, existence, @@ -154,7 +154,7 @@ impl MerkleProofGadget { case_ii_selector, other_key, other_value, - }) + } } } @@ -241,7 +241,7 @@ impl MerkleProofExistenceGadget { // compute the root for the given siblings and the computed leaf_hash. let obtained_root = - compute_root_from_leaf(self.max_depth, builder, &path, &leaf_hash, &siblings)?; + compute_root_from_leaf(self.max_depth, builder, &path, &leaf_hash, &siblings); // check that obtained_root==root (from inputs), when enabled==true let zero = builder.zero(); @@ -305,7 +305,7 @@ fn compute_root_from_leaf( path: &[BoolTarget], leaf_hash: &HashOutTarget, siblings: &[HashOutTarget], -) -> Result { +) -> HashOutTarget { assert_eq!(siblings.len(), max_depth); // Convenience constants let zero = builder.zero(); @@ -356,7 +356,7 @@ fn compute_root_from_leaf( .collect(); h = HashOutTarget::from_vec(h_targ); } - Ok(h) + h } // Note: this logic is in its own method for easy of reusability but @@ -546,7 +546,7 @@ pub mod tests { let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::::new(); - let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; + let targets = MerkleProofGadget { max_depth }.eval(&mut builder); targets.set_targets( &mut pw, true, @@ -667,7 +667,7 @@ pub mod tests { let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::::new(); - let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; + let targets = MerkleProofGadget { max_depth }.eval(&mut builder); targets.set_targets( &mut pw, true, @@ -714,7 +714,7 @@ pub mod tests { let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::::new(); - let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; + let targets = MerkleProofGadget { max_depth }.eval(&mut builder); // verification enabled & proof of existence let mp = MerkleClaimAndProof::new(tree2.root(), key, Some(value), proof); targets.set_targets(&mut pw, true, &mp)?; @@ -730,7 +730,7 @@ pub mod tests { let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::::new(); - let targets = MerkleProofGadget { max_depth }.eval(&mut builder)?; + let targets = MerkleProofGadget { max_depth }.eval(&mut builder); // verification disabled & proof of existence targets.set_targets(&mut pw, false, &mp)?; diff --git a/src/backends/plonky2/signedpod.rs b/src/backends/plonky2/signedpod.rs index fbe69cc..f5d8db1 100644 --- a/src/backends/plonky2/signedpod.rs +++ b/src/backends/plonky2/signedpod.rs @@ -28,13 +28,13 @@ use crate::{ pub struct Signer(pub SecretKey); impl Signer { - fn _sign(&mut self, _params: &Params, kvs: &HashMap) -> Result { + fn _sign(&mut self, params: &Params, kvs: &HashMap) -> Result { let mut kvs = kvs.clone(); let pubkey = self.0.public_key(); kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey)); kvs.insert(Key::from(KEY_TYPE), Value::from(PodType::Signed)); - let dict = Dictionary::new(kvs)?; + let dict = Dictionary::new(params.max_depth_mt_containers, kvs)?; let id = RawValue::from(dict.commitment()); // PodId as Value let nonce = OsRng.gen_biguint_below(&GROUP_ORDER); @@ -232,7 +232,7 @@ pub mod tests { .into_iter() .chain(iter::once(bad_kv)) .collect::>(); - bad_pod.dict = Dictionary::new(bad_kvs).unwrap(); + bad_pod.dict = Dictionary::new(params.max_depth_mt_containers, bad_kvs).unwrap(); assert!(bad_pod.verify().is_err()); let mut bad_pod = pod.clone(); @@ -244,7 +244,7 @@ pub mod tests { .into_iter() .chain(iter::once(bad_kv)) .collect::>(); - bad_pod.dict = Dictionary::new(bad_kvs).unwrap(); + bad_pod.dict = Dictionary::new(params.max_depth_mt_containers, bad_kvs).unwrap(); assert!(bad_pod.verify().is_err()); Ok(()) diff --git a/src/examples/mod.rs b/src/examples/mod.rs index 5a373c5..f8f6963 100644 --- a/src/examples/mod.rs +++ b/src/examples/mod.rs @@ -8,8 +8,8 @@ use crate::{ backends::plonky2::mock::signedpod::MockSigner, frontend::{MainPodBuilder, Result, SignedPod, SignedPodBuilder}, middleware::{ - containers::Set, CustomPredicateRef, Params, PodType, Statement, TypedValue, Value, - KEY_SIGNER, KEY_TYPE, + containers::Set, CustomPredicateRef, Params, PodType, Statement, TypedValue, VDSet, Value, + DEFAULT_VD_SET, KEY_SIGNER, KEY_TYPE, }, op, }; @@ -20,7 +20,8 @@ pub fn zu_kyc_sign_pod_builders( params: &Params, ) -> (SignedPodBuilder, SignedPodBuilder, SignedPodBuilder) { let sanctions_values: HashSet = ["A343434340"].iter().map(|s| Value::from(*s)).collect(); - let sanction_set = Value::from(Set::new(sanctions_values).unwrap()); + let sanction_set = + Value::from(Set::new(params.max_depth_mt_containers, sanctions_values).unwrap()); let mut gov_id = SignedPodBuilder::new(params); gov_id.insert("idNumber", "4242424242"); @@ -40,6 +41,7 @@ pub fn zu_kyc_sign_pod_builders( pub fn zu_kyc_pod_builder( params: &Params, + vd_set: &VDSet, gov_id: &SignedPod, pay_stub: &SignedPod, sanction_list: &SignedPod, @@ -47,7 +49,7 @@ pub fn zu_kyc_pod_builder( let now_minus_18y: i64 = 1169909388; let now_minus_1y: i64 = 1706367566; - let mut kyc = MainPodBuilder::new(params); + let mut kyc = MainPodBuilder::new(params, vd_set); kyc.add_signed_pod(gov_id); kyc.add_signed_pod(pay_stub); kyc.add_signed_pod(sanction_list); @@ -78,6 +80,7 @@ pub fn eth_friend_signed_pod_builder(params: &Params, friend_pubkey: Value) -> S pub fn eth_dos_pod_builder( params: &Params, + vd_set: &VDSet, mock: bool, alice_attestation: &SignedPod, charlie_attestation: &SignedPod, @@ -91,7 +94,7 @@ pub fn eth_dos_pod_builder( let eth_dos = CustomPredicateRef::new(eth_dos_batch.clone(), 2); // ETHDoS POD builder - let mut alice_bob_ethdos = MainPodBuilder::new(params); + let mut alice_bob_ethdos = MainPodBuilder::new(params, vd_set); alice_bob_ethdos.add_signed_pod(alice_attestation); alice_bob_ethdos.add_signed_pod(charlie_attestation); @@ -229,6 +232,7 @@ pub fn friend_sign_pod_builder(params: &Params, friend: &str) -> SignedPodBuilde pub fn great_boy_pod_builder( params: &Params, + vd_set: &VDSet, good_boy_pods: [&SignedPod; 4], friend_pods: [&SignedPod; 2], good_boy_issuers: &Value, @@ -242,7 +246,7 @@ pub fn great_boy_pod_builder( // good boy 0 -> friend_pods[0] => receiver // good boy 1 -> friend_pods[1] => receiver - let mut great_boy = MainPodBuilder::new(params); + let mut great_boy = MainPodBuilder::new(params, vd_set); for i in 0..4 { great_boy.add_signed_pod(good_boy_pods[i]); } @@ -305,6 +309,7 @@ pub fn great_boy_pod_full_flow() -> Result<(Params, MainPodBuilder)> { num_public_statements_id: 50, ..Default::default() }; + let vd_set = &*DEFAULT_VD_SET; let good_boy_issuers = ["Giggles", "Macrosoft", "FaeBook"]; let mut giggles_signer = MockSigner { @@ -348,11 +353,13 @@ pub fn great_boy_pod_full_flow() -> Result<(Params, MainPodBuilder)> { alice_friend_pods.push(friend.sign(&mut charlie_signer).unwrap()); let good_boy_issuers = Value::from(Set::new( + params.max_depth_mt_containers, good_boy_issuers.into_iter().map(Value::from).collect(), )?); let builder = great_boy_pod_builder( ¶ms, + &vd_set, [ &bob_good_boys[0], &bob_good_boys[1], @@ -383,6 +390,7 @@ pub fn tickets_sign_pod_builder(params: &Params) -> SignedPodBuilder { pub fn tickets_pod_builder( params: &Params, + vd_set: &VDSet, signed_pod: &SignedPod, expected_event_id: i64, expect_consumed: bool, @@ -390,7 +398,7 @@ pub fn tickets_pod_builder( ) -> Result { let blacklisted_email_set_value = Value::from(TypedValue::Set(blacklisted_emails.clone())); // Create a main pod referencing this signed pod with some statements - let mut builder = MainPodBuilder::new(params); + let mut builder = MainPodBuilder::new(params, vd_set); builder.add_signed_pod(signed_pod); builder.pub_op(op!(eq, (signed_pod, "eventId"), expected_event_id))?; builder.pub_op(op!(eq, (signed_pod, "isConsumed"), expect_consumed))?; @@ -405,7 +413,15 @@ pub fn tickets_pod_builder( pub fn tickets_pod_full_flow() -> Result { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let builder = tickets_sign_pod_builder(¶ms); let signed_pod = builder.sign(&mut MockSigner { pk: "test".into() }).unwrap(); - tickets_pod_builder(¶ms, &signed_pod, 123, true, &Set::new(HashSet::new())?) + tickets_pod_builder( + ¶ms, + vd_set, + &signed_pod, + 123, + true, + &Set::new(params.max_depth_mt_containers, HashSet::new())?, + ) } diff --git a/src/frontend/custom.rs b/src/frontend/custom.rs index c51ba3c..095bf9d 100644 --- a/src/frontend/custom.rs +++ b/src/frontend/custom.rs @@ -294,7 +294,7 @@ mod tests { backends::plonky2::mock::mainpod::MockProver, examples::custom::{eth_dos_batch, eth_friend_batch}, frontend::MainPodBuilder, - middleware::{self, containers::Set, CustomPredicateRef, Params, PodType}, + middleware::{self, containers::Set, CustomPredicateRef, Params, PodType, DEFAULT_VD_SET}, op, }; @@ -328,6 +328,7 @@ mod tests { #[test] fn test_desugared_gt_custom_pred() -> Result<()> { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let mut builder = CustomPredicateBatchBuilder::new(params.clone(), "gt_custom_pred".into()); let gt_stb = StatementTmplBuilder::new(NativePredicate::Gt) @@ -344,7 +345,7 @@ mod tests { let batch_clone = batch.clone(); let gt_custom_pred = CustomPredicateRef::new(batch, 0); - let mut mp_builder = MainPodBuilder::new(¶ms); + let mut mp_builder = MainPodBuilder::new(¶ms, &vd_set); // 2 > 1 let s1 = mp_builder.literal(true, Value::from(2))?; @@ -376,6 +377,7 @@ mod tests { #[test] fn test_desugared_set_contains_custom_pred() -> Result<()> { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let mut builder = CustomPredicateBatchBuilder::new(params.clone(), "set_contains_custom_pred".into()); @@ -392,10 +394,13 @@ mod tests { let batch = builder.finish(); let batch_clone = batch.clone(); - let mut mp_builder = MainPodBuilder::new(¶ms); + let mut mp_builder = MainPodBuilder::new(¶ms, &vd_set); let set_values: HashSet = [1, 2, 3].iter().map(|i| Value::from(*i)).collect(); - let s1 = mp_builder.literal(true, Value::from(Set::new(set_values)?))?; + let s1 = mp_builder.literal( + true, + Value::from(Set::new(params.max_depth_mt_containers, set_values)?), + )?; let s2 = mp_builder.literal(true, Value::from(1))?; let set_contains = mp_builder.pub_op(op!(set_contains, s1, s2))?; diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index f701c5c..739ce98 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -10,8 +10,7 @@ use serialization::{SerializedMainPod, SerializedSignedPod}; use crate::middleware::{ self, check_st_tmpl, hash_str, hash_values, AnchoredKey, Hash, Key, MainPodInputs, NativeOperation, NativePredicate, OperationAux, OperationType, Params, PodId, PodProver, - PodSigner, Predicate, Statement, StatementArg, Value, WildcardValue, EMPTY_HASH, KEY_TYPE, - SELF, + PodSigner, Predicate, Statement, StatementArg, VDSet, Value, WildcardValue, KEY_TYPE, SELF, }; mod custom; @@ -117,6 +116,7 @@ impl SignedPod { #[derive(Debug)] pub struct MainPodBuilder { pub params: Params, + pub vd_set: VDSet, pub input_signed_pods: Vec, pub input_main_pods: Vec, pub statements: Vec, @@ -151,9 +151,10 @@ impl fmt::Display for MainPodBuilder { } impl MainPodBuilder { - pub fn new(params: &Params) -> Self { + pub fn new(params: &Params, vd_set: &VDSet) -> Self { Self { params: params.clone(), + vd_set: vd_set.clone(), input_signed_pods: Vec::new(), input_main_pods: Vec::new(), statements: Vec::new(), @@ -548,6 +549,7 @@ impl MainPodBuilder { }; let (statements, operations, public_statements) = compiler.compile(inputs, params)?; + let inputs = MainPodInputs { signed_pods: &self .input_signed_pods @@ -562,9 +564,9 @@ impl MainPodBuilder { statements: &statements, operations: &operations, public_statements: &public_statements, - vds_root: EMPTY_HASH, // TODO https://github.com/0xPARC/pod2/issues/249 + vds_set: self.vd_set.clone(), }; - let pod = prover.prove(&self.params, inputs)?; + let pod = prover.prove(&self.params, &self.vd_set, inputs)?; // Gather public statements, making sure to inject the type // information specified by the backend. @@ -838,7 +840,7 @@ pub mod tests { eth_dos_pod_builder, eth_friend_signed_pod_builder, great_boy_pod_full_flow, tickets_pod_full_flow, zu_kyc_pod_builder, zu_kyc_sign_pod_builders, }, - middleware::{containers::Dictionary, Value}, + middleware::{containers::Dictionary, Value, DEFAULT_VD_SET}, }; // Check that frontend public statements agree with those @@ -873,6 +875,7 @@ pub mod tests { #[test] fn test_front_zu_kyc() -> Result<()> { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let (gov_id, pay_stub, sanction_list) = zu_kyc_sign_pod_builders(¶ms); println!("{}", gov_id); @@ -899,7 +902,7 @@ pub mod tests { check_kvs(&sanction_list)?; println!("{}", sanction_list); - let kyc_builder = zu_kyc_pod_builder(¶ms, &gov_id, &pay_stub, &sanction_list)?; + let kyc_builder = zu_kyc_pod_builder(¶ms, &vd_set, &gov_id, &pay_stub, &sanction_list)?; println!("{}", kyc_builder); // prove kyc with MockProver and print it @@ -926,6 +929,7 @@ pub mod tests { max_custom_predicate_wildcards: 12, ..Default::default() }; + let vd_set = &*DEFAULT_VD_SET; let mut alice = MockSigner { pk: "Alice".into() }; let bob = MockSigner { pk: "Bob".into() }; @@ -945,6 +949,7 @@ pub mod tests { let mut prover = MockProver {}; let alice_bob_ethdos = eth_dos_pod_builder( ¶ms, + &vd_set, true, &alice_attestation, &charlie_attestation, @@ -978,13 +983,15 @@ pub mod tests { #[should_panic] fn test_equal() { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; + let mut signed_builder = SignedPodBuilder::new(¶ms); signed_builder.insert("a", 1); signed_builder.insert("b", 1); let mut signer = MockSigner { pk: "key".into() }; let signed_pod = signed_builder.sign(&mut signer).unwrap(); - let mut builder = MainPodBuilder::new(¶ms); + let mut builder = MainPodBuilder::new(¶ms, &vd_set); builder.add_signed_pod(&signed_pod); //let op_val1 = Operation{ @@ -1028,6 +1035,7 @@ pub mod tests { #[should_panic] fn test_false_st() { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let mut builder = SignedPodBuilder::new(¶ms); builder.insert("num", 2); @@ -1039,7 +1047,7 @@ pub mod tests { println!("{}", pod); - let mut builder = MainPodBuilder::new(¶ms); + let mut builder = MainPodBuilder::new(¶ms, &vd_set); builder.add_signed_pod(&pod); builder.pub_op(op!(gt, (&pod, "num"), 5)).unwrap(); @@ -1053,6 +1061,7 @@ pub mod tests { #[test] fn test_dictionaries() -> Result<()> { let params = Params::default(); + let vd_set = &*DEFAULT_VD_SET; let mut builder = SignedPodBuilder::new(¶ms); let mut my_dict_kvs: HashMap = HashMap::new(); @@ -1061,7 +1070,7 @@ pub mod tests { my_dict_kvs.insert(Key::from("c"), Value::from(3)); // let my_dict_as_mt = MerkleTree::new(5, &my_dict_kvs).unwrap(); // let dict = Dictionary { mt: my_dict_as_mt }; - let dict = Dictionary::new(my_dict_kvs)?; + let dict = Dictionary::new(params.max_depth_mt_containers, my_dict_kvs)?; let dict_root = Value::from(dict.clone()); builder.insert("dict", dict_root); @@ -1070,7 +1079,7 @@ pub mod tests { }; let pod = builder.sign(&mut signer).unwrap(); - let mut builder = MainPodBuilder::new(¶ms); + let mut builder = MainPodBuilder::new(¶ms, &vd_set); builder.add_signed_pod(&pod); let st0 = pod.get_statement("dict").unwrap(); let st1 = builder.op(true, op!(new_entry, ("key", "a"))).unwrap(); @@ -1106,7 +1115,8 @@ pub mod tests { env_logger::init(); let params = Params::default(); - let mut builder = MainPodBuilder::new(¶ms); + let vd_set = &*DEFAULT_VD_SET; + let mut builder = MainPodBuilder::new(¶ms, &vd_set); let st = Statement::ValueOf(AnchoredKey::from((SELF, "a")), Value::from(3)); let op_new_entry = Operation( OperationType::Native(NativeOperation::NewEntry), @@ -1124,8 +1134,7 @@ pub mod tests { // try to insert a statement that doesn't follow from the operation // right now the mock prover catches this when it calls compile() - let params = Params::default(); - let mut builder = MainPodBuilder::new(¶ms); + let mut builder = MainPodBuilder::new(¶ms, &vd_set); let self_a = AnchoredKey::from((SELF, "a")); let self_b = AnchoredKey::from((SELF, "b")); let value_of_a = Statement::ValueOf(self_a.clone(), Value::from(3)); diff --git a/src/frontend/serialization.rs b/src/frontend/serialization.rs index 7531619..62dc4f4 100644 --- a/src/frontend/serialization.rs +++ b/src/frontend/serialization.rs @@ -112,24 +112,25 @@ mod tests { middleware::{ self, containers::{Array, Dictionary, Set}, - Params, TypedValue, + Params, TypedValue, DEFAULT_VD_SET, }, }; #[test] fn test_value_serialization() { + let params = &Params::default(); // Pairs of values and their expected serialized representations let values = vec![ (TypedValue::String("hello".to_string()), "\"hello\""), (TypedValue::Int(42), "{\"Int\":\"42\"}"), (TypedValue::Bool(true), "true"), ( - TypedValue::Array(Array::new(vec!["foo".into(), false.into()]).unwrap()), - "[\"foo\",false]", + TypedValue::Array(Array::new(params.max_depth_mt_containers, vec!["foo".into(), false.into()]).unwrap()), + "{\"max_depth\":32,\"array\":[\"foo\",false]}", ), ( TypedValue::Dictionary( - Dictionary::new(HashMap::from([ + Dictionary::new(params.max_depth_mt_containers, HashMap::from([ // The set of valid keys is equal to the set of valid JSON keys ("foo".into(), 123.into()), // Empty strings are valid JSON keys @@ -145,11 +146,11 @@ mod tests { ])) .unwrap(), ), - "{\"Dictionary\":{\"\":\"baz\",\"\\u0000\":\"\",\" hi\":false,\"!@£$%^&&*()\":\"\",\"foo\":{\"Int\":\"123\"},\"🥳\":\"party time!\"}}", + "{\"Dictionary\":{\"max_depth\":32,\"kvs\":{\"\":\"baz\",\"\\u0000\":\"\",\" hi\":false,\"!@£$%^&&*()\":\"\",\"foo\":{\"Int\":\"123\"},\"🥳\":\"party time!\"}}}", ), ( - TypedValue::Set(Set::new(HashSet::from(["foo".into(), "bar".into()])).unwrap()), - "{\"Set\":[\"bar\",\"foo\"]}", + TypedValue::Set(Set::new(params.max_depth_mt_containers, HashSet::from(["foo".into(), "bar".into()])).unwrap()), + "{\"Set\":{\"max_depth\":32,\"set\":[\"bar\",\"foo\"]}}", ), ]; @@ -168,30 +169,45 @@ mod tests { } fn signed_pod_builder() -> SignedPodBuilder { - let mut builder = SignedPodBuilder::new(&Params::default()); + let params = &Params::default(); + let mut builder = SignedPodBuilder::new(params); builder.insert("name", "test"); builder.insert("age", 30); builder.insert("very_large_int", 1152921504606846976); builder.insert( "a_dict_containing_one_key", - Dictionary::new(HashMap::from([ - ("foo".into(), 123.into()), - ( - "an_array_containing_three_ints".into(), - Array::new(vec![1.into(), 2.into(), 3.into()]) + Dictionary::new( + params.max_depth_mt_containers, + HashMap::from([ + ("foo".into(), 123.into()), + ( + "an_array_containing_three_ints".into(), + Array::new( + params.max_depth_mt_containers, + vec![1.into(), 2.into(), 3.into()], + ) .unwrap() .into(), - ), - ( - "a_set_containing_two_strings".into(), - Set::new(HashSet::from([ - Array::new(vec!["foo".into(), "bar".into()]).unwrap().into(), - "baz".into(), - ])) - .unwrap() - .into(), - ), - ])) + ), + ( + "a_set_containing_two_strings".into(), + Set::new( + params.max_depth_mt_containers, + HashSet::from([ + Array::new( + params.max_depth_mt_containers, + vec!["foo".into(), "bar".into()], + ) + .unwrap() + .into(), + "baz".into(), + ]), + ) + .unwrap() + .into(), + ), + ]), + ) .unwrap(), ); builder @@ -235,6 +251,7 @@ mod tests { fn build_mock_zukyc_pod() -> Result { let params = middleware::Params::default(); + let vd_set = &*DEFAULT_VD_SET; let (gov_id_builder, pay_stub_builder, sanction_list_builder) = zu_kyc_sign_pod_builders(¶ms); @@ -250,8 +267,14 @@ mod tests { pk: "ZooOFAC".into(), }; let sanction_list_pod = sanction_list_builder.sign(&mut signer).unwrap(); - let kyc_builder = - zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod, &sanction_list_pod).unwrap(); + let kyc_builder = zu_kyc_pod_builder( + ¶ms, + &vd_set, + &gov_id_pod, + &pay_stub_pod, + &sanction_list_pod, + ) + .unwrap(); let mut prover = MockProver {}; let kyc_pod = kyc_builder.prove(&mut prover, ¶ms).unwrap(); @@ -265,6 +288,7 @@ mod tests { max_input_recursive_pods: 1, ..Default::default() }; + let vd_set = &*DEFAULT_VD_SET; let (gov_id_builder, pay_stub_builder, sanction_list_builder) = zu_kyc_sign_pod_builders(¶ms); @@ -274,8 +298,13 @@ mod tests { let pay_stub_pod = pay_stub_builder.sign(&mut signer)?; let mut signer = Signer(SecretKey(3u32.into())); let sanction_list_pod = sanction_list_builder.sign(&mut signer)?; - let kyc_builder = - zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?; + let kyc_builder = zu_kyc_pod_builder( + ¶ms, + &vd_set, + &gov_id_pod, + &pay_stub_pod, + &sanction_list_pod, + )?; let mut prover = Prover {}; let kyc_pod = kyc_builder.prove(&mut prover, ¶ms)?; @@ -324,6 +353,7 @@ mod tests { max_custom_predicate_wildcards: 12, ..Default::default() }; + let vd_set = &*DEFAULT_VD_SET; let mut alice = MockSigner { pk: "Alice".into() }; let bob = MockSigner { pk: "Bob".into() }; @@ -341,6 +371,7 @@ mod tests { let mut prover = MockProver {}; let alice_bob_ethdos = eth_dos_pod_builder( ¶ms, + &vd_set, true, &alice_attestation, &charlie_attestation, diff --git a/src/lang/processor.rs b/src/lang/processor.rs index 791c778..ae5549e 100644 --- a/src/lang/processor.rs +++ b/src/lang/processor.rs @@ -659,8 +659,11 @@ fn process_literal_value(lit_val_pair: &Pair) -> Result { @@ -668,8 +671,10 @@ fn process_literal_value(lit_val_pair: &Pair) -> Result { @@ -684,9 +689,11 @@ fn process_literal_value(lit_val_pair: &Pair) -> Result unreachable!("Unexpected rule: {:?}", inner_lit.as_rule()), diff --git a/src/middleware/containers.rs b/src/middleware/containers.rs index 3861f54..2b6c47d 100644 --- a/src/middleware/containers.rs +++ b/src/middleware/containers.rs @@ -9,31 +9,32 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::serialization::{ordered_map, ordered_set}; #[cfg(feature = "backend_plonky2")] use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree}; -use crate::{ - constants::MAX_DEPTH, - middleware::{hash_value, Error, Hash, Key, RawValue, Result, Value}, -}; +use crate::middleware::{hash_value, Error, Hash, Key, RawValue, Result, Value}; /// Dictionary: the user original keys and values are hashed to be used in the leaf. /// leaf.key=hash(original_key) /// leaf.value=hash(original_value) -#[derive(Clone, Debug, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Serialize, JsonSchema)] pub struct Dictionary { #[serde(skip)] + #[schemars(skip)] mt: MerkleTree, + max_depth: usize, #[serde(serialize_with = "ordered_map")] kvs: HashMap, } impl Dictionary { - pub fn new(kvs: HashMap) -> Result { + /// max_depth determines the depth of the underlying MerkleTree, allowing to + /// store 2^max_depth elements in the Dictionary + pub fn new(max_depth: usize, kvs: HashMap) -> Result { let kvs_raw: HashMap = kvs .iter() .map(|(k, v)| (RawValue(k.hash().0), v.raw())) .collect(); Ok(Self { - mt: MerkleTree::new(MAX_DEPTH, &kvs_raw)?, + mt: MerkleTree::new(max_depth, &kvs_raw)?, + max_depth, kvs, }) } @@ -53,20 +54,31 @@ impl Dictionary { pub fn prove_nonexistence(&self, key: &Key) -> Result { Ok(self.mt.prove_nonexistence(&RawValue(key.hash().0))?) } - pub fn verify(root: Hash, proof: &MerkleProof, key: &Key, value: &Value) -> Result<()> { + pub fn verify( + max_depth: usize, + root: Hash, + proof: &MerkleProof, + key: &Key, + value: &Value, + ) -> Result<()> { let key = RawValue(key.hash().0); Ok(MerkleTree::verify( - MAX_DEPTH, + max_depth, root, proof, &key, &value.raw(), )?) } - pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Key) -> Result<()> { + pub fn verify_nonexistence( + max_depth: usize, + root: Hash, + proof: &MerkleProof, + key: &Key, + ) -> Result<()> { let key = RawValue(key.hash().0); Ok(MerkleTree::verify_nonexistence( - MAX_DEPTH, root, proof, &key, + max_depth, root, proof, &key, )?) } // TODO: Rename to dict to be consistent maybe? @@ -74,14 +86,6 @@ impl Dictionary { &self.kvs } } -// impl<'a> IntoIterator for &'a Dictionary { -// type Item = (&'a RawValue, &'a RawValue); -// type IntoIter = TreeIter<'a>; -// -// fn into_iter(self) -> Self::IntoIter { -// self.mt.iter() -// } -// } impl PartialEq for Dictionary { fn eq(&self, other: &Self) -> bool { @@ -95,36 +99,34 @@ impl<'de> Deserialize<'de> for Dictionary { where D: Deserializer<'de>, { - let kvs: HashMap = HashMap::deserialize(deserializer)?; - Dictionary::new(kvs).map_err(serde::de::Error::custom) - } -} - -impl JsonSchema for Dictionary { - fn schema_name() -> String { - "Dictionary".to_string() - } - - fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - // Just use the schema of HashMap since that's what we're actually serializing - >::json_schema(gen) + #[derive(Deserialize)] + struct Aux { + #[serde(serialize_with = "ordered_map")] + kvs: HashMap, + max_depth: usize, + } + let aux = Aux::deserialize(deserializer)?; + Dictionary::new(aux.max_depth, aux.kvs).map_err(serde::de::Error::custom) } } /// Set: the value field of the leaf is unused, and the key contains the hash of the element. /// leaf.key=hash(original_value) /// leaf.value=0 -#[derive(Clone, Debug, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Serialize, JsonSchema)] pub struct Set { #[serde(skip)] + #[schemars(skip)] mt: MerkleTree, + max_depth: usize, #[serde(serialize_with = "ordered_set")] set: HashSet, } impl Set { - pub fn new(set: HashSet) -> Result { + /// max_depth determines the depth of the underlying MerkleTree, allowing to + /// store 2^max_depth elements in the Array + pub fn new(max_depth: usize, set: HashSet) -> Result { let kvs_raw: HashMap = set .iter() .map(|e| { @@ -133,7 +135,8 @@ impl Set { }) .collect(); Ok(Self { - mt: MerkleTree::new(MAX_DEPTH, &kvs_raw)?, + mt: MerkleTree::new(max_depth, &kvs_raw)?, + max_depth, set, }) } @@ -152,20 +155,25 @@ impl Set { let h = hash_value(&value.raw()); Ok(self.mt.prove_nonexistence(&RawValue::from(h))?) } - pub fn verify(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> { + pub fn verify(max_depth: usize, root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> { let h = hash_value(&value.raw()); Ok(MerkleTree::verify( - MAX_DEPTH, + max_depth, root, proof, &RawValue::from(h), &RawValue::from(h), )?) } - pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> { + pub fn verify_nonexistence( + max_depth: usize, + root: Hash, + proof: &MerkleProof, + value: &Value, + ) -> Result<()> { let h = hash_value(&value.raw()); Ok(MerkleTree::verify_nonexistence( - MAX_DEPTH, + max_depth, root, proof, &RawValue::from(h), @@ -188,22 +196,14 @@ impl<'de> Deserialize<'de> for Set { where D: Deserializer<'de>, { - // Deserialize the set directly - let set: HashSet = HashSet::deserialize(deserializer)?; - - // Create a new Set using the set field - Set::new(set).map_err(serde::de::Error::custom) - } -} - -impl JsonSchema for Set { - fn schema_name() -> String { - "Set".to_string() - } - - fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - // Just use the schema of HashSet since that's what we're actually serializing - >::json_schema(gen) + #[derive(Deserialize, JsonSchema)] + struct Aux { + #[serde(serialize_with = "ordered_set")] + set: HashSet, + max_depth: usize, + } + let aux = Aux::deserialize(deserializer)?; + Set::new(aux.max_depth, aux.set).map_err(serde::de::Error::custom) } } @@ -211,16 +211,19 @@ impl JsonSchema for Set { /// array index (integer). /// leaf.key=i /// leaf.value=original_value -#[derive(Clone, Debug, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Serialize, JsonSchema)] pub struct Array { #[serde(skip)] + #[schemars(skip)] mt: MerkleTree, + max_depth: usize, array: Vec, } impl Array { - pub fn new(array: Vec) -> Result { + /// max_depth determines the depth of the underlying MerkleTree, allowing to + /// store 2^max_depth elements in the Array + pub fn new(max_depth: usize, array: Vec) -> Result { let kvs_raw: HashMap = array .iter() .enumerate() @@ -228,7 +231,8 @@ impl Array { .collect(); Ok(Self { - mt: MerkleTree::new(MAX_DEPTH, &kvs_raw)?, + mt: MerkleTree::new(max_depth, &kvs_raw)?, + max_depth, array, }) } @@ -245,9 +249,15 @@ impl Array { let value = self.array.get(i).expect("valid index"); Ok((value, mtp)) } - pub fn verify(root: Hash, proof: &MerkleProof, i: usize, value: &Value) -> Result<()> { + pub fn verify( + max_depth: usize, + root: Hash, + proof: &MerkleProof, + i: usize, + value: &Value, + ) -> Result<()> { Ok(MerkleTree::verify( - MAX_DEPTH, + max_depth, root, proof, &RawValue::from(i as i64), @@ -271,18 +281,12 @@ impl<'de> Deserialize<'de> for Array { where D: Deserializer<'de>, { - let array: Vec = Vec::deserialize(deserializer)?; - Array::new(array).map_err(serde::de::Error::custom) - } -} - -impl JsonSchema for Array { - fn schema_name() -> String { - "Array".to_string() - } - - fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - // Just use the schema of Vec since that's what we're actually serializing - >::json_schema(gen) + #[derive(Deserialize, JsonSchema)] + struct Aux { + array: Vec, + max_depth: usize, + } + let aux = Aux::deserialize(deserializer)?; + Array::new(aux.max_depth, aux.array).map_err(serde::de::Error::custom) } } diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index ef357f2..4daa760 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -597,6 +597,7 @@ impl fmt::Display for PodType { } } +/// Params: non dynamic parameters that define the circuit. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)] #[serde(rename_all = "camelCase")] pub struct Params { @@ -612,10 +613,14 @@ pub struct Params { // max number of operations using custom predicates that can be verified in the MainPod pub max_custom_predicate_verifications: usize, pub max_custom_predicate_wildcards: usize, - // maximum number of merkle proofs - pub max_merkle_proofs: usize, - // maximum depth for merkle tree gadget - pub max_depth_mt_gadget: usize, + // maximum number of merkle proofs used for container operations + pub max_merkle_proofs_containers: usize, + // maximum depth for merkle tree gadget used for container operations + pub max_depth_mt_containers: usize, + // maximum depth of the merkle tree gadget used for verifier_data membership + // check. This allows creating verifying sets of pod circuits of size + // 2^max_depth_mt_vds. + pub max_depth_mt_vds: usize, // // The following parameters define how a pod id is calculated. They need to be the same among // different circuits to be compatible in their verification. @@ -651,8 +656,9 @@ impl Default for Params { max_custom_predicate_arity: 5, max_custom_predicate_wildcards: 10, max_custom_batch_size: 5, - max_merkle_proofs: 5, - max_depth_mt_gadget: 32, + max_merkle_proofs_containers: 5, + max_depth_mt_containers: 32, + max_depth_mt_vds: 6, // up to 64 (2^6) different pod circuits } } } @@ -843,13 +849,14 @@ pub struct MainPodInputs<'a> { /// Statements that need to be made public (they can come from input pods or input /// statements) pub public_statements: &'a [Statement], - pub vds_root: Hash, // TODO: Figure out if we use Hash or a Map here https://github.com/0xPARC/pod2/issues/249 + pub vds_set: VDSet, } pub trait PodProver { fn prove( &self, params: &Params, + vd_set: &VDSet, inputs: MainPodInputs, ) -> Result, Box>; }