authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-13 14:40:21+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-13 14:40:21+13:00
log51fdbf7f8c282c7b91a688c9069b363e90bedf6e
treed509b0494776da54c78aa299d4679cf4f17180e0
parent304f6f1d0165f9bdacb7d80479298ca0acff1c27

Add Md5 and Sha1 hash functions

Some performance comparisons to C. We take the fastest time measurement taken across multiple runs. The block hashing functions use the same md5/sha1 methods. ``` Cpu: Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz Gcc: 7.2.1 20171224 Clang: 5.0.1 Zig: 0.1.1.304f6f1d ``` See https://www.nayuki.io/page/fast-md5-hash-implementation-in-x86-assembly: ``` gcc -O2 661 Mb/s clang -O2 490 Mb/s zig --release-fast and zig --release-safe 570 Mb/s zig 50 Mb/s ``` See https://www.nayuki.io/page/fast-sha1-hash-implementation-in-x86-assembly: ``` gcc -O2 588 Mb/s clang -O2 563 Mb/s zig --release-fast and zig --release-safe 610 Mb/s zig 21 Mb/s ``` In short, zig provides pretty useful tools for writing this sort of code. We are in the lead against clang (which uses the same LLVM backend) with us being slower only against md5 with GCC.

5 files changed, 544 insertions(+), 0 deletions(-)

CMakeLists.txt+3
...@@ -364,6 +364,9 @@ set(ZIG_STD_FILES...@@ -364,6 +364,9 @@ set(ZIG_STD_FILES
364 "c/index.zig"364 "c/index.zig"
365 "c/linux.zig"365 "c/linux.zig"
366 "c/windows.zig"366 "c/windows.zig"
367 "crypto/index.zig"
368 "crypto/md5.zig"
369 "crypto/sha1.zig"
367 "cstr.zig"370 "cstr.zig"
368 "debug/failing_allocator.zig"371 "debug/failing_allocator.zig"
369 "debug/index.zig"372 "debug/index.zig"
std/crypto/index.zig created+7
...@@ -0,0 +1,7 @@
1pub const Sha1 = @import("md5.zig").Sha1;
2pub const Md5 = @import("sha1.zig").Md5;
3
4test "crypto" {
5 _ = @import("md5.zig");
6 _ = @import("sha1.zig");
7}
std/crypto/md5.zig created+252
...@@ -0,0 +1,252 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5
6const RoundParam = struct {
7 a: u32, b: u32, c: u32, d: u32,
8 k: u32, s: u32, t: u32
9};
10
11fn Rp(a: u32, b: u32, c: u32, d: u32, k: u32, s: u5, t: u32) -> RoundParam {
12 return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
13}
14
15/// const hash1 = Md5.hash("my input");
16///
17/// const hasher = Md5.init();
18/// hasher.update("my ");
19/// hasher.update("input");
20/// const hash2 = hasher.final();
21pub const Md5 = struct {
22 const Self = this;
23
24 s: [4]u32,
25 // Streaming Cache
26 buf: [64]u8,
27 buf_len: u8,
28 total_len: u64,
29
30 pub fn init() -> Self {
31 var d: Self = undefined;
32 d.reset();
33 return d;
34 }
35
36 pub fn reset(d: &Self) {
37 d.s[0] = 0x67452301;
38 d.s[1] = 0xEFCDAB89;
39 d.s[2] = 0x98BADCFE;
40 d.s[3] = 0x10325476;
41 d.buf_len = 0;
42 d.total_len = 0;
43 }
44
45 pub fn hash(b: []const u8) -> u128 {
46 var d = Md5.init();
47 d.update(b);
48 return d.final();
49 }
50
51 pub fn update(d: &Self, b: []const u8) {
52 var off: usize = 0;
53
54 // Partial buffer exists from previous update. Copy into buffer then hash.
55 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
56 off += 64 - d.buf_len;
57 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
58
59 d.round(d.buf[0..]);
60 d.buf_len = 0;
61 }
62
63 // Full middle blocks.
64 while (off + 64 < b.len) : (off += 64) {
65 d.round(b[off..off + 64]);
66 }
67
68 // Copy any remainder for next pass.
69 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
70 d.buf_len += u8(b[off..].len);
71
72 d.total_len += b.len;
73 }
74
75 pub fn final(d: &Self) -> u128 {
76 // The buffer here will never be completely full.
77 mem.set(u8, d.buf[d.buf_len..], 0);
78
79 // Append padding bits.
80 d.buf[d.buf_len] = 0x80;
81 d.buf_len += 1;
82
83 // > 448 mod 512 so need to add an extra round to wrap around.
84 if (64 - d.buf_len < 8) {
85 d.round(d.buf[0..]);
86 mem.set(u8, d.buf[0..], 0);
87 }
88
89 // Append message length.
90 var i: usize = 1;
91 var len = d.total_len >> 5;
92 d.buf[56] = u8(d.total_len & 0x1f) << 3;
93 while (i < 8) : (i += 1) {
94 d.buf[56 + i] = u8(len & 0xff);
95 len >>= 8;
96 }
97
98 d.round(d.buf[0..]);
99
100 const r =
101 (u128(d.s[3]) << 96) |
102 (u128(d.s[2]) << 64) |
103 (u128(d.s[1]) << 32) |
104 (u128(d.s[0]) << 0);
105
106 return endian.swapIfLe(u128, r);
107 }
108
109 fn round(d: &Self, b: []const u8) {
110 debug.assert(b.len == 64);
111
112 var s: [16]u32 = undefined;
113
114 // ERROR: cannot unroll this at comptime
115 var i: usize = 0;
116 while (i < 16) : (i += 1) {
117 // NOTE: Performing or's separately improves perf by ~10%
118 s[i] = 0;
119 s[i] |= u32(b[i*4+0]);
120 s[i] |= u32(b[i*4+1]) << 8;
121 s[i] |= u32(b[i*4+2]) << 16;
122 s[i] |= u32(b[i*4+3]) << 24;
123 }
124
125 var v: [4]u32 = []u32 {
126 d.s[0], d.s[1], d.s[2], d.s[3],
127 };
128
129 const round0 = comptime []RoundParam {
130 Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
131 Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
132 Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
133 Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
134 Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
135 Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
136 Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
137 Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
138 Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
139 Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
140 Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
141 Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
142 Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
143 Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
144 Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
145 Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
146 };
147 inline for (round0) |r| {
148 v[r.a] = v[r.a] +% (v[r.d] ^ (v[r.b] & (v[r.c] ^ v[r.d]))) +% r.t +% s[r.k];
149 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
150 }
151
152 const round1 = comptime []RoundParam {
153 Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
154 Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
155 Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
156 Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
157 Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
158 Rp(3, 0, 1, 2, 10, 9, 0x02441453),
159 Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
160 Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
161 Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
162 Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
163 Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
164 Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
165 Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
166 Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
167 Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
168 Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
169 };
170 inline for (round1) |r| {
171 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.d] & (v[r.b] ^ v[r.c]))) +% r.t +% s[r.k];
172 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
173 }
174
175 const round2 = comptime []RoundParam {
176 Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
177 Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
178 Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
179 Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
180 Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
181 Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
182 Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
183 Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
184 Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
185 Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
186 Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
187 Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
188 Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
189 Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
190 Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
191 Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
192 };
193 inline for (round2) |r| {
194 v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
195 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
196 }
197
198 const round3 = comptime []RoundParam {
199 Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
200 Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
201 Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
202 Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
203 Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
204 Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
205 Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
206 Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
207 Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
208 Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
209 Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
210 Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
211 Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
212 Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
213 Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
214 Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
215 };
216 inline for (round3) |r| {
217 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
218 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
219 }
220
221 d.s[0] +%= v[0];
222 d.s[1] +%= v[1];
223 d.s[2] +%= v[2];
224 d.s[3] +%= v[3];
225 }
226};
227
228test "md5 single" {
229 debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == Md5.hash(""));
230 debug.assert(0x0cc175b9c0f1b6a831c399e269772661 == Md5.hash("a"));
231 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == Md5.hash("abc"));
232 debug.assert(0xf96b697d7cb7938d525a2f31aaf161d0 == Md5.hash("message digest"));
233 debug.assert(0xc3fcd3d76192e4007dfb496cca67e13b == Md5.hash("abcdefghijklmnopqrstuvwxyz"));
234 debug.assert(0xd174ab98d277d9f5a5611c2c9f419d9f == Md5.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
235 debug.assert(0x57edf4a22be3c955ac49da2e2107b67a == Md5.hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
236}
237
238test "md5 streaming" {
239 var h = Md5.init();
240
241 debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == h.final());
242
243 h.reset();
244 h.update("abc");
245 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
246
247 h.reset();
248 h.update("a");
249 h.update("b");
250 h.update("c");
251 debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
252}
std/crypto/sha1.zig created+280
...@@ -0,0 +1,280 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5
6pub const u160 = @IntType(false, 160);
7
8const RoundParam = struct {
9 a: u32, b: u32, c: u32, d: u32, e: u32, i: u32,
10};
11
12fn Rp(a: u32, b: u32, c: u32, d: u32, e: u32, i: u32) -> RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
14}
15
16pub const Sha1 = struct {
17 const Self = this;
18
19 s: [5]u32,
20 // Streaming Cache
21 buf: [64]u8,
22 buf_len: u8,
23 total_len: u64,
24
25 pub fn init() -> Self {
26 var d: Self = undefined;
27 d.reset();
28 return d;
29 }
30
31 pub fn reset(d: &Self) {
32 d.s[0] = 0x67452301;
33 d.s[1] = 0xEFCDAB89;
34 d.s[2] = 0x98BADCFE;
35 d.s[3] = 0x10325476;
36 d.s[4] = 0xC3D2E1F0;
37 d.buf_len = 0;
38 d.total_len = 0;
39 }
40
41 pub fn hash(b: []const u8) -> u160 {
42 var d = Sha1.init();
43 d.update(b);
44 return d.final();
45 }
46
47 pub fn update(d: &Self, b: []const u8) {
48 var off: usize = 0;
49
50 // Partial buffer exists from previous update. Copy into buffer then hash.
51 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
52 off += 64 - d.buf_len;
53 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
54
55 d.round(d.buf[0..]);
56 d.buf_len = 0;
57 }
58
59 // Full middle blocks.
60 while (off + 64 < b.len) : (off += 64) {
61 d.round(b[off..off + 64]);
62 }
63
64 // Copy any remainder for next pass.
65 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
66 d.buf_len += u8(b[off..].len);
67
68 d.total_len += b.len;
69 }
70
71 pub fn final(d: &Self) -> u160 {
72 // The buffer here will never be completely full.
73 mem.set(u8, d.buf[d.buf_len..], 0);
74
75 // Append padding bits.
76 d.buf[d.buf_len] = 0x80;
77 d.buf_len += 1;
78
79 // > 448 mod 512 so need to add an extra round to wrap around.
80 if (64 - d.buf_len < 8) {
81 d.round(d.buf[0..]);
82 mem.set(u8, d.buf[0..], 0);
83 }
84
85 // Append message length.
86 var i: usize = 1;
87 var len = d.total_len >> 5;
88 d.buf[63] = u8(d.total_len & 0x1f) << 3;
89 while (i < 8) : (i += 1) {
90 d.buf[63 - i] = u8(len & 0xff);
91 len >>= 8;
92 }
93
94 d.round(d.buf[0..]);
95
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);
104 }
105
106 fn round(d: &Self, b: []const u8) {
107 debug.assert(b.len == 64);
108
109 var s: [16]u32 = undefined;
110
111 var v: [5]u32 = []u32 {
112 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
113 };
114
115 const round0a = comptime []RoundParam {
116 Rp(0, 1, 2, 3, 4, 0),
117 Rp(4, 0, 1, 2, 3, 1),
118 Rp(3, 4, 0, 1, 2, 2),
119 Rp(2, 3, 4, 0, 1, 3),
120 Rp(1, 2, 3, 4, 0, 4),
121 Rp(0, 1, 2, 3, 4, 5),
122 Rp(4, 0, 1, 2, 3, 6),
123 Rp(3, 4, 0, 1, 2, 7),
124 Rp(2, 3, 4, 0, 1, 8),
125 Rp(1, 2, 3, 4, 0, 9),
126 Rp(0, 1, 2, 3, 4, 10),
127 Rp(4, 0, 1, 2, 3, 11),
128 Rp(3, 4, 0, 1, 2, 12),
129 Rp(2, 3, 4, 0, 1, 13),
130 Rp(1, 2, 3, 4, 0, 14),
131 Rp(0, 1, 2, 3, 4, 15),
132 };
133 inline for (round0a) |r| {
134 s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
135 (u32(b[r.i * 4 + 1]) << 16) |
136 (u32(b[r.i * 4 + 2]) << 8) |
137 (u32(b[r.i * 4 + 3]) << 0);
138
139 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
140 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
141 v[r.b] = math.rotl(u32, v[r.b], u32(30));
142 }
143
144 const round0b = comptime []RoundParam {
145 Rp(4, 0, 1, 2, 3, 16),
146 Rp(3, 4, 0, 1, 2, 17),
147 Rp(2, 3, 4, 0, 1, 18),
148 Rp(1, 2, 3, 4, 0, 19),
149 };
150 inline for (round0b) |r| {
151 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
152 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
153
154 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
155 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
156 v[r.b] = math.rotl(u32, v[r.b], u32(30));
157 }
158
159 const round1 = comptime []RoundParam {
160 Rp(0, 1, 2, 3, 4, 20),
161 Rp(4, 0, 1, 2, 3, 21),
162 Rp(3, 4, 0, 1, 2, 22),
163 Rp(2, 3, 4, 0, 1, 23),
164 Rp(1, 2, 3, 4, 0, 24),
165 Rp(0, 1, 2, 3, 4, 25),
166 Rp(4, 0, 1, 2, 3, 26),
167 Rp(3, 4, 0, 1, 2, 27),
168 Rp(2, 3, 4, 0, 1, 28),
169 Rp(1, 2, 3, 4, 0, 29),
170 Rp(0, 1, 2, 3, 4, 30),
171 Rp(4, 0, 1, 2, 3, 31),
172 Rp(3, 4, 0, 1, 2, 32),
173 Rp(2, 3, 4, 0, 1, 33),
174 Rp(1, 2, 3, 4, 0, 34),
175 Rp(0, 1, 2, 3, 4, 35),
176 Rp(4, 0, 1, 2, 3, 36),
177 Rp(3, 4, 0, 1, 2, 37),
178 Rp(2, 3, 4, 0, 1, 38),
179 Rp(1, 2, 3, 4, 0, 39),
180 };
181 inline for (round1) |r| {
182 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
183 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
184
185 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
186 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
187 v[r.b] = math.rotl(u32, v[r.b], u32(30));
188 }
189
190 const round2 = comptime []RoundParam {
191 Rp(0, 1, 2, 3, 4, 40),
192 Rp(4, 0, 1, 2, 3, 41),
193 Rp(3, 4, 0, 1, 2, 42),
194 Rp(2, 3, 4, 0, 1, 43),
195 Rp(1, 2, 3, 4, 0, 44),
196 Rp(0, 1, 2, 3, 4, 45),
197 Rp(4, 0, 1, 2, 3, 46),
198 Rp(3, 4, 0, 1, 2, 47),
199 Rp(2, 3, 4, 0, 1, 48),
200 Rp(1, 2, 3, 4, 0, 49),
201 Rp(0, 1, 2, 3, 4, 50),
202 Rp(4, 0, 1, 2, 3, 51),
203 Rp(3, 4, 0, 1, 2, 52),
204 Rp(2, 3, 4, 0, 1, 53),
205 Rp(1, 2, 3, 4, 0, 54),
206 Rp(0, 1, 2, 3, 4, 55),
207 Rp(4, 0, 1, 2, 3, 56),
208 Rp(3, 4, 0, 1, 2, 57),
209 Rp(2, 3, 4, 0, 1, 58),
210 Rp(1, 2, 3, 4, 0, 59),
211 };
212 inline for (round2) |r| {
213 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
214 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
215
216 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
217 +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
218 v[r.b] = math.rotl(u32, v[r.b], u32(30));
219 }
220
221 const round3 = comptime []RoundParam {
222 Rp(0, 1, 2, 3, 4, 60),
223 Rp(4, 0, 1, 2, 3, 61),
224 Rp(3, 4, 0, 1, 2, 62),
225 Rp(2, 3, 4, 0, 1, 63),
226 Rp(1, 2, 3, 4, 0, 64),
227 Rp(0, 1, 2, 3, 4, 65),
228 Rp(4, 0, 1, 2, 3, 66),
229 Rp(3, 4, 0, 1, 2, 67),
230 Rp(2, 3, 4, 0, 1, 68),
231 Rp(1, 2, 3, 4, 0, 69),
232 Rp(0, 1, 2, 3, 4, 70),
233 Rp(4, 0, 1, 2, 3, 71),
234 Rp(3, 4, 0, 1, 2, 72),
235 Rp(2, 3, 4, 0, 1, 73),
236 Rp(1, 2, 3, 4, 0, 74),
237 Rp(0, 1, 2, 3, 4, 75),
238 Rp(4, 0, 1, 2, 3, 76),
239 Rp(3, 4, 0, 1, 2, 77),
240 Rp(2, 3, 4, 0, 1, 78),
241 Rp(1, 2, 3, 4, 0, 79),
242 };
243 inline for (round3) |r| {
244 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
245 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
246
247 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
248 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
249 v[r.b] = math.rotl(u32, v[r.b], u32(30));
250 }
251
252 d.s[0] +%= v[0];
253 d.s[1] +%= v[1];
254 d.s[2] +%= v[2];
255 d.s[3] +%= v[3];
256 d.s[4] +%= v[4];
257 }
258};
259
260test "sha1 single" {
261 debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == Sha1.hash(""));
262 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == Sha1.hash("abc"));
263 debug.assert(0xa49b2446a02c645bf419f995b67091253a04a259 == Sha1.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
264}
265
266test "sha1 streaming" {
267 var h = Sha1.init();
268
269 debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == h.final());
270
271 h.reset();
272 h.update("abc");
273 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
274
275 h.reset();
276 h.update("a");
277 h.update("b");
278 h.update("c");
279 debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
280}
std/index.zig+2
...@@ -10,6 +10,7 @@ pub const LinkedList = @import("linked_list.zig").LinkedList;...@@ -10,6 +10,7 @@ pub const LinkedList = @import("linked_list.zig").LinkedList;
10pub const base64 = @import("base64.zig");10pub const base64 = @import("base64.zig");
11pub const build = @import("build.zig");11pub const build = @import("build.zig");
12pub const c = @import("c/index.zig");12pub const c = @import("c/index.zig");
13pub const crypto = @import("crypto/index.zig");
13pub const cstr = @import("cstr.zig");14pub const cstr = @import("cstr.zig");
14pub const debug = @import("debug/index.zig");15pub const debug = @import("debug/index.zig");
15pub const dwarf = @import("dwarf.zig");16pub const dwarf = @import("dwarf.zig");
...@@ -39,6 +40,7 @@ test "std" {...@@ -39,6 +40,7 @@ test "std" {
39 _ = @import("base64.zig");40 _ = @import("base64.zig");
40 _ = @import("build.zig");41 _ = @import("build.zig");
41 _ = @import("c/index.zig");42 _ = @import("c/index.zig");
43 _ = @import("crypto/index.zig");
42 _ = @import("cstr.zig");44 _ = @import("cstr.zig");
43 _ = @import("debug/index.zig");45 _ = @import("debug/index.zig");
44 _ = @import("dwarf.zig");46 _ = @import("dwarf.zig");