authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-16 21:35:31+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-17 00:17:48+13:00
logfa7b33549e43abbdb4fba1d686dfd63c2ca8e8ca
tree94a34c5994d14a9351ee9659403ff04269e4bdcb
parent4cf86b4a94adf0a27d0c536746f1703ddf1fd0df

Change crypto functions to fill a buffer

- Rename blake2x -> blake2 - Fix blake2s truncated tests

7 files changed, 565 insertions(+), 539 deletions(-)

CMakeLists.txt+1-1
...@@ -368,7 +368,7 @@ set(ZIG_STD_FILES...@@ -368,7 +368,7 @@ set(ZIG_STD_FILES
368 "crypto/md5.zig"368 "crypto/md5.zig"
369 "crypto/sha1.zig"369 "crypto/sha1.zig"
370 "crypto/sha2.zig"370 "crypto/sha2.zig"
371 "crypto/blake2x.zig"371 "crypto/blake2.zig"
372 "cstr.zig"372 "cstr.zig"
373 "debug/failing_allocator.zig"373 "debug/failing_allocator.zig"
374 "debug/index.zig"374 "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/blake2x.zig deleted-439
...@@ -1,439 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3const math = std.math;
4const debug = std.debug;
5
6const RoundParam = struct {
7 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
8};
9
10fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) -> RoundParam {
11 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
12}
13
14/////////////////////
15// Blake2s
16
17pub const Blake2s224 = Blake2s(224);
18pub const Blake2s256 = Blake2s(256);
19
20fn Blake2s(comptime out_len: usize) -> type { return struct {
21 const Self = this;
22 const ReturnType = @IntType(false, out_len);
23
24 const iv = [8]u32 {
25 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
26 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
27 };
28
29 const sigma = [10][16]u8 {
30 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
31 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
32 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
33 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
34 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
35 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
36 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
37 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
38 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
39 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
40 };
41
42 h: [8]u32,
43 t: u64,
44 // Streaming cache
45 buf: [64]u8,
46 buf_len: u8,
47
48 pub fn init() -> Self {
49 debug.assert(8 <= out_len and out_len <= 512);
50
51 var s: Self = undefined;
52 s.reset();
53 return s;
54 }
55
56 pub fn reset(d: &Self) {
57 mem.copy(u32, d.h[0..], iv[0..]);
58
59 // No key plus default parameters
60 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
61 d.t = 0;
62 d.buf_len = 0;
63 }
64
65 pub fn hash(b: []const u8) -> ReturnType {
66 var d = Self.init();
67 d.update(b);
68 return d.final();
69 }
70
71 pub fn update(d: &Self, b: []const u8) {
72 var off: usize = 0;
73
74 // Partial buffer exists from previous update. Copy into buffer then hash.
75 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
76 off += 64 - d.buf_len;
77 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
78 d.t += 64;
79 d.round(d.buf[0..], false);
80 d.buf_len = 0;
81 }
82
83 // Full middle blocks.
84 while (off + 64 < b.len) : (off += 64) {
85 d.t += 64;
86 d.round(b[off..off + 64], false);
87 }
88
89 // Copy any remainder for next pass.
90 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
91 d.buf_len += u8(b[off..].len);
92 }
93
94 pub fn final(d: &Self) -> ReturnType {
95 mem.set(u8, d.buf[d.buf_len..], 0);
96 d.t += d.buf_len;
97 d.round(d.buf[0..], true);
98
99 const rr = d.h[0 .. out_len / 32];
100
101 // NOTE: mem.readIntLE or equivalent would be useful here.
102 var j: u8 = 0;
103 var r: ReturnType = 0;
104 for (rr) |p| {
105 r |= ReturnType(p) << j;
106 j +%= 32;
107 }
108
109 return std.endian.swapIfLe(ReturnType, r);
110 }
111
112 fn round(d: &Self, b: []const u8, last: bool) {
113 debug.assert(b.len == 64);
114
115 var m: [16]u32 = undefined;
116 var v: [16]u32 = undefined;
117
118 for (m) |*r, i| {
119 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
120 }
121
122 var k: usize = 0;
123 while (k < 8) : (k += 1) {
124 v[k] = d.h[k];
125 v[k+8] = iv[k];
126 }
127
128 v[12] ^= @truncate(u32, d.t);
129 v[13] ^= u32(d.t >> 32);
130 if (last) v[14] = ~v[14];
131
132 const rounds = comptime []RoundParam {
133 Rp(0, 4, 8, 12, 0, 1),
134 Rp(1, 5, 9, 13, 2, 3),
135 Rp(2, 6, 10, 14, 4, 5),
136 Rp(3, 7, 11, 15, 6, 7),
137 Rp(0, 5, 10, 15, 8, 9),
138 Rp(1, 6, 11, 12, 10, 11),
139 Rp(2, 7, 8, 13, 12, 13),
140 Rp(3, 4, 9, 14, 14, 15),
141 };
142
143 comptime var j: usize = 0;
144 inline while (j < 10) : (j += 1) {
145 inline for (rounds) |r| {
146 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
147 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
148 v[r.c] = v[r.c] +% v[r.d];
149 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
150 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
151 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
152 v[r.c] = v[r.c] +% v[r.d];
153 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
154 }
155 }
156
157 for (d.h) |*r, i| {
158 *r ^= v[i] ^ v[i + 8];
159 }
160 }
161};}
162
163// TODO: bigint rem >1 digits for 224 integer output.
164//
165// test "blake2s224 single" {
166// const hash1 = 0xa847d26c2f966c5c4cc222b174918a56037cdee34b3f872f;
167// debug.assert(hash1 == Blake2s224.hash(""));
168//
169// const hash2 = 0x1e2ed10fcdbc46e0ab3ea3f268a6c288083ae04e3d63a8de;
170// debug.assert(hash2 == Blake2s224.hash("abc"));
171//
172// const hash3 = 0xe486adf7b22d2944b434ae78ae64720c16ccf0479dab072d;
173// debug.assert(hash3 == Blake2s224.hash("The quick brown fox jumps over the lazy dog"));
174// }
175//
176// test "blake2s224 streaming" {
177// var h = Blake2s224.init();
178//
179// const hash1 = 0xa847d26c2f966c5c4cc222b174918a56037cdee34b3f872f;
180// debug.assert(hash1 == h.final());
181//
182// const hash2 = 0x1e2ed10fcdbc46e0ab3ea3f268a6c288083ae04e3d63a8de;
183//
184// h.reset();
185// h.update("abc");
186// debug.assert(hash2 == h.final());
187//
188// h.reset();
189// h.update("a");
190// h.update("b");
191// h.update("c");
192// debug.assert(hash2 == h.final());
193// }
194
195test "blake2s256 single" {
196 const hash1 = 0x69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9;
197 debug.assert(hash1 == Blake2s256.hash(""));
198
199 const hash2 = 0x508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982;
200 debug.assert(hash2 == Blake2s256.hash("abc"));
201
202 const hash3 = 0x606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812;
203 debug.assert(hash3 == Blake2s256.hash("The quick brown fox jumps over the lazy dog"));
204}
205
206test "blake2s256 streaming" {
207 var h = Blake2s256.init();
208
209 const hash1 = 0x69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9;
210 debug.assert(hash1 == h.final());
211
212 const hash2 = 0x508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982;
213
214 h.reset();
215 h.update("abc");
216 debug.assert(hash2 == h.final());
217
218 h.reset();
219 h.update("a");
220 h.update("b");
221 h.update("c");
222 debug.assert(hash2 == h.final());
223}
224
225
226/////////////////////
227// Blake2b
228
229pub const Blake2b384 = Blake2b(384);
230pub const Blake2b512 = Blake2b(512);
231
232fn Blake2b(comptime out_len: usize) -> type { return struct {
233 const Self = this;
234 const ReturnType = @IntType(false, out_len);
235 const u9 = @IntType(false, 9);
236
237 const iv = [8]u64 {
238 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
239 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
240 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
241 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
242 };
243
244 const sigma = [12][16]u8 {
245 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
246 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
247 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
248 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
249 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
250 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
251 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
252 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
253 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
254 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
255 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
256 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
257 };
258
259 h: [8]u64,
260 t: u128,
261 // Streaming cache
262 buf: [128]u8,
263 buf_len: u8,
264
265 pub fn init() -> Self {
266 debug.assert(8 <= out_len and out_len <= 512);
267
268 var s: Self = undefined;
269 s.reset();
270 return s;
271 }
272
273 pub fn reset(d: &Self) {
274 mem.copy(u64, d.h[0..], iv[0..]);
275
276 // No key plus default parameters
277 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
278 d.t = 0;
279 d.buf_len = 0;
280 }
281
282 pub fn hash(b: []const u8) -> ReturnType {
283 var d = Self.init();
284 d.update(b);
285 return d.final();
286 }
287
288 pub fn update(d: &Self, b: []const u8) {
289 var off: usize = 0;
290
291 // Partial buffer exists from previous update. Copy into buffer then hash.
292 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
293 off += 128 - d.buf_len;
294 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
295 d.t += 128;
296 d.round(d.buf[0..], false);
297 d.buf_len = 0;
298 }
299
300 // Full middle blocks.
301 while (off + 128 < b.len) : (off += 128) {
302 d.t += 128;
303 d.round(b[off..off + 128], false);
304 }
305
306 // Copy any remainder for next pass.
307 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
308 d.buf_len += u8(b[off..].len);
309 }
310
311 pub fn final(d: &Self) -> ReturnType {
312 mem.set(u8, d.buf[d.buf_len..], 0);
313 d.t += d.buf_len;
314 d.round(d.buf[0..], true);
315
316 const rr = d.h[0 .. out_len / 64];
317
318 var j: u9 = 0;
319 var r: ReturnType = 0;
320 for (rr) |p| {
321 r |= ReturnType(p) << j;
322 j +%= 64;
323 }
324
325 return std.endian.swapIfLe(ReturnType, r);
326 }
327
328 fn round(d: &Self, b: []const u8, last: bool) {
329 debug.assert(b.len == 128);
330
331 var m: [16]u64 = undefined;
332 var v: [16]u64 = undefined;
333
334 for (m) |*r, i| {
335 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
336 }
337
338 var k: usize = 0;
339 while (k < 8) : (k += 1) {
340 v[k] = d.h[k];
341 v[k+8] = iv[k];
342 }
343
344 v[12] ^= @truncate(u64, d.t);
345 v[13] ^= u64(d.t >> 64);
346 if (last) v[14] = ~v[14];
347
348 const rounds = comptime []RoundParam {
349 Rp(0, 4, 8, 12, 0, 1),
350 Rp(1, 5, 9, 13, 2, 3),
351 Rp(2, 6, 10, 14, 4, 5),
352 Rp(3, 7, 11, 15, 6, 7),
353 Rp(0, 5, 10, 15, 8, 9),
354 Rp(1, 6, 11, 12, 10, 11),
355 Rp(2, 7, 8, 13, 12, 13),
356 Rp(3, 4, 9, 14, 14, 15),
357 };
358
359 comptime var j: usize = 0;
360 inline while (j < 12) : (j += 1) {
361 inline for (rounds) |r| {
362 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
363 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
364 v[r.c] = v[r.c] +% v[r.d];
365 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
366 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
367 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
368 v[r.c] = v[r.c] +% v[r.d];
369 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
370 }
371 }
372
373 for (d.h) |*r, i| {
374 *r ^= v[i] ^ v[i + 8];
375 }
376 }
377};}
378
379// TODO: bigint rem >1 digits for 384 integer output.
380
381// test "blake2b384 single" {
382// const hash1 = 0xb32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100;
383// debug.assert(hash1 == Blake2b384.hash(""));
384//
385// const hash2 = 0x6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4;
386// debug.assert(hash2 == Blake2b384.hash("abc"));
387//
388// const hash3 = 0xb7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d;
389// debug.assert(hash3 == Blake2b384.hash("The quick brown fox jumps over the lazy dog"));
390// }
391//
392// test "blake2b384 streaming" {
393// var h = Blake2b384.init();
394//
395// const hash1 = 0xb32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100;
396// debug.assert(hash1 == h.final());
397//
398// const hash2 = 0x6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4;
399//
400// h.reset();
401// h.update("abc");
402// debug.assert(hash2 == h.final());
403//
404// h.reset();
405// h.update("a");
406// h.update("b");
407// h.update("c");
408// debug.assert(hash2 == h.final());
409// }
410
411test "blake2b512 single" {
412 const hash1 = 0x786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce;
413 debug.assert(hash1 == Blake2b512.hash(""));
414
415 const hash2 = 0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923;
416 debug.assert(hash2 == Blake2b512.hash("abc"));
417
418 const hash3 = 0xa8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918;
419 debug.assert(hash3 == Blake2b512.hash("The quick brown fox jumps over the lazy dog"));
420}
421
422test "blake2b512 streaming" {
423 var h = Blake2b512.init();
424
425 const hash1 = 0x786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce;
426 debug.assert(hash1 == h.final());
427
428 const hash2 = 0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923;
429
430 h.reset();
431 h.update("abc");
432 debug.assert(hash2 == h.final());
433
434 h.reset();
435 h.update("a");
436 h.update("b");
437 h.update("c");
438 debug.assert(hash2 == h.final());
439}
std/crypto/index.zig+6-6
...@@ -7,15 +7,15 @@ pub const Sha256 = sha2.Sha256;...@@ -7,15 +7,15 @@ pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;8pub const Sha512 = sha2.Sha512;
99
10const blake2x = @import("blake2x.zig");10const blake2 = @import("blake2.zig");
11pub const Blake2s224 = blake2x.Blake2s224;11pub const Blake2s224 = blake2.Blake2s224;
12pub const Blake2s256 = blake2x.Blake2s256;12pub const Blake2s256 = blake2.Blake2s256;
13pub const Blake2b384 = blake2x.Blake2b384;13pub const Blake2b384 = blake2.Blake2b384;
14pub const Blake2b512 = blake2x.Blake2b512;14pub const Blake2b512 = blake2.Blake2b512;
1515
16test "crypto" {16test "crypto" {
17 _ = @import("md5.zig");17 _ = @import("md5.zig");
18 _ = @import("sha1.zig");18 _ = @import("sha1.zig");
19 _ = @import("sha2.zig");19 _ = @import("sha2.zig");
20 _ = @import("blake2x.zig");20 _ = @import("blake2.zig");
21}21}
std/crypto/md5.zig+27-20
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const builtin = @import("builtin");
4const debug = @import("../debug/index.zig");5const debug = @import("../debug/index.zig");
6const fmt = @import("../fmt/index.zig");
57
6const RoundParam = struct {8const RoundParam = struct {
7 a: usize, b: usize, c: usize, d: usize,9 a: usize, b: usize, c: usize, d: usize,
...@@ -42,10 +44,10 @@ pub const Md5 = struct {...@@ -42,10 +44,10 @@ pub const Md5 = struct {
42 d.total_len = 0;44 d.total_len = 0;
43 }45 }
4446
45 pub fn hash(b: []const u8) -> u128 {47 pub fn hash(b: []const u8, out: []u8) {
46 var d = Md5.init();48 var d = Md5.init();
47 d.update(b);49 d.update(b);
48 return d.final();50 d.final(out);
49 }51 }
5052
51 pub fn update(d: &Self, b: []const u8) {53 pub fn update(d: &Self, b: []const u8) {
...@@ -73,7 +75,9 @@ pub const Md5 = struct {...@@ -73,7 +75,9 @@ pub const Md5 = struct {
73 d.total_len +%= b.len;75 d.total_len +%= b.len;
74 }76 }
7577
76 pub fn final(d: &Self) -> u128 {78 pub fn final(d: &Self, out: []u8) {
79 debug.assert(out.len >= 16);
80
77 // The buffer here will never be completely full.81 // The buffer here will never be completely full.
78 mem.set(u8, d.buf[d.buf_len..], 0);82 mem.set(u8, d.buf[d.buf_len..], 0);
7983
...@@ -98,13 +102,9 @@ pub const Md5 = struct {...@@ -98,13 +102,9 @@ pub const Md5 = struct {
98102
99 d.round(d.buf[0..]);103 d.round(d.buf[0..]);
100104
101 const r =105 for (d.s) |s, j| {
102 (u128(d.s[3]) << 96) |106 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
103 (u128(d.s[2]) << 64) |107 }
104 (u128(d.s[1]) << 32) |
105 (u128(d.s[0]) << 0);
106
107 return endian.swapIfLe(u128, r);
108 }108 }
109109
110 fn round(d: &Self, b: []const u8) {110 fn round(d: &Self, b: []const u8) {
...@@ -226,28 +226,35 @@ pub const Md5 = struct {...@@ -226,28 +226,35 @@ pub const Md5 = struct {
226 }226 }
227};227};
228228
229const htest = @import("test.zig");
230
229test "md5 single" {231test "md5 single" {
230 debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == Md5.hash(""));232 htest.assertEqualHash(Md5, "d41d8cd98f00b204e9800998ecf8427e", "");
231 debug.assert(0x0cc175b9c0f1b6a831c399e269772661 == Md5.hash("a"));233 htest.assertEqualHash(Md5, "0cc175b9c0f1b6a831c399e269772661", "a");
232 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == Md5.hash("abc"));234 htest.assertEqualHash(Md5, "900150983cd24fb0d6963f7d28e17f72", "abc");
233 debug.assert(0xf96b697d7cb7938d525a2f31aaf161d0 == Md5.hash("message digest"));235 htest.assertEqualHash(Md5, "f96b697d7cb7938d525a2f31aaf161d0", "message digest");
234 debug.assert(0xc3fcd3d76192e4007dfb496cca67e13b == Md5.hash("abcdefghijklmnopqrstuvwxyz"));236 htest.assertEqualHash(Md5, "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz");
235 debug.assert(0xd174ab98d277d9f5a5611c2c9f419d9f == Md5.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));237 htest.assertEqualHash(Md5, "d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
236 debug.assert(0x57edf4a22be3c955ac49da2e2107b67a == Md5.hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));238 htest.assertEqualHash(Md5, "57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
237}239}
238240
239test "md5 streaming" {241test "md5 streaming" {
240 var h = Md5.init();242 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
244 h.reset();248 h.reset();
245 h.update("abc");249 h.update("abc");
246 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());250 h.final(out[0..]);
251 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
247252
248 h.reset();253 h.reset();
249 h.update("a");254 h.update("a");
250 h.update("b");255 h.update("b");
251 h.update("c");256 h.update("c");
252 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());257 h.final(out[0..]);
258
259 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
253}260}
std/crypto/sha1.zig+21-17
...@@ -2,6 +2,7 @@ const mem = @import("../mem.zig");...@@ -2,6 +2,7 @@ const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
56
6pub const u160 = @IntType(false, 160);7pub const u160 = @IntType(false, 160);
78
...@@ -38,10 +39,10 @@ pub const Sha1 = struct {...@@ -38,10 +39,10 @@ pub const Sha1 = struct {
38 d.total_len = 0;39 d.total_len = 0;
39 }40 }
4041
41 pub fn hash(b: []const u8) -> u160 {42 pub fn hash(b: []const u8, out: []u8) {
42 var d = Sha1.init();43 var d = Sha1.init();
43 d.update(b);44 d.update(b);
44 return d.final();45 d.final(out);
45 }46 }
4647
47 pub fn update(d: &Self, b: []const u8) {48 pub fn update(d: &Self, b: []const u8) {
...@@ -68,7 +69,9 @@ pub const Sha1 = struct {...@@ -68,7 +69,9 @@ pub const Sha1 = struct {
68 d.total_len += b.len;69 d.total_len += b.len;
69 }70 }
7071
71 pub fn final(d: &Self) -> u160 {72 pub fn final(d: &Self, out: []u8) {
73 debug.assert(out.len >= 20);
74
72 // The buffer here will never be completely full.75 // The buffer here will never be completely full.
73 mem.set(u8, d.buf[d.buf_len..], 0);76 mem.set(u8, d.buf[d.buf_len..], 0);
7477
...@@ -93,14 +96,9 @@ pub const Sha1 = struct {...@@ -93,14 +96,9 @@ pub const Sha1 = struct {
9396
94 d.round(d.buf[0..]);97 d.round(d.buf[0..]);
9598
96 const r =99 for (d.s) |s, j| {
97 (u160(d.s[0]) << 128) |100 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
98 (u160(d.s[1]) << 96) |101 }
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);
104 }102 }
105103
106 fn round(d: &Self, b: []const u8) {104 fn round(d: &Self, b: []const u8) {
...@@ -257,24 +255,30 @@ pub const Sha1 = struct {...@@ -257,24 +255,30 @@ pub const Sha1 = struct {
257 }255 }
258};256};
259257
258const htest = @import("test.zig");
259
260test "sha1 single" {260test "sha1 single" {
261 debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == Sha1.hash(""));261 htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
262 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == Sha1.hash("abc"));262 htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
263 debug.assert(0xa49b2446a02c645bf419f995b67091253a04a259 == Sha1.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));263 htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
264}264}
265265
266test "sha1 streaming" {266test "sha1 streaming" {
267 var h = Sha1.init();267 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
271 h.reset();273 h.reset();
272 h.update("abc");274 h.update("abc");
273 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());275 h.final(out[0..]);
276 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
274277
275 h.reset();278 h.reset();
276 h.update("a");279 h.update("a");
277 h.update("b");280 h.update("b");
278 h.update("c");281 h.update("c");
279 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());282 h.final(out[0..]);
283 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
280}284}
std/crypto/sha2.zig+65-56
...@@ -3,6 +3,7 @@ const math = @import("../math/index.zig");...@@ -3,6 +3,7 @@ const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const htest = @import("test.zig");
67
7/////////////////////8/////////////////////
8// Sha224 + Sha2569// Sha224 + Sha256
...@@ -57,7 +58,6 @@ pub const Sha256 = Sha2_32(Sha256Params);...@@ -57,7 +58,6 @@ pub const Sha256 = Sha2_32(Sha256Params);
5758
58fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {59fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
59 const Self = this;60 const Self = this;
60 const ReturnType = @IntType(false, params.out_len);
6161
62 s: [8]u32,62 s: [8]u32,
63 // Streaming Cache63 // Streaming Cache
...@@ -84,10 +84,10 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {...@@ -84,10 +84,10 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
84 d.total_len = 0;84 d.total_len = 0;
85 }85 }
8686
87 pub fn hash(b: []const u8) -> ReturnType {87 pub fn hash(b: []const u8, out: []u8) {
88 var d = Self.init();88 var d = Self.init();
89 d.update(b);89 d.update(b);
90 return d.final();90 d.final(out);
91 }91 }
9292
93 pub fn update(d: &Self, b: []const u8) {93 pub fn update(d: &Self, b: []const u8) {
...@@ -114,7 +114,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {...@@ -114,7 +114,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
114 d.total_len += b.len;114 d.total_len += b.len;
115 }115 }
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
118 // The buffer here will never be completely full.120 // The buffer here will never be completely full.
119 mem.set(u8, d.buf[d.buf_len..], 0);121 mem.set(u8, d.buf[d.buf_len..], 0);
120122
...@@ -142,14 +144,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {...@@ -142,14 +144,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
142 // May truncate for possible 224 output144 // May truncate for possible 224 output
143 const rr = d.s[0 .. params.out_len / 32];145 const rr = d.s[0 .. params.out_len / 32];
144146
145 var j: u8 = u8(rr.len - 1) * 32;147 for (rr) |s, j| {
146 var r: ReturnType = 0;148 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
147 for (rr) |p| {
148 r |= ReturnType(p) << j;
149 j -%= 32;
150 }149 }
151
152 return endian.swapIfBe(ReturnType, r);
153 }150 }
154151
155 fn round(d: &Self, b: []const u8) {152 fn round(d: &Self, b: []const u8) {
...@@ -275,9 +272,9 @@ test "sha224 single" {...@@ -275,9 +272,9 @@ test "sha224 single" {
275 return;272 return;
276 }273 }
277274
278 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == Sha224.hash(""));275 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
279 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == Sha224.hash("abc"));276 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
280 debug.assert(0xc97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3 == Sha224.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));277 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
281}278}
282279
283test "sha224 streaming" {280test "sha224 streaming" {
...@@ -287,18 +284,22 @@ test "sha224 streaming" {...@@ -287,18 +284,22 @@ test "sha224 streaming" {
287 }284 }
288285
289 var h = Sha224.init();286 var h = Sha224.init();
287 var out: [28]u8 = undefined;
290288
291 debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == h.final());289 h.final(out[0..]);
290 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
292291
293 h.reset();292 h.reset();
294 h.update("abc");293 h.update("abc");
295 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());294 h.final(out[0..]);
295 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
296296
297 h.reset();297 h.reset();
298 h.update("a");298 h.update("a");
299 h.update("b");299 h.update("b");
300 h.update("c");300 h.update("c");
301 debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());301 h.final(out[0..]);
302 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
302}303}
303304
304test "sha256 single" {305test "sha256 single" {
...@@ -307,9 +308,9 @@ test "sha256 single" {...@@ -307,9 +308,9 @@ test "sha256 single" {
307 return;308 return;
308 }309 }
309310
310 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == Sha256.hash(""));311 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
311 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == Sha256.hash("abc"));312 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
312 debug.assert(0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1 == Sha256.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));313 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
313}314}
314315
315test "sha256 streaming" {316test "sha256 streaming" {
...@@ -319,18 +320,22 @@ test "sha256 streaming" {...@@ -319,18 +320,22 @@ test "sha256 streaming" {
319 }320 }
320321
321 var h = Sha256.init();322 var h = Sha256.init();
323 var out: [32]u8 = undefined;
322324
323 debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == h.final());325 h.final(out[0..]);
326 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
324327
325 h.reset();328 h.reset();
326 h.update("abc");329 h.update("abc");
327 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());330 h.final(out[0..]);
331 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
328332
329 h.reset();333 h.reset();
330 h.update("a");334 h.update("a");
331 h.update("b");335 h.update("b");
332 h.update("c");336 h.update("c");
333 debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());337 h.final(out[0..]);
338 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
334}339}
335340
336341
...@@ -387,7 +392,6 @@ pub const Sha512 = Sha2_64(Sha512Params);...@@ -387,7 +392,6 @@ pub const Sha512 = Sha2_64(Sha512Params);
387392
388fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {393fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
389 const Self = this;394 const Self = this;
390 const ReturnType = @IntType(false, params.out_len);
391 const u9 = @IntType(false, 9);395 const u9 = @IntType(false, 9);
392396
393 s: [8]u64,397 s: [8]u64,
...@@ -415,10 +419,10 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {...@@ -415,10 +419,10 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
415 d.total_len = 0;419 d.total_len = 0;
416 }420 }
417421
418 pub fn hash(b: []const u8) -> ReturnType {422 pub fn hash(b: []const u8, out: []u8) {
419 var d = Self.init();423 var d = Self.init();
420 d.update(b);424 d.update(b);
421 return d.final();425 d.final(out);
422 }426 }
423427
424 pub fn update(d: &Self, b: []const u8) {428 pub fn update(d: &Self, b: []const u8) {
...@@ -445,7 +449,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {...@@ -445,7 +449,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
445 d.total_len += b.len;449 d.total_len += b.len;
446 }450 }
447451
448 pub fn final(d: &Self) -> ReturnType {452 pub fn final(d: &Self, out: []u8) {
453 debug.assert(out.len >= params.out_len / 8);
454
449 // The buffer here will never be completely full.455 // The buffer here will never be completely full.
450 mem.set(u8, d.buf[d.buf_len..], 0);456 mem.set(u8, d.buf[d.buf_len..], 0);
451457
...@@ -473,14 +479,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {...@@ -473,14 +479,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
473 // May truncate for possible 384 output479 // May truncate for possible 384 output
474 const rr = d.s[0 .. params.out_len / 64];480 const rr = d.s[0 .. params.out_len / 64];
475481
476 var j: u9 = u9(rr.len - 1) * 64;482 for (rr) |s, j| {
477 var r: ReturnType = 0;483 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
478 for (rr) |p| {
479 r |= ReturnType(p) << j;
480 j -%= 64;
481 }484 }
482
483 return endian.swapIfBe(ReturnType, r);
484 }485 }
485486
486 fn round(d: &Self, b: []const u8) {487 fn round(d: &Self, b: []const u8) {
...@@ -626,14 +627,14 @@ test "sha384 single" {...@@ -626,14 +627,14 @@ test "sha384 single" {
626 return;627 return;
627 }628 }
628629
629 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;630 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
630 debug.assert(h1 == Sha384.hash(""));631 htest.assertEqualHash(Sha384, h1, "");
631632
632 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;633 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
633 debug.assert(h2 == Sha384.hash("abc"));634 htest.assertEqualHash(Sha384, h2, "abc");
634635
635 const h3 = 0x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039;636 const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
636 debug.assert(h3 == Sha384.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));637 htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
637}638}
638639
639test "sha384 streaming" {640test "sha384 streaming" {
...@@ -643,21 +644,25 @@ test "sha384 streaming" {...@@ -643,21 +644,25 @@ test "sha384 streaming" {
643 }644 }
644645
645 var h = Sha384.init();646 var h = Sha384.init();
647 var out: [48]u8 = undefined;
646648
647 const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;649 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
648 debug.assert(h1 == h.final());650 h.final(out[0..]);
651 htest.assertEqual(h1, out[0..]);
649652
650 const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;653 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
651654
652 h.reset();655 h.reset();
653 h.update("abc");656 h.update("abc");
654 debug.assert(h2 == h.final());657 h.final(out[0..]);
658 htest.assertEqual(h2, out[0..]);
655659
656 h.reset();660 h.reset();
657 h.update("a");661 h.update("a");
658 h.update("b");662 h.update("b");
659 h.update("c");663 h.update("c");
660 debug.assert(h2 == h.final());664 h.final(out[0..]);
665 htest.assertEqual(h2, out[0..]);
661}666}
662667
663test "sha512 single" {668test "sha512 single" {
...@@ -666,14 +671,14 @@ test "sha512 single" {...@@ -666,14 +671,14 @@ test "sha512 single" {
666 return;671 return;
667 }672 }
668673
669 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;674 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
670 debug.assert(h1 == Sha512.hash(""));675 htest.assertEqualHash(Sha512, h1, "");
671676
672 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;677 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
673 debug.assert(h2 == Sha512.hash("abc"));678 htest.assertEqualHash(Sha512, h2, "abc");
674679
675 const h3 = 0x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909;680 const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
676 debug.assert(h3 == Sha512.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));681 htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
677}682}
678683
679test "sha512 streaming" {684test "sha512 streaming" {
...@@ -683,19 +688,23 @@ test "sha512 streaming" {...@@ -683,19 +688,23 @@ test "sha512 streaming" {
683 }688 }
684689
685 var h = Sha512.init();690 var h = Sha512.init();
691 var out: [64]u8 = undefined;
686692
687 const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;693 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
688 debug.assert(h1 == h.final());694 h.final(out[0..]);
695 htest.assertEqual(h1, out[0..]);
689696
690 const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;697 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
691698
692 h.reset();699 h.reset();
693 h.update("abc");700 h.update("abc");
694 debug.assert(h2 == h.final());701 h.final(out[0..]);
702 htest.assertEqual(h2, out[0..]);
695703
696 h.reset();704 h.reset();
697 h.update("a");705 h.update("a");
698 h.update("b");706 h.update("b");
699 h.update("c");707 h.update("c");
700 debug.assert(h2 == h.final());708 h.final(out[0..]);
709 htest.assertEqual(h2, out[0..]);
701}710}