Skip to content
Open
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
102 changes: 98 additions & 4 deletions src/backends/plonky2/mainpod/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,10 @@ impl Pod for MainPod {

#[cfg(test)]
pub mod tests {
use std::{any::Any, collections::HashSet};
use std::{
any::Any,
collections::{HashMap, HashSet},
};

use num::{BigUint, One};

Expand All @@ -821,11 +824,15 @@ pub mod tests {
zu_kyc_sign_dict_builders, EthDosHelper,
},
frontend::{
self, literal, CustomPredicateBatchBuilder, MainPodBuilder, StatementTmplBuilder as STB,
self, literal, CustomPredicateBatchBuilder, MainPodBuilder, SignedDictBuilder,
StatementTmplBuilder as STB,
},
lang::parse,
middleware::{
self, containers::Set, CustomPredicateRef, NativePredicate as NP, Signer as _,
DEFAULT_VD_LIST, DEFAULT_VD_SET,
self,
containers::{Dictionary, Set},
CustomPredicateRef, NativePredicate as NP, Signer as _, Value, DEFAULT_VD_LIST,
DEFAULT_VD_SET, EMPTY_HASH,
},
};

Expand Down Expand Up @@ -859,6 +866,93 @@ pub mod tests {
Ok(pod.verify()?)
}

#[test]
fn test_main_dict_updates() -> frontend::Result<()> {
let params = &middleware::Params::default();
let mut vds = DEFAULT_VD_LIST.clone();
vds.push(rec_main_pod_circuit_data(params).1.verifier_only.clone());
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
let signer = Signer(SecretKey(1u32.into()));

let empty_dict = Dictionary::new_empty(params.max_depth_mt_containers);
assert_eq!(empty_dict.commitment(), EMPTY_HASH);

let mut hash_map: HashMap<middleware::Key, Value> = HashMap::new();
hash_map.insert(middleware::Key::from("i"), Value::from(123456));
let int_dict = Dictionary::new(params.max_depth_mt_containers, hash_map)?;

let mut before_dict_builder = SignedDictBuilder::new(params);
before_dict_builder.insert("a", "A");
before_dict_builder.insert("i", 123456);
let before_dict = before_dict_builder.sign(&signer)?;

let mut after_dict_builder = SignedDictBuilder::new(params);
after_dict_builder.insert("a", "B");
after_dict_builder.insert("i", 123456);
let after_dict = after_dict_builder.sign(&signer)?;

let mut pod_builder = MainPodBuilder::new(params, &vd_set);
pod_builder.pub_op(frontend::Operation::dict_signed_by(&before_dict))?;
pod_builder.pub_op(frontend::Operation::dict_signed_by(&after_dict))?;
pod_builder.pub_op(frontend::Operation::dict_insert(
int_dict.clone(),
empty_dict,
"i",
123456,
))?;
pod_builder.pub_op(frontend::Operation::dict_insert(
before_dict.dict.clone(),
int_dict.clone(),
"a",
"A",
))?;
pod_builder.pub_op(frontend::Operation::dict_update(
after_dict.dict.clone(),
before_dict.dict.clone(),
"a",
"B",
))?;

let prover = Prover {};
let proven = pod_builder.prove(&prover)?;
crate::measure_gates_print!();
let pod = (proven.pod as Box<dyn Any>).downcast::<MainPod>().unwrap();

pod.verify()?;

// The exact_match_pod() search doesn't know about syntactic sugar
// statements, so we need to use Container* not Dict*.
let podlang_input1 = r#"
REQUEST(
SignedBy(?before, ?signer)
SignedBy(?after, ?signer)
ContainerInsert(?int_only, {}, "i", 123456)
ContainerInsert(?before, ?int_only, "a", "A")
ContainerUpdate(?after, ?before, "a", "B")
)
"#;

let request1 = parse(podlang_input1, params, &[])?.request;
assert!(request1.exact_match_pod(&*pod).is_ok());

// Try the same again but use the null literal instead of {}, since
// they're intended to be equivalent (equating to EMPTY_HASH)
let podlang_input2 = r#"
REQUEST(
SignedBy(?before, ?signer)
SignedBy(?after, ?signer)
ContainerInsert(?int_only, null, "i", 123456)
ContainerInsert(?before, ?int_only, "a", "A")
ContainerUpdate(?after, ?before, "a", "B")
)
"#;

let request2 = parse(podlang_input2, params, &[])?.request;
assert!(request2.exact_match_pod(&*pod).is_ok());

Ok(())
}

// `RUST_LOG=pod2::backends=debug cargo test --release --no-default-features --features=backend_plonky2,mem_cache,zk,metrics test_measure_main_pod -- --nocapture --ignored`
#[ignore]
#[test]
Expand Down
95 changes: 92 additions & 3 deletions src/backends/plonky2/mock/mainpod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ impl Pod for MockMainPod {

#[cfg(test)]
pub mod tests {
use std::any::Any;
use std::{any::Any, collections::HashMap};

use super::*;
use crate::{
Expand All @@ -381,8 +381,9 @@ pub mod tests {
great_boy_pod_full_flow, tickets_pod_full_flow, zu_kyc_pod_builder, zu_kyc_pod_request,
zu_kyc_sign_dict_builders, MOCK_VD_SET,
},
frontend, middleware,
middleware::{Signer as _, Value},
frontend::{self, MainPodBuilder, SignedDictBuilder},
lang::parse,
middleware::{self, containers::Dictionary, Signer as _, Value},
};

#[test]
Expand Down Expand Up @@ -447,4 +448,92 @@ pub mod tests {

Ok(())
}

#[test]
fn test_mock_main_dict_updates() -> frontend::Result<()> {
let params = &middleware::Params::default();
let vd_set = &*MOCK_VD_SET;
let signer = Signer(SecretKey(1u32.into()));

let empty_dict = Dictionary::new_empty(params.max_depth_mt_containers);
assert_eq!(empty_dict.commitment(), EMPTY_HASH);

let mut hash_map: HashMap<middleware::Key, Value> = HashMap::new();
hash_map.insert(middleware::Key::from("i"), Value::from(123456));
let int_dict = Dictionary::new(params.max_depth_mt_containers, hash_map)?;

let mut before_dict_builder = SignedDictBuilder::new(params);
before_dict_builder.insert("a", "A");
before_dict_builder.insert("i", 123456);
let before_dict = before_dict_builder.sign(&signer)?;

let mut after_dict_builder = SignedDictBuilder::new(params);
after_dict_builder.insert("a", "B");
after_dict_builder.insert("i", 123456);
let after_dict = after_dict_builder.sign(&signer)?;

let mut pod_builder = MainPodBuilder::new(params, vd_set);
pod_builder.pub_op(frontend::Operation::dict_signed_by(&before_dict))?;
pod_builder.pub_op(frontend::Operation::dict_signed_by(&after_dict))?;
pod_builder.pub_op(frontend::Operation::dict_insert(
int_dict.clone(),
empty_dict,
"i",
123456,
))?;
pod_builder.pub_op(frontend::Operation::dict_insert(
before_dict.dict.clone(),
int_dict.clone(),
"a",
"A",
))?;
pod_builder.pub_op(frontend::Operation::dict_update(
after_dict.dict.clone(),
before_dict.dict.clone(),
"a",
"B",
))?;

let prover = MockProver {};
let proven = pod_builder.prove(&prover)?;
let pod = (proven.pod as Box<dyn Any>)
.downcast::<MockMainPod>()
.unwrap();

println!("{:#}", pod);

pod.verify()?;

// The exact_match_pod() search doesn't know about syntactic sugar
// statements, so we need to use Container* not Dict*.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be fixed by #380 (right now there's no way to communicate the original code along with a MainPod, just the lowered representation).

let podlang_input1 = r#"
REQUEST(
SignedBy(?before, ?signer)
SignedBy(?after, ?signer)
ContainerInsert(?int_only, {}, "i", 123456)
ContainerInsert(?before, ?int_only, "a", "A")
ContainerUpdate(?after, ?before, "a", "B")
)
"#;

let request1 = parse(podlang_input1, params, &[])?.request;
assert!(request1.exact_match_pod(&*pod).is_ok());

// Try the same again but use the null literal instead of {}, since
// they're intended to be equivalent (equating to EMPTY_HASH)
let podlang_input2 = r#"
REQUEST(
SignedBy(?before, ?signer)
SignedBy(?after, ?signer)
ContainerInsert(?int_only, null, "i", 123456)
ContainerInsert(?before, ?int_only, "a", "A")
ContainerUpdate(?after, ?before, "a", "B")
)
"#;

let request2 = parse(podlang_input2, params, &[])?.request;
assert!(request2.exact_match_pod(&*pod).is_ok());

Ok(())
}
}
6 changes: 4 additions & 2 deletions src/lang/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ COMMENT = _{ "//" ~ (!NEWLINE ~ ANY)* }

// Define rules for identifiers (predicate names, variable names without '?')
// Must start with alpha or _, followed by alpha, numeric, or _
identifier = @{ !("private") ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
identifier = @{ !("private" | "null") ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }

private_kw = { "private:" }

Expand Down Expand Up @@ -65,12 +65,14 @@ literal_value = {
literal_bool |
literal_raw |
literal_string |
literal_int
literal_int |
literal_null
}

// Primitive literal types
literal_int = @{ "-"? ~ ASCII_DIGIT+ }
literal_bool = @{ "true" | "false" }
literal_null = @{ "null" }

// hash_hex: 0x followed by exactly 32 PAIRS of hex digits (64 hex characters)
// representing a 32-byte value in big-endian order
Expand Down
10 changes: 9 additions & 1 deletion src/lang/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,17 @@ mod tests {
assert_parses(Rule::literal_int, "-45");
assert_parses(Rule::literal_int, "0");
assert_fails(Rule::test_literal_int, "1.23"); // Use test_literal_int rule
// Bool

// Bool
assert_parses(Rule::literal_bool, "true");
assert_fails(Rule::literal_null, "TRUE");
assert_parses(Rule::literal_bool, "false");
assert_fails(Rule::literal_null, "FALSE");

// Null
assert_parses(Rule::literal_null, "null");
assert_fails(Rule::literal_null, "NULL");
assert_fails(Rule::literal_null, "0");

// Raw - Require 64 hex digits (32 bytes, equal to 4 * 64-bit field elements)
assert_parses(
Expand Down
5 changes: 3 additions & 2 deletions src/lang/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
lang::parser::Rule,
middleware::{
self, CustomPredicateBatch, CustomPredicateRef, Key, NativePredicate, Params, Predicate,
StatementTmpl, StatementTmplArg, Value, Wildcard, F, VALUE_SIZE,
StatementTmpl, StatementTmplArg, Value, Wildcard, EMPTY_VALUE, F, VALUE_SIZE,
},
};

Expand Down Expand Up @@ -752,6 +752,7 @@ fn process_literal_value(
let val = inner_lit.as_str().parse::<bool>().unwrap();
Ok(Value::from(val))
}
Rule::literal_null => Ok(Value::from(EMPTY_VALUE)),
Rule::literal_raw => {
let full_literal_str = inner_lit.clone().into_inner().next().unwrap();
let hex_str_no_prefix = full_literal_str
Expand Down Expand Up @@ -1255,7 +1256,7 @@ mod processor_tests {
REQUEST(
EQUAL(?A["b"], ?C["d"])
)
"#;
"#;
let pairs = get_document_content_pairs(input)?;
let params = Params::default();
let mut ctx = ProcessingContext::new(&params);
Expand Down
5 changes: 5 additions & 0 deletions src/middleware/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ impl Dictionary {
kvs,
})
}

pub fn new_empty(max_depth: usize) -> Self {
Self::new(max_depth, HashMap::new()).unwrap()
}

pub fn commitment(&self) -> Hash {
self.mt.root()
}
Expand Down