hashes: Refactor process_block to process_block(state, data)
What changed, and why it matters
This is a routine internal code cleanup in the project's hash-function code. It changes how a low-level helper function is called so it takes the hash state and data block as explicit arguments, rather than reading them from a surrounding object. The commit message and diff show no change to the actual hashing math or results. There is no security issue here.
No action required. Treat as a normal refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors process_block from an instance method fn process_block(&mut self) to a free-function-style associated method fn process_block(state, block) across RIPEMD-160, SHA-1, SHA-256, SHA-512, and SHA3-256 implementations. It also renames SHA3-256’s internal state field to h for consistency. All call sites are updated to pass &mut self.h and &self.buffer explicitly. The cryptographic round logic, constants, and data flow are unchanged. A TODO comment is added noting future support for multiple blocks.
Changed components
hashes/src/internal_macros.rshashes/src/ripemd160/crypto.rshashes/src/sha1/crypto.rshashes/src/sha256/crypto.rshashes/src/sha3_256/mod.rshashes/src/sha512/crypto.rsInspect captured patch +93 / −92
diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs
index 1f6a8a0d..f151a52f 100644
--- a/hashes/src/internal_macros.rs
+++ b/hashes/src/internal_macros.rs
@@ -181,7 +181,8 @@ macro_rules! engine_input_impl(
.copy_from_slice(&inp[..write_len]);
self.bytes_hashed += write_len as u64;
if $crate::incomplete_block_len(self) == 0 {
- self.process_block();
+ // TODO change this to accept multiple blocks instead
+ Self::process_block(&mut self.h, &self.buffer);
}
inp = &inp[write_len..];
}
diff --git a/hashes/src/ripemd160/crypto.rs b/hashes/src/ripemd160/crypto.rs
index 189e52c3..ca545218 100644
--- a/hashes/src/ripemd160/crypto.rs
+++ b/hashes/src/ripemd160/crypto.rs
@@ -131,15 +131,15 @@ macro_rules! process_block(
);
impl HashEngine {
- pub(super) fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
+ pub(super) fn process_block(state: &mut [u32; 5], block: &[u8; BLOCK_SIZE]) {
+ debug_assert_eq!(block.len(), BLOCK_SIZE);
let mut w = [0u32; 16];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.bitcoin_as_chunks().0) {
+ for (w_val, buff_bytes) in w.iter_mut().zip(block.bitcoin_as_chunks().0) {
*w_val = u32::from_le_bytes(*buff_bytes)
}
- process_block!(self.h, w,
+ process_block!(*state, w,
// Round 1
round1: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 11;
round1: h_ordering 4, 0, 1, 2, 3; data_index 1; roll_shift 14;
diff --git a/hashes/src/sha1/crypto.rs b/hashes/src/sha1/crypto.rs
index 70d04f50..14d866fb 100644
--- a/hashes/src/sha1/crypto.rs
+++ b/hashes/src/sha1/crypto.rs
@@ -6,22 +6,22 @@ use super::{HashEngine, BLOCK_SIZE};
impl HashEngine {
// Basic unoptimized algorithm from Wikipedia
- pub(super) fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
+ pub(super) fn process_block(state: &mut[u32; 5], block: &[u8; BLOCK_SIZE]) {
+ debug_assert_eq!(block.len(), BLOCK_SIZE);
let mut w = [0u32; 80];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.bitcoin_as_chunks().0) {
+ for (w_val, buff_bytes) in w.iter_mut().zip(block.bitcoin_as_chunks().0) {
*w_val = u32::from_be_bytes(*buff_bytes)
}
for i in 16..80 {
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
}
- let mut a = self.h[0];
- let mut b = self.h[1];
- let mut c = self.h[2];
- let mut d = self.h[3];
- let mut e = self.h[4];
+ let mut a = state[0];
+ let mut b = state[1];
+ let mut c = state[2];
+ let mut d = state[3];
+ let mut e = state[4];
for (i, &wi) in w.iter().enumerate() {
let (f, k) = match i {
@@ -41,10 +41,10 @@ impl HashEngine {
a = new_a;
}
- self.h[0] = self.h[0].wrapping_add(a);
- self.h[1] = self.h[1].wrapping_add(b);
- self.h[2] = self.h[2].wrapping_add(c);
- self.h[3] = self.h[3].wrapping_add(d);
- self.h[4] = self.h[4].wrapping_add(e);
+ state[0] = state[0].wrapping_add(a);
+ state[1] = state[1].wrapping_add(b);
+ state[2] = state[2].wrapping_add(c);
+ state[3] = state[3].wrapping_add(d);
+ state[4] = state[4].wrapping_add(e);
}
}
diff --git a/hashes/src/sha256/crypto.rs b/hashes/src/sha256/crypto.rs
index aa7cc935..a27f0caf 100644
--- a/hashes/src/sha256/crypto.rs
+++ b/hashes/src/sha256/crypto.rs
@@ -269,7 +269,7 @@ impl Midstate {
}
impl HashEngine {
- pub(super) fn process_block(&mut self) {
+ pub(super) fn process_block(state: &mut[u32; 8], block: &[u8; BLOCK_SIZE]) {
#[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))]
{
if std::is_x86_feature_detected!("sse4.1")
@@ -277,14 +277,14 @@ impl HashEngine {
&& std::is_x86_feature_detected!("sse2")
&& std::is_x86_feature_detected!("ssse3")
{
- return unsafe { self.process_block_simd_x86_intrinsics() };
+ return unsafe { Self::process_block_simd_x86_intrinsics(state, block) };
}
}
#[cfg(all(feature = "cpufeatures", any(target_arch = "x86", target_arch = "x86_64")))]
{
if cpuid_sha256_x86::get() {
- return unsafe { self.process_block_simd_x86_intrinsics() };
+ return unsafe { Self::process_block_simd_x86_intrinsics(state, block) };
}
}
@@ -292,24 +292,24 @@ impl HashEngine {
#[cfg(all(feature = "std", target_arch = "aarch64"))]
{
if std::arch::is_aarch64_feature_detected!("sha2") {
- return unsafe { self.process_block_simd_arm_intrinsics() };
+ return unsafe { Self::process_block_simd_arm_intrinsics(state, block) };
}
}
#[cfg(all(feature = "cpufeatures", target_arch = "aarch64"))]
{
if cpuid_sha256_aarch64::get() {
- return unsafe { self.process_block_simd_arm_intrinsics() };
+ return unsafe { Self::process_block_simd_arm_intrinsics(state, block) };
}
}
// fallback implementation without using any intrinsics
- self.software_process_block()
+ Self::software_process_block(state, block)
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), any(feature = "std", feature = "cpufeatures")))]
#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
- unsafe fn process_block_simd_x86_intrinsics(&mut self) {
+ unsafe fn process_block_simd_x86_intrinsics(state: &mut[u32; 8], block: &[u8; BLOCK_SIZE]) {
// Code translated and based on from
// https://github.com/noloader/SHA-Intrinsics/blob/4899efc81d1af159c1fd955936c673139f35aea9/sha256-x86.c
@@ -335,8 +335,8 @@ impl HashEngine {
// Load initial values
// CAST SAFETY: loadu_si128 documentation states that mem_addr does not
// need to be aligned on any particular boundary.
- tmp = _mm_loadu_si128(self.h.as_ptr().add(0).cast::<__m128i>());
- state1 = _mm_loadu_si128(self.h.as_ptr().add(4).cast::<__m128i>());
+ tmp = _mm_loadu_si128(state.as_ptr().add(0).cast::<__m128i>());
+ state1 = _mm_loadu_si128(state.as_ptr().add(4).cast::<__m128i>());
tmp = _mm_shuffle_epi32(tmp, 0xB1); // CDAB
state1 = _mm_shuffle_epi32(state1, 0x1B); // EFGH
@@ -350,7 +350,7 @@ impl HashEngine {
cdgh_save = state1;
// Rounds 0-3
- msg = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset).cast::<__m128i>());
+ msg = _mm_loadu_si128(block.as_ptr().add(block_offset).cast::<__m128i>());
msg0 = _mm_shuffle_epi8(msg, MASK);
msg = _mm_add_epi32(
msg0,
@@ -361,7 +361,7 @@ impl HashEngine {
state0 = _mm_sha256rnds2_epu32(state0, state1, msg);
// Rounds 4-7
- msg1 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 16).cast::<__m128i>());
+ msg1 = _mm_loadu_si128(block.as_ptr().add(block_offset + 16).cast::<__m128i>());
msg1 = _mm_shuffle_epi8(msg1, MASK);
msg = _mm_add_epi32(
msg1,
@@ -373,7 +373,7 @@ impl HashEngine {
msg0 = _mm_sha256msg1_epu32(msg0, msg1);
// Rounds 8-11
- msg2 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 32).cast::<__m128i>());
+ msg2 = _mm_loadu_si128(block.as_ptr().add(block_offset + 32).cast::<__m128i>());
msg2 = _mm_shuffle_epi8(msg2, MASK);
msg = _mm_add_epi32(
msg2,
@@ -385,7 +385,7 @@ impl HashEngine {
msg1 = _mm_sha256msg1_epu32(msg1, msg2);
// Rounds 12-15
- msg3 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 48).cast::<__m128i>());
+ msg3 = _mm_loadu_si128(block.as_ptr().add(block_offset + 48).cast::<__m128i>());
msg3 = _mm_shuffle_epi8(msg3, MASK);
msg = _mm_add_epi32(
msg3,
@@ -562,13 +562,13 @@ impl HashEngine {
// Save state
// CAST SAFETY: storeu_si128 documentation states that mem_addr does not
// need to be aligned on any particular boundary.
- _mm_storeu_si128(self.h.as_mut_ptr().add(0).cast::<__m128i>(), state0);
- _mm_storeu_si128(self.h.as_mut_ptr().add(4).cast::<__m128i>(), state1);
+ _mm_storeu_si128(state.as_mut_ptr().add(0).cast::<__m128i>(), state0);
+ _mm_storeu_si128(state.as_mut_ptr().add(4).cast::<__m128i>(), state1);
}
#[cfg(all(target_arch = "aarch64", any(feature = "std", feature = "cpufeatures")))]
#[target_feature(enable = "sha2")]
- unsafe fn process_block_simd_arm_intrinsics(&mut self) {
+ unsafe fn process_block_simd_arm_intrinsics(state: &mut[u32; 8], block: &[u8; BLOCK_SIZE]) {
// Code translated and based on from
// https://github.com/noloader/SHA-Intrinsics/blob/4e754bec921a9f281b69bd681ca0065763aa911c/sha256-arm.c
@@ -605,18 +605,18 @@ impl HashEngine {
let (mut tmp0, mut tmp1, mut tmp2);
// Load state
- state0 = vld1q_u32(self.h.as_ptr().add(0));
- state1 = vld1q_u32(self.h.as_ptr().add(4));
+ state0 = vld1q_u32(state.as_ptr().add(0));
+ state1 = vld1q_u32(state.as_ptr().add(4));
// Save state
abcd_save = state0;
efgh_save = state1;
// Load message
- msg0 = vld1q_u32(self.buffer.as_ptr().add(0).cast::<u32>());
- msg1 = vld1q_u32(self.buffer.as_ptr().add(16).cast::<u32>());
- msg2 = vld1q_u32(self.buffer.as_ptr().add(32).cast::<u32>());
- msg3 = vld1q_u32(self.buffer.as_ptr().add(48).cast::<u32>());
+ msg0 = vld1q_u32(block.as_ptr().add(0).cast::<u32>());
+ msg1 = vld1q_u32(block.as_ptr().add(16).cast::<u32>());
+ msg2 = vld1q_u32(block.as_ptr().add(32).cast::<u32>());
+ msg3 = vld1q_u32(block.as_ptr().add(48).cast::<u32>());
// Reverse for little endian
msg0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(msg0)));
@@ -750,27 +750,27 @@ impl HashEngine {
state1 = vaddq_u32(state1, efgh_save);
// Save state
- vst1q_u32(self.h.as_mut_ptr().add(0), state0);
- vst1q_u32(self.h.as_mut_ptr().add(4), state1);
+ vst1q_u32(state.as_mut_ptr().add(0), state0);
+ vst1q_u32(state.as_mut_ptr().add(4), state1);
}
// Algorithm copied from libsecp256k1
- fn software_process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
+ fn software_process_block(state: &mut[u32; 8], block: &[u8; BLOCK_SIZE]) {
+ debug_assert_eq!(block.len(), BLOCK_SIZE);
let mut w = [0u32; 16];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.bitcoin_as_chunks().0) {
+ for (w_val, buff_bytes) in w.iter_mut().zip(block.bitcoin_as_chunks().0) {
*w_val = u32::from_be_bytes(*buff_bytes);
}
- let mut a = self.h[0];
- let mut b = self.h[1];
- let mut c = self.h[2];
- let mut d = self.h[3];
- let mut e = self.h[4];
- let mut f = self.h[5];
- let mut g = self.h[6];
- let mut h = self.h[7];
+ let mut a = state[0];
+ let mut b = state[1];
+ let mut c = state[2];
+ let mut d = state[3];
+ let mut e = state[4];
+ let mut f = state[5];
+ let mut g = state[6];
+ let mut h = state[7];
round!(a, b, c, d, e, f, g, h, 0x428a2f98, w[0]);
round!(h, a, b, c, d, e, f, g, 0x71374491, w[1]);
@@ -841,13 +841,13 @@ impl HashEngine {
round!(b, c, d, e, f, g, h, a, 0xc67178f2, w[15], w[13], w[8], w[0]);
let _ = w[15]; // silence "unnecessary assignment" lint in macro
- self.h[0] = self.h[0].wrapping_add(a);
- self.h[1] = self.h[1].wrapping_add(b);
- self.h[2] = self.h[2].wrapping_add(c);
- self.h[3] = self.h[3].wrapping_add(d);
- self.h[4] = self.h[4].wrapping_add(e);
- self.h[5] = self.h[5].wrapping_add(f);
- self.h[6] = self.h[6].wrapping_add(g);
- self.h[7] = self.h[7].wrapping_add(h);
+ state[0] = state[0].wrapping_add(a);
+ state[1] = state[1].wrapping_add(b);
+ state[2] = state[2].wrapping_add(c);
+ state[3] = state[3].wrapping_add(d);
+ state[4] = state[4].wrapping_add(e);
+ state[5] = state[5].wrapping_add(f);
+ state[6] = state[6].wrapping_add(g);
+ state[7] = state[7].wrapping_add(h);
}
}
diff --git a/hashes/src/sha3_256/mod.rs b/hashes/src/sha3_256/mod.rs
index e345b14d..aa626196 100644
--- a/hashes/src/sha3_256/mod.rs
+++ b/hashes/src/sha3_256/mod.rs
@@ -167,7 +167,7 @@ fn keccakf1600(state: &mut KeccakState) {
/// Engine to compute the Sha3-256 hash function.
#[derive(Debug, Clone)]
pub struct HashEngine {
- state: KeccakState,
+ h: KeccakState,
bytes_hashed: u64,
buffer: [u8; RATE],
}
@@ -179,23 +179,23 @@ impl Default for HashEngine {
impl HashEngine {
/// Construct a new Sha3-256 hash engine.
pub const fn new() -> Self {
- Self { state: KeccakState::new(), bytes_hashed: 0, buffer: [0; RATE] }
+ Self { h: KeccakState::new(), bytes_hashed: 0, buffer: [0; RATE] }
}
- fn absorb(&mut self, block: [u8; RATE]) {
+ fn absorb(state: &mut KeccakState, block: &[u8; RATE]) {
for lane in 0..RATE_LANES {
let x = lane % 5;
let y = lane / 5;
let mut pad_block = [0u8; 8];
pad_block.copy_from_slice(&block[8 * lane..8 * lane + 8]);
let shuffle = u64::from_le_bytes(pad_block);
- self.state.xor_assign(x, y, shuffle);
+ state.xor_assign(x, y, shuffle);
}
}
- fn process_block(&mut self) {
- self.absorb(self.buffer);
- keccakf1600(&mut self.state);
+ fn process_block(state: &mut KeccakState, block: &[u8; RATE]) {
+ Self::absorb(state, block);
+ keccakf1600(state);
}
}
@@ -213,13 +213,13 @@ impl crate::HashEngine for HashEngine {
self.buffer[incomplete_block_len + 1..].fill(0);
self.buffer[incomplete_block_len] = 0x06;
self.buffer[RATE - 1] ^= 0x80;
- self.process_block();
+ Self::process_block(&mut self.h, &self.buffer);
let mut out = [0u8; 32];
- out[..8].copy_from_slice(&self.state.lane(0, 0).to_le_bytes());
- out[8..16].copy_from_slice(&self.state.lane(1, 0).to_le_bytes());
- out[16..24].copy_from_slice(&self.state.lane(2, 0).to_le_bytes());
- out[24..].copy_from_slice(&self.state.lane(3, 0).to_le_bytes());
+ out[..8].copy_from_slice(&self.h.lane(0, 0).to_le_bytes());
+ out[8..16].copy_from_slice(&self.h.lane(1, 0).to_le_bytes());
+ out[16..24].copy_from_slice(&self.h.lane(2, 0).to_le_bytes());
+ out[24..].copy_from_slice(&self.h.lane(3, 0).to_le_bytes());
Hash(out)
}
}
diff --git a/hashes/src/sha512/crypto.rs b/hashes/src/sha512/crypto.rs
index 7fd8def2..a9b46adb 100644
--- a/hashes/src/sha512/crypto.rs
+++ b/hashes/src/sha512/crypto.rs
@@ -75,22 +75,22 @@ mod fast_hash {
impl HashEngine {
// Algorithm copied from libsecp256k1
- pub(crate) fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
+ pub(crate) fn process_block(state: &mut[u64; 8], block: &[u8; BLOCK_SIZE]) {
+ debug_assert_eq!(block.len(), BLOCK_SIZE);
let mut w = [0u64; 16];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.bitcoin_as_chunks().0) {
+ for (w_val, buff_bytes) in w.iter_mut().zip(block.bitcoin_as_chunks().0) {
*w_val = u64::from_be_bytes(*buff_bytes);
}
- let mut a = self.h[0];
- let mut b = self.h[1];
- let mut c = self.h[2];
- let mut d = self.h[3];
- let mut e = self.h[4];
- let mut f = self.h[5];
- let mut g = self.h[6];
- let mut h = self.h[7];
+ let mut a = state[0];
+ let mut b = state[1];
+ let mut c = state[2];
+ let mut d = state[3];
+ let mut e = state[4];
+ let mut f = state[5];
+ let mut g = state[6];
+ let mut h = state[7];
round!(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22, w[0]);
round!(h, a, b, c, d, e, f, g, 0x7137449123ef65cd, w[1]);
@@ -178,13 +178,13 @@ impl HashEngine {
round!(b, c, d, e, f, g, h, a, 0x6c44198c4a475817, w[15], w[13], w[8], w[0]);
let _ = w[15]; // silence "unnecessary assignment" lint in macro
- self.h[0] = self.h[0].wrapping_add(a);
- self.h[1] = self.h[1].wrapping_add(b);
- self.h[2] = self.h[2].wrapping_add(c);
- self.h[3] = self.h[3].wrapping_add(d);
- self.h[4] = self.h[4].wrapping_add(e);
- self.h[5] = self.h[5].wrapping_add(f);
- self.h[6] = self.h[6].wrapping_add(g);
- self.h[7] = self.h[7].wrapping_add(h);
+ state[0] = state[0].wrapping_add(a);
+ state[1] = state[1].wrapping_add(b);
+ state[2] = state[2].wrapping_add(c);
+ state[3] = state[3].wrapping_add(d);
+ state[4] = state[4].wrapping_add(e);
+ state[5] = state[5].wrapping_add(f);
+ state[6] = state[6].wrapping_add(g);
+ state[7] = state[7].wrapping_add(h);
}
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.