diff --git a/src/analyzer/mod.rs b/src/analyzer/mod.rs index 177464e4b..1beb786b1 100644 --- a/src/analyzer/mod.rs +++ b/src/analyzer/mod.rs @@ -611,7 +611,10 @@ impl Context { let old_locals = std::mem::take(&mut self.local_variables); - let mac = &self.macros[name]; + let mac = &self + .macros + .get(name) + .unwrap_or_else(|| panic!("Macro {name} not found.")); self.local_variables = mac .parameters .iter() @@ -681,6 +684,11 @@ impl Context { assert!(right <= u32::MAX.into()); left.pow(right as u32) } + BinaryOperator::Mod => left % right, + BinaryOperator::BinaryAnd => left & right, + BinaryOperator::BinaryOr => left | right, + BinaryOperator::ShiftLeft => left << right, + BinaryOperator::ShiftRight => left >> right, }) } else { None diff --git a/src/commit_evaluator/mod.rs b/src/commit_evaluator/mod.rs index ec7fc0ec5..0d2fbdeca 100644 --- a/src/commit_evaluator/mod.rs +++ b/src/commit_evaluator/mod.rs @@ -196,6 +196,27 @@ impl<'a> Evaluator<'a> { None } } + BinaryOperator::Mod + | BinaryOperator::BinaryAnd + | BinaryOperator::BinaryOr + | BinaryOperator::ShiftLeft + | BinaryOperator::ShiftRight => { + if let (Some(left), Some(right)) = + (left.constant_value(), right.constant_value()) + { + let result = match op { + BinaryOperator::Mod => left % right, + BinaryOperator::BinaryAnd => left & right, + BinaryOperator::BinaryOr => left | right, + BinaryOperator::ShiftLeft => left << right, + BinaryOperator::ShiftRight => left >> right, + _ => panic!(), + }; + Some(result.into()) + } else { + panic!() + } + } } } else { None diff --git a/src/constant_evaluator/mod.rs b/src/constant_evaluator/mod.rs index 008126eff..d112b884e 100644 --- a/src/constant_evaluator/mod.rs +++ b/src/constant_evaluator/mod.rs @@ -87,6 +87,11 @@ impl<'a> Evaluator<'a> { assert!(right <= u32::MAX.into()); left.pow(right as u32) } + BinaryOperator::Mod => left % right, + BinaryOperator::BinaryAnd => left & right, + BinaryOperator::BinaryOr => left | right, + BinaryOperator::ShiftLeft => left << right, + BinaryOperator::ShiftRight => left >> right, } } diff --git a/src/json_exporter/mod.rs b/src/json_exporter/mod.rs index a0d740072..291c11619 100644 --- a/src/json_exporter/mod.rs +++ b/src/json_exporter/mod.rs @@ -263,6 +263,13 @@ impl<'a> Exporter<'a> { ); ("pow", deg_left + deg_right) } + BinaryOperator::Mod + | BinaryOperator::BinaryAnd + | BinaryOperator::BinaryOr + | BinaryOperator::ShiftLeft + | BinaryOperator::ShiftRight => { + panic!("Operator {op:?} not supported on polynomials.") + } }; ( degree, diff --git a/src/parser/ast.rs b/src/parser/ast.rs index c16fa8691..d6c4178cd 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -74,5 +74,10 @@ pub enum BinaryOperator { Sub, Mul, Div, + Mod, Pow, + BinaryAnd, + BinaryOr, + ShiftLeft, + ShiftRight, } diff --git a/src/parser/pil.lalrpop b/src/parser/pil.lalrpop index a45ecdb94..6727d405e 100644 --- a/src/parser/pil.lalrpop +++ b/src/parser/pil.lalrpop @@ -129,7 +129,39 @@ Expression: Expression = { } BoxedExpression: Box = { - BoxedExpression SumOp Product => Box::new(Expression::BinaryOperation(<>)), + BinaryOr +} + +BinaryOr: Box = { + BinaryOr BinaryOrOp BinaryAnd => Box::new(Expression::BinaryOperation(<>)), + BinaryAnd, +} + +BinaryOrOp: BinaryOperator = { + "|" => BinaryOperator::BinaryOr, +} + +BinaryAnd: Box = { + BinaryAnd BinaryAndOp BitShift => Box::new(Expression::BinaryOperation(<>)), + BitShift, +} + +BinaryAndOp: BinaryOperator = { + "&" => BinaryOperator::BinaryAnd, +} + +BitShift: Box = { + BitShift BitShiftOp Sum => Box::new(Expression::BinaryOperation(<>)), + Sum, +} + +BitShiftOp: BinaryOperator = { + "<<" => BinaryOperator::ShiftLeft, + ">>" => BinaryOperator::ShiftRight, +} + +Sum: Box = { + Sum SumOp Product => Box::new(Expression::BinaryOperation(<>)), Product, } @@ -146,6 +178,7 @@ Product: Box = { ProductOp: BinaryOperator = { "*" => BinaryOperator::Mul, "/" => BinaryOperator::Div, + "%" => BinaryOperator::Mod, } Power: Box = { diff --git a/tests/global.pil b/tests/global.pil new file mode 100644 index 000000000..16c4758ac --- /dev/null +++ b/tests/global.pil @@ -0,0 +1,41 @@ +/* + * LICENSE WARNING + * + * These files are from the [polygon-hermez zkEVM project](https://github.com/0xPolygonHermez/zkevm-proverjs) + * and were developed by Polygon. They are not covered by the MIT license of this repository. + * All rights reserved by Polygon. + */ + +constant %N = 2**20; + +namespace Global(%N); + macro is_nonzero(X) { X / X }; // 0 / 0 == 0 makes this work... + macro is_zero(X) { 1 - is_nonzero(X) }; + macro is_equal(A, B) { is_zero(A - B) }; + macro is_one(X) { is_equal(X, 1) }; + macro ite(C, A, B) { is_nonzero(C) * A + is_zero(C) * B}; + macro one_hot(i, index) { ite(is_equal(i, index), 1, 0) }; + + col fixed L1(i) { one_hot(i, 0) }; + col fixed LLAST(i) { one_hot(i, %N - 1) }; + col fixed BYTE(i) { i & 0xff }; + col fixed BYTE2(i) { i & 0xffff }; +// col fixed BYTE_2A(i) { BYTE2(i) >> 8 }; + col fixed BYTE_2A(i) { (i & 0xffff) >> 8 }; + // TODO it might be confusing to remember which one is the array index + // and which one is the polynomial parameter. + // Here, k is the array index and i is the polynomial parameter. + + // TODO + //col fixed CLK32[32](k, i) { one_hot(i, i % 32 == k) }; + +// TODO +// col fixed BYTE_FACTOR[8](k i) { ((i >> 2) & 0x07) == index ? [1n, 256n, 256n**2n, 256n**3n][i % 4]:0n }; + // [0] = 1,256,256**2,256**3, 0:28 (cyclic) + // [1] = 0:4, 1,256,256**2,256**3, 0:24 (cyclic) + // [7] = 0:28, 1,256,256**2,256**3 (cyclic) + + col fixed STEP(i) { i }; // 0, 1, 2, 3, ...... N-1 + + col fixed STEP32(i) { i % 32 }; + diff --git a/tests/integration.rs b/tests/integration.rs index 07d600462..e91dbfc1e 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -42,3 +42,8 @@ fn test_fibonacci() { fn test_fibonacci_macro() { verify("fib_macro.pil"); } + +#[test] +fn test_global() { + verify("global.pil"); +}