From 59423e50b48a734950bc1cd27abae9621ec409fc Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 11 Jul 2024 00:28:18 -0400 Subject: [PATCH 01/12] add simple acvm test for binary AND commutativity, add single-op solver helper, add wip slice control flow test (currently hitting the 'push_back'-panics-in-unevaluated-branch bug), add wip array control flow test --- Cargo.lock | 1 + acvm-repo/acir/src/circuit/mod.rs | 3 + acvm-repo/acvm/Cargo.toml | 1 + acvm-repo/acvm/tests/solver.rs | 76 ++- .../execution_success/array_regex/Nargo.toml | 7 + .../execution_success/array_regex/src/main.nr | 528 ++++++++++++++++++ .../execution_success/slice_regex/Nargo.toml | 7 + .../execution_success/slice_regex/src/main.nr | 431 ++++++++++++++ 8 files changed, 1053 insertions(+), 1 deletion(-) create mode 100644 test_programs/execution_success/array_regex/Nargo.toml create mode 100644 test_programs/execution_success/array_regex/src/main.nr create mode 100644 test_programs/execution_success/slice_regex/Nargo.toml create mode 100644 test_programs/execution_success/slice_regex/src/main.nr diff --git a/Cargo.lock b/Cargo.lock index 1df84a80bc7..e4e72f5dc38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,7 @@ dependencies = [ "brillig_vm", "indexmap 1.9.3", "num-bigint", + "proptest", "serde", "thiserror", "tracing", diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index 5d749e709b3..00d0933a3aa 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -377,11 +377,13 @@ mod tests { output: Witness(3), }) } + fn range_opcode() -> Opcode { Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { input: FunctionInput::witness(Witness(1), 8), }) } + fn keccakf1600_opcode() -> Opcode { let inputs: Box<[FunctionInput; 25]> = Box::new(std::array::from_fn(|i| FunctionInput::witness(Witness(i as u32 + 1), 8))); @@ -389,6 +391,7 @@ mod tests { Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccakf1600 { inputs, outputs }) } + fn schnorr_verify_opcode() -> Opcode { let public_key_x = FunctionInput::witness(Witness(1), FieldElement::max_num_bits()); let public_key_y = FunctionInput::witness(Witness(2), FieldElement::max_num_bits()); diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index 892575902a4..4428c5303e7 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -38,3 +38,4 @@ bls12_381 = [ [dev-dependencies] ark-bls12-381 = { version = "^0.4.0", default-features = false, features = ["curve"] } +proptest.workspace = true diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index e55dbb73ae1..87159d8abce 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -5,7 +5,7 @@ use acir::{ brillig::{BinaryFieldOp, HeapArray, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, circuit::{ brillig::{BrilligBytecode, BrilligInputs, BrilligOutputs}, - opcodes::{BlockId, BlockType, MemOp}, + opcodes::{BlackBoxFuncCall, BlockId, BlockType, FunctionInput, MemOp}, Opcode, OpcodeLocation, }, native_types::{Expression, Witness, WitnessMap}, @@ -16,6 +16,8 @@ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolution use acvm_blackbox_solver::StubbedBlackBoxSolver; use brillig_vm::brillig::HeapValueType; +use proptest::prelude::*; + // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. #[test] @@ -722,3 +724,75 @@ fn memory_operations() { assert_eq!(witness_map[&Witness(8)], FieldElement::from(6u128)); } + +// Solve the given BlackBoxFuncCall with witnesses: 1, 2 as x, y, resp. +#[cfg(test)] +fn solve_blackbox_func_call(blackbox_func_call: BlackBoxFuncCall, x: u128, y: u128) -> FieldElement { + let initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(x)), + (Witness(2), FieldElement::from(y)), + ])); + + let op = Opcode::BlackBoxFuncCall(blackbox_func_call); + let opcodes = vec![op]; + let unconstrained_functions = vec![]; + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved); + let witness_map = acvm.finalize(); + + witness_map[&Witness(3)] +} + + +// TODO: cleanup new tests and rename this +#[test] +fn binary_operations() { + + // // special cases + // BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub, + // BlackBoxFuncCall::BigIntDiv { .. } + // + // // BigInt: + // // + // // pub struct BigIntSolver { + // // bigint_id_to_value: HashMap, + // // bigint_id_to_modulus: HashMap, + // // } + // // + // BlackBoxFuncCall::BigIntAdd { .. } + // BlackBoxFuncCall::BigIntMul { .. } + // + // // unique calling convention + // BlackBoxFuncCall::EmbeddedCurveAdd { .. } + // + // // + // BlackBoxFuncCall::AND { .. } + // BlackBoxFuncCall::XOR { .. } + // + // AND | XOR { + // lhs: FunctionInput, + // rhs: FunctionInput, + // output: Witness, + // }, + // + + // TODO: + // - commutativity + // - associativity + // - .. + + let x = 1; + let y = 3; + + let and_op = BlackBoxFuncCall::AND { + lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), + rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), + output: Witness(3), + }; + + assert_eq!(solve_blackbox_func_call(and_op.clone(), x, y), solve_blackbox_func_call(and_op, y, x)); + +} + diff --git a/test_programs/execution_success/array_regex/Nargo.toml b/test_programs/execution_success/array_regex/Nargo.toml new file mode 100644 index 00000000000..19f70994b7f --- /dev/null +++ b/test_programs/execution_success/array_regex/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regex_array" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/array_regex/src/main.nr b/test_programs/execution_success/array_regex/src/main.nr new file mode 100644 index 00000000000..58b23ca2791 --- /dev/null +++ b/test_programs/execution_success/array_regex/src/main.nr @@ -0,0 +1,528 @@ + +// offset <= len <= N +struct Bvec { + inner: [T; N], + + // elements at indices < offset are zero + offset: u32, + + // elements at indices >= len are zero + len: u32, +} + +impl Eq for Bvec where T: Eq { + fn eq(self, other: Self) -> bool { + (self.inner == other.inner) & + (self.offset == other.offset) & + (self.len == other.len) + } +} + + +impl Bvec { + fn empty() -> Self { + Self { + inner: [std::unsafe::zeroed(); N], + offset: 0, + len: 0, + } + } + + // pushing when len == N is a no-op + fn push(self, x: T) -> Self { + let mut inner = self.inner; + let mut len = self.len; + if self.len < N { + inner[self.len] = x; + len += 1; + } + + Self { + inner, + offset: self.offset, + len, + } + } + + fn pop_front(self) -> (T, Self) { + assert(self.offset <= self.len); + assert(self.len != 0); + + let first_elem = self.inner[self.offset]; + let popped_slice = Self { + inner: self.inner, + offset: self.offset + 1, + len: self.len - 1, + }; + + (first_elem, popped_slice) + } +} + +struct Match { + succeeded: bool, + match_ends: u32, + leftover: Bvec, +} + +impl Match { + fn empty(leftover: Bvec) -> Self { + Match { + succeeded: true, + match_ends: 0, + leftover, + } + } +} + +impl Eq for Match { + fn eq(self, other: Self) -> bool { + (self.succeeded == other.succeeded) & + (self.match_ends == other.match_ends) & + (self.leftover == other.leftover) + } +} + +// TODO: load match into str and assert that it's the correct length +// impl From for str + +trait Regex { + fn match(self, input: Bvec) -> Match; +} + +// Empty +impl Regex for () { + fn match(self, input: Bvec) -> Match { + assert(self == self); // ensure 'self' is used + Match::empty(input) + } +} + +// Exact +impl Regex for str { + fn match(self, input: Bvec) -> Match { + let mut leftover = input; + let mut matches_input = true; + let self_as_bytes = self.as_bytes(); + for c in self_as_bytes { + if leftover.len != 0 { + let (first_elem, popped_slice) = leftover.pop_front(); + leftover = popped_slice; + matches_input &= first_elem == c; + } else { + matches_input = false; + } + } + if matches_input { + Match { + succeeded: true, + match_ends: self_as_bytes.len(), + leftover, + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } +} + +// And +impl Regex for (T, U) where T: Regex, U: Regex { + fn match(self, input: Bvec) -> Match { + let lhs_result = self.0.match(input); + if lhs_result.succeeded { + let rhs_result = self.1.match(lhs_result.leftover); + if rhs_result.succeeded { + Match { + succeeded: true, + match_ends: lhs_result.match_ends + rhs_result.match_ends, + leftover: rhs_result.leftover, + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } +} + +// N T's: (T, (T, (T, T))) +struct Repeated { + inner: T, +} + +impl Regex for Repeated where T: Regex { + fn match(self, input: Bvec) -> Match { + let mut result = Match::empty(input); + for _ in 0..M { + if result.succeeded { + let next_result = self.inner.match(result.leftover); + result = Match { + succeeded: next_result.succeeded, + match_ends: result.match_ends + next_result.match_ends, + leftover: next_result.leftover, + }; + } + } + result + } +} + +struct Or { + lhs: T, + rhs: U, +} + +impl Regex for Or where T: Regex, U: Regex { + fn match(self, input: Bvec) -> Match { + let lhs_result = self.lhs.match(input); + if lhs_result.succeeded { + lhs_result + } else { + self.rhs.match(input) + } + } +} + +struct Question { + inner: T, +} + +impl Regex for Question where T: Regex { + fn match(self, input: Bvec) -> Match { + Or { + lhs: self.inner, + rhs: (), + }.match(input) + } +} + +// 0 <= num_matches <= N +struct Star { + inner: T, +} + +impl Regex for Star where T: Regex { + fn match(self, input: Bvec) -> Match { + let regex: Repeated<_, M> = Repeated { + inner: Question { inner: self.inner }, + }; + regex.match(input) + } +} + +// 0 < num_matches <= N +struct Plus { + inner: T, +} + +impl Regex for Plus where T: Regex { + fn match(self, input: Bvec) -> Match { + std::static_assert(M_PRED + 1 == M, "M - 1 != M_PRED"); + let star: Star = Star { inner: self.inner }; + ( + self.inner, + star + ).match(input) + } +} + + +fn main() { + + let mut xs: Bvec = Bvec::empty(); + + xs = xs.push(0); + assert_eq(xs, Bvec { + inner: [0, 0, 0], + offset: 0, + len: 1, + }); + + xs = xs.push(1); + assert_eq(xs, Bvec { + inner: [0, 1, 0], + offset: 0, + len: 2, + }); + + xs = xs.push(2); + assert_eq(xs, Bvec { + inner: [0, 1, 2], + offset: 0, + len: 3, + }); + + xs = xs.push(3); + assert_eq(xs, Bvec { + inner: [0, 1, 2], + offset: 0, + len: 3, + }); + + + // TODO test push_front + + + // TODO + // + // // gr(a|e)y + // let graey_regex = ( + // "gr", + // ( + // Or { + // lhs: "a", + // rhs: "e", + // }, + // "y" + // ) + // ); + // + // // NOTE: leftover ignored in Eq: Match + // let result = graey_regex.match("gray".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 4, + // leftover: &[], + // }); + // + // + // // NOTE: leftover ignored in Eq: Match + // let result = graey_regex.match("grey".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 4, + // leftover: &[], + // }); + // + // // colou?r + // let colour_regex = ( + // "colo", + // ( + // Question { + // inner: "u", + // }, + // "r" + // ) + // ); + // + // let result = colour_regex.match("color".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 5, + // leftover: &[], + // }); + // + // let result = colour_regex.match("colour".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 6, + // leftover: &[], + // }); + // + // // parse the empty string three times + // // EMPTY{3} + // let three_empties_regex: Repeated<(), 3> = Repeated { + // inner: (), + // }; + // + // let result = three_empties_regex.match("111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 0, + // leftover: &[], + // }); + // + // // 1{0} + // let zero_ones_regex: Repeated, 0> = Repeated { + // inner: "1", + // }; + // + // let result = zero_ones_regex.match("111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 0, + // leftover: &[], + // }); + // + // // 1{1} + // let one_ones_regex: Repeated, 1> = Repeated { + // inner: "1", + // }; + // + // let result = one_ones_regex.match("111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 1, + // leftover: &[], + // }); + // + // // 1{2} + // let two_ones_regex: Repeated, 2> = Repeated { + // inner: "1", + // }; + // + // let result = two_ones_regex.match("111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 2, + // leftover: &[], + // }); + // + // // 1{3} + // let three_ones_regex: Repeated, 3> = Repeated { + // inner: "1", + // }; + // + // let result = three_ones_regex.match("1111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 3, + // leftover: &[], + // }); + // + // // 1* + // let ones_regex: Star, 5> = Star { + // inner: "1", + // }; + // + // let result = ones_regex.match("11000".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 2, + // leftover: &[], + // }); + // + // let result = ones_regex.match("11".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 2, + // leftover: &[], + // }); + // + // let result = ones_regex.match("111111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 5, + // leftover: &[], + // }); + // + // // 1+ + // let nonempty_ones_regex: Plus, 5, 4> = Plus { + // inner: "1", + // }; + // + // let result = nonempty_ones_regex.match("111111".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 5, + // leftover: &[], + // }); + // + // + // // 2^n-1 in binary: 1+0 + // let pred_pow_two_regex = ( + // nonempty_ones_regex, + // "0" + // ); + // + // let result = pred_pow_two_regex.match("1110".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 3, + // leftover: &[], + // }); + // + // + // // (0|1)* + // let binary_regex: Star, str<1>>, 5> = Star { + // inner: Or { + // lhs: "0", + // rhs: "1", + // } + // }; + // + // let result = binary_regex.match("110100".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 5, + // leftover: &[], + // }); + // + // // even numbers in binary: 1(0|1)*0 + // let even_binary_regex = ( + // "1", + // ( + // binary_regex, + // "0" + // ) + // ); + // + // let result = even_binary_regex.match("1111110".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 6, + // leftover: &[], + // }); + // + // // 2-letter capitalized words: [A-Z][a-z] + // + // // numbers: \d+ + // // [0-9]+ + // + // // words: \w+ + // // [a-Z]+ + // + // // adapted URL parser: (https?:\/\/)?([\da-z.\-]+)\.([a-z.]+)([\/\w \.\-]*)*\/? + // + // + // // // panics (at compile time) when input string is too short + // // let foo_regex = ( + // // "colo", + // // ( + // // Question { + // // inner: "u", + // // }, + // // "r" + // // ) + // // ); + // // + // // let result = foo_regex.match("colo".as_bytes().as_slice()); + // // println(result); + // // assert_eq(result, Match { + // // succeeded: true, + // // match_ends: 4, + // // leftover: &[], + // // }); + // + +} + diff --git a/test_programs/execution_success/slice_regex/Nargo.toml b/test_programs/execution_success/slice_regex/Nargo.toml new file mode 100644 index 00000000000..5f2b90d7580 --- /dev/null +++ b/test_programs/execution_success/slice_regex/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regex" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/slice_regex/src/main.nr b/test_programs/execution_success/slice_regex/src/main.nr new file mode 100644 index 00000000000..9dbec547a67 --- /dev/null +++ b/test_programs/execution_success/slice_regex/src/main.nr @@ -0,0 +1,431 @@ + +struct Match { + succeeded: bool, + match_ends: u32, + leftover: [u8], +} + +impl Match { + fn empty(leftover: [u8]) -> Self { + Match { + succeeded: true, + match_ends: 0, + leftover, + } + } +} + +impl Eq for Match { + fn eq(self, other: Self) -> bool { + (self.succeeded == other.succeeded) & + (self.match_ends == other.match_ends) + // (self.leftover == other.leftover) + } +} + +// TODO: load match into str and assert that it's the correct length +// impl From for str + +trait Regex { + fn match(self, input: [u8]) -> Match; +} + +// Empty +impl Regex for () { + fn match(self, input: [u8]) -> Match { + assert(self == self); // ensure 'self' is used + Match::empty(input) + } +} + +// Exact +impl Regex for str { + fn match(self, input: [u8]) -> Match { + let mut leftover = input; + let mut matches_input = true; + let self_as_bytes = self.as_bytes(); + for c in self_as_bytes { + if leftover.len() != 0 { + let (first_elem, popped_slice) = leftover.pop_front(); + leftover = popped_slice; + matches_input &= first_elem == c; + } else { + matches_input = false; + } + } + if matches_input { + Match { + succeeded: true, + match_ends: self_as_bytes.len(), + leftover, + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } +} + +// And +impl Regex for (T, U) where T: Regex, U: Regex { + fn match(self, input: [u8]) -> Match { + let lhs_result = self.0.match(input); + if lhs_result.succeeded { + let rhs_result = self.1.match(lhs_result.leftover); + if rhs_result.succeeded { + Match { + succeeded: true, + match_ends: lhs_result.match_ends + rhs_result.match_ends, + leftover: rhs_result.leftover, + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } else { + Match { + succeeded: false, + match_ends: 0, + leftover: input, + } + } + } +} + +// N T's: (T, (T, (T, T))) +struct Repeated { + inner: T, +} + +impl Regex for Repeated where T: Regex { + fn match(self, input: [u8]) -> Match { + let mut result = Match::empty(input); + for _ in 0..N { + if result.succeeded { + let next_result = self.inner.match(result.leftover); + result = Match { + succeeded: next_result.succeeded, + match_ends: result.match_ends + next_result.match_ends, + leftover: next_result.leftover, + }; + } + } + result + } +} + +struct Or { + lhs: T, + rhs: U, +} + +impl Regex for Or where T: Regex, U: Regex { + fn match(self, input: [u8]) -> Match { + let lhs_result = self.lhs.match(input); + if lhs_result.succeeded { + lhs_result + } else { + self.rhs.match(input) + } + } +} + +struct Question { + inner: T, +} + +impl Regex for Question where T: Regex { + fn match(self, input: [u8]) -> Match { + Or { + lhs: self.inner, + rhs: (), + }.match(input) + } +} + +// 0 <= num_matches <= N +struct Star { + inner: T, +} + +impl Regex for Star where T: Regex { + fn match(self, input: [u8]) -> Match { + let regex: Repeated<_, N> = Repeated { + inner: Question { inner: self.inner }, + }; + regex.match(input) + } +} + +// 0 < num_matches <= N +struct Plus { + inner: T, +} + +impl Regex for Plus where T: Regex { + fn match(self, input: [u8]) -> Match { + std::static_assert(N_PRED + 1 == N, "N - 1 != N_PRED"); + let star: Star = Star { inner: self.inner }; + ( + self.inner, + star + ).match(input) + } +} + + +fn main() { + + // gr(a|e)y + let graey_regex = ( + "gr", + ( + Or { + lhs: "a", + rhs: "e", + }, + "y" + ) + ); + + // NOTE: leftover ignored in Eq: Match + let result = graey_regex.match("gray".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 4, + leftover: &[], + }); + + + // NOTE: leftover ignored in Eq: Match + let result = graey_regex.match("grey".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 4, + leftover: &[], + }); + + // colou?r + let colour_regex = ( + "colo", + ( + Question { + inner: "u", + }, + "r" + ) + ); + + let result = colour_regex.match("color".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 5, + leftover: &[], + }); + + let result = colour_regex.match("colour".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 6, + leftover: &[], + }); + + // parse the empty string three times + // EMPTY{3} + let three_empties_regex: Repeated<(), 3> = Repeated { + inner: (), + }; + + let result = three_empties_regex.match("111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 0, + leftover: &[], + }); + + // 1{0} + let zero_ones_regex: Repeated, 0> = Repeated { + inner: "1", + }; + + let result = zero_ones_regex.match("111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 0, + leftover: &[], + }); + + // 1{1} + let one_ones_regex: Repeated, 1> = Repeated { + inner: "1", + }; + + let result = one_ones_regex.match("111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 1, + leftover: &[], + }); + + // 1{2} + let two_ones_regex: Repeated, 2> = Repeated { + inner: "1", + }; + + let result = two_ones_regex.match("111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 2, + leftover: &[], + }); + + // 1{3} + let three_ones_regex: Repeated, 3> = Repeated { + inner: "1", + }; + + let result = three_ones_regex.match("1111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 3, + leftover: &[], + }); + + // 1* + let ones_regex: Star, 5> = Star { + inner: "1", + }; + + let result = ones_regex.match("11000".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 2, + leftover: &[], + }); + + let result = ones_regex.match("11".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 2, + leftover: &[], + }); + + let result = ones_regex.match("111111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 5, + leftover: &[], + }); + + // 1+ + let nonempty_ones_regex: Plus, 5, 4> = Plus { + inner: "1", + }; + + let result = nonempty_ones_regex.match("111111".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 5, + leftover: &[], + }); + + + // 2^n-1 in binary: 1+0 + let pred_pow_two_regex = ( + nonempty_ones_regex, + "0" + ); + + let result = pred_pow_two_regex.match("1110".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 3, + leftover: &[], + }); + + + // (0|1)* + let binary_regex: Star, str<1>>, 5> = Star { + inner: Or { + lhs: "0", + rhs: "1", + } + }; + + let result = binary_regex.match("110100".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 5, + leftover: &[], + }); + + // even numbers in binary: 1(0|1)*0 + let even_binary_regex = ( + "1", + ( + binary_regex, + "0" + ) + ); + + let result = even_binary_regex.match("1111110".as_bytes().as_slice()); + println(result); + assert_eq(result, Match { + succeeded: true, + match_ends: 6, + leftover: &[], + }); + + // 2-letter capitalized words: [A-Z][a-z] + + // numbers: \d+ + // [0-9]+ + + // words: \w+ + // [a-Z]+ + + // adapted URL parser: (https?:\/\/)?([\da-z.\-]+)\.([a-z.]+)([\/\w \.\-]*)*\/? + + + // // panics (at compile time) when input string is too short + // let foo_regex = ( + // "colo", + // ( + // Question { + // inner: "u", + // }, + // "r" + // ) + // ); + // + // let result = foo_regex.match("colo".as_bytes().as_slice()); + // println(result); + // assert_eq(result, Match { + // succeeded: true, + // match_ends: 4, + // leftover: &[], + // }); + +} + From ba5811962f4bf8356b41c76e88bc2a5b58a48a13 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 11 Jul 2024 17:37:53 -0400 Subject: [PATCH 02/12] wip commutative tests for and/xor, converted and extended control flow test to arrays --- acvm-repo/acvm/tests/solver.rs | 59 ++ .../execution_success/array_regex/src/main.nr | 577 ++++++++++-------- 2 files changed, 385 insertions(+), 251 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 87159d8abce..eaf8ad55370 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -17,6 +17,7 @@ use acvm_blackbox_solver::StubbedBlackBoxSolver; use brillig_vm::brillig::HeapValueType; use proptest::prelude::*; +use proptest::arbitrary::any; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -796,3 +797,61 @@ fn binary_operations() { } +fn and_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::AND { + lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), + rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), + output: Witness(3), + } +} + +fn xor_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::XOR { + lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), + rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), + output: Witness(3), + } +} + +fn prop_assert_eq(op: BlackBoxFuncCall, x: u128, y: u128) -> TestCaseResult { + let assertion: Result<_, TestCaseError> = prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); + assertion?; + Ok(()) +} + + +proptest! { + + #[test] + fn and_commutative(x in any::(), y in any::()) { + let op = and_op(); + prop_assert_commutes(op, x, y) + } + + #[test] + fn xor_commutative(x in any::(), y in any::()) { + let op = xor_op(); + prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); + } + + // #[test] + // fn and_associative(x in any::(), y in any::()) { + // let op = and_op(); + // prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); + // } + + + // // This currently panics due to the fact that we allow inputs which are greater than the field modulus, + // // automatically reducing them to fit within the canonical range. + // #[test] + // #[should_panic(expected = "serialized field element is not equal to input")] + // fn recovers_original_hex_string(hex in "[0-9a-f]{64}") { + // let fe: FieldElement:: = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string"); + // let output_hex = fe.to_hex(); + // + // prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input"); + // } + +} + + diff --git a/test_programs/execution_success/array_regex/src/main.nr b/test_programs/execution_success/array_regex/src/main.nr index 58b23ca2791..612ca45c37a 100644 --- a/test_programs/execution_success/array_regex/src/main.nr +++ b/test_programs/execution_success/array_regex/src/main.nr @@ -28,6 +28,14 @@ impl Bvec { } } + fn new(array: [T; N]) -> Self { + let mut result = Bvec::empty(); + for x in array { + result = result.push(x); + } + result + } + // pushing when len == N is a no-op fn push(self, x: T) -> Self { let mut inner = self.inner; @@ -45,7 +53,7 @@ impl Bvec { } fn pop_front(self) -> (T, Self) { - assert(self.offset <= self.len); + assert(self.offset <= self.inner.len()); assert(self.len != 0); let first_elem = self.inner[self.offset]; @@ -73,6 +81,14 @@ impl Match { leftover, } } + + fn failed(leftover: Bvec) -> Self { + Match { + succeeded: false, + match_ends: 0, + leftover, + } + } } impl Eq for Match { @@ -87,6 +103,7 @@ impl Eq for Match { // impl From for str trait Regex { + // Perform a match without backtracking fn match(self, input: Bvec) -> Match; } @@ -239,9 +256,36 @@ impl Regex for Plus where T: Regex } } +// Repeated is to (,) as AnyOf is to Or +struct AnyOf { + inner: [T; N], +} + +impl Regex for AnyOf where T: Regex { + fn match(self, input: Bvec) -> Match { + let mut result = Match::failed(input); + for i in 0..M { + if !result.succeeded { + result = self.inner[i].match(result.leftover); + } + } + result + } +} + +fn reverse_array(input: [T; N]) -> [T; N] { + let mut output = [std::unsafe::zeroed(); N]; + for i in 0..N { + output[i] = input[N - (i + 1)]; + } + output +} fn main() { + assert_eq(reverse_array([1, 2, 3, 4]), [4, 3, 2, 1]); + + let mut xs: Bvec = Bvec::empty(); xs = xs.push(0); @@ -272,257 +316,288 @@ fn main() { len: 3, }); + let ys = Bvec::new([0, 1, 2]); + assert_eq(xs, ys); + + + // test that pop_front gives all contents, in order, + // followed by std::unsafe::zeroed() + println(xs); + let (x, new_xs) = xs.pop_front(); + assert_eq(x, 0); + + xs = new_xs; + println(xs); + let (x, new_xs) = xs.pop_front(); + assert_eq(x, 1); + + xs = new_xs; + println(xs); + let (x, new_xs) = xs.pop_front(); + assert_eq(x, 2); + + xs = new_xs; + println(xs); + if xs.len != 0 { + let (x, _new_xs) = xs.pop_front(); + assert_eq(x, std::unsafe::zeroed()); + } + + assert_eq(new_xs, Bvec { + inner: [0, 1, 2], + offset: 3, + len: 0, + }); + + + // gr(a|e)y + let graey_regex = ( + "gr", + ( + Or { + lhs: "a", + rhs: "e", + }, + "y" + ) + ); + + let result = graey_regex.match(Bvec::new("gray".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 4); + assert_eq(result.leftover.len, 0); + + let result = graey_regex.match(Bvec::new("grey".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 4); + assert_eq(result.leftover.len, 0); + + // colou?r + let colour_regex = ( + "colo", + ( + Question { + inner: "u", + }, + "r" + ) + ); + + let result = colour_regex.match(Bvec::new("color".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 5); + assert_eq(result.leftover.len, 0); + + let result = colour_regex.match(Bvec::new("colour".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 6); + assert_eq(result.leftover.len, 0); + + // parse the empty string three times + // EMPTY{3} + let three_empties_regex: Repeated<(), 3> = Repeated { + inner: (), + }; + + let result = three_empties_regex.match(Bvec::new("111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 0); + assert_eq(result.leftover.len, 3); + + // 1{0} + let zero_ones_regex: Repeated, 0> = Repeated { + inner: "1", + }; + + let result = zero_ones_regex.match(Bvec::new("111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 0); + assert_eq(result.leftover.len, 3); + + // 1{1} + let one_ones_regex: Repeated, 1> = Repeated { + inner: "1", + }; + + let result = one_ones_regex.match(Bvec::new("111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 1); + assert_eq(result.leftover.len, 2); + + // 1{2} + let two_ones_regex: Repeated, 2> = Repeated { + inner: "1", + }; + + let result = two_ones_regex.match(Bvec::new("111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 2); + assert_eq(result.leftover.len, 1); + + // 1{3} + let three_ones_regex: Repeated, 3> = Repeated { + inner: "1", + }; + + let result = three_ones_regex.match(Bvec::new("1111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 3); + assert_eq(result.leftover.len, 1); + + // 1* + let ones_regex: Star, 5> = Star { + inner: "1", + }; + + let result = ones_regex.match(Bvec::new("11000".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 2); + assert_eq(result.leftover.len, 3); + + + let result = ones_regex.match(Bvec::new("11".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 2); + assert_eq(result.leftover.len, 0); + + let result = ones_regex.match(Bvec::new("111111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 5); + assert_eq(result.leftover.len, 1); + + // 1+ + let nonempty_ones_regex: Plus, 5, 4> = Plus { + inner: "1", + }; + + let result = nonempty_ones_regex.match(Bvec::new("111111".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 5); + assert_eq(result.leftover.len, 1); + + // 2^n-1 in binary: 1+0 + let pred_pow_two_regex = ( + nonempty_ones_regex, + "0" + ); + + let result = pred_pow_two_regex.match(Bvec::new("1110".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 4); + assert_eq(result.leftover.len, 0); + + // (0|1)* + let binary_regex: Star, str<1>>, 5> = Star { + inner: Or { + lhs: "0", + rhs: "1", + } + }; - // TODO test push_front - - - // TODO - // - // // gr(a|e)y - // let graey_regex = ( - // "gr", - // ( - // Or { - // lhs: "a", - // rhs: "e", - // }, - // "y" - // ) - // ); - // - // // NOTE: leftover ignored in Eq: Match - // let result = graey_regex.match("gray".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 4, - // leftover: &[], - // }); - // - // - // // NOTE: leftover ignored in Eq: Match - // let result = graey_regex.match("grey".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 4, - // leftover: &[], - // }); - // - // // colou?r - // let colour_regex = ( - // "colo", - // ( - // Question { - // inner: "u", - // }, - // "r" - // ) - // ); - // - // let result = colour_regex.match("color".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 5, - // leftover: &[], - // }); - // - // let result = colour_regex.match("colour".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 6, - // leftover: &[], - // }); - // - // // parse the empty string three times - // // EMPTY{3} - // let three_empties_regex: Repeated<(), 3> = Repeated { - // inner: (), - // }; - // - // let result = three_empties_regex.match("111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 0, - // leftover: &[], - // }); - // - // // 1{0} - // let zero_ones_regex: Repeated, 0> = Repeated { - // inner: "1", - // }; - // - // let result = zero_ones_regex.match("111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 0, - // leftover: &[], - // }); - // - // // 1{1} - // let one_ones_regex: Repeated, 1> = Repeated { - // inner: "1", - // }; - // - // let result = one_ones_regex.match("111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 1, - // leftover: &[], - // }); - // - // // 1{2} - // let two_ones_regex: Repeated, 2> = Repeated { - // inner: "1", - // }; - // - // let result = two_ones_regex.match("111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 2, - // leftover: &[], - // }); - // - // // 1{3} - // let three_ones_regex: Repeated, 3> = Repeated { - // inner: "1", - // }; - // - // let result = three_ones_regex.match("1111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 3, - // leftover: &[], - // }); - // - // // 1* - // let ones_regex: Star, 5> = Star { - // inner: "1", - // }; - // - // let result = ones_regex.match("11000".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 2, - // leftover: &[], - // }); - // - // let result = ones_regex.match("11".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 2, - // leftover: &[], - // }); - // - // let result = ones_regex.match("111111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 5, - // leftover: &[], - // }); - // - // // 1+ - // let nonempty_ones_regex: Plus, 5, 4> = Plus { - // inner: "1", - // }; - // - // let result = nonempty_ones_regex.match("111111".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 5, - // leftover: &[], - // }); - // - // - // // 2^n-1 in binary: 1+0 - // let pred_pow_two_regex = ( - // nonempty_ones_regex, - // "0" - // ); - // - // let result = pred_pow_two_regex.match("1110".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 3, - // leftover: &[], - // }); - // - // - // // (0|1)* - // let binary_regex: Star, str<1>>, 5> = Star { - // inner: Or { - // lhs: "0", - // rhs: "1", - // } - // }; - // - // let result = binary_regex.match("110100".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 5, - // leftover: &[], - // }); - // - // // even numbers in binary: 1(0|1)*0 - // let even_binary_regex = ( - // "1", - // ( - // binary_regex, - // "0" - // ) - // ); - // - // let result = even_binary_regex.match("1111110".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 6, - // leftover: &[], - // }); - // - // // 2-letter capitalized words: [A-Z][a-z] - // - // // numbers: \d+ - // // [0-9]+ - // - // // words: \w+ - // // [a-Z]+ - // - // // adapted URL parser: (https?:\/\/)?([\da-z.\-]+)\.([a-z.]+)([\/\w \.\-]*)*\/? - // - // - // // // panics (at compile time) when input string is too short - // // let foo_regex = ( - // // "colo", - // // ( - // // Question { - // // inner: "u", - // // }, - // // "r" - // // ) - // // ); - // // - // // let result = foo_regex.match("colo".as_bytes().as_slice()); - // // println(result); - // // assert_eq(result, Match { - // // succeeded: true, - // // match_ends: 4, - // // leftover: &[], - // // }); - // + let result = binary_regex.match(Bvec::new("110100".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 5); + assert_eq(result.leftover.len, 1); + + // even numbers in binary: 1(0|1)*0 + let even_binary_regex = ( + "1", + ( + binary_regex, + "0" + ) + ); + + let result = even_binary_regex.match(Bvec::new("1111110".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 7); + assert_eq(result.leftover.len, 0); + + // digit: \d+ + // [0-9] + let digit_regex = AnyOf { + inner: [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ], + }; + + let result = digit_regex.match(Bvec::new("157196345823795".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 1); + assert_eq(result.leftover.len, 14); + + let result = digit_regex.match(Bvec::new("hi".as_bytes())); + println(result); + assert(!result.succeeded); + assert_eq(result.match_ends, 0); + assert_eq(result.leftover.len, 2); + + // digits: \d+ + // [0-9]+ + let digits_regex: Plus, 10>, 32, 31> = Plus { + inner: digit_regex, + }; + + let result = digits_regex.match(Bvec::new("123456789012345".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 15); + assert_eq(result.leftover.len, 0); + + let result = digits_regex.match(Bvec::new("123456789012345 then words".as_bytes())); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 15); + assert_eq(result.leftover.len, 11); + + // multiples of 10 + // apply to a reversed input string (because there isn't backtracking) + // 0\d+ + let backwards_mult_of_10_regex = ( + "0", + digits_regex + ); + + let result = backwards_mult_of_10_regex.match(Bvec::new(reverse_array("1230".as_bytes()))); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 4); + assert_eq(result.leftover.len, 0); + + let ten_pow_16: str<17> = "10000000000000000"; + let result = backwards_mult_of_10_regex.match(Bvec::new(reverse_array(ten_pow_16.as_bytes()))); + println(result); + assert(result.succeeded); + assert_eq(result.match_ends, 17); + assert_eq(result.leftover.len, 0); + + // adapted URL parser: (https?:\/\/)?([\da-c.\-]+)\.([a-c.]+)([\/\w \.\-]*)*\/? } From bd36dc56f4b6654ed215f9d7ab54edb26d247be2 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Fri, 12 Jul 2024 18:02:04 -0400 Subject: [PATCH 03/12] add handling for witness vs constant inputs, wip testing bigint's, add tests for to/from le bytes, add tests for commutative/associative/identity and/xor --- .../acvm/tests/solver.proptest-regressions | 8 + acvm-repo/acvm/tests/solver.rs | 338 +++++++++++++++--- 2 files changed, 291 insertions(+), 55 deletions(-) create mode 100644 acvm-repo/acvm/tests/solver.proptest-regressions diff --git a/acvm-repo/acvm/tests/solver.proptest-regressions b/acvm-repo/acvm/tests/solver.proptest-regressions new file mode 100644 index 00000000000..9fb0d963d57 --- /dev/null +++ b/acvm-repo/acvm/tests/solver.proptest-regressions @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc e4dd0e141df173f5dfdfb186bba4154247ec284b71d8f294fa3282da953a0e92 # shrinks to x = 0, y = 1 +cc 419ed6fdf1bf1f2513889c42ec86c665c9d0500ceb075cbbd07f72444dbd78c6 # shrinks to x = 266672725 diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index eaf8ad55370..c6e556e7e2d 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -16,8 +16,10 @@ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolution use acvm_blackbox_solver::StubbedBlackBoxSolver; use brillig_vm::brillig::HeapValueType; -use proptest::prelude::*; use proptest::arbitrary::any; +use proptest::prelude::*; +use proptest::result::maybe_ok; +use proptest::sample::select; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -728,13 +730,30 @@ fn memory_operations() { // Solve the given BlackBoxFuncCall with witnesses: 1, 2 as x, y, resp. #[cfg(test)] -fn solve_blackbox_func_call(blackbox_func_call: BlackBoxFuncCall, x: u128, y: u128) -> FieldElement { +fn solve_blackbox_func_call( + blackbox_func_call: impl Fn(Option, Option) -> BlackBoxFuncCall, + x: (FieldElement, bool), // if false, use a Witness + y: (FieldElement, bool), // if false, use a Witness +) -> FieldElement { + let (x, x_constant) = x; + let (y, y_constant) = y; + let initial_witness = WitnessMap::from(BTreeMap::from_iter([ - (Witness(1), FieldElement::from(x)), - (Witness(2), FieldElement::from(y)), + (Witness(1), x), + (Witness(2), y), ])); - let op = Opcode::BlackBoxFuncCall(blackbox_func_call); + let mut lhs = None; + if x_constant { + lhs = Some(x); + } + + let mut rhs = None; + if y_constant { + rhs = Some(y); + } + + let op = Opcode::BlackBoxFuncCall(blackbox_func_call(lhs, rhs)); let opcodes = vec![op]; let unconstrained_functions = vec![]; let mut acvm = @@ -747,6 +766,29 @@ fn solve_blackbox_func_call(blackbox_func_call: BlackBoxFuncCall, } +fn allowed_bigint_moduli() -> Vec> { + let bn254_fq: Vec = vec![0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; + let bn254_fr: Vec = vec![1, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]; + let secpk1_fr: Vec = vec![0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + let secpk1_fq: Vec = vec![0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + let secpr1_fq: Vec = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; + let secpr1_fr: Vec = vec![81, 37, 99, 252, 194, 202, 185, 243, 132, 158, 23, 167, 173, 250, 230, 188, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255]; + + vec![ + bn254_fq, + bn254_fr, + secpk1_fr, + secpk1_fq, + secpr1_fq, + secpr1_fr, + ] +} + + // TODO: cleanup new tests and rename this #[test] fn binary_operations() { @@ -767,90 +809,276 @@ fn binary_operations() { // // // unique calling convention // BlackBoxFuncCall::EmbeddedCurveAdd { .. } - // - // // - // BlackBoxFuncCall::AND { .. } - // BlackBoxFuncCall::XOR { .. } - // - // AND | XOR { - // lhs: FunctionInput, - // rhs: FunctionInput, - // output: Witness, - // }, - // // TODO: // - commutativity // - associativity - // - .. + // - left/right identity - let x = 1; - let y = 3; + // let x = FieldElement::from(1u128); + // let y = FieldElement::from(3u128); + + + + + let zero_constant = false; + let modulus = &allowed_bigint_moduli()[0]; + + let initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::zero()), + ])); + + let zero_function_input = if zero_constant { + FunctionInput::constant(FieldElement::zero(), FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(1), FieldElement::max_num_bits()) - let and_op = BlackBoxFuncCall::AND { - lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), - rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), - output: Witness(3), }; + let zero: Vec<_> = modulus.clone().into_iter().map(|_| zero_function_input).collect(); - assert_eq!(solve_blackbox_func_call(and_op.clone(), x, y), solve_blackbox_func_call(and_op, y, x)); + let bigint_from_op = BlackBoxFuncCall::BigIntFromLeBytes { + inputs: zero, + modulus: modulus.clone(), + output: 0, + }; + + // BigIntToLeBytes { + // input: u32, + // outputs: Vec, + // }, + + // let add_op = BlackBoxFuncCall::BigIntAdd { + // lhs: 0, + // rhs: 1, + // output: 2, + // }; + + let op = Opcode::BlackBoxFuncCall(bigint_from_op); + let opcodes = vec![op]; + let unconstrained_functions = vec![]; + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved); + let witness_map = acvm.finalize(); + + dbg!(witness_map[&Witness(1)]); + +} + +fn function_input_from_option(witness: Witness, opt_constant: Option) -> FunctionInput { + opt_constant + .map(|constant| FunctionInput::constant(constant, FieldElement::max_num_bits())) + .unwrap_or(FunctionInput::witness(witness, FieldElement::max_num_bits())) } -fn and_op() -> BlackBoxFuncCall { +fn and_op(x: Option, y: Option) -> BlackBoxFuncCall { + let lhs = function_input_from_option(Witness(1), x); + let rhs = function_input_from_option(Witness(2), y); BlackBoxFuncCall::AND { - lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), - rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), + lhs, + rhs, output: Witness(3), } } -fn xor_op() -> BlackBoxFuncCall { +fn xor_op(x: Option, y: Option) -> BlackBoxFuncCall { + let lhs = function_input_from_option(Witness(1), x); + let rhs = function_input_from_option(Witness(2), y); BlackBoxFuncCall::XOR { - lhs: FunctionInput::witness(Witness(1), FieldElement::max_num_bits()), - rhs: FunctionInput::witness(Witness(2), FieldElement::max_num_bits()), + lhs, + rhs, output: Witness(3), } } -fn prop_assert_eq(op: BlackBoxFuncCall, x: u128, y: u128) -> TestCaseResult { - let assertion: Result<_, TestCaseError> = prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); - assertion?; - Ok(()) + + +fn prop_assert_commutative( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + x: (FieldElement, bool), + y: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(&op, x, y), solve_blackbox_func_call(&op, y, x)) } +fn prop_assert_associative( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + x: (FieldElement, bool), + y: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(&op, x, y), solve_blackbox_func_call(&op, y, x)) +} + +fn prop_assert_identity_l( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + op_identity: (FieldElement, bool), + x: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(op, op_identity, x), x.0) +} + +fn prop_assert_identity_r( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + op_identity: (FieldElement, bool), + x: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(op, x, op_identity), x.0) +} + +prop_compose! { + // Use both `u128` and hex proptest strategies + fn field_element() + (u128_or_hex in maybe_ok(any::(), "[0-9a-f]{64}"), + constant_input in any::()) + -> (FieldElement, bool) + { + match u128_or_hex { + Ok(number) => (FieldElement::from(number), constant_input), + Err(hex) => (FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string"), constant_input), + } + } +} + +fn field_element_ones() -> FieldElement { + let exponent: FieldElement = (FieldElement::max_num_bits() as u128).into(); + FieldElement::from(2u128).pow(&exponent) - FieldElement::one() +} + +fn bigint_solve_from_to_le_bytes(modulus: Vec, zero_constant: bool) -> WitnessMap { + let initial_witness_vec: Vec<_> = (1..2 + modulus.len()) + .map(|i| (Witness(i as u32), FieldElement::zero())) + .collect(); + let output_witnesses: Vec<_> = initial_witness_vec + .iter() + .skip(1) + .map(|(witness, _)| *witness) + .collect(); + + let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); + let zero_function_input = if zero_constant { + FunctionInput::constant(FieldElement::zero(), FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(1), FieldElement::max_num_bits()) + + }; + let zero: Vec<_> = modulus.iter().map(|_| zero_function_input).collect(); + + let bigint_from_op = BlackBoxFuncCall::BigIntFromLeBytes { + inputs: zero, + modulus: modulus.clone(), + output: 0, + }; + let bigint_to_op = BlackBoxFuncCall::BigIntToLeBytes { + input: 0, + outputs: output_witnesses, + }; + + let bigint_from_op = Opcode::BlackBoxFuncCall(bigint_from_op); + let bigint_to_op = Opcode::BlackBoxFuncCall(bigint_to_op); + let opcodes = vec![bigint_from_op, bigint_to_op]; + let unconstrained_functions = vec![]; + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved); + let witness_map = acvm.finalize(); + + witness_map +} + + proptest! { #[test] - fn and_commutative(x in any::(), y in any::()) { - let op = and_op(); - prop_assert_commutes(op, x, y) + fn and_commutative(x in field_element(), y in field_element()) { + let (lhs, rhs) = prop_assert_commutative(and_op, x, y); + prop_assert_eq!(lhs, rhs); } #[test] - fn xor_commutative(x in any::(), y in any::()) { - let op = xor_op(); - prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); + fn xor_commutative(x in field_element(), y in field_element()) { + let (lhs, rhs) = prop_assert_commutative(xor_op, x, y); + prop_assert_eq!(lhs, rhs); } - // #[test] - // fn and_associative(x in any::(), y in any::()) { - // let op = and_op(); - // prop_assert_eq!(solve_blackbox_func_call(op.clone(), x, y), solve_blackbox_func_call(op, y, x)); - // } + #[test] + fn and_associative(x in field_element(), y in field_element()) { + let (lhs, rhs) = prop_assert_associative(and_op, x, y); + prop_assert_eq!(lhs, rhs); + } + #[test] + fn xor_associative(x in field_element(), y in field_element()) { + let (lhs, rhs) = prop_assert_associative(xor_op, x, y); + prop_assert_eq!(lhs, rhs); + } - // // This currently panics due to the fact that we allow inputs which are greater than the field modulus, - // // automatically reducing them to fit within the canonical range. - // #[test] - // #[should_panic(expected = "serialized field element is not equal to input")] - // fn recovers_original_hex_string(hex in "[0-9a-f]{64}") { - // let fe: FieldElement:: = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string"); - // let output_hex = fe.to_hex(); - // - // prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input"); - // } + #[test] + fn and_identity_l(x in field_element(), ones_constant in any::()) { + let ones = (field_element_ones(), ones_constant); + let (lhs, rhs) = prop_assert_identity_l(and_op, ones, x); + if x <= ones { + prop_assert_eq!(lhs, rhs); + } else { + // TODO + prop_assert!(lhs != rhs); + } + } + + #[test] + fn xor_identity_l(x in field_element(), zero_constant in any::()) { + let zero = (FieldElement::zero(), zero_constant); + let (lhs, rhs) = prop_assert_identity_l(xor_op, zero, x); + prop_assert_eq!(lhs, rhs); + } + + #[test] + fn and_identity_r(x in field_element(), ones_constant in any::()) { + let ones = (field_element_ones(), ones_constant); + let (lhs, rhs) = prop_assert_identity_r(and_op, ones, x); + if x <= ones { + prop_assert_eq!(lhs, rhs); + } else { + // TODO + prop_assert!(lhs != rhs); + } + } + + #[test] + fn xor_identity_r(x in field_element(), zero_constant in any::()) { + let zero = (FieldElement::zero(), zero_constant); + let (lhs, rhs) = prop_assert_identity_r(xor_op, zero, x); + prop_assert_eq!(lhs, rhs); + } + + #[test] + fn bigint_from_to_le_bytes(modulus in select(allowed_bigint_moduli()), zero_constant in any::()) { + let modulus_len = modulus.len(); + let witness_map = bigint_solve_from_to_le_bytes(modulus.clone(), zero_constant); + for i in 1..2 + modulus_len { + prop_assert_eq!(witness_map.get(&Witness(i as u32)).cloned(), Some(FieldElement::zero())); + } + } + + #[test] + // TODO: this test attempts to use a guaranteed-invalid BigInt modulus + #[should_panic(expected = "attempt to add with overflow")] + fn bigint_from_to_le_bytes_disallowed_modulus(modulus in select(allowed_bigint_moduli()), patch_location: usize, patch_amount: u8, zero_constant in any::()) { + let patch_location = patch_location % modulus.len(); + let patch_amount = patch_amount.clamp(1, u8::MAX); + + let mut modulus = modulus; + modulus[patch_location] += patch_amount; + let modulus_len = modulus.len(); + + let witness_map = bigint_solve_from_to_le_bytes(modulus, zero_constant); + for i in 1..2 + modulus_len { + prop_assert_eq!(witness_map.get(&Witness(i as u32)).cloned(), Some(FieldElement::zero())); + } + } } From 1ed070e3e7c1a1a75e1971f2ccfcb93c55d1b867 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 16 Jul 2024 12:12:01 -0400 Subject: [PATCH 04/12] add tests for zero l/r for AND, bigint generator/harness with a bunch of identity and zero tests --- .../acvm/tests/solver.proptest-regressions | 1 + acvm-repo/acvm/tests/solver.rs | 326 ++++++++++++++++-- 2 files changed, 297 insertions(+), 30 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.proptest-regressions b/acvm-repo/acvm/tests/solver.proptest-regressions index 9fb0d963d57..6b8f31a6c6c 100644 --- a/acvm-repo/acvm/tests/solver.proptest-regressions +++ b/acvm-repo/acvm/tests/solver.proptest-regressions @@ -6,3 +6,4 @@ # everyone who runs the test benefits from these saved cases. cc e4dd0e141df173f5dfdfb186bba4154247ec284b71d8f294fa3282da953a0e92 # shrinks to x = 0, y = 1 cc 419ed6fdf1bf1f2513889c42ec86c665c9d0500ceb075cbbd07f72444dbd78c6 # shrinks to x = 266672725 +cc 0810fc9e126b56cf0a0ddb25e0dc498fa3b2f1980951550403479fc01c209833 # shrinks to modulus = [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48], zero_or_ones_constant = false, use_constant = false diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index c6e556e7e2d..8f706785ed8 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -819,8 +819,6 @@ fn binary_operations() { // let y = FieldElement::from(3u128); - - let zero_constant = false; let modulus = &allowed_bigint_moduli()[0]; @@ -927,6 +925,22 @@ fn prop_assert_identity_r( (solve_blackbox_func_call(op, x, op_identity), x.0) } +fn prop_assert_zero_l( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + op_zero: (FieldElement, bool), + x: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(op, op_zero, x), FieldElement::zero()) +} + +fn prop_assert_zero_r( + op: impl Fn(Option, Option) -> BlackBoxFuncCall, + op_zero: (FieldElement, bool), + x: (FieldElement, bool), +) -> (FieldElement, FieldElement) { + (solve_blackbox_func_call(op, x, op_zero), FieldElement::zero()) +} + prop_compose! { // Use both `u128` and hex proptest strategies fn field_element() @@ -941,38 +955,59 @@ prop_compose! { } } +prop_compose! { + fn bigint_with_modulus()(modulus in select(allowed_bigint_moduli())) + (input in proptest::collection::vec(any::<(u8, bool)>(), modulus.len()), modulus in Just(modulus)) + -> (Vec<(FieldElement, bool)>, Vec) { + let input = input.into_iter().map(|(x, use_constant)| { + (FieldElement::from(x as u128), use_constant) + }).collect(); + (input, modulus) + } +} + +prop_compose! { + fn bigint_pair_with_modulus()(input_modulus in bigint_with_modulus()) + (ys in proptest::collection::vec(any::<(u8, bool)>(), input_modulus.1.len()), input_modulus in Just(input_modulus)) + -> (Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec) { + let ys = ys.into_iter().map(|(x, use_constant)| { + (FieldElement::from(x as u128), use_constant) + }).collect(); + (input_modulus.0, ys, input_modulus.1) + } +} + fn field_element_ones() -> FieldElement { let exponent: FieldElement = (FieldElement::max_num_bits() as u128).into(); FieldElement::from(2u128).pow(&exponent) - FieldElement::one() } -fn bigint_solve_from_to_le_bytes(modulus: Vec, zero_constant: bool) -> WitnessMap { - let initial_witness_vec: Vec<_> = (1..2 + modulus.len()) - .map(|i| (Witness(i as u32), FieldElement::zero())) - .collect(); +fn bigint_solve_from_to_le_bytes(modulus: Vec, input: Vec<(FieldElement, bool)>) -> Vec { + let initial_witness_vec: Vec<_> = input.iter().enumerate().map(|(i, (x, _))| { + (Witness(i as u32), x.clone()) + }).collect(); let output_witnesses: Vec<_> = initial_witness_vec .iter() - .skip(1) .map(|(witness, _)| *witness) .collect(); let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); - let zero_function_input = if zero_constant { - FunctionInput::constant(FieldElement::zero(), FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness(1), FieldElement::max_num_bits()) - - }; - let zero: Vec<_> = modulus.iter().map(|_| zero_function_input).collect(); + let input: Vec<_> = input.into_iter().enumerate().map(|(i, (x, use_constant))| { + if use_constant { + FunctionInput::constant(x, FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) + } + }).collect(); let bigint_from_op = BlackBoxFuncCall::BigIntFromLeBytes { - inputs: zero, + inputs: input, modulus: modulus.clone(), output: 0, }; let bigint_to_op = BlackBoxFuncCall::BigIntToLeBytes { input: 0, - outputs: output_witnesses, + outputs: output_witnesses.clone(), }; let bigint_from_op = Opcode::BlackBoxFuncCall(bigint_from_op); @@ -985,7 +1020,71 @@ fn bigint_solve_from_to_le_bytes(modulus: Vec, zero_constant: bool) -> Witne assert_eq!(solver_status, ACVMStatus::Solved); let witness_map = acvm.finalize(); - witness_map + // TODO: remove clone? + output_witnesses.iter().map(|witness| { + witness_map.get(witness).expect("all witnesses to be set").clone() + }).collect() +} + + +fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Vec, xs: Vec<(FieldElement, bool)>, ys: Vec<(FieldElement, bool)>) -> Vec { + let initial_witness_vec: Vec<_> = xs.iter().chain(ys.iter()).enumerate().map(|(i, (x, _))| { + (Witness(i as u32), x.clone()) + }).collect(); + let output_witnesses: Vec<_> = initial_witness_vec + .iter() + .take(xs.len()) + .map(|(witness, _)| *witness) + .collect(); + let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); + + let xs: Vec<_> = xs.into_iter().enumerate().map(|(i, (x, use_constant))| { + if use_constant { + FunctionInput::constant(x, FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) + } + }).collect(); + let ys: Vec<_> = ys.into_iter().enumerate().map(|(i, (x, use_constant))| { + if use_constant { + FunctionInput::constant(x, FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) + } + }).collect(); + + let bigint_from_x_op = BlackBoxFuncCall::BigIntFromLeBytes { + inputs: xs, + modulus: modulus.clone(), + output: 0, + }; + let bigint_from_y_op = BlackBoxFuncCall::BigIntFromLeBytes { + inputs: ys, + modulus: modulus.clone(), + output: 1, + }; + let bigint_to_op = BlackBoxFuncCall::BigIntToLeBytes { + input: 2, + outputs: output_witnesses.clone(), + }; + + let bigint_from_x_op = Opcode::BlackBoxFuncCall(bigint_from_x_op); + let bigint_from_y_op = Opcode::BlackBoxFuncCall(bigint_from_y_op); + + let middle_op = Opcode::BlackBoxFuncCall(middle_op); + let bigint_to_op = Opcode::BlackBoxFuncCall(bigint_to_op); + let opcodes = vec![bigint_from_x_op, bigint_from_y_op, middle_op, bigint_to_op]; + let unconstrained_functions = vec![]; + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved); + let witness_map = acvm.finalize(); + + // TODO: remove clone? + output_witnesses.iter().map(|witness| { + witness_map.get(witness).expect("all witnesses to be set").clone() + }).collect() } @@ -1016,7 +1115,9 @@ proptest! { prop_assert_eq!(lhs, rhs); } + // TODO bug #[test] + #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] fn and_identity_l(x in field_element(), ones_constant in any::()) { let ones = (field_element_ones(), ones_constant); let (lhs, rhs) = prop_assert_identity_l(and_op, ones, x); @@ -1035,7 +1136,9 @@ proptest! { prop_assert_eq!(lhs, rhs); } + // TODO bug #[test] + #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] fn and_identity_r(x in field_element(), ones_constant in any::()) { let ones = (field_element_ones(), ones_constant); let (lhs, rhs) = prop_assert_identity_r(and_op, ones, x); @@ -1055,29 +1158,192 @@ proptest! { } #[test] - fn bigint_from_to_le_bytes(modulus in select(allowed_bigint_moduli()), zero_constant in any::()) { - let modulus_len = modulus.len(); - let witness_map = bigint_solve_from_to_le_bytes(modulus.clone(), zero_constant); - for i in 1..2 + modulus_len { - prop_assert_eq!(witness_map.get(&Witness(i as u32)).cloned(), Some(FieldElement::zero())); - } + fn and_zero_l(x in field_element(), ones_constant in any::()) { + let zero = (FieldElement::zero(), ones_constant); + let (lhs, rhs) = prop_assert_zero_l(and_op, zero, x); + prop_assert_eq!(lhs, rhs); + } + + #[test] + fn and_zero_r(x in field_element(), ones_constant in any::()) { + let zero = (FieldElement::zero(), ones_constant); + let (lhs, rhs) = prop_assert_zero_r(and_op, zero, x); + prop_assert_eq!(lhs, rhs); + } + + #[test] + fn bigint_from_to_le_bytes_zero_one(modulus in select(allowed_bigint_moduli()), zero_or_ones_constant in any::(), use_constant in any::()) { + let zero_function_input = if zero_or_ones_constant { + FieldElement::one() + } else { + FieldElement::zero() + }; + let zero_or_ones: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); + let expected_results: Vec<_> = zero_or_ones.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero_or_ones); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_from_to_le_bytes((input, modulus) in bigint_with_modulus()) { + let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); + prop_assert_eq!(results, expected_results) + } + + #[test] + // TODO: desired behavior? + fn bigint_from_to_le_bytes_extra_input_byte((input, modulus) in bigint_with_modulus(), extra_byte in any::(), use_constant in any::()) { + let mut input = input; + input.push((FieldElement::from(extra_byte as u128), use_constant)); + let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); + prop_assert_eq!(results, expected_results) + } + + #[test] + // TODO: desired behavior? + fn bigint_from_to_le_bytes_two_extra_input_bytes((input, modulus) in bigint_with_modulus(), extra_byte in any::(), extra_byte_2 in any::(), use_constant in any::(), use_constant_2 in any::()) { + let mut input = input; + input.push((FieldElement::from(extra_byte as u128), use_constant)); + input.push((FieldElement::from(extra_byte_2 as u128), use_constant_2)); + let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); + prop_assert_eq!(results, expected_results) + } + + #[test] + // TODO: desired behavior? + fn bigint_from_to_le_bytes_extra_input_bytes((input, modulus) in bigint_with_modulus(), extra_bytes_len in any::(), extra_bytes in proptest::collection::vec(any::<(u8, bool)>(), u8::MAX as usize)) { + let mut input = input; + let mut extra_bytes: Vec<_> = extra_bytes.into_iter().take(extra_bytes_len as usize).map(|(x, use_constant)| (FieldElement::from(x as u128), use_constant)).collect(); + input.append(&mut extra_bytes); + let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); + prop_assert_eq!(results, expected_results) + } + + #[test] + // TODO: desired behavior? + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_from_to_le_bytes_bigger_than_u8((input, modulus) in bigint_with_modulus(), patch_location in any::(), larger_value in any::(), use_constant in any::()) { + let mut input = input; + let patch_location = patch_location % input.len(); + let larger_value = FieldElement::from(std::cmp::max((u8::MAX as u16) + 1, larger_value) as u128); + input[patch_location] = (larger_value, use_constant); + let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); + prop_assert_eq!(results, expected_results) } #[test] // TODO: this test attempts to use a guaranteed-invalid BigInt modulus #[should_panic(expected = "attempt to add with overflow")] - fn bigint_from_to_le_bytes_disallowed_modulus(modulus in select(allowed_bigint_moduli()), patch_location: usize, patch_amount: u8, zero_constant in any::()) { + fn bigint_from_to_le_bytes_disallowed_modulus(modulus in select(allowed_bigint_moduli()), patch_location in any::(), patch_amount in any::(), zero_or_ones_constant in any::(), use_constant in any::()) { let patch_location = patch_location % modulus.len(); let patch_amount = patch_amount.clamp(1, u8::MAX); - let mut modulus = modulus; modulus[patch_location] += patch_amount; - let modulus_len = modulus.len(); - let witness_map = bigint_solve_from_to_le_bytes(modulus, zero_constant); - for i in 1..2 + modulus_len { - prop_assert_eq!(witness_map.get(&Witness(i as u32)).cloned(), Some(FieldElement::zero())); - } + let zero_function_input = if zero_or_ones_constant { + FieldElement::zero() + } else { + FieldElement::one() + }; + let zero: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); + let expected_results: Vec<_> = zero.iter().map(|x| x.0).collect(); + let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero); + + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_add_zero_l((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, zero, xs); + + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_add_zero_r((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, zero); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_mul_zero_l((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let results = bigint_solve_binary_op(op, modulus, zero, xs); + let expected_results: Vec<_> = results.iter().map(|_| FieldElement::zero()).collect(); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_mul_zero_r((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, zero); + let expected_results: Vec<_> = results.iter().map(|_| FieldElement::zero()).collect(); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_mul_one_l((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + // little-endian + one[0] = (FieldElement::one(), one[0].1); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, one, xs); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_mul_one_r((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + // little-endian + one[0] = (FieldElement::one(), one[0].1); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, one); + prop_assert_eq!(results, expected_results) } } From 6db5c25cf6856a0bbbba26baccd2e7f3fa2de2e0 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 18 Jul 2024 14:56:19 -0400 Subject: [PATCH 05/12] add noir test program for too-large bigint, add method to generate triple of bigint's, fix bug in bigint_solve_binary_op, add commutative/associative/identity/zero/inverse/distributive tests for bigint's --- .../acvm/tests/solver.proptest-regressions | 4 + acvm-repo/acvm/tests/solver.rs | 441 ++++++++++++++---- .../bigint_from_too_many_le_bytes/Nargo.toml | 7 + .../bigint_from_too_many_le_bytes/src/main.nr | 22 + 4 files changed, 391 insertions(+), 83 deletions(-) create mode 100644 test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml create mode 100644 test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr diff --git a/acvm-repo/acvm/tests/solver.proptest-regressions b/acvm-repo/acvm/tests/solver.proptest-regressions index 6b8f31a6c6c..35627c1fbae 100644 --- a/acvm-repo/acvm/tests/solver.proptest-regressions +++ b/acvm-repo/acvm/tests/solver.proptest-regressions @@ -7,3 +7,7 @@ cc e4dd0e141df173f5dfdfb186bba4154247ec284b71d8f294fa3282da953a0e92 # shrinks to x = 0, y = 1 cc 419ed6fdf1bf1f2513889c42ec86c665c9d0500ceb075cbbd07f72444dbd78c6 # shrinks to x = 266672725 cc 0810fc9e126b56cf0a0ddb25e0dc498fa3b2f1980951550403479fc01c209833 # shrinks to modulus = [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48], zero_or_ones_constant = false, use_constant = false +cc 735ee9beb1a1dbb82ded6f30e544d7dfde149957e5d45a8c96fc65a690b6b71c # shrinks to (xs, modulus) = ([(0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (49, false)], [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]) +cc ca81bc11114a2a2b34021f44ecc1e10cb018e35021ef4d728e07a6791dad38d6 # shrinks to (xs, modulus) = ([(0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (49, false)], [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]) +cc 6c1d571a0111e6b4c244dc16da122ebab361e77b71db7770d638076ab21a717b # shrinks to (xs, modulus) = ([(0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (49, false)], [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]) +cc ccb7061ab6b85e2554d00bf03d74204977ed7a4109d7e2d5c6b5aaa2179cfaf9 # shrinks to (xs, modulus) = ([(0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (49, false)], [71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 8f706785ed8..c1e0aec2d77 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -788,83 +788,6 @@ fn allowed_bigint_moduli() -> Vec> { ] } - -// TODO: cleanup new tests and rename this -#[test] -fn binary_operations() { - - // // special cases - // BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub, - // BlackBoxFuncCall::BigIntDiv { .. } - // - // // BigInt: - // // - // // pub struct BigIntSolver { - // // bigint_id_to_value: HashMap, - // // bigint_id_to_modulus: HashMap, - // // } - // // - // BlackBoxFuncCall::BigIntAdd { .. } - // BlackBoxFuncCall::BigIntMul { .. } - // - // // unique calling convention - // BlackBoxFuncCall::EmbeddedCurveAdd { .. } - - // TODO: - // - commutativity - // - associativity - // - left/right identity - - // let x = FieldElement::from(1u128); - // let y = FieldElement::from(3u128); - - - let zero_constant = false; - let modulus = &allowed_bigint_moduli()[0]; - - let initial_witness = WitnessMap::from(BTreeMap::from_iter([ - (Witness(1), FieldElement::zero()), - ])); - - let zero_function_input = if zero_constant { - FunctionInput::constant(FieldElement::zero(), FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness(1), FieldElement::max_num_bits()) - - }; - let zero: Vec<_> = modulus.clone().into_iter().map(|_| zero_function_input).collect(); - - let bigint_from_op = BlackBoxFuncCall::BigIntFromLeBytes { - inputs: zero, - modulus: modulus.clone(), - output: 0, - }; - - // BigIntToLeBytes { - // input: u32, - // outputs: Vec, - // }, - - // let add_op = BlackBoxFuncCall::BigIntAdd { - // lhs: 0, - // rhs: 1, - // output: 2, - // }; - - let op = Opcode::BlackBoxFuncCall(bigint_from_op); - let opcodes = vec![op]; - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); - let solver_status = acvm.solve(); - assert_eq!(solver_status, ACVMStatus::Solved); - let witness_map = acvm.finalize(); - - dbg!(witness_map[&Witness(1)]); - - -} - fn function_input_from_option(witness: Witness, opt_constant: Option) -> FunctionInput { opt_constant .map(|constant| FunctionInput::constant(constant, FieldElement::max_num_bits())) @@ -891,8 +814,6 @@ fn xor_op(x: Option, y: Option) -> BlackBoxFuncCall< } } - - fn prop_assert_commutative( op: impl Fn(Option, Option) -> BlackBoxFuncCall, x: (FieldElement, bool), @@ -977,6 +898,17 @@ prop_compose! { } } +prop_compose! { + fn bigint_triple_with_modulus()(xs_ys_modulus in bigint_pair_with_modulus()) + (zs in proptest::collection::vec(any::<(u8, bool)>(), xs_ys_modulus.2.len()), xs_ys_modulus in Just(xs_ys_modulus)) + -> (Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec) { + let zs = zs.into_iter().map(|(x, use_constant)| { + (FieldElement::from(x as u128), use_constant) + }).collect(); + (xs_ys_modulus.0, xs_ys_modulus.1, zs, xs_ys_modulus.2) + } +} + fn field_element_ones() -> FieldElement { let exponent: FieldElement = (FieldElement::max_num_bits() as u128).into(); FieldElement::from(2u128).pow(&exponent) - FieldElement::one() @@ -1026,7 +958,6 @@ fn bigint_solve_from_to_le_bytes(modulus: Vec, input: Vec<(FieldElement, boo }).collect() } - fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Vec, xs: Vec<(FieldElement, bool)>, ys: Vec<(FieldElement, bool)>) -> Vec { let initial_witness_vec: Vec<_> = xs.iter().chain(ys.iter()).enumerate().map(|(i, (x, _))| { (Witness(i as u32), x.clone()) @@ -1034,7 +965,8 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve let output_witnesses: Vec<_> = initial_witness_vec .iter() .take(xs.len()) - .map(|(witness, _)| *witness) + .enumerate() + .map(|(i, _)| Witness((i + 2 * xs.len()) as u32)) .collect(); let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); @@ -1049,7 +981,7 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve if use_constant { FunctionInput::constant(x, FieldElement::max_num_bits()) } else { - FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) + FunctionInput::witness(Witness((i + xs.len()) as u32), FieldElement::max_num_bits()) } }).collect(); @@ -1077,6 +1009,7 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve let unconstrained_functions = vec![]; let mut acvm = ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); + let solver_status = acvm.solve(); assert_eq!(solver_status, ACVMStatus::Solved); let witness_map = acvm.finalize(); @@ -1088,7 +1021,9 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve } - +// NOTE: an "average" bigint is large, so consider increasing the number of proptest shrinking +// iterations (from the default 1024) to reach a simplified case: +// PROPTEST_MAX_SHRINK_ITERS=1024000 proptest! { #[test] @@ -1258,6 +1193,116 @@ proptest! { } #[test] + fn bigint_add_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { + let op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + + let lhs_results = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let rhs_results = bigint_solve_binary_op(op, modulus, ys, xs); + + prop_assert_eq!(lhs_results, rhs_results) + } + + #[test] + fn bigint_mul_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let lhs_results = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let rhs_results = bigint_solve_binary_op(op, modulus, ys, xs); + + prop_assert_eq!(lhs_results, rhs_results) + } + + #[test] + fn bigint_add_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { + let op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + + // f(f(xs, ys), zs) == + let op_xs_ys = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); + let op_xs_ys_op_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), xs_ys, zs.clone()); + + // f(xs, f(ys, zs)) + let op_ys_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); + let op_xs_op_ys_zs = bigint_solve_binary_op(op, modulus, xs, ys_zs); + + prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) + } + + #[test] + fn bigint_mul_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { + let op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + // f(f(xs, ys), zs) == + let op_xs_ys = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); + let op_xs_ys_op_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), xs_ys, zs.clone()); + + // f(xs, f(ys, zs)) + let op_ys_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); + let op_xs_op_ys_zs = bigint_solve_binary_op(op, modulus, xs, ys_zs); + + prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) + } + + // TODO + // + // minimal failing input: (xs, ys, zs, modulus) = ( + // [ (0, false), (0, false), (158, true), (171, true), (134, false), (0, true), (37, true), (5, false), (241, true), (103, false), (20, false), (139, true), (227, false), (7, true), (9, true), (190, true), (220, false), (1, false), (43, true), (147, true), (235, true), (70, false), (146, true), (26, true), (211, true), (234, true), (54, false), (7, true), (97, false), (50, false), (228, true), (6, true)], + // [ (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (7, false), (125, true), (213, false), (40, true), (66, false), (34, true), (102, true), (87, true), (87, true), (166, false), (39, false), (60, true), (179, true), (162, false), (194, false), (235, true), ], + // [ (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (1, true), (186, true), (43, false), (167, false), (178, false), (161, true), (70, false), (2⁴×14, false), (129, false), (177, true), (129, true), (2⁴×9, false), (76, true), (104, true), (222, false), (107, true), (197, true), (186, true), (57, true), (251, false), (159, false), ], + // [ 65, 65, 54, 208, 140, 94, 210, 191, 59, 160, 72, 175, 230, 220, 174, 186, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] + // ) + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_mul_add_distributive((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { + let add_op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + let mul_op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + // xs * (ys + zs) == + let add_ys_zs = bigint_solve_binary_op(add_op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let add_ys_zs: Vec<_> = add_ys_zs.into_iter().map(|x| (x, false)).collect(); + let mul_xs_add_ys_zs = bigint_solve_binary_op(mul_op.clone(), modulus.clone(), xs.clone(), add_ys_zs); + + // xs * ys + xs * zs + let mul_xs_ys = bigint_solve_binary_op(mul_op.clone(), modulus.clone(), xs.clone(), ys); + let mul_xs_ys: Vec<_> = mul_xs_ys.into_iter().map(|x| (x, false)).collect(); + let mul_xs_zs = bigint_solve_binary_op(mul_op, modulus.clone(), xs, zs); + let mul_xs_zs: Vec<_> = mul_xs_zs.into_iter().map(|x| (x, false)).collect(); + let add_mul_xs_ys_mul_xs_zs = bigint_solve_binary_op(add_op, modulus, mul_xs_ys, mul_xs_zs); + + prop_assert_eq!(mul_xs_add_ys_zs, add_mul_xs_ys_mul_xs_zs) + } + + + // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_add_zero_l((xs, modulus) in bigint_with_modulus()) { let op = BlackBoxFuncCall::BigIntAdd { lhs: 0, @@ -1272,7 +1317,9 @@ proptest! { prop_assert_eq!(results, expected_results) } + // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_add_zero_r((xs, modulus) in bigint_with_modulus()) { let op = BlackBoxFuncCall::BigIntAdd { lhs: 0, @@ -1314,7 +1361,9 @@ proptest! { prop_assert_eq!(results, expected_results) } + // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_one_l((xs, modulus) in bigint_with_modulus()) { let op = BlackBoxFuncCall::BigIntMul { lhs: 0, @@ -1330,7 +1379,9 @@ proptest! { prop_assert_eq!(results, expected_results) } + // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_one_r((xs, modulus) in bigint_with_modulus()) { let op = BlackBoxFuncCall::BigIntMul { lhs: 0, @@ -1341,11 +1392,235 @@ proptest! { let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); // little-endian one[0] = (FieldElement::one(), one[0].1); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); let results = bigint_solve_binary_op(op, modulus, xs, one); prop_assert_eq!(results, expected_results) } + #[test] + fn bigint_sub_self((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntSub { + lhs: 0, + rhs: 1, + output: 2, + }; + + let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); + let results = bigint_solve_binary_op(op, modulus, xs.clone(), xs); + prop_assert_eq!(results, expected_results) + } + + // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_sub_zero((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntSub { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, zero); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_sub_one((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntSub { + lhs: 0, + rhs: 1, + output: 2, + }; + + let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + // little-endian + one[0] = (FieldElement::one(), one[0].1); + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, one); + prop_assert!(results != expected_results, "{:?} == {:?}", results, expected_results) + } + + #[test] + fn bigint_div_self((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + + let mut one: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); + // little-endian + one[0] = FieldElement::one(); + + let results = bigint_solve_binary_op(op, modulus, xs.clone(), xs); + prop_assert_eq!(results, one) + } + + // TODO? + #[test] + fn bigint_div_by_zero((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, zero); + prop_assert_eq!(results, expected_results) + } + + // Fails on 49, see bigint_add_zero_l_single_case_49 + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_div_one((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + + let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + // little-endian + one[0] = (FieldElement::one(), one[0].1); + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus, xs, one); + prop_assert_eq!(results, expected_results) + } + + #[test] + fn bigint_div_zero((xs, modulus) in bigint_with_modulus()) { + let op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); + let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); + let results = bigint_solve_binary_op(op, modulus, zero, xs); + prop_assert_eq!(results, expected_results) + } + + // TODO: fails on (x=0, y=97) + #[test] + #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] + fn bigint_add_sub((xs, ys, modulus) in bigint_pair_with_modulus()) { + let add_op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + let sub_op = BlackBoxFuncCall::BigIntSub { + lhs: 0, + rhs: 1, + output: 2, + }; + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let add_results = bigint_solve_binary_op(add_op, modulus.clone(), xs, ys.clone()); + let add_bigint: Vec<_> = add_results.into_iter().map(|x| (x, false)).collect(); + let results = bigint_solve_binary_op(sub_op, modulus, add_bigint, ys); + + prop_assert_eq!(results, expected_results) + } + + #[test] + #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] + fn bigint_sub_add((xs, ys, modulus) in bigint_pair_with_modulus()) { + let add_op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + let sub_op = BlackBoxFuncCall::BigIntSub { + lhs: 0, + rhs: 1, + output: 2, + }; + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let sub_results = bigint_solve_binary_op(sub_op, modulus.clone(), xs, ys.clone()); + let add_bigint: Vec<_> = sub_results.into_iter().map(|x| (x, false)).collect(); + let results = bigint_solve_binary_op(add_op, modulus, add_bigint, ys); + + prop_assert_eq!(results, expected_results) + } + + // Fails on 49, see bigint_add_zero_l_single_case_49 + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_div_mul((xs, ys, modulus) in bigint_pair_with_modulus()) { + let div_op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + let mul_op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let div_results = bigint_solve_binary_op(div_op, modulus.clone(), xs, ys.clone()); + let div_bigint: Vec<_> = div_results.into_iter().map(|x| (x, false)).collect(); + let results = bigint_solve_binary_op(mul_op, modulus, div_bigint, ys); + + prop_assert_eq!(results, expected_results) + } + + // Fails on 49, see bigint_add_zero_l_single_case_49 + #[test] + #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] + fn bigint_mul_div((xs, ys, modulus) in bigint_pair_with_modulus()) { + let div_op = BlackBoxFuncCall::BigIntDiv { + lhs: 0, + rhs: 1, + output: 2, + }; + let mul_op = BlackBoxFuncCall::BigIntMul { + lhs: 0, + rhs: 1, + output: 2, + }; + + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let mul_results = bigint_solve_binary_op(mul_op, modulus.clone(), xs, ys.clone()); + let mul_bigint: Vec<_> = mul_results.into_iter().map(|x| (x, false)).collect(); + let results = bigint_solve_binary_op(div_op, modulus, mul_bigint, ys); + + prop_assert_eq!(results, expected_results) + } + } +// TODO: this test is redundant with bigint_add_zero_l, +// but may be useful for debugging. It can be removed once bigint_add_zero_l is +// passing because proptest automatically retries previous failures first. +#[test] +#[should_panic(expected = "assertion `left == right` failed")] +fn bigint_add_zero_l_single_case_49() { + let modulus = &allowed_bigint_moduli()[0]; + let mut xs: Vec<_> = modulus.iter().map(|_| (FieldElement::zero(), false)).collect(); + xs[modulus.len() - 1] = (FieldElement::from(49u128), false); + + let op = BlackBoxFuncCall::BigIntAdd { + lhs: 0, + rhs: 1, + output: 2, + }; + + let zero: Vec<_> = xs.iter().map(|(_, _use_constant)| (FieldElement::zero(), false)).collect(); + let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); + let results = bigint_solve_binary_op(op, modulus.clone(), zero, xs); + + assert_eq!(results, expected_results) +} diff --git a/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml b/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml new file mode 100644 index 00000000000..cbdfc2d83d9 --- /dev/null +++ b/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bigint_from_too_many_le_bytes" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr b/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr new file mode 100644 index 00000000000..8b29cdeec01 --- /dev/null +++ b/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr @@ -0,0 +1,22 @@ +use std::bigint::{bn254_fq, BigInt}; + +// TODO: make issue for this to fail at compile time and then move to compile_failure +// +// Fails at runtime: +// +// error: Assertion failed: 'Index out of bounds' +// ┌─ std/cmp.nr:35:34 +// │ +// 35 │ result &= self[i].eq(other[i]); +// │ -------- +// │ +// = Call stack: +// 1. /Users/michaelklein/Coding/rust/noir/test_programs/compile_failure/bigint_from_too_many_le_bytes/src/main.nr:7:12 +// 2. std/cmp.nr:35:34 +// Failed assertion +fn main() { + let bytes: [u8] = bn254_fq.push_front(0x00); + let bigint = BigInt::from_le_bytes(bytes, bn254_fq); + let result_bytes = bigint.to_le_bytes(); + assert(bytes == result_bytes.as_slice()); +} From 822f6a9d0503b6702716b6c5fbacea822996d29a Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 18 Jul 2024 15:34:41 -0400 Subject: [PATCH 06/12] cargo fmt, factor out opcode and input setup functions --- acvm-repo/acvm/tests/solver.rs | 596 ++++++++++++--------------------- 1 file changed, 218 insertions(+), 378 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index c1e0aec2d77..573ff8e65db 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -731,17 +731,17 @@ fn memory_operations() { // Solve the given BlackBoxFuncCall with witnesses: 1, 2 as x, y, resp. #[cfg(test)] fn solve_blackbox_func_call( - blackbox_func_call: impl Fn(Option, Option) -> BlackBoxFuncCall, + blackbox_func_call: impl Fn( + Option, + Option, + ) -> BlackBoxFuncCall, x: (FieldElement, bool), // if false, use a Witness y: (FieldElement, bool), // if false, use a Witness ) -> FieldElement { let (x, x_constant) = x; let (y, y_constant) = y; - let initial_witness = WitnessMap::from(BTreeMap::from_iter([ - (Witness(1), x), - (Witness(2), y), - ])); + let initial_witness = WitnessMap::from(BTreeMap::from_iter([(Witness(1), x), (Witness(2), y)])); let mut lhs = None; if x_constant { @@ -765,30 +765,43 @@ fn solve_blackbox_func_call( witness_map[&Witness(3)] } - fn allowed_bigint_moduli() -> Vec> { - let bn254_fq: Vec = vec![0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, - 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; - let bn254_fr: Vec = vec![1, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]; - let secpk1_fr: Vec = vec![0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; - let secpk1_fq: Vec = vec![0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; - let secpr1_fq: Vec = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; - let secpr1_fr: Vec = vec![81, 37, 99, 252, 194, 202, 185, 243, 132, 158, 23, 167, 173, 250, 230, 188, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255]; - - vec![ - bn254_fq, - bn254_fr, - secpk1_fr, - secpk1_fq, - secpr1_fq, - secpr1_fr, - ] + let bn254_fq: Vec = vec![ + 0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, + 0x97, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, + 0x64, 0x30, + ]; + let bn254_fr: Vec = vec![ + 1, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, + 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48, + ]; + let secpk1_fr: Vec = vec![ + 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, + 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, + ]; + let secpk1_fq: Vec = vec![ + 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, + ]; + let secpr1_fq: Vec = vec![ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, + ]; + let secpr1_fr: Vec = vec![ + 81, 37, 99, 252, 194, 202, 185, 243, 132, 158, 23, 167, 173, 250, 230, 188, 255, 255, 255, + 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, + ]; + + vec![bn254_fq, bn254_fr, secpk1_fr, secpk1_fq, secpr1_fq, secpr1_fr] } -fn function_input_from_option(witness: Witness, opt_constant: Option) -> FunctionInput { +fn function_input_from_option( + witness: Witness, + opt_constant: Option, +) -> FunctionInput { opt_constant .map(|constant| FunctionInput::constant(constant, FieldElement::max_num_bits())) .unwrap_or(FunctionInput::witness(witness, FieldElement::max_num_bits())) @@ -797,21 +810,13 @@ fn function_input_from_option(witness: Witness, opt_constant: Option, y: Option) -> BlackBoxFuncCall { let lhs = function_input_from_option(Witness(1), x); let rhs = function_input_from_option(Witness(2), y); - BlackBoxFuncCall::AND { - lhs, - rhs, - output: Witness(3), - } + BlackBoxFuncCall::AND { lhs, rhs, output: Witness(3) } } fn xor_op(x: Option, y: Option) -> BlackBoxFuncCall { let lhs = function_input_from_option(Witness(1), x); let rhs = function_input_from_option(Witness(2), y); - BlackBoxFuncCall::XOR { - lhs, - rhs, - output: Witness(3), - } + BlackBoxFuncCall::XOR { lhs, rhs, output: Witness(3) } } fn prop_assert_commutative( @@ -914,54 +919,55 @@ fn field_element_ones() -> FieldElement { FieldElement::from(2u128).pow(&exponent) - FieldElement::one() } -fn bigint_solve_from_to_le_bytes(modulus: Vec, input: Vec<(FieldElement, bool)>) -> Vec { - let initial_witness_vec: Vec<_> = input.iter().enumerate().map(|(i, (x, _))| { - (Witness(i as u32), x.clone()) - }).collect(); - let output_witnesses: Vec<_> = initial_witness_vec - .iter() - .map(|(witness, _)| *witness) - .collect(); +fn bigint_add_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::BigIntAdd { lhs: 0, rhs: 1, output: 2 } +} - let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); - let input: Vec<_> = input.into_iter().enumerate().map(|(i, (x, use_constant))| { - if use_constant { - FunctionInput::constant(x, FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) - } - }).collect(); +fn bigint_mul_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::BigIntMul { lhs: 0, rhs: 1, output: 2 } +} - let bigint_from_op = BlackBoxFuncCall::BigIntFromLeBytes { - inputs: input, - modulus: modulus.clone(), - output: 0, - }; - let bigint_to_op = BlackBoxFuncCall::BigIntToLeBytes { - input: 0, - outputs: output_witnesses.clone(), - }; +fn bigint_sub_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::BigIntSub { lhs: 0, rhs: 1, output: 2 } +} - let bigint_from_op = Opcode::BlackBoxFuncCall(bigint_from_op); - let bigint_to_op = Opcode::BlackBoxFuncCall(bigint_to_op); - let opcodes = vec![bigint_from_op, bigint_to_op]; - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); - let solver_status = acvm.solve(); - assert_eq!(solver_status, ACVMStatus::Solved); - let witness_map = acvm.finalize(); +fn bigint_div_op() -> BlackBoxFuncCall { + BlackBoxFuncCall::BigIntDiv { lhs: 0, rhs: 1, output: 2 } +} + +// Input is a BigInt, represented as a LE Vec of u8-range FieldElement's along +// with their use_constant values. +// +// Output is a zeroed BigInt with the same byte-length and use_constant values +// as the input. +fn bigint_zeroed(input: &Vec<(FieldElement, bool)>) -> Vec<(FieldElement, bool)> { + input.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect() +} - // TODO: remove clone? - output_witnesses.iter().map(|witness| { - witness_map.get(witness).expect("all witnesses to be set").clone() - }).collect() +// bigint_zeroed, but returns one +fn bigint_oned(input: &Vec<(FieldElement, bool)>) -> Vec<(FieldElement, bool)> { + let mut one = bigint_zeroed(&xs); + // little-endian + one[0] = (FieldElement::one(), one[0].1); + one } -fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Vec, xs: Vec<(FieldElement, bool)>, ys: Vec<(FieldElement, bool)>) -> Vec { - let initial_witness_vec: Vec<_> = xs.iter().chain(ys.iter()).enumerate().map(|(i, (x, _))| { - (Witness(i as u32), x.clone()) - }).collect(); +fn drop_use_constant(input: &Vec<(FieldElement, bool)>) -> Vec { + input.into_iter().map(|x| x.0).collect() +} + +fn bigint_solve_binary_op_opt( + middle_op: Option>, + modulus: Vec, + xs: Vec<(FieldElement, bool)>, + ys: Vec<(FieldElement, bool)>, +) -> Vec { + let initial_witness_vec: Vec<_> = xs + .iter() + .chain(ys.iter()) + .enumerate() + .map(|(i, (x, _))| (Witness(i as u32), x.clone())) + .collect(); let output_witnesses: Vec<_> = initial_witness_vec .iter() .take(xs.len()) @@ -970,42 +976,49 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve .collect(); let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); - let xs: Vec<_> = xs.into_iter().enumerate().map(|(i, (x, use_constant))| { - if use_constant { - FunctionInput::constant(x, FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) - } - }).collect(); - let ys: Vec<_> = ys.into_iter().enumerate().map(|(i, (x, use_constant))| { - if use_constant { - FunctionInput::constant(x, FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness((i + xs.len()) as u32), FieldElement::max_num_bits()) - } - }).collect(); + let xs: Vec<_> = xs + .into_iter() + .enumerate() + .map(|(i, (x, use_constant))| { + if use_constant { + FunctionInput::constant(x, FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) + } + }) + .collect(); + let ys: Vec<_> = ys + .into_iter() + .enumerate() + .map(|(i, (x, use_constant))| { + if use_constant { + FunctionInput::constant(x, FieldElement::max_num_bits()) + } else { + FunctionInput::witness(Witness((i + xs.len()) as u32), FieldElement::max_num_bits()) + } + }) + .collect(); - let bigint_from_x_op = BlackBoxFuncCall::BigIntFromLeBytes { - inputs: xs, - modulus: modulus.clone(), - output: 0, - }; - let bigint_from_y_op = BlackBoxFuncCall::BigIntFromLeBytes { - inputs: ys, - modulus: modulus.clone(), - output: 1, - }; - let bigint_to_op = BlackBoxFuncCall::BigIntToLeBytes { - input: 2, - outputs: output_witnesses.clone(), - }; + let to_op_input = if middle_op.is_some() { 2 } else { 0 }; + + let bigint_from_x_op = + BlackBoxFuncCall::BigIntFromLeBytes { inputs: xs, modulus: modulus.clone(), output: 0 }; + let bigint_from_y_op = + BlackBoxFuncCall::BigIntFromLeBytes { inputs: ys, modulus: modulus.clone(), output: 1 }; + let bigint_to_op = + BlackBoxFuncCall::BigIntToLeBytes { input: to_op_input, outputs: output_witnesses.clone() }; let bigint_from_x_op = Opcode::BlackBoxFuncCall(bigint_from_x_op); let bigint_from_y_op = Opcode::BlackBoxFuncCall(bigint_from_y_op); - let middle_op = Opcode::BlackBoxFuncCall(middle_op); + let mut opcodes = vec![bigint_from_x_op, bigint_from_y_op]; + if let Some(middle_op) = middle_op { + let middle_op = Opcode::BlackBoxFuncCall(middle_op); + opcodes.push(middle_op); + } let bigint_to_op = Opcode::BlackBoxFuncCall(bigint_to_op); - let opcodes = vec![bigint_from_x_op, bigint_from_y_op, middle_op, bigint_to_op]; + opcodes.push(bigint_to_op); + let unconstrained_functions = vec![]; let mut acvm = ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); @@ -1014,16 +1027,31 @@ fn bigint_solve_binary_op(middle_op: BlackBoxFuncCall, modulus: Ve assert_eq!(solver_status, ACVMStatus::Solved); let witness_map = acvm.finalize(); - // TODO: remove clone? - output_witnesses.iter().map(|witness| { - witness_map.get(witness).expect("all witnesses to be set").clone() - }).collect() + output_witnesses + .iter() + .map(|witness| witness_map.get(witness).expect("all witnesses to be set").clone()) + .collect() } +fn bigint_solve_binary_op( + middle_op: BlackBoxFuncCall, + modulus: Vec, + xs: Vec<(FieldElement, bool)>, + ys: Vec<(FieldElement, bool)>, +) -> Vec { + bigint_solve_binary_op_opt(Some(middle_op), modulus, xs, ys) +} + +fn bigint_solve_from_to_le_bytes( + modulus: Vec, + input: Vec<(FieldElement, bool)>, +) -> Vec { + bigint_solve_binary_op_opt(None, modulus, input, vec![]) // TODO: input instead of vec![] ? +} // NOTE: an "average" bigint is large, so consider increasing the number of proptest shrinking -// iterations (from the default 1024) to reach a simplified case: -// PROPTEST_MAX_SHRINK_ITERS=1024000 +// iterations (from the default 1024) to reach a simplified case, e.g. +// PROPTEST_MAX_SHRINK_ITERS=1024000 proptest! { #[test] @@ -1114,14 +1142,14 @@ proptest! { FieldElement::zero() }; let zero_or_ones: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); - let expected_results: Vec<_> = zero_or_ones.iter().map(|x| x.0).collect(); + let expected_results = drop_use_constant(&zero_or_ones); let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero_or_ones); prop_assert_eq!(results, expected_results) } #[test] fn bigint_from_to_le_bytes((input, modulus) in bigint_with_modulus()) { - let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&input); let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); prop_assert_eq!(results, expected_results) } @@ -1131,7 +1159,7 @@ proptest! { fn bigint_from_to_le_bytes_extra_input_byte((input, modulus) in bigint_with_modulus(), extra_byte in any::(), use_constant in any::()) { let mut input = input; input.push((FieldElement::from(extra_byte as u128), use_constant)); - let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&input); let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); prop_assert_eq!(results, expected_results) } @@ -1142,7 +1170,7 @@ proptest! { let mut input = input; input.push((FieldElement::from(extra_byte as u128), use_constant)); input.push((FieldElement::from(extra_byte_2 as u128), use_constant_2)); - let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&input); let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); prop_assert_eq!(results, expected_results) } @@ -1153,7 +1181,7 @@ proptest! { let mut input = input; let mut extra_bytes: Vec<_> = extra_bytes.into_iter().take(extra_bytes_len as usize).map(|(x, use_constant)| (FieldElement::from(x as u128), use_constant)).collect(); input.append(&mut extra_bytes); - let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&input); let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); prop_assert_eq!(results, expected_results) } @@ -1166,7 +1194,7 @@ proptest! { let patch_location = patch_location % input.len(); let larger_value = FieldElement::from(std::cmp::max((u8::MAX as u16) + 1, larger_value) as u128); input[patch_location] = (larger_value, use_constant); - let expected_results: Vec<_> = input.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&input); let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); prop_assert_eq!(results, expected_results) } @@ -1186,7 +1214,7 @@ proptest! { FieldElement::one() }; let zero: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); - let expected_results: Vec<_> = zero.iter().map(|x| x.0).collect(); + let expected_results: Vec<_> = drop_use_constant(&zero); let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero); prop_assert_eq!(results, expected_results) @@ -1194,107 +1222,63 @@ proptest! { #[test] fn bigint_add_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { - let op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - - let lhs_results = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); - let rhs_results = bigint_solve_binary_op(op, modulus, ys, xs); + let lhs_results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs.clone(), ys.clone()); + let rhs_results = bigint_solve_binary_op(bigint_add_op(), modulus, ys, xs); prop_assert_eq!(lhs_results, rhs_results) } #[test] fn bigint_mul_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let lhs_results = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); - let rhs_results = bigint_solve_binary_op(op, modulus, ys, xs); + let lhs_results = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys.clone()); + let rhs_results = bigint_solve_binary_op(bigint_mul_op(), modulus, ys, xs); prop_assert_eq!(lhs_results, rhs_results) } #[test] fn bigint_add_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - let op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - // f(f(xs, ys), zs) == - let op_xs_ys = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let op_xs_ys = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs.clone(), ys.clone()); let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); - let op_xs_ys_op_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), xs_ys, zs.clone()); + let op_xs_ys_op_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs_ys, zs.clone()); // f(xs, f(ys, zs)) - let op_ys_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let op_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), ys.clone(), zs.clone()); let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); - let op_xs_op_ys_zs = bigint_solve_binary_op(op, modulus, xs, ys_zs); + let op_xs_op_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus, xs, ys_zs); prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) } #[test] fn bigint_mul_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - // f(f(xs, ys), zs) == - let op_xs_ys = bigint_solve_binary_op(op.clone(), modulus.clone(), xs.clone(), ys.clone()); + let op_xs_ys = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys.clone()); let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); - let op_xs_ys_op_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), xs_ys, zs.clone()); + let op_xs_ys_op_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs_ys, zs.clone()); // f(xs, f(ys, zs)) - let op_ys_zs = bigint_solve_binary_op(op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let op_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), ys.clone(), zs.clone()); let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); - let op_xs_op_ys_zs = bigint_solve_binary_op(op, modulus, xs, ys_zs); + let op_xs_op_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, ys_zs); prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) } - // TODO - // - // minimal failing input: (xs, ys, zs, modulus) = ( - // [ (0, false), (0, false), (158, true), (171, true), (134, false), (0, true), (37, true), (5, false), (241, true), (103, false), (20, false), (139, true), (227, false), (7, true), (9, true), (190, true), (220, false), (1, false), (43, true), (147, true), (235, true), (70, false), (146, true), (26, true), (211, true), (234, true), (54, false), (7, true), (97, false), (50, false), (228, true), (6, true)], - // [ (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (7, false), (125, true), (213, false), (40, true), (66, false), (34, true), (102, true), (87, true), (87, true), (166, false), (39, false), (60, true), (179, true), (162, false), (194, false), (235, true), ], - // [ (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (0, false), (1, true), (186, true), (43, false), (167, false), (178, false), (161, true), (70, false), (2⁴×14, false), (129, false), (177, true), (129, true), (2⁴×9, false), (76, true), (104, true), (222, false), (107, true), (197, true), (186, true), (57, true), (251, false), (159, false), ], - // [ 65, 65, 54, 208, 140, 94, 210, 191, 59, 160, 72, 175, 230, 220, 174, 186, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] - // ) #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_add_distributive((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - let add_op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - let mul_op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - // xs * (ys + zs) == - let add_ys_zs = bigint_solve_binary_op(add_op.clone(), modulus.clone(), ys.clone(), zs.clone()); + let add_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), ys.clone(), zs.clone()); let add_ys_zs: Vec<_> = add_ys_zs.into_iter().map(|x| (x, false)).collect(); - let mul_xs_add_ys_zs = bigint_solve_binary_op(mul_op.clone(), modulus.clone(), xs.clone(), add_ys_zs); + let mul_xs_add_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), add_ys_zs); // xs * ys + xs * zs - let mul_xs_ys = bigint_solve_binary_op(mul_op.clone(), modulus.clone(), xs.clone(), ys); + let mul_xs_ys = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys); let mul_xs_ys: Vec<_> = mul_xs_ys.into_iter().map(|x| (x, false)).collect(); - let mul_xs_zs = bigint_solve_binary_op(mul_op, modulus.clone(), xs, zs); + let mul_xs_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs, zs); let mul_xs_zs: Vec<_> = mul_xs_zs.into_iter().map(|x| (x, false)).collect(); - let add_mul_xs_ys_mul_xs_zs = bigint_solve_binary_op(add_op, modulus, mul_xs_ys, mul_xs_zs); + let add_mul_xs_ys_mul_xs_zs = bigint_solve_binary_op(bigint_add_op(), modulus, mul_xs_ys, mul_xs_zs); prop_assert_eq!(mul_xs_add_ys_zs, add_mul_xs_ys_mul_xs_zs) } @@ -1304,15 +1288,9 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_add_zero_l((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, zero, xs); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_add_op(), modulus, zero, xs); prop_assert_eq!(results, expected_results) } @@ -1321,43 +1299,25 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_add_zero_r((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, zero); + let zero = bigint_zeroed(&xs); + let expected_results: Vec<_> = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_add_op(), modulus, xs, zero); prop_assert_eq!(results, expected_results) } #[test] fn bigint_mul_zero_l((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let results = bigint_solve_binary_op(op, modulus, zero, xs); - let expected_results: Vec<_> = results.iter().map(|_| FieldElement::zero()).collect(); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&zero); + let results = bigint_solve_binary_op(bigint_mul_op(), modulus, zero, xs); prop_assert_eq!(results, expected_results) } #[test] fn bigint_mul_zero_r((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, zero); - let expected_results: Vec<_> = results.iter().map(|_| FieldElement::zero()).collect(); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&zero); + let results = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, zero); prop_assert_eq!(results, expected_results) } @@ -1365,17 +1325,9 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_one_l((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - // little-endian - one[0] = (FieldElement::one(), one[0].1); - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, one, xs); + let one = bigint_oned(&xs); + let expected_results: Vec<_> = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_mul_op(), modulus, one, xs); prop_assert_eq!(results, expected_results) } @@ -1383,31 +1335,16 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_one_r((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - // little-endian - one[0] = (FieldElement::one(), one[0].1); - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, one); + let one = bigint_oned(&xs); + let expected_results = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, one); prop_assert_eq!(results, expected_results) } #[test] fn bigint_sub_self((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntSub { - lhs: 0, - rhs: 1, - output: 2, - }; - - let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); - let results = bigint_solve_binary_op(op, modulus, xs.clone(), xs); + let expected_results = drop_use_constant(&bigint_zeroed(&xs)); + let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs.clone(), xs); prop_assert_eq!(results, expected_results) } @@ -1415,63 +1352,32 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_sub_zero((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntSub { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, zero); + let zero = bigint_zeroed(&xs); + let expected_results: Vec<_> = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs, zero); prop_assert_eq!(results, expected_results) } #[test] fn bigint_sub_one((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntSub { - lhs: 0, - rhs: 1, - output: 2, - }; - - let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - // little-endian - one[0] = (FieldElement::one(), one[0].1); - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, one); + let one = bigint_oned(&xs); + let expected_results: Vec<_> = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs, one); prop_assert!(results != expected_results, "{:?} == {:?}", results, expected_results) } #[test] fn bigint_div_self((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - - let mut one: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); - // little-endian - one[0] = FieldElement::one(); - - let results = bigint_solve_binary_op(op, modulus, xs.clone(), xs); + let one = bigint_oned(&xs); + let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs.clone(), xs); prop_assert_eq!(results, one) } - // TODO? #[test] fn bigint_div_by_zero((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, zero); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&zero); + let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs, zero); prop_assert_eq!(results, expected_results) } @@ -1479,32 +1385,17 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_div_one((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - - let mut one: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - // little-endian - one[0] = (FieldElement::one(), one[0].1); - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus, xs, one); + let one = bigint_oned(&xs); + let expected_results = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs, one); prop_assert_eq!(results, expected_results) } #[test] fn bigint_div_zero((xs, modulus) in bigint_with_modulus()) { - let op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect(); - let expected_results: Vec<_> = xs.iter().map(|_| FieldElement::zero()).collect(); - let results = bigint_solve_binary_op(op, modulus, zero, xs); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&zero); + let results = bigint_solve_binary_op(bigint_div_op(), modulus, zero, xs); prop_assert_eq!(results, expected_results) } @@ -1512,21 +1403,10 @@ proptest! { #[test] #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] fn bigint_add_sub((xs, ys, modulus) in bigint_pair_with_modulus()) { - let add_op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - let sub_op = BlackBoxFuncCall::BigIntSub { - lhs: 0, - rhs: 1, - output: 2, - }; - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let add_results = bigint_solve_binary_op(add_op, modulus.clone(), xs, ys.clone()); + let expected_results = drop_use_constant(&xs); + let add_results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs, ys.clone()); let add_bigint: Vec<_> = add_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(sub_op, modulus, add_bigint, ys); + let results = bigint_solve_binary_op(bigint_sub_op(), modulus, add_bigint, ys); prop_assert_eq!(results, expected_results) } @@ -1534,21 +1414,10 @@ proptest! { #[test] #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] fn bigint_sub_add((xs, ys, modulus) in bigint_pair_with_modulus()) { - let add_op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - let sub_op = BlackBoxFuncCall::BigIntSub { - lhs: 0, - rhs: 1, - output: 2, - }; - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let sub_results = bigint_solve_binary_op(sub_op, modulus.clone(), xs, ys.clone()); + let expected_results = drop_use_constant(&xs); + let sub_results = bigint_solve_binary_op(bigint_sub_op(), modulus.clone(), xs, ys.clone()); let add_bigint: Vec<_> = sub_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(add_op, modulus, add_bigint, ys); + let results = bigint_solve_binary_op(bigint_add_op(), modulus, add_bigint, ys); prop_assert_eq!(results, expected_results) } @@ -1557,21 +1426,10 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_div_mul((xs, ys, modulus) in bigint_pair_with_modulus()) { - let div_op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - let mul_op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let div_results = bigint_solve_binary_op(div_op, modulus.clone(), xs, ys.clone()); + let expected_results = drop_use_constant(&xs); + let div_results = bigint_solve_binary_op(bigint_div_op(), modulus.clone(), xs, ys.clone()); let div_bigint: Vec<_> = div_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(mul_op, modulus, div_bigint, ys); + let results = bigint_solve_binary_op(bigint_mul_op(), modulus, div_bigint, ys); prop_assert_eq!(results, expected_results) } @@ -1580,21 +1438,10 @@ proptest! { #[test] #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] fn bigint_mul_div((xs, ys, modulus) in bigint_pair_with_modulus()) { - let div_op = BlackBoxFuncCall::BigIntDiv { - lhs: 0, - rhs: 1, - output: 2, - }; - let mul_op = BlackBoxFuncCall::BigIntMul { - lhs: 0, - rhs: 1, - output: 2, - }; - - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let mul_results = bigint_solve_binary_op(mul_op, modulus.clone(), xs, ys.clone()); + let expected_results = drop_use_constant(&xs); + let mul_results = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs, ys.clone()); let mul_bigint: Vec<_> = mul_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(div_op, modulus, mul_bigint, ys); + let results = bigint_solve_binary_op(bigint_div_op(), modulus, mul_bigint, ys); prop_assert_eq!(results, expected_results) } @@ -1611,16 +1458,9 @@ fn bigint_add_zero_l_single_case_49() { let mut xs: Vec<_> = modulus.iter().map(|_| (FieldElement::zero(), false)).collect(); xs[modulus.len() - 1] = (FieldElement::from(49u128), false); - let op = BlackBoxFuncCall::BigIntAdd { - lhs: 0, - rhs: 1, - output: 2, - }; - - let zero: Vec<_> = xs.iter().map(|(_, _use_constant)| (FieldElement::zero(), false)).collect(); - let expected_results: Vec<_> = xs.iter().map(|x| x.0).collect(); - let results = bigint_solve_binary_op(op, modulus.clone(), zero, xs); + let zero = bigint_zeroed(&xs); + let expected_results = drop_use_constant(&xs); + let results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), zero, xs); assert_eq!(results, expected_results) } - From df45f200c1dd29e5fd1ddf6baecad9ba98e79709 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 18 Jul 2024 16:38:19 -0400 Subject: [PATCH 07/12] remove bigint and control flow tests --- acvm-repo/acvm/tests/solver.rs | 530 --------------- .../execution_success/array_regex/Nargo.toml | 7 - .../execution_success/array_regex/src/main.nr | 603 ------------------ .../bigint_from_too_many_le_bytes/Nargo.toml | 7 - .../bigint_from_too_many_le_bytes/src/main.nr | 22 - .../execution_success/slice_regex/Nargo.toml | 7 - .../execution_success/slice_regex/src/main.nr | 431 ------------- 7 files changed, 1607 deletions(-) delete mode 100644 test_programs/execution_success/array_regex/Nargo.toml delete mode 100644 test_programs/execution_success/array_regex/src/main.nr delete mode 100644 test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml delete mode 100644 test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr delete mode 100644 test_programs/execution_success/slice_regex/Nargo.toml delete mode 100644 test_programs/execution_success/slice_regex/src/main.nr diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 573ff8e65db..90e0212e948 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -19,7 +19,6 @@ use brillig_vm::brillig::HeapValueType; use proptest::arbitrary::any; use proptest::prelude::*; use proptest::result::maybe_ok; -use proptest::sample::select; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -765,39 +764,6 @@ fn solve_blackbox_func_call( witness_map[&Witness(3)] } -fn allowed_bigint_moduli() -> Vec> { - let bn254_fq: Vec = vec![ - 0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, - 0x97, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, - 0x64, 0x30, - ]; - let bn254_fr: Vec = vec![ - 1, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, - 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48, - ]; - let secpk1_fr: Vec = vec![ - 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, - 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, - ]; - let secpk1_fq: Vec = vec![ - 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, - ]; - let secpr1_fq: Vec = vec![ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, - ]; - let secpr1_fr: Vec = vec![ - 81, 37, 99, 252, 194, 202, 185, 243, 132, 158, 23, 167, 173, 250, 230, 188, 255, 255, 255, - 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, - ]; - - vec![bn254_fq, bn254_fr, secpk1_fr, secpk1_fq, secpr1_fq, secpr1_fr] -} - fn function_input_from_option( witness: Witness, opt_constant: Option, @@ -881,177 +847,11 @@ prop_compose! { } } -prop_compose! { - fn bigint_with_modulus()(modulus in select(allowed_bigint_moduli())) - (input in proptest::collection::vec(any::<(u8, bool)>(), modulus.len()), modulus in Just(modulus)) - -> (Vec<(FieldElement, bool)>, Vec) { - let input = input.into_iter().map(|(x, use_constant)| { - (FieldElement::from(x as u128), use_constant) - }).collect(); - (input, modulus) - } -} - -prop_compose! { - fn bigint_pair_with_modulus()(input_modulus in bigint_with_modulus()) - (ys in proptest::collection::vec(any::<(u8, bool)>(), input_modulus.1.len()), input_modulus in Just(input_modulus)) - -> (Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec) { - let ys = ys.into_iter().map(|(x, use_constant)| { - (FieldElement::from(x as u128), use_constant) - }).collect(); - (input_modulus.0, ys, input_modulus.1) - } -} - -prop_compose! { - fn bigint_triple_with_modulus()(xs_ys_modulus in bigint_pair_with_modulus()) - (zs in proptest::collection::vec(any::<(u8, bool)>(), xs_ys_modulus.2.len()), xs_ys_modulus in Just(xs_ys_modulus)) - -> (Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec<(FieldElement, bool)>, Vec) { - let zs = zs.into_iter().map(|(x, use_constant)| { - (FieldElement::from(x as u128), use_constant) - }).collect(); - (xs_ys_modulus.0, xs_ys_modulus.1, zs, xs_ys_modulus.2) - } -} - fn field_element_ones() -> FieldElement { let exponent: FieldElement = (FieldElement::max_num_bits() as u128).into(); FieldElement::from(2u128).pow(&exponent) - FieldElement::one() } -fn bigint_add_op() -> BlackBoxFuncCall { - BlackBoxFuncCall::BigIntAdd { lhs: 0, rhs: 1, output: 2 } -} - -fn bigint_mul_op() -> BlackBoxFuncCall { - BlackBoxFuncCall::BigIntMul { lhs: 0, rhs: 1, output: 2 } -} - -fn bigint_sub_op() -> BlackBoxFuncCall { - BlackBoxFuncCall::BigIntSub { lhs: 0, rhs: 1, output: 2 } -} - -fn bigint_div_op() -> BlackBoxFuncCall { - BlackBoxFuncCall::BigIntDiv { lhs: 0, rhs: 1, output: 2 } -} - -// Input is a BigInt, represented as a LE Vec of u8-range FieldElement's along -// with their use_constant values. -// -// Output is a zeroed BigInt with the same byte-length and use_constant values -// as the input. -fn bigint_zeroed(input: &Vec<(FieldElement, bool)>) -> Vec<(FieldElement, bool)> { - input.iter().map(|(_, use_constant)| (FieldElement::zero(), *use_constant)).collect() -} - -// bigint_zeroed, but returns one -fn bigint_oned(input: &Vec<(FieldElement, bool)>) -> Vec<(FieldElement, bool)> { - let mut one = bigint_zeroed(&xs); - // little-endian - one[0] = (FieldElement::one(), one[0].1); - one -} - -fn drop_use_constant(input: &Vec<(FieldElement, bool)>) -> Vec { - input.into_iter().map(|x| x.0).collect() -} - -fn bigint_solve_binary_op_opt( - middle_op: Option>, - modulus: Vec, - xs: Vec<(FieldElement, bool)>, - ys: Vec<(FieldElement, bool)>, -) -> Vec { - let initial_witness_vec: Vec<_> = xs - .iter() - .chain(ys.iter()) - .enumerate() - .map(|(i, (x, _))| (Witness(i as u32), x.clone())) - .collect(); - let output_witnesses: Vec<_> = initial_witness_vec - .iter() - .take(xs.len()) - .enumerate() - .map(|(i, _)| Witness((i + 2 * xs.len()) as u32)) - .collect(); - let initial_witness = WitnessMap::from(BTreeMap::from_iter(initial_witness_vec)); - - let xs: Vec<_> = xs - .into_iter() - .enumerate() - .map(|(i, (x, use_constant))| { - if use_constant { - FunctionInput::constant(x, FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness(i as u32), FieldElement::max_num_bits()) - } - }) - .collect(); - let ys: Vec<_> = ys - .into_iter() - .enumerate() - .map(|(i, (x, use_constant))| { - if use_constant { - FunctionInput::constant(x, FieldElement::max_num_bits()) - } else { - FunctionInput::witness(Witness((i + xs.len()) as u32), FieldElement::max_num_bits()) - } - }) - .collect(); - - let to_op_input = if middle_op.is_some() { 2 } else { 0 }; - - let bigint_from_x_op = - BlackBoxFuncCall::BigIntFromLeBytes { inputs: xs, modulus: modulus.clone(), output: 0 }; - let bigint_from_y_op = - BlackBoxFuncCall::BigIntFromLeBytes { inputs: ys, modulus: modulus.clone(), output: 1 }; - let bigint_to_op = - BlackBoxFuncCall::BigIntToLeBytes { input: to_op_input, outputs: output_witnesses.clone() }; - - let bigint_from_x_op = Opcode::BlackBoxFuncCall(bigint_from_x_op); - let bigint_from_y_op = Opcode::BlackBoxFuncCall(bigint_from_y_op); - - let mut opcodes = vec![bigint_from_x_op, bigint_from_y_op]; - if let Some(middle_op) = middle_op { - let middle_op = Opcode::BlackBoxFuncCall(middle_op); - opcodes.push(middle_op); - } - let bigint_to_op = Opcode::BlackBoxFuncCall(bigint_to_op); - opcodes.push(bigint_to_op); - - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); - - let solver_status = acvm.solve(); - assert_eq!(solver_status, ACVMStatus::Solved); - let witness_map = acvm.finalize(); - - output_witnesses - .iter() - .map(|witness| witness_map.get(witness).expect("all witnesses to be set").clone()) - .collect() -} - -fn bigint_solve_binary_op( - middle_op: BlackBoxFuncCall, - modulus: Vec, - xs: Vec<(FieldElement, bool)>, - ys: Vec<(FieldElement, bool)>, -) -> Vec { - bigint_solve_binary_op_opt(Some(middle_op), modulus, xs, ys) -} - -fn bigint_solve_from_to_le_bytes( - modulus: Vec, - input: Vec<(FieldElement, bool)>, -) -> Vec { - bigint_solve_binary_op_opt(None, modulus, input, vec![]) // TODO: input instead of vec![] ? -} - -// NOTE: an "average" bigint is large, so consider increasing the number of proptest shrinking -// iterations (from the default 1024) to reach a simplified case, e.g. -// PROPTEST_MAX_SHRINK_ITERS=1024000 proptest! { #[test] @@ -1133,334 +933,4 @@ proptest! { let (lhs, rhs) = prop_assert_zero_r(and_op, zero, x); prop_assert_eq!(lhs, rhs); } - - #[test] - fn bigint_from_to_le_bytes_zero_one(modulus in select(allowed_bigint_moduli()), zero_or_ones_constant in any::(), use_constant in any::()) { - let zero_function_input = if zero_or_ones_constant { - FieldElement::one() - } else { - FieldElement::zero() - }; - let zero_or_ones: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); - let expected_results = drop_use_constant(&zero_or_ones); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero_or_ones); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_from_to_le_bytes((input, modulus) in bigint_with_modulus()) { - let expected_results: Vec<_> = drop_use_constant(&input); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); - prop_assert_eq!(results, expected_results) - } - - #[test] - // TODO: desired behavior? - fn bigint_from_to_le_bytes_extra_input_byte((input, modulus) in bigint_with_modulus(), extra_byte in any::(), use_constant in any::()) { - let mut input = input; - input.push((FieldElement::from(extra_byte as u128), use_constant)); - let expected_results: Vec<_> = drop_use_constant(&input); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); - prop_assert_eq!(results, expected_results) - } - - #[test] - // TODO: desired behavior? - fn bigint_from_to_le_bytes_two_extra_input_bytes((input, modulus) in bigint_with_modulus(), extra_byte in any::(), extra_byte_2 in any::(), use_constant in any::(), use_constant_2 in any::()) { - let mut input = input; - input.push((FieldElement::from(extra_byte as u128), use_constant)); - input.push((FieldElement::from(extra_byte_2 as u128), use_constant_2)); - let expected_results: Vec<_> = drop_use_constant(&input); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); - prop_assert_eq!(results, expected_results) - } - - #[test] - // TODO: desired behavior? - fn bigint_from_to_le_bytes_extra_input_bytes((input, modulus) in bigint_with_modulus(), extra_bytes_len in any::(), extra_bytes in proptest::collection::vec(any::<(u8, bool)>(), u8::MAX as usize)) { - let mut input = input; - let mut extra_bytes: Vec<_> = extra_bytes.into_iter().take(extra_bytes_len as usize).map(|(x, use_constant)| (FieldElement::from(x as u128), use_constant)).collect(); - input.append(&mut extra_bytes); - let expected_results: Vec<_> = drop_use_constant(&input); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); - prop_assert_eq!(results, expected_results) - } - - #[test] - // TODO: desired behavior? - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_from_to_le_bytes_bigger_than_u8((input, modulus) in bigint_with_modulus(), patch_location in any::(), larger_value in any::(), use_constant in any::()) { - let mut input = input; - let patch_location = patch_location % input.len(); - let larger_value = FieldElement::from(std::cmp::max((u8::MAX as u16) + 1, larger_value) as u128); - input[patch_location] = (larger_value, use_constant); - let expected_results: Vec<_> = drop_use_constant(&input); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), input); - prop_assert_eq!(results, expected_results) - } - - #[test] - // TODO: this test attempts to use a guaranteed-invalid BigInt modulus - #[should_panic(expected = "attempt to add with overflow")] - fn bigint_from_to_le_bytes_disallowed_modulus(modulus in select(allowed_bigint_moduli()), patch_location in any::(), patch_amount in any::(), zero_or_ones_constant in any::(), use_constant in any::()) { - let patch_location = patch_location % modulus.len(); - let patch_amount = patch_amount.clamp(1, u8::MAX); - let mut modulus = modulus; - modulus[patch_location] += patch_amount; - - let zero_function_input = if zero_or_ones_constant { - FieldElement::zero() - } else { - FieldElement::one() - }; - let zero: Vec<_> = modulus.iter().map(|_| (zero_function_input, use_constant)).collect(); - let expected_results: Vec<_> = drop_use_constant(&zero); - let results = bigint_solve_from_to_le_bytes(modulus.clone(), zero); - - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_add_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { - let lhs_results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs.clone(), ys.clone()); - let rhs_results = bigint_solve_binary_op(bigint_add_op(), modulus, ys, xs); - - prop_assert_eq!(lhs_results, rhs_results) - } - - #[test] - fn bigint_mul_commutative((xs, ys, modulus) in bigint_pair_with_modulus()) { - let lhs_results = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys.clone()); - let rhs_results = bigint_solve_binary_op(bigint_mul_op(), modulus, ys, xs); - - prop_assert_eq!(lhs_results, rhs_results) - } - - #[test] - fn bigint_add_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - // f(f(xs, ys), zs) == - let op_xs_ys = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs.clone(), ys.clone()); - let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); - let op_xs_ys_op_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs_ys, zs.clone()); - - // f(xs, f(ys, zs)) - let op_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), ys.clone(), zs.clone()); - let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); - let op_xs_op_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus, xs, ys_zs); - - prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) - } - - #[test] - fn bigint_mul_associative((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - // f(f(xs, ys), zs) == - let op_xs_ys = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys.clone()); - let xs_ys: Vec<_> = op_xs_ys.into_iter().map(|x| (x, false)).collect(); - let op_xs_ys_op_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs_ys, zs.clone()); - - // f(xs, f(ys, zs)) - let op_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), ys.clone(), zs.clone()); - let ys_zs: Vec<_> = op_ys_zs.into_iter().map(|x| (x, false)).collect(); - let op_xs_op_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, ys_zs); - - prop_assert_eq!(op_xs_ys_op_zs, op_xs_op_ys_zs) - } - - #[test] - fn bigint_mul_add_distributive((xs, ys, zs, modulus) in bigint_triple_with_modulus()) { - // xs * (ys + zs) == - let add_ys_zs = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), ys.clone(), zs.clone()); - let add_ys_zs: Vec<_> = add_ys_zs.into_iter().map(|x| (x, false)).collect(); - let mul_xs_add_ys_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), add_ys_zs); - - // xs * ys + xs * zs - let mul_xs_ys = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs.clone(), ys); - let mul_xs_ys: Vec<_> = mul_xs_ys.into_iter().map(|x| (x, false)).collect(); - let mul_xs_zs = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs, zs); - let mul_xs_zs: Vec<_> = mul_xs_zs.into_iter().map(|x| (x, false)).collect(); - let add_mul_xs_ys_mul_xs_zs = bigint_solve_binary_op(bigint_add_op(), modulus, mul_xs_ys, mul_xs_zs); - - prop_assert_eq!(mul_xs_add_ys_zs, add_mul_xs_ys_mul_xs_zs) - } - - - // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_add_zero_l((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_add_op(), modulus, zero, xs); - - prop_assert_eq!(results, expected_results) - } - - // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_add_zero_r((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results: Vec<_> = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_add_op(), modulus, xs, zero); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_mul_zero_l((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&zero); - let results = bigint_solve_binary_op(bigint_mul_op(), modulus, zero, xs); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_mul_zero_r((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&zero); - let results = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, zero); - prop_assert_eq!(results, expected_results) - } - - // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_mul_one_l((xs, modulus) in bigint_with_modulus()) { - let one = bigint_oned(&xs); - let expected_results: Vec<_> = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_mul_op(), modulus, one, xs); - prop_assert_eq!(results, expected_results) - } - - // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_mul_one_r((xs, modulus) in bigint_with_modulus()) { - let one = bigint_oned(&xs); - let expected_results = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_mul_op(), modulus, xs, one); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_sub_self((xs, modulus) in bigint_with_modulus()) { - let expected_results = drop_use_constant(&bigint_zeroed(&xs)); - let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs.clone(), xs); - prop_assert_eq!(results, expected_results) - } - - // TODO: Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_sub_zero((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results: Vec<_> = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs, zero); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_sub_one((xs, modulus) in bigint_with_modulus()) { - let one = bigint_oned(&xs); - let expected_results: Vec<_> = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_sub_op(), modulus, xs, one); - prop_assert!(results != expected_results, "{:?} == {:?}", results, expected_results) - } - - #[test] - fn bigint_div_self((xs, modulus) in bigint_with_modulus()) { - let one = bigint_oned(&xs); - let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs.clone(), xs); - prop_assert_eq!(results, one) - } - - #[test] - fn bigint_div_by_zero((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&zero); - let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs, zero); - prop_assert_eq!(results, expected_results) - } - - // Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_div_one((xs, modulus) in bigint_with_modulus()) { - let one = bigint_oned(&xs); - let expected_results = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_div_op(), modulus, xs, one); - prop_assert_eq!(results, expected_results) - } - - #[test] - fn bigint_div_zero((xs, modulus) in bigint_with_modulus()) { - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&zero); - let results = bigint_solve_binary_op(bigint_div_op(), modulus, zero, xs); - prop_assert_eq!(results, expected_results) - } - - // TODO: fails on (x=0, y=97) - #[test] - #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] - fn bigint_add_sub((xs, ys, modulus) in bigint_pair_with_modulus()) { - let expected_results = drop_use_constant(&xs); - let add_results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), xs, ys.clone()); - let add_bigint: Vec<_> = add_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(bigint_sub_op(), modulus, add_bigint, ys); - - prop_assert_eq!(results, expected_results) - } - - #[test] - #[should_panic(expected = "Test failed: Cannot subtract b from a because b is larger than a..")] - fn bigint_sub_add((xs, ys, modulus) in bigint_pair_with_modulus()) { - let expected_results = drop_use_constant(&xs); - let sub_results = bigint_solve_binary_op(bigint_sub_op(), modulus.clone(), xs, ys.clone()); - let add_bigint: Vec<_> = sub_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(bigint_add_op(), modulus, add_bigint, ys); - - prop_assert_eq!(results, expected_results) - } - - // Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_div_mul((xs, ys, modulus) in bigint_pair_with_modulus()) { - let expected_results = drop_use_constant(&xs); - let div_results = bigint_solve_binary_op(bigint_div_op(), modulus.clone(), xs, ys.clone()); - let div_bigint: Vec<_> = div_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(bigint_mul_op(), modulus, div_bigint, ys); - - prop_assert_eq!(results, expected_results) - } - - // Fails on 49, see bigint_add_zero_l_single_case_49 - #[test] - #[should_panic(expected = "Test failed: assertion failed: `(left == right)`")] - fn bigint_mul_div((xs, ys, modulus) in bigint_pair_with_modulus()) { - let expected_results = drop_use_constant(&xs); - let mul_results = bigint_solve_binary_op(bigint_mul_op(), modulus.clone(), xs, ys.clone()); - let mul_bigint: Vec<_> = mul_results.into_iter().map(|x| (x, false)).collect(); - let results = bigint_solve_binary_op(bigint_div_op(), modulus, mul_bigint, ys); - - prop_assert_eq!(results, expected_results) - } - -} - -// TODO: this test is redundant with bigint_add_zero_l, -// but may be useful for debugging. It can be removed once bigint_add_zero_l is -// passing because proptest automatically retries previous failures first. -#[test] -#[should_panic(expected = "assertion `left == right` failed")] -fn bigint_add_zero_l_single_case_49() { - let modulus = &allowed_bigint_moduli()[0]; - let mut xs: Vec<_> = modulus.iter().map(|_| (FieldElement::zero(), false)).collect(); - xs[modulus.len() - 1] = (FieldElement::from(49u128), false); - - let zero = bigint_zeroed(&xs); - let expected_results = drop_use_constant(&xs); - let results = bigint_solve_binary_op(bigint_add_op(), modulus.clone(), zero, xs); - - assert_eq!(results, expected_results) } diff --git a/test_programs/execution_success/array_regex/Nargo.toml b/test_programs/execution_success/array_regex/Nargo.toml deleted file mode 100644 index 19f70994b7f..00000000000 --- a/test_programs/execution_success/array_regex/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "regex_array" -type = "bin" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/array_regex/src/main.nr b/test_programs/execution_success/array_regex/src/main.nr deleted file mode 100644 index 612ca45c37a..00000000000 --- a/test_programs/execution_success/array_regex/src/main.nr +++ /dev/null @@ -1,603 +0,0 @@ - -// offset <= len <= N -struct Bvec { - inner: [T; N], - - // elements at indices < offset are zero - offset: u32, - - // elements at indices >= len are zero - len: u32, -} - -impl Eq for Bvec where T: Eq { - fn eq(self, other: Self) -> bool { - (self.inner == other.inner) & - (self.offset == other.offset) & - (self.len == other.len) - } -} - - -impl Bvec { - fn empty() -> Self { - Self { - inner: [std::unsafe::zeroed(); N], - offset: 0, - len: 0, - } - } - - fn new(array: [T; N]) -> Self { - let mut result = Bvec::empty(); - for x in array { - result = result.push(x); - } - result - } - - // pushing when len == N is a no-op - fn push(self, x: T) -> Self { - let mut inner = self.inner; - let mut len = self.len; - if self.len < N { - inner[self.len] = x; - len += 1; - } - - Self { - inner, - offset: self.offset, - len, - } - } - - fn pop_front(self) -> (T, Self) { - assert(self.offset <= self.inner.len()); - assert(self.len != 0); - - let first_elem = self.inner[self.offset]; - let popped_slice = Self { - inner: self.inner, - offset: self.offset + 1, - len: self.len - 1, - }; - - (first_elem, popped_slice) - } -} - -struct Match { - succeeded: bool, - match_ends: u32, - leftover: Bvec, -} - -impl Match { - fn empty(leftover: Bvec) -> Self { - Match { - succeeded: true, - match_ends: 0, - leftover, - } - } - - fn failed(leftover: Bvec) -> Self { - Match { - succeeded: false, - match_ends: 0, - leftover, - } - } -} - -impl Eq for Match { - fn eq(self, other: Self) -> bool { - (self.succeeded == other.succeeded) & - (self.match_ends == other.match_ends) & - (self.leftover == other.leftover) - } -} - -// TODO: load match into str and assert that it's the correct length -// impl From for str - -trait Regex { - // Perform a match without backtracking - fn match(self, input: Bvec) -> Match; -} - -// Empty -impl Regex for () { - fn match(self, input: Bvec) -> Match { - assert(self == self); // ensure 'self' is used - Match::empty(input) - } -} - -// Exact -impl Regex for str { - fn match(self, input: Bvec) -> Match { - let mut leftover = input; - let mut matches_input = true; - let self_as_bytes = self.as_bytes(); - for c in self_as_bytes { - if leftover.len != 0 { - let (first_elem, popped_slice) = leftover.pop_front(); - leftover = popped_slice; - matches_input &= first_elem == c; - } else { - matches_input = false; - } - } - if matches_input { - Match { - succeeded: true, - match_ends: self_as_bytes.len(), - leftover, - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } -} - -// And -impl Regex for (T, U) where T: Regex, U: Regex { - fn match(self, input: Bvec) -> Match { - let lhs_result = self.0.match(input); - if lhs_result.succeeded { - let rhs_result = self.1.match(lhs_result.leftover); - if rhs_result.succeeded { - Match { - succeeded: true, - match_ends: lhs_result.match_ends + rhs_result.match_ends, - leftover: rhs_result.leftover, - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } -} - -// N T's: (T, (T, (T, T))) -struct Repeated { - inner: T, -} - -impl Regex for Repeated where T: Regex { - fn match(self, input: Bvec) -> Match { - let mut result = Match::empty(input); - for _ in 0..M { - if result.succeeded { - let next_result = self.inner.match(result.leftover); - result = Match { - succeeded: next_result.succeeded, - match_ends: result.match_ends + next_result.match_ends, - leftover: next_result.leftover, - }; - } - } - result - } -} - -struct Or { - lhs: T, - rhs: U, -} - -impl Regex for Or where T: Regex, U: Regex { - fn match(self, input: Bvec) -> Match { - let lhs_result = self.lhs.match(input); - if lhs_result.succeeded { - lhs_result - } else { - self.rhs.match(input) - } - } -} - -struct Question { - inner: T, -} - -impl Regex for Question where T: Regex { - fn match(self, input: Bvec) -> Match { - Or { - lhs: self.inner, - rhs: (), - }.match(input) - } -} - -// 0 <= num_matches <= N -struct Star { - inner: T, -} - -impl Regex for Star where T: Regex { - fn match(self, input: Bvec) -> Match { - let regex: Repeated<_, M> = Repeated { - inner: Question { inner: self.inner }, - }; - regex.match(input) - } -} - -// 0 < num_matches <= N -struct Plus { - inner: T, -} - -impl Regex for Plus where T: Regex { - fn match(self, input: Bvec) -> Match { - std::static_assert(M_PRED + 1 == M, "M - 1 != M_PRED"); - let star: Star = Star { inner: self.inner }; - ( - self.inner, - star - ).match(input) - } -} - -// Repeated is to (,) as AnyOf is to Or -struct AnyOf { - inner: [T; N], -} - -impl Regex for AnyOf where T: Regex { - fn match(self, input: Bvec) -> Match { - let mut result = Match::failed(input); - for i in 0..M { - if !result.succeeded { - result = self.inner[i].match(result.leftover); - } - } - result - } -} - -fn reverse_array(input: [T; N]) -> [T; N] { - let mut output = [std::unsafe::zeroed(); N]; - for i in 0..N { - output[i] = input[N - (i + 1)]; - } - output -} - -fn main() { - - assert_eq(reverse_array([1, 2, 3, 4]), [4, 3, 2, 1]); - - - let mut xs: Bvec = Bvec::empty(); - - xs = xs.push(0); - assert_eq(xs, Bvec { - inner: [0, 0, 0], - offset: 0, - len: 1, - }); - - xs = xs.push(1); - assert_eq(xs, Bvec { - inner: [0, 1, 0], - offset: 0, - len: 2, - }); - - xs = xs.push(2); - assert_eq(xs, Bvec { - inner: [0, 1, 2], - offset: 0, - len: 3, - }); - - xs = xs.push(3); - assert_eq(xs, Bvec { - inner: [0, 1, 2], - offset: 0, - len: 3, - }); - - let ys = Bvec::new([0, 1, 2]); - assert_eq(xs, ys); - - - // test that pop_front gives all contents, in order, - // followed by std::unsafe::zeroed() - println(xs); - let (x, new_xs) = xs.pop_front(); - assert_eq(x, 0); - - xs = new_xs; - println(xs); - let (x, new_xs) = xs.pop_front(); - assert_eq(x, 1); - - xs = new_xs; - println(xs); - let (x, new_xs) = xs.pop_front(); - assert_eq(x, 2); - - xs = new_xs; - println(xs); - if xs.len != 0 { - let (x, _new_xs) = xs.pop_front(); - assert_eq(x, std::unsafe::zeroed()); - } - - assert_eq(new_xs, Bvec { - inner: [0, 1, 2], - offset: 3, - len: 0, - }); - - - // gr(a|e)y - let graey_regex = ( - "gr", - ( - Or { - lhs: "a", - rhs: "e", - }, - "y" - ) - ); - - let result = graey_regex.match(Bvec::new("gray".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 4); - assert_eq(result.leftover.len, 0); - - let result = graey_regex.match(Bvec::new("grey".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 4); - assert_eq(result.leftover.len, 0); - - // colou?r - let colour_regex = ( - "colo", - ( - Question { - inner: "u", - }, - "r" - ) - ); - - let result = colour_regex.match(Bvec::new("color".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 5); - assert_eq(result.leftover.len, 0); - - let result = colour_regex.match(Bvec::new("colour".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 6); - assert_eq(result.leftover.len, 0); - - // parse the empty string three times - // EMPTY{3} - let three_empties_regex: Repeated<(), 3> = Repeated { - inner: (), - }; - - let result = three_empties_regex.match(Bvec::new("111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 0); - assert_eq(result.leftover.len, 3); - - // 1{0} - let zero_ones_regex: Repeated, 0> = Repeated { - inner: "1", - }; - - let result = zero_ones_regex.match(Bvec::new("111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 0); - assert_eq(result.leftover.len, 3); - - // 1{1} - let one_ones_regex: Repeated, 1> = Repeated { - inner: "1", - }; - - let result = one_ones_regex.match(Bvec::new("111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 1); - assert_eq(result.leftover.len, 2); - - // 1{2} - let two_ones_regex: Repeated, 2> = Repeated { - inner: "1", - }; - - let result = two_ones_regex.match(Bvec::new("111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 2); - assert_eq(result.leftover.len, 1); - - // 1{3} - let three_ones_regex: Repeated, 3> = Repeated { - inner: "1", - }; - - let result = three_ones_regex.match(Bvec::new("1111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 3); - assert_eq(result.leftover.len, 1); - - // 1* - let ones_regex: Star, 5> = Star { - inner: "1", - }; - - let result = ones_regex.match(Bvec::new("11000".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 2); - assert_eq(result.leftover.len, 3); - - - let result = ones_regex.match(Bvec::new("11".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 2); - assert_eq(result.leftover.len, 0); - - let result = ones_regex.match(Bvec::new("111111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 5); - assert_eq(result.leftover.len, 1); - - // 1+ - let nonempty_ones_regex: Plus, 5, 4> = Plus { - inner: "1", - }; - - let result = nonempty_ones_regex.match(Bvec::new("111111".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 5); - assert_eq(result.leftover.len, 1); - - // 2^n-1 in binary: 1+0 - let pred_pow_two_regex = ( - nonempty_ones_regex, - "0" - ); - - let result = pred_pow_two_regex.match(Bvec::new("1110".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 4); - assert_eq(result.leftover.len, 0); - - // (0|1)* - let binary_regex: Star, str<1>>, 5> = Star { - inner: Or { - lhs: "0", - rhs: "1", - } - }; - - let result = binary_regex.match(Bvec::new("110100".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 5); - assert_eq(result.leftover.len, 1); - - // even numbers in binary: 1(0|1)*0 - let even_binary_regex = ( - "1", - ( - binary_regex, - "0" - ) - ); - - let result = even_binary_regex.match(Bvec::new("1111110".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 7); - assert_eq(result.leftover.len, 0); - - // digit: \d+ - // [0-9] - let digit_regex = AnyOf { - inner: [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - ], - }; - - let result = digit_regex.match(Bvec::new("157196345823795".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 1); - assert_eq(result.leftover.len, 14); - - let result = digit_regex.match(Bvec::new("hi".as_bytes())); - println(result); - assert(!result.succeeded); - assert_eq(result.match_ends, 0); - assert_eq(result.leftover.len, 2); - - // digits: \d+ - // [0-9]+ - let digits_regex: Plus, 10>, 32, 31> = Plus { - inner: digit_regex, - }; - - let result = digits_regex.match(Bvec::new("123456789012345".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 15); - assert_eq(result.leftover.len, 0); - - let result = digits_regex.match(Bvec::new("123456789012345 then words".as_bytes())); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 15); - assert_eq(result.leftover.len, 11); - - // multiples of 10 - // apply to a reversed input string (because there isn't backtracking) - // 0\d+ - let backwards_mult_of_10_regex = ( - "0", - digits_regex - ); - - let result = backwards_mult_of_10_regex.match(Bvec::new(reverse_array("1230".as_bytes()))); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 4); - assert_eq(result.leftover.len, 0); - - let ten_pow_16: str<17> = "10000000000000000"; - let result = backwards_mult_of_10_regex.match(Bvec::new(reverse_array(ten_pow_16.as_bytes()))); - println(result); - assert(result.succeeded); - assert_eq(result.match_ends, 17); - assert_eq(result.leftover.len, 0); - - // adapted URL parser: (https?:\/\/)?([\da-c.\-]+)\.([a-c.]+)([\/\w \.\-]*)*\/? - -} - diff --git a/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml b/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml deleted file mode 100644 index cbdfc2d83d9..00000000000 --- a/test_programs/execution_success/bigint_from_too_many_le_bytes/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "bigint_from_too_many_le_bytes" -type = "bin" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr b/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr deleted file mode 100644 index 8b29cdeec01..00000000000 --- a/test_programs/execution_success/bigint_from_too_many_le_bytes/src/main.nr +++ /dev/null @@ -1,22 +0,0 @@ -use std::bigint::{bn254_fq, BigInt}; - -// TODO: make issue for this to fail at compile time and then move to compile_failure -// -// Fails at runtime: -// -// error: Assertion failed: 'Index out of bounds' -// ┌─ std/cmp.nr:35:34 -// │ -// 35 │ result &= self[i].eq(other[i]); -// │ -------- -// │ -// = Call stack: -// 1. /Users/michaelklein/Coding/rust/noir/test_programs/compile_failure/bigint_from_too_many_le_bytes/src/main.nr:7:12 -// 2. std/cmp.nr:35:34 -// Failed assertion -fn main() { - let bytes: [u8] = bn254_fq.push_front(0x00); - let bigint = BigInt::from_le_bytes(bytes, bn254_fq); - let result_bytes = bigint.to_le_bytes(); - assert(bytes == result_bytes.as_slice()); -} diff --git a/test_programs/execution_success/slice_regex/Nargo.toml b/test_programs/execution_success/slice_regex/Nargo.toml deleted file mode 100644 index 5f2b90d7580..00000000000 --- a/test_programs/execution_success/slice_regex/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "regex" -type = "bin" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/slice_regex/src/main.nr b/test_programs/execution_success/slice_regex/src/main.nr deleted file mode 100644 index 9dbec547a67..00000000000 --- a/test_programs/execution_success/slice_regex/src/main.nr +++ /dev/null @@ -1,431 +0,0 @@ - -struct Match { - succeeded: bool, - match_ends: u32, - leftover: [u8], -} - -impl Match { - fn empty(leftover: [u8]) -> Self { - Match { - succeeded: true, - match_ends: 0, - leftover, - } - } -} - -impl Eq for Match { - fn eq(self, other: Self) -> bool { - (self.succeeded == other.succeeded) & - (self.match_ends == other.match_ends) - // (self.leftover == other.leftover) - } -} - -// TODO: load match into str and assert that it's the correct length -// impl From for str - -trait Regex { - fn match(self, input: [u8]) -> Match; -} - -// Empty -impl Regex for () { - fn match(self, input: [u8]) -> Match { - assert(self == self); // ensure 'self' is used - Match::empty(input) - } -} - -// Exact -impl Regex for str { - fn match(self, input: [u8]) -> Match { - let mut leftover = input; - let mut matches_input = true; - let self_as_bytes = self.as_bytes(); - for c in self_as_bytes { - if leftover.len() != 0 { - let (first_elem, popped_slice) = leftover.pop_front(); - leftover = popped_slice; - matches_input &= first_elem == c; - } else { - matches_input = false; - } - } - if matches_input { - Match { - succeeded: true, - match_ends: self_as_bytes.len(), - leftover, - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } -} - -// And -impl Regex for (T, U) where T: Regex, U: Regex { - fn match(self, input: [u8]) -> Match { - let lhs_result = self.0.match(input); - if lhs_result.succeeded { - let rhs_result = self.1.match(lhs_result.leftover); - if rhs_result.succeeded { - Match { - succeeded: true, - match_ends: lhs_result.match_ends + rhs_result.match_ends, - leftover: rhs_result.leftover, - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } else { - Match { - succeeded: false, - match_ends: 0, - leftover: input, - } - } - } -} - -// N T's: (T, (T, (T, T))) -struct Repeated { - inner: T, -} - -impl Regex for Repeated where T: Regex { - fn match(self, input: [u8]) -> Match { - let mut result = Match::empty(input); - for _ in 0..N { - if result.succeeded { - let next_result = self.inner.match(result.leftover); - result = Match { - succeeded: next_result.succeeded, - match_ends: result.match_ends + next_result.match_ends, - leftover: next_result.leftover, - }; - } - } - result - } -} - -struct Or { - lhs: T, - rhs: U, -} - -impl Regex for Or where T: Regex, U: Regex { - fn match(self, input: [u8]) -> Match { - let lhs_result = self.lhs.match(input); - if lhs_result.succeeded { - lhs_result - } else { - self.rhs.match(input) - } - } -} - -struct Question { - inner: T, -} - -impl Regex for Question where T: Regex { - fn match(self, input: [u8]) -> Match { - Or { - lhs: self.inner, - rhs: (), - }.match(input) - } -} - -// 0 <= num_matches <= N -struct Star { - inner: T, -} - -impl Regex for Star where T: Regex { - fn match(self, input: [u8]) -> Match { - let regex: Repeated<_, N> = Repeated { - inner: Question { inner: self.inner }, - }; - regex.match(input) - } -} - -// 0 < num_matches <= N -struct Plus { - inner: T, -} - -impl Regex for Plus where T: Regex { - fn match(self, input: [u8]) -> Match { - std::static_assert(N_PRED + 1 == N, "N - 1 != N_PRED"); - let star: Star = Star { inner: self.inner }; - ( - self.inner, - star - ).match(input) - } -} - - -fn main() { - - // gr(a|e)y - let graey_regex = ( - "gr", - ( - Or { - lhs: "a", - rhs: "e", - }, - "y" - ) - ); - - // NOTE: leftover ignored in Eq: Match - let result = graey_regex.match("gray".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 4, - leftover: &[], - }); - - - // NOTE: leftover ignored in Eq: Match - let result = graey_regex.match("grey".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 4, - leftover: &[], - }); - - // colou?r - let colour_regex = ( - "colo", - ( - Question { - inner: "u", - }, - "r" - ) - ); - - let result = colour_regex.match("color".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 5, - leftover: &[], - }); - - let result = colour_regex.match("colour".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 6, - leftover: &[], - }); - - // parse the empty string three times - // EMPTY{3} - let three_empties_regex: Repeated<(), 3> = Repeated { - inner: (), - }; - - let result = three_empties_regex.match("111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 0, - leftover: &[], - }); - - // 1{0} - let zero_ones_regex: Repeated, 0> = Repeated { - inner: "1", - }; - - let result = zero_ones_regex.match("111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 0, - leftover: &[], - }); - - // 1{1} - let one_ones_regex: Repeated, 1> = Repeated { - inner: "1", - }; - - let result = one_ones_regex.match("111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 1, - leftover: &[], - }); - - // 1{2} - let two_ones_regex: Repeated, 2> = Repeated { - inner: "1", - }; - - let result = two_ones_regex.match("111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 2, - leftover: &[], - }); - - // 1{3} - let three_ones_regex: Repeated, 3> = Repeated { - inner: "1", - }; - - let result = three_ones_regex.match("1111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 3, - leftover: &[], - }); - - // 1* - let ones_regex: Star, 5> = Star { - inner: "1", - }; - - let result = ones_regex.match("11000".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 2, - leftover: &[], - }); - - let result = ones_regex.match("11".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 2, - leftover: &[], - }); - - let result = ones_regex.match("111111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 5, - leftover: &[], - }); - - // 1+ - let nonempty_ones_regex: Plus, 5, 4> = Plus { - inner: "1", - }; - - let result = nonempty_ones_regex.match("111111".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 5, - leftover: &[], - }); - - - // 2^n-1 in binary: 1+0 - let pred_pow_two_regex = ( - nonempty_ones_regex, - "0" - ); - - let result = pred_pow_two_regex.match("1110".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 3, - leftover: &[], - }); - - - // (0|1)* - let binary_regex: Star, str<1>>, 5> = Star { - inner: Or { - lhs: "0", - rhs: "1", - } - }; - - let result = binary_regex.match("110100".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 5, - leftover: &[], - }); - - // even numbers in binary: 1(0|1)*0 - let even_binary_regex = ( - "1", - ( - binary_regex, - "0" - ) - ); - - let result = even_binary_regex.match("1111110".as_bytes().as_slice()); - println(result); - assert_eq(result, Match { - succeeded: true, - match_ends: 6, - leftover: &[], - }); - - // 2-letter capitalized words: [A-Z][a-z] - - // numbers: \d+ - // [0-9]+ - - // words: \w+ - // [a-Z]+ - - // adapted URL parser: (https?:\/\/)?([\da-z.\-]+)\.([a-z.]+)([\/\w \.\-]*)*\/? - - - // // panics (at compile time) when input string is too short - // let foo_regex = ( - // "colo", - // ( - // Question { - // inner: "u", - // }, - // "r" - // ) - // ); - // - // let result = foo_regex.match("colo".as_bytes().as_slice()); - // println(result); - // assert_eq(result, Match { - // succeeded: true, - // match_ends: 4, - // leftover: &[], - // }); - -} - From fc72df03bc67d4b9934fb3f306e0115e7d0df5c6 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 23 Jul 2024 16:20:41 -0400 Subject: [PATCH 08/12] add f(x, x) tests, convert any:: to ': T', link to follow-up issue --- acvm-repo/acvm/tests/solver.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 90e0212e948..cfc31c0b141 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -837,7 +837,7 @@ prop_compose! { // Use both `u128` and hex proptest strategies fn field_element() (u128_or_hex in maybe_ok(any::(), "[0-9a-f]{64}"), - constant_input in any::()) + constant_input: bool) -> (FieldElement, bool) { match u128_or_hex { @@ -878,10 +878,22 @@ proptest! { prop_assert_eq!(lhs, rhs); } - // TODO bug + // test that AND(x, x) == x + #[test] + fn and_self_identity(x in field_element()) { + prop_assert_eq!(solve_blackbox_func_call(and_op, x, x), x.0); + } + + // test that XOR(x, x) == 0 + #[test] + fn xor_self_zero(x in field_element()) { + prop_assert_eq!(solve_blackbox_func_call(xor_op, x, x), FieldElement::zero()); + } + + // TODO(https://github.com/noir-lang/noir/issues/5597) #[test] #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] - fn and_identity_l(x in field_element(), ones_constant in any::()) { + fn and_identity_l(x in field_element(), ones_constant: bool) { let ones = (field_element_ones(), ones_constant); let (lhs, rhs) = prop_assert_identity_l(and_op, ones, x); if x <= ones { @@ -893,16 +905,16 @@ proptest! { } #[test] - fn xor_identity_l(x in field_element(), zero_constant in any::()) { + fn xor_identity_l(x in field_element(), zero_constant: bool) { let zero = (FieldElement::zero(), zero_constant); let (lhs, rhs) = prop_assert_identity_l(xor_op, zero, x); prop_assert_eq!(lhs, rhs); } - // TODO bug + // TODO(https://github.com/noir-lang/noir/issues/5597) #[test] #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] - fn and_identity_r(x in field_element(), ones_constant in any::()) { + fn and_identity_r(x in field_element(), ones_constant: bool) { let ones = (field_element_ones(), ones_constant); let (lhs, rhs) = prop_assert_identity_r(and_op, ones, x); if x <= ones { @@ -914,21 +926,21 @@ proptest! { } #[test] - fn xor_identity_r(x in field_element(), zero_constant in any::()) { + fn xor_identity_r(x in field_element(), zero_constant: bool) { let zero = (FieldElement::zero(), zero_constant); let (lhs, rhs) = prop_assert_identity_r(xor_op, zero, x); prop_assert_eq!(lhs, rhs); } #[test] - fn and_zero_l(x in field_element(), ones_constant in any::()) { + fn and_zero_l(x in field_element(), ones_constant: bool) { let zero = (FieldElement::zero(), ones_constant); let (lhs, rhs) = prop_assert_zero_l(and_op, zero, x); prop_assert_eq!(lhs, rhs); } #[test] - fn and_zero_r(x in field_element(), ones_constant in any::()) { + fn and_zero_r(x in field_element(), ones_constant: bool) { let zero = (FieldElement::zero(), ones_constant); let (lhs, rhs) = prop_assert_zero_r(and_op, zero, x); prop_assert_eq!(lhs, rhs); From 605c1e91b62a1c16df52f91f6aee01a0153df1c6 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Wed, 24 Jul 2024 17:51:31 -0400 Subject: [PATCH 09/12] remove redundant '_r' tests, fix associativity test --- acvm-repo/acvm/tests/solver.rs | 61 +++++++--------------------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index cfc31c0b141..af56f770669 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -797,8 +797,15 @@ fn prop_assert_associative( op: impl Fn(Option, Option) -> BlackBoxFuncCall, x: (FieldElement, bool), y: (FieldElement, bool), + z: (FieldElement, bool), ) -> (FieldElement, FieldElement) { - (solve_blackbox_func_call(&op, x, y), solve_blackbox_func_call(&op, y, x)) + let f_xy = (solve_blackbox_func_call(&op, x, y), x.1 ^ y.1); + let f_f_xy_z = solve_blackbox_func_call(&op, f_xy, z); + + let f_yz = (solve_blackbox_func_call(&op, y, z), y.1 ^ z.1); + let f_x_f_yz = solve_blackbox_func_call(&op, x, f_yz); + + (f_f_xy_z, f_x_f_yz) } fn prop_assert_identity_l( @@ -809,14 +816,6 @@ fn prop_assert_identity_l( (solve_blackbox_func_call(op, op_identity, x), x.0) } -fn prop_assert_identity_r( - op: impl Fn(Option, Option) -> BlackBoxFuncCall, - op_identity: (FieldElement, bool), - x: (FieldElement, bool), -) -> (FieldElement, FieldElement) { - (solve_blackbox_func_call(op, x, op_identity), x.0) -} - fn prop_assert_zero_l( op: impl Fn(Option, Option) -> BlackBoxFuncCall, op_zero: (FieldElement, bool), @@ -825,14 +824,6 @@ fn prop_assert_zero_l( (solve_blackbox_func_call(op, op_zero, x), FieldElement::zero()) } -fn prop_assert_zero_r( - op: impl Fn(Option, Option) -> BlackBoxFuncCall, - op_zero: (FieldElement, bool), - x: (FieldElement, bool), -) -> (FieldElement, FieldElement) { - (solve_blackbox_func_call(op, x, op_zero), FieldElement::zero()) -} - prop_compose! { // Use both `u128` and hex proptest strategies fn field_element() @@ -867,14 +858,14 @@ proptest! { } #[test] - fn and_associative(x in field_element(), y in field_element()) { - let (lhs, rhs) = prop_assert_associative(and_op, x, y); + fn and_associative(x in field_element(), y in field_element(), z in field_element()) { + let (lhs, rhs) = prop_assert_associative(and_op, x, y, z); prop_assert_eq!(lhs, rhs); } #[test] - fn xor_associative(x in field_element(), y in field_element()) { - let (lhs, rhs) = prop_assert_associative(xor_op, x, y); + fn xor_associative(x in field_element(), y in field_element(), z in field_element()) { + let (lhs, rhs) = prop_assert_associative(xor_op, x, y, z); prop_assert_eq!(lhs, rhs); } @@ -911,38 +902,10 @@ proptest! { prop_assert_eq!(lhs, rhs); } - // TODO(https://github.com/noir-lang/noir/issues/5597) - #[test] - #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] - fn and_identity_r(x in field_element(), ones_constant: bool) { - let ones = (field_element_ones(), ones_constant); - let (lhs, rhs) = prop_assert_identity_r(and_op, ones, x); - if x <= ones { - prop_assert_eq!(lhs, rhs); - } else { - // TODO - prop_assert!(lhs != rhs); - } - } - - #[test] - fn xor_identity_r(x in field_element(), zero_constant: bool) { - let zero = (FieldElement::zero(), zero_constant); - let (lhs, rhs) = prop_assert_identity_r(xor_op, zero, x); - prop_assert_eq!(lhs, rhs); - } - #[test] fn and_zero_l(x in field_element(), ones_constant: bool) { let zero = (FieldElement::zero(), ones_constant); let (lhs, rhs) = prop_assert_zero_l(and_op, zero, x); prop_assert_eq!(lhs, rhs); } - - #[test] - fn and_zero_r(x in field_element(), ones_constant: bool) { - let zero = (FieldElement::zero(), ones_constant); - let (lhs, rhs) = prop_assert_zero_r(and_op, zero, x); - prop_assert_eq!(lhs, rhs); - } } From 2ed945d76c9e6f8a98bc42f9985bf669f87c5428 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Wed, 24 Jul 2024 18:01:48 -0400 Subject: [PATCH 10/12] fix exponenet in field_element_ones --- acvm-repo/acvm/tests/solver.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index af56f770669..f82fa8d0909 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -839,7 +839,7 @@ prop_compose! { } fn field_element_ones() -> FieldElement { - let exponent: FieldElement = (FieldElement::max_num_bits() as u128).into(); + let exponent: FieldElement = (253 as u128).into(); FieldElement::from(2u128).pow(&exponent) - FieldElement::one() } @@ -881,16 +881,13 @@ proptest! { prop_assert_eq!(solve_blackbox_func_call(xor_op, x, x), FieldElement::zero()); } - // TODO(https://github.com/noir-lang/noir/issues/5597) #[test] - #[should_panic(expected="Test failed: assertion failed: `(left == right)`")] fn and_identity_l(x in field_element(), ones_constant: bool) { let ones = (field_element_ones(), ones_constant); let (lhs, rhs) = prop_assert_identity_l(and_op, ones, x); if x <= ones { prop_assert_eq!(lhs, rhs); } else { - // TODO prop_assert!(lhs != rhs); } } From bddd985c2a5b58b9776edbc88eb1794bceb5f660 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 29 Jul 2024 10:59:53 -0400 Subject: [PATCH 11/12] use proptest-provided use_constant for xy/yz binary operations --- acvm-repo/acvm/tests/solver.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index f82fa8d0909..f4bcb922ed3 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -798,11 +798,13 @@ fn prop_assert_associative( x: (FieldElement, bool), y: (FieldElement, bool), z: (FieldElement, bool), + use_constant_xy: bool, + use_constant_yz: bool, ) -> (FieldElement, FieldElement) { - let f_xy = (solve_blackbox_func_call(&op, x, y), x.1 ^ y.1); + let f_xy = (solve_blackbox_func_call(&op, x, y), use_constant_xy); let f_f_xy_z = solve_blackbox_func_call(&op, f_xy, z); - let f_yz = (solve_blackbox_func_call(&op, y, z), y.1 ^ z.1); + let f_yz = (solve_blackbox_func_call(&op, y, z), use_constant_yz); let f_x_f_yz = solve_blackbox_func_call(&op, x, f_yz); (f_f_xy_z, f_x_f_yz) @@ -858,14 +860,14 @@ proptest! { } #[test] - fn and_associative(x in field_element(), y in field_element(), z in field_element()) { - let (lhs, rhs) = prop_assert_associative(and_op, x, y, z); + fn and_associative(x in field_element(), y in field_element(), z in field_element(), use_constant_xy: bool, use_constant_yz: bool) { + let (lhs, rhs) = prop_assert_associative(and_op, x, y, z, use_constant_xy, use_constant_yz); prop_assert_eq!(lhs, rhs); } #[test] - fn xor_associative(x in field_element(), y in field_element(), z in field_element()) { - let (lhs, rhs) = prop_assert_associative(xor_op, x, y, z); + fn xor_associative(x in field_element(), y in field_element(), z in field_element(), use_constant_xy: bool, use_constant_yz: bool) { + let (lhs, rhs) = prop_assert_associative(xor_op, x, y, z, use_constant_xy, use_constant_yz); prop_assert_eq!(lhs, rhs); } From 5797c703dad0a68b52c28ebbaf9520656585ed7e Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 30 Jul 2024 12:37:59 -0400 Subject: [PATCH 12/12] mark test as expected failure w/ linked issue, cargo clippy --- acvm-repo/acvm/tests/solver.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index f4bcb922ed3..279b0444609 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -841,7 +841,7 @@ prop_compose! { } fn field_element_ones() -> FieldElement { - let exponent: FieldElement = (253 as u128).into(); + let exponent: FieldElement = (253_u128).into(); FieldElement::from(2u128).pow(&exponent) - FieldElement::one() } @@ -866,6 +866,8 @@ proptest! { } #[test] + // TODO(https://github.com/noir-lang/noir/issues/5638) + #[should_panic(expected = "assertion failed: `(left == right)`")] fn xor_associative(x in field_element(), y in field_element(), z in field_element(), use_constant_xy: bool, use_constant_yz: bool) { let (lhs, rhs) = prop_assert_associative(xor_op, x, y, z, use_constant_xy, use_constant_yz); prop_assert_eq!(lhs, rhs);