authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-13 22:23:12+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-13 22:37:47+13:00
log2659ac01be85662265be6e7fcdd8e03dcade1c50
treed4f95c92612d336ecda3c9d1fcb314574a1f0914
parenta2315cfbfcfe33a2b9010994a1da6674854151e9

Add Sha2 functions

We take the fastest time measurement taken across multiple runs. Tested across multiple compiler flags and the best chosen. ``` Cpu: Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz Gcc: 7.2.1 20171224 Clang: 5.0.1 Zig: 0.1.1.304f6f1d ``` See https://www.nayuki.io/page/fast-sha2-hashes-in-x86-assembly. ``` Gcc -O2 219 Mb/s Clang -O2 213 Mb/s Zig --release-fast 284 Mb/s Zig --release-safe 211 Mb/s Zig 6 Mb/s ``` ``` Gcc -O2 350 Mb/s Clang -O2 354 Mb/s Zig --release-fast 426 Mb/s Zig --release-safe 300 Mb/s Zig 11 Mb/s ```

3 files changed, 669 insertions(+), 1 deletions(-)

CMakeLists.txt+1
......@@ -367,6 +367,7 @@ set(ZIG_STD_FILES
367367 "crypto/index.zig"
368368 "crypto/md5.zig"
369369 "crypto/sha1.zig"
370 "crypto/sha2.zig"
370371 "cstr.zig"
371372 "debug/failing_allocator.zig"
372373 "debug/index.zig"
std/crypto/index.zig+8-1
......@@ -1,7 +1,14 @@
1pub const Sha1 = @import("md5.zig").Sha1;
21pub const Md5 = @import("sha1.zig").Md5;
2pub const Sha1 = @import("md5.zig").Sha1;
3
4const sha2 = @import("sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
39
410test "crypto" {
511 _ = @import("md5.zig");
612 _ = @import("sha1.zig");
13 _ = @import("sha2.zig");
714}
std/crypto/sha2.zig created+660
......@@ -0,0 +1,660 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5
6/////////////////////
7// Sha224 + Sha256
8
9const RoundParam256 = struct {
10 a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32,
11 i: u32, k: u32,
12};
13
14fn Rp256(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32, i: u32, k: u32) -> RoundParam256 {
15 return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
16}
17
18const Sha2Params32 = struct {
19 iv0: u32,
20 iv1: u32,
21 iv2: u32,
22 iv3: u32,
23 iv4: u32,
24 iv5: u32,
25 iv6: u32,
26 iv7: u32,
27 out_len: u32,
28};
29
30const Sha224Params = Sha2Params32 {
31 .iv0 = 0xC1059ED8,
32 .iv1 = 0x367CD507,
33 .iv2 = 0x3070DD17,
34 .iv3 = 0xF70E5939,
35 .iv4 = 0xFFC00B31,
36 .iv5 = 0x68581511,
37 .iv6 = 0x64F98FA7,
38 .iv7 = 0xBEFA4FA4,
39 .out_len = 224,
40};
41
42const Sha256Params = Sha2Params32 {
43 .iv0 = 0x6A09E667,
44 .iv1 = 0xBB67AE85,
45 .iv2 = 0x3C6EF372,
46 .iv3 = 0xA54FF53A,
47 .iv4 = 0x510E527F,
48 .iv5 = 0x9B05688C,
49 .iv6 = 0x1F83D9AB,
50 .iv7 = 0x5BE0CD19,
51 .out_len = 256,
52};
53
54pub const Sha224 = Sha2_32(Sha224Params);
55pub const Sha256 = Sha2_32(Sha256Params);
56
57fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
58 const Self = this;
59 const ReturnType = @IntType(false, params.out_len);
60
61 s: [8]u32,
62 // Streaming Cache
63 buf: [64]u8,
64 buf_len: u8,
65 total_len: u64,
66
67 pub fn init() -> Self {
68 var d: Self = undefined;
69 d.reset();
70 return d;
71 }
72
73 pub fn reset(d: &Self) {
74 d.s[0] = params.iv0;
75 d.s[1] = params.iv1;
76 d.s[2] = params.iv2;
77 d.s[3] = params.iv3;
78 d.s[4] = params.iv4;
79 d.s[5] = params.iv5;
80 d.s[6] = params.iv6;
81 d.s[7] = params.iv7;
82 d.buf_len = 0;
83 d.total_len = 0;
84 }
85
86 pub fn hash(b: []const u8) -> ReturnType {
87 var d = Self.init();
88 d.update(b);
89 return d.final();
90 }
91
92 pub fn update(d: &Self, b: []const u8) {
93 var off: usize = 0;
94
95 // Partial buffer exists from previous update. Copy into buffer then hash.
96 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
97 off += 64 - d.buf_len;
98 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
99
100 d.round(d.buf[0..]);
101 d.buf_len = 0;
102 }
103
104 // Full middle blocks.
105 while (off + 64 < b.len) : (off += 64) {
106 d.round(b[off..off + 64]);
107 }
108
109 // Copy any remainder for next pass.
110 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
111 d.buf_len += u8(b[off..].len);
112
113 d.total_len += b.len;
114 }
115
116 pub fn final(d: &Self) -> ReturnType {
117 // The buffer here will never be completely full.
118 mem.set(u8, d.buf[d.buf_len..], 0);
119
120 // Append padding bits.
121 d.buf[d.buf_len] = 0x80;
122 d.buf_len += 1;
123
124 // > 448 mod 512 so need to add an extra round to wrap around.
125 if (64 - d.buf_len < 8) {
126 d.round(d.buf[0..]);
127 mem.set(u8, d.buf[0..], 0);
128 }
129
130 // Append message length.
131 var i: usize = 1;
132 var len = d.total_len >> 5;
133 d.buf[63] = u8(d.total_len & 0x1f) << 3;
134 while (i < 8) : (i += 1) {
135 d.buf[63 - i] = u8(len & 0xff);
136 len >>= 8;
137 }
138
139 d.round(d.buf[0..]);
140
141 // May truncate for possible 224 output
142 const rr = d.s[0 .. params.out_len / 32];
143
144 var j: u8 = u8(rr.len - 1) * 32;
145 var r: ReturnType = 0;
146 for (rr) |p| {
147 r |= ReturnType(p) << j;
148 j -%= 32;
149 }
150
151 return endian.swapIfBe(ReturnType, r);
152 }
153
154 fn round(d: &Self, b: []const u8) {
155 debug.assert(b.len == 64);
156
157 var s: [64]u32 = undefined;
158
159 // ERROR: Cannot unroll at compile-time.
160 var i: usize = 0;
161 while (i < 16) : (i += 1) {
162 s[i] = 0;
163 s[i] |= u32(b[i*4+0]) << 24;
164 s[i] |= u32(b[i*4+1]) << 16;
165 s[i] |= u32(b[i*4+2]) << 8;
166 s[i] |= u32(b[i*4+3]) << 0;
167 }
168 while (i < 64) : (i += 1) {
169 s[i] =
170 s[i-16] +% s[i-7] +%
171 (math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
172 (math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
173 }
174
175 var v: [8]u32 = []u32 {
176 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
177 };
178
179 const round0 = comptime []RoundParam256 {
180 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
181 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
182 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
183 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
184 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
185 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
186 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
187 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
188 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
189 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
190 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
191 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
192 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
193 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
194 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
195 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
196 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
197 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
198 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
199 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
200 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
201 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
202 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
203 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
204 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
205 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
206 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
207 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
208 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
209 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
210 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
211 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
212 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
213 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
214 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
215 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
216 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
217 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
218 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
219 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
220 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
221 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
222 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
223 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
224 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
225 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
226 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
227 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
228 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
229 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
230 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
231 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
232 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
233 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
234 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
235 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
236 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
237 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
238 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
239 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
240 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
241 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
242 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
243 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
244 };
245 inline for (round0) |r| {
246 v[r.h] =
247 v[r.h] +%
248 (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
249 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
250 r.k +% s[r.i];
251
252 v[r.d] = v[r.d] +% v[r.h];
253
254 v[r.h] =
255 v[r.h] +%
256 (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
257 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
258 }
259
260 d.s[0] +%= v[0];
261 d.s[1] +%= v[1];
262 d.s[2] +%= v[2];
263 d.s[3] +%= v[3];
264 d.s[4] +%= v[4];
265 d.s[5] +%= v[5];
266 d.s[6] +%= v[6];
267 d.s[7] +%= v[7];
268 }
269};}
270
271test "sha224 single" {
272 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == Sha224.hash(""));
273 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == Sha224.hash("abc"));
274 debug.assert(0xc97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3 == Sha224.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
275}
276
277test "sha224 streaming" {
278 var h = Sha224.init();
279
280 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == h.final());
281
282 h.reset();
283 h.update("abc");
284 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
285
286 h.reset();
287 h.update("a");
288 h.update("b");
289 h.update("c");
290 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
291}
292
293test "sha256 single" {
294 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == Sha256.hash(""));
295 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == Sha256.hash("abc"));
296 debug.assert(0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1 == Sha256.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
297}
298
299test "sha256 streaming" {
300 var h = Sha256.init();
301
302 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == h.final());
303
304 h.reset();
305 h.update("abc");
306 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
307
308 h.reset();
309 h.update("a");
310 h.update("b");
311 h.update("c");
312 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
313}
314
315
316/////////////////////
317// Sha384 + Sha512
318
319const RoundParam512 = struct {
320 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
321 i: usize, k: u64,
322};
323
324fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) -> RoundParam512 {
325 return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
326}
327
328const Sha2Params64 = struct {
329 iv0: u64,
330 iv1: u64,
331 iv2: u64,
332 iv3: u64,
333 iv4: u64,
334 iv5: u64,
335 iv6: u64,
336 iv7: u64,
337 out_len: usize,
338};
339
340const Sha384Params = Sha2Params64 {
341 .iv0 = 0xCBBB9D5DC1059ED8,
342 .iv1 = 0x629A292A367CD507,
343 .iv2 = 0x9159015A3070DD17,
344 .iv3 = 0x152FECD8F70E5939,
345 .iv4 = 0x67332667FFC00B31,
346 .iv5 = 0x8EB44A8768581511,
347 .iv6 = 0xDB0C2E0D64F98FA7,
348 .iv7 = 0x47B5481DBEFA4FA4,
349 .out_len = 384,
350};
351
352const Sha512Params = Sha2Params64 {
353 .iv0 = 0x6A09E667F3BCC908,
354 .iv1 = 0xBB67AE8584CAA73B,
355 .iv2 = 0x3C6EF372FE94F82B,
356 .iv3 = 0xA54FF53A5F1D36F1,
357 .iv4 = 0x510E527FADE682D1,
358 .iv5 = 0x9B05688C2B3E6C1F,
359 .iv6 = 0x1F83D9ABFB41BD6B,
360 .iv7 = 0x5BE0CD19137E2179,
361 .out_len = 512
362};
363
364pub const Sha384 = Sha2_64(Sha384Params);
365pub const Sha512 = Sha2_64(Sha512Params);
366
367fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
368 const Self = this;
369 const ReturnType = @IntType(false, params.out_len);
370 const u9 = @IntType(false, 9);
371
372 s: [8]u64,
373 // Streaming Cache
374 buf: [128]u8,
375 buf_len: u8,
376 total_len: u64,
377
378 pub fn init() -> Self {
379 var d: Self = undefined;
380 d.reset();
381 return d;
382 }
383
384 pub fn reset(d: &Self) {
385 d.s[0] = params.iv0;
386 d.s[1] = params.iv1;
387 d.s[2] = params.iv2;
388 d.s[3] = params.iv3;
389 d.s[4] = params.iv4;
390 d.s[5] = params.iv5;
391 d.s[6] = params.iv6;
392 d.s[7] = params.iv7;
393 d.buf_len = 0;
394 d.total_len = 0;
395 }
396
397 pub fn hash(b: []const u8) -> ReturnType {
398 var d = Self.init();
399 d.update(b);
400 return d.final();
401 }
402
403 pub fn update(d: &Self, b: []const u8) {
404 var off: usize = 0;
405
406 // Partial buffer exists from previous update. Copy into buffer then hash.
407 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
408 off += 128 - d.buf_len;
409 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
410
411 d.round(d.buf[0..]);
412 d.buf_len = 0;
413 }
414
415 // Full middle blocks.
416 while (off + 128 < b.len) : (off += 128) {
417 d.round(b[off..off + 128]);
418 }
419
420 // Copy any remainder for next pass.
421 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
422 d.buf_len += u8(b[off..].len);
423
424 d.total_len += b.len;
425 }
426
427 pub fn final(d: &Self) -> ReturnType {
428 // The buffer here will never be completely full.
429 mem.set(u8, d.buf[d.buf_len..], 0);
430
431 // Append padding bits.
432 d.buf[d.buf_len] = 0x80;
433 d.buf_len += 1;
434
435 // > 896 mod 1024 so need to add an extra round to wrap around.
436 if (128 - d.buf_len < 16) {
437 d.round(d.buf[0..]);
438 mem.set(u8, d.buf[0..], 0);
439 }
440
441 // Append message length.
442 var i: usize = 1;
443 var len = d.total_len >> 5;
444 d.buf[127] = u8(d.total_len & 0x1f) << 3;
445 while (i < 16) : (i += 1) {
446 d.buf[127 - i] = u8(len & 0xff);
447 len >>= 8;
448 }
449
450 d.round(d.buf[0..]);
451
452 // May truncate for possible 384 output
453 const rr = d.s[0 .. params.out_len / 64];
454
455 var j: u9 = u9(rr.len - 1) * 64;
456 var r: ReturnType = 0;
457 for (rr) |p| {
458 r |= ReturnType(p) << j;
459 j -%= 64;
460 }
461
462 return endian.swapIfBe(ReturnType, r);
463 }
464
465 fn round(d: &Self, b: []const u8) {
466 debug.assert(b.len == 128);
467
468 var s: [80]u64 = undefined;
469
470 // ERROR: Cannot unroll at compile-time.
471 var i: usize = 0;
472 while (i < 16) : (i += 1) {
473 s[i] = 0;
474 s[i] |= u64(b[i*8+0]) << 56;
475 s[i] |= u64(b[i*8+1]) << 48;
476 s[i] |= u64(b[i*8+2]) << 40;
477 s[i] |= u64(b[i*8+3]) << 32;
478 s[i] |= u64(b[i*8+4]) << 24;
479 s[i] |= u64(b[i*8+5]) << 16;
480 s[i] |= u64(b[i*8+6]) << 8;
481 s[i] |= u64(b[i*8+7]) << 0;
482 }
483 while (i < 80) : (i += 1) {
484 s[i] =
485 s[i-16] +% s[i-7] +%
486 (math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
487 (math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
488 }
489
490 var v: [8]u64 = []u64 {
491 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
492 };
493
494 const round0 = comptime []RoundParam512 {
495 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
496 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
497 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
498 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
499 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
500 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
501 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
502 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
503 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
504 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
505 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
506 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
507 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
508 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
509 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
510 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
511 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
512 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
513 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
514 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
515 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
516 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
517 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
518 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
519 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
520 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
521 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
522 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
523 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
524 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
525 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
526 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
527 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
528 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
529 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
530 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
531 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
532 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
533 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
534 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
535 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
536 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
537 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
538 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
539 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
540 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
541 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
542 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
543 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
544 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
545 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
546 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
547 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
548 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
549 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
550 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
551 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
552 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
553 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
554 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
555 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
556 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
557 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
558 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
559 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
560 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
561 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
562 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
563 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
564 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
565 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
566 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
567 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
568 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
569 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
570 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
571 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
572 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
573 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
574 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
575 };
576 inline for (round0) |r| {
577 v[r.h] =
578 v[r.h] +%
579 (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
580 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
581 r.k +% s[r.i];
582
583 v[r.d] = v[r.d] +% v[r.h];
584
585 v[r.h] =
586 v[r.h] +%
587 (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
588 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
589 }
590
591 d.s[0] +%= v[0];
592 d.s[1] +%= v[1];
593 d.s[2] +%= v[2];
594 d.s[3] +%= v[3];
595 d.s[4] +%= v[4];
596 d.s[5] +%= v[5];
597 d.s[6] +%= v[6];
598 d.s[7] +%= v[7];
599 }
600};}
601
602test "sha384 single" {
603 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
604 debug.assert(h1 == Sha384.hash(""));
605
606 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
607 debug.assert(h2 == Sha384.hash("abc"));
608
609 const h3 = 0x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039;
610 debug.assert(h3 == Sha384.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
611}
612
613test "sha384 streaming" {
614 var h = Sha384.init();
615
616 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
617 debug.assert(h1 == h.final());
618
619 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
620
621 h.reset();
622 h.update("abc");
623 debug.assert(h2 == h.final());
624
625 h.reset();
626 h.update("a");
627 h.update("b");
628 h.update("c");
629 debug.assert(h2 == h.final());
630}
631
632test "sha512 single" {
633 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
634 debug.assert(h1 == Sha512.hash(""));
635
636 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
637 debug.assert(h2 == Sha512.hash("abc"));
638
639 const h3 = 0x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909;
640 debug.assert(h3 == Sha512.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
641}
642
643test "sha512 streaming" {
644 var h = Sha512.init();
645
646 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
647 debug.assert(h1 == h.final());
648
649 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
650
651 h.reset();
652 h.update("abc");
653 debug.assert(h2 == h.final());
654
655 h.reset();
656 h.update("a");
657 h.update("b");
658 h.update("c");
659 debug.assert(h2 == h.final());
660}