1#![allow(clippy::many_single_char_names)]
2use crate::consts::BLOCK_LEN;
3use core::convert::TryInto;
4
5#[inline(always)]
6fn shl(v: [u32; 4], o: u32) -> [u32; 4] {
7 [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o]
8}
9
10#[inline(always)]
11fn shr(v: [u32; 4], o: u32) -> [u32; 4] {
12 [v[0] << o, v[1] << o, v[2] << o, v[3] << o]
13}
14
15#[inline(always)]
16fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
17 [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]]
18}
19
20#[inline(always)]
21fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
22 [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]]
23}
24
25#[inline(always)]
26fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
27 [
28 a[0].wrapping_add(b[0]),
29 a[1].wrapping_add(b[1]),
30 a[2].wrapping_add(b[2]),
31 a[3].wrapping_add(b[3]),
32 ]
33}
34
35fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
36 [v3[3], v2[0], v2[1], v2[2]]
37}
38
39fn sha256swap(v0: [u32; 4]) -> [u32; 4] {
40 [v0[2], v0[3], v0[0], v0[1]]
41}
42
43fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] {
44 // sigma 0 on vectors
45 #[inline]
46 fn sigma0x4(x: [u32; 4]) -> [u32; 4] {
47 let t1: [u32; 4] = or(a:shl(x, 7), b:shr(v:x, o:25));
48 let t2: [u32; 4] = or(a:shl(x, 18), b:shr(v:x, o:14));
49 let t3: [u32; 4] = shl(v:x, o:3);
50 xor(a:xor(t1, t2), b:t3)
51 }
52
53 add(a:v0, b:sigma0x4(sha256load(v2:v0, v3:v1)))
54}
55
56fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
57 macro_rules! sigma1 {
58 ($a:expr) => {
59 $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10)
60 };
61 }
62
63 let [x3: u32, x2: u32, x1: u32, x0: u32] = v4;
64 let [w15: u32, w14: u32, _, _] = v3;
65
66 let w16: u32 = x0.wrapping_add(sigma1!(w14));
67 let w17: u32 = x1.wrapping_add(sigma1!(w15));
68 let w18: u32 = x2.wrapping_add(sigma1!(w16));
69 let w19: u32 = x3.wrapping_add(sigma1!(w17));
70
71 [w19, w18, w17, w16]
72}
73
74fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] {
75 macro_rules! big_sigma0 {
76 ($a:expr) => {
77 ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22))
78 };
79 }
80 macro_rules! big_sigma1 {
81 ($a:expr) => {
82 ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25))
83 };
84 }
85 macro_rules! bool3ary_202 {
86 ($a:expr, $b:expr, $c:expr) => {
87 $c ^ ($a & ($b ^ $c))
88 };
89 } // Choose, MD5F, SHA1C
90 macro_rules! bool3ary_232 {
91 ($a:expr, $b:expr, $c:expr) => {
92 ($a & $b) ^ ($a & $c) ^ ($b & $c)
93 };
94 } // Majority, SHA1M
95
96 let [_, _, wk1, wk0] = wk;
97 let [a0, b0, e0, f0] = abef;
98 let [c0, d0, g0, h0] = cdgh;
99
100 // a round
101 let x0 = big_sigma1!(e0)
102 .wrapping_add(bool3ary_202!(e0, f0, g0))
103 .wrapping_add(wk0)
104 .wrapping_add(h0);
105 let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
106 let (a1, b1, c1, d1, e1, f1, g1, h1) = (
107 x0.wrapping_add(y0),
108 a0,
109 b0,
110 c0,
111 x0.wrapping_add(d0),
112 e0,
113 f0,
114 g0,
115 );
116
117 // a round
118 let x1 = big_sigma1!(e1)
119 .wrapping_add(bool3ary_202!(e1, f1, g1))
120 .wrapping_add(wk1)
121 .wrapping_add(h1);
122 let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
123 let (a2, b2, _, _, e2, f2, _, _) = (
124 x1.wrapping_add(y1),
125 a1,
126 b1,
127 c1,
128 x1.wrapping_add(d1),
129 e1,
130 f1,
131 g1,
132 );
133
134 [a2, b2, e2, f2]
135}
136
137fn schedule(v0: [u32; 4], v1: [u32; 4], v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
138 let t1: [u32; 4] = sha256msg1(v0, v1);
139 let t2: [u32; 4] = sha256load(v2, v3);
140 let t3: [u32; 4] = add(a:t1, b:t2);
141 sha256msg2(v4:t3, v3)
142}
143
144macro_rules! rounds4 {
145 ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{
146 let t1 = add($rest, crate::consts::K32X4[$i]);
147 $cdgh = sha256_digest_round_x2($cdgh, $abef, t1);
148 let t2 = sha256swap(t1);
149 $abef = sha256_digest_round_x2($abef, $cdgh, t2);
150 }};
151}
152
153macro_rules! schedule_rounds4 {
154 (
155 $abef:ident, $cdgh:ident,
156 $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr,
157 $i: expr
158 ) => {{
159 $w4 = schedule($w0, $w1, $w2, $w3);
160 rounds4!($abef, $cdgh, $w4, $i);
161 }};
162}
163
164/// Process a block with the SHA-256 algorithm.
165fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) {
166 let mut abef = [state[0], state[1], state[4], state[5]];
167 let mut cdgh = [state[2], state[3], state[6], state[7]];
168
169 // Rounds 0..64
170 let mut w0 = [block[3], block[2], block[1], block[0]];
171 let mut w1 = [block[7], block[6], block[5], block[4]];
172 let mut w2 = [block[11], block[10], block[9], block[8]];
173 let mut w3 = [block[15], block[14], block[13], block[12]];
174 let mut w4;
175
176 rounds4!(abef, cdgh, w0, 0);
177 rounds4!(abef, cdgh, w1, 1);
178 rounds4!(abef, cdgh, w2, 2);
179 rounds4!(abef, cdgh, w3, 3);
180 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4);
181 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5);
182 schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6);
183 schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7);
184 schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8);
185 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9);
186 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10);
187 schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11);
188 schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12);
189 schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13);
190 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14);
191 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15);
192
193 let [a, b, e, f] = abef;
194 let [c, d, g, h] = cdgh;
195
196 state[0] = state[0].wrapping_add(a);
197 state[1] = state[1].wrapping_add(b);
198 state[2] = state[2].wrapping_add(c);
199 state[3] = state[3].wrapping_add(d);
200 state[4] = state[4].wrapping_add(e);
201 state[5] = state[5].wrapping_add(f);
202 state[6] = state[6].wrapping_add(g);
203 state[7] = state[7].wrapping_add(h);
204}
205
206pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
207 let mut block_u32: [u32; 16] = [0u32; BLOCK_LEN];
208 // since LLVM can't properly use aliasing yet it will make
209 // unnecessary state stores without this copy
210 let mut state_cpy: [u32; 8] = *state;
211 for block: &[u8; 64] in blocks {
212 for (o: &mut u32, chunk: &[u8]) in block_u32.iter_mut().zip(block.chunks_exact(chunk_size:4)) {
213 *o = u32::from_be_bytes(chunk.try_into().unwrap());
214 }
215 sha256_digest_block_u32(&mut state_cpy, &block_u32);
216 }
217 *state = state_cpy;
218}
219