From cbfddb03942a110ad6f1044f039164a97c36896c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 Sep 2024 17:40:53 +1000 Subject: [PATCH] hashes: Rename length field and use u64 The hash engine types have a `length` field that is used to cache the number of bytes hashed so far, as such it is an arbitrary number and could use a `u64` instead of `usize`. While we are at it rename `length` to `bytes_hashed` to remove any ambiguity of what this field is. Note this field is private, we already have the public getter `n_bytes_hashes` to get the value. Introduce a private function `incomplete_block_size`, the purpose of this function is to put all the casts in one place so they can be well documented and easily understood. Fix: #3016 --- hashes/src/hash160.rs | 2 +- hashes/src/hmac.rs | 2 +- hashes/src/lib.rs | 11 +++++++-- hashes/src/ripemd160.rs | 20 ++++++++-------- hashes/src/sha1.rs | 20 ++++++++-------- hashes/src/sha256.rs | 52 ++++++++++++++++++++-------------------- hashes/src/sha256d.rs | 2 +- hashes/src/sha384.rs | 2 +- hashes/src/sha512.rs | 24 +++++++++---------- hashes/src/sha512_256.rs | 2 +- hashes/src/siphash24.rs | 20 ++++++++-------- hashes/src/util.rs | 7 +++--- 12 files changed, 86 insertions(+), 78 deletions(-) diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs index ba4d4724e..01cf9929a 100644 --- a/hashes/src/hash160.rs +++ b/hashes/src/hash160.rs @@ -34,7 +34,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE; fn input(&mut self, data: &[u8]) { self.0.input(data) } - fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } + fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() } } fn from_engine(e: HashEngine) -> Hash { diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs index f11b9f9ba..b64e8049c 100644 --- a/hashes/src/hmac.rs +++ b/hashes/src/hmac.rs @@ -102,7 +102,7 @@ impl HmacEngine { impl HashEngine for HmacEngine { const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE; - fn n_bytes_hashed(&self) -> usize { self.iengine.n_bytes_hashed() } + fn n_bytes_hashed(&self) -> u64 { self.iengine.n_bytes_hashed() } fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) } } diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index eb979a4d4..72b017d56 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -187,8 +187,8 @@ pub trait HashEngine: Clone { /// Add data to the hash engine. fn input(&mut self, data: &[u8]); - /// Return the number of bytes already n_bytes_hashed(inputted). - fn n_bytes_hashed(&self) -> usize; + /// Return the number of bytes already input into the engine. + fn n_bytes_hashed(&self) -> u64; } /// Trait describing hash digests which can be constructed by hashing arbitrary data. @@ -314,6 +314,13 @@ mod sealed { impl IsByteArray for [u8; N] { } } +fn incomplete_block_len(eng: &H) -> usize { + let block_size = ::BLOCK_SIZE as u64; // Cast usize to u64 is ok. + + // After modulo operation we know cast u64 to usize as ok. + (eng.n_bytes_hashed() % block_size) as usize +} + /// Attempted to create a hash from an invalid length slice. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromSliceError { diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs index 13a1248d4..90d200e76 100644 --- a/hashes/src/ripemd160.rs +++ b/hashes/src/ripemd160.rs @@ -6,7 +6,7 @@ use core::cmp; use core::ops::Index; use core::slice::SliceIndex; -use crate::HashEngine as _; +use crate::{incomplete_block_len, HashEngine as _}; crate::internal_macros::hash_type! { 160, @@ -17,19 +17,19 @@ crate::internal_macros::hash_type! { #[cfg(not(hashes_fuzz))] fn from_engine(mut e: HashEngine) -> Hash { // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining - let data_len = e.length as u64; + let n_bytes_hashed = e.bytes_hashed; let zeroes = [0; BLOCK_SIZE - 8]; e.input(&[0x80]); - if e.length % BLOCK_SIZE > zeroes.len() { + if crate::incomplete_block_len(&e) > zeroes.len() { e.input(&zeroes); } - let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + let pad_length = zeroes.len() - incomplete_block_len(&e); e.input(&zeroes[..pad_length]); - debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + debug_assert_eq!(incomplete_block_len(&e), zeroes.len()); - e.input(&(8 * data_len).to_le_bytes()); - debug_assert_eq!(e.length % BLOCK_SIZE, 0); + e.input(&(8 * n_bytes_hashed).to_le_bytes()); + debug_assert_eq!(incomplete_block_len(&e), 0); Hash(e.midstate()) } @@ -48,7 +48,7 @@ const BLOCK_SIZE: usize = 64; pub struct HashEngine { buffer: [u8; BLOCK_SIZE], h: [u32; 5], - length: usize, + bytes_hashed: u64, } impl HashEngine { @@ -56,7 +56,7 @@ impl HashEngine { pub const fn new() -> Self { Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -85,7 +85,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 64; - fn n_bytes_hashed(&self) -> usize { self.length } + fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } engine_input_impl!(); } diff --git a/hashes/src/sha1.rs b/hashes/src/sha1.rs index 7ca56f0c1..234558e45 100644 --- a/hashes/src/sha1.rs +++ b/hashes/src/sha1.rs @@ -6,7 +6,7 @@ use core::cmp; use core::ops::Index; use core::slice::SliceIndex; -use crate::HashEngine as _; +use crate::{incomplete_block_len, HashEngine as _}; crate::internal_macros::hash_type! { 160, @@ -16,19 +16,19 @@ crate::internal_macros::hash_type! { fn from_engine(mut e: HashEngine) -> Hash { // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining - let data_len = e.length as u64; + let n_bytes_hashed = e.bytes_hashed; let zeroes = [0; BLOCK_SIZE - 8]; e.input(&[0x80]); - if e.length % BLOCK_SIZE > zeroes.len() { + if incomplete_block_len(&e) > zeroes.len() { e.input(&zeroes); } - let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + let pad_length = zeroes.len() - incomplete_block_len(&e); e.input(&zeroes[..pad_length]); - debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + debug_assert_eq!(incomplete_block_len(&e), zeroes.len()); - e.input(&(8 * data_len).to_be_bytes()); - debug_assert_eq!(e.length % BLOCK_SIZE, 0); + e.input(&(8 * n_bytes_hashed).to_be_bytes()); + debug_assert_eq!(incomplete_block_len(&e), 0); Hash(e.midstate()) } @@ -40,7 +40,7 @@ const BLOCK_SIZE: usize = 64; pub struct HashEngine { buffer: [u8; BLOCK_SIZE], h: [u32; 5], - length: usize, + bytes_hashed: u64, } impl HashEngine { @@ -48,7 +48,7 @@ impl HashEngine { pub const fn new() -> Self { Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -77,7 +77,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 64; - fn n_bytes_hashed(&self) -> usize { self.length } + fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } engine_input_impl!(); } diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index d7377a212..12b1abb61 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -12,7 +12,7 @@ use core::{cmp, convert, fmt}; use hex::DisplayHex; -use crate::{sha256d, HashEngine as _}; +use crate::{incomplete_block_len, sha256d, HashEngine as _}; #[cfg(doc)] use crate::{sha256t, sha256t_tag}; @@ -25,19 +25,19 @@ crate::internal_macros::hash_type! { #[cfg(not(hashes_fuzz))] fn from_engine(mut e: HashEngine) -> Hash { // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining - let data_len = e.length as u64; + let n_bytes_hashed = e.bytes_hashed; let zeroes = [0; BLOCK_SIZE - 8]; e.input(&[0x80]); - if e.length % BLOCK_SIZE > zeroes.len() { + if incomplete_block_len(&e) > zeroes.len() { e.input(&zeroes); } - let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + let pad_length = zeroes.len() - incomplete_block_len(&e); e.input(&zeroes[..pad_length]); - debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + debug_assert_eq!(incomplete_block_len(&e), zeroes.len()); - e.input(&(8 * data_len).to_be_bytes()); - debug_assert_eq!(e.length % BLOCK_SIZE, 0); + e.input(&(8 * n_bytes_hashed).to_be_bytes()); + debug_assert_eq!(incomplete_block_len(&e), 0); Hash(e.midstate_unchecked().bytes) } @@ -60,7 +60,7 @@ const BLOCK_SIZE: usize = 64; pub struct HashEngine { buffer: [u8; BLOCK_SIZE], h: [u32; 8], - length: usize, + bytes_hashed: u64, } impl HashEngine { @@ -71,7 +71,7 @@ impl HashEngine { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -85,7 +85,7 @@ impl HashEngine { *ret_val = u32::from_be_bytes(midstate_bytes.try_into().expect("4 byte slice")); } - HashEngine { buffer: [0; BLOCK_SIZE], h: ret, length: midstate.length } + HashEngine { buffer: [0; BLOCK_SIZE], h: ret, bytes_hashed: midstate.bytes_hashed } } /// Returns `true` if the midstate can be extracted from this engine. @@ -94,14 +94,14 @@ impl HashEngine { /// the hash engine is a multiple of 64. See caveat on [`Self::midstate`]. /// /// Please see docs on [`Midstate`] before using this function. - pub const fn can_extract_midstate(&self) -> bool { self.length % 64 == 0 } + pub const fn can_extract_midstate(&self) -> bool { self.bytes_hashed % 64 == 0 } /// Outputs the midstate of the hash engine. /// /// Please see docs on [`Midstate`] before using this function. pub fn midstate(&self) -> Result { if !self.can_extract_midstate() { - return Err(MidstateError { invalid_length: self.length }); + return Err(MidstateError { invalid_n_bytes_hashed: self.bytes_hashed }); } Ok(self.midstate_unchecked()) } @@ -113,7 +113,7 @@ impl HashEngine { for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) { ret_bytes.copy_from_slice(&val.to_be_bytes()); } - Midstate { bytes: ret, length: self.length } + Midstate { bytes: ret, bytes_hashed: self.bytes_hashed } } // Does not check that `HashEngine::can_extract_midstate`. @@ -121,7 +121,7 @@ impl HashEngine { fn midstate_unchecked(&self) -> Midstate { let mut ret = [0; 32]; ret.copy_from_slice(&self.buffer[..32]); - Midstate { bytes: ret, length: self.length } + Midstate { bytes: ret, bytes_hashed: self.bytes_hashed } } } @@ -132,7 +132,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 64; - fn n_bytes_hashed(&self) -> usize { self.length } + fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } engine_input_impl!(); } @@ -177,7 +177,7 @@ pub struct Midstate { bytes: [u8; 32], /// Number of bytes hashed to achieve this midstate. // INVARIANT must always be a multiple of 64. - length: usize, + bytes_hashed: u64, } impl Midstate { @@ -186,19 +186,19 @@ impl Midstate { /// # Panics /// /// Panics if `bytes_hashed` is not a multiple of 64. - pub const fn new(state: [u8; 32], bytes_hashed: usize) -> Self { + pub const fn new(state: [u8; 32], bytes_hashed: u64) -> Self { if bytes_hashed % 64 != 0 { panic!("bytes hashed is not a multiple of 64"); } - Midstate { bytes: state, length: bytes_hashed } + Midstate { bytes: state, bytes_hashed } } /// Deconstructs the [`Midstate`], returning the underlying byte array and number of bytes hashed. - pub const fn as_parts(&self) -> (&[u8; 32], usize) { (&self.bytes, self.length) } + pub const fn as_parts(&self) -> (&[u8; 32], u64) { (&self.bytes, self.bytes_hashed) } /// Deconstructs the [`Midstate`], returning the underlying byte array and number of bytes hashed. - pub const fn into_parts(self) -> ([u8; 32], usize) { (self.bytes, self.length) } + pub const fn into_parts(self) -> ([u8; 32], u64) { (self.bytes, self.bytes_hashed) } /// Creates midstate for tagged hashes. /// @@ -222,7 +222,7 @@ impl fmt::Debug for Midstate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Midstate") .field("bytes", &self.bytes.as_hex()) - .field("length", &self.length) + .field("length", &self.bytes_hashed) .finish() } } @@ -235,7 +235,7 @@ impl convert::AsRef<[u8]> for Midstate { #[derive(Debug, Clone, PartialEq, Eq)] pub struct MidstateError { /// The invalid number of bytes hashed. - invalid_length: usize, + invalid_n_bytes_hashed: u64, } impl fmt::Display for MidstateError { @@ -243,7 +243,7 @@ impl fmt::Display for MidstateError { write!( f, "invalid number of bytes hashed {} (should have been a multiple of 64)", - self.invalid_length + self.invalid_n_bytes_hashed ) } } @@ -485,7 +485,7 @@ impl Midstate { output[i * 4 + 3] = (state[i + 0] >> 0) as u8; i += 1; } - Midstate { bytes: output, length: bytes.len() } + Midstate { bytes: output, bytes_hashed: bytes.len() as u64 } } } @@ -996,7 +996,7 @@ mod tests { let mut midstate_engine = sha256::HashEngine::from_midstate(engine.midstate_unchecked()); assert_eq!(engine.h, midstate_engine.h); - assert_eq!(engine.length, midstate_engine.length); + assert_eq!(engine.bytes_hashed, midstate_engine.bytes_hashed); engine.input(data); midstate_engine.input(data); assert_eq!(engine.h, midstate_engine.h); @@ -1037,7 +1037,7 @@ mod tests { assert_eq!( Hash::hash(bytes), Hash::hash_unoptimized(bytes), - "hashes don't match for length {}", + "hashes don't match for n_bytes_hashed {}", i + 1 ); } diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs index 72f246887..8df009d2e 100644 --- a/hashes/src/sha256d.rs +++ b/hashes/src/sha256d.rs @@ -29,7 +29,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE; fn input(&mut self, data: &[u8]) { self.0.input(data) } - fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } + fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() } } fn from_engine(e: HashEngine) -> Hash { diff --git a/hashes/src/sha384.rs b/hashes/src/sha384.rs index c588309cb..027acd3ef 100644 --- a/hashes/src/sha384.rs +++ b/hashes/src/sha384.rs @@ -35,7 +35,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = sha512::BLOCK_SIZE; - fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } + fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() } fn input(&mut self, inp: &[u8]) { self.0.input(inp); } } diff --git a/hashes/src/sha512.rs b/hashes/src/sha512.rs index 4a4df0617..f3e10cb13 100644 --- a/hashes/src/sha512.rs +++ b/hashes/src/sha512.rs @@ -6,7 +6,7 @@ use core::cmp; use core::ops::Index; use core::slice::SliceIndex; -use crate::HashEngine as _; +use crate::{incomplete_block_len, HashEngine as _}; crate::internal_macros::hash_type! { 512, @@ -17,20 +17,20 @@ crate::internal_macros::hash_type! { #[cfg(not(hashes_fuzz))] pub(crate) fn from_engine(mut e: HashEngine) -> Hash { // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining - let data_len = e.length as u64; + let n_bytes_hashed = e.bytes_hashed; let zeroes = [0; BLOCK_SIZE - 16]; e.input(&[0x80]); - if e.length % BLOCK_SIZE > zeroes.len() { + if incomplete_block_len(&e) > zeroes.len() { e.input(&zeroes); } - let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + let pad_length = zeroes.len() - incomplete_block_len(&e); e.input(&zeroes[..pad_length]); - debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + debug_assert_eq!(incomplete_block_len(&e), zeroes.len()); e.input(&[0; 8]); - e.input(&(8 * data_len).to_be_bytes()); - debug_assert_eq!(e.length % BLOCK_SIZE, 0); + e.input(&(8 * n_bytes_hashed).to_be_bytes()); + debug_assert_eq!(incomplete_block_len(&e), 0); Hash(e.midstate()) } @@ -48,7 +48,7 @@ pub(crate) const BLOCK_SIZE: usize = 128; #[derive(Clone)] pub struct HashEngine { h: [u64; 8], - length: usize, + bytes_hashed: u64, buffer: [u8; BLOCK_SIZE], } @@ -61,7 +61,7 @@ impl HashEngine { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, ], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -96,7 +96,7 @@ impl HashEngine { 0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd, 0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2, ], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -109,7 +109,7 @@ impl HashEngine { 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, ], - length: 0, + bytes_hashed: 0, buffer: [0; BLOCK_SIZE], } } @@ -118,7 +118,7 @@ impl HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = 128; - fn n_bytes_hashed(&self) -> usize { self.length } + fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } engine_input_impl!(); } diff --git a/hashes/src/sha512_256.rs b/hashes/src/sha512_256.rs index 30b36e82b..9490a5316 100644 --- a/hashes/src/sha512_256.rs +++ b/hashes/src/sha512_256.rs @@ -45,7 +45,7 @@ impl Default for HashEngine { impl crate::HashEngine for HashEngine { const BLOCK_SIZE: usize = sha512::BLOCK_SIZE; - fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } + fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() } fn input(&mut self, inp: &[u8]) { self.0.input(inp); } } diff --git a/hashes/src/siphash24.rs b/hashes/src/siphash24.rs index 8999c64b1..2df24dc2b 100644 --- a/hashes/src/siphash24.rs +++ b/hashes/src/siphash24.rs @@ -81,7 +81,7 @@ pub struct State { pub struct HashEngine { k0: u64, k1: u64, - length: usize, // how many bytes we've processed + bytes_hashed: u64, // how many bytes we've processed state: State, // hash State tail: u64, // unprocessed bytes le ntail: usize, // how many bytes in tail are valid @@ -94,7 +94,7 @@ impl HashEngine { HashEngine { k0, k1, - length: 0, + bytes_hashed: 0, state: State { v0: k0 ^ 0x736f6d6570736575, v1: k1 ^ 0x646f72616e646f6d, @@ -129,16 +129,16 @@ impl crate::HashEngine for HashEngine { #[inline] fn input(&mut self, msg: &[u8]) { - let length = msg.len(); - self.length += length; + let bytes_hashed = msg.len(); + self.bytes_hashed += bytes_hashed as u64; // Cast usize to u64 is ok. let mut needed = 0; if self.ntail != 0 { needed = 8 - self.ntail; - self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); - if length < needed { - self.ntail += length; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(bytes_hashed, needed)) } << (8 * self.ntail); + if bytes_hashed < needed { + self.ntail += bytes_hashed; return; } else { self.state.v3 ^= self.tail; @@ -149,7 +149,7 @@ impl crate::HashEngine for HashEngine { } // Buffered tail is now flushed, process new input. - let len = length - needed; + let len = bytes_hashed - needed; let left = len & 0x7; let mut i = needed; @@ -167,7 +167,7 @@ impl crate::HashEngine for HashEngine { self.ntail = left; } - fn n_bytes_hashed(&self) -> usize { self.length } + fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed } } impl Hash { @@ -190,7 +190,7 @@ impl Hash { pub fn from_engine_to_u64(e: HashEngine) -> u64 { let mut state = e.state; - let b: u64 = ((e.length as u64 & 0xff) << 56) | e.tail; + let b: u64 = ((e.bytes_hashed & 0xff) << 56) | e.tail; state.v3 ^= b; HashEngine::c_rounds(&mut state); diff --git a/hashes/src/util.rs b/hashes/src/util.rs index a3129d8e5..cb71a42c3 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -70,15 +70,16 @@ macro_rules! engine_input_impl( () => ( #[cfg(not(hashes_fuzz))] fn input(&mut self, mut inp: &[u8]) { + while !inp.is_empty() { - let buf_idx = self.length % ::BLOCK_SIZE; + let buf_idx = $crate::incomplete_block_len(self); let rem_len = ::BLOCK_SIZE - buf_idx; let write_len = cmp::min(rem_len, inp.len()); self.buffer[buf_idx..buf_idx + write_len] .copy_from_slice(&inp[..write_len]); - self.length += write_len; - if self.length % ::BLOCK_SIZE == 0 { + self.bytes_hashed += write_len as u64; + if $crate::incomplete_block_len(self) == 0 { self.process_block(); } inp = &inp[write_len..];