chore(frontend): make Merkle proofs optional (#198)
* Make frontend Merkle proofs optional * Code review * Clippy
This commit is contained in:
parent
281f57f0a0
commit
17e6c2a092
7 changed files with 98 additions and 48 deletions
|
|
@ -548,7 +548,7 @@ pub mod tests {
|
|||
let key = RawValue::from(hash_value(&RawValue::from(5)));
|
||||
let (value, proof) = tree.prove(&key)?;
|
||||
assert_eq!(value, RawValue::from(5));
|
||||
assert_eq!(proof.existence, true);
|
||||
assert!(proof.existence);
|
||||
|
||||
MerkleTree::verify(max_depth, tree.root(), &proof, &key, &value)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ pub mod custom;
|
|||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::Result;
|
||||
use custom::{eth_dos_batch, eth_friend_batch};
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::mock::signedpod::MockSigner,
|
||||
frontend::{MainPodBuilder, SignedPod, SignedPodBuilder},
|
||||
middleware::{
|
||||
containers::Set, CustomPredicateRef, Key, Params, PodType, Statement, TypedValue, Value,
|
||||
containers::Set, CustomPredicateRef, Params, PodType, Statement, TypedValue, Value,
|
||||
KEY_SIGNER, KEY_TYPE,
|
||||
},
|
||||
op,
|
||||
|
|
@ -45,16 +45,9 @@ pub fn zu_kyc_pod_builder(
|
|||
pay_stub: &SignedPod,
|
||||
sanction_list: &SignedPod,
|
||||
) -> Result<MainPodBuilder> {
|
||||
let sanction_set = match sanction_list.get("sanctionList").map(|v| v.typed()) {
|
||||
Some(TypedValue::Set(s)) => Ok(s),
|
||||
_ => Err(anyhow!("Missing sanction list!")),
|
||||
}?;
|
||||
let now_minus_18y: i64 = 1169909388;
|
||||
let now_minus_1y: i64 = 1706367566;
|
||||
|
||||
let gov_id_kvs = gov_id.kvs();
|
||||
let id_number_value = gov_id_kvs.get(&Key::from("idNumber")).unwrap();
|
||||
|
||||
let mut kyc = MainPodBuilder::new(params);
|
||||
kyc.add_signed_pod(gov_id);
|
||||
kyc.add_signed_pod(pay_stub);
|
||||
|
|
@ -62,8 +55,7 @@ pub fn zu_kyc_pod_builder(
|
|||
kyc.pub_op(op!(
|
||||
set_not_contains,
|
||||
(sanction_list, "sanctionList"),
|
||||
(gov_id, "idNumber"),
|
||||
sanction_set.prove_nonexistence(id_number_value)?
|
||||
(gov_id, "idNumber")
|
||||
))?;
|
||||
kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y))?;
|
||||
kyc.pub_op(op!(
|
||||
|
|
@ -269,8 +261,6 @@ pub fn great_boy_pod_builder(
|
|||
PodType::MockSigned as i64
|
||||
))?;
|
||||
for issuer_idx in 0..2 {
|
||||
let pod_kvs = good_boy_pods[good_boy_idx * 2 + issuer_idx].kvs();
|
||||
|
||||
// Type check
|
||||
great_boy.pub_op(op!(
|
||||
eq,
|
||||
|
|
@ -278,16 +268,10 @@ pub fn great_boy_pod_builder(
|
|||
PodType::MockSigned as i64
|
||||
))?;
|
||||
// Each good boy POD comes from a valid issuer
|
||||
let good_boy_proof = match good_boy_issuers.typed() {
|
||||
TypedValue::Set(set) => Ok(set),
|
||||
_ => Err(anyhow!("Invalid good boy issuers!")),
|
||||
}?
|
||||
.prove(pod_kvs.get(&Key::from(KEY_SIGNER)).unwrap())?;
|
||||
great_boy.pub_op(op!(
|
||||
set_contains,
|
||||
good_boy_issuers,
|
||||
(good_boy_pods[good_boy_idx * 2 + issuer_idx], KEY_SIGNER),
|
||||
good_boy_proof
|
||||
(good_boy_pods[good_boy_idx * 2 + issuer_idx], KEY_SIGNER)
|
||||
))?;
|
||||
// Each good boy has 2 good boy pods
|
||||
great_boy.pub_op(op!(
|
||||
|
|
@ -403,12 +387,6 @@ pub fn tickets_pod_builder(
|
|||
expect_consumed: bool,
|
||||
blacklisted_emails: &Set,
|
||||
) -> Result<MainPodBuilder> {
|
||||
let attendee_email_value = signed_pod
|
||||
.kvs()
|
||||
.get(&Key::from("attendeeEmail"))
|
||||
.unwrap()
|
||||
.clone();
|
||||
let attendee_nin_blacklist_pf = blacklisted_emails.prove_nonexistence(&attendee_email_value)?;
|
||||
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);
|
||||
|
|
@ -419,8 +397,7 @@ pub fn tickets_pod_builder(
|
|||
builder.pub_op(op!(
|
||||
dict_not_contains,
|
||||
blacklisted_email_set_value,
|
||||
(signed_pod, "attendeeEmail"),
|
||||
attendee_nin_blacklist_pf
|
||||
(signed_pod, "attendeeEmail")
|
||||
))?;
|
||||
Ok(builder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ mod tests {
|
|||
|
||||
let eth_dos_batch = eth_dos_batch(¶ms)?;
|
||||
let eth_dos_batch_mw: middleware::CustomPredicateBatch =
|
||||
Arc::unwrap_or_clone(eth_dos_batch).into();
|
||||
Arc::unwrap_or_clone(eth_dos_batch);
|
||||
let fields = eth_dos_batch_mw.to_fields(¶ms);
|
||||
println!("Batch b, serialized: {:?}", fields);
|
||||
|
||||
|
|
|
|||
|
|
@ -262,9 +262,39 @@ impl MainPodBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Fills in auxiliary data if necessary/possible.
|
||||
fn fill_in_aux(op: Operation) -> Result<Operation> {
|
||||
use NativeOperation::{ContainsFromEntries, NotContainsFromEntries};
|
||||
use OperationAux as OpAux;
|
||||
use OperationType::Native;
|
||||
|
||||
let op_type = &op.0;
|
||||
|
||||
match (op_type, &op.2) {
|
||||
(Native(ContainsFromEntries), OpAux::None)
|
||||
| (Native(NotContainsFromEntries), OpAux::None) => {
|
||||
let container =
|
||||
op.1.get(0)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(anyhow!("Invalid container argument for op {}.", op))?;
|
||||
let key =
|
||||
op.1.get(1)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(anyhow!("Invalid key argument for op {}.", op))?;
|
||||
let proof = if op_type == &Native(ContainsFromEntries) {
|
||||
container.prove_existence(key)?.1
|
||||
} else {
|
||||
container.prove_nonexistence(key)?
|
||||
};
|
||||
Ok(Operation(op_type.clone(), op.1, OpAux::MerkleProof(proof)))
|
||||
}
|
||||
_ => Ok(op),
|
||||
}
|
||||
}
|
||||
|
||||
fn op(&mut self, public: bool, op: Operation) -> Result<Statement, anyhow::Error> {
|
||||
use NativeOperation::*;
|
||||
let mut op = Self::lower_op(op);
|
||||
let mut op = Self::fill_in_aux(Self::lower_op(op))?;
|
||||
let Operation(op_type, ref mut args, _) = &mut op;
|
||||
// TODO: argument type checking
|
||||
let pred = op_type.output_predicate().map(Ok).unwrap_or_else(|| {
|
||||
|
|
@ -736,21 +766,21 @@ pub mod build_utils {
|
|||
(custom, $op:expr, $($arg:expr),+) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Custom($op),
|
||||
$crate::op_args!($($arg),*), $crate::middleware::OperationAux::None) };
|
||||
(dict_contains, $dict:expr, $key:expr, $value:expr, $aux:expr) => { $crate::frontend::Operation(
|
||||
(dict_contains, $dict:expr, $key:expr, $value:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::DictContainsFromEntries),
|
||||
$crate::op_args!($dict, $key, $value), $crate::middleware::OperationAux::MerkleProof($aux)) };
|
||||
(dict_not_contains, $dict:expr, $key:expr, $aux:expr) => { $crate::frontend::Operation(
|
||||
$crate::op_args!($dict, $key, $value), $crate::middleware::OperationAux::None) };
|
||||
(dict_not_contains, $dict:expr, $key:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::DictNotContainsFromEntries),
|
||||
$crate::op_args!($dict, $key), $crate::middleware::OperationAux::MerkleProof($aux)) };
|
||||
(set_contains, $set:expr, $value:expr, $aux:expr) => { $crate::frontend::Operation(
|
||||
$crate::op_args!($dict, $key), $crate::middleware::OperationAux::None) };
|
||||
(set_contains, $set:expr, $value:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::SetContainsFromEntries),
|
||||
$crate::op_args!($set, $value), $crate::middleware::OperationAux::MerkleProof($aux)) };
|
||||
(set_not_contains, $set:expr, $value:expr, $aux:expr) => { $crate::frontend::Operation(
|
||||
$crate::op_args!($set, $value), $crate::middleware::OperationAux::None) };
|
||||
(set_not_contains, $set:expr, $value:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::SetNotContainsFromEntries),
|
||||
$crate::op_args!($set, $value), $crate::middleware::OperationAux::MerkleProof($aux)) };
|
||||
(array_contains, $array:expr, $index:expr, $value:expr, $aux:expr) => { $crate::frontend::Operation(
|
||||
$crate::op_args!($set, $value), $crate::middleware::OperationAux::None) };
|
||||
(array_contains, $array:expr, $index:expr, $value:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::ArrayContainsFromEntries),
|
||||
$crate::op_args!($array, $index, $value), $crate::middleware::OperationAux::MerkleProof($aux)) };
|
||||
$crate::op_args!($array, $index, $value), $crate::middleware::OperationAux::None) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -781,12 +811,7 @@ pub mod tests {
|
|||
// Check that frontend key-values agree with those embedded in a
|
||||
// SignedPod.
|
||||
fn check_kvs(pod: &SignedPod) -> Result<()> {
|
||||
let kvs = pod
|
||||
.kvs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let kvs = pod.kvs.clone().into_iter().collect::<HashMap<_, _>>();
|
||||
let embedded_kvs = pod
|
||||
.pod
|
||||
.kvs()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,18 @@ pub enum OperationArg {
|
|||
Entry(String, Value),
|
||||
}
|
||||
|
||||
impl OperationArg {
|
||||
/// Extracts the value underlying literal and `ValueOf` statement
|
||||
/// operation args.
|
||||
pub(crate) fn value(&self) -> Option<&Value> {
|
||||
match self {
|
||||
Self::Literal(v) => Some(v),
|
||||
Self::Statement(Statement::ValueOf(_, v)) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OperationArg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ pub use operation::*;
|
|||
// use serde::{Deserialize, Serialize};
|
||||
pub use statement::*;
|
||||
|
||||
use crate::backends::plonky2::primitives::merkletree::MerkleProof;
|
||||
|
||||
pub const SELF: PodId = PodId(SELF_ID_HASH);
|
||||
|
||||
// TODO: Move all value-related types to to `value.rs`
|
||||
|
|
@ -136,6 +138,16 @@ impl TryFrom<&TypedValue> for i64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<TypedValue> for Key {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(tv: TypedValue) -> Result<Self> {
|
||||
match tv {
|
||||
TypedValue::String(s) => Ok(Key::new(s)),
|
||||
_ => Err(anyhow!("Value {} cannot be converted to a key.", tv)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
@ -218,6 +230,30 @@ impl Value {
|
|||
pub fn raw(&self) -> RawValue {
|
||||
self.raw
|
||||
}
|
||||
/// Determines Merkle existence proof for `key` in `self` (if applicable).
|
||||
pub(crate) fn prove_existence<'a>(
|
||||
&'a self,
|
||||
key: &'a Value,
|
||||
) -> Result<(&'a Value, MerkleProof)> {
|
||||
match &self.typed() {
|
||||
TypedValue::Array(a) => match key.typed() {
|
||||
TypedValue::Int(i) if i >= &0 => a.prove((*i) as usize),
|
||||
_ => Err(anyhow!("Invalid key {} for container {}.", key, self))?,
|
||||
},
|
||||
TypedValue::Dictionary(d) => d.prove(&key.typed().clone().try_into()?),
|
||||
TypedValue::Set(s) => Ok((key, s.prove(key)?)),
|
||||
_ => Err(anyhow!("Invalid container value {}", self.typed())),
|
||||
}
|
||||
}
|
||||
/// Determines Merkle non-existence proof for `key` in `self` (if applicable).
|
||||
pub(crate) fn prove_nonexistence<'a>(&'a self, key: &'a Value) -> Result<MerkleProof> {
|
||||
match &self.typed() {
|
||||
TypedValue::Array(_) => Err(anyhow!("Arrays do not support `NotContains` operation.")),
|
||||
TypedValue::Dictionary(d) => d.prove_nonexistence(&key.typed().clone().try_into()?),
|
||||
TypedValue::Set(s) => s.prove_nonexistence(key),
|
||||
_ => Err(anyhow!("Invalid container value {}", self.typed())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A Value can be created from any type Into<TypedValue> type: bool, string-like, i64, ...
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use plonky2::field::types::Field;
|
|||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree},
|
||||
backends::plonky2::primitives::merkletree::MerkleProof,
|
||||
middleware::{
|
||||
custom::KeyOrWildcard, AnchoredKey, CustomPredicateBatch, CustomPredicateRef,
|
||||
NativePredicate, Params, Predicate, Statement, StatementArg, StatementTmplArg, ToFields,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue