chore(backend): implement more circuit op logic (#173)
* Add backend MerkleProof type * Add eval_not_contains * Remove print statement * Handle some edge cases * Add test * Add missing ? * Optimisation and stylistic changes * Code review
This commit is contained in:
parent
adad695ba5
commit
6528914366
10 changed files with 502 additions and 48 deletions
|
|
@ -3,14 +3,16 @@
|
||||||
use crate::backends::plonky2::basetypes::D;
|
use crate::backends::plonky2::basetypes::D;
|
||||||
use crate::backends::plonky2::mock::mainpod::Statement;
|
use crate::backends::plonky2::mock::mainpod::Statement;
|
||||||
use crate::backends::plonky2::mock::mainpod::{Operation, OperationArg};
|
use crate::backends::plonky2::mock::mainpod::{Operation, OperationArg};
|
||||||
|
use crate::backends::plonky2::primitives::merkletree::MerkleClaimAndProofTarget;
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
NativeOperation, NativePredicate, Params, Predicate, StatementArg, ToFields, Value,
|
NativeOperation, NativePredicate, Params, Predicate, StatementArg, ToFields, Value,
|
||||||
EMPTY_VALUE, F, HASH_SIZE, OPERATION_ARG_F_LEN, STATEMENT_ARG_F_LEN, VALUE_SIZE,
|
EMPTY_VALUE, F, HASH_SIZE, OPERATION_ARG_F_LEN, OPERATION_AUX_F_LEN, STATEMENT_ARG_F_LEN,
|
||||||
|
VALUE_SIZE,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use plonky2::field::extension::Extendable;
|
use plonky2::field::extension::Extendable;
|
||||||
use plonky2::field::types::{Field, PrimeField64};
|
use plonky2::field::types::{Field, PrimeField64};
|
||||||
use plonky2::hash::hash_types::RichField;
|
use plonky2::hash::hash_types::{HashOutTarget, RichField, NUM_HASH_OUT_ELTS};
|
||||||
use plonky2::iop::target::{BoolTarget, Target};
|
use plonky2::iop::target::{BoolTarget, Target};
|
||||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
|
@ -155,6 +157,7 @@ impl StatementTarget {
|
||||||
pub struct OperationTarget {
|
pub struct OperationTarget {
|
||||||
pub op_type: [Target; Params::operation_type_size()],
|
pub op_type: [Target; Params::operation_type_size()],
|
||||||
pub args: Vec<[Target; OPERATION_ARG_F_LEN]>,
|
pub args: Vec<[Target; OPERATION_ARG_F_LEN]>,
|
||||||
|
pub aux: [Target; OPERATION_AUX_F_LEN],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperationTarget {
|
impl OperationTarget {
|
||||||
|
|
@ -174,6 +177,7 @@ impl OperationTarget {
|
||||||
{
|
{
|
||||||
pw.set_target_arr(&self.args[i], &arg.to_fields(params))?;
|
pw.set_target_arr(&self.args[i], &arg.to_fields(params))?;
|
||||||
}
|
}
|
||||||
|
pw.set_target_arr(&self.aux, &op.aux().to_fields(params))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,6 +201,56 @@ pub trait Flattenable {
|
||||||
fn from_flattened(vs: &[Target]) -> Self;
|
fn from_flattened(vs: &[Target]) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For the purpose of op verification, we need only look up the
|
||||||
|
/// Merkle claim rather than the Merkle proof since it is verified
|
||||||
|
/// elsewhere.
|
||||||
|
pub struct MerkleClaimTarget {
|
||||||
|
pub(crate) enabled: BoolTarget,
|
||||||
|
pub(crate) root: HashOutTarget,
|
||||||
|
pub(crate) key: ValueTarget,
|
||||||
|
pub(crate) value: ValueTarget,
|
||||||
|
pub(crate) existence: BoolTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MerkleClaimAndProofTarget> for MerkleClaimTarget {
|
||||||
|
fn from(pf: MerkleClaimAndProofTarget) -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: pf.enabled,
|
||||||
|
root: pf.root,
|
||||||
|
key: pf.key,
|
||||||
|
value: pf.value,
|
||||||
|
existence: pf.existence,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flattenable for MerkleClaimTarget {
|
||||||
|
fn flatten(&self) -> Vec<Target> {
|
||||||
|
[
|
||||||
|
vec![self.enabled.target],
|
||||||
|
self.root.elements.to_vec(),
|
||||||
|
self.key.elements.to_vec(),
|
||||||
|
self.value.elements.to_vec(),
|
||||||
|
vec![self.existence.target],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_flattened(vs: &[Target]) -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: BoolTarget::new_unsafe(vs[0]),
|
||||||
|
root: HashOutTarget::from_vec((&vs[1..1 + NUM_HASH_OUT_ELTS]).to_vec()),
|
||||||
|
key: ValueTarget::from_slice(
|
||||||
|
&vs[1 + NUM_HASH_OUT_ELTS..1 + NUM_HASH_OUT_ELTS + VALUE_SIZE],
|
||||||
|
),
|
||||||
|
value: ValueTarget::from_slice(
|
||||||
|
&vs[1 + NUM_HASH_OUT_ELTS + VALUE_SIZE..1 + NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||||
|
),
|
||||||
|
existence: BoolTarget::new_unsafe(vs[1 + NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Flattenable for StatementTarget {
|
impl Flattenable for StatementTarget {
|
||||||
fn flatten(&self) -> Vec<Target> {
|
fn flatten(&self) -> Vec<Target> {
|
||||||
self.predicate
|
self.predicate
|
||||||
|
|
@ -290,6 +344,7 @@ impl CircuitBuilderPod<F, D> for CircuitBuilder<F, D> {
|
||||||
args: (0..params.max_operation_args)
|
args: (0..params.max_operation_args)
|
||||||
.map(|_| self.add_virtual_target_arr())
|
.map(|_| self.add_virtual_target_arr())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
aux: self.add_virtual_target_arr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use itertools::zip_eq;
|
use itertools::zip_eq;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::{hash_types::HashOutTarget, poseidon::PoseidonHash},
|
hash::{hash_types::HashOutTarget, poseidon::PoseidonHash},
|
||||||
|
|
@ -6,19 +6,27 @@ use plonky2::{
|
||||||
plonk::circuit_builder::CircuitBuilder,
|
plonk::circuit_builder::CircuitBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::backends::plonky2::basetypes::{Value, D, EMPTY_HASH, F, VALUE_SIZE};
|
|
||||||
use crate::backends::plonky2::circuits::common::{
|
|
||||||
CircuitBuilderPod, OperationTarget, StatementTarget, ValueTarget,
|
|
||||||
};
|
|
||||||
use crate::backends::plonky2::mock::mainpod;
|
use crate::backends::plonky2::mock::mainpod;
|
||||||
use crate::backends::plonky2::signedpod::SignedPod;
|
use crate::backends::plonky2::signedpod::SignedPod;
|
||||||
|
use crate::backends::plonky2::{
|
||||||
|
basetypes::{Value, D, EMPTY_HASH, F, VALUE_SIZE},
|
||||||
|
mock::mainpod::MerkleClaimAndProof,
|
||||||
|
primitives::merkletree::{MerkleClaimAndProofTarget, MerkleProofGadget},
|
||||||
|
};
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
hash_str, AnchoredKey, NativeOperation, NativePredicate, Params, PodType, Statement,
|
hash_str, AnchoredKey, NativeOperation, NativePredicate, Params, PodType, Statement,
|
||||||
StatementArg, ToFields, KEY_TYPE, SELF,
|
StatementArg, ToFields, KEY_TYPE, SELF,
|
||||||
};
|
};
|
||||||
|
use crate::{
|
||||||
|
backends::plonky2::{
|
||||||
|
circuits::common::{CircuitBuilderPod, OperationTarget, StatementTarget, ValueTarget},
|
||||||
|
primitives::merkletree,
|
||||||
|
},
|
||||||
|
middleware,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
common::Flattenable,
|
common::{Flattenable, MerkleClaimTarget},
|
||||||
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -37,6 +45,7 @@ impl OperationVerifyGadget {
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op: &OperationTarget,
|
op: &OperationTarget,
|
||||||
prev_statements: &[StatementTarget],
|
prev_statements: &[StatementTarget],
|
||||||
|
merkle_claims: &[MerkleClaimTarget],
|
||||||
) -> Result<OperationVerifyTarget> {
|
) -> Result<OperationVerifyTarget> {
|
||||||
let _true = builder._true();
|
let _true = builder._true();
|
||||||
let _false = builder._false();
|
let _false = builder._false();
|
||||||
|
|
@ -54,6 +63,12 @@ impl OperationVerifyGadget {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Certain operations (Contains/NotContains) will refer to one
|
||||||
|
// of the provided Merkle proofs (if any). These proofs have already
|
||||||
|
// been verified, so we need only look up the claim.
|
||||||
|
let resolved_merkle_claim =
|
||||||
|
(merkle_claims.len() > 0).then(|| builder.vec_ref(merkle_claims, op.aux[0]));
|
||||||
|
|
||||||
// The verification may require aux data which needs to be stored in the
|
// The verification may require aux data which needs to be stored in the
|
||||||
// `OperationVerifyTarget` so that we can set during witness generation.
|
// `OperationVerifyTarget` so that we can set during witness generation.
|
||||||
|
|
||||||
|
|
@ -77,6 +92,18 @@ impl OperationVerifyGadget {
|
||||||
self.eval_lt_from_entries(builder, st, op, &resolved_op_args),
|
self.eval_lt_from_entries(builder, st, op, &resolved_op_args),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
// Skip these if there are no resolved Merkle claims
|
||||||
|
if let Some(resolved_merkle_claim) = resolved_merkle_claim {
|
||||||
|
vec![self.eval_not_contains_from_entries(
|
||||||
|
builder,
|
||||||
|
st,
|
||||||
|
op,
|
||||||
|
resolved_merkle_claim,
|
||||||
|
&resolved_op_args,
|
||||||
|
)]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
|
|
@ -87,6 +114,74 @@ impl OperationVerifyGadget {
|
||||||
Ok(OperationVerifyTarget {})
|
Ok(OperationVerifyTarget {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_not_contains_from_entries(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
st: &StatementTarget,
|
||||||
|
op: &OperationTarget,
|
||||||
|
resolved_merkle_claim: MerkleClaimTarget,
|
||||||
|
resolved_op_args: &[StatementTarget],
|
||||||
|
) -> BoolTarget {
|
||||||
|
let op_code_ok = op.has_native_type(builder, NativeOperation::NotContainsFromEntries);
|
||||||
|
|
||||||
|
// Expect 2 op args of type `ValueOf`.
|
||||||
|
let op_arg_type_checks = resolved_op_args
|
||||||
|
.iter()
|
||||||
|
.take(2)
|
||||||
|
.map(|op_arg| op_arg.has_native_type(builder, &self.params, NativePredicate::ValueOf))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let op_arg_types_ok = builder.all(op_arg_type_checks);
|
||||||
|
|
||||||
|
// The values embedded in the op args must be values, i.e. the
|
||||||
|
// last `STATEMENT_ARG_F_LEN - VALUE_SIZE` slots of each being
|
||||||
|
// 0.
|
||||||
|
let merkle_root_arg = &resolved_op_args[0].args[1];
|
||||||
|
let key_arg = &resolved_op_args[1].args[1];
|
||||||
|
let op_arg_range_checks = [
|
||||||
|
builder.statement_arg_is_value(merkle_root_arg),
|
||||||
|
builder.statement_arg_is_value(key_arg),
|
||||||
|
];
|
||||||
|
let op_arg_range_ok = builder.all(op_arg_range_checks);
|
||||||
|
|
||||||
|
// Check Merkle proof (verified elsewhere) against op args.
|
||||||
|
let merkle_proof_checks = [
|
||||||
|
/* The supplied Merkle proof must be enabled. */
|
||||||
|
resolved_merkle_claim.enabled,
|
||||||
|
/* ...and it must be a nonexistence proof. */
|
||||||
|
builder.not(resolved_merkle_claim.existence),
|
||||||
|
/* ...for the root-key pair in the resolved op args. */
|
||||||
|
builder.is_equal_slice(
|
||||||
|
&merkle_root_arg.elements[..VALUE_SIZE],
|
||||||
|
&resolved_merkle_claim.root.elements,
|
||||||
|
),
|
||||||
|
builder.is_equal_slice(
|
||||||
|
&key_arg.elements[..VALUE_SIZE],
|
||||||
|
&resolved_merkle_claim.key.elements,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let merkle_proof_ok = builder.all(merkle_proof_checks);
|
||||||
|
|
||||||
|
// Check output statement
|
||||||
|
let arg1_key = resolved_op_args[0].args[0].clone();
|
||||||
|
let arg2_key = resolved_op_args[1].args[0].clone();
|
||||||
|
let expected_statement = StatementTarget::new_native(
|
||||||
|
builder,
|
||||||
|
&self.params,
|
||||||
|
NativePredicate::NotContains,
|
||||||
|
&[arg1_key, arg2_key],
|
||||||
|
);
|
||||||
|
let st_ok = builder.is_equal_flattenable(st, &expected_statement);
|
||||||
|
|
||||||
|
builder.all([
|
||||||
|
op_code_ok,
|
||||||
|
op_arg_types_ok,
|
||||||
|
op_arg_range_ok,
|
||||||
|
merkle_proof_ok,
|
||||||
|
st_ok,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_eq_from_entries(
|
fn eval_eq_from_entries(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
|
@ -315,6 +410,19 @@ impl MainPodVerifyGadget {
|
||||||
let pub_statements =
|
let pub_statements =
|
||||||
&input_statements[input_statements.len() - params.max_public_statements..];
|
&input_statements[input_statements.len() - params.max_public_statements..];
|
||||||
|
|
||||||
|
// Add Merkle claim/proof targets
|
||||||
|
let mp_gadget = MerkleProofGadget {
|
||||||
|
max_depth: params.max_depth_mt_gadget,
|
||||||
|
};
|
||||||
|
let merkle_proofs: Vec<_> = (0..params.max_merkle_proofs)
|
||||||
|
.map(|_| mp_gadget.eval(builder))
|
||||||
|
.collect::<Result<_>>()?;
|
||||||
|
let merkle_claims: Vec<_> = merkle_proofs
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|pf| pf.into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
// 2. Calculate the Pod Id from the public statements
|
// 2. Calculate the Pod Id from the public statements
|
||||||
let pub_statements_flattened = pub_statements
|
let pub_statements_flattened = pub_statements
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -350,7 +458,7 @@ impl MainPodVerifyGadget {
|
||||||
let op_verification = OperationVerifyGadget {
|
let op_verification = OperationVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
}
|
}
|
||||||
.eval(builder, st, op, prev_statements)?;
|
.eval(builder, st, op, prev_statements, &merkle_claims)?;
|
||||||
op_verifications.push(op_verification);
|
op_verifications.push(op_verification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,6 +468,7 @@ impl MainPodVerifyGadget {
|
||||||
signed_pods,
|
signed_pods,
|
||||||
statements: input_statements.to_vec(),
|
statements: input_statements.to_vec(),
|
||||||
operations,
|
operations,
|
||||||
|
merkle_proofs,
|
||||||
op_verifications,
|
op_verifications,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -372,6 +481,7 @@ pub struct MainPodVerifyTarget {
|
||||||
// The KEY_TYPE statement must be the first public one
|
// The KEY_TYPE statement must be the first public one
|
||||||
statements: Vec<StatementTarget>,
|
statements: Vec<StatementTarget>,
|
||||||
operations: Vec<OperationTarget>,
|
operations: Vec<OperationTarget>,
|
||||||
|
merkle_proofs: Vec<MerkleClaimAndProofTarget>,
|
||||||
op_verifications: Vec<OperationVerifyTarget>,
|
op_verifications: Vec<OperationVerifyTarget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,6 +489,7 @@ pub struct MainPodVerifyInput {
|
||||||
pub signed_pods: Vec<SignedPod>,
|
pub signed_pods: Vec<SignedPod>,
|
||||||
pub statements: Vec<mainpod::Statement>,
|
pub statements: Vec<mainpod::Statement>,
|
||||||
pub operations: Vec<mainpod::Operation>,
|
pub operations: Vec<mainpod::Operation>,
|
||||||
|
pub merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainPodVerifyTarget {
|
impl MainPodVerifyTarget {
|
||||||
|
|
@ -402,6 +513,23 @@ impl MainPodVerifyTarget {
|
||||||
self.statements[i].set_targets(pw, &self.params, st)?;
|
self.statements[i].set_targets(pw, &self.params, st)?;
|
||||||
self.operations[i].set_targets(pw, &self.params, op)?;
|
self.operations[i].set_targets(pw, &self.params, op)?;
|
||||||
}
|
}
|
||||||
|
assert_eq!(input.merkle_proofs.len(), self.params.max_merkle_proofs);
|
||||||
|
for (i, mp) in input.merkle_proofs.iter().enumerate() {
|
||||||
|
assert_eq!(mp.siblings.len(), self.params.max_depth_mt_gadget);
|
||||||
|
self.merkle_proofs[i].set_targets(
|
||||||
|
pw,
|
||||||
|
mp.enabled,
|
||||||
|
mp.existence,
|
||||||
|
mp.root,
|
||||||
|
mp.clone().try_into().unwrap_or(merkletree::MerkleProof {
|
||||||
|
existence: mp.existence,
|
||||||
|
siblings: mp.siblings.clone(),
|
||||||
|
other_leaf: None,
|
||||||
|
}),
|
||||||
|
mp.key,
|
||||||
|
mp.value,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -423,6 +551,7 @@ impl MainPodVerifyCircuit {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use merkletree::MerkleTree;
|
||||||
use plonky2::plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig};
|
use plonky2::plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -437,8 +566,12 @@ mod tests {
|
||||||
st: mainpod::Statement,
|
st: mainpod::Statement,
|
||||||
op: mainpod::Operation,
|
op: mainpod::Operation,
|
||||||
prev_statements: Vec<mainpod::Statement>,
|
prev_statements: Vec<mainpod::Statement>,
|
||||||
|
merkle_proofs: Vec<mainpod::MerkleClaimAndProof>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let params = Params::default();
|
let params = Params::default();
|
||||||
|
let mp_gadget = MerkleProofGadget {
|
||||||
|
max_depth: params.max_depth_mt_gadget,
|
||||||
|
};
|
||||||
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
|
@ -448,6 +581,15 @@ mod tests {
|
||||||
let prev_statements_target: Vec<_> = (0..prev_statements.len())
|
let prev_statements_target: Vec<_> = (0..prev_statements.len())
|
||||||
.map(|_| builder.add_virtual_statement(¶ms))
|
.map(|_| builder.add_virtual_statement(¶ms))
|
||||||
.collect();
|
.collect();
|
||||||
|
let merkle_proofs_target: Vec<_> = merkle_proofs
|
||||||
|
.iter()
|
||||||
|
.map(|_| mp_gadget.eval(&mut builder))
|
||||||
|
.collect::<Result<_>>()?;
|
||||||
|
let merkle_claims_target: Vec<_> = merkle_proofs_target
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|pf| pf.into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let operation_verify = OperationVerifyGadget {
|
let operation_verify = OperationVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
|
|
@ -457,6 +599,7 @@ mod tests {
|
||||||
&st_target,
|
&st_target,
|
||||||
&op_target,
|
&op_target,
|
||||||
&prev_statements_target,
|
&prev_statements_target,
|
||||||
|
&merkle_claims_target,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut pw = PartialWitness::<F>::new();
|
let mut pw = PartialWitness::<F>::new();
|
||||||
|
|
@ -465,6 +608,19 @@ mod tests {
|
||||||
for (prev_st_target, prev_st) in prev_statements_target.iter().zip(prev_statements.iter()) {
|
for (prev_st_target, prev_st) in prev_statements_target.iter().zip(prev_statements.iter()) {
|
||||||
prev_st_target.set_targets(&mut pw, ¶ms, prev_st)?;
|
prev_st_target.set_targets(&mut pw, ¶ms, prev_st)?;
|
||||||
}
|
}
|
||||||
|
for (merkle_proof_target, merkle_proof) in
|
||||||
|
merkle_proofs_target.iter().zip(merkle_proofs.iter())
|
||||||
|
{
|
||||||
|
merkle_proof_target.set_targets(
|
||||||
|
&mut pw,
|
||||||
|
merkle_proof.enabled,
|
||||||
|
merkle_proof.existence,
|
||||||
|
merkle_proof.root,
|
||||||
|
merkle_proof.clone().try_into()?,
|
||||||
|
merkle_proof.key,
|
||||||
|
merkle_proof.value,
|
||||||
|
)?
|
||||||
|
}
|
||||||
let input = OperationVerifyInput {};
|
let input = OperationVerifyInput {};
|
||||||
operation_verify.set_targets(&mut pw, &input)?;
|
operation_verify.set_targets(&mut pw, &input)?;
|
||||||
|
|
||||||
|
|
@ -478,6 +634,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_operation_verify() -> Result<()> {
|
fn test_operation_verify() -> Result<()> {
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
// None
|
// None
|
||||||
let st: mainpod::Statement = Statement::None.into();
|
let st: mainpod::Statement = Statement::None.into();
|
||||||
let op = mainpod::Operation(
|
let op = mainpod::Operation(
|
||||||
|
|
@ -486,7 +644,13 @@ mod tests {
|
||||||
OperationAux::None,
|
OperationAux::None,
|
||||||
);
|
);
|
||||||
let prev_statements = vec![Statement::None.into()];
|
let prev_statements = vec![Statement::None.into()];
|
||||||
operation_verify(st.clone(), op, prev_statements.clone())?;
|
let merkle_proofs = vec![];
|
||||||
|
operation_verify(
|
||||||
|
st.clone(),
|
||||||
|
op,
|
||||||
|
prev_statements.clone(),
|
||||||
|
merkle_proofs.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// NewEntry
|
// NewEntry
|
||||||
let st1: mainpod::Statement =
|
let st1: mainpod::Statement =
|
||||||
|
|
@ -502,7 +666,12 @@ mod tests {
|
||||||
vec![],
|
vec![],
|
||||||
OperationAux::None,
|
OperationAux::None,
|
||||||
);
|
);
|
||||||
operation_verify(st1.clone(), op, prev_statements.clone())?;
|
operation_verify(
|
||||||
|
st1.clone(),
|
||||||
|
op,
|
||||||
|
prev_statements.clone(),
|
||||||
|
merkle_proofs.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// Copy
|
// Copy
|
||||||
let st: mainpod::Statement = Statement::None.into();
|
let st: mainpod::Statement = Statement::None.into();
|
||||||
|
|
@ -512,7 +681,7 @@ mod tests {
|
||||||
OperationAux::None,
|
OperationAux::None,
|
||||||
);
|
);
|
||||||
let prev_statements = vec![Statement::None.into()];
|
let prev_statements = vec![Statement::None.into()];
|
||||||
operation_verify(st, op, prev_statements)?;
|
operation_verify(st, op, prev_statements, merkle_proofs.clone())?;
|
||||||
|
|
||||||
// Eq
|
// Eq
|
||||||
let st2: mainpod::Statement = Statement::ValueOf(
|
let st2: mainpod::Statement = Statement::ValueOf(
|
||||||
|
|
@ -531,7 +700,7 @@ mod tests {
|
||||||
OperationAux::None,
|
OperationAux::None,
|
||||||
);
|
);
|
||||||
let prev_statements = vec![st1.clone(), st2];
|
let prev_statements = vec![st1.clone(), st2];
|
||||||
operation_verify(st, op, prev_statements)?;
|
operation_verify(st, op, prev_statements, merkle_proofs.clone())?;
|
||||||
|
|
||||||
// Lt
|
// Lt
|
||||||
let st2: mainpod::Statement = Statement::ValueOf(
|
let st2: mainpod::Statement = Statement::ValueOf(
|
||||||
|
|
@ -550,7 +719,40 @@ mod tests {
|
||||||
OperationAux::None,
|
OperationAux::None,
|
||||||
);
|
);
|
||||||
let prev_statements = vec![st1.clone(), st2];
|
let prev_statements = vec![st1.clone(), st2];
|
||||||
operation_verify(st, op, prev_statements)?;
|
operation_verify(st, op, prev_statements, merkle_proofs.clone())?;
|
||||||
|
|
||||||
|
// NotContainsFromEntries
|
||||||
|
let kvs = [
|
||||||
|
(1.into(), 55.into()),
|
||||||
|
(2.into(), 88.into()),
|
||||||
|
(175.into(), 0.into()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
let mt = MerkleTree::new(params.max_depth_mt_gadget, &kvs)?;
|
||||||
|
|
||||||
|
let root = mt.root().into();
|
||||||
|
let root_ak = AnchoredKey(PodId(Value::from(88).into()), "merkle root".into());
|
||||||
|
|
||||||
|
let key = 5.into();
|
||||||
|
let key_ak = AnchoredKey(PodId(Value::from(88).into()), "key".into());
|
||||||
|
|
||||||
|
let no_key_pf = mt.prove_nonexistence(&key)?;
|
||||||
|
|
||||||
|
let root_st: mainpod::Statement = Statement::ValueOf(root_ak, root).into();
|
||||||
|
let key_st: mainpod::Statement = Statement::ValueOf(key_ak, key).into();
|
||||||
|
let st: mainpod::Statement = Statement::NotContains(root_ak, key_ak).into();
|
||||||
|
let op = mainpod::Operation(
|
||||||
|
OperationType::Native(NativeOperation::NotContainsFromEntries),
|
||||||
|
vec![OperationArg::Index(0), OperationArg::Index(1)],
|
||||||
|
OperationAux::MerkleProofIndex(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let merkle_proofs = vec![mainpod::MerkleClaimAndProof::try_from_middleware(
|
||||||
|
¶ms, &root, &key, None, &no_key_pf,
|
||||||
|
)?];
|
||||||
|
let prev_statements = vec![root_st, key_st];
|
||||||
|
operation_verify(st, op, prev_statements, merkle_proofs.clone())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ use crate::middleware::{
|
||||||
SELF,
|
SELF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::mock::mainpod::MerkleClaimAndProof;
|
||||||
|
|
||||||
pub struct Prover {}
|
pub struct Prover {}
|
||||||
|
|
||||||
impl PodProver for Prover {
|
impl PodProver for Prover {
|
||||||
|
|
@ -47,12 +49,14 @@ impl PodProver for Prover {
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
|
let merkle_proofs = MockMainPod::extract_merkle_proofs(params, &inputs.operations)?;
|
||||||
|
|
||||||
// TODO: Move these methods from the mock main pod to a common place
|
// TODO: Move these methods from the mock main pod to a common place
|
||||||
let statements = MockMainPod::layout_statements(params, &inputs);
|
let statements = MockMainPod::layout_statements(params, &inputs);
|
||||||
let operations = MockMainPod::process_private_statements_operations(
|
let operations = MockMainPod::process_private_statements_operations(
|
||||||
params,
|
params,
|
||||||
&statements,
|
&statements,
|
||||||
&[], // TODO: fill in the merkle proofs for Contains/NotContains ops
|
&merkle_proofs,
|
||||||
inputs.operations,
|
inputs.operations,
|
||||||
)?;
|
)?;
|
||||||
let operations =
|
let operations =
|
||||||
|
|
@ -67,6 +71,7 @@ impl PodProver for Prover {
|
||||||
signed_pods: signed_pods_input,
|
signed_pods: signed_pods_input,
|
||||||
statements: statements[statements.len() - params.max_statements..].to_vec(),
|
statements: statements[statements.len() - params.max_statements..].to_vec(),
|
||||||
operations,
|
operations,
|
||||||
|
merkle_proofs,
|
||||||
};
|
};
|
||||||
main_pod.set_targets(&mut pw, &input)?;
|
main_pod.set_targets(&mut pw, &input)?;
|
||||||
|
|
||||||
|
|
@ -173,19 +178,28 @@ pub mod tests {
|
||||||
pay_stub: &frontend::SignedPod,
|
pay_stub: &frontend::SignedPod,
|
||||||
sanction_list: &frontend::SignedPod,
|
sanction_list: &frontend::SignedPod,
|
||||||
) -> Result<frontend::MainPodBuilder> {
|
) -> Result<frontend::MainPodBuilder> {
|
||||||
|
let sanction_set = match sanction_list.kvs.get("sanctionList") {
|
||||||
|
Some(frontend::Value::Set(s)) => Ok(s),
|
||||||
|
_ => Err(anyhow!("Missing sanction list!")),
|
||||||
|
}?;
|
||||||
let now_minus_18y: i64 = 1169909388;
|
let now_minus_18y: i64 = 1169909388;
|
||||||
let now_minus_1y: i64 = 1706367566;
|
let now_minus_1y: i64 = 1706367566;
|
||||||
|
|
||||||
|
let gov_id_kvs = gov_id.kvs();
|
||||||
|
let id_number_value = gov_id_kvs.get(&"idNumber".into()).unwrap();
|
||||||
|
|
||||||
let mut kyc = frontend::MainPodBuilder::new(params);
|
let mut kyc = frontend::MainPodBuilder::new(params);
|
||||||
kyc.add_signed_pod(gov_id);
|
kyc.add_signed_pod(gov_id);
|
||||||
kyc.add_signed_pod(pay_stub);
|
kyc.add_signed_pod(pay_stub);
|
||||||
kyc.add_signed_pod(sanction_list);
|
kyc.add_signed_pod(sanction_list);
|
||||||
// NOTE: Unimplemented in the circuit
|
kyc.pub_op(op!(
|
||||||
// kyc.pub_op(op!(
|
set_not_contains,
|
||||||
// not_contains,
|
(sanction_list, "sanctionList"),
|
||||||
// (sanction_list, "sanctionList"),
|
(gov_id, "idNumber"),
|
||||||
// (gov_id, "idNumber")
|
sanction_set
|
||||||
// ))?;
|
.middleware_set()
|
||||||
|
.prove_nonexistence(id_number_value)?
|
||||||
|
))?;
|
||||||
kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y))?;
|
kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y))?;
|
||||||
kyc.pub_op(op!(
|
kyc.pub_op(op!(
|
||||||
eq,
|
eq,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use std::any::Any;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::MerkleProof,
|
backends::plonky2::primitives::merkletree,
|
||||||
middleware::{
|
middleware::{
|
||||||
self, hash_str, AnchoredKey, Hash, MainPodInputs, NativeOperation, NativePredicate,
|
self, hash_str, AnchoredKey, Hash, MainPodInputs, NativeOperation, NativePredicate,
|
||||||
NonePod, OperationType, Params, Pod, PodId, PodProver, PodType, Predicate, StatementArg,
|
NonePod, OperationType, Params, Pod, PodId, PodProver, PodType, Predicate, StatementArg,
|
||||||
|
|
@ -44,7 +44,7 @@ pub struct MockMainPod {
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
// All Merkle proofs
|
// All Merkle proofs
|
||||||
// TODO: Use a backend-specific representation
|
// TODO: Use a backend-specific representation
|
||||||
merkle_proofs: Vec<MerkleProof>,
|
merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for MockMainPod {
|
impl fmt::Display for MockMainPod {
|
||||||
|
|
@ -227,6 +227,52 @@ impl MockMainPod {
|
||||||
statements
|
statements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts and pads Merkle proofs from Contains/NotContains ops.
|
||||||
|
pub(crate) fn extract_merkle_proofs(
|
||||||
|
params: &Params,
|
||||||
|
operations: &[middleware::Operation],
|
||||||
|
) -> Result<Vec<MerkleClaimAndProof>> {
|
||||||
|
let mut merkle_proofs = operations
|
||||||
|
.iter()
|
||||||
|
.flat_map(|op| match op {
|
||||||
|
middleware::Operation::ContainsFromEntries(
|
||||||
|
middleware::Statement::ValueOf(_, root),
|
||||||
|
middleware::Statement::ValueOf(_, key),
|
||||||
|
middleware::Statement::ValueOf(_, value),
|
||||||
|
pf,
|
||||||
|
) => Some(MerkleClaimAndProof::try_from_middleware(
|
||||||
|
params,
|
||||||
|
root,
|
||||||
|
key,
|
||||||
|
Some(value),
|
||||||
|
pf,
|
||||||
|
)),
|
||||||
|
middleware::Operation::NotContainsFromEntries(
|
||||||
|
middleware::Statement::ValueOf(_, root),
|
||||||
|
middleware::Statement::ValueOf(_, key),
|
||||||
|
pf,
|
||||||
|
) => Some(MerkleClaimAndProof::try_from_middleware(
|
||||||
|
params, root, key, None, pf,
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
if merkle_proofs.len() > params.max_merkle_proofs {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"The number of required Merkle proofs ({}) exceeds the maximum number ({}).",
|
||||||
|
merkle_proofs.len(),
|
||||||
|
params.max_merkle_proofs
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
fill_pad(
|
||||||
|
&mut merkle_proofs,
|
||||||
|
MerkleClaimAndProof::empty(params.max_depth_mt_gadget),
|
||||||
|
params.max_merkle_proofs,
|
||||||
|
);
|
||||||
|
Ok(merkle_proofs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_op_arg(
|
fn find_op_arg(
|
||||||
statements: &[Statement],
|
statements: &[Statement],
|
||||||
op_arg: &middleware::Statement,
|
op_arg: &middleware::Statement,
|
||||||
|
|
@ -248,7 +294,7 @@ impl MockMainPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_op_aux(
|
fn find_op_aux(
|
||||||
merkle_proofs: &[MerkleProof],
|
merkle_proofs: &[MerkleClaimAndProof],
|
||||||
op_aux: &middleware::OperationAux,
|
op_aux: &middleware::OperationAux,
|
||||||
) -> Result<OperationAux> {
|
) -> Result<OperationAux> {
|
||||||
match op_aux {
|
match op_aux {
|
||||||
|
|
@ -256,7 +302,14 @@ impl MockMainPod {
|
||||||
middleware::OperationAux::MerkleProof(pf_arg) => merkle_proofs
|
middleware::OperationAux::MerkleProof(pf_arg) => merkle_proofs
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(i, pf)| (pf == pf_arg).then_some(i))
|
.find_map(|(i, pf)| {
|
||||||
|
pf.clone()
|
||||||
|
.try_into()
|
||||||
|
.ok()
|
||||||
|
.and_then(|mid_pf: merkletree::MerkleProof| {
|
||||||
|
(&mid_pf == pf_arg).then_some(i)
|
||||||
|
})
|
||||||
|
})
|
||||||
.map(OperationAux::MerkleProofIndex)
|
.map(OperationAux::MerkleProofIndex)
|
||||||
.ok_or(anyhow!(
|
.ok_or(anyhow!(
|
||||||
"Merkle proof corresponding to op arg {} not found",
|
"Merkle proof corresponding to op arg {} not found",
|
||||||
|
|
@ -268,7 +321,7 @@ impl MockMainPod {
|
||||||
pub(crate) fn process_private_statements_operations(
|
pub(crate) fn process_private_statements_operations(
|
||||||
params: &Params,
|
params: &Params,
|
||||||
statements: &[Statement],
|
statements: &[Statement],
|
||||||
merkle_proofs: &[MerkleProof],
|
merkle_proofs: &[MerkleClaimAndProof],
|
||||||
input_operations: &[middleware::Operation],
|
input_operations: &[middleware::Operation],
|
||||||
) -> Result<Vec<Operation>> {
|
) -> Result<Vec<Operation>> {
|
||||||
let mut operations = Vec::new();
|
let mut operations = Vec::new();
|
||||||
|
|
@ -336,15 +389,9 @@ impl MockMainPod {
|
||||||
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
||||||
// value=PodType::MockMainPod`
|
// value=PodType::MockMainPod`
|
||||||
let statements = Self::layout_statements(params, &inputs);
|
let statements = Self::layout_statements(params, &inputs);
|
||||||
let merkle_proofs = inputs
|
// Extract Merkle proofs and pad.
|
||||||
.operations
|
let merkle_proofs = Self::extract_merkle_proofs(params, &inputs.operations)?;
|
||||||
.iter()
|
|
||||||
.flat_map(|op| match op {
|
|
||||||
middleware::Operation::ContainsFromEntries(_, _, _, pf) => Some(pf.clone()),
|
|
||||||
middleware::Operation::NotContainsFromEntries(_, _, pf) => Some(pf.clone()),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let operations = Self::process_private_statements_operations(
|
let operations = Self::process_private_statements_operations(
|
||||||
params,
|
params,
|
||||||
&statements,
|
&statements,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use super::Statement;
|
use super::Statement;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::MerkleProof,
|
backends::plonky2::primitives::merkletree::{self, kv_hash},
|
||||||
middleware::{self, OperationType, Params, ToFields, F},
|
middleware::{self, Hash, OperationType, Params, ToFields, Value, EMPTY_HASH, EMPTY_VALUE, F},
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use plonky2::field::types::{Field, PrimeField64};
|
use plonky2::field::types::{Field, PrimeField64};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::{fmt, iter};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum OperationArg {
|
pub enum OperationArg {
|
||||||
|
|
@ -36,6 +36,118 @@ pub enum OperationAux {
|
||||||
MerkleProofIndex(usize),
|
MerkleProofIndex(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToFields for OperationAux {
|
||||||
|
fn to_fields(&self, _params: &Params) -> Vec<F> {
|
||||||
|
let f = match self {
|
||||||
|
Self::None => F::ZERO,
|
||||||
|
Self::MerkleProofIndex(i) => F::from_canonical_usize(*i),
|
||||||
|
};
|
||||||
|
vec![f]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct MerkleClaimAndProof {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub root: Hash,
|
||||||
|
pub key: Value,
|
||||||
|
pub value: Value,
|
||||||
|
pub existence: bool,
|
||||||
|
pub siblings: Vec<Hash>,
|
||||||
|
pub case_ii_selector: bool,
|
||||||
|
pub other_key: Value,
|
||||||
|
pub other_value: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MerkleClaimAndProof {
|
||||||
|
pub fn empty(max_depth: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: false,
|
||||||
|
root: EMPTY_HASH,
|
||||||
|
key: Value::from(1),
|
||||||
|
value: EMPTY_VALUE,
|
||||||
|
existence: false,
|
||||||
|
siblings: iter::repeat(EMPTY_HASH).take(max_depth).collect(),
|
||||||
|
case_ii_selector: false,
|
||||||
|
other_key: EMPTY_VALUE,
|
||||||
|
other_value: EMPTY_VALUE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_from_middleware(
|
||||||
|
params: &Params,
|
||||||
|
root: &Value,
|
||||||
|
key: &Value,
|
||||||
|
value: Option<&Value>,
|
||||||
|
mid_mp: &merkletree::MerkleProof,
|
||||||
|
) -> Result<Self> {
|
||||||
|
if mid_mp.siblings.len() > params.max_depth_mt_gadget {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Number of siblings ({}) exceeds maximum depth ({})",
|
||||||
|
mid_mp.siblings.len(),
|
||||||
|
params.max_depth_mt_gadget
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
let (other_key, other_value) = mid_mp.other_leaf.unwrap_or((EMPTY_VALUE, EMPTY_VALUE));
|
||||||
|
Ok(Self {
|
||||||
|
enabled: true,
|
||||||
|
root: root.clone().into(),
|
||||||
|
key: key.clone(),
|
||||||
|
value: value.cloned().unwrap_or(EMPTY_VALUE),
|
||||||
|
existence: mid_mp.existence,
|
||||||
|
siblings: mid_mp
|
||||||
|
.siblings
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(iter::repeat(EMPTY_HASH))
|
||||||
|
.take(params.max_depth_mt_gadget)
|
||||||
|
.collect(),
|
||||||
|
case_ii_selector: mid_mp.other_leaf.is_some(),
|
||||||
|
other_key,
|
||||||
|
other_value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<MerkleClaimAndProof> for merkletree::MerkleProof {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
fn try_from(mp: MerkleClaimAndProof) -> Result<Self> {
|
||||||
|
if !mp.enabled {
|
||||||
|
return Err(anyhow!("Not a valid Merkle proof."));
|
||||||
|
}
|
||||||
|
let existence = mp.existence;
|
||||||
|
let other_leaf = if mp.case_ii_selector {
|
||||||
|
Some((mp.other_key, mp.other_value))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
// Trim padding (if any).
|
||||||
|
let siblings = mp
|
||||||
|
.siblings
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.skip_while(|s| s == &EMPTY_HASH)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.collect();
|
||||||
|
Ok(merkletree::MerkleProof {
|
||||||
|
existence,
|
||||||
|
siblings,
|
||||||
|
other_leaf,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MerkleClaimAndProof {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match merkletree::MerkleProof::try_from(self.clone()) {
|
||||||
|
Err(_) => write!(f, "∅"),
|
||||||
|
Ok(mp) => mp.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
|
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
|
||||||
|
|
||||||
|
|
@ -46,10 +158,13 @@ impl Operation {
|
||||||
pub fn args(&self) -> &[OperationArg] {
|
pub fn args(&self) -> &[OperationArg] {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
pub fn aux(&self) -> &OperationAux {
|
||||||
|
&self.2
|
||||||
|
}
|
||||||
pub fn deref(
|
pub fn deref(
|
||||||
&self,
|
&self,
|
||||||
statements: &[Statement],
|
statements: &[Statement],
|
||||||
merkle_proofs: &[MerkleProof],
|
merkle_proofs: &[MerkleClaimAndProof],
|
||||||
) -> Result<crate::middleware::Operation> {
|
) -> Result<crate::middleware::Operation> {
|
||||||
let deref_args = self
|
let deref_args = self
|
||||||
.1
|
.1
|
||||||
|
|
@ -65,7 +180,10 @@ impl Operation {
|
||||||
.get(i)
|
.get(i)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(anyhow!("Missing Merkle proof index {}", i))
|
.ok_or(anyhow!("Missing Merkle proof index {}", i))
|
||||||
.map(crate::middleware::OperationAux::MerkleProof),
|
.and_then(|mp| {
|
||||||
|
mp.try_into()
|
||||||
|
.map(crate::middleware::OperationAux::MerkleProof)
|
||||||
|
}),
|
||||||
}?;
|
}?;
|
||||||
middleware::Operation::op(self.0.clone(), &deref_args, &deref_aux)
|
middleware::Operation::op(self.0.clone(), &deref_args, &deref_aux)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,21 @@ pub struct MerkleTree {
|
||||||
impl MerkleTree {
|
impl MerkleTree {
|
||||||
/// builds a new `MerkleTree` where the leaves contain the given key-values
|
/// builds a new `MerkleTree` where the leaves contain the given key-values
|
||||||
pub fn new(max_depth: usize, kvs: &HashMap<Value, Value>) -> Result<Self> {
|
pub fn new(max_depth: usize, kvs: &HashMap<Value, Value>) -> Result<Self> {
|
||||||
let mut root = Node::Intermediate(Intermediate::empty());
|
// Construct leaves.
|
||||||
|
let mut leaves: Vec<_> = kvs
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| Leaf::new(max_depth, *k, *v))
|
||||||
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
for (k, v) in kvs.iter() {
|
// Start with a leaf or conclude with an empty node as root.
|
||||||
let leaf = Leaf::new(max_depth, *k, *v)?;
|
let mut root = leaves.pop().map(|l| Node::Leaf(l)).unwrap_or(Node::None);
|
||||||
|
|
||||||
|
// Iterate over remaining leaves (if any) and add them.
|
||||||
|
for leaf in leaves.into_iter() {
|
||||||
root.add_leaf(0, max_depth, leaf)?;
|
root.add_leaf(0, max_depth, leaf)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill in hashes.
|
||||||
let _ = root.compute_hash();
|
let _ = root.compute_hash();
|
||||||
Ok(Self { max_depth, root })
|
Ok(Self { max_depth, root })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,9 @@ pub struct MerkleProofGadget {
|
||||||
pub max_depth: usize,
|
pub max_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MerkleProofTarget {
|
#[derive(Clone)]
|
||||||
max_depth: usize,
|
pub struct MerkleClaimAndProofTarget {
|
||||||
|
pub(crate) max_depth: usize,
|
||||||
// `enabled` determines if the merkleproof verification is enabled
|
// `enabled` determines if the merkleproof verification is enabled
|
||||||
pub(crate) enabled: BoolTarget,
|
pub(crate) enabled: BoolTarget,
|
||||||
pub(crate) root: HashOutTarget,
|
pub(crate) root: HashOutTarget,
|
||||||
|
|
@ -51,7 +52,7 @@ pub struct MerkleProofTarget {
|
||||||
|
|
||||||
impl MerkleProofGadget {
|
impl MerkleProofGadget {
|
||||||
/// creates the targets and defines the logic of the circuit
|
/// creates the targets and defines the logic of the circuit
|
||||||
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<MerkleProofTarget> {
|
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<MerkleClaimAndProofTarget> {
|
||||||
let enabled = builder.add_virtual_bool_target_safe();
|
let enabled = builder.add_virtual_bool_target_safe();
|
||||||
let root = builder.add_virtual_hash();
|
let root = builder.add_virtual_hash();
|
||||||
let key = builder.add_virtual_value();
|
let key = builder.add_virtual_value();
|
||||||
|
|
@ -133,7 +134,7 @@ impl MerkleProofGadget {
|
||||||
builder.connect(computed_root[j], expected_root[j]);
|
builder.connect(computed_root[j], expected_root[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(MerkleProofTarget {
|
Ok(MerkleClaimAndProofTarget {
|
||||||
max_depth: self.max_depth,
|
max_depth: self.max_depth,
|
||||||
enabled,
|
enabled,
|
||||||
existence,
|
existence,
|
||||||
|
|
@ -148,7 +149,7 @@ impl MerkleProofGadget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MerkleProofTarget {
|
impl MerkleClaimAndProofTarget {
|
||||||
/// assigns the given values to the targets
|
/// assigns the given values to the targets
|
||||||
pub fn set_targets(
|
pub fn set_targets(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::backends::plonky2::primitives::merkletree::MerkleProof;
|
||||||
|
|
||||||
pub const SELF: PodId = PodId(SELF_ID_HASH);
|
pub const SELF: PodId = PodId(SELF_ID_HASH);
|
||||||
|
|
||||||
impl fmt::Display for PodId {
|
impl fmt::Display for PodId {
|
||||||
|
|
@ -105,6 +107,8 @@ pub struct Params {
|
||||||
// in a custom predicate
|
// in a custom predicate
|
||||||
pub max_custom_predicate_arity: usize,
|
pub max_custom_predicate_arity: usize,
|
||||||
pub max_custom_batch_size: usize,
|
pub max_custom_batch_size: usize,
|
||||||
|
// maximum number of merkle proofs
|
||||||
|
pub max_merkle_proofs: usize,
|
||||||
// maximum depth for merkle tree gadget
|
// maximum depth for merkle tree gadget
|
||||||
pub max_depth_mt_gadget: usize,
|
pub max_depth_mt_gadget: usize,
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +125,7 @@ impl Default for Params {
|
||||||
max_operation_args: 5,
|
max_operation_args: 5,
|
||||||
max_custom_predicate_arity: 5,
|
max_custom_predicate_arity: 5,
|
||||||
max_custom_batch_size: 5,
|
max_custom_batch_size: 5,
|
||||||
|
max_merkle_proofs: 5,
|
||||||
max_depth_mt_gadget: 32,
|
max_depth_mt_gadget: 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use super::Hash;
|
||||||
use super::{CustomPredicateRef, NativePredicate, Statement, StatementArg, ToFields, F};
|
use super::{CustomPredicateRef, NativePredicate, Statement, StatementArg, ToFields, F};
|
||||||
|
use crate::middleware::EMPTY_HASH;
|
||||||
|
use crate::middleware::EMPTY_VALUE;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree},
|
backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree},
|
||||||
middleware::{AnchoredKey, Params, Predicate, Value, SELF},
|
middleware::{AnchoredKey, Params, Predicate, Value, SELF},
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ pub const KEY_SIGNER: &str = "_signer";
|
||||||
pub const KEY_TYPE: &str = "_type";
|
pub const KEY_TYPE: &str = "_type";
|
||||||
pub const STATEMENT_ARG_F_LEN: usize = 8;
|
pub const STATEMENT_ARG_F_LEN: usize = 8;
|
||||||
pub const OPERATION_ARG_F_LEN: usize = 1;
|
pub const OPERATION_ARG_F_LEN: usize = 1;
|
||||||
|
pub const OPERATION_AUX_F_LEN: usize = 1;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum NativePredicate {
|
pub enum NativePredicate {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue