Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/backends/plonky2/primitives/merkletree_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;

Expand Down
33 changes: 5 additions & 28 deletions src/examples/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -45,25 +45,17 @@ 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);
kyc.add_signed_pod(sanction_list);
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!(
Expand Down Expand Up @@ -269,25 +261,17 @@ 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,
(good_boy_pods[good_boy_idx * 2 + issuer_idx], KEY_TYPE),
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!(
Expand Down Expand Up @@ -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);
Expand All @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ mod tests {

let eth_dos_batch = eth_dos_batch(&params)?;
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(&params);
println!("Batch b, serialized: {:?}", fields);

Expand Down
59 changes: 42 additions & 17 deletions src/frontend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(|| {
Expand Down Expand Up @@ -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) };
}
}

Expand Down Expand Up @@ -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()
Expand Down
12 changes: 12 additions & 0 deletions src/frontend/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 36 additions & 0 deletions src/middleware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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, ...
Expand Down
2 changes: 1 addition & 1 deletion src/middleware/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading