allow SELF in st_tmpl (#240)

* allow SELF in st_tmpl

* add some tests

* Update src/backends/plonky2/circuits/mainpod.rs

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

---------

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
This commit is contained in:
Eduard S. 2025-05-22 15:13:02 +02:00 committed by GitHub
parent b4a4c72328
commit 82481e88d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 178 additions and 87 deletions

View file

@ -1,4 +1,4 @@
use std::{array, sync::Arc};
use std::{array, iter, sync::Arc};
use itertools::{zip_eq, Itertools};
use plonky2::{
@ -767,12 +767,18 @@ impl CustomOperationVerifyGadget {
// optimization: ak_id_wc_index and wc_index use the same signals, so we only need to do one
// random access to resolve both of them
assert_eq!(ak_id_wc_index, wc_index);
// optimization: the wildcard indices have an offset of +1. This allows us to set a fixed
// SELF in args[0] to resolve SelfOrWildcard::SELF encoded as a wildcard at index 0.
let value_self = ValueTarget::from_slice(&builder.constants(&SELF.0 .0));
let args = iter::once(value_self)
.chain(args.iter().cloned())
.collect_vec();
// If the index is not used, use a 0 instead to still pass the range constraints from
// vec_ref
let first_index = ak_id_wc_index;
let is_first_index_valid = builder.or(is_ak, is_wc_literal);
let first_index = builder.select(is_first_index_valid, first_index, zero);
let resolved_ak_id = builder.vec_ref(&self.params, args, first_index);
let resolved_ak_id = builder.vec_ref(&self.params, &args, first_index);
let resolved_wc = resolved_ak_id;
// If the index is not used, use a 0 instead to still pass the range constraints from
@ -780,7 +786,7 @@ impl CustomOperationVerifyGadget {
let second_index = ak_key_wc_index;
let is_second_index_valid = builder.and(is_ak, is_ak_key_wc);
let second_index = builder.select(is_second_index_valid, second_index, zero);
let resolved_ak_key = builder.vec_ref(&self.params, args, second_index);
let resolved_ak_key = builder.vec_ref(&self.params, &args, second_index);
let ak_key = ak_key_lit; // is_ak_key_lit
let ak_key =
@ -1278,7 +1284,7 @@ mod tests {
frontend::{self, key, literal, CustomPredicateBatchBuilder, StatementTmplBuilder},
middleware::{
hash_str, hash_values, Hash, Key, KeyOrWildcard, OperationType, PodId, Predicate,
RawValue, StatementTmpl, StatementTmplArg, Wildcard, WildcardValue,
RawValue, SelfOrWildcard, StatementTmpl, StatementTmplArg, Wildcard, WildcardValue,
},
};
@ -2222,7 +2228,7 @@ mod tests {
// case: AnchoredKey(id_wildcard, key_literal)
let st_tmpl_arg = StatementTmplArg::AnchoredKey(
Wildcard::new("a".to_string(), 1),
SelfOrWildcard::Wildcard(Wildcard::new("a".to_string(), 1)),
KeyOrWildcard::Key(Key::from("foo")),
);
let args = vec![Value::from(1), Value::from(pod_id.0), Value::from(3)];
@ -2231,13 +2237,31 @@ mod tests {
// case: AnchoredKey(id_wildcard, key_wildcard)
let st_tmpl_arg = StatementTmplArg::AnchoredKey(
Wildcard::new("a".to_string(), 1),
SelfOrWildcard::Wildcard(Wildcard::new("a".to_string(), 1)),
KeyOrWildcard::Wildcard(Wildcard::new("b".to_string(), 2)),
);
let args = vec![Value::from(1), Value::from(pod_id.0), Value::from("key")];
let expected_st_arg = StatementArg::Key(AnchoredKey::new(pod_id, Key::from("key")));
helper_statement_arg_from_template(&params, st_tmpl_arg, args, expected_st_arg)?;
// case: AnchoredKey(SELF, key_literal)
let st_tmpl_arg = StatementTmplArg::AnchoredKey(
SelfOrWildcard::SELF,
KeyOrWildcard::Key(Key::from("foo")),
);
let args = vec![Value::from(1), Value::from(pod_id.0), Value::from(3)];
let expected_st_arg = StatementArg::Key(AnchoredKey::new(SELF, Key::from("foo")));
helper_statement_arg_from_template(&params, st_tmpl_arg, args, expected_st_arg)?;
// case: AnchoredKey(SELF, key_wildcard)
let st_tmpl_arg = StatementTmplArg::AnchoredKey(
SelfOrWildcard::SELF,
KeyOrWildcard::Wildcard(Wildcard::new("b".to_string(), 2)),
);
let args = vec![Value::from(1), Value::from(pod_id.0), Value::from("key")];
let expected_st_arg = StatementArg::Key(AnchoredKey::new(SELF, Key::from("key")));
helper_statement_arg_from_template(&params, st_tmpl_arg, args, expected_st_arg)?;
// case: WildcardLiteral(wildcard)
let st_tmpl_arg = StatementTmplArg::WildcardLiteral(Wildcard::new("a".to_string(), 1));
let args = vec![Value::from(1), Value::from("key"), Value::from(3)];
@ -2294,7 +2318,7 @@ mod tests {
pred: Predicate::Native(NativePredicate::ValueOf),
args: vec![
StatementTmplArg::AnchoredKey(
Wildcard::new("a".to_string(), 1),
SelfOrWildcard::Wildcard(Wildcard::new("a".to_string(), 1)),
KeyOrWildcard::Key(Key::from("key")),
),
StatementTmplArg::Literal(Value::from("value")),

View file

@ -67,7 +67,7 @@ pub mod measure_macros {
#[macro_export]
macro_rules! measure_gates_begin {
($builder:expr, $name:expr) => {{
use $crate::backends::plonky2::circuits::utils::METRICS;
use $crate::backends::plonky2::circuits::metrics::METRICS;
let mut metrics = METRICS.lock().unwrap();
metrics.begin($builder, $name)
}};
@ -76,7 +76,7 @@ pub mod measure_macros {
#[macro_export]
macro_rules! measure_gates_end {
($builder:expr, $measure:expr) => {{
use $crate::backends::plonky2::circuits::utils::METRICS;
use $crate::backends::plonky2::circuits::metrics::METRICS;
let mut metrics = METRICS.lock().unwrap();
metrics.end($builder, $measure);
}};
@ -85,7 +85,7 @@ pub mod measure_macros {
#[macro_export]
macro_rules! measure_gates_print {
() => {{
use $crate::backends::plonky2::circuits::utils::METRICS;
use $crate::backends::plonky2::circuits::metrics::METRICS;
let metrics = METRICS.lock().unwrap();
metrics.print();
}};

View file

@ -737,11 +737,11 @@ pub mod tests {
max_statements: 26,
max_public_statements: 5,
max_signed_pod_values: 8,
max_statement_args: 6,
max_statement_args: 3,
max_operation_args: 4,
max_custom_predicate_arity: 4,
max_custom_batch_size: 3,
max_custom_predicate_wildcards: 12,
max_custom_predicate_wildcards: 6,
max_custom_predicate_verifications: 8,
..Default::default()
};