ring/digest/sha2/
fallback.rs

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