diff --git a/tasm-lib/benchmarks/tasmlib_test_compare_Bfe.json b/tasm-lib/benchmarks/tasmlib_test_compare_Bfe.json new file mode 100644 index 00000000..c5f29145 --- /dev/null +++ b/tasm-lib/benchmarks/tasmlib_test_compare_Bfe.json @@ -0,0 +1,24 @@ +[ + { + "name": "tasmlib_test_compare_Bfe", + "benchmark_result": { + "clock_cycle_count": 4, + "hash_table_height": 6, + "u32_table_height": 0, + "op_stack_table_height": 1, + "ram_table_height": 0 + }, + "case": "CommonCase" + }, + { + "name": "tasmlib_test_compare_Bfe", + "benchmark_result": { + "clock_cycle_count": 4, + "hash_table_height": 6, + "u32_table_height": 0, + "op_stack_table_height": 1, + "ram_table_height": 0 + }, + "case": "WorstCase" + } +] \ No newline at end of file diff --git a/tasm-lib/benchmarks/tasmlib_test_compare_Digest.json b/tasm-lib/benchmarks/tasmlib_test_compare_Digest.json new file mode 100644 index 00000000..4012bf3c --- /dev/null +++ b/tasm-lib/benchmarks/tasmlib_test_compare_Digest.json @@ -0,0 +1,24 @@ +[ + { + "name": "tasmlib_test_compare_Digest", + "benchmark_result": { + "clock_cycle_count": 17, + "hash_table_height": 18, + "u32_table_height": 0, + "op_stack_table_height": 9, + "ram_table_height": 0 + }, + "case": "CommonCase" + }, + { + "name": "tasmlib_test_compare_Digest", + "benchmark_result": { + "clock_cycle_count": 17, + "hash_table_height": 18, + "u32_table_height": 0, + "op_stack_table_height": 9, + "ram_table_height": 0 + }, + "case": "WorstCase" + } +] \ No newline at end of file diff --git a/tasm-lib/src/data_type.rs b/tasm-lib/src/data_type.rs index 80e3477b..7131948e 100644 --- a/tasm-lib/src/data_type.rs +++ b/tasm-lib/src/data_type.rs @@ -661,3 +661,81 @@ mod tests { prop_assert!(<[[Digest; INNER_LEN]; OUTER_LEN]>::decode(&array).is_ok()); } } + +/// Test [`DataType::compare`] by wrapping it in [`BasicSnippet`] and +/// implementing [`RustShadow`] for it. +#[cfg(test)] +mod compare_literals { + use super::*; + use crate::prelude::*; + use crate::test_prelude::*; + + macro_rules! comparison_snippet { + ($name:ident for tasm_ty $tasm_ty:ident and rust_ty $rust_ty:ident) => { + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] + struct $name; + + impl BasicSnippet for $name { + fn inputs(&self) -> Vec<(DataType, String)> { + ["left", "right"] + .map(|s| (DataType::$tasm_ty, s.to_string())) + .to_vec() + } + + fn outputs(&self) -> Vec<(DataType, String)> { + vec![(DataType::Bool, "are_eq".to_string())] + } + + fn entrypoint(&self) -> String { + let ty = stringify!($tasm_ty); + format!("tasmlib_test_compare_{ty}") + } + + fn code(&self, _: &mut Library) -> Vec { + triton_asm!({self.entrypoint()}: {&DataType::$tasm_ty.compare()} return) + } + } + + impl Closure for $name { + type Args = ($rust_ty, $rust_ty); + + fn rust_shadow(&self, stack: &mut Vec) { + let (right, left) = pop_encodable::(stack); + push_encodable(stack, &(left == right)); + } + + fn pseudorandom_args( + &self, + seed: [u8; 32], + _: Option + ) -> Self::Args { + // almost certainly different arguments, comparison gives `false` + StdRng::from_seed(seed).gen() + } + + fn corner_case_args(&self) -> Vec { + // identical arguments, comparison gives `true` + vec![Self::Args::default()] + } + } + }; + } + + // stack size == 1 + comparison_snippet!(CompareBfes for tasm_ty Bfe and rust_ty BFieldElement); + + // stack size > 1 + comparison_snippet!(CompareDigests for tasm_ty Digest and rust_ty Digest); + + #[test] + fn test() { + ShadowedClosure::new(CompareBfes).test(); + ShadowedClosure::new(CompareDigests).test(); + } + + #[test] + fn bench() { + ShadowedClosure::new(CompareBfes).bench(); + ShadowedClosure::new(CompareDigests).bench(); + } +}