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
15use crate::c;
16use 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")))]
22pub(super) extern "C" fn 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")))]
32pub(super) extern "C" fn 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]
46fn 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.cast::<[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, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = H;
75
76 // FIPS 180-4 {6.2.2, 6.4.2} Step 3
77 for (Kt, Wt) in S::K.iter().zip(W.iter()) {
78 let T1 = h + SIGMA_1(e) + ch(e, f, g) + *Kt + *Wt;
79 let T2 = SIGMA_0(a) + maj(a, b, c);
80 h = g;
81 g = f;
82 f = e;
83 e = d + T1;
84 d = c;
85 c = b;
86 b = a;
87 a = T1 + T2;
88 }
89
90 // FIPS 180-4 {6.2.2, 6.4.2} Step 4
91 H[0] += a;
92 H[1] += b;
93 H[2] += c;
94 H[3] += d;
95 H[4] += e;
96 H[5] += f;
97 H[6] += g;
98 H[7] += h;
99 }
100
101 H
102}
103
104// FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
105#[inline(always)]
106pub(super) fn ch<W: Word>(x: W, y: W, z: W) -> W {
107 (x & y) | (!x & z)
108}
109
110// FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
111#[inline(always)]
112pub(super) fn maj<W: Word>(x: W, y: W, z: W) -> W {
113 (x & y) | (x & z) | (y & z)
114}
115
116// FIPS 180-4 {4.1.2, 4.1.3}
117#[inline(always)]
118fn SIGMA_0<S: Sha2>(x: S) -> S {
119 x.rotr(S::BIG_SIGMA_0.0) ^ x.rotr(S::BIG_SIGMA_0.1) ^ x.rotr(S::BIG_SIGMA_0.2)
120}
121
122// FIPS 180-4 {4.1.2, 4.1.3}
123#[inline(always)]
124fn SIGMA_1<S: Sha2>(x: S) -> S {
125 x.rotr(S::BIG_SIGMA_1.0) ^ x.rotr(S::BIG_SIGMA_1.1) ^ x.rotr(S::BIG_SIGMA_1.2)
126}
127
128// FIPS 180-4 {4.1.2, 4.1.3}
129#[inline(always)]
130fn sigma_0<S: Sha2>(x: S) -> S {
131 x.rotr(S::SMALL_SIGMA_0.0) ^ x.rotr(S::SMALL_SIGMA_0.1) ^ (x >> S::SMALL_SIGMA_0.2)
132}
133
134// FIPS 180-4 {4.1.2, 4.1.3}
135#[inline(always)]
136fn sigma_1<S: Sha2>(x: S) -> S {
137 x.rotr(S::SMALL_SIGMA_1.0) ^ x.rotr(S::SMALL_SIGMA_1.1) ^ (x >> S::SMALL_SIGMA_1.2)
138}
139
140// Commonality between SHA-1 and SHA-2 words.
141pub(super) trait Word:
142 'static
143 + Sized
144 + Copy
145 + Add<Output = Self>
146 + AddAssign
147 + BitAnd<Output = Self>
148 + BitOr<Output = Self>
149 + Not<Output = Self>
150{
151 const ZERO: Self;
152
153 type InputBytes: Copy;
154
155 fn from_be_bytes(input: Self::InputBytes) -> Self;
156
157 fn rotr(self, count: u32) -> Self;
158}
159
160/// A SHA-2 input word.
161trait Sha2: Word + BitXor<Output = Self> + Shr<usize, Output = Self> {
162 const BIG_SIGMA_0: (u32, u32, u32);
163 const BIG_SIGMA_1: (u32, u32, u32);
164 const SMALL_SIGMA_0: (u32, u32, usize);
165 const SMALL_SIGMA_1: (u32, u32, usize);
166
167 const K: &'static [Self];
168}
169
170const MAX_ROUNDS: usize = 80;
171pub(super) const CHAINING_WORDS: usize = 8;
172
173impl Word for Wrapping<u32> {
174 const ZERO: Self = Self(0);
175 type InputBytes = [u8; 4];
176
177 #[inline(always)]
178 fn from_be_bytes(input: Self::InputBytes) -> Self {
179 Self(u32::from_be_bytes(input))
180 }
181
182 #[inline(always)]
183 fn rotr(self, count: u32) -> Self {
184 Self(self.0.rotate_right(count))
185 }
186}
187
188// SHA-256
189impl Sha2 for Wrapping<u32> {
190 // FIPS 180-4 4.1.2
191 const BIG_SIGMA_0: (u32, u32, u32) = (2, 13, 22);
192 const BIG_SIGMA_1: (u32, u32, u32) = (6, 11, 25);
193 const SMALL_SIGMA_0: (u32, u32, usize) = (7, 18, 3);
194 const SMALL_SIGMA_1: (u32, u32, usize) = (17, 19, 10);
195
196 // FIPS 180-4 4.2.2
197 const K: &'static [Self] = &[
198 Self(0x428a2f98),
199 Self(0x71374491),
200 Self(0xb5c0fbcf),
201 Self(0xe9b5dba5),
202 Self(0x3956c25b),
203 Self(0x59f111f1),
204 Self(0x923f82a4),
205 Self(0xab1c5ed5),
206 Self(0xd807aa98),
207 Self(0x12835b01),
208 Self(0x243185be),
209 Self(0x550c7dc3),
210 Self(0x72be5d74),
211 Self(0x80deb1fe),
212 Self(0x9bdc06a7),
213 Self(0xc19bf174),
214 Self(0xe49b69c1),
215 Self(0xefbe4786),
216 Self(0x0fc19dc6),
217 Self(0x240ca1cc),
218 Self(0x2de92c6f),
219 Self(0x4a7484aa),
220 Self(0x5cb0a9dc),
221 Self(0x76f988da),
222 Self(0x983e5152),
223 Self(0xa831c66d),
224 Self(0xb00327c8),
225 Self(0xbf597fc7),
226 Self(0xc6e00bf3),
227 Self(0xd5a79147),
228 Self(0x06ca6351),
229 Self(0x14292967),
230 Self(0x27b70a85),
231 Self(0x2e1b2138),
232 Self(0x4d2c6dfc),
233 Self(0x53380d13),
234 Self(0x650a7354),
235 Self(0x766a0abb),
236 Self(0x81c2c92e),
237 Self(0x92722c85),
238 Self(0xa2bfe8a1),
239 Self(0xa81a664b),
240 Self(0xc24b8b70),
241 Self(0xc76c51a3),
242 Self(0xd192e819),
243 Self(0xd6990624),
244 Self(0xf40e3585),
245 Self(0x106aa070),
246 Self(0x19a4c116),
247 Self(0x1e376c08),
248 Self(0x2748774c),
249 Self(0x34b0bcb5),
250 Self(0x391c0cb3),
251 Self(0x4ed8aa4a),
252 Self(0x5b9cca4f),
253 Self(0x682e6ff3),
254 Self(0x748f82ee),
255 Self(0x78a5636f),
256 Self(0x84c87814),
257 Self(0x8cc70208),
258 Self(0x90befffa),
259 Self(0xa4506ceb),
260 Self(0xbef9a3f7),
261 Self(0xc67178f2),
262 ];
263}
264
265impl Word for Wrapping<u64> {
266 const ZERO: Self = Self(0);
267 type InputBytes = [u8; 8];
268
269 #[inline(always)]
270 fn from_be_bytes(input: Self::InputBytes) -> Self {
271 Self(u64::from_be_bytes(input))
272 }
273
274 #[inline(always)]
275 fn rotr(self, count: u32) -> Self {
276 Self(self.0.rotate_right(count))
277 }
278}
279
280// SHA-384 and SHA-512
281impl Sha2 for Wrapping<u64> {
282 // FIPS 180-4 4.1.3
283 const BIG_SIGMA_0: (u32, u32, u32) = (28, 34, 39);
284 const BIG_SIGMA_1: (u32, u32, u32) = (14, 18, 41);
285 const SMALL_SIGMA_0: (u32, u32, usize) = (1, 8, 7);
286 const SMALL_SIGMA_1: (u32, u32, usize) = (19, 61, 6);
287
288 // FIPS 180-4 4.2.3
289 const K: &'static [Self] = &[
290 Self(0x428a2f98d728ae22),
291 Self(0x7137449123ef65cd),
292 Self(0xb5c0fbcfec4d3b2f),
293 Self(0xe9b5dba58189dbbc),
294 Self(0x3956c25bf348b538),
295 Self(0x59f111f1b605d019),
296 Self(0x923f82a4af194f9b),
297 Self(0xab1c5ed5da6d8118),
298 Self(0xd807aa98a3030242),
299 Self(0x12835b0145706fbe),
300 Self(0x243185be4ee4b28c),
301 Self(0x550c7dc3d5ffb4e2),
302 Self(0x72be5d74f27b896f),
303 Self(0x80deb1fe3b1696b1),
304 Self(0x9bdc06a725c71235),
305 Self(0xc19bf174cf692694),
306 Self(0xe49b69c19ef14ad2),
307 Self(0xefbe4786384f25e3),
308 Self(0x0fc19dc68b8cd5b5),
309 Self(0x240ca1cc77ac9c65),
310 Self(0x2de92c6f592b0275),
311 Self(0x4a7484aa6ea6e483),
312 Self(0x5cb0a9dcbd41fbd4),
313 Self(0x76f988da831153b5),
314 Self(0x983e5152ee66dfab),
315 Self(0xa831c66d2db43210),
316 Self(0xb00327c898fb213f),
317 Self(0xbf597fc7beef0ee4),
318 Self(0xc6e00bf33da88fc2),
319 Self(0xd5a79147930aa725),
320 Self(0x06ca6351e003826f),
321 Self(0x142929670a0e6e70),
322 Self(0x27b70a8546d22ffc),
323 Self(0x2e1b21385c26c926),
324 Self(0x4d2c6dfc5ac42aed),
325 Self(0x53380d139d95b3df),
326 Self(0x650a73548baf63de),
327 Self(0x766a0abb3c77b2a8),
328 Self(0x81c2c92e47edaee6),
329 Self(0x92722c851482353b),
330 Self(0xa2bfe8a14cf10364),
331 Self(0xa81a664bbc423001),
332 Self(0xc24b8b70d0f89791),
333 Self(0xc76c51a30654be30),
334 Self(0xd192e819d6ef5218),
335 Self(0xd69906245565a910),
336 Self(0xf40e35855771202a),
337 Self(0x106aa07032bbd1b8),
338 Self(0x19a4c116b8d2d0c8),
339 Self(0x1e376c085141ab53),
340 Self(0x2748774cdf8eeb99),
341 Self(0x34b0bcb5e19b48a8),
342 Self(0x391c0cb3c5c95a63),
343 Self(0x4ed8aa4ae3418acb),
344 Self(0x5b9cca4f7763e373),
345 Self(0x682e6ff3d6b2b8a3),
346 Self(0x748f82ee5defb2fc),
347 Self(0x78a5636f43172f60),
348 Self(0x84c87814a1f0ab72),
349 Self(0x8cc702081a6439ec),
350 Self(0x90befffa23631e28),
351 Self(0xa4506cebde82bde9),
352 Self(0xbef9a3f7b2c67915),
353 Self(0xc67178f2e372532b),
354 Self(0xca273eceea26619c),
355 Self(0xd186b8c721c0c207),
356 Self(0xeada7dd6cde0eb1e),
357 Self(0xf57d4f7fee6ed178),
358 Self(0x06f067aa72176fba),
359 Self(0x0a637dc5a2c898a6),
360 Self(0x113f9804bef90dae),
361 Self(0x1b710b35131c471b),
362 Self(0x28db77f523047d84),
363 Self(0x32caab7b40c72493),
364 Self(0x3c9ebe0a15c9bebc),
365 Self(0x431d67c49c100d4c),
366 Self(0x4cc5d4becb3e42b6),
367 Self(0x597f299cfc657e2a),
368 Self(0x5fcb6fab3ad6faec),
369 Self(0x6c44198c4a475817),
370 ];
371}
372
373#[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64"))]
374prefixed_extern! {
375 pub(super) fn sha256_block_data_order(
376 state: &mut super::State,
377 data: *const u8,
378 num: c::size_t,
379 );
380 pub(super) fn sha512_block_data_order(
381 state: &mut super::State,
382 data: *const u8,
383 num: c::size_t,
384 );
385}
386