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 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")))]
32pub(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]
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 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)]
113pub(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)]
119pub(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)]
125fn 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)]
131fn 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)]
137fn 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)]
143fn 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.
148pub(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
162    fn from_be_bytes(input: Self::InputBytes) -> Self;
163
164    fn rotr(self, count: u32) -> Self;
165}
166
167/// A SHA-2 input word.
168trait 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
177const MAX_ROUNDS: usize = 80;
178pub(super) const CHAINING_WORDS: usize = 8;
179
180impl Word for Wrapping<u32> {
181    const ZERO: Self = Wrapping(0);
182    type InputBytes = [u8; 4];
183
184    #[inline(always)]
185    fn from_be_bytes(input: Self::InputBytes) -> Self {
186        Wrapping(u32::from_be_bytes(input))
187    }
188
189    #[inline(always)]
190    fn rotr(self, count: u32) -> Self {
191        Wrapping(self.0.rotate_right(count))
192    }
193}
194
195// SHA-256
196impl 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
272impl Word for Wrapping<u64> {
273    const ZERO: Self = Wrapping(0);
274    type InputBytes = [u8; 8];
275
276    #[inline(always)]
277    fn from_be_bytes(input: Self::InputBytes) -> Self {
278        Wrapping(u64::from_be_bytes(input))
279    }
280
281    #[inline(always)]
282    fn rotr(self, count: u32) -> Self {
283        Wrapping(self.0.rotate_right(count))
284    }
285}
286
287// SHA-384 and SHA-512
288impl 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"))]
381extern "C" {
382    pub(super) fn GFp_sha256_block_data_order(
383        state: &mut super::State,
384        data: *const u8,
385        num: c::size_t,
386    );
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}