1 // Copyright 2019 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15 use crate::c;
16 use core::{
17 num::Wrapping,
18 ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Not, Shr},
19 };
20
21 #[cfg(not(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64")))]
GFp_sha256_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )22 pub(super) extern "C" fn GFp_sha256_block_data_order(
23 state: &mut super::State,
24 data: *const u8,
25 num: c::size_t,
26 ) {
27 let state = unsafe { &mut state.as32 };
28 *state = block_data_order(*state, data, num)
29 }
30
31 #[cfg(not(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64")))]
GFp_sha512_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )32 pub(super) extern "C" fn GFp_sha512_block_data_order(
33 state: &mut super::State,
34 data: *const u8,
35 num: c::size_t,
36 ) {
37 let state = unsafe { &mut state.as64 };
38 *state = block_data_order(*state, data, num)
39 }
40
41 #[cfg_attr(
42 any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64"),
43 allow(dead_code)
44 )]
45 #[inline]
block_data_order<S: Sha2>( mut H: [S; CHAINING_WORDS], M: *const u8, num: c::size_t, ) -> [S; CHAINING_WORDS]46 fn block_data_order<S: Sha2>(
47 mut H: [S; CHAINING_WORDS],
48 M: *const u8,
49 num: c::size_t,
50 ) -> [S; CHAINING_WORDS] {
51 let M = M as *const [S::InputBytes; 16];
52 let M: &[[S::InputBytes; 16]] = unsafe { core::slice::from_raw_parts(M, num) };
53
54 for M in M {
55 // FIPS 180-4 {6.2.2, 6.4.2} Step 1
56 //
57 // TODO: Use `let W: [S::ZERO; S::ROUNDS]` instead of allocating
58 // `MAX_ROUNDS` items and then slicing to `K.len()`; depends on
59 // https://github.com/rust-lang/rust/issues/43408.
60 let mut W = [S::ZERO; MAX_ROUNDS];
61 let W: &[S] = {
62 let W = &mut W[..S::K.len()];
63 for (W, M) in W.iter_mut().zip(M) {
64 *W = S::from_be_bytes(*M);
65 }
66 for t in M.len()..S::K.len() {
67 W[t] = sigma_1(W[t - 2]) + W[t - 7] + sigma_0(W[t - 15]) + W[t - 16]
68 }
69
70 W
71 };
72
73 // FIPS 180-4 {6.2.2, 6.4.2} Step 2
74 let mut a = H[0];
75 let mut b = H[1];
76 let mut c = H[2];
77 let mut d = H[3];
78 let mut e = H[4];
79 let mut f = H[5];
80 let mut g = H[6];
81 let mut h = H[7];
82
83 // FIPS 180-4 {6.2.2, 6.4.2} Step 3
84 for (Kt, Wt) in S::K.iter().zip(W.iter()) {
85 let T1 = h + SIGMA_1(e) + ch(e, f, g) + *Kt + *Wt;
86 let T2 = SIGMA_0(a) + maj(a, b, c);
87 h = g;
88 g = f;
89 f = e;
90 e = d + T1;
91 d = c;
92 c = b;
93 b = a;
94 a = T1 + T2;
95 }
96
97 // FIPS 180-4 {6.2.2, 6.4.2} Step 4
98 H[0] += a;
99 H[1] += b;
100 H[2] += c;
101 H[3] += d;
102 H[4] += e;
103 H[5] += f;
104 H[6] += g;
105 H[7] += h;
106 }
107
108 H
109 }
110
111 // FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
112 #[inline(always)]
ch<W: Word>(x: W, y: W, z: W) -> W113 pub(super) fn ch<W: Word>(x: W, y: W, z: W) -> W {
114 (x & y) | (!x & z)
115 }
116
117 // FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
118 #[inline(always)]
maj<W: Word>(x: W, y: W, z: W) -> W119 pub(super) fn maj<W: Word>(x: W, y: W, z: W) -> W {
120 (x & y) | (x & z) | (y & z)
121 }
122
123 // FIPS 180-4 {4.1.2, 4.1.3}
124 #[inline(always)]
SIGMA_0<S: Sha2>(x: S) -> S125 fn SIGMA_0<S: Sha2>(x: S) -> S {
126 x.rotr(S::BIG_SIGMA_0.0) ^ x.rotr(S::BIG_SIGMA_0.1) ^ x.rotr(S::BIG_SIGMA_0.2)
127 }
128
129 // FIPS 180-4 {4.1.2, 4.1.3}
130 #[inline(always)]
SIGMA_1<S: Sha2>(x: S) -> S131 fn SIGMA_1<S: Sha2>(x: S) -> S {
132 x.rotr(S::BIG_SIGMA_1.0) ^ x.rotr(S::BIG_SIGMA_1.1) ^ x.rotr(S::BIG_SIGMA_1.2)
133 }
134
135 // FIPS 180-4 {4.1.2, 4.1.3}
136 #[inline(always)]
sigma_0<S: Sha2>(x: S) -> S137 fn sigma_0<S: Sha2>(x: S) -> S {
138 x.rotr(S::SMALL_SIGMA_0.0) ^ x.rotr(S::SMALL_SIGMA_0.1) ^ (x >> S::SMALL_SIGMA_0.2)
139 }
140
141 // FIPS 180-4 {4.1.2, 4.1.3}
142 #[inline(always)]
sigma_1<S: Sha2>(x: S) -> S143 fn sigma_1<S: Sha2>(x: S) -> S {
144 x.rotr(S::SMALL_SIGMA_1.0) ^ x.rotr(S::SMALL_SIGMA_1.1) ^ (x >> S::SMALL_SIGMA_1.2)
145 }
146
147 // Commonality between SHA-1 and SHA-2 words.
148 pub(super) trait Word:
149 'static
150 + Sized
151 + Copy
152 + Add<Output = Self>
153 + AddAssign
154 + BitAnd<Output = Self>
155 + BitOr<Output = Self>
156 + Not<Output = Self>
157 {
158 const ZERO: Self;
159
160 type InputBytes: Copy;
161
from_be_bytes(input: Self::InputBytes) -> Self162 fn from_be_bytes(input: Self::InputBytes) -> Self;
163
rotr(self, count: u32) -> Self164 fn rotr(self, count: u32) -> Self;
165 }
166
167 /// A SHA-2 input word.
168 trait Sha2: Word + BitXor<Output = Self> + Shr<usize, Output = Self> {
169 const BIG_SIGMA_0: (u32, u32, u32);
170 const BIG_SIGMA_1: (u32, u32, u32);
171 const SMALL_SIGMA_0: (u32, u32, usize);
172 const SMALL_SIGMA_1: (u32, u32, usize);
173
174 const K: &'static [Self];
175 }
176
177 const MAX_ROUNDS: usize = 80;
178 pub(super) const CHAINING_WORDS: usize = 8;
179
180 impl Word for Wrapping<u32> {
181 const ZERO: Self = Wrapping(0);
182 type InputBytes = [u8; 4];
183
184 #[inline(always)]
from_be_bytes(input: Self::InputBytes) -> Self185 fn from_be_bytes(input: Self::InputBytes) -> Self {
186 Wrapping(u32::from_be_bytes(input))
187 }
188
189 #[inline(always)]
rotr(self, count: u32) -> Self190 fn rotr(self, count: u32) -> Self {
191 Wrapping(self.0.rotate_right(count))
192 }
193 }
194
195 // SHA-256
196 impl Sha2 for Wrapping<u32> {
197 // FIPS 180-4 4.1.2
198 const BIG_SIGMA_0: (u32, u32, u32) = (2, 13, 22);
199 const BIG_SIGMA_1: (u32, u32, u32) = (6, 11, 25);
200 const SMALL_SIGMA_0: (u32, u32, usize) = (7, 18, 3);
201 const SMALL_SIGMA_1: (u32, u32, usize) = (17, 19, 10);
202
203 // FIPS 180-4 4.2.2
204 const K: &'static [Self] = &[
205 Self(0x428a2f98),
206 Self(0x71374491),
207 Self(0xb5c0fbcf),
208 Self(0xe9b5dba5),
209 Self(0x3956c25b),
210 Self(0x59f111f1),
211 Self(0x923f82a4),
212 Self(0xab1c5ed5),
213 Self(0xd807aa98),
214 Self(0x12835b01),
215 Self(0x243185be),
216 Self(0x550c7dc3),
217 Self(0x72be5d74),
218 Self(0x80deb1fe),
219 Self(0x9bdc06a7),
220 Self(0xc19bf174),
221 Self(0xe49b69c1),
222 Self(0xefbe4786),
223 Self(0x0fc19dc6),
224 Self(0x240ca1cc),
225 Self(0x2de92c6f),
226 Self(0x4a7484aa),
227 Self(0x5cb0a9dc),
228 Self(0x76f988da),
229 Self(0x983e5152),
230 Self(0xa831c66d),
231 Self(0xb00327c8),
232 Self(0xbf597fc7),
233 Self(0xc6e00bf3),
234 Self(0xd5a79147),
235 Self(0x06ca6351),
236 Self(0x14292967),
237 Self(0x27b70a85),
238 Self(0x2e1b2138),
239 Self(0x4d2c6dfc),
240 Self(0x53380d13),
241 Self(0x650a7354),
242 Self(0x766a0abb),
243 Self(0x81c2c92e),
244 Self(0x92722c85),
245 Self(0xa2bfe8a1),
246 Self(0xa81a664b),
247 Self(0xc24b8b70),
248 Self(0xc76c51a3),
249 Self(0xd192e819),
250 Self(0xd6990624),
251 Self(0xf40e3585),
252 Self(0x106aa070),
253 Self(0x19a4c116),
254 Self(0x1e376c08),
255 Self(0x2748774c),
256 Self(0x34b0bcb5),
257 Self(0x391c0cb3),
258 Self(0x4ed8aa4a),
259 Self(0x5b9cca4f),
260 Self(0x682e6ff3),
261 Self(0x748f82ee),
262 Self(0x78a5636f),
263 Self(0x84c87814),
264 Self(0x8cc70208),
265 Self(0x90befffa),
266 Self(0xa4506ceb),
267 Self(0xbef9a3f7),
268 Self(0xc67178f2),
269 ];
270 }
271
272 impl Word for Wrapping<u64> {
273 const ZERO: Self = Wrapping(0);
274 type InputBytes = [u8; 8];
275
276 #[inline(always)]
from_be_bytes(input: Self::InputBytes) -> Self277 fn from_be_bytes(input: Self::InputBytes) -> Self {
278 Wrapping(u64::from_be_bytes(input))
279 }
280
281 #[inline(always)]
rotr(self, count: u32) -> Self282 fn rotr(self, count: u32) -> Self {
283 Wrapping(self.0.rotate_right(count))
284 }
285 }
286
287 // SHA-384 and SHA-512
288 impl Sha2 for Wrapping<u64> {
289 // FIPS 180-4 4.1.3
290 const BIG_SIGMA_0: (u32, u32, u32) = (28, 34, 39);
291 const BIG_SIGMA_1: (u32, u32, u32) = (14, 18, 41);
292 const SMALL_SIGMA_0: (u32, u32, usize) = (1, 8, 7);
293 const SMALL_SIGMA_1: (u32, u32, usize) = (19, 61, 6);
294
295 // FIPS 180-4 4.2.3
296 const K: &'static [Self] = &[
297 Self(0x428a2f98d728ae22),
298 Self(0x7137449123ef65cd),
299 Self(0xb5c0fbcfec4d3b2f),
300 Self(0xe9b5dba58189dbbc),
301 Self(0x3956c25bf348b538),
302 Self(0x59f111f1b605d019),
303 Self(0x923f82a4af194f9b),
304 Self(0xab1c5ed5da6d8118),
305 Self(0xd807aa98a3030242),
306 Self(0x12835b0145706fbe),
307 Self(0x243185be4ee4b28c),
308 Self(0x550c7dc3d5ffb4e2),
309 Self(0x72be5d74f27b896f),
310 Self(0x80deb1fe3b1696b1),
311 Self(0x9bdc06a725c71235),
312 Self(0xc19bf174cf692694),
313 Self(0xe49b69c19ef14ad2),
314 Self(0xefbe4786384f25e3),
315 Self(0x0fc19dc68b8cd5b5),
316 Self(0x240ca1cc77ac9c65),
317 Self(0x2de92c6f592b0275),
318 Self(0x4a7484aa6ea6e483),
319 Self(0x5cb0a9dcbd41fbd4),
320 Self(0x76f988da831153b5),
321 Self(0x983e5152ee66dfab),
322 Self(0xa831c66d2db43210),
323 Self(0xb00327c898fb213f),
324 Self(0xbf597fc7beef0ee4),
325 Self(0xc6e00bf33da88fc2),
326 Self(0xd5a79147930aa725),
327 Self(0x06ca6351e003826f),
328 Self(0x142929670a0e6e70),
329 Self(0x27b70a8546d22ffc),
330 Self(0x2e1b21385c26c926),
331 Self(0x4d2c6dfc5ac42aed),
332 Self(0x53380d139d95b3df),
333 Self(0x650a73548baf63de),
334 Self(0x766a0abb3c77b2a8),
335 Self(0x81c2c92e47edaee6),
336 Self(0x92722c851482353b),
337 Self(0xa2bfe8a14cf10364),
338 Self(0xa81a664bbc423001),
339 Self(0xc24b8b70d0f89791),
340 Self(0xc76c51a30654be30),
341 Self(0xd192e819d6ef5218),
342 Self(0xd69906245565a910),
343 Self(0xf40e35855771202a),
344 Self(0x106aa07032bbd1b8),
345 Self(0x19a4c116b8d2d0c8),
346 Self(0x1e376c085141ab53),
347 Self(0x2748774cdf8eeb99),
348 Self(0x34b0bcb5e19b48a8),
349 Self(0x391c0cb3c5c95a63),
350 Self(0x4ed8aa4ae3418acb),
351 Self(0x5b9cca4f7763e373),
352 Self(0x682e6ff3d6b2b8a3),
353 Self(0x748f82ee5defb2fc),
354 Self(0x78a5636f43172f60),
355 Self(0x84c87814a1f0ab72),
356 Self(0x8cc702081a6439ec),
357 Self(0x90befffa23631e28),
358 Self(0xa4506cebde82bde9),
359 Self(0xbef9a3f7b2c67915),
360 Self(0xc67178f2e372532b),
361 Self(0xca273eceea26619c),
362 Self(0xd186b8c721c0c207),
363 Self(0xeada7dd6cde0eb1e),
364 Self(0xf57d4f7fee6ed178),
365 Self(0x06f067aa72176fba),
366 Self(0x0a637dc5a2c898a6),
367 Self(0x113f9804bef90dae),
368 Self(0x1b710b35131c471b),
369 Self(0x28db77f523047d84),
370 Self(0x32caab7b40c72493),
371 Self(0x3c9ebe0a15c9bebc),
372 Self(0x431d67c49c100d4c),
373 Self(0x4cc5d4becb3e42b6),
374 Self(0x597f299cfc657e2a),
375 Self(0x5fcb6fab3ad6faec),
376 Self(0x6c44198c4a475817),
377 ];
378 }
379
380 #[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64"))]
381 extern "C" {
GFp_sha256_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )382 pub(super) fn GFp_sha256_block_data_order(
383 state: &mut super::State,
384 data: *const u8,
385 num: c::size_t,
386 );
GFp_sha512_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )387 pub(super) fn GFp_sha512_block_data_order(
388 state: &mut super::State,
389 data: *const u8,
390 num: c::size_t,
391 );
392 }
393