authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 00:27:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 00:27:48-07:00
log750b00c642782127736eb378ec9583db2d680bb6
tree095ef980bdd7cdaeffaa2277be775b2cb1e4a2f2
parentfa6d150441d1d8679a77c5e9a6071fa952851376
parenta0c0f9ead53dab4f558dbb51cc8a49961fc6984f

Merge remote-tracking branch 'origin/master' into stage2-zig-cc


26 files changed, 2611 insertions(+), 1170 deletions(-)

CMakeLists.txt+6
......@@ -55,6 +55,7 @@ set(ZIG_PREFER_CLANG_CPP_DYLIB off CACHE BOOL "Try to link against -lclang-cpp")
5555set(ZIG_WORKAROUND_4799 off CACHE BOOL "workaround for https://github.com/ziglang/zig/issues/4799")
5656set(ZIG_WORKAROUND_POLLY_SO off CACHE STRING "workaround for https://github.com/ziglang/zig/issues/4799")
5757set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache if available")
58set(ZIG_WORKAROUND_6087 off CACHE BOOL "workaround for https://github.com/ziglang/zig/issues/6087")
5859
5960if(CCACHE_PROGRAM AND ZIG_USE_CCACHE)
6061 SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
......@@ -84,6 +85,11 @@ if(APPLE AND ZIG_STATIC)
8485 list(APPEND LLVM_LIBRARIES "${ZLIB}")
8586endif()
8687
88if(APPLE AND ZIG_WORKAROUND_6087)
89 list(REMOVE_ITEM LLVM_LIBRARIES "-llibxml2.tbd")
90 list(APPEND LLVM_LIBRARIES "-lxml2")
91endif()
92
8793if(APPLE AND ZIG_WORKAROUND_4799)
8894 # eg: ${CMAKE_PREFIX_PATH} could be /usr/local/opt/llvm/
8995 list(APPEND LLVM_LIBRARIES "-Wl,${CMAKE_PREFIX_PATH}/lib/libPolly.a" "-Wl,${CMAKE_PREFIX_PATH}/lib/libPollyPPCG.a" "-Wl,${CMAKE_PREFIX_PATH}/lib/libPollyISL.a")
README.md+6-1
......@@ -73,7 +73,12 @@ or
7373[error: unable to create target: 'Unable to find target for this triple (no targets are registered)'](https://github.com/ziglang/zig/issues/5055),
7474in which case try `-DZIG_WORKAROUND_4799=ON`
7575
76Hopefully this will be fixed upstream with LLVM 10.0.1.
76This has been fixed upstream with LLVM 10.0.1.
77
78Building with LLVM 10.0.1 you might run into this problem:
79`ld: library not found for -llibxml2.tbd`
80[Building with LLVM 10.0.1 installed via Homebrew fails](https://github.com/ziglang/zig/issues/6087),
81in which case you can try `-DZIG_WORKAROUND_6087=ON`.
7782
7883##### Windows
7984
doc/langref.html.in+9-16
......@@ -1841,7 +1841,7 @@ const Point = struct {
18411841 y: i32,
18421842};
18431843
1844test "compile-time array initalization" {
1844test "compile-time array initialization" {
18451845 assert(fancy_array[4].x == 4);
18461846 assert(fancy_array[4].y == 8);
18471847}
......@@ -8468,30 +8468,23 @@ test "integer truncation" {
84688468 <li>{#syntax#}@TypeOf(null){#endsyntax#}</li>
84698469 <li>{#link|Arrays#}</li>
84708470 <li>{#link|Optionals#}</li>
8471 <li>{#link|Error Set Type#}</li>
84718472 <li>{#link|Error Union Type#}</li>
84728473 <li>{#link|Vectors#}</li>
84738474 <li>{#link|Opaque Types#}</li>
8474 <li>AnyFrame</li>
8475 </ul>
8476 <p>
8477 For these types it is a
8478 <a href="https://github.com/ziglang/zig/issues/2907">TODO in the compiler to implement</a>:
8479 </p>
8480 <ul>
8481 <li>ErrorSet</li>
8482 <li>Enum</li>
8483 <li>FnFrame</li>
8484 <li>EnumLiteral</li>
8475 <li>{#link|@Frame#}</li>
8476 <li>{#syntax#}anyframe{#endsyntax#}</li>
8477 <li>{#link|struct#}</li>
8478 <li>{#link|enum#}</li>
8479 <li>{#link|Enum Literals#}</li>
8480 <li>{#link|union#}</li>
84858481 </ul>
84868482 <p>
8487 For these types, {#syntax#}@Type{#endsyntax#} is not available.
8488 <a href="https://github.com/ziglang/zig/issues/383">There is an open proposal to allow unions and structs</a>.
8483 For these types, {#syntax#}@Type{#endsyntax#} is not available:
84898484 </p>
84908485 <ul>
8491 <li>{#link|union#}</li>
84928486 <li>{#link|Functions#}</li>
84938487 <li>BoundFn</li>
8494 <li>{#link|struct#}</li>
84958488 </ul>
84968489 {#header_close#}
84978490 {#header_open|@typeInfo#}
lib/std/build.zig+23-1
......@@ -1165,6 +1165,11 @@ pub const FileSource = union(enum) {
11651165 }
11661166};
11671167
1168const BuildOptionArtifactArg = struct {
1169 name: []const u8,
1170 artifact: *LibExeObjStep,
1171};
1172
11681173pub const LibExeObjStep = struct {
11691174 step: Step,
11701175 builder: *Builder,
......@@ -1210,6 +1215,7 @@ pub const LibExeObjStep = struct {
12101215 out_pdb_filename: []const u8,
12111216 packages: ArrayList(Pkg),
12121217 build_options_contents: std.ArrayList(u8),
1218 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),
12131219 system_linker_hack: bool = false,
12141220
12151221 object_src: []const u8,
......@@ -1355,6 +1361,7 @@ pub const LibExeObjStep = struct {
13551361 .framework_dirs = ArrayList([]const u8).init(builder.allocator),
13561362 .object_src = undefined,
13571363 .build_options_contents = std.ArrayList(u8).init(builder.allocator),
1364 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),
13581365 .c_std = Builder.CStd.C99,
13591366 .override_lib_dir = null,
13601367 .main_pkg_path = null,
......@@ -1810,6 +1817,13 @@ pub const LibExeObjStep = struct {
18101817 out.print("pub const {} = {};\n", .{ name, value }) catch unreachable;
18111818 }
18121819
1820 /// The value is the path in the cache dir.
1821 /// Adds a dependency automatically.
1822 pub fn addBuildOptionArtifact(self: *LibExeObjStep, name: []const u8, artifact: *LibExeObjStep) void {
1823 self.build_options_artifact_args.append(.{ .name = name, .artifact = artifact }) catch unreachable;
1824 self.step.dependOn(&artifact.step);
1825 }
1826
18131827 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
18141828 self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable;
18151829 }
......@@ -2004,7 +2018,15 @@ pub const LibExeObjStep = struct {
20042018 }
20052019 }
20062020
2007 if (self.build_options_contents.items.len > 0) {
2021 if (self.build_options_contents.items.len > 0 or self.build_options_artifact_args.items.len > 0) {
2022 // Render build artifact options at the last minute, now that the path is known.
2023 for (self.build_options_artifact_args.items) |item| {
2024 const out = self.build_options_contents.writer();
2025 out.print("pub const {}: []const u8 = ", .{item.name}) catch unreachable;
2026 std.zig.renderStringLiteral(item.artifact.getOutputPath(), out) catch unreachable;
2027 out.writeAll(";\n") catch unreachable;
2028 }
2029
20082030 const build_options_file = try fs.path.join(
20092031 builder.allocator,
20102032 &[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },
lib/std/crypto.zig+25-6
......@@ -35,12 +35,23 @@ pub const onetimeauth = struct {
3535 pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
3636};
3737
38/// A Key Derivation Function (KDF) is intended to turn a weak, human generated password into a
39/// strong key, suitable for cryptographic uses. It does this by salting and stretching the
40/// password. Salting injects non-secret random data, so that identical passwords will be converted
41/// into unique keys. Stretching applies a deliberately slow hashing function to frustrate
42/// brute-force guessing.
43pub const kdf = struct {
38/// A password hashing function derives a uniform key from low-entropy input material such as passwords.
39/// It is intentionally slow or expensive.
40///
41/// With the standard definition of a key derivation function, if a key space is small, an exhaustive search may be practical.
42/// Password hashing functions make exhaustive searches way slower or way more expensive, even when implemented on GPUs and ASICs, by using different, optionally combined strategies:
43///
44/// - Requiring a lot of computation cycles to complete
45/// - Requiring a lot of memory to complete
46/// - Requiring multiple CPU cores to complete
47/// - Requiring cache-local data to complete in reasonable time
48/// - Requiring large static tables
49/// - Avoiding precomputations and time/memory tradeoffs
50/// - Requiring multi-party computations
51/// - Combining the input material with random per-entry data (salts), application-specific contexts and keys
52///
53/// Password hashing functions must be used whenever sensitive data has to be directly derived from a password.
54pub const pwhash = struct {
4455 pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
4556};
4657
......@@ -48,6 +59,13 @@ pub const kdf = struct {
4859pub const core = struct {
4960 pub const aes = @import("crypto/aes.zig");
5061 pub const Gimli = @import("crypto/gimli.zig").State;
62
63 /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
64 ///
65 /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
66 ///
67 /// Most applications may want to use AEADs instead.
68 pub const modes = @import("crypto/modes.zig");
5169};
5270
5371/// Elliptic-curve arithmetic.
......@@ -100,6 +118,7 @@ test "crypto" {
100118 _ = @import("crypto/gimli.zig");
101119 _ = @import("crypto/hmac.zig");
102120 _ = @import("crypto/md5.zig");
121 _ = @import("crypto/modes.zig");
103122 _ = @import("crypto/pbkdf2.zig");
104123 _ = @import("crypto/poly1305.zig");
105124 _ = @import("crypto/sha1.zig");
lib/std/crypto/aes.zig+72-638
......@@ -3,249 +3,44 @@
33// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
6// Based on Go stdlib implementation
76
87const std = @import("../std.zig");
9const mem = std.mem;
108const testing = std.testing;
9const builtin = std.builtin;
1110
12// Apply sbox0 to each byte in w.
13fn subw(w: u32) u32 {
14 return @as(u32, sbox0[w >> 24]) << 24 | @as(u32, sbox0[w >> 16 & 0xff]) << 16 | @as(u32, sbox0[w >> 8 & 0xff]) << 8 | @as(u32, sbox0[w & 0xff]);
15}
16
17fn rotw(w: u32) u32 {
18 return w << 8 | w >> 24;
19}
20
21// Encrypt one block from src into dst, using the expanded key xk.
22fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
23 var s0 = mem.readIntBig(u32, src[0..4]);
24 var s1 = mem.readIntBig(u32, src[4..8]);
25 var s2 = mem.readIntBig(u32, src[8..12]);
26 var s3 = mem.readIntBig(u32, src[12..16]);
27
28 // First round just XORs input with key.
29 s0 ^= xk[0];
30 s1 ^= xk[1];
31 s2 ^= xk[2];
32 s3 ^= xk[3];
33
34 // Middle rounds shuffle using tables.
35 // Number of rounds is set by length of expanded key.
36 var nr = xk.len / 4 - 2; // - 2: one above, one more below
37 var k: usize = 4;
38 var t0: u32 = undefined;
39 var t1: u32 = undefined;
40 var t2: u32 = undefined;
41 var t3: u32 = undefined;
42 var r: usize = 0;
43 while (r < nr) : (r += 1) {
44 t0 = xk[k + 0] ^ te0[@truncate(u8, s0 >> 24)] ^ te1[@truncate(u8, s1 >> 16)] ^ te2[@truncate(u8, s2 >> 8)] ^ te3[@truncate(u8, s3)];
45 t1 = xk[k + 1] ^ te0[@truncate(u8, s1 >> 24)] ^ te1[@truncate(u8, s2 >> 16)] ^ te2[@truncate(u8, s3 >> 8)] ^ te3[@truncate(u8, s0)];
46 t2 = xk[k + 2] ^ te0[@truncate(u8, s2 >> 24)] ^ te1[@truncate(u8, s3 >> 16)] ^ te2[@truncate(u8, s0 >> 8)] ^ te3[@truncate(u8, s1)];
47 t3 = xk[k + 3] ^ te0[@truncate(u8, s3 >> 24)] ^ te1[@truncate(u8, s0 >> 16)] ^ te2[@truncate(u8, s1 >> 8)] ^ te3[@truncate(u8, s2)];
48 k += 4;
49 s0 = t0;
50 s1 = t1;
51 s2 = t2;
52 s3 = t3;
53 }
54
55 // Last round uses s-box directly and XORs to produce output.
56 s0 = @as(u32, sbox0[t0 >> 24]) << 24 | @as(u32, sbox0[t1 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t2 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t3 & 0xff]);
57 s1 = @as(u32, sbox0[t1 >> 24]) << 24 | @as(u32, sbox0[t2 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t3 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t0 & 0xff]);
58 s2 = @as(u32, sbox0[t2 >> 24]) << 24 | @as(u32, sbox0[t3 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t0 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t1 & 0xff]);
59 s3 = @as(u32, sbox0[t3 >> 24]) << 24 | @as(u32, sbox0[t0 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t1 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t2 & 0xff]);
60
61 s0 ^= xk[k + 0];
62 s1 ^= xk[k + 1];
63 s2 ^= xk[k + 2];
64 s3 ^= xk[k + 3];
65
66 mem.writeIntBig(u32, dst[0..4], s0);
67 mem.writeIntBig(u32, dst[4..8], s1);
68 mem.writeIntBig(u32, dst[8..12], s2);
69 mem.writeIntBig(u32, dst[12..16], s3);
70}
71
72// Decrypt one block from src into dst, using the expanded key xk.
73pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
74 var s0 = mem.readIntBig(u32, src[0..4]);
75 var s1 = mem.readIntBig(u32, src[4..8]);
76 var s2 = mem.readIntBig(u32, src[8..12]);
77 var s3 = mem.readIntBig(u32, src[12..16]);
78
79 // First round just XORs input with key.
80 s0 ^= xk[0];
81 s1 ^= xk[1];
82 s2 ^= xk[2];
83 s3 ^= xk[3];
84
85 // Middle rounds shuffle using tables.
86 // Number of rounds is set by length of expanded key.
87 var nr = xk.len / 4 - 2; // - 2: one above, one more below
88 var k: usize = 4;
89 var t0: u32 = undefined;
90 var t1: u32 = undefined;
91 var t2: u32 = undefined;
92 var t3: u32 = undefined;
93 var r: usize = 0;
94 while (r < nr) : (r += 1) {
95 t0 = xk[k + 0] ^ td0[@truncate(u8, s0 >> 24)] ^ td1[@truncate(u8, s3 >> 16)] ^ td2[@truncate(u8, s2 >> 8)] ^ td3[@truncate(u8, s1)];
96 t1 = xk[k + 1] ^ td0[@truncate(u8, s1 >> 24)] ^ td1[@truncate(u8, s0 >> 16)] ^ td2[@truncate(u8, s3 >> 8)] ^ td3[@truncate(u8, s2)];
97 t2 = xk[k + 2] ^ td0[@truncate(u8, s2 >> 24)] ^ td1[@truncate(u8, s1 >> 16)] ^ td2[@truncate(u8, s0 >> 8)] ^ td3[@truncate(u8, s3)];
98 t3 = xk[k + 3] ^ td0[@truncate(u8, s3 >> 24)] ^ td1[@truncate(u8, s2 >> 16)] ^ td2[@truncate(u8, s1 >> 8)] ^ td3[@truncate(u8, s0)];
99 k += 4;
100 s0 = t0;
101 s1 = t1;
102 s2 = t2;
103 s3 = t3;
104 }
105
106 // Last round uses s-box directly and XORs to produce output.
107 s0 = @as(u32, sbox1[t0 >> 24]) << 24 | @as(u32, sbox1[t3 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t2 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t1 & 0xff]);
108 s1 = @as(u32, sbox1[t1 >> 24]) << 24 | @as(u32, sbox1[t0 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t3 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t2 & 0xff]);
109 s2 = @as(u32, sbox1[t2 >> 24]) << 24 | @as(u32, sbox1[t1 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t0 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t3 & 0xff]);
110 s3 = @as(u32, sbox1[t3 >> 24]) << 24 | @as(u32, sbox1[t2 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t1 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t0 & 0xff]);
111
112 s0 ^= xk[k + 0];
113 s1 ^= xk[k + 1];
114 s2 ^= xk[k + 2];
115 s3 ^= xk[k + 3];
116
117 mem.writeIntBig(u32, dst[0..4], s0);
118 mem.writeIntBig(u32, dst[4..8], s1);
119 mem.writeIntBig(u32, dst[8..12], s2);
120 mem.writeIntBig(u32, dst[12..16], s3);
121}
122
123fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {
124 var n = std.math.min(dst.len, std.math.min(a.len, b.len));
125 for (dst[0..n]) |_, i| {
126 dst[i] = a[i] ^ b[i];
127 }
128 return n;
129}
130
131pub const AES128 = AES(128);
132pub const AES256 = AES(256);
133
134fn AES(comptime keysize: usize) type {
135 return struct {
136 const Self = @This();
137
138 pub const Encrypt = AESEncrypt(keysize);
139 pub const Decrypt = AESDecrypt(keysize);
140
141 const nn = (keysize / 8) + 28;
142 enc: Encrypt,
143 dec: Decrypt,
144
145 pub fn init(key: [keysize / 8]u8) Self {
146 var ctx: Self = undefined;
147 ctx.enc = Encrypt.init(key);
148 ctx.dec = ctx.enc.toDecrypt();
149 return ctx;
150 }
11const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes);
12const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
13const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) @import("aes/aesni.zig") else @import("aes/soft.zig");
15114
152 pub fn encrypt(ctx: Self, dst: []u8, src: []const u8) void {
153 ctx.enc.encrypt(dst, src);
154 }
155 pub fn decrypt(ctx: Self, dst: []u8, src: []const u8) void {
156 ctx.dec.decrypt(dst, src);
157 }
158 pub fn ctr(ctx: Self, dst: []u8, src: []const u8, iv: [16]u8) void {
159 ctx.enc.ctr(dst, src, iv);
160 }
161 };
162}
163
164fn AESEncrypt(comptime keysize: usize) type {
165 return struct {
166 const Self = @This();
167
168 const Decrypt = AESDecrypt(keysize);
169
170 const nn = (keysize / 8) + 28;
171 enc: [nn]u32,
15pub const Block = impl.Block;
16pub const AESEncryptCtx = impl.AESEncryptCtx;
17pub const AESDecryptCtx = impl.AESDecryptCtx;
18pub const AES128 = impl.AES128;
19pub const AES256 = impl.AES256;
17220
173 pub fn init(key: [keysize / 8]u8) Self {
174 var ctx: Self = undefined;
175 expandKeyEncrypt(&key, ctx.enc[0..]);
176 return ctx;
177 }
178
179 pub fn toDecrypt(ctx: Self) Decrypt {
180 var dec: Decrypt = undefined;
181 expandKeyDecrypt(ctx.enc[0..], dec.dec[0..]);
182 return dec;
183 }
184
185 pub fn encrypt(ctx: Self, dst: []u8, src: []const u8) void {
186 encryptBlock(ctx.enc[0..], dst, src);
187 }
188 pub fn ctr(ctx: Self, dst: []u8, src: []const u8, iv: [16]u8) void {
189 std.debug.assert(dst.len >= src.len);
190
191 var keystream: [16]u8 = undefined;
192 var ctrbuf = iv;
193 var n: usize = 0;
194 while (n < src.len) {
195 ctx.encrypt(keystream[0..], ctrbuf[0..]);
196 var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]);
197 std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1);
21test "ctr" {
22 // NIST SP 800-38A pp 55-58
23 const ctr = @import("modes.zig").ctr;
19824
199 n += xorBytes(dst[n..], src[n..], &keystream);
200 }
201 }
25 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
26 const iv = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
27 const in = [_]u8{
28 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
29 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
30 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
31 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
20232 };
203}
204
205fn AESDecrypt(comptime keysize: usize) type {
206 return struct {
207 const Self = @This();
208
209 const nn = (keysize / 8) + 28;
210 dec: [nn]u32,
211
212 pub fn init(key: [keysize / 8]u8) Self {
213 var ctx: Self = undefined;
214 var enc: [nn]u32 = undefined;
215 expandKeyEncrypt(key[0..], enc[0..]);
216 expandKeyDecrypt(enc[0..], ctx.dec[0..]);
217 return ctx;
218 }
219
220 pub fn decrypt(ctx: Self, dst: []u8, src: []const u8) void {
221 decryptBlock(ctx.dec[0..], dst, src);
222 }
33 const exp_out = [_]u8{
34 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
35 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
36 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
37 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
22338 };
224}
225
226test "ctr" {
227 // NIST SP 800-38A pp 55-58
228 {
229 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
230 const iv = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
231 const in = [_]u8{
232 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
233 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
234 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
235 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
236 };
237 const exp_out = [_]u8{
238 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
239 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
240 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
241 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
242 };
24339
244 var out: [exp_out.len]u8 = undefined;
245 var aes = AES128.init(key);
246 aes.ctr(out[0..], in[0..], iv);
247 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
248 }
40 var out: [exp_out.len]u8 = undefined;
41 var ctx = AES128.initEnc(key);
42 ctr(AESEncryptCtx(AES128), ctx, out[0..], in[0..], iv, builtin.Endian.Big);
43 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
24944}
25045
25146test "encrypt" {
......@@ -256,8 +51,8 @@ test "encrypt" {
25651 const exp_out = [_]u8{ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
25752
25853 var out: [exp_out.len]u8 = undefined;
259 var aes = AES128.init(key);
260 aes.encrypt(out[0..], in[0..]);
54 var ctx = AES128.initEnc(key);
55 ctx.encrypt(out[0..], in[0..]);
26156 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
26257 }
26358
......@@ -271,8 +66,8 @@ test "encrypt" {
27166 const exp_out = [_]u8{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
27267
27368 var out: [exp_out.len]u8 = undefined;
274 var aes = AES256.init(key);
275 aes.encrypt(out[0..], in[0..]);
69 var ctx = AES256.initEnc(key);
70 ctx.encrypt(out[0..], in[0..]);
27671 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
27772 }
27873}
......@@ -285,8 +80,8 @@ test "decrypt" {
28580 const exp_out = [_]u8{ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
28681
28782 var out: [exp_out.len]u8 = undefined;
288 var aes = AES128.init(key);
289 aes.decrypt(out[0..], in[0..]);
83 var ctx = AES128.initDec(key);
84 ctx.decrypt(out[0..], in[0..]);
29085 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
29186 }
29287
......@@ -300,413 +95,52 @@ test "decrypt" {
30095 const exp_out = [_]u8{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
30196
30297 var out: [exp_out.len]u8 = undefined;
303 var aes = AES256.init(key);
304 aes.decrypt(out[0..], in[0..]);
98 var ctx = AES256.initDec(key);
99 ctx.decrypt(out[0..], in[0..]);
305100 testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
306101 }
307102}
308103
309// Key expansion algorithm. See FIPS-197, Figure 11.
310fn expandKeyEncrypt(key: []const u8, enc: []u32) void {
311 var i: usize = 0;
312 var nk = key.len / 4;
313 while (i < nk) : (i += 1) {
314 enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]);
315 }
316 while (i < enc.len) : (i += 1) {
317 var t = enc[i - 1];
318 if (i % nk == 0) {
319 t = subw(rotw(t)) ^ (@as(u32, powx[i / nk - 1]) << 24);
320 } else if (nk > 6 and i % nk == 4) {
321 t = subw(t);
322 }
323 enc[i] = enc[i - nk] ^ t;
324 }
325}
104test "expand 128-bit key" {
105 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
106 const exp_enc = [_]*const [32:0]u8{
107 "2b7e151628aed2a6abf7158809cf4f3c", "a0fafe1788542cb123a339392a6c7605", "f2c295f27a96b9435935807a7359f67f", "3d80477d4716fe3e1e237e446d7a883b", "ef44a541a8525b7fb671253bdb0bad00", "d4d1c6f87c839d87caf2b8bc11f915bc", "6d88a37a110b3efddbf98641ca0093fd", "4e54f70e5f5fc9f384a64fb24ea6dc4f", "ead27321b58dbad2312bf5607f8d292f", "ac7766f319fadc2128d12941575c006e", "d014f9a8c9ee2589e13f0cc8b6630ca6",
108 };
109 const exp_dec = [_]*const [32:0]u8{
110 "2b7e151628aed2a6abf7158809cf4f3c", "a0fafe1788542cb123a339392a6c7605", "f2c295f27a96b9435935807a7359f67f", "3d80477d4716fe3e1e237e446d7a883b", "ef44a541a8525b7fb671253bdb0bad00", "d4d1c6f87c839d87caf2b8bc11f915bc", "6d88a37a110b3efddbf98641ca0093fd", "4e54f70e5f5fc9f384a64fb24ea6dc4f", "ead27321b58dbad2312bf5607f8d292f", "ac7766f319fadc2128d12941575c006e", "d014f9a8c9ee2589e13f0cc8b6630ca6",
111 };
112 const enc = AES128.initEnc(key);
113 const dec = AES128.initDec(key);
114 var exp: [16]u8 = undefined;
326115
327fn expandKeyDecrypt(enc: []const u32, dec: []u32) void {
328 var i: usize = 0;
329 var n = enc.len;
330 while (i < n) : (i += 4) {
331 var ei = n - i - 4;
332 var j: usize = 0;
333 while (j < 4) : (j += 1) {
334 var x = enc[ei + j];
335 if (i > 0 and i + 4 < n) {
336 x = td0[sbox0[x >> 24]] ^ td1[sbox0[x >> 16 & 0xff]] ^ td2[sbox0[x >> 8 & 0xff]] ^ td3[sbox0[x & 0xff]];
337 }
338 dec[i + j] = x;
339 }
116 for (enc.key_schedule.round_keys) |round_key, i| {
117 try std.fmt.hexToBytes(&exp, exp_enc[i]);
118 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
119 }
120 for (enc.key_schedule.round_keys) |round_key, i| {
121 try std.fmt.hexToBytes(&exp, exp_dec[i]);
122 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
340123 }
341124}
342125
343test "expand key" {
344 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
345 const exp_enc = [_]u32{
346 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
347 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
348 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
349 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
350 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
351 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
352 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
353 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
354 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
355 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
356 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
126test "expand 256-bit key" {
127 const key = [_]u8{ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 };
128 const exp_enc = [_]*const [32:0]u8{
129 "603deb1015ca71be2b73aef0857d7781", "1f352c073b6108d72d9810a30914dff4", "9ba354118e6925afa51a8b5f2067fcde", "a8b09c1a93d194cdbe49846eb75d5b9a", "d59aecb85bf3c917fee94248de8ebe96", "b5a9328a2678a647983122292f6c79b3", "812c81addadf48ba24360af2fab8b464", "98c5bfc9bebd198e268c3ba709e04214", "68007bacb2df331696e939e46c518d80", "c814e20476a9fb8a5025c02d59c58239", "de1369676ccc5a71fa2563959674ee15", "5886ca5d2e2f31d77e0af1fa27cf73c3", "749c47ab18501ddae2757e4f7401905a", "cafaaae3e4d59b349adf6acebd10190d", "fe4890d1e6188d0b046df344706c631e",
357130 };
358 const exp_dec = [_]u32{
359 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
360 0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
361 0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
362 0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
363 0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
364 0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
365 0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
366 0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
367 0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
368 0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
369 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
131 const exp_dec = [_]*const [32:0]u8{
132 "fe4890d1e6188d0b046df344706c631e", "ada23f4963e23b2455427c8a5c709104", "57c96cf6074f07c0706abb07137f9241", "b668b621ce40046d36a047ae0932ed8e", "34ad1e4450866b367725bcc763152946", "32526c367828b24cf8e043c33f92aa20", "c440b289642b757227a3d7f114309581", "d669a7334a7ade7a80c8f18fc772e9e3", "25ba3c22a06bc7fb4388a28333934270", "54fb808b9c137949cab22ff547ba186c", "6c3d632985d1fbd9e3e36578701be0f3", "4a7459f9c8e8f9c256a156bc8d083799", "42107758e9ec98f066329ea193f8858b", "8ec6bff6829ca03b9e49af7edba96125", "603deb1015ca71be2b73aef0857d7781",
370133 };
371 var enc: [exp_enc.len]u32 = undefined;
372 var dec: [exp_dec.len]u32 = undefined;
373 expandKeyEncrypt(key[0..], enc[0..]);
374 expandKeyDecrypt(enc[0..], dec[0..]);
375 testing.expectEqualSlices(u32, exp_enc[0..], enc[0..]);
376 testing.expectEqualSlices(u32, exp_dec[0..], dec[0..]);
377}
134 const enc = AES256.initEnc(key);
135 const dec = AES256.initDec(key);
136 var exp: [16]u8 = undefined;
378137
379// constants
380
381const poly = 1 << 8 | 1 << 4 | 1 << 3 | 1 << 1 | 1 << 0;
382
383const powx = [16]u8{
384 0x01,
385 0x02,
386 0x04,
387 0x08,
388 0x10,
389 0x20,
390 0x40,
391 0x80,
392 0x1b,
393 0x36,
394 0x6c,
395 0xd8,
396 0xab,
397 0x4d,
398 0x9a,
399 0x2f,
400};
401
402const sbox0 = [256]u8{
403 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
404 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
405 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
406 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
407 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
408 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
409 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
410 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
411 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
412 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
413 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
414 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
415 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
416 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
417 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
418 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
419};
420
421const sbox1 = [256]u8{
422 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
423 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
424 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
425 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
426 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
427 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
428 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
429 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
430 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
431 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
432 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
433 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
434 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
435 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
436 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
437 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
438};
439
440const te0 = [256]u32{
441 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
442 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
443 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
444 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
445 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
446 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
447 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
448 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
449 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
450 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
451 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
452 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
453 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
454 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
455 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
456 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
457 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
458 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
459 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
460 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
461 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
462 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
463 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
464 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
465 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
466 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
467 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
468 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
469 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
470 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
471 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
472 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
473};
474const te1 = [256]u32{
475 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
476 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
477 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
478 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
479 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
480 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
481 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
482 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
483 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
484 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
485 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
486 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
487 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
488 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
489 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
490 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
491 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
492 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
493 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
494 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
495 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
496 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
497 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
498 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
499 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
500 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
501 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
502 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
503 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
504 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
505 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
506 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
507};
508const te2 = [256]u32{
509 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
510 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
511 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
512 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
513 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
514 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
515 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
516 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
517 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
518 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
519 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
520 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
521 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
522 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
523 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
524 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
525 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
526 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
527 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
528 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
529 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
530 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
531 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
532 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
533 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
534 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
535 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
536 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
537 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
538 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
539 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
540 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
541};
542const te3 = [256]u32{
543 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
544 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
545 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
546 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
547 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
548 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
549 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
550 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
551 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
552 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
553 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
554 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
555 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
556 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
557 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
558 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
559 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
560 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
561 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
562 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
563 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
564 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
565 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
566 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
567 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
568 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
569 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
570 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
571 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
572 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
573 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
574 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
575};
576
577const td0 = [256]u32{
578 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
579 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
580 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
581 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
582 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
583 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
584 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
585 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
586 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
587 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
588 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
589 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
590 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
591 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
592 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
593 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
594 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
595 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
596 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
597 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
598 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
599 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
600 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
601 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
602 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
603 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
604 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
605 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
606 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
607 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
608 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
609 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
610};
611const td1 = [256]u32{
612 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
613 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
614 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
615 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
616 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
617 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
618 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
619 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
620 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
621 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
622 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
623 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
624 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
625 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
626 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
627 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
628 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
629 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
630 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
631 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
632 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
633 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
634 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
635 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
636 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
637 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
638 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
639 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
640 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
641 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
642 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
643 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
644};
645const td2 = [256]u32{
646 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
647 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
648 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
649 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
650 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
651 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
652 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
653 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
654 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
655 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
656 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
657 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
658 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
659 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
660 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
661 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
662 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
663 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
664 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
665 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
666 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
667 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
668 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
669 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
670 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
671 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
672 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
673 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
674 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
675 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
676 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
677 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
678};
679const td3 = [256]u32{
680 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
681 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
682 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
683 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
684 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
685 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
686 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
687 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
688 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
689 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
690 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
691 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
692 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
693 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
694 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
695 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
696 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
697 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
698 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
699 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
700 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
701 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
702 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
703 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
704 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
705 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
706 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
707 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
708 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
709 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
710 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
711 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
712};
138 for (enc.key_schedule.round_keys) |round_key, i| {
139 try std.fmt.hexToBytes(&exp, exp_enc[i]);
140 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
141 }
142 for (dec.key_schedule.round_keys) |round_key, i| {
143 try std.fmt.hexToBytes(&exp, exp_dec[i]);
144 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
145 }
146}
lib/std/crypto/aes/aesni.zig created+420
......@@ -0,0 +1,420 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6// Based on Go stdlib implementation
7
8const std = @import("../../std.zig");
9const mem = std.mem;
10const debug = std.debug;
11const Vector = std.meta.Vector;
12
13const BlockVec = Vector(2, u64);
14
15/// A single AES block.
16pub const Block = struct {
17 pub const block_size: usize = 16;
18
19 /// Internal representation of a block.
20 repr: BlockVec,
21
22 /// Convert a byte sequence into an internal representation.
23 pub inline fn fromBytes(bytes: *const [16]u8) Block {
24 const repr = mem.bytesToValue(BlockVec, bytes);
25 return Block{ .repr = repr };
26 }
27
28 /// Convert the internal representation of a block into a byte sequence.
29 pub inline fn toBytes(block: Block) [16]u8 {
30 return mem.toBytes(block.repr);
31 }
32
33 /// XOR the block with a byte sequence.
34 pub inline fn xorBytes(block: Block, bytes: *const [16]u8) [16]u8 {
35 const x = block.repr ^ fromBytes(bytes).repr;
36 return mem.toBytes(x);
37 }
38
39 /// Encrypt a block with a round key.
40 pub inline fn encrypt(block: Block, round_key: Block) Block {
41 return Block{
42 .repr = asm (
43 \\ vaesenc %[rk], %[in], %[out]
44 : [out] "=x" (-> BlockVec)
45 : [in] "x" (block.repr),
46 [rk] "x" (round_key.repr)
47 ),
48 };
49 }
50
51 /// Encrypt a block with the last round key.
52 pub inline fn encryptLast(block: Block, round_key: Block) Block {
53 return Block{
54 .repr = asm (
55 \\ vaesenclast %[rk], %[in], %[out]
56 : [out] "=x" (-> BlockVec)
57 : [in] "x" (block.repr),
58 [rk] "x" (round_key.repr)
59 ),
60 };
61 }
62
63 /// Decrypt a block with a round key.
64 pub inline fn decrypt(block: Block, inv_round_key: Block) Block {
65 return Block{
66 .repr = asm (
67 \\ vaesdec %[rk], %[in], %[out]
68 : [out] "=x" (-> BlockVec)
69 : [in] "x" (block.repr),
70 [rk] "x" (inv_round_key.repr)
71 ),
72 };
73 }
74
75 /// Decrypt a block with the last round key.
76 pub inline fn decryptLast(block: Block, inv_round_key: Block) Block {
77 return Block{
78 .repr = asm (
79 \\ vaesdeclast %[rk], %[in], %[out]
80 : [out] "=x" (-> BlockVec)
81 : [in] "x" (block.repr),
82 [rk] "x" (inv_round_key.repr)
83 ),
84 };
85 }
86
87 /// XOR the content of two blocks.
88 pub inline fn xor(block1: Block, block2: Block) Block {
89 return Block{ .repr = block1.repr ^ block2.repr };
90 }
91
92 /// Perform operations on multiple blocks in parallel.
93 pub const parallel = struct {
94 /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation.
95 pub const optimal_parallel_blocks = 8;
96
97 /// Encrypt multiple blocks in parallel, each their own round key.
98 pub inline fn encryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
99 comptime var i = 0;
100 var out: [count]Block = undefined;
101 inline while (i < count) : (i += 1) {
102 out[i] = blocks[i].encrypt(round_keys[i]);
103 }
104 return out;
105 }
106
107 /// Decrypt multiple blocks in parallel, each their own round key.
108 pub inline fn decryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
109 comptime var i = 0;
110 var out: [count]Block = undefined;
111 inline while (i < count) : (i += 1) {
112 out[i] = blocks[i].decrypt(round_keys[i]);
113 }
114 return out;
115 }
116
117 /// Encrypt multple blocks in parallel with the same round key.
118 pub inline fn encryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
119 comptime var i = 0;
120 var out: [count]Block = undefined;
121 inline while (i < count) : (i += 1) {
122 out[i] = blocks[i].encrypt(round_key);
123 }
124 return out;
125 }
126
127 /// Decrypt multple blocks in parallel with the same round key.
128 pub inline fn decryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
129 comptime var i = 0;
130 var out: [count]Block = undefined;
131 inline while (i < count) : (i += 1) {
132 out[i] = blocks[i].decrypt(round_key);
133 }
134 return out;
135 }
136
137 /// Encrypt multple blocks in parallel with the same last round key.
138 pub inline fn encryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
139 comptime var i = 0;
140 var out: [count]Block = undefined;
141 inline while (i < count) : (i += 1) {
142 out[i] = blocks[i].encryptLast(round_key);
143 }
144 return out;
145 }
146
147 /// Decrypt multple blocks in parallel with the same last round key.
148 pub inline fn decryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
149 comptime var i = 0;
150 var out: [count]Block = undefined;
151 inline while (i < count) : (i += 1) {
152 out[i] = blocks[i].decryptLast(round_key);
153 }
154 return out;
155 }
156 };
157};
158
159fn KeySchedule(comptime AES: type) type {
160 std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
161 const rounds = AES.rounds;
162
163 return struct {
164 const Self = @This();
165 round_keys: [rounds + 1]Block,
166
167 fn drc(comptime second: bool, comptime rc: u8, t: BlockVec, tx: BlockVec) BlockVec {
168 var s: BlockVec = undefined;
169 var ts: BlockVec = undefined;
170 return asm (
171 \\ vaeskeygenassist %[rc], %[t], %[s]
172 \\ vpslldq $4, %[tx], %[ts]
173 \\ vpxor %[ts], %[tx], %[r]
174 \\ vpslldq $8, %[r], %[ts]
175 \\ vpxor %[ts], %[r], %[r]
176 \\ vpshufd %[mask], %[s], %[ts]
177 \\ vpxor %[ts], %[r], %[r]
178 : [r] "=&x" (-> BlockVec),
179 [s] "=&x" (s),
180 [ts] "=&x" (ts)
181 : [rc] "n" (rc),
182 [t] "x" (t),
183 [tx] "x" (tx),
184 [mask] "n" (@as(u8, if (second) 0xaa else 0xff))
185 );
186 }
187
188 fn expand128(t1: *Block) Self {
189 var round_keys: [11]Block = undefined;
190 const rcs = [_]u8{ 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
191 inline for (rcs) |rc, round| {
192 round_keys[round] = t1.*;
193 t1.repr = drc(false, rc, t1.repr, t1.repr);
194 }
195 round_keys[rcs.len] = t1.*;
196 return Self{ .round_keys = round_keys };
197 }
198
199 fn expand256(t1: *Block, t2: *Block) Self {
200 var round_keys: [15]Block = undefined;
201 const rcs = [_]u8{ 1, 2, 4, 8, 16, 32 };
202 round_keys[0] = t1.*;
203 inline for (rcs) |rc, round| {
204 round_keys[round * 2 + 1] = t2.*;
205 t1.repr = drc(false, rc, t2.repr, t1.repr);
206 round_keys[round * 2 + 2] = t1.*;
207 t2.repr = drc(true, rc, t1.repr, t2.repr);
208 }
209 round_keys[rcs.len * 2 + 1] = t2.*;
210 t1.repr = drc(false, 64, t2.repr, t1.repr);
211 round_keys[rcs.len * 2 + 2] = t1.*;
212 return Self{ .round_keys = round_keys };
213 }
214
215 /// Invert the key schedule.
216 pub fn invert(key_schedule: Self) Self {
217 const round_keys = &key_schedule.round_keys;
218 var inv_round_keys: [rounds + 1]Block = undefined;
219 inv_round_keys[0] = round_keys[rounds];
220 comptime var i = 1;
221 inline while (i < rounds) : (i += 1) {
222 inv_round_keys[i] = Block{
223 .repr = asm (
224 \\ vaesimc %[rk], %[inv_rk]
225 : [inv_rk] "=x" (-> BlockVec)
226 : [rk] "x" (round_keys[rounds - i].repr)
227 ),
228 };
229 }
230 inv_round_keys[rounds] = round_keys[0];
231 return Self{ .round_keys = inv_round_keys };
232 }
233 };
234}
235
236/// A context to perform encryption using the standard AES key schedule.
237pub fn AESEncryptCtx(comptime AES: type) type {
238 std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
239 const rounds = AES.rounds;
240
241 return struct {
242 const Self = @This();
243 pub const block = AES.block;
244 pub const block_size = block.block_size;
245 key_schedule: KeySchedule(AES),
246
247 /// Create a new encryption context with the given key.
248 pub fn init(key: [AES.key_bits / 8]u8) Self {
249 var t1 = Block.fromBytes(key[0..16]);
250 const key_schedule = if (AES.key_bits == 128) ks: {
251 break :ks KeySchedule(AES).expand128(&t1);
252 } else ks: {
253 var t2 = Block.fromBytes(key[16..32]);
254 break :ks KeySchedule(AES).expand256(&t1, &t2);
255 };
256 return Self{
257 .key_schedule = key_schedule,
258 };
259 }
260
261 /// Encrypt a single block.
262 pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
263 const round_keys = ctx.key_schedule.round_keys;
264 var t = Block.fromBytes(src).xor(round_keys[0]);
265 comptime var i = 1;
266 inline while (i < rounds) : (i += 1) {
267 t = t.encrypt(round_keys[i]);
268 }
269 t = t.encryptLast(round_keys[rounds]);
270 dst.* = t.toBytes();
271 }
272
273 /// Encrypt+XOR a single block.
274 pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void {
275 const round_keys = ctx.key_schedule.round_keys;
276 var t = Block.fromBytes(&counter).xor(round_keys[0]);
277 comptime var i = 1;
278 inline while (i < rounds) : (i += 1) {
279 t = t.encrypt(round_keys[i]);
280 }
281 t = t.encryptLast(round_keys[rounds]);
282 dst.* = t.xorBytes(src);
283 }
284
285 /// Encrypt multiple blocks, possibly leveraging parallelization.
286 pub fn encryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
287 const round_keys = ctx.key_schedule.round_keys;
288 var ts: [count]Block = undefined;
289 comptime var j = 0;
290 inline while (j < count) : (j += 1) {
291 ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xor(round_keys[0]);
292 }
293 comptime var i = 1;
294 inline while (i < rounds) : (i += 1) {
295 ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
296 }
297 i = 1;
298 inline while (i < count) : (i += 1) {
299 ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
300 }
301 j = 0;
302 inline while (j < count) : (j += 1) {
303 dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
304 }
305 }
306
307 /// Encrypt+XOR multiple blocks, possibly leveraging parallelization.
308 pub fn xorWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8, counters: [16 * count]u8) void {
309 const round_keys = ctx.key_schedule.round_keys;
310 var ts: [count]Block = undefined;
311 comptime var j = 0;
312 inline while (j < count) : (j += 1) {
313 ts[j] = Block.fromBytes(counters[j * 16 .. j * 16 + 16][0..16]).xor(round_keys[0]);
314 }
315 comptime var i = 1;
316 inline while (i < rounds) : (i += 1) {
317 ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
318 }
319 ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
320 j = 0;
321 inline while (j < count) : (j += 1) {
322 dst[16 * j .. 16 * j + 16].* = ts[j].xorBytes(src[16 * j .. 16 * j + 16]);
323 }
324 }
325 };
326}
327
328/// A context to perform decryption using the standard AES key schedule.
329pub fn AESDecryptCtx(comptime AES: type) type {
330 std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
331 const rounds = AES.rounds;
332
333 return struct {
334 const Self = @This();
335 pub const block = AES.block;
336 pub const block_size = block.block_size;
337 key_schedule: KeySchedule(AES),
338
339 /// Create a decryption context from an existing encryption context.
340 pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
341 return Self{
342 .key_schedule = ctx.key_schedule.invert(),
343 };
344 }
345
346 /// Create a new decryption context with the given key.
347 pub fn init(key: [AES.key_bits / 8]u8) Self {
348 const enc_ctx = AESEncryptCtx(AES).init(key);
349 return initFromEnc(enc_ctx);
350 }
351
352 /// Decrypt a single block.
353 pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
354 const inv_round_keys = ctx.key_schedule.round_keys;
355 var t = Block.fromBytes(src).xor(inv_round_keys[0]);
356 comptime var i = 1;
357 inline while (i < rounds) : (i += 1) {
358 t = t.decrypt(inv_round_keys[i]);
359 }
360 t = t.decryptLast(inv_round_keys[rounds]);
361 dst.* = t.toBytes();
362 }
363
364 /// Decrypt multiple blocks, possibly leveraging parallelization.
365 pub fn decryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
366 const inv_round_keys = ctx.key_schedule.round_keys;
367 var ts: [count]Block = undefined;
368 comptime var j = 0;
369 inline while (j < count) : (j += 1) {
370 ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xor(inv_round_keys[0]);
371 }
372 comptime var i = 1;
373 inline while (i < rounds) : (i += 1) {
374 ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]);
375 }
376 i = 1;
377 inline while (i < count) : (i += 1) {
378 ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
379 }
380 j = 0;
381 inline while (j < count) : (j += 1) {
382 dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
383 }
384 }
385 };
386}
387
388/// AES-128 with the standard key schedule.
389pub const AES128 = struct {
390 pub const key_bits: usize = 128;
391 pub const rounds = ((key_bits - 64) / 32 + 8);
392 pub const block = Block;
393
394 /// Create a new context for encryption.
395 pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
396 return AESEncryptCtx(AES128).init(key);
397 }
398
399 /// Create a new context for decryption.
400 pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
401 return AESDecryptCtx(AES128).init(key);
402 }
403};
404
405/// AES-256 with the standard key schedule.
406pub const AES256 = struct {
407 pub const key_bits: usize = 256;
408 pub const rounds = ((key_bits - 64) / 32 + 8);
409 pub const block = Block;
410
411 /// Create a new context for encryption.
412 pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
413 return AESEncryptCtx(AES256).init(key);
414 }
415
416 /// Create a new context for decryption.
417 pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
418 return AESDecryptCtx(AES256).init(key);
419 }
420};
lib/std/crypto/aes/soft.zig created+735
......@@ -0,0 +1,735 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6// Based on Go stdlib implementation
7
8const std = @import("../../std.zig");
9const mem = std.mem;
10
11const BlockVec = [4]u32;
12
13/// A single AES block.
14pub const Block = struct {
15 pub const block_size: usize = 16;
16
17 /// Internal representation of a block.
18 repr: BlockVec align(16),
19
20 /// Convert a byte sequence into an internal representation.
21 pub inline fn fromBytes(bytes: *const [16]u8) Block {
22 const s0 = mem.readIntBig(u32, bytes[0..4]);
23 const s1 = mem.readIntBig(u32, bytes[4..8]);
24 const s2 = mem.readIntBig(u32, bytes[8..12]);
25 const s3 = mem.readIntBig(u32, bytes[12..16]);
26 return Block{ .repr = BlockVec{ s0, s1, s2, s3 } };
27 }
28
29 /// Convert the internal representation of a block into a byte sequence.
30 pub inline fn toBytes(block: Block) [16]u8 {
31 var bytes: [16]u8 = undefined;
32 mem.writeIntBig(u32, bytes[0..4], block.repr[0]);
33 mem.writeIntBig(u32, bytes[4..8], block.repr[1]);
34 mem.writeIntBig(u32, bytes[8..12], block.repr[2]);
35 mem.writeIntBig(u32, bytes[12..16], block.repr[3]);
36 return bytes;
37 }
38
39 /// XOR the block with a byte sequence.
40 pub inline fn xorBytes(block: Block, bytes: *const [16]u8) [16]u8 {
41 const block_bytes = block.toBytes();
42 var x: [16]u8 = undefined;
43 comptime var i: usize = 0;
44 inline while (i < 16) : (i += 1) {
45 x[i] = block_bytes[i] ^ bytes[i];
46 }
47 return x;
48 }
49
50 /// Encrypt a block with a round key.
51 pub inline fn encrypt(block: Block, round_key: Block) Block {
52 const src = &block.repr;
53
54 const s0 = block.repr[0];
55 const s1 = block.repr[1];
56 const s2 = block.repr[2];
57 const s3 = block.repr[3];
58
59 const t0 = round_key.repr[0] ^ te0[@truncate(u8, s0 >> 24)] ^ te1[@truncate(u8, s1 >> 16)] ^ te2[@truncate(u8, s2 >> 8)] ^ te3[@truncate(u8, s3)];
60 const t1 = round_key.repr[1] ^ te0[@truncate(u8, s1 >> 24)] ^ te1[@truncate(u8, s2 >> 16)] ^ te2[@truncate(u8, s3 >> 8)] ^ te3[@truncate(u8, s0)];
61 const t2 = round_key.repr[2] ^ te0[@truncate(u8, s2 >> 24)] ^ te1[@truncate(u8, s3 >> 16)] ^ te2[@truncate(u8, s0 >> 8)] ^ te3[@truncate(u8, s1)];
62 const t3 = round_key.repr[3] ^ te0[@truncate(u8, s3 >> 24)] ^ te1[@truncate(u8, s0 >> 16)] ^ te2[@truncate(u8, s1 >> 8)] ^ te3[@truncate(u8, s2)];
63
64 return Block{ .repr = BlockVec{ t0, t1, t2, t3 } };
65 }
66
67 /// Encrypt a block with the last round key.
68 pub inline fn encryptLast(block: Block, round_key: Block) Block {
69 const src = &block.repr;
70
71 const t0 = block.repr[0];
72 const t1 = block.repr[1];
73 const t2 = block.repr[2];
74 const t3 = block.repr[3];
75
76 // Last round uses s-box directly and XORs to produce output.
77 var s0 = @as(u32, sbox0[t0 >> 24]) << 24 | @as(u32, sbox0[t1 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t2 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t3 & 0xff]);
78 var s1 = @as(u32, sbox0[t1 >> 24]) << 24 | @as(u32, sbox0[t2 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t3 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t0 & 0xff]);
79 var s2 = @as(u32, sbox0[t2 >> 24]) << 24 | @as(u32, sbox0[t3 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t0 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t1 & 0xff]);
80 var s3 = @as(u32, sbox0[t3 >> 24]) << 24 | @as(u32, sbox0[t0 >> 16 & 0xff]) << 16 | @as(u32, sbox0[t1 >> 8 & 0xff]) << 8 | @as(u32, sbox0[t2 & 0xff]);
81 s0 ^= round_key.repr[0];
82 s1 ^= round_key.repr[1];
83 s2 ^= round_key.repr[2];
84 s3 ^= round_key.repr[3];
85
86 return Block{ .repr = BlockVec{ s0, s1, s2, s3 } };
87 }
88
89 /// Decrypt a block with a round key.
90 pub inline fn decrypt(block: Block, round_key: Block) Block {
91 const src = &block.repr;
92
93 const s0 = block.repr[0];
94 const s1 = block.repr[1];
95 const s2 = block.repr[2];
96 const s3 = block.repr[3];
97
98 const t0 = round_key.repr[0] ^ td0[@truncate(u8, s0 >> 24)] ^ td1[@truncate(u8, s3 >> 16)] ^ td2[@truncate(u8, s2 >> 8)] ^ td3[@truncate(u8, s1)];
99 const t1 = round_key.repr[1] ^ td0[@truncate(u8, s1 >> 24)] ^ td1[@truncate(u8, s0 >> 16)] ^ td2[@truncate(u8, s3 >> 8)] ^ td3[@truncate(u8, s2)];
100 const t2 = round_key.repr[2] ^ td0[@truncate(u8, s2 >> 24)] ^ td1[@truncate(u8, s1 >> 16)] ^ td2[@truncate(u8, s0 >> 8)] ^ td3[@truncate(u8, s3)];
101 const t3 = round_key.repr[3] ^ td0[@truncate(u8, s3 >> 24)] ^ td1[@truncate(u8, s2 >> 16)] ^ td2[@truncate(u8, s1 >> 8)] ^ td3[@truncate(u8, s0)];
102
103 return Block{ .repr = BlockVec{ t0, t1, t2, t3 } };
104 }
105
106 /// Decrypt a block with the last round key.
107 pub inline fn decryptLast(block: Block, round_key: Block) Block {
108 const src = &block.repr;
109
110 const t0 = block.repr[0];
111 const t1 = block.repr[1];
112 const t2 = block.repr[2];
113 const t3 = block.repr[3];
114
115 // Last round uses s-box directly and XORs to produce output.
116 var s0 = @as(u32, sbox1[t0 >> 24]) << 24 | @as(u32, sbox1[t3 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t2 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t1 & 0xff]);
117 var s1 = @as(u32, sbox1[t1 >> 24]) << 24 | @as(u32, sbox1[t0 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t3 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t2 & 0xff]);
118 var s2 = @as(u32, sbox1[t2 >> 24]) << 24 | @as(u32, sbox1[t1 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t0 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t3 & 0xff]);
119 var s3 = @as(u32, sbox1[t3 >> 24]) << 24 | @as(u32, sbox1[t2 >> 16 & 0xff]) << 16 | @as(u32, sbox1[t1 >> 8 & 0xff]) << 8 | @as(u32, sbox1[t0 & 0xff]);
120 s0 ^= round_key.repr[0];
121 s1 ^= round_key.repr[1];
122 s2 ^= round_key.repr[2];
123 s3 ^= round_key.repr[3];
124
125 return Block{ .repr = BlockVec{ s0, s1, s2, s3 } };
126 }
127
128 /// XOR the content of two blocks.
129 pub inline fn xor(block1: Block, block2: Block) Block {
130 var x: BlockVec = undefined;
131 comptime var i = 0;
132 inline while (i < 4) : (i += 1) {
133 x[i] = block1.repr[i] ^ block2.repr[i];
134 }
135 return Block{ .repr = x };
136 }
137
138 /// Perform operations on multiple blocks in parallel.
139 pub const parallel = struct {
140 /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation.
141 pub const optimal_parallel_blocks = 1;
142
143 /// Encrypt multiple blocks in parallel, each their own round key.
144 pub fn encryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
145 var i = 0;
146 var out: [count]Block = undefined;
147 while (i < count) : (i += 1) {
148 out[i] = blocks[i].encrypt(round_keys[i]);
149 }
150 return out;
151 }
152
153 /// Decrypt multiple blocks in parallel, each their own round key.
154 pub fn decryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
155 var i = 0;
156 var out: [count]Block = undefined;
157 while (i < count) : (i += 1) {
158 out[i] = blocks[i].decrypt(round_keys[i]);
159 }
160 return out;
161 }
162
163 /// Encrypt multple blocks in parallel with the same round key.
164 pub fn encryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
165 var i = 0;
166 var out: [count]Block = undefined;
167 while (i < count) : (i += 1) {
168 out[i] = blocks[i].encrypt(round_key);
169 }
170 return out;
171 }
172
173 /// Decrypt multple blocks in parallel with the same round key.
174 pub fn decryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
175 var i = 0;
176 var out: [count]Block = undefined;
177 while (i < count) : (i += 1) {
178 out[i] = blocks[i].decrypt(round_key);
179 }
180 return out;
181 }
182
183 /// Encrypt multple blocks in parallel with the same last round key.
184 pub fn encryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
185 var i = 0;
186 var out: [count]Block = undefined;
187 while (i < count) : (i += 1) {
188 out[i] = blocks[i].encryptLast(round_key);
189 }
190 return out;
191 }
192
193 /// Decrypt multple blocks in parallel with the same last round key.
194 pub fn decryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
195 var i = 0;
196 var out: [count]Block = undefined;
197 while (i < count) : (i += 1) {
198 out[i] = blocks[i].decryptLast(round_key);
199 }
200 return out;
201 }
202 };
203};
204
205fn KeySchedule(comptime AES: type) type {
206 std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
207 const key_size = AES.key_bits / 8;
208 const rounds = AES.rounds;
209
210 return struct {
211 const Self = @This();
212 const words_in_key = key_size / 4;
213
214 round_keys: [rounds + 1]Block,
215
216 // Key expansion algorithm. See FIPS-197, Figure 11.
217 fn expandKey(key: [key_size]u8) Self {
218 const subw = struct {
219 // Apply sbox0 to each byte in w.
220 fn func(w: u32) u32 {
221 return @as(u32, sbox0[w >> 24]) << 24 | @as(u32, sbox0[w >> 16 & 0xff]) << 16 | @as(u32, sbox0[w >> 8 & 0xff]) << 8 | @as(u32, sbox0[w & 0xff]);
222 }
223 }.func;
224
225 var round_keys: [rounds + 1]Block = undefined;
226 comptime var i: usize = 0;
227 inline while (i < words_in_key) : (i += 1) {
228 round_keys[i / 4].repr[i % 4] = mem.readIntBig(u32, key[4 * i ..][0..4]);
229 }
230 inline while (i < round_keys.len * 4) : (i += 1) {
231 var t = round_keys[(i - 1) / 4].repr[(i - 1) % 4];
232 if (i % words_in_key == 0) {
233 t = subw(std.math.rotl(u32, t, 8)) ^ (@as(u32, powx[i / words_in_key - 1]) << 24);
234 } else if (words_in_key > 6 and i % words_in_key == 4) {
235 t = subw(t);
236 }
237 round_keys[i / 4].repr[i % 4] = round_keys[(i - words_in_key) / 4].repr[(i - words_in_key) % 4] ^ t;
238 }
239 return Self{ .round_keys = round_keys };
240 }
241
242 /// Invert the key schedule.
243 pub fn invert(key_schedule: Self) Self {
244 const round_keys = &key_schedule.round_keys;
245 var inv_round_keys: [rounds + 1]Block = undefined;
246 const total_words = 4 * round_keys.len;
247 var i: usize = 0;
248 while (i < total_words) : (i += 4) {
249 const ei = total_words - i - 4;
250 comptime var j: usize = 0;
251 inline while (j < 4) : (j += 1) {
252 var x = round_keys[(ei + j) / 4].repr[(ei + j) % 4];
253 if (i > 0 and i + 4 < total_words) {
254 x = td0[sbox0[x >> 24]] ^ td1[sbox0[x >> 16 & 0xff]] ^ td2[sbox0[x >> 8 & 0xff]] ^ td3[sbox0[x & 0xff]];
255 }
256 inv_round_keys[(i + j) / 4].repr[(i + j) % 4] = x;
257 }
258 }
259 return Self{ .round_keys = inv_round_keys };
260 }
261 };
262}
263
264/// A context to perform encryption using the standard AES key schedule.
265pub fn AESEncryptCtx(comptime AES: type) type {
266 std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
267 const rounds = AES.rounds;
268
269 return struct {
270 const Self = @This();
271 pub const block = AES.block;
272 pub const block_size = block.block_size;
273 key_schedule: KeySchedule(AES),
274
275 /// Create a new encryption context with the given key.
276 pub fn init(key: [AES.key_bits / 8]u8) Self {
277 const key_schedule = KeySchedule(AES).expandKey(key);
278 return Self{
279 .key_schedule = key_schedule,
280 };
281 }
282
283 /// Encrypt a single block.
284 pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
285 const round_keys = ctx.key_schedule.round_keys;
286 var t = Block.fromBytes(src).xor(round_keys[0]);
287 comptime var i = 1;
288 inline while (i < rounds) : (i += 1) {
289 t = t.encrypt(round_keys[i]);
290 }
291 t = t.encryptLast(round_keys[rounds]);
292 dst.* = t.toBytes();
293 }
294
295 /// Encrypt+XOR a single block.
296 pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void {
297 const round_keys = ctx.key_schedule.round_keys;
298 var t = Block.fromBytes(&counter).xor(round_keys[0]);
299 comptime var i = 1;
300 inline while (i < rounds) : (i += 1) {
301 t = t.encrypt(round_keys[i]);
302 }
303 t = t.encryptLast(round_keys[rounds]);
304 dst.* = t.xorBytes(src);
305 }
306
307 /// Encrypt multiple blocks, possibly leveraging parallelization.
308 pub fn encryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
309 var i: usize = 0;
310 while (i < count) : (i += 1) {
311 ctx.encrypt(dst[16 * i .. 16 * i + 16][0..16], src[16 * i .. 16 * i + 16][0..16]);
312 }
313 }
314
315 /// Encrypt+XOR multiple blocks, possibly leveraging parallelization.
316 pub fn xorWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8, counters: [16 * count]u8) void {
317 var i: usize = 0;
318 while (i < count) : (i += 1) {
319 ctx.xor(dst[16 * i .. 16 * i + 16][0..16], src[16 * i .. 16 * i + 16][0..16], counters[16 * i .. 16 * i + 16][0..16].*);
320 }
321 }
322 };
323}
324
325/// A context to perform decryption using the standard AES key schedule.
326pub fn AESDecryptCtx(comptime AES: type) type {
327 std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
328 const rounds = AES.rounds;
329
330 return struct {
331 const Self = @This();
332 pub const block = AES.block;
333 pub const block_size = block.block_size;
334 key_schedule: KeySchedule(AES),
335
336 /// Create a decryption context from an existing encryption context.
337 pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
338 return Self{
339 .key_schedule = ctx.key_schedule.invert(),
340 };
341 }
342
343 /// Create a new decryption context with the given key.
344 pub fn init(key: [AES.key_bits / 8]u8) Self {
345 const enc_ctx = AESEncryptCtx(AES).init(key);
346 return initFromEnc(enc_ctx);
347 }
348
349 /// Decrypt a single block.
350 pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
351 const inv_round_keys = ctx.key_schedule.round_keys;
352 var t = Block.fromBytes(src).xor(inv_round_keys[0]);
353 comptime var i = 1;
354 inline while (i < rounds) : (i += 1) {
355 t = t.decrypt(inv_round_keys[i]);
356 }
357 t = t.decryptLast(inv_round_keys[rounds]);
358 dst.* = t.toBytes();
359 }
360
361 /// Decrypt multiple blocks, possibly leveraging parallelization.
362 pub fn decryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
363 var i: usize = 0;
364 while (i < count) : (i += 1) {
365 ctx.decrypt(dst[16 * i .. 16 * i + 16][0..16], src[16 * i .. 16 * i + 16][0..16]);
366 }
367 }
368 };
369}
370
371/// AES-128 with the standard key schedule.
372pub const AES128 = struct {
373 pub const key_bits: usize = 128;
374 pub const rounds = ((key_bits - 64) / 32 + 8);
375 pub const block = Block;
376
377 /// Create a new context for encryption.
378 pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
379 return AESEncryptCtx(AES128).init(key);
380 }
381
382 /// Create a new context for decryption.
383 pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
384 return AESDecryptCtx(AES128).init(key);
385 }
386};
387
388/// AES-256 with the standard key schedule.
389pub const AES256 = struct {
390 pub const key_bits: usize = 256;
391 pub const rounds = ((key_bits - 64) / 32 + 8);
392 pub const block = Block;
393
394 /// Create a new context for encryption.
395 pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
396 return AESEncryptCtx(AES256).init(key);
397 }
398
399 /// Create a new context for decryption.
400 pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
401 return AESDecryptCtx(AES256).init(key);
402 }
403};
404
405// constants
406const powx = [16]u8{
407 0x01,
408 0x02,
409 0x04,
410 0x08,
411 0x10,
412 0x20,
413 0x40,
414 0x80,
415 0x1b,
416 0x36,
417 0x6c,
418 0xd8,
419 0xab,
420 0x4d,
421 0x9a,
422 0x2f,
423};
424
425const sbox0 align(64) = [256]u8{
426 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
427 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
428 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
429 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
430 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
431 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
432 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
433 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
434 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
435 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
436 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
437 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
438 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
439 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
440 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
441 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
442};
443
444const sbox1 align(64) = [256]u8{
445 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
446 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
447 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
448 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
449 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
450 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
451 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
452 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
453 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
454 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
455 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
456 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
457 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
458 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
459 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
460 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
461};
462
463const te0 align(64) = [256]u32{
464 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
465 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
466 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
467 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
468 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
469 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
470 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
471 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
472 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
473 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
474 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
475 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
476 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
477 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
478 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
479 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
480 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
481 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
482 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
483 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
484 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
485 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
486 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
487 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
488 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
489 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
490 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
491 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
492 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
493 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
494 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
495 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
496};
497const te1 align(64) = [256]u32{
498 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
499 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
500 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
501 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
502 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
503 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
504 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
505 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
506 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
507 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
508 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
509 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
510 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
511 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
512 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
513 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
514 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
515 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
516 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
517 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
518 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
519 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
520 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
521 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
522 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
523 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
524 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
525 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
526 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
527 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
528 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
529 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
530};
531const te2 align(64) = [256]u32{
532 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
533 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
534 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
535 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
536 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
537 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
538 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
539 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
540 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
541 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
542 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
543 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
544 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
545 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
546 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
547 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
548 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
549 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
550 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
551 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
552 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
553 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
554 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
555 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
556 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
557 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
558 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
559 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
560 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
561 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
562 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
563 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
564};
565const te3 align(64) = [256]u32{
566 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
567 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
568 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
569 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
570 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
571 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
572 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
573 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
574 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
575 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
576 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
577 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
578 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
579 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
580 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
581 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
582 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
583 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
584 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
585 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
586 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
587 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
588 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
589 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
590 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
591 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
592 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
593 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
594 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
595 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
596 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
597 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
598};
599
600const td0 align(64) = [256]u32{
601 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
602 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
603 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
604 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
605 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
606 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
607 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
608 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
609 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
610 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
611 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
612 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
613 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
614 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
615 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
616 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
617 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
618 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
619 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
620 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
621 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
622 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
623 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
624 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
625 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
626 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
627 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
628 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
629 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
630 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
631 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
632 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
633};
634const td1 align(64) = [256]u32{
635 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
636 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
637 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
638 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
639 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
640 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
641 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
642 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
643 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
644 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
645 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
646 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
647 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
648 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
649 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
650 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
651 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
652 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
653 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
654 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
655 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
656 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
657 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
658 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
659 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
660 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
661 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
662 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
663 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
664 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
665 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
666 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
667};
668const td2 align(64) = [256]u32{
669 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
670 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
671 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
672 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
673 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
674 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
675 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
676 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
677 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
678 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
679 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
680 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
681 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
682 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
683 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
684 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
685 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
686 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
687 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
688 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
689 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
690 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
691 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
692 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
693 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
694 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
695 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
696 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
697 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
698 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
699 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
700 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
701};
702const td3 align(64) = [256]u32{
703 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
704 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
705 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
706 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
707 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
708 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
709 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
710 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
711 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
712 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
713 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
714 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
715 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
716 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
717 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
718 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
719 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
720 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
721 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
722 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
723 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
724 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
725 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
726 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
727 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
728 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
729 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
730 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
731 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
732 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
733 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
734 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
735};
lib/std/crypto/benchmark.zig+77-5
......@@ -179,6 +179,64 @@ pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64
179179 return throughput;
180180}
181181
182const aes = [_]Crypto{
183 Crypto{ .ty = crypto.core.aes.AES128, .name = "aes128-single" },
184 Crypto{ .ty = crypto.core.aes.AES256, .name = "aes256-single" },
185};
186
187pub fn benchmarkAES(comptime AES: anytype, comptime count: comptime_int) !u64 {
188 var key: [AES.key_bits / 8]u8 = undefined;
189 prng.random.bytes(key[0..]);
190 const ctx = AES.initEnc(key);
191
192 var in = [_]u8{0} ** 16;
193
194 var timer = try Timer.start();
195 const start = timer.lap();
196 {
197 var i: usize = 0;
198 while (i < count) : (i += 1) {
199 ctx.encrypt(&in, &in);
200 }
201 }
202 mem.doNotOptimizeAway(&in);
203 const end = timer.read();
204
205 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
206 const throughput = @floatToInt(u64, count / elapsed_s);
207
208 return throughput;
209}
210
211const aes8 = [_]Crypto{
212 Crypto{ .ty = crypto.core.aes.AES128, .name = "aes128-8" },
213 Crypto{ .ty = crypto.core.aes.AES256, .name = "aes256-8" },
214};
215
216pub fn benchmarkAES8(comptime AES: anytype, comptime count: comptime_int) !u64 {
217 var key: [AES.key_bits / 8]u8 = undefined;
218 prng.random.bytes(key[0..]);
219 const ctx = AES.initEnc(key);
220
221 var in = [_]u8{0} ** (8 * 16);
222
223 var timer = try Timer.start();
224 const start = timer.lap();
225 {
226 var i: usize = 0;
227 while (i < count) : (i += 1) {
228 ctx.encryptWide(8, &in, &in);
229 }
230 }
231 mem.doNotOptimizeAway(&in);
232 const end = timer.read();
233
234 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
235 const throughput = @floatToInt(u64, 8 * count / elapsed_s);
236
237 return throughput;
238}
239
182240fn usage() void {
183241 std.debug.warn(
184242 \\throughput_test [options]
......@@ -238,35 +296,49 @@ pub fn main() !void {
238296 inline for (hashes) |H| {
239297 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
240298 const throughput = try benchmarkHash(H.ty, mode(128 * MiB));
241 try stdout.print("{:>17}: {:7} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
299 try stdout.print("{:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
242300 }
243301 }
244302
245303 inline for (macs) |M| {
246304 if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
247305 const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
248 try stdout.print("{:>17}: {:7} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
306 try stdout.print("{:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
249307 }
250308 }
251309
252310 inline for (exchanges) |E| {
253311 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
254312 const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
255 try stdout.print("{:>17}: {:7} exchanges/s\n", .{ E.name, throughput });
313 try stdout.print("{:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
256314 }
257315 }
258316
259317 inline for (signatures) |E| {
260318 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
261319 const throughput = try benchmarkSignature(E.ty, mode(1000));
262 try stdout.print("{:>17}: {:7} signatures/s\n", .{ E.name, throughput });
320 try stdout.print("{:>17}: {:10} signatures/s\n", .{ E.name, throughput });
263321 }
264322 }
265323
266324 inline for (aeads) |E| {
267325 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
268326 const throughput = try benchmarkAead(E.ty, mode(128 * MiB));
269 try stdout.print("{:>17}: {:7} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
327 try stdout.print("{:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
328 }
329 }
330
331 inline for (aes) |E| {
332 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
333 const throughput = try benchmarkAES(E.ty, mode(100000000));
334 try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
335 }
336 }
337
338 inline for (aes8) |E| {
339 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
340 const throughput = try benchmarkAES8(E.ty, mode(10000000));
341 try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
270342 }
271343 }
272344}
lib/std/crypto/modes.zig created+51
......@@ -0,0 +1,51 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6// Based on Go stdlib implementation
7
8const std = @import("../std.zig");
9const builtin = std.builtin;
10const mem = std.mem;
11const debug = std.debug;
12
13/// Counter mode.
14///
15/// This mode creates a key stream by encrypting an incrementing counter using a block cipher, and adding it to the source material.
16///
17/// Important: the counter mode doesn't provide authenticated encryption: the ciphertext can be trivially modified without this being detected.
18/// As a result, applications should generally never use it directly, but only in a construction that includes a MAC.
19pub fn ctr(comptime BlockCipher: anytype, block_cipher: BlockCipher, dst: []u8, src: []const u8, iv: [BlockCipher.block_size]u8, endian: comptime builtin.Endian) void {
20 debug.assert(dst.len >= src.len);
21 const block_size = BlockCipher.block_size;
22 var counter: [BlockCipher.block_size]u8 = undefined;
23 var counterInt = mem.readInt(u128, &iv, endian);
24 var i: usize = 0;
25
26 const parallel_count = BlockCipher.block.parallel.optimal_parallel_blocks;
27 const wide_block_size = parallel_count * 16;
28 if (src.len >= wide_block_size) {
29 var counters: [parallel_count * 16]u8 = undefined;
30 while (i + wide_block_size <= src.len) : (i += wide_block_size) {
31 comptime var j = 0;
32 inline while (j < parallel_count) : (j += 1) {
33 mem.writeInt(u128, counters[j * 16 .. j * 16 + 16], counterInt, endian);
34 counterInt +%= 1;
35 }
36 block_cipher.xorWide(parallel_count, dst[i .. i + wide_block_size][0..wide_block_size], src[i .. i + wide_block_size][0..wide_block_size], counters);
37 }
38 }
39 while (i + block_size <= src.len) : (i += block_size) {
40 mem.writeInt(u128, &counter, counterInt, endian);
41 counterInt +%= 1;
42 block_cipher.xor(dst[i .. i + block_size][0..block_size], src[i .. i + block_size][0..block_size], counter);
43 }
44 if (i < src.len) {
45 mem.writeInt(u128, &counter, counterInt, endian);
46 var pad = [_]u8{0} ** block_size;
47 mem.copy(u8, &pad, src[i..]);
48 block_cipher.xor(&pad, &pad, counter);
49 mem.copy(u8, dst[i..], pad[0 .. src.len - i]);
50 }
51}
lib/std/event/lock.zig+90-115
......@@ -16,107 +16,107 @@ const Loop = std.event.Loop;
1616/// Allows only one actor to hold the lock.
1717/// TODO: make this API also work in blocking I/O mode.
1818pub const Lock = struct {
19 shared: bool,
20 queue: Queue,
21 queue_empty: bool,
19 mutex: std.Mutex = std.Mutex{},
20 head: usize = UNLOCKED,
2221
23 const Queue = std.atomic.Queue(anyframe);
22 const UNLOCKED = 0;
23 const LOCKED = 1;
2424
2525 const global_event_loop = Loop.instance orelse
2626 @compileError("std.event.Lock currently only works with event-based I/O");
2727
28 pub const Held = struct {
29 lock: *Lock,
30
31 pub fn release(self: Held) void {
32 // Resume the next item from the queue.
33 if (self.lock.queue.get()) |node| {
34 global_event_loop.onNextTick(node);
35 return;
36 }
37
38 // We need to release the lock.
39 @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
40 @atomicStore(bool, &self.lock.shared, false, .SeqCst);
41
42 // There might be a queue item. If we know the queue is empty, we can be done,
43 // because the other actor will try to obtain the lock.
44 // But if there's a queue item, we are the actor which must loop and attempt
45 // to grab the lock again.
46 if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
47 return;
48 }
49
50 while (true) {
51 if (@atomicRmw(bool, &self.lock.shared, .Xchg, true, .SeqCst)) {
52 // We did not obtain the lock. Great, the queue is someone else's problem.
53 return;
54 }
55
56 // Resume the next item from the queue.
57 if (self.lock.queue.get()) |node| {
58 global_event_loop.onNextTick(node);
59 return;
60 }
61
62 // Release the lock again.
63 @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
64 @atomicStore(bool, &self.lock.shared, false, .SeqCst);
28 const Waiter = struct {
29 // forced Waiter alignment to ensure it doesn't clash with LOCKED
30 next: ?*Waiter align(2),
31 tail: *Waiter,
32 node: Loop.NextTickNode,
33 };
6534
66 // Find out if we can be done.
67 if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
68 return;
69 }
70 }
35 pub fn acquire(self: *Lock) Held {
36 const held = self.mutex.acquire();
37
38 // self.head transitions from multiple stages depending on the value:
39 // UNLOCKED -> LOCKED:
40 // acquire Lock ownership when theres no waiters
41 // LOCKED -> <Waiter head ptr>:
42 // Lock is already owned, enqueue first Waiter
43 // <head ptr> -> <head ptr>:
44 // Lock is owned with pending waiters. Push our waiter to the queue.
45
46 if (self.head == UNLOCKED) {
47 self.head = LOCKED;
48 held.release();
49 return Held{ .lock = self };
7150 }
72 };
7351
74 pub fn init() Lock {
75 return Lock{
76 .shared = false,
77 .queue = Queue.init(),
78 .queue_empty = true,
79 };
80 }
52 var waiter: Waiter = undefined;
53 waiter.next = null;
54 waiter.tail = &waiter;
8155
82 pub fn initLocked() Lock {
83 return Lock{
84 .shared = true,
85 .queue = Queue.init(),
86 .queue_empty = true,
56 const head = switch (self.head) {
57 UNLOCKED => unreachable,
58 LOCKED => null,
59 else => @intToPtr(*Waiter, self.head),
8760 };
88 }
89
90 /// Must be called when not locked. Not thread safe.
91 /// All calls to acquire() and release() must complete before calling deinit().
92 pub fn deinit(self: *Lock) void {
93 assert(!self.shared);
94 while (self.queue.get()) |node| resume node.data;
95 }
9661
97 pub fn acquire(self: *Lock) callconv(.Async) Held {
98 var my_tick_node = Loop.NextTickNode.init(@frame());
62 if (head) |h| {
63 h.tail.next = &waiter;
64 h.tail = &waiter;
65 } else {
66 self.head = @ptrToInt(&waiter);
67 }
9968
100 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
10169 suspend {
102 self.queue.put(&my_tick_node);
103
104 // At this point, we are in the queue, so we might have already been resumed.
70 waiter.node = Loop.NextTickNode{
71 .prev = undefined,
72 .next = undefined,
73 .data = @frame(),
74 };
75 held.release();
76 }
10577
106 // We set this bit so that later we can rely on the fact, that if queue_empty == true, some actor
107 // will attempt to grab the lock.
108 @atomicStore(bool, &self.queue_empty, false, .SeqCst);
78 return Held{ .lock = self };
79 }
10980
110 if (!@atomicRmw(bool, &self.shared, .Xchg, true, .SeqCst)) {
111 if (self.queue.get()) |node| {
112 // Whether this node is us or someone else, we tail resume it.
113 resume node.data;
81 pub const Held = struct {
82 lock: *Lock,
83
84 pub fn release(self: Held) void {
85 const waiter = blk: {
86 const held = self.lock.mutex.acquire();
87 defer held.release();
88
89 // self.head goes through the reverse transition from acquire():
90 // <head ptr> -> <new head ptr>:
91 // pop a waiter from the queue to give Lock ownership when theres still others pending
92 // <head ptr> -> LOCKED:
93 // pop the laster waiter from the queue, while also giving it lock ownership when awaken
94 // LOCKED -> UNLOCKED:
95 // last lock owner releases lock while no one else is waiting for it
96
97 switch (self.lock.head) {
98 UNLOCKED => {
99 unreachable; // Lock unlocked while unlocking
100 },
101 LOCKED => {
102 self.lock.head = UNLOCKED;
103 break :blk null;
104 },
105 else => {
106 const waiter = @intToPtr(*Waiter, self.lock.head);
107 self.lock.head = if (waiter.next == null) LOCKED else @ptrToInt(waiter.next);
108 if (waiter.next) |next|
109 next.tail = waiter.tail;
110 break :blk waiter;
111 },
114112 }
113 };
114
115 if (waiter) |w| {
116 global_event_loop.onNextTick(&w.node);
115117 }
116118 }
117
118 return Held{ .lock = self };
119 }
119 };
120120};
121121
122122test "std.event.Lock" {
......@@ -128,41 +128,16 @@ test "std.event.Lock" {
128128 // TODO https://github.com/ziglang/zig/issues/3251
129129 if (builtin.os.tag == .freebsd) return error.SkipZigTest;
130130
131 // TODO this file has bit-rotted. repair it
132 if (true) return error.SkipZigTest;
133
134 var lock = Lock.init();
135 defer lock.deinit();
136
137 _ = async testLock(&lock);
131 var lock = Lock{};
132 testLock(&lock);
138133
139134 const expected_result = [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
140135 testing.expectEqualSlices(i32, &expected_result, &shared_test_data);
141136}
142fn testLock(lock: *Lock) callconv(.Async) void {
137fn testLock(lock: *Lock) void {
143138 var handle1 = async lockRunner(lock);
144 var tick_node1 = Loop.NextTickNode{
145 .prev = undefined,
146 .next = undefined,
147 .data = &handle1,
148 };
149 Loop.instance.?.onNextTick(&tick_node1);
150
151139 var handle2 = async lockRunner(lock);
152 var tick_node2 = Loop.NextTickNode{
153 .prev = undefined,
154 .next = undefined,
155 .data = &handle2,
156 };
157 Loop.instance.?.onNextTick(&tick_node2);
158
159140 var handle3 = async lockRunner(lock);
160 var tick_node3 = Loop.NextTickNode{
161 .prev = undefined,
162 .next = undefined,
163 .data = &handle3,
164 };
165 Loop.instance.?.onNextTick(&tick_node3);
166141
167142 await handle1;
168143 await handle2;
......@@ -171,13 +146,13 @@ fn testLock(lock: *Lock) callconv(.Async) void {
171146
172147var shared_test_data = [1]i32{0} ** 10;
173148var shared_test_index: usize = 0;
174fn lockRunner(lock: *Lock) callconv(.Async) void {
175 suspend; // resumed by onNextTick
149
150fn lockRunner(lock: *Lock) void {
151 Lock.global_event_loop.yield();
176152
177153 var i: usize = 0;
178154 while (i < shared_test_data.len) : (i += 1) {
179 var lock_frame = async lock.acquire();
180 const handle = await lock_frame;
155 const handle = lock.acquire();
181156 defer handle.release();
182157
183158 shared_test_index = 0;
lib/std/event/loop.zig+326-106
......@@ -112,8 +112,9 @@ pub const Loop = struct {
112112 /// have the correct pointer value.
113113 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
114114 pub fn init(self: *Loop) !void {
115 if (builtin.single_threaded
116 or (@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded)) {
115 if (builtin.single_threaded or
116 (@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded))
117 {
117118 return self.initSingleThreaded();
118119 } else {
119120 return self.initMultiThreaded();
......@@ -687,9 +688,14 @@ pub const Loop = struct {
687688
688689 switch (builtin.os.tag) {
689690 .linux => {
690 // writing 8 bytes to an eventfd cannot fail
691 const amt = os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
692 assert(amt == wakeup_bytes.len);
691 // writing to the eventfd will only wake up one thread, thus multiple writes
692 // are needed to wakeup all the threads
693 var i: usize = 0;
694 while (i < self.extra_threads.len + 1) : (i += 1) {
695 // writing 8 bytes to an eventfd cannot fail
696 const amt = os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
697 assert(amt == wakeup_bytes.len);
698 }
693699 return;
694700 },
695701 .macosx, .freebsd, .netbsd, .dragonfly => {
......@@ -715,6 +721,50 @@ pub const Loop = struct {
715721 }
716722 }
717723
724 /// ------- I/0 APIs -------
725 pub fn accept(
726 self: *Loop,
727 /// This argument is a socket that has been created with `socket`, bound to a local address
728 /// with `bind`, and is listening for connections after a `listen`.
729 sockfd: os.fd_t,
730 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the
731 /// address of the peer socket, as known to the communications layer. The exact format of the
732 /// address returned addr is determined by the socket's address family (see `socket` and the
733 /// respective protocol man pages).
734 addr: *os.sockaddr,
735 /// This argument is a value-result argument: the caller must initialize it to contain the
736 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
737 /// of the peer address.
738 ///
739 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
740 /// will return a value greater than was supplied to the call.
741 addr_size: *os.socklen_t,
742 /// The following values can be bitwise ORed in flags to obtain different behavior:
743 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
744 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
745 flags: u32,
746 ) os.AcceptError!os.fd_t {
747 while (true) {
748 return os.accept(sockfd, addr, addr_size, flags | os.SOCK_NONBLOCK) catch |err| switch (err) {
749 error.WouldBlock => {
750 self.waitUntilFdReadable(sockfd);
751 continue;
752 },
753 else => return err,
754 };
755 }
756 }
757
758 pub fn connect(self: *Loop, sockfd: os.socket_t, sock_addr: *const os.sockaddr, len: os.socklen_t) os.ConnectError!void {
759 os.connect(sockfd, sock_addr, len) catch |err| switch (err) {
760 error.WouldBlock => {
761 self.waitUntilFdWritable(sockfd);
762 return os.getsockoptError(sockfd);
763 },
764 else => return err,
765 };
766 }
767
718768 /// Performs an async `os.open` using a separate thread.
719769 pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {
720770 var req_node = Request.Node{
......@@ -773,152 +823,309 @@ pub const Loop = struct {
773823
774824 /// Performs an async `os.read` using a separate thread.
775825 /// `fd` must block and not return EAGAIN.
776 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8) os.ReadError!usize {
777 var req_node = Request.Node{
778 .data = .{
779 .msg = .{
780 .read = .{
781 .fd = fd,
782 .buf = buf,
783 .result = undefined,
826 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8, simulate_evented: bool) os.ReadError!usize {
827 if (simulate_evented) {
828 var req_node = Request.Node{
829 .data = .{
830 .msg = .{
831 .read = .{
832 .fd = fd,
833 .buf = buf,
834 .result = undefined,
835 },
784836 },
837 .finish = .{ .TickNode = .{ .data = @frame() } },
785838 },
786 .finish = .{ .TickNode = .{ .data = @frame() } },
787 },
788 };
789 suspend {
790 self.posixFsRequest(&req_node);
839 };
840 suspend {
841 self.posixFsRequest(&req_node);
842 }
843 return req_node.data.msg.read.result;
844 } else {
845 while (true) {
846 return os.read(fd, buf) catch |err| switch (err) {
847 error.WouldBlock => {
848 self.waitUntilFdReadable(fd);
849 continue;
850 },
851 else => return err,
852 };
853 }
791854 }
792 return req_node.data.msg.read.result;
793855 }
794856
795857 /// Performs an async `os.readv` using a separate thread.
796858 /// `fd` must block and not return EAGAIN.
797 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec) os.ReadError!usize {
798 var req_node = Request.Node{
799 .data = .{
800 .msg = .{
801 .readv = .{
802 .fd = fd,
803 .iov = iov,
804 .result = undefined,
859 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, simulate_evented: bool) os.ReadError!usize {
860 if (simulate_evented) {
861 var req_node = Request.Node{
862 .data = .{
863 .msg = .{
864 .readv = .{
865 .fd = fd,
866 .iov = iov,
867 .result = undefined,
868 },
805869 },
870 .finish = .{ .TickNode = .{ .data = @frame() } },
806871 },
807 .finish = .{ .TickNode = .{ .data = @frame() } },
808 },
809 };
810 suspend {
811 self.posixFsRequest(&req_node);
872 };
873 suspend {
874 self.posixFsRequest(&req_node);
875 }
876 return req_node.data.msg.readv.result;
877 } else {
878 while (true) {
879 return os.readv(fd, iov) catch |err| switch (err) {
880 error.WouldBlock => {
881 self.waitUntilFdReadable(fd);
882 continue;
883 },
884 else => return err,
885 };
886 }
812887 }
813 return req_node.data.msg.readv.result;
814888 }
815889
816890 /// Performs an async `os.pread` using a separate thread.
817891 /// `fd` must block and not return EAGAIN.
818 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64) os.PReadError!usize {
819 var req_node = Request.Node{
820 .data = .{
821 .msg = .{
822 .pread = .{
823 .fd = fd,
824 .buf = buf,
825 .offset = offset,
826 .result = undefined,
892 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64, simulate_evented: bool) os.PReadError!usize {
893 if (simulate_evented) {
894 var req_node = Request.Node{
895 .data = .{
896 .msg = .{
897 .pread = .{
898 .fd = fd,
899 .buf = buf,
900 .offset = offset,
901 .result = undefined,
902 },
827903 },
904 .finish = .{ .TickNode = .{ .data = @frame() } },
828905 },
829 .finish = .{ .TickNode = .{ .data = @frame() } },
830 },
831 };
832 suspend {
833 self.posixFsRequest(&req_node);
906 };
907 suspend {
908 self.posixFsRequest(&req_node);
909 }
910 return req_node.data.msg.pread.result;
911 } else {
912 while (true) {
913 return os.pread(fd, buf, offset) catch |err| switch (err) {
914 error.WouldBlock => {
915 self.waitUntilFdReadable(fd);
916 continue;
917 },
918 else => return err,
919 };
920 }
834921 }
835 return req_node.data.msg.pread.result;
836922 }
837923
838924 /// Performs an async `os.preadv` using a separate thread.
839925 /// `fd` must block and not return EAGAIN.
840 pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64) os.ReadError!usize {
841 var req_node = Request.Node{
842 .data = .{
843 .msg = .{
844 .preadv = .{
845 .fd = fd,
846 .iov = iov,
847 .offset = offset,
848 .result = undefined,
926 pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64, simulate_evented: bool) os.ReadError!usize {
927 if (simulate_evented) {
928 var req_node = Request.Node{
929 .data = .{
930 .msg = .{
931 .preadv = .{
932 .fd = fd,
933 .iov = iov,
934 .offset = offset,
935 .result = undefined,
936 },
849937 },
938 .finish = .{ .TickNode = .{ .data = @frame() } },
850939 },
851 .finish = .{ .TickNode = .{ .data = @frame() } },
852 },
853 };
854 suspend {
855 self.posixFsRequest(&req_node);
940 };
941 suspend {
942 self.posixFsRequest(&req_node);
943 }
944 return req_node.data.msg.preadv.result;
945 } else {
946 while (true) {
947 return os.preadv(fd, iov, offset) catch |err| switch (err) {
948 error.WouldBlock => {
949 self.waitUntilFdReadable(fd);
950 continue;
951 },
952 else => return err,
953 };
954 }
856955 }
857 return req_node.data.msg.preadv.result;
858956 }
859957
860958 /// Performs an async `os.write` using a separate thread.
861959 /// `fd` must block and not return EAGAIN.
862 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8) os.WriteError!usize {
863 var req_node = Request.Node{
864 .data = .{
865 .msg = .{
866 .write = .{
867 .fd = fd,
868 .bytes = bytes,
869 .result = undefined,
960 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8, simulate_evented: bool) os.WriteError!usize {
961 if (simulate_evented) {
962 var req_node = Request.Node{
963 .data = .{
964 .msg = .{
965 .write = .{
966 .fd = fd,
967 .bytes = bytes,
968 .result = undefined,
969 },
870970 },
971 .finish = .{ .TickNode = .{ .data = @frame() } },
871972 },
872 .finish = .{ .TickNode = .{ .data = @frame() } },
873 },
874 };
875 suspend {
876 self.posixFsRequest(&req_node);
973 };
974 suspend {
975 self.posixFsRequest(&req_node);
976 }
977 return req_node.data.msg.write.result;
978 } else {
979 while (true) {
980 return os.write(fd, bytes) catch |err| switch (err) {
981 error.WouldBlock => {
982 self.waitUntilFdWritable(fd);
983 continue;
984 },
985 else => return err,
986 };
987 }
877988 }
878 return req_node.data.msg.write.result;
879989 }
880990
881991 /// Performs an async `os.writev` using a separate thread.
882992 /// `fd` must block and not return EAGAIN.
883 pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const) os.WriteError!usize {
884 var req_node = Request.Node{
885 .data = .{
886 .msg = .{
887 .writev = .{
888 .fd = fd,
889 .iov = iov,
890 .result = undefined,
993 pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, simulate_evented: bool) os.WriteError!usize {
994 if (simulate_evented) {
995 var req_node = Request.Node{
996 .data = .{
997 .msg = .{
998 .writev = .{
999 .fd = fd,
1000 .iov = iov,
1001 .result = undefined,
1002 },
8911003 },
1004 .finish = .{ .TickNode = .{ .data = @frame() } },
8921005 },
893 .finish = .{ .TickNode = .{ .data = @frame() } },
894 },
895 };
896 suspend {
897 self.posixFsRequest(&req_node);
1006 };
1007 suspend {
1008 self.posixFsRequest(&req_node);
1009 }
1010 return req_node.data.msg.writev.result;
1011 } else {
1012 while (true) {
1013 return os.writev(fd, iov) catch |err| switch (err) {
1014 error.WouldBlock => {
1015 self.waitUntilFdWritable(fd);
1016 continue;
1017 },
1018 else => return err,
1019 };
1020 }
1021 }
1022 }
1023
1024 /// Performs an async `os.pwrite` using a separate thread.
1025 /// `fd` must block and not return EAGAIN.
1026 pub fn pwrite(self: *Loop, fd: os.fd_t, bytes: []const u8, offset: u64, simulate_evented: bool) os.PerformsWriteError!usize {
1027 if (simulate_evented) {
1028 var req_node = Request.Node{
1029 .data = .{
1030 .msg = .{
1031 .pwrite = .{
1032 .fd = fd,
1033 .bytes = bytes,
1034 .offset = offset,
1035 .result = undefined,
1036 },
1037 },
1038 .finish = .{ .TickNode = .{ .data = @frame() } },
1039 },
1040 };
1041 suspend {
1042 self.posixFsRequest(&req_node);
1043 }
1044 return req_node.data.msg.pwrite.result;
1045 } else {
1046 while (true) {
1047 return os.pwrite(fd, bytes, offset) catch |err| switch (err) {
1048 error.WouldBlock => {
1049 self.waitUntilFdWritable(fd);
1050 continue;
1051 },
1052 else => return err,
1053 };
1054 }
8981055 }
899 return req_node.data.msg.writev.result;
9001056 }
9011057
9021058 /// Performs an async `os.pwritev` using a separate thread.
9031059 /// `fd` must block and not return EAGAIN.
904 pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64) os.WriteError!usize {
905 var req_node = Request.Node{
906 .data = .{
907 .msg = .{
908 .pwritev = .{
909 .fd = fd,
910 .iov = iov,
911 .offset = offset,
912 .result = undefined,
1060 pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64, simulate_evented: bool) os.PWriteError!usize {
1061 if (simulate_evented) {
1062 var req_node = Request.Node{
1063 .data = .{
1064 .msg = .{
1065 .pwritev = .{
1066 .fd = fd,
1067 .iov = iov,
1068 .offset = offset,
1069 .result = undefined,
1070 },
9131071 },
1072 .finish = .{ .TickNode = .{ .data = @frame() } },
9141073 },
915 .finish = .{ .TickNode = .{ .data = @frame() } },
916 },
917 };
918 suspend {
919 self.posixFsRequest(&req_node);
1074 };
1075 suspend {
1076 self.posixFsRequest(&req_node);
1077 }
1078 return req_node.data.msg.pwritev.result;
1079 } else {
1080 while (true) {
1081 return os.pwritev(fd, iov, offset) catch |err| switch (err) {
1082 error.WouldBlock => {
1083 self.waitUntilFdWritable(fd);
1084 continue;
1085 },
1086 else => return err,
1087 };
1088 }
1089 }
1090 }
1091
1092 pub fn sendto(
1093 self: *Loop,
1094 /// The file descriptor of the sending socket.
1095 sockfd: os.fd_t,
1096 /// Message to send.
1097 buf: []const u8,
1098 flags: u32,
1099 dest_addr: ?*const os.sockaddr,
1100 addrlen: os.socklen_t,
1101 ) os.SendError!usize {
1102 while (true) {
1103 return os.sendto(sockfd, buf, flags, dest_addr, addrlen) catch |err| switch (err) {
1104 error.WouldBlock => {
1105 self.waitUntilFdWritable(sockfd);
1106 continue;
1107 },
1108 else => return err,
1109 };
1110 }
1111 }
1112
1113 pub fn recvfrom(
1114 sockfd: os.fd_t,
1115 buf: []u8,
1116 flags: u32,
1117 src_addr: ?*os.sockaddr,
1118 addrlen: ?*os.socklen_t,
1119 ) os.RecvFromError!usize {
1120 while (true) {
1121 return os.recvfrom(sockfd, buf, flags, src_addr, addrlen) catch |err| switch (err) {
1122 error.WouldBlock => {
1123 self.waitUntilFdReadable(sockfd);
1124 continue;
1125 },
1126 else => return err,
1127 };
9201128 }
921 return req_node.data.msg.pwritev.result;
9221129 }
9231130
9241131 /// Performs an async `os.faccessatZ` using a separate thread.
......@@ -1073,6 +1280,9 @@ pub const Loop = struct {
10731280 .writev => |*msg| {
10741281 msg.result = os.writev(msg.fd, msg.iov);
10751282 },
1283 .pwrite => |*msg| {
1284 msg.result = os.pwrite(msg.fd, msg.bytes, msg.offset);
1285 },
10761286 .pwritev => |*msg| {
10771287 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
10781288 },
......@@ -1142,6 +1352,7 @@ pub const Loop = struct {
11421352 readv: ReadV,
11431353 write: Write,
11441354 writev: WriteV,
1355 pwrite: PWrite,
11451356 pwritev: PWriteV,
11461357 pread: PRead,
11471358 preadv: PReadV,
......@@ -1185,6 +1396,15 @@ pub const Loop = struct {
11851396 pub const Error = os.WriteError;
11861397 };
11871398
1399 pub const PWrite = struct {
1400 fd: os.fd_t,
1401 bytes: []const u8,
1402 offset: usize,
1403 result: Error!usize,
1404
1405 pub const Error = os.PWriteError;
1406 };
1407
11881408 pub const PWriteV = struct {
11891409 fd: os.fd_t,
11901410 iov: []const os.iovec_const,
lib/std/fifo.zig+11-1
......@@ -186,7 +186,9 @@ pub fn LinearFifo(
186186 } else {
187187 var head = self.head + count;
188188 if (powers_of_two) {
189 head &= self.buf.len - 1;
189 // Note it is safe to do a wrapping subtract as
190 // bitwise & with all 1s is a noop
191 head &= self.buf.len -% 1;
190192 } else {
191193 head %= self.buf.len;
192194 }
......@@ -376,6 +378,14 @@ pub fn LinearFifo(
376378 };
377379}
378380
381test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" {
382 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
383 defer fifo.deinit();
384
385 // If overflow is not explicitly allowed this will crash in debug / safe mode
386 fifo.discard(0);
387}
388
379389test "LinearFifo(u8, .Dynamic)" {
380390 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
381391 defer fifo.deinit();
lib/std/fs/file.zig+40-24
......@@ -414,10 +414,12 @@ pub const File = struct {
414414 pub fn read(self: File, buffer: []u8) ReadError!usize {
415415 if (is_windows) {
416416 return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
417 } else if (self.capable_io_mode != self.intended_io_mode) {
418 return std.event.Loop.instance.?.read(self.handle, buffer);
419 } else {
417 }
418
419 if (self.intended_io_mode == .blocking) {
420420 return os.read(self.handle, buffer);
421 } else {
422 return std.event.Loop.instance.?.read(self.handle, buffer, self.capable_io_mode != self.intended_io_mode);
421423 }
422424 }
423425
......@@ -436,10 +438,12 @@ pub const File = struct {
436438 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
437439 if (is_windows) {
438440 return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
439 } else if (self.capable_io_mode != self.intended_io_mode) {
440 return std.event.Loop.instance.?.pread(self.handle, buffer, offset);
441 } else {
441 }
442
443 if (self.intended_io_mode == .blocking) {
442444 return os.pread(self.handle, buffer, offset);
445 } else {
446 return std.event.Loop.instance.?.pread(self.handle, buffer, offset, self.capable_io_mode != self.intended_io_mode);
443447 }
444448 }
445449
......@@ -461,10 +465,12 @@ pub const File = struct {
461465 if (iovecs.len == 0) return @as(usize, 0);
462466 const first = iovecs[0];
463467 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
464 } else if (self.capable_io_mode != self.intended_io_mode) {
465 return std.event.Loop.instance.?.readv(self.handle, iovecs);
466 } else {
468 }
469
470 if (self.intended_io_mode == .blocking) {
467471 return os.readv(self.handle, iovecs);
472 } else {
473 return std.event.Loop.instance.?.readv(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
468474 }
469475 }
470476
......@@ -500,10 +506,12 @@ pub const File = struct {
500506 if (iovecs.len == 0) return @as(usize, 0);
501507 const first = iovecs[0];
502508 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
503 } else if (self.capable_io_mode != self.intended_io_mode) {
504 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);
505 } else {
509 }
510
511 if (self.intended_io_mode == .blocking) {
506512 return os.preadv(self.handle, iovecs, offset);
513 } else {
514 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
507515 }
508516 }
509517
......@@ -539,10 +547,12 @@ pub const File = struct {
539547 pub fn write(self: File, bytes: []const u8) WriteError!usize {
540548 if (is_windows) {
541549 return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
542 } else if (self.capable_io_mode != self.intended_io_mode) {
543 return std.event.Loop.instance.?.write(self.handle, bytes);
544 } else {
550 }
551
552 if (self.intended_io_mode == .blocking) {
545553 return os.write(self.handle, bytes);
554 } else {
555 return std.event.Loop.instance.?.write(self.handle, bytes, self.capable_io_mode != self.intended_io_mode);
546556 }
547557 }
548558
......@@ -556,10 +566,12 @@ pub const File = struct {
556566 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
557567 if (is_windows) {
558568 return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
559 } else if (self.capable_io_mode != self.intended_io_mode) {
560 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);
561 } else {
569 }
570
571 if (self.intended_io_mode == .blocking) {
562572 return os.pwrite(self.handle, bytes, offset);
573 } else {
574 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset, self.capable_io_mode != self.intended_io_mode);
563575 }
564576 }
565577
......@@ -576,10 +588,12 @@ pub const File = struct {
576588 if (iovecs.len == 0) return @as(usize, 0);
577589 const first = iovecs[0];
578590 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
579 } else if (self.capable_io_mode != self.intended_io_mode) {
580 return std.event.Loop.instance.?.writev(self.handle, iovecs);
581 } else {
591 }
592
593 if (self.intended_io_mode == .blocking) {
582594 return os.writev(self.handle, iovecs);
595 } else {
596 return std.event.Loop.instance.?.writev(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
583597 }
584598 }
585599
......@@ -607,10 +621,12 @@ pub const File = struct {
607621 if (iovecs.len == 0) return @as(usize, 0);
608622 const first = iovecs[0];
609623 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
610 } else if (self.capable_io_mode != self.intended_io_mode) {
611 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);
612 } else {
624 }
625
626 if (self.intended_io_mode == .blocking) {
613627 return os.pwritev(self.handle, iovecs, offset);
628 } else {
629 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
614630 }
615631 }
616632
lib/std/fs/test.zig+23
......@@ -813,3 +813,26 @@ fn run_lock_file_test(contexts: []FileLockTestContext) !void {
813813 try threads.append(try std.Thread.spawn(ctx, FileLockTestContext.run));
814814 }
815815}
816
817test "deleteDir" {
818 var tmp_dir = tmpDir(.{});
819 defer tmp_dir.cleanup();
820
821 // deleting a non-existent directory
822 testing.expectError(error.FileNotFound, tmp_dir.dir.deleteDir("test_dir"));
823
824 var dir = try tmp_dir.dir.makeOpenPath("test_dir", .{});
825 var file = try dir.createFile("test_file", .{});
826 file.close();
827 dir.close();
828
829 // deleting a non-empty directory
830 testing.expectError(error.DirNotEmpty, tmp_dir.dir.deleteDir("test_dir"));
831
832 dir = try tmp_dir.dir.openDir("test_dir", .{});
833 try dir.deleteFile("test_file");
834 dir.close();
835
836 // deleting an empty directory
837 try tmp_dir.dir.deleteDir("test_dir");
838}
lib/std/heap.zig+7
......@@ -919,6 +919,13 @@ pub fn testAllocator(base_allocator: *mem.Allocator) !void {
919919 const zero_bit_ptr = try allocator.create(u0);
920920 zero_bit_ptr.* = 0;
921921 allocator.destroy(zero_bit_ptr);
922
923 const oversize = try allocator.allocAdvanced(u32, null, 5, .at_least);
924 testing.expect(oversize.len >= 5);
925 for (oversize) |*item| {
926 item.* = 0xDEADBEEF;
927 }
928 allocator.free(oversize);
922929}
923930
924931pub fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void {
lib/std/heap/arena_allocator.zig+15-6
......@@ -75,13 +75,22 @@ pub const ArenaAllocator = struct {
7575 const adjusted_addr = mem.alignForward(addr, ptr_align);
7676 const adjusted_index = self.state.end_index + (adjusted_addr - addr);
7777 const new_end_index = adjusted_index + n;
78 if (new_end_index > cur_buf.len) {
79 cur_node = try self.createNode(cur_buf.len, n + ptr_align);
80 continue;
78
79 if (new_end_index <= cur_buf.len) {
80 const result = cur_buf[adjusted_index..new_end_index];
81 self.state.end_index = new_end_index;
82 return result;
8183 }
82 const result = cur_buf[adjusted_index..new_end_index];
83 self.state.end_index = new_end_index;
84 return result;
84
85 const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
86 // Try to grow the buffer in-place
87 cur_node.data = self.child_allocator.resize(cur_node.data, bigger_buf_size) catch |err| switch (err) {
88 error.OutOfMemory => {
89 // Allocate a new node if that's not possible
90 cur_node = try self.createNode(cur_buf.len, n + ptr_align);
91 continue;
92 },
93 };
8594 }
8695 }
8796
lib/std/net.zig+36-14
......@@ -614,11 +614,11 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
614614
615615 var addr = try std.net.Address.initUnix(path);
616616
617 try os.connect(
618 sockfd,
619 &addr.any,
620 addr.getOsSockLen(),
621 );
617 if (std.io.is_async) {
618 try loop.connect(sockfd, &addr.any, addr.getOsSockLen());
619 } else {
620 try os.connect(sockfd, &addr.any, addr.getOsSockLen());
621 }
622622
623623 return fs.File{
624624 .handle = sockfd,
......@@ -677,7 +677,13 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
677677 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
678678 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
679679 errdefer os.close(sockfd);
680 try os.connect(sockfd, &address.any, address.getOsSockLen());
680
681 if (std.io.is_async) {
682 const loop = std.event.Loop.instance orelse return error.WouldBlock;
683 try loop.connect(sockfd, &address.any, address.getOsSockLen());
684 } else {
685 try os.connect(sockfd, &address.any, address.getOsSockLen());
686 }
681687
682688 return fs.File{ .handle = sockfd };
683689}
......@@ -1429,7 +1435,11 @@ fn resMSendRc(
14291435 if (answers[i].len == 0) {
14301436 var j: usize = 0;
14311437 while (j < ns.len) : (j += 1) {
1432 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1438 if (std.io.is_async) {
1439 _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1440 } else {
1441 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1442 }
14331443 }
14341444 }
14351445 }
......@@ -1444,7 +1454,10 @@ fn resMSendRc(
14441454
14451455 while (true) {
14461456 var sl_copy = sl;
1447 const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
1457 const rlen = if (std.io.is_async)
1458 std.event.Loop.instance.?.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break
1459 else
1460 os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
14481461
14491462 // Ignore non-identifiable packets
14501463 if (rlen < 4) continue;
......@@ -1470,7 +1483,11 @@ fn resMSendRc(
14701483 0, 3 => {},
14711484 2 => if (servfail_retry != 0) {
14721485 servfail_retry -= 1;
1473 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1486 if (std.io.is_async) {
1487 _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1488 } else {
1489 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1490 }
14741491 },
14751492 else => continue,
14761493 }
......@@ -1661,18 +1678,23 @@ pub const StreamServer = struct {
16611678
16621679 /// If this function succeeds, the returned `Connection` is a caller-managed resource.
16631680 pub fn accept(self: *StreamServer) AcceptError!Connection {
1664 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
1665 const accept_flags = nonblock | os.SOCK_CLOEXEC;
16661681 var accepted_addr: Address = undefined;
16671682 var adr_len: os.socklen_t = @sizeOf(Address);
1668 if (os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
1683 const accept_result = blk: {
1684 if (std.io.is_async) {
1685 const loop = std.event.Loop.instance orelse return error.UnexpectedError;
1686 break :blk loop.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
1687 } else {
1688 break :blk os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
1689 }
1690 };
1691
1692 if (accept_result) |fd| {
16691693 return Connection{
16701694 .file = fs.File{ .handle = fd },
16711695 .address = accepted_addr,
16721696 };
16731697 } else |err| switch (err) {
1674 // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
1675 // is handled by os.accept4.
16761698 error.WouldBlock => unreachable,
16771699 else => |e| return e,
16781700 }
lib/std/os.zig+34-90
......@@ -314,8 +314,8 @@ pub const ReadError = error{
314314
315315/// Returns the number of bytes that were read, which can be less than
316316/// buf.len. If 0 bytes were read, that means EOF.
317/// If the application has a global event loop enabled, EAGAIN is handled
318/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
317/// If `fd` is opened in non blocking mode, the function will return error.WouldBlock
318/// when EAGAIN is received.
319319///
320320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
321321/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
......@@ -366,12 +366,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
366366 EINTR => continue,
367367 EINVAL => unreachable,
368368 EFAULT => unreachable,
369 EAGAIN => if (std.event.Loop.instance) |loop| {
370 loop.waitUntilFdReadable(fd);
371 continue;
372 } else {
373 return error.WouldBlock;
374 },
369 EAGAIN => return error.WouldBlock,
375370 EBADF => return error.NotOpenForReading, // Can be a race condition.
376371 EIO => return error.InputOutput,
377372 EISDIR => return error.IsDir,
......@@ -387,8 +382,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
387382
388383/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
389384///
390/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
391/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
385/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
386/// return error.WouldBlock when EAGAIN is received.
392387/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
393388/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
394389///
......@@ -428,12 +423,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
428423 EINTR => continue,
429424 EINVAL => unreachable,
430425 EFAULT => unreachable,
431 EAGAIN => if (std.event.Loop.instance) |loop| {
432 loop.waitUntilFdReadable(fd);
433 continue;
434 } else {
435 return error.WouldBlock;
436 },
426 EAGAIN => return error.WouldBlock,
437427 EBADF => return error.NotOpenForReading, // can be a race condition
438428 EIO => return error.InputOutput,
439429 EISDIR => return error.IsDir,
......@@ -450,8 +440,8 @@ pub const PReadError = ReadError || error{Unseekable};
450440///
451441/// Retries when interrupted by a signal.
452442///
453/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
454/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
443/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
444/// return error.WouldBlock when EAGAIN is received.
455445/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
456446/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
457447pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
......@@ -492,12 +482,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
492482 EINTR => continue,
493483 EINVAL => unreachable,
494484 EFAULT => unreachable,
495 EAGAIN => if (std.event.Loop.instance) |loop| {
496 loop.waitUntilFdReadable(fd);
497 continue;
498 } else {
499 return error.WouldBlock;
500 },
485 EAGAIN => return error.WouldBlock,
501486 EBADF => return error.NotOpenForReading, // Can be a race condition.
502487 EIO => return error.InputOutput,
503488 EISDIR => return error.IsDir,
......@@ -586,8 +571,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
586571///
587572/// Retries when interrupted by a signal.
588573///
589/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
590/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
574/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
575/// return error.WouldBlock when EAGAIN is received.
591576/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
592577/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
593578///
......@@ -637,12 +622,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
637622 EINTR => continue,
638623 EINVAL => unreachable,
639624 EFAULT => unreachable,
640 EAGAIN => if (std.event.Loop.instance) |loop| {
641 loop.waitUntilFdReadable(fd);
642 continue;
643 } else {
644 return error.WouldBlock;
645 },
625 EAGAIN => return error.WouldBlock,
646626 EBADF => return error.NotOpenForReading, // can be a race condition
647627 EIO => return error.InputOutput,
648628 EISDIR => return error.IsDir,
......@@ -687,8 +667,8 @@ pub const WriteError = error{
687667/// another write() call to transfer the remaining bytes. The subsequent call will either
688668/// transfer further bytes or may result in an error (e.g., if the disk is now full).
689669///
690/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
691/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
670/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
671/// return error.WouldBlock when EAGAIN is received.
692672/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
693673/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
694674///
......@@ -741,12 +721,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
741721 EINTR => continue,
742722 EINVAL => unreachable,
743723 EFAULT => unreachable,
744 EAGAIN => if (std.event.Loop.instance) |loop| {
745 loop.waitUntilFdWritable(fd);
746 continue;
747 } else {
748 return error.WouldBlock;
749 },
724 EAGAIN => return error.WouldBlock,
750725 EBADF => return error.NotOpenForWriting, // can be a race condition.
751726 EDESTADDRREQ => unreachable, // `connect` was never called.
752727 EDQUOT => return error.DiskQuota,
......@@ -772,8 +747,8 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
772747/// another write() call to transfer the remaining bytes. The subsequent call will either
773748/// transfer further bytes or may result in an error (e.g., if the disk is now full).
774749///
775/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
776/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
750/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
751/// return error.WouldBlock when EAGAIN is received.k`.
777752/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
778753/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
779754///
......@@ -814,12 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
814789 EINTR => continue,
815790 EINVAL => unreachable,
816791 EFAULT => unreachable,
817 EAGAIN => if (std.event.Loop.instance) |loop| {
818 loop.waitUntilFdWritable(fd);
819 continue;
820 } else {
821 return error.WouldBlock;
822 },
792 EAGAIN => return error.WouldBlock,
823793 EBADF => return error.NotOpenForWriting, // Can be a race condition.
824794 EDESTADDRREQ => unreachable, // `connect` was never called.
825795 EDQUOT => return error.DiskQuota,
......@@ -847,8 +817,8 @@ pub const PWriteError = WriteError || error{Unseekable};
847817/// another write() call to transfer the remaining bytes. The subsequent call will either
848818/// transfer further bytes or may result in an error (e.g., if the disk is now full).
849819///
850/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
851/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
820/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
821/// return error.WouldBlock when EAGAIN is received.
852822/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
853823/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
854824///
......@@ -905,12 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
905875 EINTR => continue,
906876 EINVAL => unreachable,
907877 EFAULT => unreachable,
908 EAGAIN => if (std.event.Loop.instance) |loop| {
909 loop.waitUntilFdWritable(fd);
910 continue;
911 } else {
912 return error.WouldBlock;
913 },
878 EAGAIN => return error.WouldBlock,
914879 EBADF => return error.NotOpenForWriting, // Can be a race condition.
915880 EDESTADDRREQ => unreachable, // `connect` was never called.
916881 EDQUOT => return error.DiskQuota,
......@@ -939,8 +904,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
939904/// another write() call to transfer the remaining bytes. The subsequent call will either
940905/// transfer further bytes or may result in an error (e.g., if the disk is now full).
941906///
942/// If the application has a global event loop enabled, EAGAIN is handled
943/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
907/// If `fd` is opened in non blocking mode, the function will
908/// return error.WouldBlock when EAGAIN is received.
944909///
945910/// The following systems do not have this syscall, and will return partial writes if more than one
946911/// vector is provided:
......@@ -993,12 +958,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
993958 EINTR => continue,
994959 EINVAL => unreachable,
995960 EFAULT => unreachable,
996 EAGAIN => if (std.event.Loop.instance) |loop| {
997 loop.waitUntilFdWritable(fd);
998 continue;
999 } else {
1000 return error.WouldBlock;
1001 },
961 EAGAIN => return error.WouldBlock,
1002962 EBADF => return error.NotOpenForWriting, // Can be a race condition.
1003963 EDESTADDRREQ => unreachable, // `connect` was never called.
1004964 EDQUOT => return error.DiskQuota,
......@@ -2846,8 +2806,8 @@ pub const AcceptError = error{
28462806} || UnexpectedError;
28472807
28482808/// Accept a connection on a socket.
2849/// If the application has a global event loop enabled, EAGAIN is handled
2850/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
2809/// If `sockfd` is opened in non blocking mode, the function will
2810/// return error.WouldBlock when EAGAIN is received.
28512811pub fn accept(
28522812 /// This argument is a socket that has been created with `socket`, bound to a local address
28532813 /// with `bind`, and is listening for connections after a `listen`.
......@@ -2890,12 +2850,7 @@ pub fn accept(
28902850 return fd;
28912851 },
28922852 EINTR => continue,
2893 EAGAIN => if (std.event.Loop.instance) |loop| {
2894 loop.waitUntilFdReadable(sockfd);
2895 continue;
2896 } else {
2897 return error.WouldBlock;
2898 },
2853 EAGAIN => return error.WouldBlock,
28992854 EBADF => unreachable, // always a race condition
29002855 ECONNABORTED => return error.ConnectionAborted,
29012856 EFAULT => unreachable,
......@@ -3081,6 +3036,8 @@ pub const ConnectError = error{
30813036} || UnexpectedError;
30823037
30833038/// Initiate a connection on a socket.
3039/// If `sockfd` is opened in non blocking mode, the function will
3040/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.
30843041pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
30853042 if (builtin.os.tag == .windows) {
30863043 const rc = windows.ws2_32.connect(sockfd, sock_addr, len);
......@@ -3113,11 +3070,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
31133070 EADDRINUSE => return error.AddressInUse,
31143071 EADDRNOTAVAIL => return error.AddressNotAvailable,
31153072 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
3116 EAGAIN, EINPROGRESS => {
3117 const loop = std.event.Loop.instance orelse return error.WouldBlock;
3118 loop.waitUntilFdWritable(sockfd);
3119 return getsockoptError(sockfd);
3120 },
3073 EAGAIN, EINPROGRESS => return error.WouldBlock,
31213074 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
31223075 EBADF => unreachable, // sockfd is not a valid open file descriptor.
31233076 ECONNREFUSED => return error.ConnectionRefused,
......@@ -4620,14 +4573,8 @@ pub fn sendto(
46204573 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
46214574 switch (errno(rc)) {
46224575 0 => return @intCast(usize, rc),
4623
46244576 EACCES => return error.AccessDenied,
4625 EAGAIN => if (std.event.Loop.instance) |loop| {
4626 loop.waitUntilFdWritable(sockfd);
4627 continue;
4628 } else {
4629 return error.WouldBlock;
4630 },
4577 EAGAIN => return error.WouldBlock,
46314578 EALREADY => return error.FastOpenAlreadyInProgress,
46324579 EBADF => unreachable, // always a race condition
46334580 ECONNRESET => return error.ConnectionResetByPeer,
......@@ -5106,6 +5053,8 @@ pub const RecvFromError = error{
51065053 SystemResources,
51075054} || UnexpectedError;
51085055
5056/// If `sockfd` is opened in non blocking mode, the function will
5057/// return error.WouldBlock when EAGAIN is received.
51095058pub fn recvfrom(
51105059 sockfd: fd_t,
51115060 buf: []u8,
......@@ -5123,12 +5072,7 @@ pub fn recvfrom(
51235072 ENOTCONN => unreachable,
51245073 ENOTSOCK => unreachable,
51255074 EINTR => continue,
5126 EAGAIN => if (std.event.Loop.instance) |loop| {
5127 loop.waitUntilFdReadable(sockfd);
5128 continue;
5129 } else {
5130 return error.WouldBlock;
5131 },
5075 EAGAIN => return error.WouldBlock,
51325076 ENOMEM => return error.SystemResources,
51335077 ECONNREFUSED => return error.ConnectionRefused,
51345078 else => |err| return unexpectedErrno(err),
lib/std/os/uefi/tables/system_table.zig+1-1
......@@ -35,7 +35,7 @@ pub const SystemTable = extern struct {
3535 runtime_services: *RuntimeServices,
3636 boot_services: ?*BootServices,
3737 number_of_table_entries: usize,
38 configuration_table: *ConfigurationTable,
38 configuration_table: [*]ConfigurationTable,
3939
4040 pub const signature: u64 = 0x5453595320494249;
4141 pub const revision_1_02: u32 = (1 << 16) | 2;
lib/std/os/windows.zig+17-1
......@@ -765,6 +765,7 @@ pub const DeleteFileError = error{
765765 Unexpected,
766766 NotDir,
767767 IsDir,
768 DirNotEmpty,
768769};
769770
770771pub const DeleteFileOptions = struct {
......@@ -819,7 +820,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
819820 0,
820821 );
821822 switch (rc) {
822 .SUCCESS => return CloseHandle(tmp_handle),
823 .SUCCESS => CloseHandle(tmp_handle),
823824 .OBJECT_NAME_INVALID => unreachable,
824825 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
825826 .INVALID_PARAMETER => unreachable,
......@@ -828,6 +829,21 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
828829 .SHARING_VIOLATION => return error.FileBusy,
829830 else => return unexpectedStatus(rc),
830831 }
832
833 // If a directory fails to be deleted, CloseHandle will still report success
834 // Check if the directory still exists and return error.DirNotEmpty if true
835 if (options.remove_dir) {
836 var basic_info: FILE_BASIC_INFORMATION = undefined;
837 switch (ntdll.NtQueryAttributesFile(&attr, &basic_info)) {
838 .SUCCESS => return error.DirNotEmpty,
839 .OBJECT_NAME_NOT_FOUND => return,
840 .OBJECT_PATH_NOT_FOUND => return,
841 .INVALID_PARAMETER => unreachable,
842 .ACCESS_DENIED => return error.AccessDenied,
843 .OBJECT_PATH_SYNTAX_BAD => unreachable,
844 else => |urc| return unexpectedStatus(urc),
845 }
846 }
831847}
832848
833849pub const MoveFileError = error{ FileNotFound, Unexpected };
lib/std/zig/ast.zig+9
......@@ -823,6 +823,15 @@ pub const Node = struct {
823823 }
824824 }
825825
826 pub fn findFirstWithId(self: *Node, id: Id) ?*Node {
827 if (self.id == id) return self;
828 var child_i: usize = 0;
829 while (self.iterate(child_i)) |child| : (child_i += 1) {
830 if (child.findFirstWithId(id)) |result| return result;
831 }
832 return null;
833 }
834
826835 pub fn dump(self: *Node, indent: usize) void {
827836 {
828837 var i: usize = 0;
lib/std/zig/parser_test.zig+325-3
......@@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {
13011301 \\const a = []u8{
13021302 \\ 1, 2,
13031303 \\ 3, 4,
1304 \\ 5, 6, // blah
1305 \\ 7, 8,
1304 \\ 5,
1305 \\ 6, // blah
1306 \\ 7,
1307 \\ 8,
13061308 \\};
13071309 \\const a = []u8{
13081310 \\ 1, 2,
......@@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
13721374 \\ \\ZIG_C_HEADER_FILES {}
13731375 \\ \\ZIG_DIA_GUIDS_LIB {}
13741376 \\ \\
1375 \\ ,
1377 \\ ,
13761378 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
13771379 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
13781380 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
......@@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {
33213323 );
33223324}
33233325
3326test "zig fmt: comments in ternary ifs" {
3327 try testCanonical(
3328 \\const x = if (true) {
3329 \\ 1;
3330 \\} else if (false)
3331 \\ // Comment
3332 \\ 0;
3333 \\const y = if (true)
3334 \\ // Comment
3335 \\ 1
3336 \\else
3337 \\ 0;
3338 \\
3339 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3340 \\
3341 );
3342}
3343
3344test "zig fmt: test comments in field access chain" {
3345 try testCanonical(
3346 \\pub const str = struct {
3347 \\ pub const Thing = more.more //
3348 \\ .more() //
3349 \\ .more().more() //
3350 \\ .more() //
3351 \\ // .more() //
3352 \\ .more() //
3353 \\ .more();
3354 \\ data: Data,
3355 \\};
3356 \\
3357 \\pub const str = struct {
3358 \\ pub const Thing = more.more //
3359 \\ .more() //
3360 \\ // .more() //
3361 \\ // .more() //
3362 \\ // .more() //
3363 \\ .more() //
3364 \\ .more();
3365 \\ data: Data,
3366 \\};
3367 \\
3368 \\pub const str = struct {
3369 \\ pub const Thing = more //
3370 \\ .more //
3371 \\ .more() //
3372 \\ .more();
3373 \\ data: Data,
3374 \\};
3375 \\
3376 );
3377}
3378
3379test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
3380 try testCanonical(
3381 \\fn foo() void {
3382 \\ z.display_message_dialog(
3383 \\ *const [323:0]u8,
3384 \\ \\Message Text
3385 \\ \\------------
3386 \\ \\xxxxxxxxxxxx
3387 \\ \\xxxxxxxxxxxx
3388 \\ ,
3389 \\ g.GtkMessageType.GTK_MESSAGE_WARNING,
3390 \\ null,
3391 \\ );
3392 \\
3393 \\ z.display_message_dialog(*const [323:0]u8,
3394 \\ \\Message Text
3395 \\ \\------------
3396 \\ \\xxxxxxxxxxxx
3397 \\ \\xxxxxxxxxxxx
3398 \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
3399 \\}
3400 \\
3401 );
3402}
3403
3404test "zig fmt: Control flow statement as body of blockless if" {
3405 try testCanonical(
3406 \\pub fn main() void {
3407 \\ const zoom_node = if (focused_node == layout_first)
3408 \\ if (it.next()) {
3409 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3410 \\ } else null
3411 \\ else
3412 \\ focused_node;
3413 \\
3414 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3415 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3416 \\ } else null else
3417 \\ focused_node;
3418 \\
3419 \\ const zoom_node = if (focused_node == layout_first)
3420 \\ if (it.next()) {
3421 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3422 \\ } else null;
3423 \\
3424 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3425 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3426 \\ };
3427 \\
3428 \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
3429 \\ break node;
3430 \\ };
3431 \\
3432 \\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
3433 \\ 0 => 0,
3434 \\ } else
3435 \\ focused_node;
3436 \\}
3437 \\
3438 );
3439}
3440
3441test "zig fmt: " {
3442 try testCanonical(
3443 \\pub fn sendViewTags(self: Self) void {
3444 \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
3445 \\ while (it.next()) |node|
3446 \\ view_tags.append(node.view.current_tags) catch {
3447 \\ c.wl_resource_post_no_memory(self.wl_resource);
3448 \\ log.crit(.river_status, "out of memory", .{});
3449 \\ return;
3450 \\ };
3451 \\}
3452 \\
3453 );
3454}
3455
3456test "zig fmt: allow trailing line comments to do manual array formatting" {
3457 try testCanonical(
3458 \\fn foo() void {
3459 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3460 \\ 0x55, // push rbp
3461 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3462 \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3463 \\ });
3464 \\
3465 \\ di_buf.appendAssumeCapacity(&[_]u8{
3466 \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3467 \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3468 \\ DW.AT_low_pc, DW_FORM_addr,
3469 \\ DW.AT_high_pc, DW_FORM_addr,
3470 \\ DW.AT_name, DW_FORM_strp,
3471 \\ DW.AT_comp_dir, DW_FORM_strp,
3472 \\ DW.AT_producer, DW_FORM_strp,
3473 \\ DW.AT_language, DW_FORM_data2,
3474 \\ 0, 0, // sentinel
3475 \\ });
3476 \\
3477 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3478 \\ 0x55, // push rbp
3479 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3480 \\ // How do we handle this?
3481 \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3482 \\ // Here's a blank line, should that be allowed?
3483 \\
3484 \\ 0x48, 0x89, 0xe5,
3485 \\ 0x33, 0x45,
3486 \\ // Now the comment breaks a single line -- how do we handle this?
3487 \\ 0x88,
3488 \\ });
3489 \\}
3490 \\
3491 );
3492}
3493
3494test "zig fmt: multiline string literals should play nice with array initializers" {
3495 try testCanonical(
3496 \\fn main() void {
3497 \\ var a = .{.{.{.{.{.{.{.{
3498 \\ 0,
3499 \\ }}}}}}}};
3500 \\ myFunc(.{
3501 \\ "aaaaaaa", "bbbbbb", "ccccc",
3502 \\ "dddd", ("eee"), ("fff"),
3503 \\ ("gggg"),
3504 \\ // Line comment
3505 \\ \\Multiline String Literals can be quite long
3506 \\ ,
3507 \\ \\Multiline String Literals can be quite long
3508 \\ \\Multiline String Literals can be quite long
3509 \\ ,
3510 \\ \\Multiline String Literals can be quite long
3511 \\ \\Multiline String Literals can be quite long
3512 \\ \\Multiline String Literals can be quite long
3513 \\ \\Multiline String Literals can be quite long
3514 \\ ,
3515 \\ (
3516 \\ \\Multiline String Literals can be quite long
3517 \\ ),
3518 \\ .{
3519 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3520 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3521 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3522 \\ },
3523 \\ .{(
3524 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3525 \\ )},
3526 \\ .{
3527 \\ "xxxxxxx", "xxx",
3528 \\ (
3529 \\ \\ xxx
3530 \\ ),
3531 \\ "xxx", "xxx",
3532 \\ },
3533 \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
3534 \\ "aaaaaaa", "bbbbbb", "ccccc", // -
3535 \\ "dddd", ("eee"), ("fff"),
3536 \\ .{
3537 \\ "xxx", "xxx",
3538 \\ (
3539 \\ \\ xxx
3540 \\ ),
3541 \\ "xxxxxxxxxxxxxx", "xxx",
3542 \\ },
3543 \\ .{
3544 \\ (
3545 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3546 \\ ),
3547 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3548 \\ },
3549 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3550 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3551 \\ });
3552 \\}
3553 \\
3554 );
3555}
3556
3557test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
3558 try testCanonical(
3559 \\pub fn makeMemUndefined(qzz: []u8) i1 {
3560 \\ cases.add( // fixed bug #2032
3561 \\ "compile diagnostic string for top level decl type",
3562 \\ \\export fn entry() void {
3563 \\ \\ var foo: u32 = @This(){};
3564 \\ \\}
3565 \\ , &[_][]const u8{
3566 \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
3567 \\ });
3568 \\ @compileError(
3569 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3570 \\ \\ Consider providing your own hash function.
3571 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3572 \\ \\ Consider providing your own hash function.
3573 \\ );
3574 \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
3575 \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
3576 \\}
3577 \\
3578 \\// This looks like garbage don't do this
3579 \\const rparen = tree.prevToken(
3580 \\// the first token for the annotation expressions is the left
3581 \\// parenthesis, hence the need for two prevToken
3582 \\ if (fn_proto.getAlignExpr()) |align_expr|
3583 \\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
3584 \\else if (fn_proto.getSectionExpr()) |section_expr|
3585 \\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
3586 \\else if (fn_proto.getCallconvExpr()) |callconv_expr|
3587 \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
3588 \\else switch (fn_proto.return_type) {
3589 \\ .Explicit => |node| node.firstToken(),
3590 \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
3591 \\ .Invalid => unreachable,
3592 \\});
3593 \\
3594 );
3595}
3596
3597test "zig fmt: single argument trailing commas in @builtins()" {
3598 try testCanonical(
3599 \\pub fn foo(qzz: []u8) i1 {
3600 \\ @panic(
3601 \\ foo,
3602 \\ );
3603 \\ panic(
3604 \\ foo,
3605 \\ );
3606 \\ @panic(
3607 \\ foo,
3608 \\ bar,
3609 \\ );
3610 \\}
3611 \\
3612 );
3613}
3614
3615test "zig fmt: trailing comma should force multiline 1 column" {
3616 try testTransform(
3617 \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
3618 \\
3619 ,
3620 \\pub const UUID_NULL: uuid_t = [16]u8{
3621 \\ 0,
3622 \\ 0,
3623 \\ 0,
3624 \\ 0,
3625 \\};
3626 \\
3627 );
3628}
3629
3630test "zig fmt: function params should align nicely" {
3631 try testCanonical(
3632 \\pub fn foo() void {
3633 \\ cases.addRuntimeSafety("slicing operator with sentinel",
3634 \\ \\const std = @import("std");
3635 \\ ++ check_panic_msg ++
3636 \\ \\pub fn main() void {
3637 \\ \\ var buf = [4]u8{'a','b','c',0};
3638 \\ \\ const slice = buf[0..:0];
3639 \\ \\}
3640 \\ );
3641 \\}
3642 \\
3643 );
3644}
3645
33243646const std = @import("std");
33253647const mem = std.mem;
33263648const warn = std.debug.warn;
lib/std/zig/render.zig+241-139
......@@ -522,7 +522,11 @@ fn renderExpression(
522522 break :blk if (loc.line == 0) op_space else Space.Newline;
523523 };
524524
525 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
525 {
526 ais.pushIndent();
527 defer ais.popIndent();
528 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
529 }
526530 ais.pushIndentOneShot();
527531 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
528532 },
......@@ -710,141 +714,194 @@ fn renderExpression(
710714 .node => |node| tree.nextToken(node.lastToken()),
711715 };
712716
713 if (exprs.len == 0) {
714 switch (lhs) {
715 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
716 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
717 }
718
719 {
720 ais.pushIndent();
721 defer ais.popIndent();
722 try renderToken(tree, ais, lbrace, Space.None);
723 }
717 switch (lhs) {
718 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
719 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
720 }
724721
722 if (exprs.len == 0) {
723 try renderToken(tree, ais, lbrace, Space.None);
725724 return renderToken(tree, ais, rtoken, space);
726725 }
727 if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
726
727 if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
728728 const expr = exprs[0];
729729
730 switch (lhs) {
731 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
732 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
733 }
734730 try renderToken(tree, ais, lbrace, Space.None);
735731 try renderExpression(allocator, ais, tree, expr, Space.None);
736732 return renderToken(tree, ais, rtoken, space);
737733 }
738734
739 switch (lhs) {
740 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
741 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
742 }
743
744735 // scan to find row size
745 const maybe_row_size: ?usize = blk: {
746 var count: usize = 1;
747 for (exprs) |expr, i| {
748 if (i + 1 < exprs.len) {
749 const expr_last_token = expr.lastToken() + 1;
750 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i + 1].firstToken());
751 if (loc.line != 0) break :blk count;
752 count += 1;
753 } else {
754 const expr_last_token = expr.lastToken();
755 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
756 if (loc.line == 0) {
757 // all on one line
758 const src_has_trailing_comma = trailblk: {
759 const maybe_comma = tree.prevToken(rtoken);
760 break :trailblk tree.token_ids[maybe_comma] == .Comma;
761 };
762 if (src_has_trailing_comma) {
763 break :blk 1; // force row size 1
764 } else {
765 break :blk null; // no newlines
766 }
767 }
768 break :blk count;
769 }
770 }
771 unreachable;
772 };
773
774 if (maybe_row_size) |row_size| {
775 // A place to store the width of each expression and its column's maximum
776 var widths = try allocator.alloc(usize, exprs.len + row_size);
777 defer allocator.free(widths);
778 mem.set(usize, widths, 0);
779
780 var expr_widths = widths[0 .. widths.len - row_size];
781 var column_widths = widths[widths.len - row_size ..];
782
783 // Null ais for counting the printed length of each expression
784 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
785 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
786
787 for (exprs) |expr, i| {
788 counting_stream.bytes_written = 0;
789 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
790 const width = @intCast(usize, counting_stream.bytes_written);
791 const col = i % row_size;
792 column_widths[col] = std.math.max(column_widths[col], width);
793 expr_widths[i] = width;
794 }
795
736 if (rowSize(tree, exprs, rtoken) != null) {
796737 {
797738 ais.pushIndentNextLine();
798739 defer ais.popIndent();
799740 try renderToken(tree, ais, lbrace, Space.Newline);
800741
801 var col: usize = 1;
802 for (exprs) |expr, i| {
803 if (i + 1 < exprs.len) {
804 const next_expr = exprs[i + 1];
805 try renderExpression(allocator, ais, tree, expr, Space.None);
806
807 const comma = tree.nextToken(expr.*.lastToken());
808
809 if (col != row_size) {
810 try renderToken(tree, ais, comma, Space.Space); // ,
811
812 const padding = column_widths[i % row_size] - expr_widths[i];
813 try ais.writer().writeByteNTimes(' ', padding);
814
815 col += 1;
816 continue;
742 var expr_index: usize = 0;
743 while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
744 const row_exprs = exprs[expr_index..];
745 // A place to store the width of each expression and its column's maximum
746 var widths = try allocator.alloc(usize, row_exprs.len + row_size);
747 defer allocator.free(widths);
748 mem.set(usize, widths, 0);
749
750 var expr_newlines = try allocator.alloc(bool, row_exprs.len);
751 defer allocator.free(expr_newlines);
752 mem.set(bool, expr_newlines, false);
753
754 var expr_widths = widths[0 .. widths.len - row_size];
755 var column_widths = widths[widths.len - row_size ..];
756
757 // Find next row with trailing comment (if any) to end the current section
758 var section_end = sec_end: {
759 var this_line_first_expr: usize = 0;
760 var this_line_size = rowSize(tree, row_exprs, rtoken);
761 for (row_exprs) |expr, i| {
762 // Ignore comment on first line of this section
763 if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
764 // Track start of line containing comment
765 if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
766 this_line_first_expr = i;
767 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
768 }
769
770 const maybe_comma = expr.lastToken() + 1;
771 const maybe_comment = expr.lastToken() + 2;
772 if (maybe_comment < tree.token_ids.len) {
773 if (tree.token_ids[maybe_comma] == .Comma and
774 tree.token_ids[maybe_comment] == .LineComment and
775 tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
776 {
777 var comment_token_loc = tree.token_locs[maybe_comment];
778 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
779 if (!comment_is_empty) {
780 // Found row ending in comment
781 break :sec_end i - this_line_size.? + 1;
782 }
783 }
784 }
817785 }
818 col = 1;
786 break :sec_end row_exprs.len;
787 };
788 expr_index += section_end;
789
790 const section_exprs = row_exprs[0..section_end];
791
792 // Null stream for counting the printed length of each expression
793 var line_find_stream = std.io.findByteOutStream('\n', std.io.null_out_stream);
794 var counting_stream = std.io.countingOutStream(line_find_stream.writer());
795 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
796
797 // Calculate size of columns in current section
798 var column_counter: usize = 0;
799 var single_line = true;
800 for (section_exprs) |expr, i| {
801 if (i + 1 < section_exprs.len) {
802 counting_stream.bytes_written = 0;
803 line_find_stream.byte_found = false;
804 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
805 const width = @intCast(usize, counting_stream.bytes_written);
806 expr_widths[i] = width;
807 expr_newlines[i] = line_find_stream.byte_found;
808
809 if (!line_find_stream.byte_found) {
810 const column = column_counter % row_size;
811 column_widths[column] = std.math.max(column_widths[column], width);
812
813 const expr_last_token = expr.*.lastToken() + 1;
814 const next_expr = section_exprs[i + 1];
815 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
816 if (loc.line == 0) {
817 column_counter += 1;
818 } else {
819 single_line = false;
820 column_counter = 0;
821 }
822 } else {
823 single_line = false;
824 column_counter = 0;
825 }
826 } else {
827 counting_stream.bytes_written = 0;
828 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
829 const width = @intCast(usize, counting_stream.bytes_written);
830 expr_widths[i] = width;
831 expr_newlines[i] = line_find_stream.byte_found;
832
833 if (!line_find_stream.byte_found) {
834 const column = column_counter % row_size;
835 column_widths[column] = std.math.max(column_widths[column], width);
836 }
837 break;
838 }
839 }
819840
820 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
841 // Render exprs in current section
842 column_counter = 0;
843 var last_col_index: usize = row_size - 1;
844 for (section_exprs) |expr, i| {
845 if (i + 1 < section_exprs.len) {
846 const next_expr = section_exprs[i + 1];
847 try renderExpression(allocator, ais, tree, expr, Space.None);
848
849 const comma = tree.nextToken(expr.*.lastToken());
850
851 if (column_counter != last_col_index) {
852 if (!expr_newlines[i] and !expr_newlines[i + 1]) {
853 // Neither the current or next expression is multiline
854 try renderToken(tree, ais, comma, Space.Space); // ,
855 assert(column_widths[column_counter % row_size] >= expr_widths[i]);
856 const padding = column_widths[column_counter % row_size] - expr_widths[i];
857 try ais.writer().writeByteNTimes(' ', padding);
858
859 column_counter += 1;
860 continue;
861 }
862 }
863 if (single_line and row_size != 1) {
864 try renderToken(tree, ais, comma, Space.Space); // ,
865 continue;
866 }
867
868 column_counter = 0;
821869 try renderToken(tree, ais, comma, Space.Newline); // ,
870 try renderExtraNewline(tree, ais, next_expr);
822871 } else {
823 try renderToken(tree, ais, comma, Space.None); // ,
872 const maybe_comma = tree.nextToken(expr.*.lastToken());
873 if (tree.token_ids[maybe_comma] == .Comma) {
874 try renderExpression(allocator, ais, tree, expr, Space.None); // ,
875 try renderToken(tree, ais, maybe_comma, Space.Newline); // ,
876 } else {
877 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
878 }
824879 }
880 }
825881
826 try renderExtraNewline(tree, ais, next_expr);
827 } else {
828 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
882 if (expr_index == exprs.len) {
883 break;
829884 }
830885 }
831886 }
832 return renderToken(tree, ais, rtoken, space);
833 } else {
834 try renderToken(tree, ais, lbrace, Space.Space);
835 for (exprs) |expr, i| {
836 if (i + 1 < exprs.len) {
837 const next_expr = exprs[i + 1];
838 try renderExpression(allocator, ais, tree, expr, Space.None);
839 const comma = tree.nextToken(expr.*.lastToken());
840 try renderToken(tree, ais, comma, Space.Space); // ,
841 } else {
842 try renderExpression(allocator, ais, tree, expr, Space.Space);
843 }
844 }
845887
846888 return renderToken(tree, ais, rtoken, space);
847889 }
890
891 // Single line
892 try renderToken(tree, ais, lbrace, Space.Space);
893 for (exprs) |expr, i| {
894 if (i + 1 < exprs.len) {
895 const next_expr = exprs[i + 1];
896 try renderExpression(allocator, ais, tree, expr, Space.None);
897 const comma = tree.nextToken(expr.*.lastToken());
898 try renderToken(tree, ais, comma, Space.Space); // ,
899 } else {
900 try renderExpression(allocator, ais, tree, expr, Space.Space);
901 }
902 }
903
904 return renderToken(tree, ais, rtoken, space);
848905 },
849906
850907 .StructInitializer, .StructInitializerDot => {
......@@ -1004,21 +1061,29 @@ fn renderExpression(
10041061 };
10051062
10061063 if (src_has_trailing_comma) {
1007 try renderToken(tree, ais, lparen, Space.Newline);
1008
1009 const params = call.params();
1010 for (params) |param_node, i| {
1064 {
10111065 ais.pushIndent();
10121066 defer ais.popIndent();
10131067
1014 if (i + 1 < params.len) {
1015 const next_node = params[i + 1];
1016 try renderExpression(allocator, ais, tree, param_node, Space.None);
1017 const comma = tree.nextToken(param_node.lastToken());
1018 try renderToken(tree, ais, comma, Space.Newline); // ,
1019 try renderExtraNewline(tree, ais, next_node);
1020 } else {
1021 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1068 try renderToken(tree, ais, lparen, Space.Newline); // (
1069 const params = call.params();
1070 for (params) |param_node, i| {
1071 if (i + 1 < params.len) {
1072 const next_node = params[i + 1];
1073 try renderExpression(allocator, ais, tree, param_node, Space.None);
1074
1075 // Unindent the comma for multiline string literals
1076 const maybe_multiline_string = param_node.firstToken();
1077 const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine;
1078 if (is_multiline_string) ais.popIndent();
1079 defer if (is_multiline_string) ais.pushIndent();
1080
1081 const comma = tree.nextToken(param_node.lastToken());
1082 try renderToken(tree, ais, comma, Space.Newline); // ,
1083 try renderExtraNewline(tree, ais, next_node);
1084 } else {
1085 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1086 }
10221087 }
10231088 }
10241089 return renderToken(tree, ais, call.rtoken, space);
......@@ -1028,17 +1093,20 @@ fn renderExpression(
10281093
10291094 const params = call.params();
10301095 for (params) |param_node, i| {
1031 if (param_node.*.tag == .MultilineStringLiteral) ais.pushIndentOneShot();
1096 const maybe_comment = param_node.firstToken() - 1;
1097 const maybe_multiline_string = param_node.firstToken();
1098 if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) {
1099 ais.pushIndentOneShot();
1100 }
10321101
10331102 try renderExpression(allocator, ais, tree, param_node, Space.None);
10341103
10351104 if (i + 1 < params.len) {
1036 const next_param = params[i + 1];
10371105 const comma = tree.nextToken(param_node.lastToken());
10381106 try renderToken(tree, ais, comma, Space.Space);
10391107 }
10401108 }
1041 return renderToken(tree, ais, call.rtoken, space);
1109 return renderToken(tree, ais, call.rtoken, space); // )
10421110 },
10431111
10441112 .ArrayAccess => {
......@@ -1429,7 +1497,7 @@ fn renderExpression(
14291497 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
14301498
14311499 const src_params_trailing_comma = blk: {
1432 if (builtin_call.params_len < 2) break :blk false;
1500 if (builtin_call.params_len == 0) break :blk false;
14331501 const last_node = builtin_call.params()[builtin_call.params_len - 1];
14341502 const maybe_comma = tree.nextToken(last_node.lastToken());
14351503 break :blk tree.token_ids[maybe_comma] == .Comma;
......@@ -1443,6 +1511,10 @@ fn renderExpression(
14431511 // render all on one line, no trailing comma
14441512 const params = builtin_call.params();
14451513 for (params) |param_node, i| {
1514 const maybe_comment = param_node.firstToken() - 1;
1515 if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) {
1516 ais.pushIndentOneShot();
1517 }
14461518 try renderExpression(allocator, ais, tree, param_node, Space.None);
14471519
14481520 if (i + 1 < params.len) {
......@@ -1494,19 +1566,20 @@ fn renderExpression(
14941566 assert(tree.token_ids[lparen] == .LParen);
14951567
14961568 const rparen = tree.prevToken(
1497 // the first token for the annotation expressions is the left
1498 // parenthesis, hence the need for two prevToken
1499 if (fn_proto.getAlignExpr()) |align_expr|
1500 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1501 else if (fn_proto.getSectionExpr()) |section_expr|
1502 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1503 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1504 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1505 else switch (fn_proto.return_type) {
1506 .Explicit => |node| node.firstToken(),
1507 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1508 .Invalid => unreachable,
1509 });
1569 // the first token for the annotation expressions is the left
1570 // parenthesis, hence the need for two prevToken
1571 if (fn_proto.getAlignExpr()) |align_expr|
1572 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1573 else if (fn_proto.getSectionExpr()) |section_expr|
1574 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1575 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1576 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1577 else switch (fn_proto.return_type) {
1578 .Explicit => |node| node.firstToken(),
1579 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1580 .Invalid => unreachable,
1581 },
1582 );
15101583 assert(tree.token_ids[rparen] == .RParen);
15111584
15121585 const src_params_trailing_comma = blk: {
......@@ -1758,7 +1831,7 @@ fn renderExpression(
17581831 }
17591832
17601833 if (while_node.payload) |payload| {
1761 const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
1834 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
17621835 try renderExpression(allocator, ais, tree, payload, payload_space);
17631836 }
17641837
......@@ -1873,7 +1946,12 @@ fn renderExpression(
18731946
18741947 if (src_has_newline) {
18751948 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1876 try renderToken(tree, ais, rparen, after_rparen_space); // )
1949
1950 {
1951 ais.pushIndent();
1952 defer ais.popIndent();
1953 try renderToken(tree, ais, rparen, after_rparen_space); // )
1954 }
18771955
18781956 if (if_node.payload) |payload| {
18791957 try renderExpression(allocator, ais, tree, payload, Space.Newline);
......@@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
25582636 else => try ais.writer().writeByte(byte),
25592637 };
25602638}
2639
2640fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
2641 const first_token = exprs[0].firstToken();
2642 const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);
2643 if (first_loc.line == 0) {
2644 const maybe_comma = tree.prevToken(rtoken);
2645 if (tree.token_ids[maybe_comma] == .Comma)
2646 return 1;
2647 return null; // no newlines
2648 }
2649
2650 var count: usize = 1;
2651 for (exprs) |expr, i| {
2652 if (i + 1 < exprs.len) {
2653 const expr_last_token = expr.lastToken() + 1;
2654 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken());
2655 if (loc.line != 0) return count;
2656 count += 1;
2657 } else {
2658 return count;
2659 }
2660 }
2661 unreachable;
2662}
lib/std/zig/tokenizer.zig+9
......@@ -1195,6 +1195,7 @@ pub const Tokenizer = struct {
11951195 },
11961196 .num_dot_hex => switch (c) {
11971197 '.' => {
1198 result.id = .IntegerLiteral;
11981199 self.index -= 1;
11991200 state = .start;
12001201 break;
......@@ -1758,6 +1759,14 @@ test "correctly parse pointer assignment" {
17581759 });
17591760}
17601761
1762test "tokenizer - range literals" {
1763 testTokenize("0...9", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral });
1764 testTokenize("'0'...'9'", &[_]Token.Id{ .CharLiteral, .Ellipsis3, .CharLiteral });
1765 testTokenize("0x00...0x09", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral });
1766 testTokenize("0b00...0b11", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral });
1767 testTokenize("0o00...0o11", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral });
1768}
1769
17611770test "tokenizer - number literals decimal" {
17621771 testTokenize("0", &[_]Token.Id{.IntegerLiteral});
17631772 testTokenize("1", &[_]Token.Id{.IntegerLiteral});
src/stage1/tokenizer.cpp+3-3
......@@ -1225,9 +1225,6 @@ void tokenize(Buf *buf, Tokenization *out) {
12251225 invalid_char_error(&t, c);
12261226 break;
12271227 }
1228 if (t.radix != 16 && t.radix != 10) {
1229 invalid_char_error(&t, c);
1230 }
12311228 t.state = TokenizeStateNumberDot;
12321229 break;
12331230 }
......@@ -1281,6 +1278,9 @@ void tokenize(Buf *buf, Tokenization *out) {
12811278 t.state = TokenizeStateStart;
12821279 continue;
12831280 }
1281 if (t.radix != 16 && t.radix != 10) {
1282 invalid_char_error(&t, c);
1283 }
12841284 t.pos -= 1;
12851285 t.state = TokenizeStateFloatFractionNoUnderscore;
12861286 assert(t.cur_tok->id == TokenIdIntLiteral);