diff options
Diffstat (limited to 'third_party/rust/blake2b_simd/src/portable.rs')
-rw-r--r-- | third_party/rust/blake2b_simd/src/portable.rs | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/third_party/rust/blake2b_simd/src/portable.rs b/third_party/rust/blake2b_simd/src/portable.rs new file mode 100644 index 0000000000..5a667ef2a8 --- /dev/null +++ b/third_party/rust/blake2b_simd/src/portable.rs @@ -0,0 +1,166 @@ +use arrayref::{array_ref, array_refs}; + +use super::*; +use crate::guts::{ + count_high, count_low, final_block, flag_word, input_debug_asserts, Finalize, LastNode, Stride, +}; + +// G is the mixing function, called eight times per round in the compression +// function. V is the 16-word state vector of the compression function, usually +// described as a 4x4 matrix. A, B, C, and D are the mixing indices, set by the +// caller first to the four columns of V, and then to its four diagonals. X and +// Y are words of input, chosen by the caller according to the message +// schedule, SIGMA. +#[inline(always)] +fn g(v: &mut [Word; 16], a: usize, b: usize, c: usize, d: usize, x: Word, y: Word) { + v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); + v[d] = (v[d] ^ v[a]).rotate_right(32); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(24); + v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); + v[d] = (v[d] ^ v[a]).rotate_right(16); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(63); +} + +#[inline(always)] +fn round(r: usize, m: &[Word; 16], v: &mut [Word; 16]) { + // Select the message schedule based on the round. + let s = SIGMA[r]; + + // Mix the columns. + g(v, 0, 4, 8, 12, m[s[0] as usize], m[s[1] as usize]); + g(v, 1, 5, 9, 13, m[s[2] as usize], m[s[3] as usize]); + g(v, 2, 6, 10, 14, m[s[4] as usize], m[s[5] as usize]); + g(v, 3, 7, 11, 15, m[s[6] as usize], m[s[7] as usize]); + + // Mix the rows. + g(v, 0, 5, 10, 15, m[s[8] as usize], m[s[9] as usize]); + g(v, 1, 6, 11, 12, m[s[10] as usize], m[s[11] as usize]); + g(v, 2, 7, 8, 13, m[s[12] as usize], m[s[13] as usize]); + g(v, 3, 4, 9, 14, m[s[14] as usize], m[s[15] as usize]); +} + +#[inline(always)] +fn compress_block( + block: &[u8; BLOCKBYTES], + words: &mut [Word; 8], + count: Count, + last_block: Word, + last_node: Word, +) { + // Initialize the compression state. + let mut v = [ + words[0], + words[1], + words[2], + words[3], + words[4], + words[5], + words[6], + words[7], + IV[0], + IV[1], + IV[2], + IV[3], + IV[4] ^ count_low(count), + IV[5] ^ count_high(count), + IV[6] ^ last_block, + IV[7] ^ last_node, + ]; + + // Parse the message bytes as ints in little endian order. + const W: usize = size_of::<Word>(); + let msg_refs = array_refs!(block, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W); + let m = [ + Word::from_le_bytes(*msg_refs.0), + Word::from_le_bytes(*msg_refs.1), + Word::from_le_bytes(*msg_refs.2), + Word::from_le_bytes(*msg_refs.3), + Word::from_le_bytes(*msg_refs.4), + Word::from_le_bytes(*msg_refs.5), + Word::from_le_bytes(*msg_refs.6), + Word::from_le_bytes(*msg_refs.7), + Word::from_le_bytes(*msg_refs.8), + Word::from_le_bytes(*msg_refs.9), + Word::from_le_bytes(*msg_refs.10), + Word::from_le_bytes(*msg_refs.11), + Word::from_le_bytes(*msg_refs.12), + Word::from_le_bytes(*msg_refs.13), + Word::from_le_bytes(*msg_refs.14), + Word::from_le_bytes(*msg_refs.15), + ]; + + round(0, &m, &mut v); + round(1, &m, &mut v); + round(2, &m, &mut v); + round(3, &m, &mut v); + round(4, &m, &mut v); + round(5, &m, &mut v); + round(6, &m, &mut v); + round(7, &m, &mut v); + round(8, &m, &mut v); + round(9, &m, &mut v); + round(10, &m, &mut v); + round(11, &m, &mut v); + + words[0] ^= v[0] ^ v[8]; + words[1] ^= v[1] ^ v[9]; + words[2] ^= v[2] ^ v[10]; + words[3] ^= v[3] ^ v[11]; + words[4] ^= v[4] ^ v[12]; + words[5] ^= v[5] ^ v[13]; + words[6] ^= v[6] ^ v[14]; + words[7] ^= v[7] ^ v[15]; +} + +pub fn compress1_loop( + input: &[u8], + words: &mut [Word; 8], + mut count: Count, + last_node: LastNode, + finalize: Finalize, + stride: Stride, +) { + input_debug_asserts(input, finalize); + + let mut local_words = *words; + + let mut fin_offset = input.len().saturating_sub(1); + fin_offset -= fin_offset % stride.padded_blockbytes(); + let mut buf = [0; BLOCKBYTES]; + let (fin_block, fin_len, _) = final_block(input, fin_offset, &mut buf, stride); + let fin_last_block = flag_word(finalize.yes()); + let fin_last_node = flag_word(finalize.yes() && last_node.yes()); + + let mut offset = 0; + loop { + let block; + let count_delta; + let last_block; + let last_node; + if offset == fin_offset { + block = fin_block; + count_delta = fin_len; + last_block = fin_last_block; + last_node = fin_last_node; + } else { + block = array_ref!(input, offset, BLOCKBYTES); + count_delta = BLOCKBYTES; + last_block = flag_word(false); + last_node = flag_word(false); + }; + + count = count.wrapping_add(count_delta as Count); + compress_block(block, &mut local_words, count, last_block, last_node); + + // Check for termination before bumping the offset, to avoid overflow. + if offset == fin_offset { + break; + } + + offset += stride.padded_blockbytes(); + } + + *words = local_words; +} |