Skip to content

Commit 0025213

Browse files
committed
feat(Tip5): Implement the Hasher trait
1 parent 3c3f8c9 commit 0025213

File tree

2 files changed

+76
-26
lines changed

2 files changed

+76
-26
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{"run_id":"1737004691-776210000","line":1125,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1125,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
2+
{"run_id":"1737005332-659153000","line":1126,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1126,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
3+
{"run_id":"1737005430-865390000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
4+
{"run_id":"1737005484-271770000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
5+
{"run_id":"1737005663-950269000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
6+
{"run_id":"1737005725-704108000","line":1131,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1131,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
7+
{"run_id":"1737010830-827085000","line":1131,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1131,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
8+
{"run_id":"1737032423-694383000","line":1132,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1132,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
9+
{"run_id":"1737033651-521588000","line":1132,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1132,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
10+
{"run_id":"1737033749-518564000","line":1133,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1133,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
11+
{"run_id":"1737034121-406118000","line":1135,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1135,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
12+
{"run_id":"1737051515-362873000","line":1128,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1128,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
13+
{"run_id":"1737051583-786216000","line":1130,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1130,"expression":"hasher.finish()"},"snapshot":"9513097171871388188"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
14+
{"run_id":"1737051918-936300000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"18293136500878598682"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
15+
{"run_id":"1737052243-557195000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"9513097171871388188"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
16+
{"run_id":"1737052246-136778000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"9513097171871388188"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
17+
{"run_id":"1737052249-861590000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"9513097171871388188"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
18+
{"run_id":"1737052266-837782000","line":1127,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1127,"expression":"hasher.finish()"},"snapshot":"9513097171871388188"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"12804282289674824842"}}
19+
{"run_id":"1737052568-331893000","line":1128,"new":null,"old":null}
20+
{"run_id":"1737053907-874238000","line":1129,"new":null,"old":null}
21+
{"run_id":"1737054343-651840000","line":1132,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1132,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"9513097171871388188"}}
22+
{"run_id":"1737054409-462933000","line":1132,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1132,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"9513097171871388188"}}
23+
{"run_id":"1737054739-176138000","line":1135,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1135,"expression":"hasher.finish()"},"snapshot":"2267905471610932299"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"9513097171871388188"}}
24+
{"run_id":"1737054913-67704000","line":1125,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1125,"expression":"hasher.finish()"},"snapshot":"0"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"9513097171871388188"}}
25+
{"run_id":"1737054939-285996000","line":1125,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1125,"expression":"hasher.finish()"},"snapshot":"2267905471610932299"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"9513097171871388188"}}
26+
{"run_id":"1737055013-39645000","line":1125,"new":null,"old":null}
27+
{"run_id":"1737055030-402477000","line":1125,"new":{"module_name":"twenty_first__math__tip5__tip5_tests","snapshot_name":"tip5_hasher_trait_test","metadata":{"source":"twenty-first/src/math/tip5.rs","assertion_line":1125,"expression":"hasher.finish()"},"snapshot":"14282602120724301820"},"old":{"module_name":"twenty_first__math__tip5__tip5_tests","metadata":{},"snapshot":"2267905471610932299"}}

twenty-first/src/math/tip5.rs

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -676,39 +676,38 @@ impl Sponge for Tip5 {
676676
}
677677

678678
impl Hasher for Tip5 {
679-
fn write(&mut self, bytes: &[u8]) {
680-
// Convert input bytes into BFieldElements and absorb them in chunks of `RATE`
681-
let mut bfield_elements = bytes
682-
.chunks(8) // Assuming each `BFieldElement` corresponds to 8 bytes
683-
.map(|chunk| {
684-
let mut buffer = [0u8; 8];
685-
buffer[..chunk.len()].copy_from_slice(chunk);
686-
BFieldElement::from_raw_u64(u64::from_le_bytes(buffer))
687-
});
688-
689-
// Absorb the data in chunks
690-
while let Ok(chunk) = bfield_elements
691-
.by_ref()
692-
.take(Tip5::RATE)
693-
.collect::<Vec<_>>()
694-
.try_into()
695-
{
696-
self.absorb(chunk);
697-
}
679+
fn finish(&self) -> u64 {
680+
self.state[0].value()
698681
}
699682

700-
/// Produce a 64-bit hash value from the sponge's state
701-
fn finish(&self) -> u64 {
702-
// Extract the first part of the state as the hash value
703-
self.state[0].raw_u64()
683+
fn write(&mut self, bytes: &[u8]) {
684+
let bfield_elements = bytes.chunks(BFieldElement::BYTES).map(|chunk| {
685+
let mut buffer = [0u8; BFieldElement::BYTES];
686+
buffer[..chunk.len()].copy_from_slice(chunk);
687+
BFieldElement::new(u64::from_le_bytes(buffer))
688+
});
689+
690+
let binding: Vec<BFieldElement> = bfield_elements.collect();
691+
let bfield_absorb_chunks = binding.chunks(Tip5::RATE);
692+
693+
bfield_absorb_chunks.for_each(|absorb_rate_chunk| {
694+
let mut asborb_chunk_buffer: [BFieldElement; Tip5::RATE] =
695+
[BFieldElement::new(0); Tip5::RATE];
696+
for (i, bfield_elt) in absorb_rate_chunk.iter().enumerate() {
697+
asborb_chunk_buffer[i] = *bfield_elt;
698+
}
699+
self.absorb(asborb_chunk_buffer)
700+
});
704701
}
705702
}
706703

707704
#[cfg(test)]
708705
pub(crate) mod tip5_tests {
709-
use std::hash::DefaultHasher;
706+
use std::hash::Hash;
710707
use std::ops::Mul;
711708

709+
use insta::assert_snapshot;
710+
use prop::sample::size_range;
712711
use proptest::prelude::*;
713712
use proptest_arbitrary_interop::arb;
714713
use rand::thread_rng;
@@ -1121,10 +1120,34 @@ pub(crate) mod tip5_tests {
11211120

11221121
#[test]
11231122
fn tip5_hasher_trait_test() {
1124-
let mut hasher = DefaultHasher::new();
1123+
let mut hasher = Tip5::init();
11251124
let data = b"hello world";
11261125
hasher.write(data);
1127-
assert_eq!(hasher.finish(), 12804282289674824842);
1126+
assert_snapshot!(hasher.finish(), @"2267905471610932299");
1127+
}
1128+
1129+
#[proptest]
1130+
fn tip5_hasher_consumes_small_data(#[filter(!#bytes.is_empty())] bytes: Vec<u8>) {
1131+
let mut hasher = Tip5::init();
1132+
bytes.hash(&mut hasher);
1133+
1134+
prop_assert_ne!(Tip5::init().finish(), hasher.finish());
1135+
}
1136+
1137+
#[proptest]
1138+
fn appending_small_data_to_big_data_changes_tip5_hash(
1139+
#[any(size_range(2_000..8_000).lift())] big_data: Vec<u8>,
1140+
#[filter(!#small_data.is_empty())] small_data: Vec<u8>,
1141+
) {
1142+
let mut hasher = Tip5::init();
1143+
big_data.hash(&mut hasher);
1144+
let big_data_hash = hasher.finish();
1145+
1146+
// finish doesn't terminate the hasher; see it's documentation
1147+
small_data.hash(&mut hasher);
1148+
let all_data_hash = hasher.finish();
1149+
1150+
prop_assert_ne!(big_data_hash, all_data_hash);
11281151
}
11291152

11301153
#[proptest]

0 commit comments

Comments
 (0)