From 384663798c186d42b5afce7d506db6e009c836f1 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Fri, 9 Aug 2024 14:46:13 +0200 Subject: [PATCH] baby bear test --- pipeline/src/test_util.rs | 25 ++++++++- pipeline/tests/asm.rs | 21 ++++---- pipeline/tests/powdr_std.rs | 16 +++++- std/machines/binary_bb.asm | 65 ++++++++++++++++++++++ std/machines/mod.asm | 3 +- test_data/std/binary_bb_test_16.asm | 73 +++++++++++++++++++++++++ test_data/std/binary_bb_test_8.asm | 83 +++++++++++++++++++++++++++++ 7 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 std/machines/binary_bb.asm create mode 100644 test_data/std/binary_bb_test_16.asm create mode 100644 test_data/std/binary_bb_test_8.asm diff --git a/pipeline/src/test_util.rs b/pipeline/src/test_util.rs index f0f1818cd..90aa523ef 100644 --- a/pipeline/src/test_util.rs +++ b/pipeline/src/test_util.rs @@ -1,6 +1,8 @@ use powdr_ast::analyzed::Analyzed; use powdr_backend::BackendType; -use powdr_number::{buffered_write_file, BigInt, Bn254Field, FieldElement, GoldilocksField}; +use powdr_number::{ + buffered_write_file, BabyBearField, BigInt, Bn254Field, FieldElement, GoldilocksField, +}; use powdr_pil_analyzer::evaluator::{self, SymbolLookup}; use std::path::PathBuf; use std::{env, fs}; @@ -69,6 +71,27 @@ pub fn regular_test(file_name: &str, inputs: &[i32]) { let inputs_bn = inputs.iter().map(|x| Bn254Field::from(*x)).collect(); let pipeline_bn = make_prepared_pipeline(file_name, inputs_bn, vec![]); test_halo2(pipeline_bn); + + let inputs_bb = inputs.iter().map(|x| BabyBearField::from(*x)).collect(); + let mut pipeline_bb = make_prepared_pipeline(file_name, inputs_bb, vec![]); + pipeline_bb.compute_witness().unwrap(); +} + +pub fn regular_test_only_babybear(file_name: &str, inputs: &[i32]) { + let inputs_bb = inputs.iter().map(|x| BabyBearField::from(*x)).collect(); + let mut pipeline_bb = make_prepared_pipeline(file_name, inputs_bb, vec![]); + pipeline_bb.compute_witness().unwrap(); +} + +pub fn regular_test_without_babybear(file_name: &str, inputs: &[i32]) { + let inputs_gl = inputs.iter().map(|x| GoldilocksField::from(*x)).collect(); + let pipeline_gl = make_prepared_pipeline(file_name, inputs_gl, vec![]); + test_pilcom(pipeline_gl.clone()); + gen_estark_proof(pipeline_gl); + + let inputs_bn = inputs.iter().map(|x| Bn254Field::from(*x)).collect(); + let pipeline_bn = make_prepared_pipeline(file_name, inputs_bn, vec![]); + test_halo2(pipeline_bn); } pub fn test_pilcom(pipeline: Pipeline) { diff --git a/pipeline/tests/asm.rs b/pipeline/tests/asm.rs index 906290d28..7e29229be 100644 --- a/pipeline/tests/asm.rs +++ b/pipeline/tests/asm.rs @@ -6,9 +6,10 @@ use powdr_number::{Bn254Field, FieldElement, GoldilocksField}; use powdr_pipeline::{ test_util::{ asm_string_to_pil, gen_estark_proof_with_backend_variant, make_prepared_pipeline, - make_simple_prepared_pipeline, regular_test, resolve_test_file, - run_pilcom_with_backend_variant, test_halo2, test_halo2_with_backend_variant, test_pilcom, - test_plonky3_with_backend_variant, BackendVariant, + make_simple_prepared_pipeline, regular_test, regular_test_without_babybear, + resolve_test_file, run_pilcom_with_backend_variant, test_halo2, + test_halo2_with_backend_variant, test_pilcom, test_plonky3_with_backend_variant, + BackendVariant, }, util::{FixedPolySet, PolySet, WitnessPolySet}, Pipeline, @@ -292,7 +293,7 @@ fn multi_return_wrong_assignment_register_length() { fn bit_access() { let f = "asm/bit_access.asm"; let i = [20]; - regular_test(f, &i); + regular_test_without_babybear(f, &i); } #[test] @@ -305,7 +306,7 @@ fn sqrt() { fn functional_instructions() { let f = "asm/functional_instructions.asm"; let i = [20]; - regular_test(f, &i); + regular_test_without_babybear(f, &i); } #[test] @@ -387,13 +388,13 @@ fn multiple_signatures() { #[test] fn permutation_simple() { let f = "asm/permutations/simple.asm"; - regular_test(f, Default::default()); + regular_test_without_babybear(f, Default::default()); } #[test] fn permutation_to_block() { let f = "asm/permutations/vm_to_block.asm"; - regular_test(f, Default::default()); + regular_test_without_babybear(f, Default::default()); } #[test] @@ -407,7 +408,7 @@ fn permutation_to_vm() { #[test] fn permutation_to_block_to_block() { let f = "asm/permutations/block_to_block.asm"; - regular_test(f, Default::default()); + regular_test_without_babybear(f, Default::default()); } #[test] @@ -420,14 +421,14 @@ fn permutation_incoming_needs_selector() { #[test] fn call_selectors_with_no_permutation() { let f = "asm/permutations/call_selectors_with_no_permutation.asm"; - regular_test(f, Default::default()); + regular_test_without_babybear(f, Default::default()); } #[test] #[ignore = "Too slow"] fn vm_args() { let f = "asm/vm_args.asm"; - regular_test(f, Default::default()); + regular_test_without_babybear(f, Default::default()); } #[test] diff --git a/pipeline/tests/powdr_std.rs b/pipeline/tests/powdr_std.rs index 71a617582..f46f0d972 100644 --- a/pipeline/tests/powdr_std.rs +++ b/pipeline/tests/powdr_std.rs @@ -6,8 +6,8 @@ use powdr_pil_analyzer::evaluator::Value; use powdr_pipeline::{ test_util::{ evaluate_function, evaluate_integer_function, execute_test_file, gen_estark_proof, - gen_halo2_proof, make_simple_prepared_pipeline, regular_test, std_analyzed, test_halo2, - test_pilcom, BackendVariant, + gen_halo2_proof, make_simple_prepared_pipeline, regular_test, regular_test_only_babybear, + std_analyzed, test_halo2, test_pilcom, BackendVariant, }, Pipeline, }; @@ -182,6 +182,18 @@ fn binary_test() { test_halo2(make_simple_prepared_pipeline(f)); } +#[test] +fn binary_bb_8_test() { + let f = "std/binary_bb_test_8.asm"; + regular_test_only_babybear(f, &[]); +} + +#[test] +fn binary_bb_16_test() { + let f = "std/binary_bb_test_16.asm"; + regular_test_only_babybear(f, &[]); +} + #[test] #[ignore = "Too slow"] fn shift_test() { diff --git a/std/machines/binary_bb.asm b/std/machines/binary_bb.asm new file mode 100644 index 000000000..ec2ff4274 --- /dev/null +++ b/std/machines/binary_bb.asm @@ -0,0 +1,65 @@ +use std::convert::int; +use std::utils::cross_product; +use std::utils::unchanged_until; +use std::machines::binary::ByteBinary; + +// Computes bitwise operations on two 32-bit numbers +// decomposed into 4 bytes each. +machine Binary8(byte_binary: ByteBinary) with + latch: latch, + operation_id: operation_id, + // Allow this machine to be connected via a permutation + call_selectors: sel, +{ + operation and<0> A1, A2, A3, A4, B1, B2, B3, B4 -> C1, C2, C3, C4; + + operation or<1> A1, A2, A3, A4, B1, B2, B3, B4 -> C1, C2, C3, C4; + + operation xor<2> A1, A2, A3, A4, B1, B2, B3, B4 -> C1, C2, C3, C4; + + col witness operation_id; + + col fixed latch(i) { 1 }; + + col witness A1, A2, A3, A4; + col witness B1, B2, B3, B4; + col witness C1, C2, C3, C4; + + link => C1 = byte_binary.run(operation_id, A1, B1); + link => C2 = byte_binary.run(operation_id, A2, B2); + link => C3 = byte_binary.run(operation_id, A3, B3); + link => C4 = byte_binary.run(operation_id, A4, B4); +} + +// Computes bitwise operations on two 32-bit numbers +// decomposed into two 16-bit limbs each. +machine Binary16(byte_binary: ByteBinary) with + latch: latch, + operation_id: operation_id, + // Allow this machine to be connected via a permutation + call_selectors: sel, +{ + operation and<0> I1, I2, I3, I4 -> O1, O2; + operation or<1> I1, I2, I3, I4 -> O1, O2; + operation xor<2> I1, I2, I3, I4 -> O1, O2; + + col witness operation_id; + + col fixed latch(i) { 1 }; + + let I1: inter = A1 + 256 * A2; + let I2: inter = A3 + 256 * A4; + let I3: inter = B1 + 256 * B2; + let I4: inter = B3 + 256 * B4; + let O1: inter = C1 + 256 * C2; + let O2: inter = C3 + 256 * C4; + + col witness A1, A2, A3, A4; + col witness B1, B2, B3, B4; + col witness C1, C2, C3, C4; + + link => C1 = byte_binary.run(operation_id, A1, B1); + link => C2 = byte_binary.run(operation_id, A2, B2); + link => C3 = byte_binary.run(operation_id, A3, B3); + link => C4 = byte_binary.run(operation_id, A4, B4); +} diff --git a/std/machines/mod.asm b/std/machines/mod.asm index 5e0306287..d059419c1 100644 --- a/std/machines/mod.asm +++ b/std/machines/mod.asm @@ -1,9 +1,10 @@ mod arith; mod binary; +mod binary_bb; mod range; mod hash; mod memory; mod memory_with_bootloader_write; mod shift; mod split; -mod write_once_memory; \ No newline at end of file +mod write_once_memory; diff --git a/test_data/std/binary_bb_test_16.asm b/test_data/std/binary_bb_test_16.asm new file mode 100644 index 000000000..a2c2035de --- /dev/null +++ b/test_data/std/binary_bb_test_16.asm @@ -0,0 +1,73 @@ +use std::machines::binary::ByteBinary; +use std::machines::binary_bb::Binary16; + +machine Main { + reg pc[@pc]; + reg X0_1[<=]; + reg X0_2[<=]; + reg X1_1[<=]; + reg X1_2[<=]; + reg X2_1[<=]; + reg X2_2[<=]; + reg A1; + reg A2; + + ByteBinary byte_binary; + Binary16 binary(byte_binary); + + instr and X0_1, X0_2, X1_1, X1_2 -> X2_1, X2_2 link ~> (X2_1, X2_2) = binary.and(X0_1, X0_2, X1_1, X1_2); + instr or X0_1, X0_2, X1_1, X1_2 -> X2_1, X2_2 link ~> (X2_1, X2_2) = binary.or(X0_1, X0_2, X1_1, X1_2); + instr xor X0_1, X0_2, X1_1, X1_2 -> X2_1, X2_2 link ~> (X2_1, X2_2) = binary.xor(X0_1, X0_2, X1_1, X1_2); + + instr assert_eq X0_1, X0_2, X1_1, X1_2 { + X0_1 = X1_1, + X0_2 = X1_2 + } + + function main { + + // AND + A1, A2 <== and(0, 0, 0, 0); + assert_eq A1, A2, 0, 0; + A1, A2 <== and(0xffff, 0xffff, 0xffff, 0xffff); + assert_eq A1, A2, 0xffff, 0xffff; + A1, A2 <== and(0xffff, 0xffff, 0xabcd, 0xef01); + assert_eq A1, A2, 0xabcd, 0xef01; + A1, A2 <== and(0xabcd, 0xef01, 0xffff, 0xffff); + assert_eq A1, A2, 0xabcd, 0xef01; + A1, A2 <== and(0, 0, 0xabcd, 0xef01); + assert_eq A1, A2, 0, 0; + A1, A2 <== and(0xabcd, 0xef01, 0, 0); + assert_eq A1, A2, 0, 0; + + // OR + A1, A2 <== or(0, 0, 0, 0); + assert_eq A1, A2, 0, 0; + A1, A2 <== or(0xffff, 0xffff, 0xffff, 0xffff); + assert_eq A1, A2, 0xffff, 0xffff; + A1, A2 <== or(0xffff, 0xffff, 0xabcd, 0xef01); + assert_eq A1, A2, 0xffff, 0xffff; + A1, A2 <== or(0xabcd, 0xef01, 0xffff, 0xffff); + assert_eq A1, A2, 0xffff, 0xffff; + A1, A2 <== or(0, 0, 0xabcd, 0xef01); + assert_eq A1, A2, 0xabcd, 0xef01; + A1, A2 <== or(0xabcd, 0xef01, 0, 0); + assert_eq A1, A2, 0xabcd, 0xef01; + + // XOR + A1, A2 <== xor(0, 0, 0, 0); + assert_eq A1, A2, 0, 0; + A1, A2 <== xor(0xffff, 0xffff, 0xffff, 0xffff); + assert_eq A1, A2, 0, 0; + A1, A2 <== xor(0xffff, 0xffff, 0xabcd, 0xef01); + assert_eq A1, A2, 0x5432, 0x10fe; + A1, A2 <== xor(0xabcd, 0xef01, 0xffff, 0xffff); + assert_eq A1, A2, 0x5432, 0x10fe; + A1, A2 <== xor(0, 0, 0xabcd, 0xef01); + assert_eq A1, A2, 0xabcd, 0xef01; + A1, A2 <== xor(0xabcd, 0xef01, 0, 0); + assert_eq A1, A2, 0xabcd, 0xef01; + + return; + } +} diff --git a/test_data/std/binary_bb_test_8.asm b/test_data/std/binary_bb_test_8.asm new file mode 100644 index 000000000..5203d1177 --- /dev/null +++ b/test_data/std/binary_bb_test_8.asm @@ -0,0 +1,83 @@ +use std::machines::binary::ByteBinary; +use std::machines::binary_bb::Binary8; + +machine Main { + reg pc[@pc]; + reg X0_1[<=]; + reg X0_2[<=]; + reg X0_3[<=]; + reg X0_4[<=]; + reg X1_1[<=]; + reg X1_2[<=]; + reg X1_3[<=]; + reg X1_4[<=]; + reg X2_1[<=]; + reg X2_2[<=]; + reg X2_3[<=]; + reg X2_4[<=]; + reg A1; + reg A2; + reg A3; + reg A4; + + ByteBinary byte_binary; + Binary8 binary(byte_binary); + + instr and X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4 -> X2_1, X2_2, X2_3, X2_4 link ~> (X2_1, X2_2, X2_3, X2_4) = binary.and(X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4); + instr or X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4 -> X2_1, X2_2, X2_3, X2_4 link ~> (X2_1, X2_2, X2_3, X2_4) = binary.or(X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4); + instr xor X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4 -> X2_1, X2_2, X2_3, X2_4 link ~> (X2_1, X2_2, X2_3, X2_4) = binary.xor(X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4); + + instr assert_eq X0_1, X0_2, X0_3, X0_4, X1_1, X1_2, X1_3, X1_4 { + X0_1 = X1_1, + X0_2 = X1_2, + X0_3 = X1_3, + X0_4 = X1_4 + } + + function main { + + // AND + A1, A2, A3, A4 <== and(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + A1, A2, A3, A4 <== and(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0xff, 0xff, 0xff, 0xff; + A1, A2, A3, A4 <== and(0xff, 0xff, 0xff, 0xff, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + A1, A2, A3, A4 <== and(0xab, 0xcd, 0xef, 0x01, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + A1, A2, A3, A4 <== and(0, 0, 0, 0, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + A1, A2, A3, A4 <== and(0xab, 0xcd, 0xef, 0x01, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + + // OR + A1, A2, A3, A4 <== or(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + A1, A2, A3, A4 <== or(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0xff, 0xff, 0xff, 0xff; + A1, A2, A3, A4 <== or(0xff, 0xff, 0xff, 0xff, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0xff, 0xff, 0xff, 0xff; + A1, A2, A3, A4 <== or(0xab, 0xcd, 0xef, 0x01, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0xff, 0xff, 0xff, 0xff; + A1, A2, A3, A4 <== or(0, 0, 0, 0, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + A1, A2, A3, A4 <== or(0xab, 0xcd, 0xef, 0x01, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + + // XOR + A1, A2, A3, A4 <== xor(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + A1, A2, A3, A4 <== xor(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0, 0, 0, 0; + A1, A2, A3, A4 <== xor(0xff, 0xff, 0xff, 0xff, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0x54, 0x32, 0x10, 0xfe; + A1, A2, A3, A4 <== xor(0xab, 0xcd, 0xef, 0x01, 0xff, 0xff, 0xff, 0xff); + assert_eq A1, A2, A3, A4, 0x54, 0x32, 0x10, 0xfe; + A1, A2, A3, A4 <== xor(0, 0, 0, 0, 0xab, 0xcd, 0xef, 0x01); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + A1, A2, A3, A4 <== xor(0xab, 0xcd, 0xef, 0x01, 0, 0, 0, 0); + assert_eq A1, A2, A3, A4, 0xab, 0xcd, 0xef, 0x01; + + return; + } +}