More code cleanup of the hash.

This commit is contained in:
Nathan Vegdahl 2020-02-24 13:31:17 +09:00
parent 4e435732d7
commit 27572c8838

View File

@ -79,7 +79,11 @@ impl LedHash256 {
} }
// Hash the message length, in bits. // Hash the message length, in bits.
mix(&mut self.state[..], &[self.message_length * 8, 0, 0, 0]); self.buf[..8].copy_from_slice(&(self.message_length * 8).to_le_bytes());
for i in (&mut self.buf[8..]).iter_mut() {
*i = 0;
}
self.mix_buffer_into_state();
// Get the digest as a byte array and return it. // Get the digest as a byte array and return it.
let mut digest = [0u8; BLOCK_SIZE]; let mut digest = [0u8; BLOCK_SIZE];
@ -90,66 +94,63 @@ impl LedHash256 {
return digest; return digest;
} }
/// The main mix function. Mixes the buffer into the hash state.
///
/// Inspired by Skein 1.3, and using its MIX function and its constants.
/// This does 9 rounds of mixing, as that produces full diffusion for
/// 256-bit state according to the Skein 1.3 paper.
///
/// The mix rotation constants, as taken from Skein 1.3 256-bit variant:
/// 14 16
/// 52 57
/// 23 40
/// 5 37
/// 25 33
/// 46 12
/// 58 22
/// 32 32
/// repeat
///
/// The permute table, as taken from Skein 1.3 256-bit variant:
/// Indices: 0 1 2 3
/// Become: 0 3 2 1
fn mix_buffer_into_state(&mut self) { fn mix_buffer_into_state(&mut self) {
// Convert the buffer to native endian u64's and xor into the
// hash state.
let (a, b, c) = unsafe { self.buf.align_to::<u64>() }; let (a, b, c) = unsafe { self.buf.align_to::<u64>() };
debug_assert!(a.is_empty()); debug_assert!(a.is_empty());
debug_assert!(c.is_empty()); debug_assert!(c.is_empty());
mix(&mut self.state[..], b); self.state[0] ^= u64::from_le(b[0]);
} self.state[1] ^= u64::from_le(b[1]);
} self.state[2] ^= u64::from_le(b[2]);
self.state[3] ^= u64::from_le(b[3]);
/// The main mix function. Mixes a block into the hash state. // Mixing constants.
/// const ROUNDS: usize = 9;
/// Inspired by Skein 1.3, and using its MIX function and its constants. const ROTATION_TABLE: [(u32, u32); 8] = [
/// This does 9 rounds of mixing, as that produces full diffusion for (14, 16),
/// 256-bit state according to the Skein 1.3 paper. (52, 57),
/// (23, 40),
/// The mix rotation constants, as taken from Skein 1.3 256-bit variant: (5, 37),
/// 14 16 (25, 33),
/// 52 57 (46, 12),
/// 23 40 (58, 22),
/// 5 37 (32, 32),
/// 25 33 ];
/// 46 12
/// 58 22
/// 32 32
/// repeat
///
/// The permute table, as taken from Skein 1.3 256-bit variant:
/// Indices: 0 1 2 3
/// Become: 0 3 2 1
fn mix(state: &mut [u64], block: &[u64]) {
// Convert the block to native endianness and xor into the hash state.
state[0] ^= u64::from_le(block[0]);
state[1] ^= u64::from_le(block[1]);
state[2] ^= u64::from_le(block[2]);
state[3] ^= u64::from_le(block[3]);
// Mixing constants. // Do the mixing.
const ROUNDS: usize = 9; for &(rot_1, rot_2) in ROTATION_TABLE.iter().cycle().take(ROUNDS) {
const ROTATION_TABLE: [(u32, u32); 8] = [ // Skein MIX function.
(14, 16), self.state[0] = self.state[0].wrapping_add(self.state[1]);
(52, 57), self.state[1] = self.state[1].rotate_left(rot_1) ^ self.state[0];
(23, 40),
(5, 37),
(25, 33),
(46, 12),
(58, 22),
(32, 32),
];
// Do the mixing. // Skein MIX function.
for &(rot_1, rot_2) in ROTATION_TABLE.iter().cycle().take(ROUNDS) { self.state[2] = self.state[2].wrapping_add(self.state[3]);
// Skein MIX function. self.state[3] = self.state[3].rotate_left(rot_2) ^ self.state[2];
state[0] = state[0].wrapping_add(state[1]);
state[1] = state[1].rotate_left(rot_1) ^ state[0];
// Skein MIX function. // Permute.
state[2] = state[2].wrapping_add(state[3]); self.state.swap(1, 3);
state[3] = state[3].rotate_left(rot_2) ^ state[2]; }
// Permute.
state.swap(1, 3);
} }
} }