diff --git a/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___bfe.json b/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___bfe.json index 35751dbe..3f0058fe 100644 --- a/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___bfe.json +++ b/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___bfe.json @@ -2,8 +2,8 @@ { "name": "tasmlib_hashing_hash_from_stack___bfe", "benchmark_result": { - "clock_cycle_count": 34, - "hash_table_height": 55, + "clock_cycle_count": 30, + "hash_table_height": 49, "u32_table_height": 0, "op_stack_table_height": 34, "ram_table_height": 0 @@ -13,8 +13,8 @@ { "name": "tasmlib_hashing_hash_from_stack___bfe", "benchmark_result": { - "clock_cycle_count": 34, - "hash_table_height": 55, + "clock_cycle_count": 30, + "hash_table_height": 49, "u32_table_height": 0, "op_stack_table_height": 34, "ram_table_height": 0 diff --git a/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___digest.json b/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___digest.json index 8136bb02..249fb627 100644 --- a/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___digest.json +++ b/tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___digest.json @@ -2,8 +2,8 @@ { "name": "tasmlib_hashing_hash_from_stack___digest", "benchmark_result": { - "clock_cycle_count": 26, - "hash_table_height": 43, + "clock_cycle_count": 22, + "hash_table_height": 37, "u32_table_height": 0, "op_stack_table_height": 30, "ram_table_height": 0 @@ -13,8 +13,8 @@ { "name": "tasmlib_hashing_hash_from_stack___digest", "benchmark_result": { - "clock_cycle_count": 26, - "hash_table_height": 43, + "clock_cycle_count": 22, + "hash_table_height": 37, "u32_table_height": 0, "op_stack_table_height": 30, "ram_table_height": 0 diff --git a/tasm-lib/src/hashing/hash_from_stack.rs b/tasm-lib/src/hashing/hash_from_stack.rs index 4c7ccf15..cd265831 100644 --- a/tasm-lib/src/hashing/hash_from_stack.rs +++ b/tasm-lib/src/hashing/hash_from_stack.rs @@ -1,21 +1,33 @@ -use triton_vm::isa::triton_asm; -use triton_vm::prelude::LabelledInstruction; -use triton_vm::prelude::Tip5; -use triton_vm::twenty_first::prelude::Sponge; +use triton_vm::prelude::*; +use twenty_first::prelude::*; -use crate::data_type::DataType; -use crate::library::Library; -use crate::prelude::BasicSnippet; +use crate::prelude::*; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct HashFromStack { - pub data_type: DataType, + ty: DataType, + ty_len: usize, +} + +impl HashFromStack { + /// # Panics + /// + /// Panics if the argument does not have statically-known length, or if that + /// length is larger than or equal to [`Tip5::RATE`]. + pub fn new(ty: DataType) -> Self { + let ty_len = ty + .static_length() + .expect("data type to hash should have static length"); + assert!(ty_len < Tip5::RATE, "type length should be small"); + + Self { ty, ty_len } + } } impl BasicSnippet for HashFromStack { fn inputs(&self) -> Vec<(DataType, String)> { - vec![(self.data_type.clone(), "preimage".to_string())] + vec![(self.ty.clone(), "preimage".to_string())] } - fn outputs(&self) -> Vec<(DataType, String)> { vec![(DataType::Digest, "digest".to_string())] } @@ -23,64 +35,41 @@ impl BasicSnippet for HashFromStack { fn entrypoint(&self) -> String { format!( "tasmlib_hashing_hash_from_stack___{}", - self.data_type.label_friendly_name() + self.ty.label_friendly_name() ) } - fn code(&self, _library: &mut Library) -> Vec { - let preimage_size = self.data_type.stack_size(); - let size = self - .data_type - .static_length() - .expect("Can only hash static-length data types from stack"); - assert_eq!( - size, preimage_size, - "Can only hash types that live on stack" - ); - assert!( - preimage_size < Tip5::RATE, - "This snippet assumes small preimage size" - ); - - let num_zeros_in_pad = Tip5::RATE - preimage_size - 1; - let zero_padding = triton_asm!( + fn code(&self, _: &mut Library) -> Vec { + let pad_single_zero = triton_asm!( push 0 - place {preimage_size} + place {self.ty_len} ); - // _ val 0 - - // _ 0 val - let zero_padding = vec![zero_padding; num_zeros_in_pad].concat(); - let one_pad = triton_asm!( - push 1 - place {preimage_size} - ); - - let pad = triton_asm!( - // _ [preimage: data_type] - {&zero_padding} - {&one_pad} - - // _ [0, 0..0] 1 [preimage] - ); + let num_zeros_in_pad = Tip5::RATE - self.ty_len - 1; + let pad_zeros = vec![pad_single_zero; num_zeros_in_pad].concat(); let entrypoint = self.entrypoint(); triton_asm!( {entrypoint}: - {&pad} + {&pad_zeros} + // _ [0, …, 0] [preimage] + + push 1 + place {self.ty_len} + // _ [0, …, 0] 1 [preimage] // _ [padded-preimage] sponge_init sponge_absorb sponge_squeeze - pick 5 pop 1 - pick 5 pop 1 - pick 5 pop 1 - pick 5 pop 1 - pick 5 pop 1 + pick 9 + pick 9 + pick 9 + pick 9 + pick 9 + pop 5 return ) @@ -89,49 +78,36 @@ impl BasicSnippet for HashFromStack { #[cfg(test)] mod tests { - use rand::rngs::StdRng; - use rand::SeedableRng; - use triton_vm::prelude::BFieldElement; - use super::*; - use crate::push_encodable; - use crate::snippet_bencher::BenchmarkCase; - use crate::traits::closure::Closure; - use crate::traits::closure::ShadowedClosure; - use crate::traits::rust_shadow::RustShadow; + use crate::test_prelude::*; impl Closure for HashFromStack { - fn rust_shadow(&self, stack: &mut Vec) { + type Args = Vec; + + fn rust_shadow(&self, stack: &mut Vec) { let mut preimage = vec![]; - for _ in 0..self.data_type.stack_size() { + for _ in 0..self.ty_len { preimage.push(stack.pop().unwrap()); } - let digest = Tip5::hash_varlen(&preimage); - - push_encodable(stack, &digest); + push_encodable(stack, &Tip5::hash_varlen(&preimage)); } - type Args = Vec; - fn pseudorandom_args(&self, seed: [u8; 32], _: Option) -> Self::Args { - let mut rng = StdRng::from_seed(seed); - - self.data_type.seeded_random_element(&mut rng) + self.ty.seeded_random_element(&mut StdRng::from_seed(seed)) } fn set_up_test_stack(&self, args: Self::Args) -> Vec { let mut stack = self.init_stack_for_isolated_run(); - for b in args.iter().rev() { - stack.push(*b); - } + stack.extend(args.into_iter().rev()); + stack } } #[test] - fn hash_from_stack_pbt() { - let primitives = [ + fn unit() { + let types = [ DataType::Bool, DataType::U32, DataType::U64, @@ -140,8 +116,8 @@ mod tests { DataType::Xfe, DataType::Digest, ]; - for data_type in primitives { - ShadowedClosure::new(HashFromStack { data_type }).test(); + for data_type in types { + ShadowedClosure::new(HashFromStack::new(data_type)).test(); } } } @@ -149,22 +125,13 @@ mod tests { #[cfg(test)] mod benches { use super::*; - use crate::traits::closure::ShadowedClosure; - use crate::traits::rust_shadow::RustShadow; + use crate::test_prelude::*; #[test] - fn hash_from_stack_bench_bfe() { - ShadowedClosure::new(HashFromStack { - data_type: DataType::Bfe, - }) - .bench() - } - - #[test] - fn hash_from_stack_bench_digest() { - ShadowedClosure::new(HashFromStack { - data_type: DataType::Digest, - }) - .bench() + fn benchmark() { + let types = [DataType::Bfe, DataType::Digest]; + for data_type in types { + ShadowedClosure::new(HashFromStack::new(data_type)).bench(); + } } }