Skip to content

Commit cd30806

Browse files
committed
get operation_verify test working
1 parent 67f8fc8 commit cd30806

File tree

6 files changed

+110
-41
lines changed

6 files changed

+110
-41
lines changed

src/backends/plonky2/common.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Common functionality to build Pod circuits with plonky2
22
3-
use crate::middleware::{
4-
Operation, Params, Statement, StatementArg, ToFields, Value, F, HASH_SIZE, VALUE_SIZE,
5-
};
3+
use crate::backends::plonky2::mock_main::Statement;
4+
use crate::backends::plonky2::mock_main::{Operation, OperationArg};
5+
use crate::middleware::{Params, StatementArg, ToFields, Value, F, HASH_SIZE, VALUE_SIZE};
66
use crate::middleware::{OPERATION_ARG_F_LEN, STATEMENT_ARG_F_LEN};
77
use anyhow::Result;
88
use plonky2::field::extension::Extendable;
@@ -68,7 +68,15 @@ impl OperationTarget {
6868
op: &Operation,
6969
) -> Result<()> {
7070
pw.set_target_arr(&self.code, &op.code().to_fields(params))?;
71-
// TODO: Arguments
71+
for (i, arg) in op
72+
.args()
73+
.iter()
74+
.chain(iter::repeat(&OperationArg::None))
75+
.take(params.max_operation_args)
76+
.enumerate()
77+
{
78+
pw.set_target_arr(&self.args[i], &arg.to_fields(params))?;
79+
}
7280
Ok(())
7381
}
7482
}

src/backends/plonky2/main.rs

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ use crate::backends::plonky2::basetypes::{Hash, Value, D, EMPTY_HASH, EMPTY_VALU
22
use crate::backends::plonky2::common::{
33
CircuitBuilderPod, OperationTarget, StatementTarget, ValueTarget,
44
};
5+
use crate::backends::plonky2::mock_main::Operation;
56
use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree};
67
use crate::backends::plonky2::primitives::merkletree::{
78
MerkleProofExistenceGate, MerkleProofExistenceTarget,
89
};
910
use crate::middleware::{
10-
hash_str, AnchoredKey, NativeOperation, NativePredicate, Operation, Params, PodType, Predicate,
11-
Statement, StatementArg, ToFields, KEY_TYPE, SELF, STATEMENT_ARG_F_LEN,
11+
hash_str, AnchoredKey, NativeOperation, NativePredicate, Params, PodType, Predicate, Statement,
12+
StatementArg, ToFields, KEY_TYPE, SELF, STATEMENT_ARG_F_LEN,
1213
};
1314
use anyhow::Result;
1415
use itertools::Itertools;
@@ -134,42 +135,62 @@ impl OperationVerifyGate {
134135
op: &OperationTarget,
135136
prev_statements: &[StatementTarget],
136137
) -> Result<OperationVerifyTarget> {
138+
let _true = builder._true();
139+
let _false = builder._false();
140+
let one = builder.constant(F::ONE);
141+
137142
// Verify that the operation `op` correctly generates the statement `st`. The operation
138143
// can reference any of the `prev_statements`.
139144
// The verification may require aux data which needs to be stored in the
140145
// `OperationVerifyTarget` so that we can set during witness generation.
141146

142-
// TODO: Figure out the right encoding of op.code
147+
// For now only support native operations
148+
builder.connect(op.code[0], one);
149+
let native_op = op.code[1];
150+
151+
let mut op_flags = Vec::new();
143152
let op_none = builder.constant(F::from_canonical_u64(NativeOperation::None as u64));
144-
let is_none = builder.is_equal(op.code[0], op_none);
153+
let is_none = builder.is_equal(native_op, op_none);
154+
op_flags.push(is_none);
145155
let op_new_entry =
146156
builder.constant(F::from_canonical_u64(NativeOperation::NewEntry as u64));
147-
let is_new_entry = builder.is_equal(op.code[0], op_new_entry);
157+
let is_new_entry = builder.is_equal(native_op, op_new_entry);
158+
op_flags.push(is_new_entry);
148159
let op_copy_statement =
149160
builder.constant(F::from_canonical_u64(NativeOperation::CopyStatement as u64));
150-
let is_copy_statement = builder.is_equal(op.code[0], op_copy_statement);
161+
let is_copy_statement = builder.is_equal(native_op, op_copy_statement);
162+
op_flags.push(is_copy_statement);
151163
let op_eq_from_entries = builder.constant(F::from_canonical_u64(
152164
NativeOperation::EqualFromEntries as u64,
153165
));
154-
let is_eq_from_entries = builder.is_equal(op.code[0], op_eq_from_entries);
155-
let op_gt_from_entries =
156-
builder.constant(F::from_canonical_u64(NativeOperation::GtFromEntries as u64));
157-
let is_gt_from_entries = builder.is_equal(op.code[0], op_gt_from_entries);
166+
let is_eq_from_entries = builder.is_equal(native_op, op_eq_from_entries);
167+
op_flags.push(is_eq_from_entries);
158168
let op_lt_from_entries =
159169
builder.constant(F::from_canonical_u64(NativeOperation::LtFromEntries as u64));
160-
let is_lt_from_entries = builder.is_equal(op.code[0], op_lt_from_entries);
161-
let op_contains_from_entries = builder.constant(F::from_canonical_u64(
162-
NativeOperation::ContainsFromEntries as u64,
170+
let is_lt_from_entries = builder.is_equal(native_op, op_lt_from_entries);
171+
op_flags.push(is_lt_from_entries);
172+
let op_not_contains_from_entries = builder.constant(F::from_canonical_u64(
173+
NativeOperation::NotContainsFromEntries as u64,
163174
));
164-
let is_contains_from_entries = builder.is_equal(op.code[0], op_contains_from_entries);
175+
let is_not_contains_from_entries =
176+
builder.is_equal(native_op, op_not_contains_from_entries);
177+
op_flags.push(is_not_contains_from_entries);
178+
179+
// One supported operation must be used. We sum all operation flags and expect the result
180+
// to be 1. Since the flags are boolean and at most one of them is true the sum is
181+
// equivalent to the OR.
182+
let or_op_flags = op_flags
183+
.iter()
184+
.map(|b| b.target)
185+
.fold(_false.target, |acc, x| builder.add(acc, x));
186+
builder.connect(or_op_flags, _true.target);
165187

166188
let ok = builder._true();
167189
let none_ok = self.eval_none(builder, st, op);
168190
let ok = builder.select_bool(is_none, none_ok, ok);
169191
let new_entry_ok = self.eval_new_entry(builder, st, op);
170192
let ok = builder.select_bool(is_new_entry, new_entry_ok, ok);
171193

172-
let _true = builder._true();
173194
builder.connect(ok.target, _true.target);
174195

175196
Ok(OperationVerifyTarget {})
@@ -214,7 +235,8 @@ struct OperationVerifyInput {
214235

215236
impl OperationVerifyTarget {
216237
fn set_targets(&self, pw: &mut PartialWitness<F>, input: &OperationVerifyInput) -> Result<()> {
217-
todo!()
238+
// TODO
239+
Ok(())
218240
}
219241
}
220242

@@ -261,8 +283,7 @@ impl MainPodVerifyGate {
261283
.collect();
262284
let id = builder.hash_n_to_hash_no_pad::<PoseidonHash>(pub_statements_flattened);
263285

264-
// 3. TODO check that all `input_statements` of type `ValueOf` with origin=SELF have unique
265-
// keys (no duplicates)
286+
// 3. TODO check that all `input_statements` of type `ValueOf` with origin=SELF have unique keys (no duplicates). Maybe we can do this via the NewEntry operation (check that the key doesn't exist in a previous statement with ID=SELF)
266287

267288
// 4. Verify type
268289
let type_statement = &pub_statements[0];
@@ -352,6 +373,8 @@ impl MainPodVerifyCircuit {
352373
mod tests {
353374
use super::*;
354375
use crate::backends::plonky2::basetypes::C;
376+
use crate::backends::plonky2::mock_main;
377+
use crate::middleware::OperationType;
355378
use plonky2::plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig};
356379

357380
#[test]
@@ -384,9 +407,9 @@ mod tests {
384407
}
385408

386409
fn operation_verify(
387-
st: Statement,
388-
op: Operation,
389-
prev_statements: Vec<Statement>,
410+
st: mock_main::Statement,
411+
op: mock_main::Operation,
412+
prev_statements: Vec<mock_main::Statement>,
390413
) -> Result<()> {
391414
let params = Params::default();
392415

@@ -429,9 +452,9 @@ mod tests {
429452
#[test]
430453
fn test_operation_verify() -> Result<()> {
431454
// None
432-
let st = Statement::None;
433-
let op = Operation::None;
434-
let prev_statements = vec![Statement::None];
455+
let st: mock_main::Statement = Statement::None.into();
456+
let op = mock_main::Operation(OperationType::Native(NativeOperation::None), vec![]);
457+
let prev_statements = vec![Statement::None.into()];
435458
operation_verify(st, op, prev_statements)?;
436459

437460
Ok(())

src/backends/plonky2/mock_main/operation.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::Statement;
2-
use crate::middleware::{self, OperationType};
2+
use crate::middleware::{self, OperationType, Params, ToFields, F};
33
use anyhow::Result;
4+
use plonky2::field::types::{Field, PrimeField64};
45
use serde::{Deserialize, Serialize};
56
use std::fmt;
67

@@ -10,6 +11,16 @@ pub enum OperationArg {
1011
Index(usize),
1112
}
1213

14+
impl ToFields for OperationArg {
15+
fn to_fields(&self, _params: &Params) -> Vec<F> {
16+
let f = match self {
17+
Self::None => F::ZERO,
18+
Self::Index(i) => F::from_canonical_usize(*i),
19+
};
20+
vec![f]
21+
}
22+
}
23+
1324
impl OperationArg {
1425
pub fn is_none(&self) -> bool {
1526
matches!(self, OperationArg::None)
@@ -20,6 +31,12 @@ impl OperationArg {
2031
pub struct Operation(pub OperationType, pub Vec<OperationArg>);
2132

2233
impl Operation {
34+
pub fn code(&self) -> OperationType {
35+
self.0.clone()
36+
}
37+
pub fn args(&self) -> &[OperationArg] {
38+
&self.1
39+
}
2340
pub fn deref(&self, statements: &[Statement]) -> Result<crate::middleware::Operation> {
2441
let deref_args = self
2542
.1

src/backends/plonky2/mock_main/statement.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ impl Statement {
1313
pub fn is_none(&self) -> bool {
1414
self.0 == Predicate::Native(NativePredicate::None)
1515
}
16+
pub fn code(&self) -> Predicate {
17+
self.0.clone()
18+
}
1619
/// Argument method. Trailing Nones are filtered out.
1720
pub fn args(&self) -> Vec<StatementArg> {
1821
let maybe_last_arg_index = (0..self.1.len()).rev().find(|i| !self.1[*i].is_none());

src/middleware/custom.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ impl fmt::Display for HashOrWildcard {
4949
}
5050

5151
impl ToFields for HashOrWildcard {
52-
fn to_fields(&self, _params: &Params) -> Vec<F> {
52+
fn to_fields(&self, params: &Params) -> Vec<F> {
5353
match self {
54-
HashOrWildcard::Hash(h) => h.to_fields(_params),
54+
HashOrWildcard::Hash(h) => h.to_fields(params),
5555
HashOrWildcard::Wildcard(w) => (0..HASH_SIZE - 1)
5656
.chain(iter::once(*w))
5757
.map(|x| F::from_canonical_u64(x as u64))
@@ -91,7 +91,7 @@ impl StatementTmplArg {
9191
}
9292

9393
impl ToFields for StatementTmplArg {
94-
fn to_fields(&self, _params: &Params) -> Vec<F> {
94+
fn to_fields(&self, params: &Params) -> Vec<F> {
9595
// None => (0, ...)
9696
// Literal(value) => (1, [value], 0, 0, 0, 0)
9797
// Key(hash_or_wildcard1, hash_or_wildcard2)
@@ -107,15 +107,15 @@ impl ToFields for StatementTmplArg {
107107
}
108108
StatementTmplArg::Literal(v) => {
109109
let fields: Vec<F> = iter::once(F::from_canonical_u64(1))
110-
.chain(v.to_fields(_params))
110+
.chain(v.to_fields(params))
111111
.chain(iter::repeat_with(|| F::from_canonical_u64(0)).take(HASH_SIZE))
112112
.collect();
113113
fields
114114
}
115115
StatementTmplArg::Key(hw1, hw2) => {
116116
let fields: Vec<F> = iter::once(F::from_canonical_u64(2))
117-
.chain(hw1.to_fields(_params))
118-
.chain(hw2.to_fields(_params))
117+
.chain(hw1.to_fields(params))
118+
.chain(hw2.to_fields(params))
119119
.collect();
120120
fields
121121
}
@@ -318,8 +318,8 @@ impl ToFields for CustomPredicateBatch {
318318
}
319319

320320
impl CustomPredicateBatch {
321-
pub fn hash(&self, _params: &Params) -> Hash {
322-
let input = self.to_fields(_params);
321+
pub fn hash(&self, params: &Params) -> Hash {
322+
let input = self.to_fields(params);
323323

324324
hash_fields(&input)
325325
}
@@ -399,7 +399,7 @@ impl From<NativePredicate> for Predicate {
399399
}
400400

401401
impl ToFields for Predicate {
402-
fn to_fields(&self, _params: &Params) -> Vec<F> {
402+
fn to_fields(&self, params: &Params) -> Vec<F> {
403403
// serialize:
404404
// NativePredicate(id) as (0, id, 0, 0, 0, 0) -- id: usize
405405
// BatchSelf(i) as (1, i, 0, 0, 0, 0) -- i: usize
@@ -410,13 +410,13 @@ impl ToFields for Predicate {
410410
// in every case: pad to (hash_size + 2) field elements
411411
let mut fields: Vec<F> = match self {
412412
Self::Native(p) => iter::once(F::from_canonical_u64(1))
413-
.chain(p.to_fields(_params))
413+
.chain(p.to_fields(params))
414414
.collect(),
415415
Self::BatchSelf(i) => iter::once(F::from_canonical_u64(2))
416416
.chain(iter::once(F::from_canonical_usize(*i)))
417417
.collect(),
418418
Self::Custom(CustomPredicateRef(pb, i)) => iter::once(F::from_canonical_u64(3))
419-
.chain(pb.hash(_params).0)
419+
.chain(pb.hash(params).0)
420420
.chain(iter::once(F::from_canonical_usize(*i)))
421421
.collect(),
422422
};

src/middleware/operation.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use anyhow::{anyhow, Result};
22
use log::error;
3+
use plonky2::field::types::Field;
34
use serde::{Deserialize, Serialize};
45
use std::fmt;
6+
use std::iter;
57

68
use super::{CustomPredicateRef, NativePredicate, Statement, StatementArg, ToFields, F};
79
use crate::middleware::{AnchoredKey, Params, Predicate, Value, SELF};
@@ -14,7 +16,17 @@ pub enum OperationType {
1416

1517
impl ToFields for OperationType {
1618
fn to_fields(&self, params: &Params) -> Vec<F> {
17-
todo!()
19+
let mut fields: Vec<F> = match self {
20+
Self::Native(p) => iter::once(F::from_canonical_u64(1))
21+
.chain(p.to_fields(params))
22+
.collect(),
23+
Self::Custom(CustomPredicateRef(pb, i)) => iter::once(F::from_canonical_u64(3))
24+
.chain(pb.hash(params).0)
25+
.chain(iter::once(F::from_canonical_usize(*i)))
26+
.collect(),
27+
};
28+
fields.resize_with(Params::operation_type_size(), || F::from_canonical_u64(0));
29+
fields
1830
}
1931
}
2032

@@ -37,6 +49,12 @@ pub enum NativeOperation {
3749
MaxOf = 15,
3850
}
3951

52+
impl ToFields for NativeOperation {
53+
fn to_fields(&self, _params: &Params) -> Vec<F> {
54+
vec![F::from_canonical_u64(*self as u64)]
55+
}
56+
}
57+
4058
impl OperationType {
4159
/// Gives the type of predicate that the operation will output, if known.
4260
/// CopyStatement may output any predicate (it will match the statement copied),

0 commit comments

Comments
 (0)