authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-13 21:38:29-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-01-13 21:38:29-05:00
loge7e7625633d4d6ef41b6f9cbf2f02d49945a9cda
tree8ad097a94c0b886af59d9cb132a1d1bc512b5947
parenta2315cfbfcfe33a2b9010994a1da6674854151e9
parent9be9f1ad20ca6c7b2e1c09423c753b1a9e13049d
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #687 from zig-lang/sha2

Add Sha2 functions

5 files changed, 717 insertions(+), 7 deletions(-)

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