Add verifier-datas tree (set) & in-circuit verification (#274)

* containers: add method to create new {Dict,Set,Array} with custom max_depth

* add vds_tree computation, update tree circuit interface

* add VDTree struct, add DEFAULT_VD_TREE, integrate it with MainPod,EmptyPod,frontend,etc.

* adapt frontend/serialization tests to new containers field (max_depth)

* adapt interfaces to allow using custom vd_tree in frontend & backend constructors

* rename VDTree to VDSet (and derivate namings too)

* containers 'new' always with param 'max_depth', use params.max_depth_mt_containers instead of the global constant MAX_DEPTH

* adapt after rebasing the branch to main latest changes

* apply review suggestions from @ed255

* use emptypod vd_mt_proofs (using vd_set as circuit input), merge the two existing set_targets methods of MainPodVerifyTarget

* document VDSet & vds_root
This commit is contained in:
arnaucube 2025-06-11 13:08:39 +02:00 committed by GitHub
parent 6258e52e1a
commit 273d803ebd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 486 additions and 259 deletions

View file

@ -36,3 +36,91 @@ pub type VerifierCircuitData = circuit_data::VerifierCircuitData<F, C, D>;
pub type CircuitBuilder = circuit_builder::CircuitBuilder<F, D>;
pub type Proof = proof::Proof<F, C, D>;
pub type ProofWithPublicInputs = proof::ProofWithPublicInputs<F, C, D>;
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<VDSet> = 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<HashOut<F>, MerkleClaimAndProof>,
}
impl VDSet {
/// builds the verifier_datas tree, and returns the root and the proofs
pub fn new(tree_depth: usize, vds: &[VerifierOnlyCircuitData]) -> Result<Self> {
// 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::<Vec<_>>();
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::<HashOut<F>, 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<Vec<MerkleClaimAndProof>> {
let mut proofs: Vec<MerkleClaimAndProof> = 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)
}
}

View file

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

View file

@ -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<MerkleClaimAndProofTarget> = 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::<Result<_>>()?;
.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<MerkleClaimAndProofTarget>,
id: HashOutTarget,
signed_pods: Vec<SignedPodVerifyTarget>,
input_pods_self_statements: Vec<Vec<StatementTarget>>,
@ -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<MerkleClaimAndProof>,
pub signed_pods: Vec<SignedPod>,
pub recursive_pods_pub_self_statements: Vec<Vec<Statement>>,
pub statements: Vec<mainpod::Statement>,
@ -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<F>,
input: &MainPodVerifyInput,
) -> Result<()> {
pw.set_target_arr(&self.vds_root.elements, &input.vds_root.0)?;
builder: &mut CircuitBuilder,
verified_proofs: &[VerifiedProofTarget],
) -> Result<MainPodVerifyTarget> {
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<Self> {
MainPodVerifyCircuit {
params: params.clone(),
}
.eval(builder, verified_proofs)
}
/// assigns the values to the targets
fn set_targets(&self, pw: &mut PartialWitness<F>, 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<MainPodVerifyTarget> {
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<Self> {
MainPodVerifyCircuit {
params: params.clone(),
}
.eval(builder, verified_proofs)
}
/// assigns the values to the targets
fn set_targets(&self, pw: &mut PartialWitness<F>, 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::<Result<_>>()?;
.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"));

View file

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

View file

@ -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<F, C, D>;
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() {

View file

@ -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<MainPod> {
fn _prove(&self, params: &Params, vd_set: &VDSet, inputs: MainPodInputs) -> Result<MainPod> {
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
let (main_pod_target, circuit_data) =
RecursiveCircuit::<MainPodVerifyTarget>::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<dyn RecursivePod>, Box<DynError>> {
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<Statement>,
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(&params);
@ -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(&params, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?;
let kyc_builder = zu_kyc_pod_builder(
&params,
&vd_set,
&gov_id_pod,
&pay_stub_pod,
&sanction_list_pod,
)?;
let mut prover = Prover {};
let kyc_pod = kyc_builder.prove(&mut prover, &params)?;
@ -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(&params);
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(&params);
let mut kyc_builder = frontend::MainPodBuilder::new(&params, &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(&params);
let pod_builder = frontend::MainPodBuilder::new(&params, &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(
&params,
&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(&params);
let mut pod_builder = MainPodBuilder::new(&params, &vd_set);
let st0 = pod_builder.priv_op(op!(new_entry, ("score", 42)))?;
let st1 = pod_builder.priv_op(op!(new_entry, ("foo", 42)))?;

View file

@ -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<dyn RecursivePod>, Box<DynError>> {
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(&params);
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(&params, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?;
let kyc_builder = zu_kyc_pod_builder(
&params,
&vd_set,
&gov_id_pod,
&pay_stub_pod,
&sanction_list_pod,
)?;
let mut prover = MockProver {};
let kyc_pod = kyc_builder.prove(&mut prover, &params)?;

View file

@ -27,13 +27,13 @@ impl MockSigner {
}
impl MockSigner {
fn _sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<MockSignedPod> {
fn _sign(&mut self, params: &Params, kvs: &HashMap<Key, Value>) -> Result<MockSignedPod> {
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 })

View file

@ -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<F, D>) -> Result<MerkleClaimAndProofTarget> {
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> 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> {
) -> 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::<F, D>::new(config);
let mut pw = PartialWitness::<F>::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::<F, D>::new(config);
let mut pw = PartialWitness::<F>::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::<F, D>::new(config);
let mut pw = PartialWitness::<F>::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::<F, D>::new(config);
let mut pw = PartialWitness::<F>::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)?;

View file

@ -28,13 +28,13 @@ use crate::{
pub struct Signer(pub SecretKey);
impl Signer {
fn _sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> {
fn _sign(&mut self, params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> {
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::<HashMap<Key, Value>>();
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::<HashMap<Key, Value>>();
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(())

View file

@ -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<Value> = ["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(
&params,
&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<MainPodBuilder> {
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<MainPodBuilder> {
let params = Params::default();
let vd_set = &*DEFAULT_VD_SET;
let builder = tickets_sign_pod_builder(&params);
let signed_pod = builder.sign(&mut MockSigner { pk: "test".into() }).unwrap();
tickets_pod_builder(&params, &signed_pod, 123, true, &Set::new(HashSet::new())?)
tickets_pod_builder(
&params,
vd_set,
&signed_pod,
123,
true,
&Set::new(params.max_depth_mt_containers, HashSet::new())?,
)
}

View file

@ -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(&params);
let mut mp_builder = MainPodBuilder::new(&params, &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(&params);
let mut mp_builder = MainPodBuilder::new(&params, &vd_set);
let set_values: HashSet<Value> = [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))?;

View file

@ -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<SignedPod>,
pub input_main_pods: Vec<MainPod>,
pub statements: Vec<Statement>,
@ -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(&params);
println!("{}", gov_id);
@ -899,7 +902,7 @@ pub mod tests {
check_kvs(&sanction_list)?;
println!("{}", sanction_list);
let kyc_builder = zu_kyc_pod_builder(&params, &gov_id, &pay_stub, &sanction_list)?;
let kyc_builder = zu_kyc_pod_builder(&params, &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(
&params,
&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(&params);
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(&params);
let mut builder = MainPodBuilder::new(&params, &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(&params);
builder.insert("num", 2);
@ -1039,7 +1047,7 @@ pub mod tests {
println!("{}", pod);
let mut builder = MainPodBuilder::new(&params);
let mut builder = MainPodBuilder::new(&params, &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(&params);
let mut my_dict_kvs: HashMap<Key, Value> = 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(&params);
let mut builder = MainPodBuilder::new(&params, &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(&params);
let vd_set = &*DEFAULT_VD_SET;
let mut builder = MainPodBuilder::new(&params, &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(&params);
let mut builder = MainPodBuilder::new(&params, &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));

View file

@ -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([
Dictionary::new(
params.max_depth_mt_containers,
HashMap::from([
("foo".into(), 123.into()),
(
"an_array_containing_three_ints".into(),
Array::new(vec![1.into(), 2.into(), 3.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(),
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<MainPod> {
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(&params);
@ -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(&params, &gov_id_pod, &pay_stub_pod, &sanction_list_pod).unwrap();
let kyc_builder = zu_kyc_pod_builder(
&params,
&vd_set,
&gov_id_pod,
&pay_stub_pod,
&sanction_list_pod,
)
.unwrap();
let mut prover = MockProver {};
let kyc_pod = kyc_builder.prove(&mut prover, &params).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(&params);
@ -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(&params, &gov_id_pod, &pay_stub_pod, &sanction_list_pod)?;
let kyc_builder = zu_kyc_pod_builder(
&params,
&vd_set,
&gov_id_pod,
&pay_stub_pod,
&sanction_list_pod,
)?;
let mut prover = Prover {};
let kyc_pod = kyc_builder.prove(&mut prover, &params)?;
@ -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(
&params,
&vd_set,
true,
&alice_attestation,
&charlie_attestation,

View file

@ -659,8 +659,11 @@ fn process_literal_value(lit_val_pair: &Pair<Rule>) -> Result<Value, ProcessorEr
.into_inner()
.map(|elem_pair| process_literal_value(&elem_pair))
.collect();
let middleware_array = middleware::containers::Array::new(elements?)
.map_err(|e| ProcessorError::Internal(format!("Failed to create Array: {}", e)))?;
let middleware_array =
middleware::containers::Array::new(crate::constants::MAX_DEPTH, elements?)
.map_err(|e| {
ProcessorError::Internal(format!("Failed to create Array: {}", e))
})?;
Ok(Value::from(middleware_array))
}
Rule::literal_set => {
@ -668,8 +671,10 @@ fn process_literal_value(lit_val_pair: &Pair<Rule>) -> Result<Value, ProcessorEr
.into_inner()
.map(|elem_pair| process_literal_value(&elem_pair))
.collect();
let middleware_set = middleware::containers::Set::new(elements?)
.map_err(|e| ProcessorError::Internal(format!("Failed to create Set: {}", e)))?;
let middleware_set =
middleware::containers::Set::new(crate::constants::MAX_DEPTH, elements?).map_err(
|e| ProcessorError::Internal(format!("Failed to create Set: {}", e)),
)?;
Ok(Value::from(middleware_set))
}
Rule::literal_dict => {
@ -684,7 +689,9 @@ fn process_literal_value(lit_val_pair: &Pair<Rule>) -> Result<Value, ProcessorEr
Ok((Key::new(key_str), val))
})
.collect();
let middleware_dict = middleware::containers::Dictionary::new(pairs?).map_err(|e| {
let middleware_dict =
middleware::containers::Dictionary::new(crate::constants::MAX_DEPTH, pairs?)
.map_err(|e| {
ProcessorError::Internal(format!("Failed to create Dictionary: {}", e))
})?;
Ok(Value::from(middleware_dict))

View file

@ -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<Key, Value>,
}
impl Dictionary {
pub fn new(kvs: HashMap<Key, Value>) -> Result<Self> {
/// 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<Key, Value>) -> Result<Self> {
let kvs_raw: HashMap<RawValue, RawValue> = 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<MerkleProof> {
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<Key, Value> = HashMap::deserialize(deserializer)?;
Dictionary::new(kvs).map_err(serde::de::Error::custom)
#[derive(Deserialize)]
struct Aux {
#[serde(serialize_with = "ordered_map")]
kvs: HashMap<Key, Value>,
max_depth: usize,
}
}
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<Key, Value> since that's what we're actually serializing
<HashMap<Key, Value>>::json_schema(gen)
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<Value>,
}
impl Set {
pub fn new(set: HashSet<Value>) -> Result<Self> {
/// 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<Value>) -> Result<Self> {
let kvs_raw: HashMap<RawValue, RawValue> = 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<Value> = HashSet::deserialize(deserializer)?;
// Create a new Set using the set field
Set::new(set).map_err(serde::de::Error::custom)
#[derive(Deserialize, JsonSchema)]
struct Aux {
#[serde(serialize_with = "ordered_set")]
set: HashSet<Value>,
max_depth: usize,
}
}
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<Value> since that's what we're actually serializing
<HashSet<Value>>::json_schema(gen)
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<Value>,
}
impl Array {
pub fn new(array: Vec<Value>) -> Result<Self> {
/// 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<Value>) -> Result<Self> {
let kvs_raw: HashMap<RawValue, RawValue> = 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<Value> = 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<Value> since that's what we're actually serializing
<Vec<Value>>::json_schema(gen)
#[derive(Deserialize, JsonSchema)]
struct Aux {
array: Vec<Value>,
max_depth: usize,
}
let aux = Aux::deserialize(deserializer)?;
Array::new(aux.max_depth, aux.array).map_err(serde::de::Error::custom)
}
}

View file

@ -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<dyn RecursivePod>, Box<DynError>>;
}