authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-16 09:13:09-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-01-16 09:13:09-05:00
log8b280d5b31858e1224ab97051df78ea29114e908
treeed2dae31b5c93ded706fb783a562f84230e88251
parent6a95b88d1b3a619532feedffc674fc4b5bf7517b
parent73b4f098457e141854c26f5f43b2858909c831a3
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #689 from zig-lang/blake2

Add Blake2X hash functions

7 files changed, 588 insertions(+), 93 deletions(-)

CMakeLists.txt+1
......@@ -368,6 +368,7 @@ set(ZIG_STD_FILES
368368 "crypto/md5.zig"
369369 "crypto/sha1.zig"
370370 "crypto/sha2.zig"
371 "crypto/blake2.zig"
371372 "cstr.zig"
372373 "debug/failing_allocator.zig"
373374 "debug/index.zig"
std/crypto/blake2.zig created+445
......@@ -0,0 +1,445 @@
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");
6const htest = @import("test.zig");
7
8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
10};
11
12fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) -> RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
14}
15
16/////////////////////
17// Blake2s
18
19pub const Blake2s224 = Blake2s(224);
20pub const Blake2s256 = Blake2s(256);
21
22fn Blake2s(comptime out_len: usize) -> type { return struct {
23 const Self = this;
24
25 const iv = [8]u32 {
26 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
27 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
28 };
29
30 const sigma = [10][16]u8 {
31 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
32 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
33 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
34 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
35 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
36 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
37 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
38 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
39 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
40 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
41 };
42
43 h: [8]u32,
44 t: u64,
45 // Streaming cache
46 buf: [64]u8,
47 buf_len: u8,
48
49 pub fn init() -> Self {
50 debug.assert(8 <= out_len and out_len <= 512);
51
52 var s: Self = undefined;
53 s.reset();
54 return s;
55 }
56
57 pub fn reset(d: &Self) {
58 mem.copy(u32, d.h[0..], iv[0..]);
59
60 // No key plus default parameters
61 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
62 d.t = 0;
63 d.buf_len = 0;
64 }
65
66 pub fn hash(b: []const u8, out: []u8) {
67 var d = Self.init();
68 d.update(b);
69 d.final(out);
70 }
71
72 pub fn update(d: &Self, b: []const u8) {
73 var off: usize = 0;
74
75 // Partial buffer exists from previous update. Copy into buffer then hash.
76 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
77 off += 64 - d.buf_len;
78 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
79 d.t += 64;
80 d.round(d.buf[0..], false);
81 d.buf_len = 0;
82 }
83
84 // Full middle blocks.
85 while (off + 64 < b.len) : (off += 64) {
86 d.t += 64;
87 d.round(b[off..off + 64], false);
88 }
89
90 // Copy any remainder for next pass.
91 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
92 d.buf_len += u8(b[off..].len);
93 }
94
95 pub fn final(d: &Self, out: []u8) {
96 debug.assert(out.len >= out_len / 8);
97
98 mem.set(u8, d.buf[d.buf_len..], 0);
99 d.t += d.buf_len;
100 d.round(d.buf[0..], true);
101
102 const rr = d.h[0 .. out_len / 32];
103
104 for (rr) |s, j| {
105 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
106 }
107 }
108
109 fn round(d: &Self, b: []const u8, last: bool) {
110 debug.assert(b.len == 64);
111
112 var m: [16]u32 = undefined;
113 var v: [16]u32 = undefined;
114
115 for (m) |*r, i| {
116 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
117 }
118
119 var k: usize = 0;
120 while (k < 8) : (k += 1) {
121 v[k] = d.h[k];
122 v[k+8] = iv[k];
123 }
124
125 v[12] ^= @truncate(u32, d.t);
126 v[13] ^= u32(d.t >> 32);
127 if (last) v[14] = ~v[14];
128
129 const rounds = comptime []RoundParam {
130 Rp(0, 4, 8, 12, 0, 1),
131 Rp(1, 5, 9, 13, 2, 3),
132 Rp(2, 6, 10, 14, 4, 5),
133 Rp(3, 7, 11, 15, 6, 7),
134 Rp(0, 5, 10, 15, 8, 9),
135 Rp(1, 6, 11, 12, 10, 11),
136 Rp(2, 7, 8, 13, 12, 13),
137 Rp(3, 4, 9, 14, 14, 15),
138 };
139
140 comptime var j: usize = 0;
141 inline while (j < 10) : (j += 1) {
142 inline for (rounds) |r| {
143 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
144 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
145 v[r.c] = v[r.c] +% v[r.d];
146 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
147 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
148 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
149 v[r.c] = v[r.c] +% v[r.d];
150 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
151 }
152 }
153
154 for (d.h) |*r, i| {
155 *r ^= v[i] ^ v[i + 8];
156 }
157 }
158};}
159
160test "blake2s224 single" {
161 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
162 htest.assertEqualHash(Blake2s224, h1, "");
163
164 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
165 htest.assertEqualHash(Blake2s224, h2, "abc");
166
167 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
168 htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
169}
170
171test "blake2s224 streaming" {
172 var h = Blake2s224.init();
173 var out: [28]u8 = undefined;
174
175 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
176
177 h.final(out[0..]);
178 htest.assertEqual(h1, out[0..]);
179
180 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
181
182 h.reset();
183 h.update("abc");
184 h.final(out[0..]);
185 htest.assertEqual(h2, out[0..]);
186
187 h.reset();
188 h.update("a");
189 h.update("b");
190 h.update("c");
191 h.final(out[0..]);
192 htest.assertEqual(h2, out[0..]);
193}
194
195test "blake2s256 single" {
196 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
197 htest.assertEqualHash(Blake2s256, h1, "");
198
199 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
200 htest.assertEqualHash(Blake2s256, h2, "abc");
201
202 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
203 htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
204}
205
206test "blake2s256 streaming" {
207 var h = Blake2s256.init();
208 var out: [32]u8 = undefined;
209
210 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
211
212 h.final(out[0..]);
213 htest.assertEqual(h1, out[0..]);
214
215 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
216
217 h.reset();
218 h.update("abc");
219 h.final(out[0..]);
220 htest.assertEqual(h2, out[0..]);
221
222 h.reset();
223 h.update("a");
224 h.update("b");
225 h.update("c");
226 h.final(out[0..]);
227 htest.assertEqual(h2, out[0..]);
228}
229
230
231/////////////////////
232// Blake2b
233
234pub const Blake2b384 = Blake2b(384);
235pub const Blake2b512 = Blake2b(512);
236
237fn Blake2b(comptime out_len: usize) -> type { return struct {
238 const Self = this;
239
240 const iv = [8]u64 {
241 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
242 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
243 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
244 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
245 };
246
247 const sigma = [12][16]u8 {
248 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
249 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
250 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
251 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
252 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
253 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
254 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
255 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
256 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
257 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
258 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
259 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
260 };
261
262 h: [8]u64,
263 t: u128,
264 // Streaming cache
265 buf: [128]u8,
266 buf_len: u8,
267
268 pub fn init() -> Self {
269 debug.assert(8 <= out_len and out_len <= 512);
270
271 var s: Self = undefined;
272 s.reset();
273 return s;
274 }
275
276 pub fn reset(d: &Self) {
277 mem.copy(u64, d.h[0..], iv[0..]);
278
279 // No key plus default parameters
280 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
281 d.t = 0;
282 d.buf_len = 0;
283 }
284
285 pub fn hash(b: []const u8, out: []u8) {
286 var d = Self.init();
287 d.update(b);
288 d.final(out);
289 }
290
291 pub fn update(d: &Self, b: []const u8) {
292 var off: usize = 0;
293
294 // Partial buffer exists from previous update. Copy into buffer then hash.
295 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
296 off += 128 - d.buf_len;
297 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
298 d.t += 128;
299 d.round(d.buf[0..], false);
300 d.buf_len = 0;
301 }
302
303 // Full middle blocks.
304 while (off + 128 < b.len) : (off += 128) {
305 d.t += 128;
306 d.round(b[off..off + 128], false);
307 }
308
309 // Copy any remainder for next pass.
310 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
311 d.buf_len += u8(b[off..].len);
312 }
313
314 pub fn final(d: &Self, out: []u8) {
315 mem.set(u8, d.buf[d.buf_len..], 0);
316 d.t += d.buf_len;
317 d.round(d.buf[0..], true);
318
319 const rr = d.h[0 .. out_len / 64];
320
321 for (rr) |s, j| {
322 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
323 }
324 }
325
326 fn round(d: &Self, b: []const u8, last: bool) {
327 debug.assert(b.len == 128);
328
329 var m: [16]u64 = undefined;
330 var v: [16]u64 = undefined;
331
332 for (m) |*r, i| {
333 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
334 }
335
336 var k: usize = 0;
337 while (k < 8) : (k += 1) {
338 v[k] = d.h[k];
339 v[k+8] = iv[k];
340 }
341
342 v[12] ^= @truncate(u64, d.t);
343 v[13] ^= u64(d.t >> 64);
344 if (last) v[14] = ~v[14];
345
346 const rounds = comptime []RoundParam {
347 Rp(0, 4, 8, 12, 0, 1),
348 Rp(1, 5, 9, 13, 2, 3),
349 Rp(2, 6, 10, 14, 4, 5),
350 Rp(3, 7, 11, 15, 6, 7),
351 Rp(0, 5, 10, 15, 8, 9),
352 Rp(1, 6, 11, 12, 10, 11),
353 Rp(2, 7, 8, 13, 12, 13),
354 Rp(3, 4, 9, 14, 14, 15),
355 };
356
357 comptime var j: usize = 0;
358 inline while (j < 12) : (j += 1) {
359 inline for (rounds) |r| {
360 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
361 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
362 v[r.c] = v[r.c] +% v[r.d];
363 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
364 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
365 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
366 v[r.c] = v[r.c] +% v[r.d];
367 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
368 }
369 }
370
371 for (d.h) |*r, i| {
372 *r ^= v[i] ^ v[i + 8];
373 }
374 }
375};}
376
377test "blake2b384 single" {
378 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
379 htest.assertEqualHash(Blake2b384, h1, "");
380
381 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
382 htest.assertEqualHash(Blake2b384, h2, "abc");
383
384 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
385 htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
386}
387
388test "blake2b384 streaming" {
389 var h = Blake2b384.init();
390 var out: [48]u8 = undefined;
391
392 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
393
394 h.final(out[0..]);
395 htest.assertEqual(h1, out[0..]);
396
397 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
398
399 h.reset();
400 h.update("abc");
401 h.final(out[0..]);
402 htest.assertEqual(h2, out[0..]);
403
404 h.reset();
405 h.update("a");
406 h.update("b");
407 h.update("c");
408 h.final(out[0..]);
409 htest.assertEqual(h2, out[0..]);
410}
411
412test "blake2b512 single" {
413 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
414 htest.assertEqualHash(Blake2b512, h1, "");
415
416 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
417 htest.assertEqualHash(Blake2b512, h2, "abc");
418
419 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
420 htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
421}
422
423test "blake2b512 streaming" {
424 var h = Blake2b512.init();
425 var out: [64]u8 = undefined;
426
427 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
428
429 h.final(out[0..]);
430 htest.assertEqual(h1, out[0..]);
431
432 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
433
434 h.reset();
435 h.update("abc");
436 h.final(out[0..]);
437 htest.assertEqual(h2, out[0..]);
438
439 h.reset();
440 h.update("a");
441 h.update("b");
442 h.update("c");
443 h.final(out[0..]);
444 htest.assertEqual(h2, out[0..]);
445}
std/crypto/index.zig+7
......@@ -7,8 +7,15 @@ pub const Sha256 = sha2.Sha256;
77pub const Sha384 = sha2.Sha384;
88pub const Sha512 = sha2.Sha512;
99
10const blake2 = @import("blake2.zig");
11pub const Blake2s224 = blake2.Blake2s224;
12pub const Blake2s256 = blake2.Blake2s256;
13pub const Blake2b384 = blake2.Blake2b384;
14pub const Blake2b512 = blake2.Blake2b512;
15
1016test "crypto" {
1117 _ = @import("md5.zig");
1218 _ = @import("sha1.zig");
1319 _ = @import("sha2.zig");
20 _ = @import("blake2.zig");
1421}
std/crypto/md5.zig+27-20
......@@ -1,7 +1,9 @@
11const mem = @import("../mem.zig");
22const math = @import("../math/index.zig");
33const endian = @import("../endian.zig");
4const builtin = @import("builtin");
45const debug = @import("../debug/index.zig");
6const fmt = @import("../fmt/index.zig");
57
68const RoundParam = struct {
79 a: usize, b: usize, c: usize, d: usize,
......@@ -42,10 +44,10 @@ pub const Md5 = struct {
4244 d.total_len = 0;
4345 }
4446
45 pub fn hash(b: []const u8) -> u128 {
47 pub fn hash(b: []const u8, out: []u8) {
4648 var d = Md5.init();
4749 d.update(b);
48 return d.final();
50 d.final(out);
4951 }
5052
5153 pub fn update(d: &Self, b: []const u8) {
......@@ -73,7 +75,9 @@ pub const Md5 = struct {
7375 d.total_len +%= b.len;
7476 }
7577
76 pub fn final(d: &Self) -> u128 {
78 pub fn final(d: &Self, out: []u8) {
79 debug.assert(out.len >= 16);
80
7781 // The buffer here will never be completely full.
7882 mem.set(u8, d.buf[d.buf_len..], 0);
7983
......@@ -98,13 +102,9 @@ pub const Md5 = struct {
98102
99103 d.round(d.buf[0..]);
100104
101 const r =
102 (u128(d.s[3]) << 96) |
103 (u128(d.s[2]) << 64) |
104 (u128(d.s[1]) << 32) |
105 (u128(d.s[0]) << 0);
106
107 return endian.swapIfLe(u128, r);
105 for (d.s) |s, j| {
106 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
107 }
108108 }
109109
110110 fn round(d: &Self, b: []const u8) {
......@@ -226,28 +226,35 @@ pub const Md5 = struct {
226226 }
227227};
228228
229const htest = @import("test.zig");
230
229231test "md5 single" {
230 debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == Md5.hash(""));
231 debug.assert(0x0cc175b9c0f1b6a831c399e269772661 == Md5.hash("a"));
232 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == Md5.hash("abc"));
233 debug.assert(0xf96b697d7cb7938d525a2f31aaf161d0 == Md5.hash("message digest"));
234 debug.assert(0xc3fcd3d76192e4007dfb496cca67e13b == Md5.hash("abcdefghijklmnopqrstuvwxyz"));
235 debug.assert(0xd174ab98d277d9f5a5611c2c9f419d9f == Md5.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
236 debug.assert(0x57edf4a22be3c955ac49da2e2107b67a == Md5.hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
232 htest.assertEqualHash(Md5, "d41d8cd98f00b204e9800998ecf8427e", "");
233 htest.assertEqualHash(Md5, "0cc175b9c0f1b6a831c399e269772661", "a");
234 htest.assertEqualHash(Md5, "900150983cd24fb0d6963f7d28e17f72", "abc");
235 htest.assertEqualHash(Md5, "f96b697d7cb7938d525a2f31aaf161d0", "message digest");
236 htest.assertEqualHash(Md5, "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz");
237 htest.assertEqualHash(Md5, "d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
238 htest.assertEqualHash(Md5, "57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
237239}
238240
239241test "md5 streaming" {
240242 var h = Md5.init();
243 var out: [16]u8 = undefined;
241244
242 debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == h.final());
245 h.final(out[0..]);
246 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
243247
244248 h.reset();
245249 h.update("abc");
246 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
250 h.final(out[0..]);
251 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
247252
248253 h.reset();
249254 h.update("a");
250255 h.update("b");
251256 h.update("c");
252 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
257 h.final(out[0..]);
258
259 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
253260}
std/crypto/sha1.zig+21-17
......@@ -2,6 +2,7 @@ const mem = @import("../mem.zig");
22const math = @import("../math/index.zig");
33const endian = @import("../endian.zig");
44const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
56
67pub const u160 = @IntType(false, 160);
78
......@@ -38,10 +39,10 @@ pub const Sha1 = struct {
3839 d.total_len = 0;
3940 }
4041
41 pub fn hash(b: []const u8) -> u160 {
42 pub fn hash(b: []const u8, out: []u8) {
4243 var d = Sha1.init();
4344 d.update(b);
44 return d.final();
45 d.final(out);
4546 }
4647
4748 pub fn update(d: &Self, b: []const u8) {
......@@ -68,7 +69,9 @@ pub const Sha1 = struct {
6869 d.total_len += b.len;
6970 }
7071
71 pub fn final(d: &Self) -> u160 {
72 pub fn final(d: &Self, out: []u8) {
73 debug.assert(out.len >= 20);
74
7275 // The buffer here will never be completely full.
7376 mem.set(u8, d.buf[d.buf_len..], 0);
7477
......@@ -93,14 +96,9 @@ pub const Sha1 = struct {
9396
9497 d.round(d.buf[0..]);
9598
96 const r =
97 (u160(d.s[0]) << 128) |
98 (u160(d.s[1]) << 96) |
99 (u160(d.s[2]) << 64) |
100 (u160(d.s[3]) << 32) |
101 (u160(d.s[4]) << 0);
102
103 return endian.swapIfBe(u160, r);
99 for (d.s) |s, j| {
100 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
101 }
104102 }
105103
106104 fn round(d: &Self, b: []const u8) {
......@@ -257,24 +255,30 @@ pub const Sha1 = struct {
257255 }
258256};
259257
258const htest = @import("test.zig");
259
260260test "sha1 single" {
261 debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == Sha1.hash(""));
262 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == Sha1.hash("abc"));
263 debug.assert(0xa49b2446a02c645bf419f995b67091253a04a259 == Sha1.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
261 htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
262 htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
263 htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
264264}
265265
266266test "sha1 streaming" {
267267 var h = Sha1.init();
268 var out: [20]u8 = undefined;
268269
269 debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == h.final());
270 h.final(out[0..]);
271 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
270272
271273 h.reset();
272274 h.update("abc");
273 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
275 h.final(out[0..]);
276 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
274277
275278 h.reset();
276279 h.update("a");
277280 h.update("b");
278281 h.update("c");
279 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
282 h.final(out[0..]);
283 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
280284}
std/crypto/sha2.zig+65-56
......@@ -3,6 +3,7 @@ const math = @import("../math/index.zig");
33const endian = @import("../endian.zig");
44const debug = @import("../debug/index.zig");
55const builtin = @import("builtin");
6const htest = @import("test.zig");
67
78/////////////////////
89// Sha224 + Sha256
......@@ -57,7 +58,6 @@ pub const Sha256 = Sha2_32(Sha256Params);
5758
5859fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
5960 const Self = this;
60 const ReturnType = @IntType(false, params.out_len);
6161
6262 s: [8]u32,
6363 // Streaming Cache
......@@ -84,10 +84,10 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
8484 d.total_len = 0;
8585 }
8686
87 pub fn hash(b: []const u8) -> ReturnType {
87 pub fn hash(b: []const u8, out: []u8) {
8888 var d = Self.init();
8989 d.update(b);
90 return d.final();
90 d.final(out);
9191 }
9292
9393 pub fn update(d: &Self, b: []const u8) {
......@@ -114,7 +114,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
114114 d.total_len += b.len;
115115 }
116116
117 pub fn final(d: &Self) -> ReturnType {
117 pub fn final(d: &Self, out: []u8) {
118 debug.assert(out.len >= params.out_len / 8);
119
118120 // The buffer here will never be completely full.
119121 mem.set(u8, d.buf[d.buf_len..], 0);
120122
......@@ -142,14 +144,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
142144 // May truncate for possible 224 output
143145 const rr = d.s[0 .. params.out_len / 32];
144146
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;
147 for (rr) |s, j| {
148 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
150149 }
151
152 return endian.swapIfBe(ReturnType, r);
153150 }
154151
155152 fn round(d: &Self, b: []const u8) {
......@@ -270,47 +267,55 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
270267};}
271268
272269test "sha224 single" {
273 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == Sha224.hash(""));
274 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == Sha224.hash("abc"));
275 debug.assert(0xc97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3 == Sha224.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
270 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
271 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
272 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
276273}
277274
278275test "sha224 streaming" {
279276 var h = Sha224.init();
277 var out: [28]u8 = undefined;
280278
281 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == h.final());
279 h.final(out[0..]);
280 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
282281
283282 h.reset();
284283 h.update("abc");
285 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
284 h.final(out[0..]);
285 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
286286
287287 h.reset();
288288 h.update("a");
289289 h.update("b");
290290 h.update("c");
291 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
291 h.final(out[0..]);
292 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
292293}
293294
294295test "sha256 single" {
295 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == Sha256.hash(""));
296 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == Sha256.hash("abc"));
297 debug.assert(0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1 == Sha256.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
296 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
297 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
298 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
298299}
299300
300301test "sha256 streaming" {
301302 var h = Sha256.init();
303 var out: [32]u8 = undefined;
302304
303 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == h.final());
305 h.final(out[0..]);
306 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
304307
305308 h.reset();
306309 h.update("abc");
307 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
310 h.final(out[0..]);
311 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
308312
309313 h.reset();
310314 h.update("a");
311315 h.update("b");
312316 h.update("c");
313 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
317 h.final(out[0..]);
318 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
314319}
315320
316321
......@@ -367,7 +372,6 @@ pub const Sha512 = Sha2_64(Sha512Params);
367372
368373fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
369374 const Self = this;
370 const ReturnType = @IntType(false, params.out_len);
371375 const u9 = @IntType(false, 9);
372376
373377 s: [8]u64,
......@@ -395,10 +399,10 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
395399 d.total_len = 0;
396400 }
397401
398 pub fn hash(b: []const u8) -> ReturnType {
402 pub fn hash(b: []const u8, out: []u8) {
399403 var d = Self.init();
400404 d.update(b);
401 return d.final();
405 d.final(out);
402406 }
403407
404408 pub fn update(d: &Self, b: []const u8) {
......@@ -425,7 +429,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
425429 d.total_len += b.len;
426430 }
427431
428 pub fn final(d: &Self) -> ReturnType {
432 pub fn final(d: &Self, out: []u8) {
433 debug.assert(out.len >= params.out_len / 8);
434
429435 // The buffer here will never be completely full.
430436 mem.set(u8, d.buf[d.buf_len..], 0);
431437
......@@ -453,14 +459,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
453459 // May truncate for possible 384 output
454460 const rr = d.s[0 .. params.out_len / 64];
455461
456 var j: u9 = u9(rr.len - 1) * 64;
457 var r: ReturnType = 0;
458 for (rr) |p| {
459 r |= ReturnType(p) << j;
460 j -%= 64;
462 for (rr) |s, j| {
463 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
461464 }
462
463 return endian.swapIfBe(ReturnType, r);
464465 }
465466
466467 fn round(d: &Self, b: []const u8) {
......@@ -601,61 +602,69 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
601602};}
602603
603604test "sha384 single" {
604 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
605 debug.assert(h1 == Sha384.hash(""));
605 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
606 htest.assertEqualHash(Sha384, h1, "");
606607
607 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
608 debug.assert(h2 == Sha384.hash("abc"));
608 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
609 htest.assertEqualHash(Sha384, h2, "abc");
609610
610 const h3 = 0x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039;
611 debug.assert(h3 == Sha384.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
611 const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
612 htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
612613}
613614
614615test "sha384 streaming" {
615616 var h = Sha384.init();
617 var out: [48]u8 = undefined;
616618
617 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
618 debug.assert(h1 == h.final());
619 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
620 h.final(out[0..]);
621 htest.assertEqual(h1, out[0..]);
619622
620 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
623 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
621624
622625 h.reset();
623626 h.update("abc");
624 debug.assert(h2 == h.final());
627 h.final(out[0..]);
628 htest.assertEqual(h2, out[0..]);
625629
626630 h.reset();
627631 h.update("a");
628632 h.update("b");
629633 h.update("c");
630 debug.assert(h2 == h.final());
634 h.final(out[0..]);
635 htest.assertEqual(h2, out[0..]);
631636}
632637
633638test "sha512 single" {
634 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
635 debug.assert(h1 == Sha512.hash(""));
639 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
640 htest.assertEqualHash(Sha512, h1, "");
636641
637 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
638 debug.assert(h2 == Sha512.hash("abc"));
642 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
643 htest.assertEqualHash(Sha512, h2, "abc");
639644
640 const h3 = 0x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909;
641 debug.assert(h3 == Sha512.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
645 const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
646 htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
642647}
643648
644649test "sha512 streaming" {
645650 var h = Sha512.init();
651 var out: [64]u8 = undefined;
646652
647 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
648 debug.assert(h1 == h.final());
653 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
654 h.final(out[0..]);
655 htest.assertEqual(h1, out[0..]);
649656
650 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
657 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
651658
652659 h.reset();
653660 h.update("abc");
654 debug.assert(h2 == h.final());
661 h.final(out[0..]);
662 htest.assertEqual(h2, out[0..]);
655663
656664 h.reset();
657665 h.update("a");
658666 h.update("b");
659667 h.update("c");
660 debug.assert(h2 == h.final());
668 h.final(out[0..]);
669 htest.assertEqual(h2, out[0..]);
661670}
std/crypto/test.zig created+22
......@@ -0,0 +1,22 @@
1const debug = @import("../debug/index.zig");
2const mem = @import("../mem.zig");
3const fmt = @import("../fmt/index.zig");
4
5// Hash using the specified hasher `H` asserting `expected == H(input)`.
6pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) {
7 var h: [expected.len / 2]u8 = undefined;
8 Hasher.hash(input, h[0..]);
9
10 assertEqual(expected, h);
11}
12
13// Assert `expected` == `input` where `input` is a bytestring.
14pub fn assertEqual(comptime expected: []const u8, input: []const u8) {
15 var expected_bytes: [expected.len / 2]u8 = undefined;
16 for (expected_bytes) |*r, i| {
17 *r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
18 }
19
20 debug.assert(mem.eql(u8, expected_bytes, input));
21}
22