From 4ab9cdb1b048494e8afc61974dec66829be41a94 Mon Sep 17 00:00:00 2001 From: schaeff Date: Mon, 19 Sep 2022 18:37:25 +0200 Subject: [PATCH 1/8] implement better check, add test --- Cargo.lock | 9 +- zokrates_core/Cargo.toml | 1 - .../boolean_array_comparator.rs | 320 ++++++++++++++++++ zokrates_core/src/static_analysis/mod.rs | 7 + .../tests/arrays/boolean_array_equality.json | 7 + .../tests/arrays/boolean_array_equality.zok | 8 + zokrates_field/src/dummy_curve.rs | 253 ++++++++++++++ zokrates_field/src/lib.rs | 2 + 8 files changed, 598 insertions(+), 9 deletions(-) create mode 100644 zokrates_core/src/static_analysis/boolean_array_comparator.rs create mode 100644 zokrates_core_test/tests/tests/arrays/boolean_array_equality.json create mode 100644 zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok create mode 100644 zokrates_field/src/dummy_curve.rs diff --git a/Cargo.lock b/Cargo.lock index 7e67221a..1a74be51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2109,12 +2109,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "reduce" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d2dc47b68ac15ea328cd7ebe01d7d512ed29787f7d534ad2a3c341328b35d7" - [[package]] name = "regex" version = "0.2.11" @@ -3127,7 +3121,6 @@ dependencies = [ "num 0.1.42", "num-bigint 0.2.6", "pretty_assertions 0.6.1", - "reduce", "serde", "serde_json", "typed-arena", @@ -3215,7 +3208,7 @@ dependencies = [ [[package]] name = "zokrates_js" -version = "1.1.2" +version = "1.1.3" dependencies = [ "console_error_panic_hook", "indexmap", diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index c1f316f2..744b685f 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -18,7 +18,6 @@ num = { version = "0.1.36", default-features = false } num-bigint = { version = "0.2", default-features = false } lazy_static = "1.4" typed-arena = "1.4.1" -reduce = "0.1.1" # serialization and deserialization serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/zokrates_core/src/static_analysis/boolean_array_comparator.rs b/zokrates_core/src/static_analysis/boolean_array_comparator.rs new file mode 100644 index 00000000..90b83f28 --- /dev/null +++ b/zokrates_core/src/static_analysis/boolean_array_comparator.rs @@ -0,0 +1,320 @@ +use zokrates_ast::typed::{ + folder::*, ArrayExpressionInner, ArrayValue, BooleanExpression, ConditionalExpression, + ConditionalKind, EqExpression, FieldElementExpression, SelectExpression, Type, TypedExpression, + TypedProgram, UExpressionInner, +}; +use zokrates_field::Field; + +#[derive(Default)] +pub struct BooleanArrayComparator; + +impl BooleanArrayComparator { + pub fn simplify(p: TypedProgram) -> TypedProgram { + Self::default().fold_program(p) + } +} + +impl<'ast, T: Field> Folder<'ast, T> for BooleanArrayComparator { + fn fold_boolean_expression( + &mut self, + e: BooleanExpression<'ast, T>, + ) -> BooleanExpression<'ast, T> { + match e { + BooleanExpression::ArrayEq(e) => match e.left.inner_type() { + Type::Boolean => { + let len = e.left.size(); + let len = match len.as_inner() { + UExpressionInner::Value(v) => *v as usize, + _ => unreachable!("array size should be known"), + }; + + let chunk_size = T::get_required_bits() as usize - 1; + + let left_elements: Vec<_> = (0..len) + .map(|i| { + BooleanExpression::Select(SelectExpression::new( + *e.left.clone(), + (i as u32).into(), + )) + }) + .collect(); + let right_elements: Vec<_> = (0..len) + .map(|i| { + BooleanExpression::Select(SelectExpression::new( + *e.right.clone(), + (i as u32).into(), + )) + }) + .collect(); + + let process = |elements: &[BooleanExpression<'ast, T>]| { + elements + .chunks(chunk_size) + .map(|chunk| { + TypedExpression::from( + chunk + .iter() + .rev() + .enumerate() + .rev() + .map(|(index, c)| { + FieldElementExpression::Conditional( + ConditionalExpression::new( + c.clone(), + FieldElementExpression::Pow( + box FieldElementExpression::Number( + T::from(2), + ), + box (index as u32).into(), + ), + T::zero().into(), + ConditionalKind::Ternary, + ), + ) + }) + .fold(None, |acc, e| match acc { + Some(acc) => { + Some(FieldElementExpression::Add(box acc, box e)) + } + None => Some(e), + }) + .unwrap_or_else(|| { + FieldElementExpression::Number(T::zero()) + }), + ) + .into() + }) + .collect() + }; + + let left: Vec<_> = process(&left_elements); + + let right: Vec<_> = process(&right_elements); + + let chunk_count = left.len(); + + BooleanExpression::ArrayEq(EqExpression::new( + ArrayExpressionInner::Value(ArrayValue(left)) + .annotate(Type::FieldElement, chunk_count as u32), + ArrayExpressionInner::Value(ArrayValue(right)) + .annotate(Type::FieldElement, chunk_count as u32), + )) + } + _ => fold_boolean_expression(self, BooleanExpression::ArrayEq(e)), + }, + e => fold_boolean_expression(self, e), + } + } +} + +#[cfg(test)] +mod tests { + use num::Zero; + use zokrates_ast::typed::{ + ArrayExpressionInner, ArrayValue, BooleanExpression, ConditionalExpression, + ConditionalKind, EqExpression, FieldElementExpression, SelectExpression, Type, + TypedExpression, UBitwidth, UExpressionInner, + }; + use zokrates_field::DummyCurveField; + + use super::*; + + #[test] + fn simplify_short_array_eq() { + // x == y // type bool[2] + // should become + // [x[0] ? 2**1 : 0 + x[1] ? 2**0 : 0] == [y[0] ? 2**1 : 0 + y[1] ? 2**0 : 0] + // a single field is sufficient, as the prime we're working with is 3 bits long, so we can pack up to 2 bits + + let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new( + ArrayExpressionInner::Identifier("x".into()).annotate(Type::Boolean, 2u32), + ArrayExpressionInner::Identifier("y".into()).annotate(Type::Boolean, 2u32), + )); + + let expected = BooleanExpression::ArrayEq(EqExpression::new( + ArrayExpressionInner::Value(ArrayValue(vec![TypedExpression::from( + FieldElementExpression::Add( + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("x".into()) + .annotate(Type::Boolean, 2u32), + UExpressionInner::Value(0).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(1).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("x".into()) + .annotate(Type::Boolean, 2u32), + UExpressionInner::Value(1).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + ), + ) + .into()])) + .annotate(Type::FieldElement, 1u32), + ArrayExpressionInner::Value(ArrayValue(vec![TypedExpression::from( + FieldElementExpression::Add( + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("y".into()) + .annotate(Type::Boolean, 2u32), + UExpressionInner::Value(0).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(1).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("y".into()) + .annotate(Type::Boolean, 2u32), + UExpressionInner::Value(1).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + ), + ) + .into()])) + .annotate(Type::FieldElement, 1u32), + )); + + let res = BooleanArrayComparator::default().fold_boolean_expression(e); + + assert_eq!(res, expected); + } + + #[test] + fn simplify_long_array_eq() { + // x == y // type bool[3] + // should become + // [x[0] ? 2**2 : 0 + x[1] ? 2**1 : 0, x[2] ? 2**0 : 0] == [y[0] ? 2**2 : 0 + y[1] ? 2**1 : 0 y[2] ? 2**0 : 0] + + let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new( + ArrayExpressionInner::Identifier("x".into()).annotate(Type::Boolean, 3u32), + ArrayExpressionInner::Identifier("y".into()).annotate(Type::Boolean, 3u32), + )); + + let expected = BooleanExpression::ArrayEq(EqExpression::new( + ArrayExpressionInner::Value(ArrayValue(vec![ + TypedExpression::from(FieldElementExpression::Add( + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("x".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(0).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(1).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("x".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(1).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + )) + .into(), + TypedExpression::from(FieldElementExpression::Conditional( + ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("x".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(2).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + ), + )) + .into(), + ])) + .annotate(Type::FieldElement, 2u32), + ArrayExpressionInner::Value(ArrayValue(vec![ + TypedExpression::from(FieldElementExpression::Add( + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("y".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(0).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(1).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + box FieldElementExpression::Conditional(ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("y".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(1).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + )), + )) + .into(), + TypedExpression::from(FieldElementExpression::Conditional( + ConditionalExpression::new( + BooleanExpression::Select(SelectExpression::new( + ArrayExpressionInner::Identifier("y".into()) + .annotate(Type::Boolean, 3u32), + UExpressionInner::Value(2).annotate(UBitwidth::B32), + )), + FieldElementExpression::Pow( + box FieldElementExpression::Number(DummyCurveField::from(2)), + box UExpressionInner::Value(0).annotate(UBitwidth::B32), + ), + FieldElementExpression::Number(DummyCurveField::zero()), + ConditionalKind::Ternary, + ), + )) + .into(), + ])) + .annotate(Type::FieldElement, 2u32), + )); + + let res = BooleanArrayComparator::default().fold_boolean_expression(e); + + assert_eq!(res, expected); + } +} diff --git a/zokrates_core/src/static_analysis/mod.rs b/zokrates_core/src/static_analysis/mod.rs index e6ed76b2..bf394dc2 100644 --- a/zokrates_core/src/static_analysis/mod.rs +++ b/zokrates_core/src/static_analysis/mod.rs @@ -4,6 +4,7 @@ //! @author Thibaut Schaeffer //! @date 2018 +mod boolean_array_comparator; mod branch_isolator; mod condition_redefiner; mod constant_argument_checker; @@ -21,6 +22,7 @@ mod uint_optimizer; mod variable_write_remover; mod zir_propagation; +use self::boolean_array_comparator::BooleanArrayComparator; use self::branch_isolator::Isolator; use self::condition_redefiner::ConditionRedefiner; use self::constant_argument_checker::ConstantArgumentChecker; @@ -146,6 +148,11 @@ pub fn analyse<'ast, T: Field>( let r = Propagator::propagate(r).map_err(Error::from)?; log::trace!("\n{}", r); + // simplify boolean array comparisons + log::debug!("Static analyser: Simplify boolean array comparisons"); + let r = BooleanArrayComparator::simplify(r); + log::trace!("\n{}", r); + // remove assignment to variable index log::debug!("Static analyser: Remove variable index"); let r = VariableWriteRemover::apply(r); diff --git a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json new file mode 100644 index 00000000..64bcaaab --- /dev/null +++ b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json @@ -0,0 +1,7 @@ +{ + "entry_point": "./tests/tests/arrays/boolean_array_equality.zok", + "curves": ["Bn128"], + "max_constraint_count": 1005, + "tests": [] + } + \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok new file mode 100644 index 00000000..a0a864d3 --- /dev/null +++ b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok @@ -0,0 +1,8 @@ +// this should cost 1000 for input constraint, and then 1 per chunk of 253 booleans (for bn128), so here 5 +// total 1005 + +const u32 SIZE = 1000; + +def main(bool[SIZE] a) { + assert(a == [true; SIZE]); +} \ No newline at end of file diff --git a/zokrates_field/src/dummy_curve.rs b/zokrates_field/src/dummy_curve.rs new file mode 100644 index 00000000..5d3aed4a --- /dev/null +++ b/zokrates_field/src/dummy_curve.rs @@ -0,0 +1,253 @@ +use crate::{Field, Pow}; +use num_bigint::BigUint; +use num_traits::{CheckedDiv, One, Zero}; +use serde_derive::{Deserialize, Serialize}; +use std::convert::{From, TryFrom}; +use std::fmt; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{Add, Div, Mul, Sub}; + +const _PRIME: u8 = 7; + +#[derive(Default, Debug, Hash, Clone, PartialOrd, Ord, Serialize, Deserialize, PartialEq, Eq)] +pub struct FieldPrime { + v: u8, +} + +impl fmt::Display for FieldPrime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.v) + } +} + +impl From for FieldPrime { + fn from(_: u128) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(_: u64) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(_: u32) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(_: u16) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(num: u8) -> Self { + FieldPrime { v: num } + } +} + +impl From for FieldPrime { + fn from(_: usize) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(_: bool) -> Self { + unimplemented!() + } +} + +impl From for FieldPrime { + fn from(num: i32) -> Self { + assert!(num < _PRIME as i32); + assert!(num >= 0); + Self::from(num as u8) + } +} + +impl TryFrom for FieldPrime { + type Error = (); + + fn try_from(_: BigUint) -> Result { + unimplemented!() + } +} + +impl Zero for FieldPrime { + fn zero() -> FieldPrime { + FieldPrime { v: 0 } + } + fn is_zero(&self) -> bool { + self.v.is_zero() + } +} + +impl One for FieldPrime { + fn one() -> FieldPrime { + FieldPrime { v: 1 } + } +} + +impl Add for FieldPrime { + type Output = FieldPrime; + + fn add(self, _: FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl<'a> Add<&'a FieldPrime> for FieldPrime { + type Output = FieldPrime; + + fn add(self, _: &FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl Sub for FieldPrime { + type Output = FieldPrime; + + fn sub(self, _: FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl<'a> Sub<&'a FieldPrime> for FieldPrime { + type Output = FieldPrime; + + fn sub(self, _: &FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl Mul for FieldPrime { + type Output = FieldPrime; + + fn mul(self, _: FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl<'a> Mul<&'a FieldPrime> for FieldPrime { + type Output = FieldPrime; + + fn mul(self, _: &FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl CheckedDiv for FieldPrime { + fn checked_div(&self, _: &FieldPrime) -> Option { + unimplemented!() + } +} + +impl Div for FieldPrime { + type Output = FieldPrime; + + fn div(self, _: FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl<'a> Div<&'a FieldPrime> for FieldPrime { + type Output = FieldPrime; + + fn div(self, _: &FieldPrime) -> FieldPrime { + unimplemented!() + } +} + +impl Pow for FieldPrime { + type Output = FieldPrime; + + fn pow(self, _: usize) -> FieldPrime { + unimplemented!() + } +} + +impl num_traits::CheckedAdd for FieldPrime { + fn checked_add(&self, _: &Self) -> Option { + unimplemented!() + } +} + +impl num_traits::CheckedMul for FieldPrime { + fn checked_mul(&self, _: &Self) -> Option { + unimplemented!() + } +} + +impl Field for FieldPrime { + const G2_TYPE: crate::G2Type = crate::G2Type::Fq2; + + fn to_byte_vector(&self) -> Vec { + unimplemented!() + } + + fn from_byte_vector(_: Vec) -> Self { + unimplemented!() + } + + fn to_dec_string(&self) -> String { + unimplemented!() + } + + fn inverse_mul(&self) -> Option { + unimplemented!() + } + + fn min_value() -> Self { + unimplemented!() + } + + fn max_value() -> Self { + unimplemented!() + } + + fn max_unique_value() -> Self { + unimplemented!() + } + + fn to_bits_be(&self) -> Vec { + unimplemented!() + } + + fn get_required_bits() -> usize { + 3 // ceil(log2(7)) + } + + fn try_from_dec_str(_: &str) -> Result { + unimplemented!() + } + + fn try_from_str(_: &str, _: u32) -> Result { + unimplemented!() + } + + fn to_compact_dec_string(&self) -> String { + unimplemented!() + } + + fn id() -> [u8; 4] { + unimplemented!() + } + + fn name() -> &'static str { + unimplemented!() + } + + fn bits(&self) -> u32 { + unimplemented!() + } + + fn to_biguint(&self) -> num_bigint::BigUint { + unimplemented!() + } +} diff --git a/zokrates_field/src/lib.rs b/zokrates_field/src/lib.rs index dc1e6b90..38f76905 100644 --- a/zokrates_field/src/lib.rs +++ b/zokrates_field/src/lib.rs @@ -632,8 +632,10 @@ pub mod bls12_377; pub mod bls12_381; pub mod bn128; pub mod bw6_761; +pub mod dummy_curve; pub use bls12_377::FieldPrime as Bls12_377Field; pub use bls12_381::FieldPrime as Bls12_381Field; pub use bn128::FieldPrime as Bn128Field; pub use bw6_761::FieldPrime as Bw6_761Field; +pub use dummy_curve::FieldPrime as DummyCurveField; From 2fc54f18b26571379699e24984076a61f3abdc56 Mon Sep 17 00:00:00 2001 From: schaeff Date: Tue, 20 Sep 2022 15:14:38 +0200 Subject: [PATCH 2/8] changelog, prettier --- changelogs/unreleased/1228-schaeff | 1 + .../tests/tests/arrays/boolean_array_equality.json | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/1228-schaeff diff --git a/changelogs/unreleased/1228-schaeff b/changelogs/unreleased/1228-schaeff new file mode 100644 index 00000000..0727702e --- /dev/null +++ b/changelogs/unreleased/1228-schaeff @@ -0,0 +1 @@ +Reduce cost of boolean array equality checks \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json index 64bcaaab..cc5ab4fb 100644 --- a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json +++ b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json @@ -1,7 +1,6 @@ { - "entry_point": "./tests/tests/arrays/boolean_array_equality.zok", - "curves": ["Bn128"], - "max_constraint_count": 1005, - "tests": [] - } - \ No newline at end of file + "entry_point": "./tests/tests/arrays/boolean_array_equality.zok", + "curves": ["Bn128"], + "max_constraint_count": 1005, + "tests": [] +} From 7f818c80bcef248d29b0d044c13684bcc8cf86d0 Mon Sep 17 00:00:00 2001 From: schaeff Date: Tue, 20 Sep 2022 15:18:54 +0200 Subject: [PATCH 3/8] fix expected constraint count --- .../tests/tests/arrays/boolean_array_equality.json | 2 +- .../tests/tests/arrays/boolean_array_equality.zok | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json index cc5ab4fb..f4397c38 100644 --- a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json +++ b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.json @@ -1,6 +1,6 @@ { "entry_point": "./tests/tests/arrays/boolean_array_equality.zok", "curves": ["Bn128"], - "max_constraint_count": 1005, + "max_constraint_count": 1004, "tests": [] } diff --git a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok index a0a864d3..e2f5a669 100644 --- a/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok +++ b/zokrates_core_test/tests/tests/arrays/boolean_array_equality.zok @@ -1,5 +1,5 @@ -// this should cost 1000 for input constraint, and then 1 per chunk of 253 booleans (for bn128), so here 5 -// total 1005 +// this should cost 1000 for input constraint, and then 1 per chunk of 253 booleans (for bn128), so here 4 +// total 1004 const u32 SIZE = 1000; From 745c495fc69967a0124e8ca0e8f88994326b3abb Mon Sep 17 00:00:00 2001 From: schaeff Date: Fri, 23 Sep 2022 15:52:33 +0200 Subject: [PATCH 4/8] use helper functions for tests, wip --- zokrates_core/Cargo.toml | 2 +- zokrates_core/src/lib.rs | 1 + .../boolean_array_comparator.rs | 204 +++--------- zokrates_core/src/utils/macros.rs | 305 ++++++++++++++++++ zokrates_core/src/utils/mod.rs | 1 + 5 files changed, 344 insertions(+), 169 deletions(-) create mode 100644 zokrates_core/src/utils/macros.rs create mode 100644 zokrates_core/src/utils/mod.rs diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 744b685f..10fa24a1 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zokrates_core" version = "0.7.2" -edition = "2018" +edition = "2021" authors = ["Jacob Eberhardt ", "Dennis Kuhnert "] repository = "https://github.com/Zokrates/ZoKrates" readme = "README.md" diff --git a/zokrates_core/src/lib.rs b/zokrates_core/src/lib.rs index b6cebfcb..e9e0358d 100644 --- a/zokrates_core/src/lib.rs +++ b/zokrates_core/src/lib.rs @@ -7,3 +7,4 @@ mod macros; mod optimizer; mod semantics; mod static_analysis; +pub mod utils; diff --git a/zokrates_core/src/static_analysis/boolean_array_comparator.rs b/zokrates_core/src/static_analysis/boolean_array_comparator.rs index 90b83f28..5456e21f 100644 --- a/zokrates_core/src/static_analysis/boolean_array_comparator.rs +++ b/zokrates_core/src/static_analysis/boolean_array_comparator.rs @@ -117,6 +117,8 @@ mod tests { }; use zokrates_field::DummyCurveField; + use crate::utils::macros::{a, a_id, conditional, f, select, u_32}; + use super::*; #[test] @@ -126,76 +128,24 @@ mod tests { // [x[0] ? 2**1 : 0 + x[1] ? 2**0 : 0] == [y[0] ? 2**1 : 0 + y[1] ? 2**0 : 0] // a single field is sufficient, as the prime we're working with is 3 bits long, so we can pack up to 2 bits - let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Identifier("x".into()).annotate(Type::Boolean, 2u32), - ArrayExpressionInner::Identifier("y".into()).annotate(Type::Boolean, 2u32), - )); + let x = x.clone(); + let y = x.clone(); + + let e: BooleanExpression = + BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); let expected = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value(ArrayValue(vec![TypedExpression::from( - FieldElementExpression::Add( - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("x".into()) - .annotate(Type::Boolean, 2u32), - UExpressionInner::Value(0).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("x".into()) - .annotate(Type::Boolean, 2u32), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - ), - ) - .into()])) - .annotate(Type::FieldElement, 1u32), - ArrayExpressionInner::Value(ArrayValue(vec![TypedExpression::from( - FieldElementExpression::Add( - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("y".into()) - .annotate(Type::Boolean, 2u32), - UExpressionInner::Value(0).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("y".into()) - .annotate(Type::Boolean, 2u32), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - ), - ) - .into()])) - .annotate(Type::FieldElement, 1u32), + a([ + conditional::, _>( + select::<_, BooleanExpression<_>, _, _>(x.clone(), 0u32), + f(2).pow(u_32(1)), + f(0), + ) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + ]), + a([ + conditional(select(y.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + + conditional(select(y.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + ]), )); let res = BooleanArrayComparator::default().fold_boolean_expression(e); @@ -209,108 +159,26 @@ mod tests { // should become // [x[0] ? 2**2 : 0 + x[1] ? 2**1 : 0, x[2] ? 2**0 : 0] == [y[0] ? 2**2 : 0 + y[1] ? 2**1 : 0 y[2] ? 2**0 : 0] - let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Identifier("x".into()).annotate(Type::Boolean, 3u32), - ArrayExpressionInner::Identifier("y".into()).annotate(Type::Boolean, 3u32), - )); + let x = a_id("x").annotate(Type::Boolean, 3u32); + let y = a_id("x").annotate(Type::Boolean, 3u32); + + let e: BooleanExpression = + BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); let expected = BooleanExpression::ArrayEq(EqExpression::new( - ArrayExpressionInner::Value(ArrayValue(vec![ - TypedExpression::from(FieldElementExpression::Add( - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("x".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(0).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("x".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - )) - .into(), - TypedExpression::from(FieldElementExpression::Conditional( - ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("x".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - ), - )) - .into(), - ])) - .annotate(Type::FieldElement, 2u32), - ArrayExpressionInner::Value(ArrayValue(vec![ - TypedExpression::from(FieldElementExpression::Add( - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("y".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(0).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(1).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - box FieldElementExpression::Conditional(ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("y".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(1).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - )), - )) - .into(), - TypedExpression::from(FieldElementExpression::Conditional( - ConditionalExpression::new( - BooleanExpression::Select(SelectExpression::new( - ArrayExpressionInner::Identifier("y".into()) - .annotate(Type::Boolean, 3u32), - UExpressionInner::Value(2).annotate(UBitwidth::B32), - )), - FieldElementExpression::Pow( - box FieldElementExpression::Number(DummyCurveField::from(2)), - box UExpressionInner::Value(0).annotate(UBitwidth::B32), - ), - FieldElementExpression::Number(DummyCurveField::zero()), - ConditionalKind::Ternary, - ), - )) - .into(), - ])) - .annotate(Type::FieldElement, 2u32), + a([ + conditional::, _>( + select::<_, BooleanExpression<_>, _, _>(x.clone(), 0u32), + f(2).pow(u_32(1)), + f(0), + ) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + conditional(select(x.clone(), 2u32), f(2).pow(u_32(0)), f(0)), + ]), + a([ + conditional(select(y.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + + conditional(select(y.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + conditional(select(y.clone(), 2u32), f(2).pow(u_32(0)), f(0)), + ]), )); let res = BooleanArrayComparator::default().fold_boolean_expression(e); diff --git a/zokrates_core/src/utils/macros.rs b/zokrates_core/src/utils/macros.rs new file mode 100644 index 00000000..ffc5f7b1 --- /dev/null +++ b/zokrates_core/src/utils/macros.rs @@ -0,0 +1,305 @@ +use std::path::PathBuf; + +use zokrates_ast::typed::{ + types::GStructMember, ArrayExpression, ArrayExpressionInner, ArrayValue, Block, + BooleanExpression, Conditional, ConditionalKind, CoreIdentifier, DeclarationFunctionKey, + DeclarationType, DefinitionRhs, Element, Expr, FieldElementExpression, FunctionCall, GVariable, + Identifier, Member, MemberId, Select, ShadowedIdentifier, StructExpression, + StructExpressionInner, StructType, TupleExpression, TupleExpressionInner, TupleType, Type, + Typed, TypedAssignee, TypedExpression, TypedExpressionOrSpread, TypedStatement, UExpression, + Variable, +}; + +pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { + FieldElementExpression::Number(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn f_id<'ast, T, I: TryInto>>(v: I) -> FieldElementExpression<'ast, T> { + zokrates_ast::typed::FieldElementExpression::Identifier(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn a_id<'ast, T, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { + zokrates_ast::typed::ArrayExpressionInner::Identifier(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn id<'ast>(id: &'ast str) -> Identifier<'ast> { + let mut limbs = id.split("_"); + let name = limbs.next().unwrap(); + let shadow = limbs.next().map(|n| n.parse().unwrap()).unwrap(); + let version = limbs.next().map(|n| n.parse().unwrap()).unwrap_or(0); + Identifier { + version, + id: CoreIdentifier::Source(ShadowedIdentifier { shadow, id: name }), + } +} + +fn parse_type<'ast, T>(s: &'ast str) -> Type<'ast, T> { + match s { + "field" => Type::FieldElement, + "bool" => Type::Boolean, + _ => unimplemented!(), + } +} + +fn parse_expression<'ast, T>(s: &'ast str, ty: &Type<'ast, T>) -> TypedExpression<'ast, T> { + let id = id(s); + match ty { + Type::FieldElement => f_id(id).into(), + _ => unimplemented!(), + } +} + +pub fn stat<'ast, T: Clone>(s: &'ast str) -> TypedStatement<'ast, T> { + let mut is_mutable = false; + let mut s = s.split(" "); + let mut next = s.next().unwrap(); + if next == "mut" { + is_mutable = true; + next = s.next().unwrap(); + } + let ty = parse_type(next); + let id = CoreIdentifier::try_from(s.next().unwrap()) + .map_err(|_| ()) + .unwrap(); + assert_eq!(s.next().unwrap(), "="); + let e = parse_expression(s.next().unwrap(), &ty); + TypedStatement::Definition(Variable::new(id, ty, is_mutable).into(), e.into()) +} + +pub fn f_v<'ast, S: Clone, U: TryInto>>(v: U) -> GVariable<'ast, S> { + GVariable::field_element(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn b<'ast, T>(v: bool) -> BooleanExpression<'ast, T> { + BooleanExpression::Value(v) +} + +pub fn b_id<'ast, T, U: TryInto>>(v: U) -> BooleanExpression<'ast, T> { + zokrates_ast::typed::BooleanExpression::Identifier(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn b_v<'ast, T: Clone, U: TryInto>>(v: U) -> Variable<'ast, T> { + Variable::boolean(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn u_64<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) + .annotate(zokrates_ast::typed::UBitwidth::B64) +} + +pub fn u_64_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Identifier(v.into()) + .annotate(zokrates_ast::typed::UBitwidth::B32) +} + +pub fn u_32<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) + .annotate(zokrates_ast::typed::UBitwidth::B32) +} + +pub fn u_32_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Identifier(v.into()) + .annotate(zokrates_ast::typed::UBitwidth::B32) +} + +pub fn u_16<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) + .annotate(zokrates_ast::typed::UBitwidth::B32) +} + +pub fn u_16_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Identifier(v.into()) + .annotate(zokrates_ast::typed::UBitwidth::B16) +} + +pub fn u_8<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) + .annotate(zokrates_ast::typed::UBitwidth::B8) +} + +pub fn u_8_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { + zokrates_ast::typed::UExpressionInner::Identifier(v.into()) + .annotate(zokrates_ast::typed::UBitwidth::B8) +} + +pub fn conditional<'ast, T, E: Conditional<'ast, T>, B: TryInto>>( + condition: B, + consequence: E, + alternative: E, +) -> E { + E::conditional( + condition.try_into().map_err(|_| ()).unwrap(), + consequence, + alternative, + ConditionalKind::Ternary, + ) +} + +pub fn block<'ast, T, E: Block<'ast, T>, const N: usize>( + statements: [TypedStatement<'ast, T>; N], + value: E, +) -> E { + E::block(statements.into(), value) +} + +pub fn select< + 'ast, + T, + E: Select<'ast, T>, + A: TryInto>, + I: TryInto>, +>( + array: A, + index: I, +) -> E { + E::select( + array.try_into().map_err(|_| ()).unwrap(), + index.try_into().map_err(|_| ()).unwrap(), + ) +} + +pub fn member< + 'ast, + T, + E: Member<'ast, T>, + S: TryInto>, + I: TryInto, +>( + struc: S, + id: I, +) -> E { + E::member( + struc.try_into().map_err(|_| ()).unwrap(), + id.try_into().map_err(|_| ()).unwrap(), + ) +} + +pub fn call<'ast, T, E: Expr<'ast, T> + FunctionCall<'ast, T>, const N: usize, const M: usize>( + key: DeclarationFunctionKey<'ast, T>, + generics: [Option>; N], + arguments: [TypedExpression<'ast, T>; M], +) -> E::Inner { + E::function_call( + key, + generics.into_iter().collect(), + arguments.into_iter().collect(), + ) +} + +pub fn element< + 'ast, + T, + E: Element<'ast, T>, + U: TryInto>, + I: TryInto, +>( + tuple: U, + index: I, +) -> E { + E::element( + tuple.try_into().map_err(|_| ()).unwrap(), + index.try_into().map_err(|_| ()).unwrap(), + ) +} + +// pub fn equals<'ast, T, E: Equals<'ast, T>>(left: E, right: E) -> BooleanExpression<'ast, T> { +// left.equals(right) +// } + +// pub fn define_no_inference< +// 'ast, +// T, +// A: TryInto>, +// E: TryInto>, +// >( +// a: A, +// e: E, +// ) -> TypedStatement<'ast, T> { +// TypedStatement::Definition( +// a.try_into().map_err(|_| ()).unwrap(), +// DefinitionRhs::Expression(e.try_into().map_err(|_| ()).unwrap()), +// ) +// } + +// pub fn define< +// 'ast, +// T: Clone, +// A: TryInto>, +// E: Typed<'ast, T> + Expr<'ast, T> + TryInto>, +// >( +// a: A, +// e: E, +// ) -> TypedStatement<'ast, T> { +// let ty = e.get_type().clone(); + +// TypedStatement::Definition( +// Variable::new(a.try_into().map_err(|_| ()).unwrap(), ty, false).into(), +// DefinitionRhs::Expression(e.try_into().map_err(|_| ()).unwrap()), +// ) +// } + +// pub fn pop_call<'ast, T>() -> TypedStatement<'ast, T> { +// TypedStatement::PopCallLog +// } + +// pub fn push_call<'ast, T>() -> TypedStatement<'ast, T> { +// TypedStatement::PushCallLog +// } + +// pub fn ret<'ast, T, E: Typed<'ast, T> + Expr<'ast, T> + TryInto>>( +// e: E, +// ) -> TypedStatement<'ast, T> { +// TypedStatement::Return(e.try_into().map_err(|_| ()).unwrap()) +// } + +pub fn condition_id<'ast>(i: usize) -> CoreIdentifier<'ast> { + CoreIdentifier::Condition(i) +} + +pub fn a< + 'ast, + T, + E: Typed<'ast, T> + Expr<'ast, T> + Into>, + const N: usize, +>( + values: [E; N], +) -> ArrayExpression<'ast, T> { + let ty = values[0].get_type(); + ArrayExpressionInner::Value(ArrayValue( + values + .into_iter() + .map(|e| TypedExpressionOrSpread::Expression(e.into())) + .collect(), + )) + .annotate(ty, N as u32) +} + +pub fn s<'ast, T: Clone, M: TryInto, I: TryInto, const N: usize>( + name: M, + members: [(I, TypedExpression<'ast, T>); N], +) -> StructExpression<'ast, T> { + let members: Vec<_> = members + .into_iter() + .map(|(id, e)| (id.try_into().map_err(|_| ()).unwrap(), e)) + .collect(); + + let ty = StructType::new( + PathBuf::default(), + name.try_into().map_err(|_| ()).unwrap(), + vec![], + members + .iter() + .map(|(id, e)| GStructMember::new(id.clone(), e.get_type().clone())) + .collect(), + ); + + StructExpressionInner::Value(members.into_iter().map(|(_, e)| e).collect()).annotate(ty) +} + +pub fn t<'ast, T: Clone, const N: usize>( + elements: [TypedExpression<'ast, T>; N], +) -> TupleExpression<'ast, T> { + let ty = TupleType::new(elements.iter().map(|e| e.get_type().clone()).collect()); + + TupleExpressionInner::Value(elements.into_iter().collect()).annotate(ty) +} diff --git a/zokrates_core/src/utils/mod.rs b/zokrates_core/src/utils/mod.rs new file mode 100644 index 00000000..eda363d6 --- /dev/null +++ b/zokrates_core/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod macros; From 955d6bae5d02a90ab85ff5aac72ee47ba24ab4c4 Mon Sep 17 00:00:00 2001 From: schaeff Date: Mon, 26 Sep 2022 15:08:41 +0200 Subject: [PATCH 5/8] clean --- zokrates_ast/src/typed/mod.rs | 1 + zokrates_ast/src/typed/utils/mod.rs | 45 +++ zokrates_core/src/lib.rs | 1 - .../boolean_array_comparator.rs | 27 +- .../src/static_analysis/reducer/inline.rs | 2 - .../static_analysis/variable_write_remover.rs | 2 - zokrates_core/src/utils/macros.rs | 305 ------------------ zokrates_core/src/utils/mod.rs | 1 - 8 files changed, 54 insertions(+), 330 deletions(-) create mode 100644 zokrates_ast/src/typed/utils/mod.rs delete mode 100644 zokrates_core/src/utils/macros.rs delete mode 100644 zokrates_core/src/utils/mod.rs diff --git a/zokrates_ast/src/typed/mod.rs b/zokrates_ast/src/typed/mod.rs index a43f59bd..0ea0870e 100644 --- a/zokrates_ast/src/typed/mod.rs +++ b/zokrates_ast/src/typed/mod.rs @@ -14,6 +14,7 @@ mod integer; mod parameter; pub mod types; mod uint; +pub mod utils; pub mod variable; pub use self::identifier::{CoreIdentifier, ShadowedIdentifier, SourceIdentifier}; diff --git a/zokrates_ast/src/typed/utils/mod.rs b/zokrates_ast/src/typed/utils/mod.rs new file mode 100644 index 00000000..1603d043 --- /dev/null +++ b/zokrates_ast/src/typed/utils/mod.rs @@ -0,0 +1,45 @@ +use super::{ + ArrayExpression, ArrayExpressionInner, BooleanExpression, Conditional, ConditionalKind, + FieldElementExpression, Identifier, Select, UBitwidth, UExpression, UExpressionInner, +}; + +pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { + FieldElementExpression::Number(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn a_id<'ast, T, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { + ArrayExpressionInner::Identifier(v.try_into().map_err(|_| ()).unwrap()) +} + +pub fn u_32<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { + UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128).annotate(UBitwidth::B32) +} + +pub fn conditional<'ast, T, E: Conditional<'ast, T>>( + condition: BooleanExpression<'ast, T>, + consequence: E, + alternative: E, +) -> E { + E::conditional( + condition, + consequence, + alternative, + ConditionalKind::Ternary, + ) +} + +pub fn select< + 'ast, + T, + E: Select<'ast, T>, + A: TryInto>, + I: TryInto>, +>( + array: A, + index: I, +) -> E { + E::select( + array.try_into().map_err(|_| ()).unwrap(), + index.try_into().map_err(|_| ()).unwrap(), + ) +} diff --git a/zokrates_core/src/lib.rs b/zokrates_core/src/lib.rs index e9e0358d..b6cebfcb 100644 --- a/zokrates_core/src/lib.rs +++ b/zokrates_core/src/lib.rs @@ -7,4 +7,3 @@ mod macros; mod optimizer; mod semantics; mod static_analysis; -pub mod utils; diff --git a/zokrates_core/src/static_analysis/boolean_array_comparator.rs b/zokrates_core/src/static_analysis/boolean_array_comparator.rs index 5456e21f..b3530b50 100644 --- a/zokrates_core/src/static_analysis/boolean_array_comparator.rs +++ b/zokrates_core/src/static_analysis/boolean_array_comparator.rs @@ -109,15 +109,10 @@ impl<'ast, T: Field> Folder<'ast, T> for BooleanArrayComparator { #[cfg(test)] mod tests { - use num::Zero; - use zokrates_ast::typed::{ - ArrayExpressionInner, ArrayValue, BooleanExpression, ConditionalExpression, - ConditionalKind, EqExpression, FieldElementExpression, SelectExpression, Type, - TypedExpression, UBitwidth, UExpressionInner, - }; + use zokrates_ast::typed::{BooleanExpression, EqExpression, FieldElementExpression, Type}; use zokrates_field::DummyCurveField; - use crate::utils::macros::{a, a_id, conditional, f, select, u_32}; + use zokrates_ast::typed::utils::{a, a_id, conditional, f, select, u_32}; use super::*; @@ -128,19 +123,16 @@ mod tests { // [x[0] ? 2**1 : 0 + x[1] ? 2**0 : 0] == [y[0] ? 2**1 : 0 + y[1] ? 2**0 : 0] // a single field is sufficient, as the prime we're working with is 3 bits long, so we can pack up to 2 bits - let x = x.clone(); - let y = x.clone(); + let x = a_id("x").annotate(Type::Boolean, 2u32); + let y = a_id("x").annotate(Type::Boolean, 2u32); let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); let expected = BooleanExpression::ArrayEq(EqExpression::new( a([ - conditional::, _>( - select::<_, BooleanExpression<_>, _, _>(x.clone(), 0u32), - f(2).pow(u_32(1)), - f(0), - ) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + conditional(select(x.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), ]), a([ conditional(select(y.clone(), 0u32), f(2).pow(u_32(1)), f(0)) @@ -167,11 +159,8 @@ mod tests { let expected = BooleanExpression::ArrayEq(EqExpression::new( a([ - conditional::, _>( - select::<_, BooleanExpression<_>, _, _>(x.clone(), 0u32), - f(2).pow(u_32(1)), - f(0), - ) + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), + conditional(select(x.clone(), 0u32), f(2).pow(u_32(1)), f(0)) + + conditional(select(x.clone(), 1u32), f(2).pow(u_32(0)), f(0)), conditional(select(x.clone(), 2u32), f(2).pow(u_32(0)), f(0)), ]), a([ diff --git a/zokrates_core/src/static_analysis/reducer/inline.rs b/zokrates_core/src/static_analysis/reducer/inline.rs index b2c12962..09aa6c93 100644 --- a/zokrates_core/src/static_analysis/reducer/inline.rs +++ b/zokrates_core/src/static_analysis/reducer/inline.rs @@ -88,8 +88,6 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>( program: &TypedProgram<'ast, T>, versions: &'a mut Versions<'ast>, ) -> InlineResult<'ast, T> { - use std::convert::TryFrom; - use zokrates_ast::typed::Typed; let output_type = output.clone().into_type(); diff --git a/zokrates_core/src/static_analysis/variable_write_remover.rs b/zokrates_core/src/static_analysis/variable_write_remover.rs index ce80c960..ea1c72da 100644 --- a/zokrates_core/src/static_analysis/variable_write_remover.rs +++ b/zokrates_core/src/static_analysis/variable_write_remover.rs @@ -37,8 +37,6 @@ impl<'ast> VariableWriteRemover { let inner_ty = base.inner_type(); let size = base.size(); - use std::convert::TryInto; - let size: u32 = size.try_into().unwrap(); let head = indices.remove(0); diff --git a/zokrates_core/src/utils/macros.rs b/zokrates_core/src/utils/macros.rs deleted file mode 100644 index ffc5f7b1..00000000 --- a/zokrates_core/src/utils/macros.rs +++ /dev/null @@ -1,305 +0,0 @@ -use std::path::PathBuf; - -use zokrates_ast::typed::{ - types::GStructMember, ArrayExpression, ArrayExpressionInner, ArrayValue, Block, - BooleanExpression, Conditional, ConditionalKind, CoreIdentifier, DeclarationFunctionKey, - DeclarationType, DefinitionRhs, Element, Expr, FieldElementExpression, FunctionCall, GVariable, - Identifier, Member, MemberId, Select, ShadowedIdentifier, StructExpression, - StructExpressionInner, StructType, TupleExpression, TupleExpressionInner, TupleType, Type, - Typed, TypedAssignee, TypedExpression, TypedExpressionOrSpread, TypedStatement, UExpression, - Variable, -}; - -pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { - FieldElementExpression::Number(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn f_id<'ast, T, I: TryInto>>(v: I) -> FieldElementExpression<'ast, T> { - zokrates_ast::typed::FieldElementExpression::Identifier(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn a_id<'ast, T, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { - zokrates_ast::typed::ArrayExpressionInner::Identifier(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn id<'ast>(id: &'ast str) -> Identifier<'ast> { - let mut limbs = id.split("_"); - let name = limbs.next().unwrap(); - let shadow = limbs.next().map(|n| n.parse().unwrap()).unwrap(); - let version = limbs.next().map(|n| n.parse().unwrap()).unwrap_or(0); - Identifier { - version, - id: CoreIdentifier::Source(ShadowedIdentifier { shadow, id: name }), - } -} - -fn parse_type<'ast, T>(s: &'ast str) -> Type<'ast, T> { - match s { - "field" => Type::FieldElement, - "bool" => Type::Boolean, - _ => unimplemented!(), - } -} - -fn parse_expression<'ast, T>(s: &'ast str, ty: &Type<'ast, T>) -> TypedExpression<'ast, T> { - let id = id(s); - match ty { - Type::FieldElement => f_id(id).into(), - _ => unimplemented!(), - } -} - -pub fn stat<'ast, T: Clone>(s: &'ast str) -> TypedStatement<'ast, T> { - let mut is_mutable = false; - let mut s = s.split(" "); - let mut next = s.next().unwrap(); - if next == "mut" { - is_mutable = true; - next = s.next().unwrap(); - } - let ty = parse_type(next); - let id = CoreIdentifier::try_from(s.next().unwrap()) - .map_err(|_| ()) - .unwrap(); - assert_eq!(s.next().unwrap(), "="); - let e = parse_expression(s.next().unwrap(), &ty); - TypedStatement::Definition(Variable::new(id, ty, is_mutable).into(), e.into()) -} - -pub fn f_v<'ast, S: Clone, U: TryInto>>(v: U) -> GVariable<'ast, S> { - GVariable::field_element(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn b<'ast, T>(v: bool) -> BooleanExpression<'ast, T> { - BooleanExpression::Value(v) -} - -pub fn b_id<'ast, T, U: TryInto>>(v: U) -> BooleanExpression<'ast, T> { - zokrates_ast::typed::BooleanExpression::Identifier(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn b_v<'ast, T: Clone, U: TryInto>>(v: U) -> Variable<'ast, T> { - Variable::boolean(v.try_into().map_err(|_| ()).unwrap()) -} - -pub fn u_64<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) - .annotate(zokrates_ast::typed::UBitwidth::B64) -} - -pub fn u_64_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Identifier(v.into()) - .annotate(zokrates_ast::typed::UBitwidth::B32) -} - -pub fn u_32<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) - .annotate(zokrates_ast::typed::UBitwidth::B32) -} - -pub fn u_32_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Identifier(v.into()) - .annotate(zokrates_ast::typed::UBitwidth::B32) -} - -pub fn u_16<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) - .annotate(zokrates_ast::typed::UBitwidth::B32) -} - -pub fn u_16_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Identifier(v.into()) - .annotate(zokrates_ast::typed::UBitwidth::B16) -} - -pub fn u_8<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128) - .annotate(zokrates_ast::typed::UBitwidth::B8) -} - -pub fn u_8_id<'ast, T>(v: &'ast str) -> UExpression<'ast, T> { - zokrates_ast::typed::UExpressionInner::Identifier(v.into()) - .annotate(zokrates_ast::typed::UBitwidth::B8) -} - -pub fn conditional<'ast, T, E: Conditional<'ast, T>, B: TryInto>>( - condition: B, - consequence: E, - alternative: E, -) -> E { - E::conditional( - condition.try_into().map_err(|_| ()).unwrap(), - consequence, - alternative, - ConditionalKind::Ternary, - ) -} - -pub fn block<'ast, T, E: Block<'ast, T>, const N: usize>( - statements: [TypedStatement<'ast, T>; N], - value: E, -) -> E { - E::block(statements.into(), value) -} - -pub fn select< - 'ast, - T, - E: Select<'ast, T>, - A: TryInto>, - I: TryInto>, ->( - array: A, - index: I, -) -> E { - E::select( - array.try_into().map_err(|_| ()).unwrap(), - index.try_into().map_err(|_| ()).unwrap(), - ) -} - -pub fn member< - 'ast, - T, - E: Member<'ast, T>, - S: TryInto>, - I: TryInto, ->( - struc: S, - id: I, -) -> E { - E::member( - struc.try_into().map_err(|_| ()).unwrap(), - id.try_into().map_err(|_| ()).unwrap(), - ) -} - -pub fn call<'ast, T, E: Expr<'ast, T> + FunctionCall<'ast, T>, const N: usize, const M: usize>( - key: DeclarationFunctionKey<'ast, T>, - generics: [Option>; N], - arguments: [TypedExpression<'ast, T>; M], -) -> E::Inner { - E::function_call( - key, - generics.into_iter().collect(), - arguments.into_iter().collect(), - ) -} - -pub fn element< - 'ast, - T, - E: Element<'ast, T>, - U: TryInto>, - I: TryInto, ->( - tuple: U, - index: I, -) -> E { - E::element( - tuple.try_into().map_err(|_| ()).unwrap(), - index.try_into().map_err(|_| ()).unwrap(), - ) -} - -// pub fn equals<'ast, T, E: Equals<'ast, T>>(left: E, right: E) -> BooleanExpression<'ast, T> { -// left.equals(right) -// } - -// pub fn define_no_inference< -// 'ast, -// T, -// A: TryInto>, -// E: TryInto>, -// >( -// a: A, -// e: E, -// ) -> TypedStatement<'ast, T> { -// TypedStatement::Definition( -// a.try_into().map_err(|_| ()).unwrap(), -// DefinitionRhs::Expression(e.try_into().map_err(|_| ()).unwrap()), -// ) -// } - -// pub fn define< -// 'ast, -// T: Clone, -// A: TryInto>, -// E: Typed<'ast, T> + Expr<'ast, T> + TryInto>, -// >( -// a: A, -// e: E, -// ) -> TypedStatement<'ast, T> { -// let ty = e.get_type().clone(); - -// TypedStatement::Definition( -// Variable::new(a.try_into().map_err(|_| ()).unwrap(), ty, false).into(), -// DefinitionRhs::Expression(e.try_into().map_err(|_| ()).unwrap()), -// ) -// } - -// pub fn pop_call<'ast, T>() -> TypedStatement<'ast, T> { -// TypedStatement::PopCallLog -// } - -// pub fn push_call<'ast, T>() -> TypedStatement<'ast, T> { -// TypedStatement::PushCallLog -// } - -// pub fn ret<'ast, T, E: Typed<'ast, T> + Expr<'ast, T> + TryInto>>( -// e: E, -// ) -> TypedStatement<'ast, T> { -// TypedStatement::Return(e.try_into().map_err(|_| ()).unwrap()) -// } - -pub fn condition_id<'ast>(i: usize) -> CoreIdentifier<'ast> { - CoreIdentifier::Condition(i) -} - -pub fn a< - 'ast, - T, - E: Typed<'ast, T> + Expr<'ast, T> + Into>, - const N: usize, ->( - values: [E; N], -) -> ArrayExpression<'ast, T> { - let ty = values[0].get_type(); - ArrayExpressionInner::Value(ArrayValue( - values - .into_iter() - .map(|e| TypedExpressionOrSpread::Expression(e.into())) - .collect(), - )) - .annotate(ty, N as u32) -} - -pub fn s<'ast, T: Clone, M: TryInto, I: TryInto, const N: usize>( - name: M, - members: [(I, TypedExpression<'ast, T>); N], -) -> StructExpression<'ast, T> { - let members: Vec<_> = members - .into_iter() - .map(|(id, e)| (id.try_into().map_err(|_| ()).unwrap(), e)) - .collect(); - - let ty = StructType::new( - PathBuf::default(), - name.try_into().map_err(|_| ()).unwrap(), - vec![], - members - .iter() - .map(|(id, e)| GStructMember::new(id.clone(), e.get_type().clone())) - .collect(), - ); - - StructExpressionInner::Value(members.into_iter().map(|(_, e)| e).collect()).annotate(ty) -} - -pub fn t<'ast, T: Clone, const N: usize>( - elements: [TypedExpression<'ast, T>; N], -) -> TupleExpression<'ast, T> { - let ty = TupleType::new(elements.iter().map(|e| e.get_type().clone()).collect()); - - TupleExpressionInner::Value(elements.into_iter().collect()).annotate(ty) -} diff --git a/zokrates_core/src/utils/mod.rs b/zokrates_core/src/utils/mod.rs deleted file mode 100644 index eda363d6..00000000 --- a/zokrates_core/src/utils/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod macros; From 230e8f0e84f7b123c91b53382aaa00089033552d Mon Sep 17 00:00:00 2001 From: schaeff Date: Mon, 26 Sep 2022 15:22:13 +0200 Subject: [PATCH 6/8] fix utils --- zokrates_ast/src/typed/utils/mod.rs | 23 +++++++++++++++++-- .../boolean_array_comparator.rs | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/zokrates_ast/src/typed/utils/mod.rs b/zokrates_ast/src/typed/utils/mod.rs index 1603d043..3720113c 100644 --- a/zokrates_ast/src/typed/utils/mod.rs +++ b/zokrates_ast/src/typed/utils/mod.rs @@ -1,6 +1,7 @@ use super::{ - ArrayExpression, ArrayExpressionInner, BooleanExpression, Conditional, ConditionalKind, - FieldElementExpression, Identifier, Select, UBitwidth, UExpression, UExpressionInner, + ArrayExpression, ArrayExpressionInner, ArrayValue, BooleanExpression, Conditional, + ConditionalKind, Expr, FieldElementExpression, Identifier, Select, Typed, TypedExpression, + TypedExpressionOrSpread, UBitwidth, UExpression, UExpressionInner, }; pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { @@ -11,6 +12,24 @@ pub fn a_id<'ast, T, I: TryInto>>(v: I) -> ArrayExpressionInner ArrayExpressionInner::Identifier(v.try_into().map_err(|_| ()).unwrap()) } +pub fn a< + 'ast, + T, + E: Typed<'ast, T> + Expr<'ast, T> + Into>, + const N: usize, +>( + values: [E; N], +) -> ArrayExpression<'ast, T> { + let ty = values[0].get_type(); + ArrayExpressionInner::Value(ArrayValue( + values + .into_iter() + .map(|e| TypedExpressionOrSpread::Expression(e.into())) + .collect(), + )) + .annotate(ty, N as u32) +} + pub fn u_32<'ast, T, U: TryInto>(v: U) -> UExpression<'ast, T> { UExpressionInner::Value(v.try_into().map_err(|_| ()).unwrap() as u128).annotate(UBitwidth::B32) } diff --git a/zokrates_core/src/static_analysis/boolean_array_comparator.rs b/zokrates_core/src/static_analysis/boolean_array_comparator.rs index b3530b50..f33d07b4 100644 --- a/zokrates_core/src/static_analysis/boolean_array_comparator.rs +++ b/zokrates_core/src/static_analysis/boolean_array_comparator.rs @@ -109,7 +109,7 @@ impl<'ast, T: Field> Folder<'ast, T> for BooleanArrayComparator { #[cfg(test)] mod tests { - use zokrates_ast::typed::{BooleanExpression, EqExpression, FieldElementExpression, Type}; + use zokrates_ast::typed::{BooleanExpression, EqExpression, Type}; use zokrates_field::DummyCurveField; use zokrates_ast::typed::utils::{a, a_id, conditional, f, select, u_32}; From c2f5e1a91f0c2e795e7bef091cfad2cbd33ab334 Mon Sep 17 00:00:00 2001 From: schaeff Date: Wed, 5 Oct 2022 14:37:05 +0200 Subject: [PATCH 7/8] fix error following merge --- zokrates_ast/src/typed/utils/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/zokrates_ast/src/typed/utils/mod.rs b/zokrates_ast/src/typed/utils/mod.rs index 3720113c..6ec6885c 100644 --- a/zokrates_ast/src/typed/utils/mod.rs +++ b/zokrates_ast/src/typed/utils/mod.rs @@ -1,15 +1,17 @@ use super::{ ArrayExpression, ArrayExpressionInner, ArrayValue, BooleanExpression, Conditional, - ConditionalKind, Expr, FieldElementExpression, Identifier, Select, Typed, TypedExpression, + ConditionalKind, Expr, FieldElementExpression, Id, Identifier, Select, Typed, TypedExpression, TypedExpressionOrSpread, UBitwidth, UExpression, UExpressionInner, }; +use zokrates_field::Field; + pub fn f<'ast, T, U: TryInto>(v: U) -> FieldElementExpression<'ast, T> { FieldElementExpression::Number(v.try_into().map_err(|_| ()).unwrap()) } -pub fn a_id<'ast, T, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { - ArrayExpressionInner::Identifier(v.try_into().map_err(|_| ()).unwrap()) +pub fn a_id<'ast, T: Field, I: TryInto>>(v: I) -> ArrayExpressionInner<'ast, T> { + ArrayExpression::identifier(v.try_into().map_err(|_| ()).unwrap()) } pub fn a< From 9aca2d7360574d344de793ddad331321107a328e Mon Sep 17 00:00:00 2001 From: schaeff Date: Wed, 26 Oct 2022 11:20:51 -0500 Subject: [PATCH 8/8] fix typo --- zokrates_core/src/static_analysis/boolean_array_comparator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zokrates_core/src/static_analysis/boolean_array_comparator.rs b/zokrates_core/src/static_analysis/boolean_array_comparator.rs index f33d07b4..cb016c03 100644 --- a/zokrates_core/src/static_analysis/boolean_array_comparator.rs +++ b/zokrates_core/src/static_analysis/boolean_array_comparator.rs @@ -124,7 +124,7 @@ mod tests { // a single field is sufficient, as the prime we're working with is 3 bits long, so we can pack up to 2 bits let x = a_id("x").annotate(Type::Boolean, 2u32); - let y = a_id("x").annotate(Type::Boolean, 2u32); + let y = a_id("y").annotate(Type::Boolean, 2u32); let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone())); @@ -152,7 +152,7 @@ mod tests { // [x[0] ? 2**2 : 0 + x[1] ? 2**1 : 0, x[2] ? 2**0 : 0] == [y[0] ? 2**2 : 0 + y[1] ? 2**1 : 0 y[2] ? 2**0 : 0] let x = a_id("x").annotate(Type::Boolean, 3u32); - let y = a_id("x").annotate(Type::Boolean, 3u32); + let y = a_id("y").annotate(Type::Boolean, 3u32); let e: BooleanExpression = BooleanExpression::ArrayEq(EqExpression::new(x.clone(), y.clone()));