ring/digest/
sha2.rs

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}