/rust/registry/src/index.crates.io-1949cf8c6b5b557f/blake3-1.8.4/src/portable.rs
Line | Count | Source |
1 | | use crate::{ |
2 | | counter_high, counter_low, CVBytes, CVWords, IncrementCounter, BLOCK_LEN, IV, MSG_SCHEDULE, |
3 | | OUT_LEN, |
4 | | }; |
5 | | use arrayref::{array_mut_ref, array_ref}; |
6 | | |
7 | | #[inline(always)] |
8 | 0 | fn g(state: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize, x: u32, y: u32) { |
9 | 0 | state[a] = state[a].wrapping_add(state[b]).wrapping_add(x); |
10 | 0 | state[d] = (state[d] ^ state[a]).rotate_right(16); |
11 | 0 | state[c] = state[c].wrapping_add(state[d]); |
12 | 0 | state[b] = (state[b] ^ state[c]).rotate_right(12); |
13 | 0 | state[a] = state[a].wrapping_add(state[b]).wrapping_add(y); |
14 | 0 | state[d] = (state[d] ^ state[a]).rotate_right(8); |
15 | 0 | state[c] = state[c].wrapping_add(state[d]); |
16 | 0 | state[b] = (state[b] ^ state[c]).rotate_right(7); |
17 | 0 | } |
18 | | |
19 | | #[inline(always)] |
20 | 0 | fn round(state: &mut [u32; 16], msg: &[u32; 16], round: usize) { |
21 | | // Select the message schedule based on the round. |
22 | 0 | let schedule = MSG_SCHEDULE[round]; |
23 | | |
24 | | // Mix the columns. |
25 | 0 | g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); |
26 | 0 | g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); |
27 | 0 | g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); |
28 | 0 | g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); |
29 | | |
30 | | // Mix the diagonals. |
31 | 0 | g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); |
32 | 0 | g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); |
33 | 0 | g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); |
34 | 0 | g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); |
35 | 0 | } |
36 | | |
37 | | #[inline(always)] |
38 | 0 | fn compress_pre( |
39 | 0 | cv: &CVWords, |
40 | 0 | block: &[u8; BLOCK_LEN], |
41 | 0 | block_len: u8, |
42 | 0 | counter: u64, |
43 | 0 | flags: u8, |
44 | 0 | ) -> [u32; 16] { |
45 | 0 | let block_words = crate::platform::words_from_le_bytes_64(block); |
46 | | |
47 | 0 | let mut state = [ |
48 | 0 | cv[0], |
49 | 0 | cv[1], |
50 | 0 | cv[2], |
51 | 0 | cv[3], |
52 | 0 | cv[4], |
53 | 0 | cv[5], |
54 | 0 | cv[6], |
55 | 0 | cv[7], |
56 | 0 | IV[0], |
57 | 0 | IV[1], |
58 | 0 | IV[2], |
59 | 0 | IV[3], |
60 | 0 | counter_low(counter), |
61 | 0 | counter_high(counter), |
62 | 0 | block_len as u32, |
63 | 0 | flags as u32, |
64 | 0 | ]; |
65 | | |
66 | 0 | round(&mut state, &block_words, 0); |
67 | 0 | round(&mut state, &block_words, 1); |
68 | 0 | round(&mut state, &block_words, 2); |
69 | 0 | round(&mut state, &block_words, 3); |
70 | 0 | round(&mut state, &block_words, 4); |
71 | 0 | round(&mut state, &block_words, 5); |
72 | 0 | round(&mut state, &block_words, 6); |
73 | | |
74 | 0 | state |
75 | 0 | } |
76 | | |
77 | 0 | pub fn compress_in_place( |
78 | 0 | cv: &mut CVWords, |
79 | 0 | block: &[u8; BLOCK_LEN], |
80 | 0 | block_len: u8, |
81 | 0 | counter: u64, |
82 | 0 | flags: u8, |
83 | 0 | ) { |
84 | 0 | let state = compress_pre(cv, block, block_len, counter, flags); |
85 | | |
86 | 0 | cv[0] = state[0] ^ state[8]; |
87 | 0 | cv[1] = state[1] ^ state[9]; |
88 | 0 | cv[2] = state[2] ^ state[10]; |
89 | 0 | cv[3] = state[3] ^ state[11]; |
90 | 0 | cv[4] = state[4] ^ state[12]; |
91 | 0 | cv[5] = state[5] ^ state[13]; |
92 | 0 | cv[6] = state[6] ^ state[14]; |
93 | 0 | cv[7] = state[7] ^ state[15]; |
94 | 0 | } |
95 | | |
96 | 0 | pub fn compress_xof( |
97 | 0 | cv: &CVWords, |
98 | 0 | block: &[u8; BLOCK_LEN], |
99 | 0 | block_len: u8, |
100 | 0 | counter: u64, |
101 | 0 | flags: u8, |
102 | 0 | ) -> [u8; 64] { |
103 | 0 | let mut state = compress_pre(cv, block, block_len, counter, flags); |
104 | 0 | state[0] ^= state[8]; |
105 | 0 | state[1] ^= state[9]; |
106 | 0 | state[2] ^= state[10]; |
107 | 0 | state[3] ^= state[11]; |
108 | 0 | state[4] ^= state[12]; |
109 | 0 | state[5] ^= state[13]; |
110 | 0 | state[6] ^= state[14]; |
111 | 0 | state[7] ^= state[15]; |
112 | 0 | state[8] ^= cv[0]; |
113 | 0 | state[9] ^= cv[1]; |
114 | 0 | state[10] ^= cv[2]; |
115 | 0 | state[11] ^= cv[3]; |
116 | 0 | state[12] ^= cv[4]; |
117 | 0 | state[13] ^= cv[5]; |
118 | 0 | state[14] ^= cv[6]; |
119 | 0 | state[15] ^= cv[7]; |
120 | 0 | crate::platform::le_bytes_from_words_64(&state) |
121 | 0 | } |
122 | | |
123 | 0 | pub fn hash1<const N: usize>( |
124 | 0 | input: &[u8; N], |
125 | 0 | key: &CVWords, |
126 | 0 | counter: u64, |
127 | 0 | flags: u8, |
128 | 0 | flags_start: u8, |
129 | 0 | flags_end: u8, |
130 | 0 | out: &mut CVBytes, |
131 | 0 | ) { |
132 | 0 | debug_assert_eq!(N % BLOCK_LEN, 0, "uneven blocks"); |
133 | 0 | let mut cv = *key; |
134 | 0 | let mut block_flags = flags | flags_start; |
135 | 0 | let mut slice = &input[..]; |
136 | 0 | while slice.len() >= BLOCK_LEN { |
137 | 0 | if slice.len() == BLOCK_LEN { |
138 | 0 | block_flags |= flags_end; |
139 | 0 | } |
140 | 0 | compress_in_place( |
141 | 0 | &mut cv, |
142 | 0 | array_ref!(slice, 0, BLOCK_LEN), |
143 | 0 | BLOCK_LEN as u8, |
144 | 0 | counter, |
145 | 0 | block_flags, |
146 | | ); |
147 | 0 | block_flags = flags; |
148 | 0 | slice = &slice[BLOCK_LEN..]; |
149 | | } |
150 | 0 | *out = crate::platform::le_bytes_from_words_32(&cv); |
151 | 0 | } Unexecuted instantiation: blake3::portable::hash1::<1024> Unexecuted instantiation: blake3::portable::hash1::<64> |
152 | | |
153 | 0 | pub fn hash_many<const N: usize>( |
154 | 0 | inputs: &[&[u8; N]], |
155 | 0 | key: &CVWords, |
156 | 0 | mut counter: u64, |
157 | 0 | increment_counter: IncrementCounter, |
158 | 0 | flags: u8, |
159 | 0 | flags_start: u8, |
160 | 0 | flags_end: u8, |
161 | 0 | out: &mut [u8], |
162 | 0 | ) { |
163 | 0 | debug_assert!(out.len() >= inputs.len() * OUT_LEN, "out too short"); |
164 | 0 | for (&input, output) in inputs.iter().zip(out.chunks_exact_mut(OUT_LEN)) { |
165 | 0 | hash1( |
166 | 0 | input, |
167 | 0 | key, |
168 | 0 | counter, |
169 | 0 | flags, |
170 | 0 | flags_start, |
171 | 0 | flags_end, |
172 | 0 | array_mut_ref!(output, 0, OUT_LEN), |
173 | | ); |
174 | 0 | if increment_counter.yes() { |
175 | 0 | counter += 1; |
176 | 0 | } |
177 | | } |
178 | 0 | } Unexecuted instantiation: blake3::portable::hash_many::<1024> Unexecuted instantiation: blake3::portable::hash_many::<64> |
179 | | |
180 | | #[cfg(test)] |
181 | | pub mod test { |
182 | | use super::*; |
183 | | |
184 | | // This is basically testing the portable implementation against itself, |
185 | | // but it also checks that compress_in_place and compress_xof are |
186 | | // consistent. And there are tests against the reference implementation and |
187 | | // against hardcoded test vectors elsewhere. |
188 | | #[test] |
189 | | fn test_compress() { |
190 | | crate::test::test_compress_fn(compress_in_place, compress_xof); |
191 | | } |
192 | | |
193 | | // Ditto. |
194 | | #[test] |
195 | | fn test_hash_many() { |
196 | | crate::test::test_hash_many_fn(hash_many, hash_many); |
197 | | } |
198 | | } |