| ... | @@ -109,14 +109,18 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -109,14 +109,18 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 109 | mem.readIntLittle(u32, c[8..12]), | 109 | mem.readIntLittle(u32, c[8..12]), |
| 110 | mem.readIntLittle(u32, c[12..16]), | 110 | mem.readIntLittle(u32, c[12..16]), |
| 111 | }; | 111 | }; |
| | 112 | const n1 = @addWithOverflow(d[0], 1); |
| 112 | return BlockVec{ | 113 | return BlockVec{ |
| 113 | constant_le, | 114 | constant_le, |
| 114 | Lane{ key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3] }, | 115 | Lane{ key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3] }, |
| 115 | Lane{ key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7] }, | 116 | Lane{ key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7] }, |
| 116 | Lane{ d[0], d[1], d[2], d[3], d[0] +% 1, d[1], d[2], d[3] }, | 117 | Lane{ d[0], d[1], d[2], d[3], n1[0], d[1] +% n1[1], d[2], d[3] }, |
| 117 | }; | 118 | }; |
| 118 | }, | 119 | }, |
| 119 | 4 => { | 120 | 4 => { |
| | 121 | const n1 = @addWithOverflow(d[0], 1); |
| | 122 | const n2 = @addWithOverflow(d[0], 2); |
| | 123 | const n3 = @addWithOverflow(d[0], 3); |
| 120 | const constant_le = Lane{ | 124 | const constant_le = Lane{ |
| 121 | mem.readIntLittle(u32, c[0..4]), | 125 | mem.readIntLittle(u32, c[0..4]), |
| 122 | mem.readIntLittle(u32, c[4..8]), | 126 | mem.readIntLittle(u32, c[4..8]), |
| ... | @@ -139,10 +143,10 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -139,10 +143,10 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 139 | constant_le, | 143 | constant_le, |
| 140 | Lane{ key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3] }, | 144 | Lane{ key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3], key[0], key[1], key[2], key[3] }, |
| 141 | Lane{ key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7] }, | 145 | Lane{ key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7], key[4], key[5], key[6], key[7] }, |
| 142 | Lane{ d[0], d[1], d[2], d[3], d[0] +% 1, d[1], d[2], d[3], d[0] +% 2, d[1], d[2], d[3], d[0] +% 3, d[1], d[2], d[3] }, | 146 | Lane{ d[0], d[1], d[2], d[3], n1[0], d[1] +% n1[1], d[2], d[3], n2[0], d[1] +% n2[1], d[2], d[3], n3[0], d[1] +% n3[1], d[2], d[3] }, |
| 143 | }; | 147 | }; |
| 144 | }, | 148 | }, |
| 145 | else => @panic("invalid degree"), | 149 | else => @compileError("invalid degree"), |
| 146 | } | 150 | } |
| 147 | } | 151 | } |
| 148 | | 152 | |
| ... | @@ -153,19 +157,19 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -153,19 +157,19 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 153 | 1 => [_]i32{ 3, 0, 1, 2 }, | 157 | 1 => [_]i32{ 3, 0, 1, 2 }, |
| 154 | 2 => [_]i32{ 3, 0, 1, 2 } ++ [_]i32{ 7, 4, 5, 6 }, | 158 | 2 => [_]i32{ 3, 0, 1, 2 } ++ [_]i32{ 7, 4, 5, 6 }, |
| 155 | 4 => [_]i32{ 3, 0, 1, 2 } ++ [_]i32{ 7, 4, 5, 6 } ++ [_]i32{ 11, 8, 9, 10 } ++ [_]i32{ 15, 12, 13, 14 }, | 159 | 4 => [_]i32{ 3, 0, 1, 2 } ++ [_]i32{ 7, 4, 5, 6 } ++ [_]i32{ 11, 8, 9, 10 } ++ [_]i32{ 15, 12, 13, 14 }, |
| 156 | else => @panic("invalid degree"), | 160 | else => @compileError("invalid degree"), |
| 157 | }; | 161 | }; |
| 158 | const m1 = switch (degree) { | 162 | const m1 = switch (degree) { |
| 159 | 1 => [_]i32{ 2, 3, 0, 1 }, | 163 | 1 => [_]i32{ 2, 3, 0, 1 }, |
| 160 | 2 => [_]i32{ 2, 3, 0, 1 } ++ [_]i32{ 6, 7, 4, 5 }, | 164 | 2 => [_]i32{ 2, 3, 0, 1 } ++ [_]i32{ 6, 7, 4, 5 }, |
| 161 | 4 => [_]i32{ 2, 3, 0, 1 } ++ [_]i32{ 6, 7, 4, 5 } ++ [_]i32{ 10, 11, 8, 9 } ++ [_]i32{ 14, 15, 12, 13 }, | 165 | 4 => [_]i32{ 2, 3, 0, 1 } ++ [_]i32{ 6, 7, 4, 5 } ++ [_]i32{ 10, 11, 8, 9 } ++ [_]i32{ 14, 15, 12, 13 }, |
| 162 | else => @panic("invalid degree"), | 166 | else => @compileError("invalid degree"), |
| 163 | }; | 167 | }; |
| 164 | const m2 = switch (degree) { | 168 | const m2 = switch (degree) { |
| 165 | 1 => [_]i32{ 1, 2, 3, 0 }, | 169 | 1 => [_]i32{ 1, 2, 3, 0 }, |
| 166 | 2 => [_]i32{ 1, 2, 3, 0 } ++ [_]i32{ 5, 6, 7, 4 }, | 170 | 2 => [_]i32{ 1, 2, 3, 0 } ++ [_]i32{ 5, 6, 7, 4 }, |
| 167 | 4 => [_]i32{ 1, 2, 3, 0 } ++ [_]i32{ 5, 6, 7, 4 } ++ [_]i32{ 9, 10, 11, 8 } ++ [_]i32{ 13, 14, 15, 12 }, | 171 | 4 => [_]i32{ 1, 2, 3, 0 } ++ [_]i32{ 5, 6, 7, 4 } ++ [_]i32{ 9, 10, 11, 8 } ++ [_]i32{ 13, 14, 15, 12 }, |
| 168 | else => @panic("invalid degree"), | 172 | else => @compileError("invalid degree"), |
| 169 | }; | 173 | }; |
| 170 | | 174 | |
| 171 | var r: usize = 0; | 175 | var r: usize = 0; |
| ... | @@ -212,8 +216,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -212,8 +216,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 212 | | 216 | |
| 213 | inline fn hashToBytes(comptime dm: usize, out: *[64 * dm]u8, x: BlockVec) void { | 217 | inline fn hashToBytes(comptime dm: usize, out: *[64 * dm]u8, x: BlockVec) void { |
| 214 | for (0..dm) |d| { | 218 | for (0..dm) |d| { |
| 215 | var i: usize = 0; | 219 | for (0..4) |i| { |
| 216 | while (i < 4) : (i += 1) { | | |
| 217 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 0 ..][0..4], x[i][0 + 4 * d]); | 220 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 0 ..][0..4], x[i][0 + 4 * d]); |
| 218 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 4 ..][0..4], x[i][1 + 4 * d]); | 221 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 4 ..][0..4], x[i][1 + 4 * d]); |
| 219 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 8 ..][0..4], x[i][2 + 4 * d]); | 222 | mem.writeIntLittle(u32, out[64 * d + 16 * i + 8 ..][0..4], x[i][2 + 4 * d]); |
| ... | @@ -229,8 +232,8 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -229,8 +232,8 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 229 | x[3] +%= ctx[3]; | 232 | x[3] +%= ctx[3]; |
| 230 | } | 233 | } |
| 231 | | 234 | |
| 232 | fn chacha20Xor(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) void { | 235 | fn chacha20Xor(out: []u8, in: []const u8, key: [8]u32, nonce_and_counter: [4]u32, comptime count64: bool) void { |
| 233 | var ctx = initContext(key, counter); | 236 | var ctx = initContext(key, nonce_and_counter); |
| 234 | var x: BlockVec = undefined; | 237 | var x: BlockVec = undefined; |
| 235 | var buf: [64 * degree]u8 = undefined; | 238 | var buf: [64 * degree]u8 = undefined; |
| 236 | var i: usize = 0; | 239 | var i: usize = 0; |
| ... | @@ -242,16 +245,20 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -242,16 +245,20 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 242 | | 245 | |
| 243 | var xout = out[i..]; | 246 | var xout = out[i..]; |
| 244 | const xin = in[i..]; | 247 | const xin = in[i..]; |
| 245 | var j: usize = 0; | 248 | for (0..64 * d) |j| { |
| 246 | while (j < 64 * d) : (j += 1) { | | |
| 247 | xout[j] = xin[j]; | 249 | xout[j] = xin[j]; |
| 248 | } | 250 | } |
| 249 | j = 0; | 251 | for (0..64 * d) |j| { |
| 250 | while (j < 64 * d) : (j += 1) { | | |
| 251 | xout[j] ^= buf[j]; | 252 | xout[j] ^= buf[j]; |
| 252 | } | 253 | } |
| 253 | inline for (0..d) |d_| { | 254 | inline for (0..d) |d_| { |
| 254 | ctx[3][4 * d_] += @intCast(u32, d); | 255 | if (count64) { |
| | 256 | const next = @addWithOverflow(ctx[3][4 * d_], d); |
| | 257 | ctx[3][4 * d_] = next[0]; |
| | 258 | ctx[3][4 * d_ + 1] +%= next[1]; |
| | 259 | } else { |
| | 260 | ctx[3][4 * d_] +%= d; |
| | 261 | } |
| 255 | } | 262 | } |
| 256 | } | 263 | } |
| 257 | } | 264 | } |
| ... | @@ -262,15 +269,14 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -262,15 +269,14 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 262 | | 269 | |
| 263 | var xout = out[i..]; | 270 | var xout = out[i..]; |
| 264 | const xin = in[i..]; | 271 | const xin = in[i..]; |
| 265 | var j: usize = 0; | 272 | for (0..in.len % 64) |j| { |
| 266 | while (j < in.len % 64) : (j += 1) { | | |
| 267 | xout[j] = xin[j] ^ buf[j]; | 273 | xout[j] = xin[j] ^ buf[j]; |
| 268 | } | 274 | } |
| 269 | } | 275 | } |
| 270 | } | 276 | } |
| 271 | | 277 | |
| 272 | fn chacha20Stream(out: []u8, key: [8]u32, counter: [4]u32) void { | 278 | fn chacha20Stream(out: []u8, key: [8]u32, nonce_and_counter: [4]u32, comptime count64: bool) void { |
| 273 | var ctx = initContext(key, counter); | 279 | var ctx = initContext(key, nonce_and_counter); |
| 274 | var x: BlockVec = undefined; | 280 | var x: BlockVec = undefined; |
| 275 | var i: usize = 0; | 281 | var i: usize = 0; |
| 276 | inline for ([_]comptime_int{ 4, 2, 1 }) |d| { | 282 | inline for ([_]comptime_int{ 4, 2, 1 }) |d| { |
| ... | @@ -279,7 +285,13 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type | ... | @@ -279,7 +285,13 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 279 | contextFeedback(&x, ctx); | 285 | contextFeedback(&x, ctx); |
| 280 | hashToBytes(d, out[i..][0 .. 64 * d], x); | 286 | hashToBytes(d, out[i..][0 .. 64 * d], x); |
| 281 | inline for (0..d) |d_| { | 287 | inline for (0..d) |d_| { |
| 282 | ctx[3][4 * d_] += @intCast(u32, d); | 288 | if (count64) { |
| | 289 | const next = @addWithOverflow(ctx[3][4 * d_], d); |
| | 290 | ctx[3][4 * d_] = next[0]; |
| | 291 | ctx[3][4 * d_ + 1] +%= next[1]; |
| | 292 | } else { |
| | 293 | ctx[3][4 * d_] +%= d; |
| | 294 | } |
| 283 | } | 295 | } |
| 284 | } | 296 | } |
| 285 | } | 297 | } |
| ... | @@ -382,8 +394,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { | ... | @@ -382,8 +394,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 382 | } | 394 | } |
| 383 | | 395 | |
| 384 | inline fn hashToBytes(out: *[64]u8, x: BlockVec) void { | 396 | inline fn hashToBytes(out: *[64]u8, x: BlockVec) void { |
| 385 | var i: usize = 0; | 397 | for (0..4) |i| { |
| 386 | while (i < 4) : (i += 1) { | | |
| 387 | mem.writeIntLittle(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0]); | 398 | mem.writeIntLittle(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0]); |
| 388 | mem.writeIntLittle(u32, out[16 * i + 4 ..][0..4], x[i * 4 + 1]); | 399 | mem.writeIntLittle(u32, out[16 * i + 4 ..][0..4], x[i * 4 + 1]); |
| 389 | mem.writeIntLittle(u32, out[16 * i + 8 ..][0..4], x[i * 4 + 2]); | 400 | mem.writeIntLittle(u32, out[16 * i + 8 ..][0..4], x[i * 4 + 2]); |
| ... | @@ -392,14 +403,13 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { | ... | @@ -392,14 +403,13 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 392 | } | 403 | } |
| 393 | | 404 | |
| 394 | inline fn contextFeedback(x: *BlockVec, ctx: BlockVec) void { | 405 | inline fn contextFeedback(x: *BlockVec, ctx: BlockVec) void { |
| 395 | var i: usize = 0; | 406 | for (0..16) |i| { |
| 396 | while (i < 16) : (i += 1) { | | |
| 397 | x[i] +%= ctx[i]; | 407 | x[i] +%= ctx[i]; |
| 398 | } | 408 | } |
| 399 | } | 409 | } |
| 400 | | 410 | |
| 401 | fn chacha20Xor(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) void { | 411 | fn chacha20Xor(out: []u8, in: []const u8, key: [8]u32, nonce_and_counter: [4]u32, comptime count64: bool) void { |
| 402 | var ctx = initContext(key, counter); | 412 | var ctx = initContext(key, nonce_and_counter); |
| 403 | var x: BlockVec = undefined; | 413 | var x: BlockVec = undefined; |
| 404 | var buf: [64]u8 = undefined; | 414 | var buf: [64]u8 = undefined; |
| 405 | var i: usize = 0; | 415 | var i: usize = 0; |
| ... | @@ -410,15 +420,19 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { | ... | @@ -410,15 +420,19 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 410 | | 420 | |
| 411 | var xout = out[i..]; | 421 | var xout = out[i..]; |
| 412 | const xin = in[i..]; | 422 | const xin = in[i..]; |
| 413 | var j: usize = 0; | 423 | for (0..64) |j| { |
| 414 | while (j < 64) : (j += 1) { | | |
| 415 | xout[j] = xin[j]; | 424 | xout[j] = xin[j]; |
| 416 | } | 425 | } |
| 417 | j = 0; | 426 | for (0..64) |j| { |
| 418 | while (j < 64) : (j += 1) { | | |
| 419 | xout[j] ^= buf[j]; | 427 | xout[j] ^= buf[j]; |
| 420 | } | 428 | } |
| 421 | ctx[12] += 1; | 429 | if (count64) { |
| | 430 | const next = @addWithOverflow(ctx[12], 1); |
| | 431 | ctx[12] = next[0]; |
| | 432 | ctx[13] +%= next[1]; |
| | 433 | } else { |
| | 434 | ctx[12] +%= 1; |
| | 435 | } |
| 422 | } | 436 | } |
| 423 | if (i < in.len) { | 437 | if (i < in.len) { |
| 424 | chacha20Core(x[0..], ctx); | 438 | chacha20Core(x[0..], ctx); |
| ... | @@ -427,22 +441,27 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { | ... | @@ -427,22 +441,27 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 427 | | 441 | |
| 428 | var xout = out[i..]; | 442 | var xout = out[i..]; |
| 429 | const xin = in[i..]; | 443 | const xin = in[i..]; |
| 430 | var j: usize = 0; | 444 | for (0..in.len % 64) |j| { |
| 431 | while (j < in.len % 64) : (j += 1) { | | |
| 432 | xout[j] = xin[j] ^ buf[j]; | 445 | xout[j] = xin[j] ^ buf[j]; |
| 433 | } | 446 | } |
| 434 | } | 447 | } |
| 435 | } | 448 | } |
| 436 | | 449 | |
| 437 | fn chacha20Stream(out: []u8, key: [8]u32, counter: [4]u32) void { | 450 | fn chacha20Stream(out: []u8, key: [8]u32, nonce_and_counter: [4]u32, comptime count64: bool) void { |
| 438 | var ctx = initContext(key, counter); | 451 | var ctx = initContext(key, nonce_and_counter); |
| 439 | var x: BlockVec = undefined; | 452 | var x: BlockVec = undefined; |
| 440 | var i: usize = 0; | 453 | var i: usize = 0; |
| 441 | while (i + 64 <= out.len) : (i += 64) { | 454 | while (i + 64 <= out.len) : (i += 64) { |
| 442 | chacha20Core(x[0..], ctx); | 455 | chacha20Core(x[0..], ctx); |
| 443 | contextFeedback(&x, ctx); | 456 | contextFeedback(&x, ctx); |
| 444 | hashToBytes(out[i..][0..64], x); | 457 | hashToBytes(out[i..][0..64], x); |
| 445 | ctx[12] += 1; | 458 | if (count64) { |
| | 459 | const next = @addWithOverflow(ctx[12], 1); |
| | 460 | ctx[12] = next[0]; |
| | 461 | ctx[13] +%= next[1]; |
| | 462 | } else { |
| | 463 | ctx[12] +%= 1; |
| | 464 | } |
| 446 | } | 465 | } |
| 447 | if (i < out.len) { | 466 | if (i < out.len) { |
| 448 | chacha20Core(x[0..], ctx); | 467 | chacha20Core(x[0..], ctx); |
| ... | @@ -496,8 +515,7 @@ fn ChaChaImpl(comptime rounds_nb: usize) type { | ... | @@ -496,8 +515,7 @@ fn ChaChaImpl(comptime rounds_nb: usize) type { |
| 496 | | 515 | |
| 497 | fn keyToWords(key: [32]u8) [8]u32 { | 516 | fn keyToWords(key: [32]u8) [8]u32 { |
| 498 | var k: [8]u32 = undefined; | 517 | var k: [8]u32 = undefined; |
| 499 | var i: usize = 0; | 518 | for (0..8) |i| { |
| 500 | while (i < 8) : (i += 1) { | | |
| 501 | k[i] = mem.readIntLittle(u32, key[i * 4 ..][0..4]); | 519 | k[i] = mem.readIntLittle(u32, key[i * 4 ..][0..4]); |
| 502 | } | 520 | } |
| 503 | return k; | 521 | return k; |
| ... | @@ -527,26 +545,26 @@ fn ChaChaIETF(comptime rounds_nb: usize) type { | ... | @@ -527,26 +545,26 @@ fn ChaChaIETF(comptime rounds_nb: usize) type { |
| 527 | /// Using the AEAD or one of the `box` versions is usually preferred. | 545 | /// Using the AEAD or one of the `box` versions is usually preferred. |
| 528 | pub fn xor(out: []u8, in: []const u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { | 546 | pub fn xor(out: []u8, in: []const u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { |
| 529 | assert(in.len == out.len); | 547 | assert(in.len == out.len); |
| 530 | assert(in.len / 64 <= (1 << 32 - 1) - counter); | 548 | assert(in.len <= 64 * (@as(u39, 1 << 32) - counter)); |
| 531 | | 549 | |
| 532 | var d: [4]u32 = undefined; | 550 | var d: [4]u32 = undefined; |
| 533 | d[0] = counter; | 551 | d[0] = counter; |
| 534 | d[1] = mem.readIntLittle(u32, nonce[0..4]); | 552 | d[1] = mem.readIntLittle(u32, nonce[0..4]); |
| 535 | d[2] = mem.readIntLittle(u32, nonce[4..8]); | 553 | d[2] = mem.readIntLittle(u32, nonce[4..8]); |
| 536 | d[3] = mem.readIntLittle(u32, nonce[8..12]); | 554 | d[3] = mem.readIntLittle(u32, nonce[8..12]); |
| 537 | ChaChaImpl(rounds_nb).chacha20Xor(out, in, keyToWords(key), d); | 555 | ChaChaImpl(rounds_nb).chacha20Xor(out, in, keyToWords(key), d, false); |
| 538 | } | 556 | } |
| 539 | | 557 | |
| 540 | /// Write the output of the ChaCha20 stream cipher into `out`. | 558 | /// Write the output of the ChaCha20 stream cipher into `out`. |
| 541 | pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { | 559 | pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { |
| 542 | assert(out.len / 64 <= (1 << 32 - 1) - counter); | 560 | assert(out.len <= 64 * (@as(u39, 1 << 32) - counter)); |
| 543 | | 561 | |
| 544 | var d: [4]u32 = undefined; | 562 | var d: [4]u32 = undefined; |
| 545 | d[0] = counter; | 563 | d[0] = counter; |
| 546 | d[1] = mem.readIntLittle(u32, nonce[0..4]); | 564 | d[1] = mem.readIntLittle(u32, nonce[0..4]); |
| 547 | d[2] = mem.readIntLittle(u32, nonce[4..8]); | 565 | d[2] = mem.readIntLittle(u32, nonce[4..8]); |
| 548 | d[3] = mem.readIntLittle(u32, nonce[8..12]); | 566 | d[3] = mem.readIntLittle(u32, nonce[8..12]); |
| 549 | ChaChaImpl(rounds_nb).chacha20Stream(out, keyToWords(key), d); | 567 | ChaChaImpl(rounds_nb).chacha20Stream(out, keyToWords(key), d, false); |
| 550 | } | 568 | } |
| 551 | }; | 569 | }; |
| 552 | } | 570 | } |
| ... | @@ -565,47 +583,28 @@ fn ChaChaWith64BitNonce(comptime rounds_nb: usize) type { | ... | @@ -565,47 +583,28 @@ fn ChaChaWith64BitNonce(comptime rounds_nb: usize) type { |
| 565 | /// Using the AEAD or one of the `box` versions is usually preferred. | 583 | /// Using the AEAD or one of the `box` versions is usually preferred. |
| 566 | pub fn xor(out: []u8, in: []const u8, counter: u64, key: [key_length]u8, nonce: [nonce_length]u8) void { | 584 | pub fn xor(out: []u8, in: []const u8, counter: u64, key: [key_length]u8, nonce: [nonce_length]u8) void { |
| 567 | assert(in.len == out.len); | 585 | assert(in.len == out.len); |
| 568 | assert(in.len / 64 <= (1 << 64 - 1) - counter); | 586 | assert(in.len <= 64 * (@as(u71, 1 << 64) - counter)); |
| 569 | | 587 | |
| 570 | var cursor: usize = 0; | | |
| 571 | const k = keyToWords(key); | 588 | const k = keyToWords(key); |
| 572 | var c: [4]u32 = undefined; | 589 | var c: [4]u32 = undefined; |
| 573 | c[0] = @truncate(u32, counter); | 590 | c[0] = @truncate(u32, counter); |
| 574 | c[1] = @truncate(u32, counter >> 32); | 591 | c[1] = @truncate(u32, counter >> 32); |
| 575 | c[2] = mem.readIntLittle(u32, nonce[0..4]); | 592 | c[2] = mem.readIntLittle(u32, nonce[0..4]); |
| 576 | c[3] = mem.readIntLittle(u32, nonce[4..8]); | 593 | c[3] = mem.readIntLittle(u32, nonce[4..8]); |
| 577 | | 594 | ChaChaImpl(rounds_nb).chacha20Xor(out, in, k, c, true); |
| 578 | // The full block size is greater than the address space on a 32bit machine | | |
| 579 | const big_block = if (@sizeOf(usize) > 4) (block_length << 32) else maxInt(usize); | | |
| 580 | | | |
| 581 | // first partial big block | | |
| 582 | if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { | | |
| 583 | ChaChaImpl(rounds_nb).chacha20Xor(out[cursor..big_block], in[cursor..big_block], k, c); | | |
| 584 | cursor = big_block - cursor; | | |
| 585 | c[1] += 1; | | |
| 586 | if (comptime @sizeOf(usize) > 4) { | | |
| 587 | // A big block is giant: 256 GiB, but we can avoid this limitation | | |
| 588 | var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); | | |
| 589 | while (remaining_blocks > 0) : (remaining_blocks -= 1) { | | |
| 590 | ChaChaImpl(rounds_nb).chacha20Xor(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); | | |
| 591 | c[1] += 1; // upper 32-bit of counter, generic chacha20Xor() doesn't know about this. | | |
| 592 | cursor += big_block; | | |
| 593 | } | | |
| 594 | } | | |
| 595 | } | | |
| 596 | ChaChaImpl(rounds_nb).chacha20Xor(out[cursor..], in[cursor..], k, c); | | |
| 597 | } | 595 | } |
| 598 | | 596 | |
| 599 | /// Write the output of the ChaCha20 stream cipher into `out`. | 597 | /// Write the output of the ChaCha20 stream cipher into `out`. |
| 600 | pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { | 598 | pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void { |
| 601 | assert(out.len / 64 <= (1 << 32 - 1) - counter); | 599 | assert(out.len <= 64 * (@as(u71, 1 << 64) - counter)); |
| | 600 | |
| 602 | const k = keyToWords(key); | 601 | const k = keyToWords(key); |
| 603 | var c: [4]u32 = undefined; | 602 | var c: [4]u32 = undefined; |
| 604 | c[0] = @truncate(u32, counter); | 603 | c[0] = @truncate(u32, counter); |
| 605 | c[1] = @truncate(u32, counter >> 32); | 604 | c[1] = @truncate(u32, counter >> 32); |
| 606 | c[2] = mem.readIntLittle(u32, nonce[0..4]); | 605 | c[2] = mem.readIntLittle(u32, nonce[0..4]); |
| 607 | c[3] = mem.readIntLittle(u32, nonce[4..8]); | 606 | c[3] = mem.readIntLittle(u32, nonce[4..8]); |
| 608 | ChaChaImpl(rounds_nb).chacha20Stream(out, k, c); | 607 | ChaChaImpl(rounds_nb).chacha20Stream(out, k, c, true); |
| 609 | } | 608 | } |
| 610 | }; | 609 | }; |
| 611 | } | 610 | } |
| ... | @@ -649,6 +648,7 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type { | ... | @@ -649,6 +648,7 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type { |
| 649 | /// k: private key | 648 | /// k: private key |
| 650 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { | 649 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { |
| 651 | assert(c.len == m.len); | 650 | assert(c.len == m.len); |
| | 651 | assert(m.len <= 64 * (@as(u39, 1 << 32) - 1)); |
| 652 | | 652 | |
| 653 | var polyKey = [_]u8{0} ** 32; | 653 | var polyKey = [_]u8{0} ** 32; |
| 654 | ChaChaIETF(rounds_nb).xor(polyKey[0..], polyKey[0..], 0, k, npub); | 654 | ChaChaIETF(rounds_nb).xor(polyKey[0..], polyKey[0..], 0, k, npub); |
| ... | @@ -766,7 +766,7 @@ test "chacha20 AEAD API" { | ... | @@ -766,7 +766,7 @@ test "chacha20 AEAD API" { |
| 766 | aead.encrypt(c[0..], tag[0..], m, ad, nonce, key); | 766 | aead.encrypt(c[0..], tag[0..], m, ad, nonce, key); |
| 767 | try aead.decrypt(out[0..], c[0..], tag, ad[0..], nonce, key); | 767 | try aead.decrypt(out[0..], c[0..], tag, ad[0..], nonce, key); |
| 768 | try testing.expectEqualSlices(u8, out[0..], m); | 768 | try testing.expectEqualSlices(u8, out[0..], m); |
| 769 | c[0] += 1; | 769 | c[0] +%= 1; |
| 770 | try testing.expectError(error.AuthenticationFailed, aead.decrypt(out[0..], c[0..], tag, ad[0..], nonce, key)); | 770 | try testing.expectError(error.AuthenticationFailed, aead.decrypt(out[0..], c[0..], tag, ad[0..], nonce, key)); |
| 771 | } | 771 | } |
| 772 | } | 772 | } |
| ... | @@ -1154,7 +1154,7 @@ test "crypto.xchacha20" { | ... | @@ -1154,7 +1154,7 @@ test "crypto.xchacha20" { |
| 1154 | var buf: [2 * c.len]u8 = undefined; | 1154 | var buf: [2 * c.len]u8 = undefined; |
| 1155 | try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234"); | 1155 | try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234"); |
| 1156 | try testing.expectEqualSlices(u8, out[0..], m); | 1156 | try testing.expectEqualSlices(u8, out[0..], m); |
| 1157 | c[0] += 1; | 1157 | c[0] +%= 1; |
| 1158 | try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key)); | 1158 | try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key)); |
| 1159 | } | 1159 | } |
| 1160 | } | 1160 | } |