Skip to content

Commit d00ff95

Browse files
tideofwordsarnaucubeax0
authored
Fe contains (#145)
* Contains should take three arguments (root, key, value) * Add a test for frontend Dictionaries * Separate frontend and middleware operations * Make tests pass: add arg to contains * Cargo fmt * Merkleproof verify circuit (#143) * merkletree: add keypath circuit * merkletree-circuit: implement proof of existence verification in-circuit * parametrize max_depth at the tree circuit * Constrain selectors in-circuit * implement merketree nonexistence proof circuit, and add edgecase tests * add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods * review comments, some extra polishing and add a test that expects wrong proofs to fail * Add circuit to check only merkleproofs-of-existence With this, the merkletree_circuit module offers two different circuits: - `MerkleProofCircuit`: allows to verify both proofs of existence and proofs non-existence with the same circuit. - `MerkleProofExistenceCircuit`: allows to verify proofs of existence only. In this way, if only proofs of existence are needed, `MerkleProofExistenceCircuit` should be used, which requires less amount of constraints than `MerkleProofCircuit`. * Code review --------- Co-authored-by: Ahmad <root@ahmadafuni.com> * Towards Contains/NotContains in middleware and backend * Fix build * Adding error handling to deal with op compile introduce extra ops * Incorporate Merkle proofs into MockMainPod * Merkleproof verify circuit (#143) * merkletree: add keypath circuit * merkletree-circuit: implement proof of existence verification in-circuit * parametrize max_depth at the tree circuit * Constrain selectors in-circuit * implement merketree nonexistence proof circuit, and add edgecase tests * add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods * review comments, some extra polishing and add a test that expects wrong proofs to fail * Add circuit to check only merkleproofs-of-existence With this, the merkletree_circuit module offers two different circuits: - `MerkleProofCircuit`: allows to verify both proofs of existence and proofs non-existence with the same circuit. - `MerkleProofExistenceCircuit`: allows to verify proofs of existence only. In this way, if only proofs of existence are needed, `MerkleProofExistenceCircuit` should be used, which requires less amount of constraints than `MerkleProofCircuit`. * Code review --------- Co-authored-by: Ahmad <root@ahmadafuni.com> * Towards Contains/NotContains in middleware and backend * Frontend compound types -- allow one frontend operation to produce multiple middleware statements (in progress) * Incorporate Merkle proofs into MockMainPod * Incorporate Merkle proof op arg into frontend * Compile one statement to many, in progress * Fix remaining tests * Minor clean-up * Oops I did a bunch of work in the middle of a rebase, committing * Incorporate Merkle proof op arg into frontend * still working on frontend compound types, refactor compile() to output multiple statements * Contains statements for frontend types: code compiles * Tests pass * Examples use front-end compound types * Remove old Contains and NotContains from frontend * Add nin to typos * Code review --------- Co-authored-by: arnaucube <git@arnaucube.com> Co-authored-by: Ahmad <root@ahmadafuni.com>
1 parent d6033b7 commit d00ff95

File tree

16 files changed

+789
-162
lines changed

16 files changed

+789
-162
lines changed

.github/workflows/typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ BA = "BA"
44
Ded = "Ded" # "ANDed", it thought "Ded" should be "Dead"
55
OT = "OT"
66
aks = "aks" # anchored keys
7+
nin = "nin" # not in

src/backends/plonky2/circuits/mainpod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,10 @@ impl MainPodVerifyCircuit {
491491
mod tests {
492492
use super::*;
493493
use crate::backends::plonky2::mock::mainpod;
494-
use crate::backends::plonky2::{basetypes::C, mock::mainpod::OperationArg};
494+
use crate::backends::plonky2::{
495+
basetypes::C,
496+
mock::mainpod::{OperationArg, OperationAux},
497+
};
495498
use crate::middleware::{OperationType, PodId};
496499
use plonky2::plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig};
497500

@@ -571,20 +574,29 @@ mod tests {
571574
fn test_operation_verify() -> Result<()> {
572575
// None
573576
let st: mainpod::Statement = Statement::None.into();
574-
let op = mainpod::Operation(OperationType::Native(NativeOperation::None), vec![]);
577+
let op = mainpod::Operation(
578+
OperationType::Native(NativeOperation::None),
579+
vec![],
580+
OperationAux::None,
581+
);
575582
let prev_statements = vec![Statement::None.into()];
576583
operation_verify(st.clone(), op, prev_statements.clone())?;
577584

578585
// NewEntry
579586
let st1: mainpod::Statement =
580587
Statement::ValueOf(AnchoredKey(SELF, "hello".into()), 55.into()).into();
581-
let op = mainpod::Operation(OperationType::Native(NativeOperation::NewEntry), vec![]);
588+
let op = mainpod::Operation(
589+
OperationType::Native(NativeOperation::NewEntry),
590+
vec![],
591+
OperationAux::None,
592+
);
582593
operation_verify(st1.clone(), op, vec![])?;
583594

584595
// Copy
585596
let op = mainpod::Operation(
586597
OperationType::Native(NativeOperation::CopyStatement),
587598
vec![OperationArg::Index(0)],
599+
OperationAux::None,
588600
);
589601
operation_verify(st, op, prev_statements)?;
590602

@@ -602,6 +614,7 @@ mod tests {
602614
let op = mainpod::Operation(
603615
OperationType::Native(NativeOperation::EqualFromEntries),
604616
vec![OperationArg::Index(0), OperationArg::Index(1)],
617+
OperationAux::None,
605618
);
606619
let prev_statements = vec![st1.clone(), st2];
607620
operation_verify(st, op, prev_statements)?;
@@ -620,6 +633,7 @@ mod tests {
620633
let op = mainpod::Operation(
621634
OperationType::Native(NativeOperation::LtFromEntries),
622635
vec![OperationArg::Index(0), OperationArg::Index(1)],
636+
OperationAux::None,
623637
);
624638
let prev_statements = vec![st1.clone(), st2];
625639
operation_verify(st, op, prev_statements)?;

src/backends/plonky2/mock/mainpod/mod.rs

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ use serde::{Deserialize, Serialize};
88
use std::any::Any;
99
use std::fmt;
1010

11-
use crate::middleware::{
12-
self, hash_str, AnchoredKey, Hash, MainPodInputs, NativeOperation, NativePredicate, NonePod,
13-
OperationType, Params, Pod, PodId, PodProver, Predicate, StatementArg, ToFields, KEY_TYPE,
14-
SELF,
11+
use crate::{
12+
backends::plonky2::primitives::merkletree::MerkleProof,
13+
middleware::{
14+
self, hash_str, AnchoredKey, Hash, MainPodInputs, NativeOperation, NativePredicate,
15+
NonePod, OperationType, Params, Pod, PodId, PodProver, Predicate, StatementArg, ToFields,
16+
KEY_TYPE, SELF,
17+
},
1518
};
1619

1720
mod operation;
@@ -41,6 +44,9 @@ pub struct MockMainPod {
4144
operations: Vec<Operation>,
4245
// All statements (inherited + new)
4346
statements: Vec<Statement>,
47+
// All Merkle proofs
48+
// TODO: Use a backend-specific representation
49+
merkle_proofs: Vec<MerkleProof>,
4450
}
4551

4652
impl fmt::Display for MockMainPod {
@@ -243,9 +249,28 @@ impl MockMainPod {
243249
}
244250
}
245251

252+
fn find_op_aux(
253+
merkle_proofs: &[MerkleProof],
254+
op_aux: &middleware::OperationAux,
255+
) -> Result<OperationAux> {
256+
match op_aux {
257+
middleware::OperationAux::None => Ok(OperationAux::None),
258+
middleware::OperationAux::MerkleProof(pf_arg) => merkle_proofs
259+
.iter()
260+
.enumerate()
261+
.find_map(|(i, pf)| (pf == pf_arg).then_some(i))
262+
.map(OperationAux::MerkleProofIndex)
263+
.ok_or(anyhow!(
264+
"Merkle proof corresponding to op arg {} not found",
265+
op_aux
266+
)),
267+
}
268+
}
269+
246270
fn process_private_statements_operations(
247271
params: &Params,
248272
statements: &[Statement],
273+
merkle_proofs: &[MerkleProof],
249274
input_operations: &[middleware::Operation],
250275
) -> Result<Vec<Operation>> {
251276
let mut operations = Vec::new();
@@ -259,8 +284,12 @@ impl MockMainPod {
259284
.iter()
260285
.map(|mid_arg| Self::find_op_arg(statements, mid_arg))
261286
.collect::<Result<Vec<_>>>()?;
287+
288+
let mid_aux = op.aux();
289+
let aux = Self::find_op_aux(merkle_proofs, &mid_aux)?;
290+
262291
Self::pad_operation_args(params, &mut args);
263-
operations.push(Operation(op.op_type(), args));
292+
operations.push(Operation(op.op_type(), args, aux));
264293
}
265294
Ok(operations)
266295
}
@@ -278,17 +307,22 @@ impl MockMainPod {
278307
operations.push(Operation(
279308
OperationType::Native(NativeOperation::NewEntry),
280309
vec![],
310+
OperationAux::None,
281311
));
282312
for i in 0..(params.max_public_statements - 1) {
283313
let st = &statements[offset_public_statements + i + 1];
284314
let mut op = if st.is_none() {
285-
Operation(OperationType::Native(NativeOperation::None), vec![])
315+
Operation(
316+
OperationType::Native(NativeOperation::None),
317+
vec![],
318+
OperationAux::None,
319+
)
286320
} else {
287321
let mid_arg = st.clone();
288322
Operation(
289323
OperationType::Native(NativeOperation::CopyStatement),
290-
// TODO
291-
vec![Self::find_op_arg(statements, &mid_arg.try_into().unwrap())?],
324+
vec![Self::find_op_arg(statements, &mid_arg.try_into()?)?],
325+
OperationAux::None,
292326
)
293327
};
294328
fill_pad(&mut op.1, OperationArg::None, params.max_operation_args);
@@ -304,8 +338,21 @@ impl MockMainPod {
304338
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
305339
// value=PodType::MockMainPod`
306340
let statements = Self::layout_statements(params, &inputs);
307-
let operations =
308-
Self::process_private_statements_operations(params, &statements, inputs.operations)?;
341+
let merkle_proofs = inputs
342+
.operations
343+
.iter()
344+
.flat_map(|op| match op {
345+
middleware::Operation::ContainsFromEntries(_, _, _, pf) => Some(pf.clone()),
346+
middleware::Operation::NotContainsFromEntries(_, _, pf) => Some(pf.clone()),
347+
_ => None,
348+
})
349+
.collect::<Vec<_>>();
350+
let operations = Self::process_private_statements_operations(
351+
params,
352+
&statements,
353+
&merkle_proofs,
354+
inputs.operations,
355+
)?;
309356
let operations =
310357
Self::process_public_statements_operations(params, &statements, operations)?;
311358

@@ -340,6 +387,7 @@ impl MockMainPod {
340387
public_statements,
341388
statements,
342389
operations,
390+
merkle_proofs,
343391
})
344392
}
345393

@@ -350,7 +398,11 @@ impl MockMainPod {
350398
}
351399

352400
fn operation_none(params: &Params) -> Operation {
353-
let mut op = Operation(OperationType::Native(NativeOperation::None), vec![]);
401+
let mut op = Operation(
402+
OperationType::Native(NativeOperation::None),
403+
vec![],
404+
OperationAux::None,
405+
);
354406
fill_pad(&mut op.1, OperationArg::None, params.max_operation_args);
355407
op
356408
}
@@ -444,7 +496,10 @@ impl Pod for MockMainPod {
444496
.enumerate()
445497
.map(|(i, s)| {
446498
self.operations[i]
447-
.deref(&self.statements[..input_statement_offset + i])
499+
.deref(
500+
&self.statements[..input_statement_offset + i],
501+
&self.merkle_proofs,
502+
)
448503
.unwrap()
449504
.check_and_log(&self.params, &s.clone().try_into().unwrap())
450505
})
@@ -513,13 +568,18 @@ pub mod tests {
513568
zu_kyc_sign_pod_builders,
514569
};
515570
use crate::middleware;
571+
use crate::middleware::containers::Set;
516572

517573
#[test]
518574
fn test_mock_main_zu_kyc() -> Result<()> {
519575
let params = middleware::Params::default();
576+
let sanctions_values = ["A343434340"].map(|s| crate::frontend::Value::from(s));
577+
let sanction_set = crate::frontend::Value::Set(crate::frontend::containers::Set::new(
578+
sanctions_values.to_vec(),
579+
)?);
520580

521581
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
522-
zu_kyc_sign_pod_builders(&params);
582+
zu_kyc_sign_pod_builders(&params, &sanction_set);
523583
let mut signer = MockSigner {
524584
pk: "ZooGov".into(),
525585
};

src/backends/plonky2/mock/mainpod/operation.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use super::Statement;
2-
use crate::middleware::{self, OperationType, Params, ToFields, F};
3-
use anyhow::Result;
2+
use crate::{
3+
backends::plonky2::primitives::merkletree::MerkleProof,
4+
middleware::{self, OperationType, Params, ToFields, F},
5+
};
6+
use anyhow::{anyhow, Result};
47
use plonky2::field::types::{Field, PrimeField64};
58
use serde::{Deserialize, Serialize};
69
use std::fmt;
@@ -28,7 +31,13 @@ impl OperationArg {
2831
}
2932

3033
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
31-
pub struct Operation(pub OperationType, pub Vec<OperationArg>);
34+
pub enum OperationAux {
35+
None,
36+
MerkleProofIndex(usize),
37+
}
38+
39+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
40+
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
3241

3342
impl Operation {
3443
pub fn op_type(&self) -> OperationType {
@@ -37,16 +46,28 @@ impl Operation {
3746
pub fn args(&self) -> &[OperationArg] {
3847
&self.1
3948
}
40-
pub fn deref(&self, statements: &[Statement]) -> Result<crate::middleware::Operation> {
49+
pub fn deref(
50+
&self,
51+
statements: &[Statement],
52+
merkle_proofs: &[MerkleProof],
53+
) -> Result<crate::middleware::Operation> {
4154
let deref_args = self
4255
.1
4356
.iter()
4457
.flat_map(|arg| match arg {
4558
OperationArg::None => None,
4659
OperationArg::Index(i) => Some(statements[*i].clone().try_into()),
4760
})
48-
.collect::<Result<Vec<crate::middleware::Statement>>>()?;
49-
middleware::Operation::op(self.0.clone(), &deref_args)
61+
.collect::<Result<Vec<_>>>()?;
62+
let deref_aux = match self.2 {
63+
OperationAux::None => Ok(crate::middleware::OperationAux::None),
64+
OperationAux::MerkleProofIndex(i) => merkle_proofs
65+
.get(i)
66+
.cloned()
67+
.ok_or(anyhow!("Missing Merkle proof index {}", i))
68+
.map(crate::middleware::OperationAux::MerkleProof),
69+
}?;
70+
middleware::Operation::op(self.0.clone(), &deref_args, &deref_aux)
5071
}
5172
}
5273

@@ -64,6 +85,10 @@ impl fmt::Display for Operation {
6485
}
6586
}
6687
}
88+
match self.2 {
89+
OperationAux::None => (),
90+
OperationAux::MerkleProofIndex(i) => write!(f, "merkle_proof_{:02}", i)?,
91+
}
6792
Ok(())
6893
}
6994
}

src/backends/plonky2/mock/mainpod/statement.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ impl TryFrom<Statement> for middleware::Statement {
6060
}
6161
(NP::Gt, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), None), 2) => S::Gt(ak1, ak2),
6262
(NP::Lt, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), None), 2) => S::Lt(ak1, ak2),
63-
(NP::Contains, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), None), 2) => {
64-
S::Contains(ak1, ak2)
63+
(NP::Contains, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), Some(SA::Key(ak3))), 3) => {
64+
S::Contains(ak1, ak2, ak3)
6565
}
6666
(NP::NotContains, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), None), 2) => {
6767
S::NotContains(ak1, ak2)

src/backends/plonky2/primitives/merkletree.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! https://0xparc.github.io/pod2/merkletree.html .
33
use anyhow::{anyhow, Result};
44
use plonky2::field::types::Field;
5+
use serde::{Deserialize, Serialize};
56
use std::collections::HashMap;
67
use std::fmt;
78
use std::iter::IntoIterator;
@@ -207,7 +208,7 @@ impl fmt::Display for MerkleTree {
207208
}
208209
}
209210

210-
#[derive(Clone, Debug)]
211+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
211212
pub struct MerkleProof {
212213
// note: currently we don't use the `_existence` field, we would use if we merge the methods
213214
// `verify` and `verify_nonexistence` into a single one

0 commit comments

Comments
 (0)