From 8d1fac792c8338e516fada70b11c70430c87bcc6 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 21 May 2024 20:48:10 +0300 Subject: [PATCH] streebog: use `[u64; 8]` instead of `[u8; 64]` for `h` (#585) --- streebog/src/consts.rs | 21 +++++++ streebog/src/core_api.rs | 128 ++++++++++++++++----------------------- 2 files changed, 72 insertions(+), 77 deletions(-) diff --git a/streebog/src/consts.rs b/streebog/src/consts.rs index e356b9fa..403073d8 100644 --- a/streebog/src/consts.rs +++ b/streebog/src/consts.rs @@ -178,6 +178,27 @@ pub const C: [[u8; BLOCK_SIZE]; 12] = [ ], ]; +/// Iteration constants represented as `[u64; 8]` +pub const C64: [[u64; 8]; 12] = { + let mut res = [[0u64; 8]; 12]; + let mut i = 0; + let mut buf = [0u8; 8]; + while i < 12 { + let mut j = 0; + while j < 8 { + let mut k = 0; + while k < 8 { + buf[k] = C[i][8 * j + k]; + k += 1; + } + res[i][j] = u64::from_le_bytes(buf); + j += 1; + } + i += 1; + } + res +}; + /// Precomputed, pre-shuffled table for linear transformation using matrix /// `const::A` and shuffled using `const::P` pub const SHUFFLED_LIN_TABLE: [[u64; 256]; 8] = { diff --git a/streebog/src/core_api.rs b/streebog/src/core_api.rs index cd581eaa..7d1b55ae 100644 --- a/streebog/src/core_api.rs +++ b/streebog/src/core_api.rs @@ -14,7 +14,7 @@ use digest::{ #[cfg(feature = "zeroize")] use digest::zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::consts::{BLOCK_SIZE, C, SHUFFLED_LIN_TABLE}; +use crate::consts::{BLOCK_SIZE, C64, SHUFFLED_LIN_TABLE}; type Block = [u8; 64]; @@ -24,70 +24,64 @@ type Block = [u8; 64]; /// i.e. 256 and 512 bits respectively. #[derive(Clone)] pub struct StreebogVarCore { - h: Block, + h: [u64; 8], n: [u64; 8], sigma: [u64; 8], } #[inline(always)] -fn lps(h: &mut Block, n: &Block) { - for i in 0..64 { +fn lps(h: &mut [u64; 8], n: &[u64; 8]) { + for i in 0..8 { h[i] ^= n[i]; } let mut buf = [0u64; 8]; - - for i in 0..4 { + #[allow(clippy::needless_range_loop)] + for i in 0..8 { for j in 0..8 { - let b = h[2 * i + 8 * j] as usize; - buf[2 * i] ^= SHUFFLED_LIN_TABLE[j][b]; - let b = h[2 * i + 1 + 8 * j] as usize; - buf[2 * i + 1] ^= SHUFFLED_LIN_TABLE[j][b]; + let idx = (h[j] >> (8 * i) & 0xff) as usize; + buf[i] ^= SHUFFLED_LIN_TABLE[j][idx]; } } - *h = to_bytes(&buf); + *h = buf; } -impl StreebogVarCore { - fn g(&mut self, n: &Block, m: &Block) { - let mut key = [0u8; 64]; - let mut block = [0u8; 64]; - - key.copy_from_slice(&self.h); - block.copy_from_slice(m); +fn g(h: &mut [u64; 8], n: &[u64; 8], m: &[u64; 8]) { + let mut key = *h; + let mut block = *m; - lps(&mut key, n); + lps(&mut key, n); - #[allow(clippy::needless_range_loop)] - for i in 0..12 { - lps(&mut block, &key); - lps(&mut key, &C[i]); - } + for c in &C64 { + lps(&mut block, &key); + lps(&mut key, c); + } - for i in 0..64 { - self.h[i] ^= block[i] ^ key[i] ^ m[i]; - } + for i in 0..8 { + h[i] ^= block[i] ^ key[i] ^ m[i]; } +} - fn update_sigma(&mut self, m: &Block) { - let t = from_bytes(m); +impl StreebogVarCore { + fn update_sigma(&mut self, m: &[u64; 8]) { let mut carry = 0; - adc(&mut self.sigma[0], t[0], &mut carry); - adc(&mut self.sigma[1], t[1], &mut carry); - adc(&mut self.sigma[2], t[2], &mut carry); - adc(&mut self.sigma[3], t[3], &mut carry); - adc(&mut self.sigma[4], t[4], &mut carry); - adc(&mut self.sigma[5], t[5], &mut carry); - adc(&mut self.sigma[6], t[6], &mut carry); - adc(&mut self.sigma[7], t[7], &mut carry); + adc(&mut self.sigma[0], m[0], &mut carry); + adc(&mut self.sigma[1], m[1], &mut carry); + adc(&mut self.sigma[2], m[2], &mut carry); + adc(&mut self.sigma[3], m[3], &mut carry); + adc(&mut self.sigma[4], m[4], &mut carry); + adc(&mut self.sigma[5], m[5], &mut carry); + adc(&mut self.sigma[6], m[6], &mut carry); + adc(&mut self.sigma[7], m[7], &mut carry); } fn update_n(&mut self, len: u64) { let mut carry = 0; // note: `len` can not be bigger than block size, - // so `8*len` will never overflow - adc(&mut self.n[0], 8 * len, &mut carry); + // so `8 * len` will never overflow + let bits_len = 8 * len; + adc(&mut self.n[0], bits_len, &mut carry); adc(&mut self.n[1], 0, &mut carry); adc(&mut self.n[2], 0, &mut carry); adc(&mut self.n[3], 0, &mut carry); @@ -98,9 +92,10 @@ impl StreebogVarCore { } fn compress(&mut self, block: &[u8; 64], msg_len: u64) { - self.g(&to_bytes(&self.n), block); + let block = from_bytes(block); + g(&mut self.h, &self.n, &block); self.update_n(msg_len); - self.update_sigma(block); + self.update_sigma(&block); } } @@ -133,8 +128,8 @@ impl VariableOutputCore for StreebogVarCore { #[inline] fn new(output_size: usize) -> Result { let h = match output_size { - 32 => [1; 64], - 64 => [0; 64], + 32 => [0x0101_0101_0101_0101; 8], + 64 => [0; 8], _ => return Err(InvalidOutputSize), }; let (n, sigma) = Default::default(); @@ -147,9 +142,9 @@ impl VariableOutputCore for StreebogVarCore { let mut block = buffer.pad_with_zeros(); block[pos] = 1; self.compress(block.as_ref(), pos as u64); - self.g(&[0u8; 64], &to_bytes(&self.n)); - self.g(&[0u8; 64], &to_bytes(&self.sigma)); - out.copy_from_slice(&self.h); + g(&mut self.h, &[0u64; 8], &self.n); + g(&mut self.h, &[0u64; 8], &self.sigma); + out.copy_from_slice(&to_bytes(&self.h)); } } @@ -185,41 +180,20 @@ impl SerializableState for StreebogVarCore { type SerializedStateSize = U192; fn serialize(&self) -> SerializedState { - let serialized_h = Array::<_, U64>::from(self.h); - - let mut serialized_n = Array::<_, U64>::default(); - for (val, chunk) in self.n.iter().zip(serialized_n.chunks_exact_mut(8)) { - chunk.copy_from_slice(&val.to_le_bytes()); - } - - let mut serialized_sigma = Array::<_, U64>::default(); - for (val, chunk) in self.sigma.iter().zip(serialized_sigma.chunks_exact_mut(8)) { - chunk.copy_from_slice(&val.to_le_bytes()); - } - - serialized_h.concat(serialized_n).concat(serialized_sigma) + let ser_h: Array = to_bytes(&self.h).into(); + let ser_n: Array = to_bytes(&self.n).into(); + let ser_sigma: Array = to_bytes(&self.sigma).into(); + ser_h.concat(ser_n).concat(ser_sigma) } - fn deserialize( - serialized_state: &SerializedState, - ) -> Result { - let (serialized_h, remaining_buffer) = serialized_state.split::(); - - let (serialized_n, serialized_sigma) = remaining_buffer.split::(); - let mut n = [0; 8]; - for (val, chunk) in n.iter_mut().zip(serialized_n.chunks_exact(8)) { - *val = u64::from_le_bytes(chunk.try_into().unwrap()); - } - - let mut sigma = [0; 8]; - for (val, chunk) in sigma.iter_mut().zip(serialized_sigma.chunks_exact(8)) { - *val = u64::from_le_bytes(chunk.try_into().unwrap()); - } + fn deserialize(ser_state: &SerializedState) -> Result { + let (ser_h, rem) = ser_state.split::(); + let (ser_n, ser_sigma) = rem.split::(); Ok(Self { - h: serialized_h.into(), - n, - sigma, + h: from_bytes(&ser_h.into()), + n: from_bytes(&ser_n.into()), + sigma: from_bytes(&ser_sigma.into()), }) } }