Skip to content

Commit

Permalink
feat(hashing): Add snippet for hashing stack value
Browse files Browse the repository at this point in the history
Handles padding.

Co-authored-by: Alan Szepieniec <[email protected]>
  • Loading branch information
Sword-Smith and aszepieniec committed Dec 20, 2024
1 parent 137de81 commit 821d7ca
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
24 changes: 24 additions & 0 deletions tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___bfe.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"name": "tasmlib_hashing_hash_from_stack___bfe",
"benchmark_result": {
"clock_cycle_count": 34,
"hash_table_height": 55,
"u32_table_height": 0,
"op_stack_table_height": 34,
"ram_table_height": 0
},
"case": "CommonCase"
},
{
"name": "tasmlib_hashing_hash_from_stack___bfe",
"benchmark_result": {
"clock_cycle_count": 34,
"hash_table_height": 55,
"u32_table_height": 0,
"op_stack_table_height": 34,
"ram_table_height": 0
},
"case": "WorstCase"
}
]
24 changes: 24 additions & 0 deletions tasm-lib/benchmarks/tasmlib_hashing_hash_from_stack___digest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"name": "tasmlib_hashing_hash_from_stack___digest",
"benchmark_result": {
"clock_cycle_count": 26,
"hash_table_height": 43,
"u32_table_height": 0,
"op_stack_table_height": 30,
"ram_table_height": 0
},
"case": "CommonCase"
},
{
"name": "tasmlib_hashing_hash_from_stack___digest",
"benchmark_result": {
"clock_cycle_count": 26,
"hash_table_height": 43,
"u32_table_height": 0,
"op_stack_table_height": 30,
"ram_table_height": 0
},
"case": "WorstCase"
}
]
1 change: 1 addition & 0 deletions tasm-lib/src/hashing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod absorb_multiple;
pub mod absorb_multiple_static_size;
pub mod algebraic_hasher;
pub mod eq_digest;
pub mod hash_from_stack;
pub mod lt_digest;
pub mod merkle_root;
pub mod merkle_root_from_xfes_generic;
Expand Down
170 changes: 170 additions & 0 deletions tasm-lib/src/hashing/hash_from_stack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use triton_vm::isa::triton_asm;
use triton_vm::prelude::LabelledInstruction;
use triton_vm::prelude::Tip5;
use triton_vm::twenty_first::prelude::Sponge;

use crate::data_type::DataType;
use crate::library::Library;
use crate::prelude::BasicSnippet;

pub struct HashFromStack {
pub data_type: DataType,
}

impl BasicSnippet for HashFromStack {
fn inputs(&self) -> Vec<(DataType, String)> {
vec![(self.data_type.clone(), "preimage".to_string())]
}

fn outputs(&self) -> Vec<(DataType, String)> {
vec![(DataType::Digest, "digest".to_string())]
}

fn entrypoint(&self) -> String {
format!(
"tasmlib_hashing_hash_from_stack___{}",
self.data_type.label_friendly_name()
)
}

fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
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!(
push 0
place {preimage_size}
);

// _ 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 entrypoint = self.entrypoint();
triton_asm!(
{entrypoint}:

{&pad}
// _ [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

return
)
}
}

#[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;

impl Closure for HashFromStack {
fn rust_shadow(&self, stack: &mut Vec<triton_vm::prelude::BFieldElement>) {
let mut preimage = vec![];
for _ in 0..self.data_type.stack_size() {
preimage.push(stack.pop().unwrap());
}

let digest = Tip5::hash_varlen(&preimage);

push_encodable(stack, &digest);
}

type Args = Vec<BFieldElement>;

fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
let mut rng = StdRng::from_seed(seed);

self.data_type.seeded_random_element(&mut rng)
}

fn set_up_test_stack(&self, args: Self::Args) -> Vec<BFieldElement> {
let mut stack = self.init_stack_for_isolated_run();
for b in args.iter().rev() {
stack.push(*b);
}
stack
}
}

#[test]
fn hash_from_stack_pbt() {
let primitives = [
DataType::Bool,
DataType::U32,
DataType::U64,
DataType::U128,
DataType::Bfe,
DataType::Xfe,
DataType::Digest,
];
for data_type in primitives {
ShadowedClosure::new(HashFromStack { data_type }).test();
}
}
}

#[cfg(test)]
mod benches {
use super::*;
use crate::traits::closure::ShadowedClosure;
use crate::traits::rust_shadow::RustShadow;

#[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()
}
}

0 comments on commit 821d7ca

Please sign in to comment.