| author | |
| committer | |
| log | 9f274e1f7df65472b0b312cbb6a559ebbaae7e1b |
| tree | 04269d3934963c66fdeb6eee94e057776056e57b |
| parent | 3342e28784b9ef7bf8356004a7b2698edcb70b40 |
Showcase that Zig can be a great option for high performance cryptography.
The AEGIS family of authenticated encryption algorithms was selected for
high-performance applications in the final portfolio of the CAESAR
competition.
They reuse the AES core function, but are substantially faster than the
CCM, GCM and OCB modes while offering a high level of security.
AEGIS algorithms are especially fast on CPUs with built-in AES support, and
the 128L variant fully takes advantage of the pipeline in modern Intel CPUs.
Performance of the Zig implementation is on par with libsodium.5 files changed, 242 insertions(+), 13 deletions(-)
lib/std/crypto.zig+1| ... | @@ -28,6 +28,7 @@ pub const aead = struct { | ... | @@ -28,6 +28,7 @@ pub const aead = struct { |
| 28 | pub const Gimli = @import("crypto/gimli.zig").Aead; | 28 | pub const Gimli = @import("crypto/gimli.zig").Aead; |
| 29 | pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; | 29 | pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; |
| 30 | pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; | 30 | pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; |
| 31 | pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L; | ||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | /// MAC functions requiring single-use secret keys. | 34 | /// MAC functions requiring single-use secret keys. |
lib/std/crypto/aegis.zig created+197| ... | @@ -0,0 +1,197 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const AESBlock = std.crypto.core.aes.Block; | ||
| 5 | |||
| 6 | const State = struct { | ||
| 7 | blocks: [8]AESBlock, | ||
| 8 | |||
| 9 | fn init(key: [16]u8, nonce: [16]u8) State { | ||
| 10 | const c1 = AESBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }); | ||
| 11 | const c2 = AESBlock.fromBytes(&[16]u8{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }); | ||
| 12 | const key_block = AESBlock.fromBytes(&key); | ||
| 13 | const nonce_block = AESBlock.fromBytes(&nonce); | ||
| 14 | const blocks = [8]AESBlock{ | ||
| 15 | key_block.xorBlocks(nonce_block), | ||
| 16 | c1, | ||
| 17 | c2, | ||
| 18 | c1, | ||
| 19 | key_block.xorBlocks(nonce_block), | ||
| 20 | key_block.xorBlocks(c2), | ||
| 21 | key_block.xorBlocks(c1), | ||
| 22 | key_block.xorBlocks(c2), | ||
| 23 | }; | ||
| 24 | var state = State{ .blocks = blocks }; | ||
| 25 | var i: usize = 0; | ||
| 26 | while (i < 10) : (i += 1) { | ||
| 27 | state.update(nonce_block, key_block); | ||
| 28 | } | ||
| 29 | return state; | ||
| 30 | } | ||
| 31 | |||
| 32 | inline fn update(state: *State, d1: AESBlock, d2: AESBlock) void { | ||
| 33 | const blocks = &state.blocks; | ||
| 34 | const tmp = blocks[7]; | ||
| 35 | comptime var i: usize = 7; | ||
| 36 | inline while (i > 0) : (i -= 1) { | ||
| 37 | blocks[i] = blocks[i - 1].encrypt(blocks[i]); | ||
| 38 | } | ||
| 39 | blocks[0] = tmp.encrypt(blocks[0]); | ||
| 40 | blocks[0] = blocks[0].xorBlocks(d1); | ||
| 41 | blocks[4] = blocks[4].xorBlocks(d2); | ||
| 42 | } | ||
| 43 | |||
| 44 | fn enc(state: *State, dst: []u8, src: []const u8) void { | ||
| 45 | const blocks = &state.blocks; | ||
| 46 | const msg0 = AESBlock.fromBytes(src[0..16]); | ||
| 47 | const msg1 = AESBlock.fromBytes(src[16..32]); | ||
| 48 | var tmp0 = msg0.xorBlocks(blocks[6]).xorBlocks(blocks[1]); | ||
| 49 | var tmp1 = msg1.xorBlocks(blocks[2]).xorBlocks(blocks[5]); | ||
| 50 | tmp0 = tmp0.xorBlocks(blocks[2].andBlocks(blocks[3])); | ||
| 51 | tmp1 = tmp1.xorBlocks(blocks[6].andBlocks(blocks[7])); | ||
| 52 | dst[0..16].* = tmp0.toBytes(); | ||
| 53 | dst[16..32].* = tmp1.toBytes(); | ||
| 54 | state.update(msg0, msg1); | ||
| 55 | } | ||
| 56 | |||
| 57 | fn dec(state: *State, dst: []u8, src: []const u8) void { | ||
| 58 | const blocks = &state.blocks; | ||
| 59 | var msg0 = AESBlock.fromBytes(src[0..16]).xorBlocks(blocks[6]).xorBlocks(blocks[1]); | ||
| 60 | var msg1 = AESBlock.fromBytes(src[16..32]).xorBlocks(blocks[2]).xorBlocks(blocks[5]); | ||
| 61 | msg0 = msg0.xorBlocks(blocks[2].andBlocks(blocks[3])); | ||
| 62 | msg1 = msg1.xorBlocks(blocks[6].andBlocks(blocks[7])); | ||
| 63 | dst[0..16].* = msg0.toBytes(); | ||
| 64 | dst[16..32].* = msg1.toBytes(); | ||
| 65 | state.update(msg0, msg1); | ||
| 66 | } | ||
| 67 | |||
| 68 | fn mac(state: *State, adlen: usize, mlen: usize) [16]u8 { | ||
| 69 | const blocks = &state.blocks; | ||
| 70 | var sizes: [16]u8 = undefined; | ||
| 71 | mem.writeIntLittle(u64, sizes[0..8], adlen * 8); | ||
| 72 | mem.writeIntLittle(u64, sizes[8..16], mlen * 8); | ||
| 73 | const tmp = AESBlock.fromBytes(&sizes).xorBlocks(blocks[2]); | ||
| 74 | var i: usize = 0; | ||
| 75 | while (i < 7) : (i += 1) { | ||
| 76 | state.update(tmp, tmp); | ||
| 77 | } | ||
| 78 | return blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]). | ||
| 79 | xorBlocks(blocks[5]).xorBlocks(blocks[6]).toBytes(); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | /// AEGIS is a very fast authenticated encryption system built on top of the core AES function. | ||
| 84 | /// | ||
| 85 | /// The 128L variant of AEGIS has a 128 bit key, a 128 bit nonce, and processes 256 bit message blocks. | ||
| 86 | /// It was designed to fully exploit the parallelism and built-in AES support of recent Intel and ARM CPUs. | ||
| 87 | /// | ||
| 88 | /// https://eprint.iacr.org/2013/695.pdf | ||
| 89 | pub const AEGIS128L = struct { | ||
| 90 | pub const tag_length = 16; | ||
| 91 | pub const nonce_length = 16; | ||
| 92 | pub const key_length = 16; | ||
| 93 | |||
| 94 | /// c: ciphertext: output buffer should be of size m.len | ||
| 95 | /// tag: authentication tag: output MAC | ||
| 96 | /// m: message | ||
| 97 | /// ad: Associated Data | ||
| 98 | /// npub: public nonce | ||
| 99 | /// k: private key | ||
| 100 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void { | ||
| 101 | assert(c.len == m.len); | ||
| 102 | var state = State.init(key, npub); | ||
| 103 | var src: [32]u8 align(16) = undefined; | ||
| 104 | var dst: [32]u8 align(16) = undefined; | ||
| 105 | var i: usize = 0; | ||
| 106 | while (i + 32 <= ad.len) : (i += 32) { | ||
| 107 | state.enc(&dst, ad[i..][0..32]); | ||
| 108 | } | ||
| 109 | if (ad.len % 32 != 0) { | ||
| 110 | mem.set(u8, src[0..], 0); | ||
| 111 | mem.copy(u8, src[0 .. ad.len % 32], ad[i .. i + ad.len % 32]); | ||
| 112 | state.enc(&dst, &src); | ||
| 113 | } | ||
| 114 | i = 0; | ||
| 115 | while (i + 32 <= m.len) : (i += 32) { | ||
| 116 | state.enc(c[i..][0..32], m[i..][0..32]); | ||
| 117 | } | ||
| 118 | if (m.len % 32 != 0) { | ||
| 119 | mem.set(u8, src[0..], 0); | ||
| 120 | mem.copy(u8, src[0 .. m.len % 32], m[i .. i + m.len % 32]); | ||
| 121 | state.enc(&dst, &src); | ||
| 122 | mem.copy(u8, c[i .. i + m.len % 32], dst[0 .. m.len % 32]); | ||
| 123 | } | ||
| 124 | tag.* = state.mac(ad.len, m.len); | ||
| 125 | } | ||
| 126 | |||
| 127 | /// m: message: output buffer should be of size c.len | ||
| 128 | /// c: ciphertext | ||
| 129 | /// tag: authentication tag | ||
| 130 | /// ad: Associated Data | ||
| 131 | /// npub: public nonce | ||
| 132 | /// k: private key | ||
| 133 | pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) !void { | ||
| 134 | assert(c.len == m.len); | ||
| 135 | var state = State.init(key, npub); | ||
| 136 | var src: [32]u8 align(16) = undefined; | ||
| 137 | var dst: [32]u8 align(16) = undefined; | ||
| 138 | var i: usize = 0; | ||
| 139 | while (i + 32 <= ad.len) : (i += 32) { | ||
| 140 | state.enc(&dst, ad[i..][0..32]); | ||
| 141 | } | ||
| 142 | if (ad.len % 32 != 0) { | ||
| 143 | mem.set(u8, src[0..], 0); | ||
| 144 | mem.copy(u8, src[0 .. ad.len % 32], ad[i .. i + ad.len % 32]); | ||
| 145 | state.enc(&dst, &src); | ||
| 146 | } | ||
| 147 | i = 0; | ||
| 148 | while (i + 32 <= m.len) : (i += 32) { | ||
| 149 | state.dec(m[i..][0..32], c[i..][0..32]); | ||
| 150 | } | ||
| 151 | if (m.len % 32 != 0) { | ||
| 152 | mem.set(u8, src[0..], 0); | ||
| 153 | mem.copy(u8, src[0 .. m.len % 32], c[i .. i + m.len % 32]); | ||
| 154 | state.dec(&dst, &src); | ||
| 155 | mem.copy(u8, m[i .. i + m.len % 32], dst[0 .. m.len % 32]); | ||
| 156 | mem.set(u8, dst[0 .. m.len % 32], 0); | ||
| 157 | const blocks = &state.blocks; | ||
| 158 | blocks[0] = blocks[0].xorBlocks(AESBlock.fromBytes(dst[0..16])); | ||
| 159 | blocks[4] = blocks[4].xorBlocks(AESBlock.fromBytes(dst[16..32])); | ||
| 160 | } | ||
| 161 | const computed_tag = state.mac(ad.len, m.len); | ||
| 162 | var acc: u8 = 0; | ||
| 163 | for (computed_tag) |_, j| { | ||
| 164 | acc |= (computed_tag[j] ^ tag[j]); | ||
| 165 | } | ||
| 166 | if (acc != 0) { | ||
| 167 | mem.set(u8, m, 0xaa); | ||
| 168 | return error.AuthenticationFailed; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | const htest = @import("test.zig"); | ||
| 174 | const testing = std.testing; | ||
| 175 | |||
| 176 | test "AEGIS128L" { | ||
| 177 | const key: [AEGIS128L.key_length]u8 = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** 14; | ||
| 178 | const nonce: [AEGIS128L.nonce_length]u8 = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** 13; | ||
| 179 | const ad = [8]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; | ||
| 180 | const m = [32]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; | ||
| 181 | var c: [m.len]u8 = undefined; | ||
| 182 | var m2: [m.len]u8 = undefined; | ||
| 183 | var tag: [AEGIS128L.tag_length]u8 = undefined; | ||
| 184 | |||
| 185 | AEGIS128L.encrypt(&c, &tag, &m, &ad, nonce, key); | ||
| 186 | try AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key); | ||
| 187 | testing.expectEqualSlices(u8, &m, &m2); | ||
| 188 | |||
| 189 | htest.assertEqual("79d94593d8c2119d7e8fd9b8fc77845c5c077a05b2528b6ac54b563aed8efe84", &c); | ||
| 190 | htest.assertEqual("cc6f3372f6aa1bb82388d695c3962d9a", &tag); | ||
| 191 | |||
| 192 | c[0] +%= 1; | ||
| 193 | testing.expectError(error.AuthenticationFailed, AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key)); | ||
| 194 | c[0] -%= 1; | ||
| 195 | tag[0] +%= 1; | ||
| 196 | testing.expectError(error.AuthenticationFailed, AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key)); | ||
| 197 | } | ||
lib/std/crypto/aes/aesni.zig+18-8| ... | @@ -84,11 +84,21 @@ pub const Block = struct { | ... | @@ -84,11 +84,21 @@ pub const Block = struct { |
| 84 | }; | 84 | }; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /// XOR the content of two blocks. | 87 | /// Apply the bitwise XOR operation to the content of two blocks. |
| 88 | pub inline fn xor(block1: Block, block2: Block) Block { | 88 | pub inline fn xorBlocks(block1: Block, block2: Block) Block { |
| 89 | return Block{ .repr = block1.repr ^ block2.repr }; | 89 | return Block{ .repr = block1.repr ^ block2.repr }; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | /// Apply the bitwise AND operation to the content of two blocks. | ||
| 93 | pub inline fn andBlocks(block1: Block, block2: Block) Block { | ||
| 94 | return Block{ .repr = block1.repr & block2.repr }; | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Apply the bitwise OR operation to the content of two blocks. | ||
| 98 | pub inline fn orBlocks(block1: Block, block2: Block) Block { | ||
| 99 | return Block{ .repr = block1.repr | block2.repr }; | ||
| 100 | } | ||
| 101 | |||
| 92 | /// Perform operations on multiple blocks in parallel. | 102 | /// Perform operations on multiple blocks in parallel. |
| 93 | pub const parallel = struct { | 103 | pub const parallel = struct { |
| 94 | /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation. | 104 | /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation. |
| ... | @@ -261,7 +271,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -261,7 +271,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 261 | /// Encrypt a single block. | 271 | /// Encrypt a single block. |
| 262 | pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { | 272 | pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { |
| 263 | const round_keys = ctx.key_schedule.round_keys; | 273 | const round_keys = ctx.key_schedule.round_keys; |
| 264 | var t = Block.fromBytes(src).xor(round_keys[0]); | 274 | var t = Block.fromBytes(src).xorBlocks(round_keys[0]); |
| 265 | comptime var i = 1; | 275 | comptime var i = 1; |
| 266 | inline while (i < rounds) : (i += 1) { | 276 | inline while (i < rounds) : (i += 1) { |
| 267 | t = t.encrypt(round_keys[i]); | 277 | t = t.encrypt(round_keys[i]); |
| ... | @@ -273,7 +283,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -273,7 +283,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 273 | /// Encrypt+XOR a single block. | 283 | /// Encrypt+XOR a single block. |
| 274 | pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void { | 284 | 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; | 285 | const round_keys = ctx.key_schedule.round_keys; |
| 276 | var t = Block.fromBytes(&counter).xor(round_keys[0]); | 286 | var t = Block.fromBytes(&counter).xorBlocks(round_keys[0]); |
| 277 | comptime var i = 1; | 287 | comptime var i = 1; |
| 278 | inline while (i < rounds) : (i += 1) { | 288 | inline while (i < rounds) : (i += 1) { |
| 279 | t = t.encrypt(round_keys[i]); | 289 | t = t.encrypt(round_keys[i]); |
| ... | @@ -288,7 +298,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -288,7 +298,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 288 | var ts: [count]Block = undefined; | 298 | var ts: [count]Block = undefined; |
| 289 | comptime var j = 0; | 299 | comptime var j = 0; |
| 290 | inline while (j < count) : (j += 1) { | 300 | inline while (j < count) : (j += 1) { |
| 291 | ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xor(round_keys[0]); | 301 | ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]); |
| 292 | } | 302 | } |
| 293 | comptime var i = 1; | 303 | comptime var i = 1; |
| 294 | inline while (i < rounds) : (i += 1) { | 304 | inline while (i < rounds) : (i += 1) { |
| ... | @@ -310,7 +320,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -310,7 +320,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 310 | var ts: [count]Block = undefined; | 320 | var ts: [count]Block = undefined; |
| 311 | comptime var j = 0; | 321 | comptime var j = 0; |
| 312 | inline while (j < count) : (j += 1) { | 322 | inline while (j < count) : (j += 1) { |
| 313 | ts[j] = Block.fromBytes(counters[j * 16 .. j * 16 + 16][0..16]).xor(round_keys[0]); | 323 | ts[j] = Block.fromBytes(counters[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]); |
| 314 | } | 324 | } |
| 315 | comptime var i = 1; | 325 | comptime var i = 1; |
| 316 | inline while (i < rounds) : (i += 1) { | 326 | inline while (i < rounds) : (i += 1) { |
| ... | @@ -352,7 +362,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { | ... | @@ -352,7 +362,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { |
| 352 | /// Decrypt a single block. | 362 | /// Decrypt a single block. |
| 353 | pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { | 363 | pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { |
| 354 | const inv_round_keys = ctx.key_schedule.round_keys; | 364 | const inv_round_keys = ctx.key_schedule.round_keys; |
| 355 | var t = Block.fromBytes(src).xor(inv_round_keys[0]); | 365 | var t = Block.fromBytes(src).xorBlocks(inv_round_keys[0]); |
| 356 | comptime var i = 1; | 366 | comptime var i = 1; |
| 357 | inline while (i < rounds) : (i += 1) { | 367 | inline while (i < rounds) : (i += 1) { |
| 358 | t = t.decrypt(inv_round_keys[i]); | 368 | t = t.decrypt(inv_round_keys[i]); |
| ... | @@ -367,7 +377,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { | ... | @@ -367,7 +377,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { |
| 367 | var ts: [count]Block = undefined; | 377 | var ts: [count]Block = undefined; |
| 368 | comptime var j = 0; | 378 | comptime var j = 0; |
| 369 | inline while (j < count) : (j += 1) { | 379 | inline while (j < count) : (j += 1) { |
| 370 | ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xor(inv_round_keys[0]); | 380 | ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(inv_round_keys[0]); |
| 371 | } | 381 | } |
| 372 | comptime var i = 1; | 382 | comptime var i = 1; |
| 373 | inline while (i < rounds) : (i += 1) { | 383 | inline while (i < rounds) : (i += 1) { |
lib/std/crypto/aes/soft.zig+25-5| ... | @@ -125,8 +125,8 @@ pub const Block = struct { | ... | @@ -125,8 +125,8 @@ pub const Block = struct { |
| 125 | return Block{ .repr = BlockVec{ s0, s1, s2, s3 } }; | 125 | return Block{ .repr = BlockVec{ s0, s1, s2, s3 } }; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /// XOR the content of two blocks. | 128 | /// Apply the bitwise XOR operation to the content of two blocks. |
| 129 | pub inline fn xor(block1: Block, block2: Block) Block { | 129 | pub inline fn xorBlocks(block1: Block, block2: Block) Block { |
| 130 | var x: BlockVec = undefined; | 130 | var x: BlockVec = undefined; |
| 131 | comptime var i = 0; | 131 | comptime var i = 0; |
| 132 | inline while (i < 4) : (i += 1) { | 132 | inline while (i < 4) : (i += 1) { |
| ... | @@ -135,6 +135,26 @@ pub const Block = struct { | ... | @@ -135,6 +135,26 @@ pub const Block = struct { |
| 135 | return Block{ .repr = x }; | 135 | return Block{ .repr = x }; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | /// Apply the bitwise AND operation to the content of two blocks. | ||
| 139 | pub inline fn andBlocks(block1: Block, block2: Block) Block { | ||
| 140 | var x: BlockVec = undefined; | ||
| 141 | comptime var i = 0; | ||
| 142 | inline while (i < 4) : (i += 1) { | ||
| 143 | x[i] = block1.repr[i] & block2.repr[i]; | ||
| 144 | } | ||
| 145 | return Block{ .repr = x }; | ||
| 146 | } | ||
| 147 | |||
| 148 | /// Apply the bitwise OR operation to the content of two blocks. | ||
| 149 | pub inline fn orBlocks(block1: Block, block2: Block) Block { | ||
| 150 | var x: BlockVec = undefined; | ||
| 151 | comptime var i = 0; | ||
| 152 | inline while (i < 4) : (i += 1) { | ||
| 153 | x[i] = block1.repr[i] | block2.repr[i]; | ||
| 154 | } | ||
| 155 | return Block{ .repr = x }; | ||
| 156 | } | ||
| 157 | |||
| 138 | /// Perform operations on multiple blocks in parallel. | 158 | /// Perform operations on multiple blocks in parallel. |
| 139 | pub const parallel = struct { | 159 | pub const parallel = struct { |
| 140 | /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation. | 160 | /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation. |
| ... | @@ -283,7 +303,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -283,7 +303,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 283 | /// Encrypt a single block. | 303 | /// Encrypt a single block. |
| 284 | pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { | 304 | pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { |
| 285 | const round_keys = ctx.key_schedule.round_keys; | 305 | const round_keys = ctx.key_schedule.round_keys; |
| 286 | var t = Block.fromBytes(src).xor(round_keys[0]); | 306 | var t = Block.fromBytes(src).xorBlocks(round_keys[0]); |
| 287 | comptime var i = 1; | 307 | comptime var i = 1; |
| 288 | inline while (i < rounds) : (i += 1) { | 308 | inline while (i < rounds) : (i += 1) { |
| 289 | t = t.encrypt(round_keys[i]); | 309 | t = t.encrypt(round_keys[i]); |
| ... | @@ -295,7 +315,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { | ... | @@ -295,7 +315,7 @@ pub fn AESEncryptCtx(comptime AES: type) type { |
| 295 | /// Encrypt+XOR a single block. | 315 | /// Encrypt+XOR a single block. |
| 296 | pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void { | 316 | 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; | 317 | const round_keys = ctx.key_schedule.round_keys; |
| 298 | var t = Block.fromBytes(&counter).xor(round_keys[0]); | 318 | var t = Block.fromBytes(&counter).xorBlocks(round_keys[0]); |
| 299 | comptime var i = 1; | 319 | comptime var i = 1; |
| 300 | inline while (i < rounds) : (i += 1) { | 320 | inline while (i < rounds) : (i += 1) { |
| 301 | t = t.encrypt(round_keys[i]); | 321 | t = t.encrypt(round_keys[i]); |
| ... | @@ -349,7 +369,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { | ... | @@ -349,7 +369,7 @@ pub fn AESDecryptCtx(comptime AES: type) type { |
| 349 | /// Decrypt a single block. | 369 | /// Decrypt a single block. |
| 350 | pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { | 370 | pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void { |
| 351 | const inv_round_keys = ctx.key_schedule.round_keys; | 371 | const inv_round_keys = ctx.key_schedule.round_keys; |
| 352 | var t = Block.fromBytes(src).xor(inv_round_keys[0]); | 372 | var t = Block.fromBytes(src).xorBlocks(inv_round_keys[0]); |
| 353 | comptime var i = 1; | 373 | comptime var i = 1; |
| 354 | inline while (i < rounds) : (i += 1) { | 374 | inline while (i < rounds) : (i += 1) { |
| 355 | t = t.decrypt(inv_round_keys[i]); | 375 | t = t.decrypt(inv_round_keys[i]); |
lib/std/crypto/benchmark.zig+1| ... | @@ -149,6 +149,7 @@ const aeads = [_]Crypto{ | ... | @@ -149,6 +149,7 @@ const aeads = [_]Crypto{ |
| 149 | Crypto{ .ty = crypto.aead.ChaCha20Poly1305, .name = "chacha20Poly1305" }, | 149 | Crypto{ .ty = crypto.aead.ChaCha20Poly1305, .name = "chacha20Poly1305" }, |
| 150 | Crypto{ .ty = crypto.aead.XChaCha20Poly1305, .name = "xchacha20Poly1305" }, | 150 | Crypto{ .ty = crypto.aead.XChaCha20Poly1305, .name = "xchacha20Poly1305" }, |
| 151 | Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" }, | 151 | Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" }, |
| 152 | Crypto{ .ty = crypto.aead.AEGIS128L, .name = "aegis128l" }, | ||
| 152 | }; | 153 | }; |
| 153 | 154 | ||
| 154 | pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 { | 155 | pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 { |