std/crypto: make the whole APIs more consistent

- use `PascalCase` for all types. So, AES256GCM is now Aes256Gcm.
- consistently use `_length` instead of mixing `_size` and `_length` for the
constants we expose
- Use `minimum_key_length` when it represents an actual minimum length.
Otherwise, use `key_length`.
- Require output buffers (for ciphertexts, macs, hashes) to be of the right
size, not at least of that size in some functions, and the exact size elsewhere.
- Use a `_bits` suffix instead of `_length` when a size is represented as a
number of bits to avoid confusion.
- Functions returning a constant-sized slice are now defined as a slice instead
of a pointer + a runtime assertion. This is the case for most hash functions.
- Use `camelCase` for all functions instead of `snake_case`.

No functional changes, but these are breaking API changes.
This commit is contained in:
Frank Denis 2020-10-16 19:10:20 +02:00 committed by Andrew Kelley
parent 0011def2b2
commit fa17447090
24 changed files with 743 additions and 758 deletions

View File

@ -11,10 +11,10 @@ pub const aead = struct {
pub const Gimli = @import("crypto/gimli.zig").Aead;
pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
pub const AES128GCM = @import("crypto/aes_gcm.zig").AES128GCM;
pub const AES256GCM = @import("crypto/aes_gcm.zig").AES256GCM;
pub const Aegis128L = @import("crypto/aegis.zig").Aegis128L;
pub const Aegis256 = @import("crypto/aegis.zig").Aegis256;
pub const Aes128Gcm = @import("crypto/aes_gcm.zig").Aes128Gcm;
pub const Aes256Gcm = @import("crypto/aes_gcm.zig").Aes256Gcm;
};
/// Authentication (MAC) functions.
@ -156,8 +156,11 @@ test "issue #4532: no index out of bounds" {
hash.sha3.Sha3_256,
hash.sha3.Sha3_384,
hash.sha3.Sha3_512,
hash.blake2.Blake2s128,
hash.blake2.Blake2s224,
hash.blake2.Blake2s256,
hash.blake2.Blake2b128,
hash.blake2.Blake2b256,
hash.blake2.Blake2b384,
hash.blake2.Blake2b512,
hash.Gimli,
@ -170,11 +173,11 @@ test "issue #4532: no index out of bounds" {
const h0 = Hasher.init(.{});
var h = h0;
h.update(block[0..]);
h.final(out1[0..]);
h.final(&out1);
h = h0;
h.update(block[0..1]);
h.update(block[1..]);
h.final(out2[0..]);
h.final(&out2);
std.testing.expectEqual(out1, out2);
}

View File

@ -14,12 +14,12 @@ pub const X25519 = struct {
/// Length (in bytes) of a secret key.
pub const secret_length = 32;
/// Length (in bytes) of the output of the DH function.
pub const minimum_key_length = 32;
pub const key_length = 32;
/// Compute the public key for a given private key.
pub fn createPublicKey(public_key: []u8, private_key: []const u8) bool {
std.debug.assert(private_key.len >= minimum_key_length);
std.debug.assert(public_key.len >= minimum_key_length);
std.debug.assert(private_key.len >= key_length);
std.debug.assert(public_key.len >= key_length);
var s: [32]u8 = undefined;
mem.copy(u8, &s, private_key[0..32]);
if (Curve.basePoint.clampedMul(s)) |q| {
@ -35,8 +35,8 @@ pub const X25519 = struct {
/// hashing it first.
pub fn create(out: []u8, private_key: []const u8, public_key: []const u8) bool {
std.debug.assert(out.len >= secret_length);
std.debug.assert(private_key.len >= minimum_key_length);
std.debug.assert(public_key.len >= minimum_key_length);
std.debug.assert(private_key.len >= key_length);
std.debug.assert(public_key.len >= key_length);
var s: [32]u8 = undefined;
var b: [32]u8 = undefined;
mem.copy(u8, &s, private_key[0..32]);

View File

@ -1,17 +1,17 @@
const std = @import("std");
const mem = std.mem;
const assert = std.debug.assert;
const AESBlock = std.crypto.core.aes.Block;
const AesBlock = std.crypto.core.aes.Block;
const State128L = struct {
blocks: [8]AESBlock,
blocks: [8]AesBlock,
fn init(key: [16]u8, nonce: [16]u8) State128L {
const c1 = AESBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd });
const c2 = AESBlock.fromBytes(&[16]u8{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 });
const key_block = AESBlock.fromBytes(&key);
const nonce_block = AESBlock.fromBytes(&nonce);
const blocks = [8]AESBlock{
const c1 = AesBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd });
const c2 = AesBlock.fromBytes(&[16]u8{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 });
const key_block = AesBlock.fromBytes(&key);
const nonce_block = AesBlock.fromBytes(&nonce);
const blocks = [8]AesBlock{
key_block.xorBlocks(nonce_block),
c1,
c2,
@ -29,7 +29,7 @@ const State128L = struct {
return state;
}
inline fn update(state: *State128L, d1: AESBlock, d2: AESBlock) void {
inline fn update(state: *State128L, d1: AesBlock, d2: AesBlock) void {
const blocks = &state.blocks;
const tmp = blocks[7];
comptime var i: usize = 7;
@ -43,8 +43,8 @@ const State128L = struct {
fn enc(state: *State128L, dst: *[32]u8, src: *const [32]u8) void {
const blocks = &state.blocks;
const msg0 = AESBlock.fromBytes(src[0..16]);
const msg1 = AESBlock.fromBytes(src[16..32]);
const msg0 = AesBlock.fromBytes(src[0..16]);
const msg1 = AesBlock.fromBytes(src[16..32]);
var tmp0 = msg0.xorBlocks(blocks[6]).xorBlocks(blocks[1]);
var tmp1 = msg1.xorBlocks(blocks[2]).xorBlocks(blocks[5]);
tmp0 = tmp0.xorBlocks(blocks[2].andBlocks(blocks[3]));
@ -56,8 +56,8 @@ const State128L = struct {
fn dec(state: *State128L, dst: *[32]u8, src: *const [32]u8) void {
const blocks = &state.blocks;
var msg0 = AESBlock.fromBytes(src[0..16]).xorBlocks(blocks[6]).xorBlocks(blocks[1]);
var msg1 = AESBlock.fromBytes(src[16..32]).xorBlocks(blocks[2]).xorBlocks(blocks[5]);
var msg0 = AesBlock.fromBytes(src[0..16]).xorBlocks(blocks[6]).xorBlocks(blocks[1]);
var msg1 = AesBlock.fromBytes(src[16..32]).xorBlocks(blocks[2]).xorBlocks(blocks[5]);
msg0 = msg0.xorBlocks(blocks[2].andBlocks(blocks[3]));
msg1 = msg1.xorBlocks(blocks[6].andBlocks(blocks[7]));
dst[0..16].* = msg0.toBytes();
@ -70,7 +70,7 @@ const State128L = struct {
var sizes: [16]u8 = undefined;
mem.writeIntLittle(u64, sizes[0..8], adlen * 8);
mem.writeIntLittle(u64, sizes[8..16], mlen * 8);
const tmp = AESBlock.fromBytes(&sizes).xorBlocks(blocks[2]);
const tmp = AesBlock.fromBytes(&sizes).xorBlocks(blocks[2]);
var i: usize = 0;
while (i < 7) : (i += 1) {
state.update(tmp, tmp);
@ -86,7 +86,7 @@ const State128L = struct {
/// It was designed to fully exploit the parallelism and built-in AES support of recent Intel and ARM CPUs.
///
/// https://competitions.cr.yp.to/round3/aegisv11.pdf
pub const AEGIS128L = struct {
pub const Aegis128L = struct {
pub const tag_length = 16;
pub const nonce_length = 16;
pub const key_length = 16;
@ -155,8 +155,8 @@ pub const AEGIS128L = struct {
mem.copy(u8, m[i .. i + m.len % 32], dst[0 .. m.len % 32]);
mem.set(u8, dst[0 .. m.len % 32], 0);
const blocks = &state.blocks;
blocks[0] = blocks[0].xorBlocks(AESBlock.fromBytes(dst[0..16]));
blocks[4] = blocks[4].xorBlocks(AESBlock.fromBytes(dst[16..32]));
blocks[0] = blocks[0].xorBlocks(AesBlock.fromBytes(dst[0..16]));
blocks[4] = blocks[4].xorBlocks(AesBlock.fromBytes(dst[16..32]));
}
const computed_tag = state.mac(ad.len, m.len);
var acc: u8 = 0;
@ -171,18 +171,18 @@ pub const AEGIS128L = struct {
};
const State256 = struct {
blocks: [6]AESBlock,
blocks: [6]AesBlock,
fn init(key: [32]u8, nonce: [32]u8) State256 {
const c1 = AESBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd });
const c2 = AESBlock.fromBytes(&[16]u8{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 });
const key_block1 = AESBlock.fromBytes(key[0..16]);
const key_block2 = AESBlock.fromBytes(key[16..32]);
const nonce_block1 = AESBlock.fromBytes(nonce[0..16]);
const nonce_block2 = AESBlock.fromBytes(nonce[16..32]);
const c1 = AesBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd });
const c2 = AesBlock.fromBytes(&[16]u8{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 });
const key_block1 = AesBlock.fromBytes(key[0..16]);
const key_block2 = AesBlock.fromBytes(key[16..32]);
const nonce_block1 = AesBlock.fromBytes(nonce[0..16]);
const nonce_block2 = AesBlock.fromBytes(nonce[16..32]);
const kxn1 = key_block1.xorBlocks(nonce_block1);
const kxn2 = key_block2.xorBlocks(nonce_block2);
const blocks = [6]AESBlock{
const blocks = [6]AesBlock{
kxn1,
kxn2,
c1,
@ -201,7 +201,7 @@ const State256 = struct {
return state;
}
inline fn update(state: *State256, d: AESBlock) void {
inline fn update(state: *State256, d: AesBlock) void {
const blocks = &state.blocks;
const tmp = blocks[5].encrypt(blocks[0]);
comptime var i: usize = 5;
@ -213,7 +213,7 @@ const State256 = struct {
fn enc(state: *State256, dst: *[16]u8, src: *const [16]u8) void {
const blocks = &state.blocks;
const msg = AESBlock.fromBytes(src);
const msg = AesBlock.fromBytes(src);
var tmp = msg.xorBlocks(blocks[5]).xorBlocks(blocks[4]).xorBlocks(blocks[1]);
tmp = tmp.xorBlocks(blocks[2].andBlocks(blocks[3]));
dst.* = tmp.toBytes();
@ -222,7 +222,7 @@ const State256 = struct {
fn dec(state: *State256, dst: *[16]u8, src: *const [16]u8) void {
const blocks = &state.blocks;
var msg = AESBlock.fromBytes(src).xorBlocks(blocks[5]).xorBlocks(blocks[4]).xorBlocks(blocks[1]);
var msg = AesBlock.fromBytes(src).xorBlocks(blocks[5]).xorBlocks(blocks[4]).xorBlocks(blocks[1]);
msg = msg.xorBlocks(blocks[2].andBlocks(blocks[3]));
dst.* = msg.toBytes();
state.update(msg);
@ -233,7 +233,7 @@ const State256 = struct {
var sizes: [16]u8 = undefined;
mem.writeIntLittle(u64, sizes[0..8], adlen * 8);
mem.writeIntLittle(u64, sizes[8..16], mlen * 8);
const tmp = AESBlock.fromBytes(&sizes).xorBlocks(blocks[3]);
const tmp = AesBlock.fromBytes(&sizes).xorBlocks(blocks[3]);
var i: usize = 0;
while (i < 7) : (i += 1) {
state.update(tmp);
@ -248,7 +248,7 @@ const State256 = struct {
/// The 256 bit variant of AEGIS has a 256 bit key, a 256 bit nonce, and processes 128 bit message blocks.
///
/// https://competitions.cr.yp.to/round3/aegisv11.pdf
pub const AEGIS256 = struct {
pub const Aegis256 = struct {
pub const tag_length = 16;
pub const nonce_length = 32;
pub const key_length = 32;
@ -317,7 +317,7 @@ pub const AEGIS256 = struct {
mem.copy(u8, m[i .. i + m.len % 16], dst[0 .. m.len % 16]);
mem.set(u8, dst[0 .. m.len % 16], 0);
const blocks = &state.blocks;
blocks[0] = blocks[0].xorBlocks(AESBlock.fromBytes(&dst));
blocks[0] = blocks[0].xorBlocks(AesBlock.fromBytes(&dst));
}
const computed_tag = state.mac(ad.len, m.len);
var acc: u8 = 0;
@ -334,113 +334,113 @@ pub const AEGIS256 = struct {
const htest = @import("test.zig");
const testing = std.testing;
test "AEGIS128L test vector 1" {
const key: [AEGIS128L.key_length]u8 = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** 14;
const nonce: [AEGIS128L.nonce_length]u8 = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** 13;
test "Aegis128L test vector 1" {
const key: [Aegis128L.key_length]u8 = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** 14;
const nonce: [Aegis128L.nonce_length]u8 = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** 13;
const ad = [8]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
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 };
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS128L.tag_length]u8 = undefined;
var tag: [Aegis128L.tag_length]u8 = undefined;
AEGIS128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis128L.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("79d94593d8c2119d7e8fd9b8fc77845c5c077a05b2528b6ac54b563aed8efe84", &c);
htest.assertEqual("cc6f3372f6aa1bb82388d695c3962d9a", &tag);
c[0] +%= 1;
testing.expectError(error.AuthenticationFailed, AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key));
testing.expectError(error.AuthenticationFailed, Aegis128L.decrypt(&m2, &c, tag, &ad, nonce, key));
c[0] -%= 1;
tag[0] +%= 1;
testing.expectError(error.AuthenticationFailed, AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key));
testing.expectError(error.AuthenticationFailed, Aegis128L.decrypt(&m2, &c, tag, &ad, nonce, key));
}
test "AEGIS128L test vector 2" {
const key: [AEGIS128L.key_length]u8 = [_]u8{0x00} ** 16;
const nonce: [AEGIS128L.nonce_length]u8 = [_]u8{0x00} ** 16;
test "Aegis128L test vector 2" {
const key: [Aegis128L.key_length]u8 = [_]u8{0x00} ** 16;
const nonce: [Aegis128L.nonce_length]u8 = [_]u8{0x00} ** 16;
const ad = [_]u8{};
const m = [_]u8{0x00} ** 16;
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS128L.tag_length]u8 = undefined;
var tag: [Aegis128L.tag_length]u8 = undefined;
AEGIS128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis128L.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("41de9000a7b5e40e2d68bb64d99ebb19", &c);
htest.assertEqual("f4d997cc9b94227ada4fe4165422b1c8", &tag);
}
test "AEGIS128L test vector 3" {
const key: [AEGIS128L.key_length]u8 = [_]u8{0x00} ** 16;
const nonce: [AEGIS128L.nonce_length]u8 = [_]u8{0x00} ** 16;
test "Aegis128L test vector 3" {
const key: [Aegis128L.key_length]u8 = [_]u8{0x00} ** 16;
const nonce: [Aegis128L.nonce_length]u8 = [_]u8{0x00} ** 16;
const ad = [_]u8{};
const m = [_]u8{};
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS128L.tag_length]u8 = undefined;
var tag: [Aegis128L.tag_length]u8 = undefined;
AEGIS128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS128L.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis128L.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis128L.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("83cc600dc4e3e7e62d4055826174f149", &tag);
}
test "AEGIS256 test vector 1" {
const key: [AEGIS256.key_length]u8 = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** 30;
const nonce: [AEGIS256.nonce_length]u8 = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** 29;
test "Aegis256 test vector 1" {
const key: [Aegis256.key_length]u8 = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** 30;
const nonce: [Aegis256.nonce_length]u8 = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** 29;
const ad = [8]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
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 };
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS256.tag_length]u8 = undefined;
var tag: [Aegis256.tag_length]u8 = undefined;
AEGIS256.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS256.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis256.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis256.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("f373079ed84b2709faee373584585d60accd191db310ef5d8b11833df9dec711", &c);
htest.assertEqual("8d86f91ee606e9ff26a01b64ccbdd91d", &tag);
c[0] +%= 1;
testing.expectError(error.AuthenticationFailed, AEGIS256.decrypt(&m2, &c, tag, &ad, nonce, key));
testing.expectError(error.AuthenticationFailed, Aegis256.decrypt(&m2, &c, tag, &ad, nonce, key));
c[0] -%= 1;
tag[0] +%= 1;
testing.expectError(error.AuthenticationFailed, AEGIS256.decrypt(&m2, &c, tag, &ad, nonce, key));
testing.expectError(error.AuthenticationFailed, Aegis256.decrypt(&m2, &c, tag, &ad, nonce, key));
}
test "AEGIS256 test vector 2" {
const key: [AEGIS256.key_length]u8 = [_]u8{0x00} ** 32;
const nonce: [AEGIS256.nonce_length]u8 = [_]u8{0x00} ** 32;
test "Aegis256 test vector 2" {
const key: [Aegis256.key_length]u8 = [_]u8{0x00} ** 32;
const nonce: [Aegis256.nonce_length]u8 = [_]u8{0x00} ** 32;
const ad = [_]u8{};
const m = [_]u8{0x00} ** 16;
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS256.tag_length]u8 = undefined;
var tag: [Aegis256.tag_length]u8 = undefined;
AEGIS256.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS256.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis256.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis256.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("b98f03a947807713d75a4fff9fc277a6", &c);
htest.assertEqual("478f3b50dc478ef7d5cf2d0f7cc13180", &tag);
}
test "AEGIS256 test vector 3" {
const key: [AEGIS256.key_length]u8 = [_]u8{0x00} ** 32;
const nonce: [AEGIS256.nonce_length]u8 = [_]u8{0x00} ** 32;
test "Aegis256 test vector 3" {
const key: [Aegis256.key_length]u8 = [_]u8{0x00} ** 32;
const nonce: [Aegis256.nonce_length]u8 = [_]u8{0x00} ** 32;
const ad = [_]u8{};
const m = [_]u8{};
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AEGIS256.tag_length]u8 = undefined;
var tag: [Aegis256.tag_length]u8 = undefined;
AEGIS256.encrypt(&c, &tag, &m, &ad, nonce, key);
try AEGIS256.decrypt(&m2, &c, tag, &ad, nonce, key);
Aegis256.encrypt(&c, &tag, &m, &ad, nonce, key);
try Aegis256.decrypt(&m2, &c, tag, &ad, nonce, key);
testing.expectEqualSlices(u8, &m, &m2);
htest.assertEqual("f7a0878f68bd083e8065354071fc27c3", &tag);

View File

@ -21,10 +21,10 @@ impl: {
};
pub const Block = impl.Block;
pub const AESEncryptCtx = impl.AESEncryptCtx;
pub const AESDecryptCtx = impl.AESDecryptCtx;
pub const AES128 = impl.AES128;
pub const AES256 = impl.AES256;
pub const AesEncryptCtx = impl.AesEncryptCtx;
pub const AesDecryptCtx = impl.AesDecryptCtx;
pub const Aes128 = impl.Aes128;
pub const Aes256 = impl.Aes256;
test "ctr" {
// NIST SP 800-38A pp 55-58
@ -46,8 +46,8 @@ test "ctr" {
};
var out: [exp_out.len]u8 = undefined;
var ctx = AES128.initEnc(key);
ctr(AESEncryptCtx(AES128), ctx, out[0..], in[0..], iv, builtin.Endian.Big);
var ctx = Aes128.initEnc(key);
ctr(AesEncryptCtx(Aes128), ctx, out[0..], in[0..], iv, builtin.Endian.Big);
testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
}
@ -59,7 +59,7 @@ test "encrypt" {
const exp_out = [_]u8{ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
var out: [exp_out.len]u8 = undefined;
var ctx = AES128.initEnc(key);
var ctx = Aes128.initEnc(key);
ctx.encrypt(out[0..], in[0..]);
testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
}
@ -74,7 +74,7 @@ test "encrypt" {
const exp_out = [_]u8{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
var out: [exp_out.len]u8 = undefined;
var ctx = AES256.initEnc(key);
var ctx = Aes256.initEnc(key);
ctx.encrypt(out[0..], in[0..]);
testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
}
@ -88,7 +88,7 @@ test "decrypt" {
const exp_out = [_]u8{ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
var out: [exp_out.len]u8 = undefined;
var ctx = AES128.initDec(key);
var ctx = Aes128.initDec(key);
ctx.decrypt(out[0..], in[0..]);
testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
}
@ -103,7 +103,7 @@ test "decrypt" {
const exp_out = [_]u8{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
var out: [exp_out.len]u8 = undefined;
var ctx = AES256.initDec(key);
var ctx = Aes256.initDec(key);
ctx.decrypt(out[0..], in[0..]);
testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
}
@ -117,8 +117,8 @@ test "expand 128-bit key" {
const exp_dec = [_]*const [32:0]u8{
"2b7e151628aed2a6abf7158809cf4f3c", "a0fafe1788542cb123a339392a6c7605", "f2c295f27a96b9435935807a7359f67f", "3d80477d4716fe3e1e237e446d7a883b", "ef44a541a8525b7fb671253bdb0bad00", "d4d1c6f87c839d87caf2b8bc11f915bc", "6d88a37a110b3efddbf98641ca0093fd", "4e54f70e5f5fc9f384a64fb24ea6dc4f", "ead27321b58dbad2312bf5607f8d292f", "ac7766f319fadc2128d12941575c006e", "d014f9a8c9ee2589e13f0cc8b6630ca6",
};
const enc = AES128.initEnc(key);
const dec = AES128.initDec(key);
const enc = Aes128.initEnc(key);
const dec = Aes128.initDec(key);
var exp: [16]u8 = undefined;
for (enc.key_schedule.round_keys) |round_key, i| {
@ -139,8 +139,8 @@ test "expand 256-bit key" {
const exp_dec = [_]*const [32:0]u8{
"fe4890d1e6188d0b046df344706c631e", "ada23f4963e23b2455427c8a5c709104", "57c96cf6074f07c0706abb07137f9241", "b668b621ce40046d36a047ae0932ed8e", "34ad1e4450866b367725bcc763152946", "32526c367828b24cf8e043c33f92aa20", "c440b289642b757227a3d7f114309581", "d669a7334a7ade7a80c8f18fc772e9e3", "25ba3c22a06bc7fb4388a28333934270", "54fb808b9c137949cab22ff547ba186c", "6c3d632985d1fbd9e3e36578701be0f3", "4a7459f9c8e8f9c256a156bc8d083799", "42107758e9ec98f066329ea193f8858b", "8ec6bff6829ca03b9e49af7edba96125", "603deb1015ca71be2b73aef0857d7781",
};
const enc = AES256.initEnc(key);
const dec = AES256.initDec(key);
const enc = Aes256.initEnc(key);
const dec = Aes256.initDec(key);
var exp: [16]u8 = undefined;
for (enc.key_schedule.round_keys) |round_key, i| {

View File

@ -13,7 +13,7 @@ const BlockVec = Vector(2, u64);
/// A single AES block.
pub const Block = struct {
pub const block_size: usize = 16;
pub const block_length: usize = 16;
/// Internal representation of a block.
repr: BlockVec,
@ -165,9 +165,9 @@ pub const Block = struct {
};
};
fn KeySchedule(comptime AES: type) type {
std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
const rounds = AES.rounds;
fn KeySchedule(comptime Aes: type) type {
std.debug.assert(Aes.rounds == 10 or Aes.rounds == 14);
const rounds = Aes.rounds;
return struct {
const Self = @This();
@ -243,24 +243,24 @@ fn KeySchedule(comptime AES: type) type {
}
/// A context to perform encryption using the standard AES key schedule.
pub fn AESEncryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesEncryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a new encryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
pub fn init(key: [Aes.key_bits / 8]u8) Self {
var t1 = Block.fromBytes(key[0..16]);
const key_schedule = if (AES.key_bits == 128) ks: {
break :ks KeySchedule(AES).expand128(&t1);
const key_schedule = if (Aes.key_bits == 128) ks: {
break :ks KeySchedule(Aes).expand128(&t1);
} else ks: {
var t2 = Block.fromBytes(key[16..32]);
break :ks KeySchedule(AES).expand256(&t1, &t2);
break :ks KeySchedule(Aes).expand256(&t1, &t2);
};
return Self{
.key_schedule = key_schedule,
@ -335,26 +335,26 @@ pub fn AESEncryptCtx(comptime AES: type) type {
}
/// A context to perform decryption using the standard AES key schedule.
pub fn AESDecryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesDecryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a decryption context from an existing encryption context.
pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
pub fn initFromEnc(ctx: AesEncryptCtx(Aes)) Self {
return Self{
.key_schedule = ctx.key_schedule.invert(),
};
}
/// Create a new decryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
const enc_ctx = AESEncryptCtx(AES).init(key);
pub fn init(key: [Aes.key_bits / 8]u8) Self {
const enc_ctx = AesEncryptCtx(Aes).init(key);
return initFromEnc(enc_ctx);
}
@ -395,35 +395,35 @@ pub fn AESDecryptCtx(comptime AES: type) type {
}
/// AES-128 with the standard key schedule.
pub const AES128 = struct {
pub const Aes128 = struct {
pub const key_bits: usize = 128;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
return AESEncryptCtx(AES128).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes128) {
return AesEncryptCtx(Aes128).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
return AESDecryptCtx(AES128).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes128) {
return AesDecryptCtx(Aes128).init(key);
}
};
/// AES-256 with the standard key schedule.
pub const AES256 = struct {
pub const Aes256 = struct {
pub const key_bits: usize = 256;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
return AESEncryptCtx(AES256).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes256) {
return AesEncryptCtx(Aes256).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
return AESDecryptCtx(AES256).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes256) {
return AesDecryptCtx(Aes256).init(key);
}
};

View File

@ -13,7 +13,7 @@ const BlockVec = Vector(2, u64);
/// A single AES block.
pub const Block = struct {
pub const block_size: usize = 16;
pub const block_length: usize = 16;
/// Internal representation of a block.
repr: BlockVec,
@ -181,9 +181,9 @@ pub const Block = struct {
};
};
fn KeySchedule(comptime AES: type) type {
std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
const rounds = AES.rounds;
fn KeySchedule(comptime Aes: type) type {
std.debug.assert(Aes.rounds == 10 or Aes.rounds == 14);
const rounds = Aes.rounds;
return struct {
const Self = @This();
@ -304,24 +304,24 @@ fn KeySchedule(comptime AES: type) type {
}
/// A context to perform encryption using the standard AES key schedule.
pub fn AESEncryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesEncryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a new encryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
pub fn init(key: [Aes.key_bits / 8]u8) Self {
var t1 = Block.fromBytes(key[0..16]);
const key_schedule = if (AES.key_bits == 128) ks: {
break :ks KeySchedule(AES).expand128(&t1);
const key_schedule = if (Aes.key_bits == 128) ks: {
break :ks KeySchedule(Aes).expand128(&t1);
} else ks: {
var t2 = Block.fromBytes(key[16..32]);
break :ks KeySchedule(AES).expand256(&t1, &t2);
break :ks KeySchedule(Aes).expand256(&t1, &t2);
};
return Self{
.key_schedule = key_schedule,
@ -396,26 +396,26 @@ pub fn AESEncryptCtx(comptime AES: type) type {
}
/// A context to perform decryption using the standard AES key schedule.
pub fn AESDecryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesDecryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a decryption context from an existing encryption context.
pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
pub fn initFromEnc(ctx: AesEncryptCtx(Aes)) Self {
return Self{
.key_schedule = ctx.key_schedule.invert(),
};
}
/// Create a new decryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
const enc_ctx = AESEncryptCtx(AES).init(key);
pub fn init(key: [Aes.key_bits / 8]u8) Self {
const enc_ctx = AesEncryptCtx(Aes).init(key);
return initFromEnc(enc_ctx);
}
@ -456,35 +456,35 @@ pub fn AESDecryptCtx(comptime AES: type) type {
}
/// AES-128 with the standard key schedule.
pub const AES128 = struct {
pub const Aes128 = struct {
pub const key_bits: usize = 128;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
return AESEncryptCtx(AES128).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes128) {
return AesEncryptCtx(Aes128).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
return AESDecryptCtx(AES128).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes128) {
return AesDecryptCtx(Aes128).init(key);
}
};
/// AES-256 with the standard key schedule.
pub const AES256 = struct {
pub const Aes256 = struct {
pub const key_bits: usize = 256;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
return AESEncryptCtx(AES256).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes256) {
return AesEncryptCtx(Aes256).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
return AESDecryptCtx(AES256).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes256) {
return AesDecryptCtx(Aes256).init(key);
}
};

View File

@ -12,7 +12,7 @@ const BlockVec = [4]u32;
/// A single AES block.
pub const Block = struct {
pub const block_size: usize = 16;
pub const block_length: usize = 16;
/// Internal representation of a block.
repr: BlockVec align(16),
@ -222,19 +222,19 @@ pub const Block = struct {
};
};
fn KeySchedule(comptime AES: type) type {
std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
const key_size = AES.key_bits / 8;
const rounds = AES.rounds;
fn KeySchedule(comptime Aes: type) type {
std.debug.assert(Aes.rounds == 10 or Aes.rounds == 14);
const key_length = Aes.key_bits / 8;
const rounds = Aes.rounds;
return struct {
const Self = @This();
const words_in_key = key_size / 4;
const words_in_key = key_length / 4;
round_keys: [rounds + 1]Block,
// Key expansion algorithm. See FIPS-197, Figure 11.
fn expandKey(key: [key_size]u8) Self {
fn expandKey(key: [key_length]u8) Self {
const subw = struct {
// Apply sbox0 to each byte in w.
fn func(w: u32) u32 {
@ -282,19 +282,19 @@ fn KeySchedule(comptime AES: type) type {
}
/// A context to perform encryption using the standard AES key schedule.
pub fn AESEncryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesEncryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a new encryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
const key_schedule = KeySchedule(AES).expandKey(key);
pub fn init(key: [Aes.key_bits / 8]u8) Self {
const key_schedule = KeySchedule(Aes).expandKey(key);
return Self{
.key_schedule = key_schedule,
};
@ -343,26 +343,26 @@ pub fn AESEncryptCtx(comptime AES: type) type {
}
/// A context to perform decryption using the standard AES key schedule.
pub fn AESDecryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
pub fn AesDecryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a decryption context from an existing encryption context.
pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
pub fn initFromEnc(ctx: AesEncryptCtx(Aes)) Self {
return Self{
.key_schedule = ctx.key_schedule.invert(),
};
}
/// Create a new decryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
const enc_ctx = AESEncryptCtx(AES).init(key);
pub fn init(key: [Aes.key_bits / 8]u8) Self {
const enc_ctx = AesEncryptCtx(Aes).init(key);
return initFromEnc(enc_ctx);
}
@ -389,36 +389,36 @@ pub fn AESDecryptCtx(comptime AES: type) type {
}
/// AES-128 with the standard key schedule.
pub const AES128 = struct {
pub const Aes128 = struct {
pub const key_bits: usize = 128;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
return AESEncryptCtx(AES128).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes128) {
return AesEncryptCtx(Aes128).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
return AESDecryptCtx(AES128).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes128) {
return AesDecryptCtx(Aes128).init(key);
}
};
/// AES-256 with the standard key schedule.
pub const AES256 = struct {
pub const Aes256 = struct {
pub const key_bits: usize = 256;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
return AESEncryptCtx(AES256).init(key);
pub fn initEnc(key: [key_bits / 8]u8) AesEncryptCtx(Aes256) {
return AesEncryptCtx(Aes256).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
return AESDecryptCtx(AES256).init(key);
pub fn initDec(key: [key_bits / 8]u8) AesDecryptCtx(Aes256) {
return AesDecryptCtx(Aes256).init(key);
}
};

View File

@ -7,16 +7,16 @@ const Ghash = std.crypto.onetimeauth.Ghash;
const mem = std.mem;
const modes = crypto.core.modes;
pub const AES128GCM = AESGCM(crypto.core.aes.AES128);
pub const AES256GCM = AESGCM(crypto.core.aes.AES256);
pub const Aes128Gcm = AesGcm(crypto.core.aes.Aes128);
pub const Aes256Gcm = AesGcm(crypto.core.aes.Aes256);
fn AESGCM(comptime AES: anytype) type {
debug.assert(AES.block.block_size == 16);
fn AesGcm(comptime Aes: anytype) type {
debug.assert(Aes.block.block_length == 16);
return struct {
pub const tag_length = 16;
pub const nonce_length = 12;
pub const key_length = AES.key_bits / 8;
pub const key_length = Aes.key_bits / 8;
const zeros = [_]u8{0} ** 16;
@ -24,7 +24,7 @@ fn AESGCM(comptime AES: anytype) type {
debug.assert(c.len == m.len);
debug.assert(m.len <= 16 * ((1 << 32) - 2));
const aes = AES.initEnc(key);
const aes = Aes.initEnc(key);
var h: [16]u8 = undefined;
aes.encrypt(&h, &zeros);
@ -56,7 +56,7 @@ fn AESGCM(comptime AES: anytype) type {
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) !void {
assert(c.len == m.len);
const aes = AES.initEnc(key);
const aes = Aes.initEnc(key);
var h: [16]u8 = undefined;
aes.encrypt(&h, &zeros);
@ -101,59 +101,59 @@ fn AESGCM(comptime AES: anytype) type {
const htest = @import("test.zig");
const testing = std.testing;
test "AES256GCM - Empty message and no associated data" {
const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
test "Aes256Gcm - Empty message and no associated data" {
const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length;
const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length;
const ad = "";
const m = "";
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AES256GCM.tag_length]u8 = undefined;
var tag: [Aes256Gcm.tag_length]u8 = undefined;
AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
Aes256Gcm.encrypt(&c, &tag, m, ad, nonce, key);
htest.assertEqual("6b6ff610a16fa4cd59f1fb7903154e92", &tag);
}
test "AES256GCM - Associated data only" {
const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
test "Aes256Gcm - Associated data only" {
const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length;
const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length;
const m = "";
const ad = "Test with associated data";
var c: [m.len]u8 = undefined;
var tag: [AES256GCM.tag_length]u8 = undefined;
var tag: [Aes256Gcm.tag_length]u8 = undefined;
AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
Aes256Gcm.encrypt(&c, &tag, m, ad, nonce, key);
htest.assertEqual("262ed164c2dfb26e080a9d108dd9dd4c", &tag);
}
test "AES256GCM - Message only" {
const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
test "Aes256Gcm - Message only" {
const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length;
const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length;
const m = "Test with message only";
const ad = "";
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AES256GCM.tag_length]u8 = undefined;
var tag: [Aes256Gcm.tag_length]u8 = undefined;
AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
try AES256GCM.decrypt(&m2, &c, tag, ad, nonce, key);
Aes256Gcm.encrypt(&c, &tag, m, ad, nonce, key);
try Aes256Gcm.decrypt(&m2, &c, tag, ad, nonce, key);
testing.expectEqualSlices(u8, m[0..], m2[0..]);
htest.assertEqual("5ca1642d90009fea33d01f78cf6eefaf01d539472f7c", &c);
htest.assertEqual("07cd7fc9103e2f9e9bf2dfaa319caff4", &tag);
}
test "AES256GCM - Message and associated data" {
const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
test "Aes256Gcm - Message and associated data" {
const key: [Aes256Gcm.key_length]u8 = [_]u8{0x69} ** Aes256Gcm.key_length;
const nonce: [Aes256Gcm.nonce_length]u8 = [_]u8{0x42} ** Aes256Gcm.nonce_length;
const m = "Test with message";
const ad = "Test with associated data";
var c: [m.len]u8 = undefined;
var m2: [m.len]u8 = undefined;
var tag: [AES256GCM.tag_length]u8 = undefined;
var tag: [Aes256Gcm.tag_length]u8 = undefined;
AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
try AES256GCM.decrypt(&m2, &c, tag, ad, nonce, key);
Aes256Gcm.encrypt(&c, &tag, m, ad, nonce, key);
try Aes256Gcm.decrypt(&m2, &c, tag, ad, nonce, key);
testing.expectEqualSlices(u8, m[0..], m2[0..]);
htest.assertEqual("5ca1642d90009fea33d01f78cf6eefaf01", &c);

View File

@ -73,7 +73,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
var in: [512 * KiB]u8 = undefined;
prng.random.bytes(in[0..]);
const key_length = if (Mac.minimum_key_length == 0) 32 else Mac.minimum_key_length;
const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;
var key: [key_length]u8 = undefined;
prng.random.bytes(key[0..]);
@ -96,12 +96,12 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
std.debug.assert(DhKeyExchange.key_length >= DhKeyExchange.secret_length);
var in: [DhKeyExchange.minimum_key_length]u8 = undefined;
var in: [DhKeyExchange.key_length]u8 = undefined;
prng.random.bytes(in[0..]);
var out: [DhKeyExchange.minimum_key_length]u8 = undefined;
var out: [DhKeyExchange.key_length]u8 = undefined;
prng.random.bytes(out[0..]);
var timer = try Timer.start();
@ -150,10 +150,10 @@ const aeads = [_]Crypto{
Crypto{ .ty = crypto.aead.ChaCha20Poly1305, .name = "chacha20Poly1305" },
Crypto{ .ty = crypto.aead.XChaCha20Poly1305, .name = "xchacha20Poly1305" },
Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" },
Crypto{ .ty = crypto.aead.AEGIS128L, .name = "aegis-128l" },
Crypto{ .ty = crypto.aead.AEGIS256, .name = "aegis-256" },
Crypto{ .ty = crypto.aead.AES128GCM, .name = "aes128-gcm" },
Crypto{ .ty = crypto.aead.AES256GCM, .name = "aes256-gcm" },
Crypto{ .ty = crypto.aead.Aegis128L, .name = "aegis-128l" },
Crypto{ .ty = crypto.aead.Aegis256, .name = "aegis-256" },
Crypto{ .ty = crypto.aead.Aes128Gcm, .name = "aes128-gcm" },
Crypto{ .ty = crypto.aead.Aes256Gcm, .name = "aes256-gcm" },
};
pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
@ -185,14 +185,14 @@ pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64
}
const aes = [_]Crypto{
Crypto{ .ty = crypto.core.aes.AES128, .name = "aes128-single" },
Crypto{ .ty = crypto.core.aes.AES256, .name = "aes256-single" },
Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-single" },
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-single" },
};
pub fn benchmarkAES(comptime AES: anytype, comptime count: comptime_int) !u64 {
var key: [AES.key_bits / 8]u8 = undefined;
pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
var key: [Aes.key_bits / 8]u8 = undefined;
prng.random.bytes(key[0..]);
const ctx = AES.initEnc(key);
const ctx = Aes.initEnc(key);
var in = [_]u8{0} ** 16;
@ -214,14 +214,14 @@ pub fn benchmarkAES(comptime AES: anytype, comptime count: comptime_int) !u64 {
}
const aes8 = [_]Crypto{
Crypto{ .ty = crypto.core.aes.AES128, .name = "aes128-8" },
Crypto{ .ty = crypto.core.aes.AES256, .name = "aes256-8" },
Crypto{ .ty = crypto.core.aes.Aes128, .name = "aes128-8" },
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-8" },
};
pub fn benchmarkAES8(comptime AES: anytype, comptime count: comptime_int) !u64 {
var key: [AES.key_bits / 8]u8 = undefined;
pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
var key: [Aes.key_bits / 8]u8 = undefined;
prng.random.bytes(key[0..]);
const ctx = AES.initEnc(key);
const ctx = Aes.initEnc(key);
var in = [_]u8{0} ** (8 * 16);
@ -335,14 +335,14 @@ pub fn main() !void {
inline for (aes) |E| {
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
const throughput = try benchmarkAES(E.ty, mode(100000000));
const throughput = try benchmarkAes(E.ty, mode(100000000));
try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
}
}
inline for (aes8) |E| {
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
const throughput = try benchmarkAES8(E.ty, mode(10000000));
const throughput = try benchmarkAes8(E.ty, mode(10000000));
try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
}
}

View File

@ -18,7 +18,7 @@ const RoundParam = struct {
y: usize,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
fn roundParam(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
return RoundParam{
.a = a,
.b = b,
@ -32,14 +32,18 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) RoundParam {
/////////////////////
// Blake2s
pub const Blake2s128 = Blake2s(128);
pub const Blake2s224 = Blake2s(224);
pub const Blake2s256 = Blake2s(256);
pub fn Blake2s(comptime out_len: usize) type {
pub fn Blake2s(comptime out_bits: usize) type {
return struct {
const Self = @This();
pub const block_length = 64;
pub const digest_length = out_len / 8;
pub const digest_length = out_bits / 8;
pub const key_length_min = 0;
pub const key_length_max = 32;
pub const key_length = 32; // recommended key length
pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null };
const iv = [8]u32{
@ -73,14 +77,14 @@ pub fn Blake2s(comptime out_len: usize) type {
buf_len: u8,
pub fn init(options: Options) Self {
debug.assert(8 <= out_len and out_len <= 512);
debug.assert(8 <= out_bits and out_bits <= 256);
var d: Self = undefined;
mem.copy(u32, d.h[0..], iv[0..]);
const key_len = if (options.key) |key| key.len else 0;
// default parameters
d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_len >> 3);
d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_bits >> 3);
d.t = 0;
d.buf_len = 0;
@ -100,7 +104,7 @@ pub fn Blake2s(comptime out_len: usize) type {
return d;
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Self.init(options);
d.update(b);
d.final(out);
@ -129,14 +133,12 @@ pub fn Blake2s(comptime out_len: usize) type {
d.buf_len += @intCast(u8, b[off..].len);
}
pub fn final(d: *Self, out: []u8) void {
debug.assert(out.len >= out_len / 8);
pub fn final(d: *Self, out: *[digest_length]u8) void {
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
const rr = d.h[0 .. out_len / 32];
const rr = d.h[0 .. digest_length / 4];
for (rr) |s, j| {
mem.writeIntSliceLittle(u32, out[4 * j ..], s);
@ -164,14 +166,14 @@ pub fn Blake2s(comptime out_len: usize) type {
if (last) v[14] = ~v[14];
const rounds = comptime [_]RoundParam{
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
roundParam(0, 4, 8, 12, 0, 1),
roundParam(1, 5, 9, 13, 2, 3),
roundParam(2, 6, 10, 14, 4, 5),
roundParam(3, 7, 11, 15, 6, 7),
roundParam(0, 5, 10, 15, 8, 9),
roundParam(1, 6, 11, 12, 10, 11),
roundParam(2, 7, 8, 13, 12, 13),
roundParam(3, 4, 9, 14, 14, 15),
};
comptime var j: usize = 0;
@ -372,15 +374,19 @@ test "comptime blake2s256" {
/////////////////////
// Blake2b
pub const Blake2b128 = Blake2b(128);
pub const Blake2b256 = Blake2b(256);
pub const Blake2b384 = Blake2b(384);
pub const Blake2b512 = Blake2b(512);
pub fn Blake2b(comptime out_len: usize) type {
pub fn Blake2b(comptime out_bits: usize) type {
return struct {
const Self = @This();
pub const block_length = 128;
pub const digest_length = out_len / 8;
pub const digest_length = out_bits / 8;
pub const key_length_min = 0;
pub const key_length_max = 64;
pub const key_length = 32; // recommended key length
pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null };
const iv = [8]u64{
@ -416,14 +422,14 @@ pub fn Blake2b(comptime out_len: usize) type {
buf_len: u8,
pub fn init(options: Options) Self {
debug.assert(8 <= out_len and out_len <= 512);
debug.assert(8 <= out_bits and out_bits <= 512);
var d: Self = undefined;
mem.copy(u64, d.h[0..], iv[0..]);
const key_len = if (options.key) |key| key.len else 0;
// default parameters
d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_len >> 3);
d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_bits >> 3);
d.t = 0;
d.buf_len = 0;
@ -443,7 +449,7 @@ pub fn Blake2b(comptime out_len: usize) type {
return d;
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Self.init(options);
d.update(b);
d.final(out);
@ -472,12 +478,12 @@ pub fn Blake2b(comptime out_len: usize) type {
d.buf_len += @intCast(u8, b[off..].len);
}
pub fn final(d: *Self, out: []u8) void {
pub fn final(d: *Self, out: *[digest_length]u8) void {
mem.set(u8, d.buf[d.buf_len..], 0);
d.t += d.buf_len;
d.round(d.buf[0..], true);
const rr = d.h[0 .. out_len / 64];
const rr = d.h[0 .. digest_length / 8];
for (rr) |s, j| {
mem.writeIntSliceLittle(u64, out[8 * j ..], s);
@ -505,14 +511,14 @@ pub fn Blake2b(comptime out_len: usize) type {
if (last) v[14] = ~v[14];
const rounds = comptime [_]RoundParam{
Rp(0, 4, 8, 12, 0, 1),
Rp(1, 5, 9, 13, 2, 3),
Rp(2, 6, 10, 14, 4, 5),
Rp(3, 7, 11, 15, 6, 7),
Rp(0, 5, 10, 15, 8, 9),
Rp(1, 6, 11, 12, 10, 11),
Rp(2, 7, 8, 13, 12, 13),
Rp(3, 4, 9, 14, 14, 15),
roundParam(0, 4, 8, 12, 0, 1),
roundParam(1, 5, 9, 13, 2, 3),
roundParam(2, 6, 10, 14, 4, 5),
roundParam(3, 7, 11, 15, 6, 7),
roundParam(0, 5, 10, 15, 8, 9),
roundParam(1, 6, 11, 12, 10, 11),
roundParam(2, 7, 8, 13, 12, 13),
roundParam(3, 4, 9, 14, 14, 15),
};
comptime var j: usize = 0;

View File

@ -124,11 +124,11 @@ fn compress(
return state;
}
fn first_8_words(words: [16]u32) [8]u32 {
fn first8Words(words: [16]u32) [8]u32 {
return @ptrCast(*const [8]u32, &words).*;
}
fn words_from_little_endian_bytes(words: []u32, bytes: []const u8) void {
fn wordsFromLittleEndianBytes(words: []u32, bytes: []const u8) void {
var byte_slice = bytes;
for (words) |*word| {
word.* = mem.readIntSliceLittle(u32, byte_slice);
@ -146,8 +146,8 @@ const Output = struct {
counter: u64,
flags: u8,
fn chaining_value(self: *const Output) [8]u32 {
return first_8_words(compress(
fn chainingValue(self: *const Output) [8]u32 {
return first8Words(compress(
self.input_chaining_value,
self.block_words,
self.block_len,
@ -156,7 +156,7 @@ const Output = struct {
));
}
fn root_output_bytes(self: *const Output, output: []u8) void {
fn rootOutputBytes(self: *const Output, output: []u8) void {
var out_block_it = ChunkIterator.init(output, 2 * OUT_LEN);
var output_block_counter: usize = 0;
while (out_block_it.next()) |out_block| {
@ -200,7 +200,7 @@ const ChunkState = struct {
return BLOCK_LEN * @as(usize, self.blocks_compressed) + @as(usize, self.block_len);
}
fn fill_block_buf(self: *ChunkState, input: []const u8) []const u8 {
fn fillBlockBuf(self: *ChunkState, input: []const u8) []const u8 {
const want = BLOCK_LEN - self.block_len;
const take = math.min(want, input.len);
mem.copy(u8, self.block[self.block_len..][0..take], input[0..take]);
@ -208,7 +208,7 @@ const ChunkState = struct {
return input[take..];
}
fn start_flag(self: *const ChunkState) u8 {
fn startFlag(self: *const ChunkState) u8 {
return if (self.blocks_compressed == 0) CHUNK_START else 0;
}
@ -219,13 +219,13 @@ const ChunkState = struct {
// input is coming, so this compression is not CHUNK_END.
if (self.block_len == BLOCK_LEN) {
var block_words: [16]u32 = undefined;
words_from_little_endian_bytes(block_words[0..], self.block[0..]);
self.chaining_value = first_8_words(compress(
wordsFromLittleEndianBytes(block_words[0..], self.block[0..]);
self.chaining_value = first8Words(compress(
self.chaining_value,
block_words,
BLOCK_LEN,
self.chunk_counter,
self.flags | self.start_flag(),
self.flags | self.startFlag(),
));
self.blocks_compressed += 1;
self.block = [_]u8{0} ** BLOCK_LEN;
@ -233,24 +233,24 @@ const ChunkState = struct {
}
// Copy input bytes into the block buffer.
input = self.fill_block_buf(input);
input = self.fillBlockBuf(input);
}
}
fn output(self: *const ChunkState) Output {
var block_words: [16]u32 = undefined;
words_from_little_endian_bytes(block_words[0..], self.block[0..]);
wordsFromLittleEndianBytes(block_words[0..], self.block[0..]);
return Output{
.input_chaining_value = self.chaining_value,
.block_words = block_words,
.block_len = self.block_len,
.counter = self.chunk_counter,
.flags = self.flags | self.start_flag() | CHUNK_END,
.flags = self.flags | self.startFlag() | CHUNK_END,
};
}
};
fn parent_output(
fn parentOutput(
left_child_cv: [8]u32,
right_child_cv: [8]u32,
key: [8]u32,
@ -268,18 +268,18 @@ fn parent_output(
};
}
fn parent_cv(
fn parentCv(
left_child_cv: [8]u32,
right_child_cv: [8]u32,
key: [8]u32,
flags: u8,
) [8]u32 {
return parent_output(left_child_cv, right_child_cv, key, flags).chaining_value();
return parentOutput(left_child_cv, right_child_cv, key, flags).chainingValue();
}
/// An incremental hasher that can accept any number of writes.
pub const Blake3 = struct {
pub const Options = struct { key: ?[KEY_LEN]u8 = null };
pub const Options = struct { key: ?[digest_length]u8 = null };
pub const KdfOptions = struct {};
chunk_state: ChunkState,
@ -288,8 +288,9 @@ pub const Blake3 = struct {
cv_stack_len: u8 = 0, // 2^54 * CHUNK_LEN = 2^64
flags: u8,
pub const digest_length = OUT_LEN;
pub const block_length = BLOCK_LEN;
pub const digest_length = OUT_LEN;
pub const key_length = KEY_LEN;
fn init_internal(key: [8]u32, flags: u8) Blake3 {
return Blake3{
@ -303,7 +304,7 @@ pub const Blake3 = struct {
pub fn init(options: Options) Blake3 {
if (options.key) |key| {
var key_words: [8]u32 = undefined;
words_from_little_endian_bytes(key_words[0..], key[0..]);
wordsFromLittleEndianBytes(key_words[0..], key[0..]);
return Blake3.init_internal(key_words, KEYED_HASH);
} else {
return Blake3.init_internal(IV, 0);
@ -318,7 +319,7 @@ pub const Blake3 = struct {
var context_key: [KEY_LEN]u8 = undefined;
context_hasher.final(context_key[0..]);
var context_key_words: [8]u32 = undefined;
words_from_little_endian_bytes(context_key_words[0..], context_key[0..]);
wordsFromLittleEndianBytes(context_key_words[0..], context_key[0..]);
return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL);
}
@ -328,18 +329,18 @@ pub const Blake3 = struct {
hasher.final(out);
}
fn push_cv(self: *Blake3, cv: [8]u32) void {
fn pushCv(self: *Blake3, cv: [8]u32) void {
self.cv_stack[self.cv_stack_len] = cv;
self.cv_stack_len += 1;
}
fn pop_cv(self: *Blake3) [8]u32 {
fn popCv(self: *Blake3) [8]u32 {
self.cv_stack_len -= 1;
return self.cv_stack[self.cv_stack_len];
}
// Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail.
fn add_chunk_chaining_value(self: *Blake3, first_cv: [8]u32, total_chunks: u64) void {
fn addChunkChainingValue(self: *Blake3, first_cv: [8]u32, total_chunks: u64) void {
// This chunk might complete some subtrees. For each completed subtree,
// its left child will be the current top entry in the CV stack, and
// its right child will be the current value of `new_cv`. Pop each left
@ -350,10 +351,10 @@ pub const Blake3 = struct {
var new_cv = first_cv;
var chunk_counter = total_chunks;
while (chunk_counter & 1 == 0) {
new_cv = parent_cv(self.pop_cv(), new_cv, self.key, self.flags);
new_cv = parentCv(self.popCv(), new_cv, self.key, self.flags);
chunk_counter >>= 1;
}
self.push_cv(new_cv);
self.pushCv(new_cv);
}
/// Add input to the hash state. This can be called any number of times.
@ -363,9 +364,9 @@ pub const Blake3 = struct {
// If the current chunk is complete, finalize it and reset the
// chunk state. More input is coming, so this chunk is not ROOT.
if (self.chunk_state.len() == CHUNK_LEN) {
const chunk_cv = self.chunk_state.output().chaining_value();
const chunk_cv = self.chunk_state.output().chainingValue();
const total_chunks = self.chunk_state.chunk_counter + 1;
self.add_chunk_chaining_value(chunk_cv, total_chunks);
self.addChunkChainingValue(chunk_cv, total_chunks);
self.chunk_state = ChunkState.init(self.key, total_chunks, self.flags);
}
@ -386,14 +387,14 @@ pub const Blake3 = struct {
var parent_nodes_remaining: usize = self.cv_stack_len;
while (parent_nodes_remaining > 0) {
parent_nodes_remaining -= 1;
output = parent_output(
output = parentOutput(
self.cv_stack[parent_nodes_remaining],
output.chaining_value(),
output.chainingValue(),
self.key,
self.flags,
);
}
output.root_output_bytes(out_slice);
output.rootOutputBytes(out_slice);
}
};
@ -561,7 +562,7 @@ const reference_test = ReferenceTest{
},
};
fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
// Save initial state
const initial_state = hasher.*;
@ -596,8 +597,8 @@ test "BLAKE3 reference test cases" {
var derive_key = &Blake3.initKdf(reference_test.context_string, .{});
for (reference_test.cases) |t| {
test_blake3(hash, t.input_len, t.hash.*);
test_blake3(keyed_hash, t.input_len, t.keyed_hash.*);
test_blake3(derive_key, t.input_len, t.derive_key.*);
testBlake3(hash, t.input_len, t.hash.*);
testBlake3(keyed_hash, t.input_len, t.keyed_hash.*);
testBlake3(derive_key, t.input_len, t.derive_key.*);
}
}

View File

@ -317,7 +317,7 @@ fn keyToWords(key: [32]u8) [8]u32 {
/// counter, nonce, and key.
pub const ChaCha20IETF = struct {
pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
assert(in.len >= out.len);
assert(in.len == out.len);
assert((in.len >> 6) + counter <= maxInt(u32));
var c: [4]u32 = undefined;
@ -334,7 +334,7 @@ pub const ChaCha20IETF = struct {
/// exceed the 256 GiB limit of the 96-bit nonce version.
pub const ChaCha20With64BitNonce = struct {
pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
assert(in.len >= out.len);
assert(in.len == out.len);
assert(counter +% (in.len >> 6) >= counter);
var cursor: usize = 0;
@ -345,9 +345,9 @@ pub const ChaCha20With64BitNonce = struct {
c[2] = mem.readIntLittle(u32, nonce[0..4]);
c[3] = mem.readIntLittle(u32, nonce[4..8]);
const block_size = (1 << 6);
const block_length = (1 << 6);
// The full block size is greater than the address space on a 32bit machine
const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
const big_block = if (@sizeOf(usize) > 4) (block_length << 32) else maxInt(usize);
// first partial big block
if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
@ -621,10 +621,10 @@ test "crypto.chacha20 test vector 5" {
testing.expectEqualSlices(u8, &expected_result, &result);
}
pub const chacha20poly1305_tag_size = 16;
pub const chacha20poly1305_tag_length = 16;
fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
assert(ciphertext.len >= plaintext.len);
fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_length]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
assert(ciphertext.len == plaintext.len);
// derive poly1305 key
var polyKey = [_]u8{0} ** 32;
@ -655,13 +655,13 @@ fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_si
}
fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce);
return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_length], plaintext, data, key, nonce);
}
/// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached.
fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_length]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
// split ciphertext and tag
assert(dst.len >= ciphertext.len);
assert(dst.len == ciphertext.len);
// derive poly1305 key
var polyKey = [_]u8{0} ** 32;
@ -706,11 +706,11 @@ fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [
/// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal.
fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
if (ciphertextAndTag.len < chacha20poly1305_tag_size) {
if (ciphertextAndTag.len < chacha20poly1305_tag_length) {
return error.InvalidMessage;
}
const ciphertextLen = ciphertextAndTag.len - chacha20poly1305_tag_size;
return try chacha20poly1305OpenDetached(dst, ciphertextAndTag[0..ciphertextLen], ciphertextAndTag[ciphertextLen..][0..chacha20poly1305_tag_size], data, key, nonce);
const ciphertextLen = ciphertextAndTag.len - chacha20poly1305_tag_length;
return try chacha20poly1305OpenDetached(dst, ciphertextAndTag[0..ciphertextLen], ciphertextAndTag[ciphertextLen..][0..chacha20poly1305_tag_length], data, key, nonce);
}
fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } {
@ -730,9 +730,9 @@ pub const XChaCha20IETF = struct {
}
};
pub const xchacha20poly1305_tag_size = 16;
pub const xchacha20poly1305_tag_length = 16;
fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_length]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
const extended = extend(key, nonce);
return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce);
}
@ -743,7 +743,7 @@ fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []
}
/// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached.
fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_length]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
const extended = extend(key, nonce);
return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce);
}
@ -883,7 +883,7 @@ test "crypto.xchacha20" {
}
{
const data = "Additional data";
var ciphertext: [input.len + xchacha20poly1305_tag_size]u8 = undefined;
var ciphertext: [input.len + xchacha20poly1305_tag_length]u8 = undefined;
xchacha20poly1305Seal(ciphertext[0..], input, data, key, nonce);
var out: [input.len]u8 = undefined;
try xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce);

View File

@ -18,9 +18,9 @@ const mem = std.mem;
///
/// GHASH is typically used to compute the authentication tag in the AES-GCM construction.
pub const Ghash = struct {
pub const block_size: usize = 16;
pub const block_length: usize = 16;
pub const mac_length = 16;
pub const minimum_key_length = 16;
pub const key_length = 16;
y0: u64 = 0,
y1: u64 = 0,
@ -39,9 +39,9 @@ pub const Ghash = struct {
hh2r: u64 = undefined,
leftover: usize = 0,
buf: [block_size]u8 align(16) = undefined,
buf: [block_length]u8 align(16) = undefined,
pub fn init(key: *const [minimum_key_length]u8) Ghash {
pub fn init(key: *const [key_length]u8) Ghash {
const h1 = mem.readIntBig(u64, key[0..8]);
const h0 = mem.readIntBig(u64, key[8..16]);
const h1r = @bitReverse(u64, h1);
@ -261,21 +261,21 @@ pub const Ghash = struct {
var mb = m;
if (st.leftover > 0) {
const want = math.min(block_size - st.leftover, mb.len);
const want = math.min(block_length - st.leftover, mb.len);
const mc = mb[0..want];
for (mc) |x, i| {
st.buf[st.leftover + i] = x;
}
mb = mb[want..];
st.leftover += want;
if (st.leftover < block_size) {
if (st.leftover < block_length) {
return;
}
st.blocks(&st.buf);
st.leftover = 0;
}
if (mb.len >= block_size) {
const want = mb.len & ~(block_size - 1);
if (mb.len >= block_length) {
const want = mb.len & ~(block_length - 1);
st.blocks(mb[0..want]);
mb = mb[want..];
}
@ -293,7 +293,7 @@ pub const Ghash = struct {
return;
}
var i = st.leftover;
while (i < block_size) : (i += 1) {
while (i < block_length) : (i += 1) {
st.buf[i] = 0;
}
st.blocks(&st.buf);
@ -308,7 +308,7 @@ pub const Ghash = struct {
mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Ghash)]);
}
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
var st = Ghash.init(key);
st.update(msg);
st.final(out);

View File

@ -200,6 +200,7 @@ pub const Hash = struct {
buf_off: usize,
pub const block_length = State.RATE;
pub const digest_length = 32;
pub const Options = struct {};
const Self = @This();
@ -231,15 +232,13 @@ pub const Hash = struct {
}
}
pub const digest_length = 32;
/// Finish the current hashing operation, writing the hash to `out`
///
/// From 4.9 "Application to hashing"
/// By default, Gimli-Hash provides a fixed-length output of 32 bytes
/// (the concatenation of two 16-byte blocks). However, Gimli-Hash can
/// be used as an extendable one-way function (XOF).
pub fn final(self: *Self, out: []u8) void {
pub fn final(self: *Self, out: *[digest_length]u8) void {
const buf = self.state.toSlice();
// XOR 1 into the next byte of the state
@ -251,7 +250,7 @@ pub const Hash = struct {
}
};
pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
pub fn hash(out: *[Hash.digest_length]u8, in: []const u8, options: Hash.Options) void {
var st = Hash.init(options);
st.update(in);
st.final(out);

View File

@ -22,14 +22,15 @@ pub fn Hmac(comptime Hash: type) type {
return struct {
const Self = @This();
pub const mac_length = Hash.digest_length;
pub const minimum_key_length = 0;
pub const key_length_min = 0;
pub const key_length = 32; // recommended key length
o_key_pad: [Hash.block_length]u8,
i_key_pad: [Hash.block_length]u8,
scratch: [Hash.block_length]u8,
hash: Hash,
// HMAC(k, m) = H(o_key_pad | H(i_key_pad | msg)) where | is concatenation
// HMAC(k, m) = H(o_key_pad || H(i_key_pad || msg)) where || is concatenation
pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
var ctx = Self.init(key);
ctx.update(msg);

View File

@ -6,7 +6,6 @@
const std = @import("../std.zig");
const mem = std.mem;
const math = std.math;
const debug = std.debug;
const RoundParam = struct {
a: usize,
@ -18,7 +17,7 @@ const RoundParam = struct {
t: u32,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundParam {
fn roundParam(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundParam {
return RoundParam{
.a = a,
.b = b,
@ -59,7 +58,7 @@ pub const Md5 = struct {
};
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Md5.init(options);
d.update(b);
d.final(out);
@ -73,13 +72,13 @@ pub const Md5 = struct {
off += 64 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.round(d.buf[0..]);
d.round(&d.buf);
d.buf_len = 0;
}
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.round(b[off .. off + 64]);
d.round(b[off..][0..64]);
}
// Copy any remainder for next pass.
@ -90,9 +89,7 @@ pub const Md5 = struct {
d.total_len +%= b.len;
}
pub fn final(d: *Self, out: []u8) void {
debug.assert(out.len >= 16);
pub fn final(d: *Self, out: *[digest_length]u8) void {
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -122,9 +119,7 @@ pub const Md5 = struct {
}
}
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 64);
fn round(d: *Self, b: *const [64]u8) void {
var s: [16]u32 = undefined;
var i: usize = 0;
@ -145,22 +140,22 @@ pub const Md5 = struct {
};
const round0 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
roundParam(0, 1, 2, 3, 0, 7, 0xD76AA478),
roundParam(3, 0, 1, 2, 1, 12, 0xE8C7B756),
roundParam(2, 3, 0, 1, 2, 17, 0x242070DB),
roundParam(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
roundParam(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
roundParam(3, 0, 1, 2, 5, 12, 0x4787C62A),
roundParam(2, 3, 0, 1, 6, 17, 0xA8304613),
roundParam(1, 2, 3, 0, 7, 22, 0xFD469501),
roundParam(0, 1, 2, 3, 8, 7, 0x698098D8),
roundParam(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
roundParam(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
roundParam(1, 2, 3, 0, 11, 22, 0x895CD7BE),
roundParam(0, 1, 2, 3, 12, 7, 0x6B901122),
roundParam(3, 0, 1, 2, 13, 12, 0xFD987193),
roundParam(2, 3, 0, 1, 14, 17, 0xA679438E),
roundParam(1, 2, 3, 0, 15, 22, 0x49B40821),
};
inline for (round0) |r| {
v[r.a] = v[r.a] +% (v[r.d] ^ (v[r.b] & (v[r.c] ^ v[r.d]))) +% r.t +% s[r.k];
@ -168,22 +163,22 @@ pub const Md5 = struct {
}
const round1 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
Rp(3, 0, 1, 2, 10, 9, 0x02441453),
Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
roundParam(0, 1, 2, 3, 1, 5, 0xF61E2562),
roundParam(3, 0, 1, 2, 6, 9, 0xC040B340),
roundParam(2, 3, 0, 1, 11, 14, 0x265E5A51),
roundParam(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
roundParam(0, 1, 2, 3, 5, 5, 0xD62F105D),
roundParam(3, 0, 1, 2, 10, 9, 0x02441453),
roundParam(2, 3, 0, 1, 15, 14, 0xD8A1E681),
roundParam(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
roundParam(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
roundParam(3, 0, 1, 2, 14, 9, 0xC33707D6),
roundParam(2, 3, 0, 1, 3, 14, 0xF4D50D87),
roundParam(1, 2, 3, 0, 8, 20, 0x455A14ED),
roundParam(0, 1, 2, 3, 13, 5, 0xA9E3E905),
roundParam(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
roundParam(2, 3, 0, 1, 7, 14, 0x676F02D9),
roundParam(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
};
inline for (round1) |r| {
v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.d] & (v[r.b] ^ v[r.c]))) +% r.t +% s[r.k];
@ -191,22 +186,22 @@ pub const Md5 = struct {
}
const round2 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
roundParam(0, 1, 2, 3, 5, 4, 0xFFFA3942),
roundParam(3, 0, 1, 2, 8, 11, 0x8771F681),
roundParam(2, 3, 0, 1, 11, 16, 0x6D9D6122),
roundParam(1, 2, 3, 0, 14, 23, 0xFDE5380C),
roundParam(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
roundParam(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
roundParam(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
roundParam(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
roundParam(0, 1, 2, 3, 13, 4, 0x289B7EC6),
roundParam(3, 0, 1, 2, 0, 11, 0xEAA127FA),
roundParam(2, 3, 0, 1, 3, 16, 0xD4EF3085),
roundParam(1, 2, 3, 0, 6, 23, 0x04881D05),
roundParam(0, 1, 2, 3, 9, 4, 0xD9D4D039),
roundParam(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
roundParam(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
roundParam(1, 2, 3, 0, 2, 23, 0xC4AC5665),
};
inline for (round2) |r| {
v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
@ -214,22 +209,22 @@ pub const Md5 = struct {
}
const round3 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
roundParam(0, 1, 2, 3, 0, 6, 0xF4292244),
roundParam(3, 0, 1, 2, 7, 10, 0x432AFF97),
roundParam(2, 3, 0, 1, 14, 15, 0xAB9423A7),
roundParam(1, 2, 3, 0, 5, 21, 0xFC93A039),
roundParam(0, 1, 2, 3, 12, 6, 0x655B59C3),
roundParam(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
roundParam(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
roundParam(1, 2, 3, 0, 1, 21, 0x85845DD1),
roundParam(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
roundParam(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
roundParam(2, 3, 0, 1, 6, 15, 0xA3014314),
roundParam(1, 2, 3, 0, 13, 21, 0x4E0811A1),
roundParam(0, 1, 2, 3, 4, 6, 0xF7537E82),
roundParam(3, 0, 1, 2, 11, 10, 0xBD3AF235),
roundParam(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
roundParam(1, 2, 3, 0, 9, 21, 0xEB86D391),
};
inline for (round3) |r| {
v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];

View File

@ -16,34 +16,34 @@ const debug = std.debug;
///
/// Important: the counter mode doesn't provide authenticated encryption: the ciphertext can be trivially modified without this being detected.
/// As a result, applications should generally never use it directly, but only in a construction that includes a MAC.
pub fn ctr(comptime BlockCipher: anytype, block_cipher: BlockCipher, dst: []u8, src: []const u8, iv: [BlockCipher.block_size]u8, endian: comptime builtin.Endian) void {
pub fn ctr(comptime BlockCipher: anytype, block_cipher: BlockCipher, dst: []u8, src: []const u8, iv: [BlockCipher.block_length]u8, endian: comptime builtin.Endian) void {
debug.assert(dst.len >= src.len);
const block_size = BlockCipher.block_size;
var counter: [BlockCipher.block_size]u8 = undefined;
const block_length = BlockCipher.block_length;
var counter: [BlockCipher.block_length]u8 = undefined;
var counterInt = mem.readInt(u128, &iv, endian);
var i: usize = 0;
const parallel_count = BlockCipher.block.parallel.optimal_parallel_blocks;
const wide_block_size = parallel_count * 16;
if (src.len >= wide_block_size) {
const wide_block_length = parallel_count * 16;
if (src.len >= wide_block_length) {
var counters: [parallel_count * 16]u8 = undefined;
while (i + wide_block_size <= src.len) : (i += wide_block_size) {
while (i + wide_block_length <= src.len) : (i += wide_block_length) {
comptime var j = 0;
inline while (j < parallel_count) : (j += 1) {
mem.writeInt(u128, counters[j * 16 .. j * 16 + 16], counterInt, endian);
counterInt +%= 1;
}
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);
block_cipher.xorWide(parallel_count, dst[i .. i + wide_block_length][0..wide_block_length], src[i .. i + wide_block_length][0..wide_block_length], counters);
}
}
while (i + block_size <= src.len) : (i += block_size) {
while (i + block_length <= src.len) : (i += block_length) {
mem.writeInt(u128, &counter, counterInt, endian);
counterInt +%= 1;
block_cipher.xor(dst[i .. i + block_size][0..block_size], src[i .. i + block_size][0..block_size], counter);
block_cipher.xor(dst[i .. i + block_length][0..block_length], src[i .. i + block_length][0..block_length], counter);
}
if (i < src.len) {
mem.writeInt(u128, &counter, counterInt, endian);
var pad = [_]u8{0} ** block_size;
var pad = [_]u8{0} ** block_length;
mem.copy(u8, &pad, src[i..]);
block_cipher.xor(&pad, &pad, counter);
mem.copy(u8, dst[i..], pad[0 .. src.len - i]);

View File

@ -7,9 +7,9 @@ const std = @import("../std.zig");
const mem = std.mem;
pub const Poly1305 = struct {
pub const block_size: usize = 16;
pub const block_length: usize = 16;
pub const mac_length = 16;
pub const minimum_key_length = 32;
pub const key_length = 32;
// constant multiplier (from the secret key)
r: [3]u64,
@ -20,9 +20,9 @@ pub const Poly1305 = struct {
// how many bytes are waiting to be processed in a partial block
leftover: usize = 0,
// partial block buffer
buf: [block_size]u8 align(16) = undefined,
buf: [block_length]u8 align(16) = undefined,
pub fn init(key: *const [minimum_key_length]u8) Poly1305 {
pub fn init(key: *const [key_length]u8) Poly1305 {
const t0 = mem.readIntLittle(u64, key[0..8]);
const t1 = mem.readIntLittle(u64, key[8..16]);
return Poly1305{
@ -49,7 +49,7 @@ pub const Poly1305 = struct {
const s1 = r1 * (5 << 2);
const s2 = r2 * (5 << 2);
var i: usize = 0;
while (i + block_size <= m.len) : (i += block_size) {
while (i + block_length <= m.len) : (i += block_length) {
// h += m[i]
const t0 = mem.readIntLittle(u64, m[i..][0..8]);
const t1 = mem.readIntLittle(u64, m[i + 8 ..][0..8]);
@ -84,14 +84,14 @@ pub const Poly1305 = struct {
// handle leftover
if (st.leftover > 0) {
const want = std.math.min(block_size - st.leftover, mb.len);
const want = std.math.min(block_length - st.leftover, mb.len);
const mc = mb[0..want];
for (mc) |x, i| {
st.buf[st.leftover + i] = x;
}
mb = mb[want..];
st.leftover += want;
if (st.leftover < block_size) {
if (st.leftover < block_length) {
return;
}
st.blocks(&st.buf, false);
@ -99,8 +99,8 @@ pub const Poly1305 = struct {
}
// process full blocks
if (mb.len >= block_size) {
const want = mb.len & ~(block_size - 1);
if (mb.len >= block_length) {
const want = mb.len & ~(block_length - 1);
st.blocks(mb[0..want], false);
mb = mb[want..];
}
@ -120,7 +120,7 @@ pub const Poly1305 = struct {
return;
}
var i = st.leftover;
while (i < block_size) : (i += 1) {
while (i < block_length) : (i += 1) {
st.buf[i] = 0;
}
st.blocks(&st.buf);
@ -132,7 +132,7 @@ pub const Poly1305 = struct {
var i = st.leftover;
st.buf[i] = 1;
i += 1;
while (i < block_size) : (i += 1) {
while (i < block_length) : (i += 1) {
st.buf[i] = 0;
}
st.blocks(&st.buf, true);
@ -198,7 +198,7 @@ pub const Poly1305 = struct {
std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]);
}
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
var st = Poly1305.init(key);
st.update(msg);
st.final(out);

View File

@ -6,7 +6,6 @@
const std = @import("../std.zig");
const mem = std.mem;
const math = std.math;
const debug = std.debug;
const RoundParam = struct {
a: usize,
@ -17,7 +16,7 @@ const RoundParam = struct {
i: u32,
};
fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
fn roundParam(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
return RoundParam{
.a = a,
.b = b,
@ -55,7 +54,7 @@ pub const Sha1 = struct {
};
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Sha1.init(options);
d.update(b);
d.final(out);
@ -75,7 +74,7 @@ pub const Sha1 = struct {
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.round(b[off .. off + 64]);
d.round(b[off..][0..64]);
}
// Copy any remainder for next pass.
@ -85,9 +84,7 @@ pub const Sha1 = struct {
d.total_len += b.len;
}
pub fn final(d: *Self, out: []u8) void {
debug.assert(out.len >= 20);
pub fn final(d: *Self, out: *[digest_length]u8) void {
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -117,9 +114,7 @@ pub const Sha1 = struct {
}
}
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 64);
fn round(d: *Self, b: *const [64]u8) void {
var s: [16]u32 = undefined;
var v: [5]u32 = [_]u32{
@ -131,22 +126,22 @@ pub const Sha1 = struct {
};
const round0a = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 4, 0),
Rp(4, 0, 1, 2, 3, 1),
Rp(3, 4, 0, 1, 2, 2),
Rp(2, 3, 4, 0, 1, 3),
Rp(1, 2, 3, 4, 0, 4),
Rp(0, 1, 2, 3, 4, 5),
Rp(4, 0, 1, 2, 3, 6),
Rp(3, 4, 0, 1, 2, 7),
Rp(2, 3, 4, 0, 1, 8),
Rp(1, 2, 3, 4, 0, 9),
Rp(0, 1, 2, 3, 4, 10),
Rp(4, 0, 1, 2, 3, 11),
Rp(3, 4, 0, 1, 2, 12),
Rp(2, 3, 4, 0, 1, 13),
Rp(1, 2, 3, 4, 0, 14),
Rp(0, 1, 2, 3, 4, 15),
roundParam(0, 1, 2, 3, 4, 0),
roundParam(4, 0, 1, 2, 3, 1),
roundParam(3, 4, 0, 1, 2, 2),
roundParam(2, 3, 4, 0, 1, 3),
roundParam(1, 2, 3, 4, 0, 4),
roundParam(0, 1, 2, 3, 4, 5),
roundParam(4, 0, 1, 2, 3, 6),
roundParam(3, 4, 0, 1, 2, 7),
roundParam(2, 3, 4, 0, 1, 8),
roundParam(1, 2, 3, 4, 0, 9),
roundParam(0, 1, 2, 3, 4, 10),
roundParam(4, 0, 1, 2, 3, 11),
roundParam(3, 4, 0, 1, 2, 12),
roundParam(2, 3, 4, 0, 1, 13),
roundParam(1, 2, 3, 4, 0, 14),
roundParam(0, 1, 2, 3, 4, 15),
};
inline for (round0a) |r| {
s[r.i] = (@as(u32, b[r.i * 4 + 0]) << 24) | (@as(u32, b[r.i * 4 + 1]) << 16) | (@as(u32, b[r.i * 4 + 2]) << 8) | (@as(u32, b[r.i * 4 + 3]) << 0);
@ -156,10 +151,10 @@ pub const Sha1 = struct {
}
const round0b = comptime [_]RoundParam{
Rp(4, 0, 1, 2, 3, 16),
Rp(3, 4, 0, 1, 2, 17),
Rp(2, 3, 4, 0, 1, 18),
Rp(1, 2, 3, 4, 0, 19),
roundParam(4, 0, 1, 2, 3, 16),
roundParam(3, 4, 0, 1, 2, 17),
roundParam(2, 3, 4, 0, 1, 18),
roundParam(1, 2, 3, 4, 0, 19),
};
inline for (round0b) |r| {
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
@ -170,26 +165,26 @@ pub const Sha1 = struct {
}
const round1 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 4, 20),
Rp(4, 0, 1, 2, 3, 21),
Rp(3, 4, 0, 1, 2, 22),
Rp(2, 3, 4, 0, 1, 23),
Rp(1, 2, 3, 4, 0, 24),
Rp(0, 1, 2, 3, 4, 25),
Rp(4, 0, 1, 2, 3, 26),
Rp(3, 4, 0, 1, 2, 27),
Rp(2, 3, 4, 0, 1, 28),
Rp(1, 2, 3, 4, 0, 29),
Rp(0, 1, 2, 3, 4, 30),
Rp(4, 0, 1, 2, 3, 31),
Rp(3, 4, 0, 1, 2, 32),
Rp(2, 3, 4, 0, 1, 33),
Rp(1, 2, 3, 4, 0, 34),
Rp(0, 1, 2, 3, 4, 35),
Rp(4, 0, 1, 2, 3, 36),
Rp(3, 4, 0, 1, 2, 37),
Rp(2, 3, 4, 0, 1, 38),
Rp(1, 2, 3, 4, 0, 39),
roundParam(0, 1, 2, 3, 4, 20),
roundParam(4, 0, 1, 2, 3, 21),
roundParam(3, 4, 0, 1, 2, 22),
roundParam(2, 3, 4, 0, 1, 23),
roundParam(1, 2, 3, 4, 0, 24),
roundParam(0, 1, 2, 3, 4, 25),
roundParam(4, 0, 1, 2, 3, 26),
roundParam(3, 4, 0, 1, 2, 27),
roundParam(2, 3, 4, 0, 1, 28),
roundParam(1, 2, 3, 4, 0, 29),
roundParam(0, 1, 2, 3, 4, 30),
roundParam(4, 0, 1, 2, 3, 31),
roundParam(3, 4, 0, 1, 2, 32),
roundParam(2, 3, 4, 0, 1, 33),
roundParam(1, 2, 3, 4, 0, 34),
roundParam(0, 1, 2, 3, 4, 35),
roundParam(4, 0, 1, 2, 3, 36),
roundParam(3, 4, 0, 1, 2, 37),
roundParam(2, 3, 4, 0, 1, 38),
roundParam(1, 2, 3, 4, 0, 39),
};
inline for (round1) |r| {
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
@ -200,26 +195,26 @@ pub const Sha1 = struct {
}
const round2 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 4, 40),
Rp(4, 0, 1, 2, 3, 41),
Rp(3, 4, 0, 1, 2, 42),
Rp(2, 3, 4, 0, 1, 43),
Rp(1, 2, 3, 4, 0, 44),
Rp(0, 1, 2, 3, 4, 45),
Rp(4, 0, 1, 2, 3, 46),
Rp(3, 4, 0, 1, 2, 47),
Rp(2, 3, 4, 0, 1, 48),
Rp(1, 2, 3, 4, 0, 49),
Rp(0, 1, 2, 3, 4, 50),
Rp(4, 0, 1, 2, 3, 51),
Rp(3, 4, 0, 1, 2, 52),
Rp(2, 3, 4, 0, 1, 53),
Rp(1, 2, 3, 4, 0, 54),
Rp(0, 1, 2, 3, 4, 55),
Rp(4, 0, 1, 2, 3, 56),
Rp(3, 4, 0, 1, 2, 57),
Rp(2, 3, 4, 0, 1, 58),
Rp(1, 2, 3, 4, 0, 59),
roundParam(0, 1, 2, 3, 4, 40),
roundParam(4, 0, 1, 2, 3, 41),
roundParam(3, 4, 0, 1, 2, 42),
roundParam(2, 3, 4, 0, 1, 43),
roundParam(1, 2, 3, 4, 0, 44),
roundParam(0, 1, 2, 3, 4, 45),
roundParam(4, 0, 1, 2, 3, 46),
roundParam(3, 4, 0, 1, 2, 47),
roundParam(2, 3, 4, 0, 1, 48),
roundParam(1, 2, 3, 4, 0, 49),
roundParam(0, 1, 2, 3, 4, 50),
roundParam(4, 0, 1, 2, 3, 51),
roundParam(3, 4, 0, 1, 2, 52),
roundParam(2, 3, 4, 0, 1, 53),
roundParam(1, 2, 3, 4, 0, 54),
roundParam(0, 1, 2, 3, 4, 55),
roundParam(4, 0, 1, 2, 3, 56),
roundParam(3, 4, 0, 1, 2, 57),
roundParam(2, 3, 4, 0, 1, 58),
roundParam(1, 2, 3, 4, 0, 59),
};
inline for (round2) |r| {
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
@ -230,26 +225,26 @@ pub const Sha1 = struct {
}
const round3 = comptime [_]RoundParam{
Rp(0, 1, 2, 3, 4, 60),
Rp(4, 0, 1, 2, 3, 61),
Rp(3, 4, 0, 1, 2, 62),
Rp(2, 3, 4, 0, 1, 63),
Rp(1, 2, 3, 4, 0, 64),
Rp(0, 1, 2, 3, 4, 65),
Rp(4, 0, 1, 2, 3, 66),
Rp(3, 4, 0, 1, 2, 67),
Rp(2, 3, 4, 0, 1, 68),
Rp(1, 2, 3, 4, 0, 69),
Rp(0, 1, 2, 3, 4, 70),
Rp(4, 0, 1, 2, 3, 71),
Rp(3, 4, 0, 1, 2, 72),
Rp(2, 3, 4, 0, 1, 73),
Rp(1, 2, 3, 4, 0, 74),
Rp(0, 1, 2, 3, 4, 75),
Rp(4, 0, 1, 2, 3, 76),
Rp(3, 4, 0, 1, 2, 77),
Rp(2, 3, 4, 0, 1, 78),
Rp(1, 2, 3, 4, 0, 79),
roundParam(0, 1, 2, 3, 4, 60),
roundParam(4, 0, 1, 2, 3, 61),
roundParam(3, 4, 0, 1, 2, 62),
roundParam(2, 3, 4, 0, 1, 63),
roundParam(1, 2, 3, 4, 0, 64),
roundParam(0, 1, 2, 3, 4, 65),
roundParam(4, 0, 1, 2, 3, 66),
roundParam(3, 4, 0, 1, 2, 67),
roundParam(2, 3, 4, 0, 1, 68),
roundParam(1, 2, 3, 4, 0, 69),
roundParam(0, 1, 2, 3, 4, 70),
roundParam(4, 0, 1, 2, 3, 71),
roundParam(3, 4, 0, 1, 2, 72),
roundParam(2, 3, 4, 0, 1, 73),
roundParam(1, 2, 3, 4, 0, 74),
roundParam(0, 1, 2, 3, 4, 75),
roundParam(4, 0, 1, 2, 3, 76),
roundParam(3, 4, 0, 1, 2, 77),
roundParam(2, 3, 4, 0, 1, 78),
roundParam(1, 2, 3, 4, 0, 79),
};
inline for (round3) |r| {
const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
@ -279,19 +274,19 @@ test "sha1 streaming" {
var h = Sha1.init(.{});
var out: [20]u8 = undefined;
h.final(out[0..]);
h.final(&out);
htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
h = Sha1.init(.{});
h.update("abc");
h.final(out[0..]);
h.final(&out);
htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
h = Sha1.init(.{});
h.update("a");
h.update("b");
h.update("c");
h.final(out[0..]);
h.final(&out);
htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
}

View File

@ -6,7 +6,6 @@
const std = @import("../std.zig");
const mem = std.mem;
const math = std.math;
const debug = std.debug;
const htest = @import("test.zig");
/////////////////////
@ -25,7 +24,7 @@ const RoundParam256 = struct {
k: u32,
};
fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) RoundParam256 {
fn roundParam256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) RoundParam256 {
return RoundParam256{
.a = a,
.b = b,
@ -49,7 +48,7 @@ const Sha2Params32 = struct {
iv5: u32,
iv6: u32,
iv7: u32,
out_len: usize,
digest_bits: usize,
};
const Sha224Params = Sha2Params32{
@ -61,7 +60,7 @@ const Sha224Params = Sha2Params32{
.iv5 = 0x68581511,
.iv6 = 0x64F98FA7,
.iv7 = 0xBEFA4FA4,
.out_len = 224,
.digest_bits = 224,
};
const Sha256Params = Sha2Params32{
@ -73,20 +72,20 @@ const Sha256Params = Sha2Params32{
.iv5 = 0x9B05688C,
.iv6 = 0x1F83D9AB,
.iv7 = 0x5BE0CD19,
.out_len = 256,
.digest_bits = 256,
};
/// SHA-224
pub const Sha224 = Sha2_32(Sha224Params);
pub const Sha224 = Sha2x32(Sha224Params);
/// SHA-256
pub const Sha256 = Sha2_32(Sha256Params);
pub const Sha256 = Sha2x32(Sha256Params);
fn Sha2_32(comptime params: Sha2Params32) type {
fn Sha2x32(comptime params: Sha2Params32) type {
return struct {
const Self = @This();
pub const block_length = 64;
pub const digest_length = params.out_len / 8;
pub const digest_length = params.digest_bits / 8;
pub const Options = struct {};
s: [8]u32,
@ -110,7 +109,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
};
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Self.init(options);
d.update(b);
d.final(out);
@ -124,13 +123,13 @@ fn Sha2_32(comptime params: Sha2Params32) type {
off += 64 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.round(d.buf[0..]);
d.round(&d.buf);
d.buf_len = 0;
}
// Full middle blocks.
while (off + 64 <= b.len) : (off += 64) {
d.round(b[off .. off + 64]);
d.round(b[off..][0..64]);
}
// Copy any remainder for next pass.
@ -140,9 +139,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
d.total_len += b.len;
}
pub fn final(d: *Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
pub fn final(d: *Self, out: *[digest_length]u8) void {
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -152,7 +149,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
// > 448 mod 512 so need to add an extra round to wrap around.
if (64 - d.buf_len < 8) {
d.round(d.buf[0..]);
d.round(&d.buf);
mem.set(u8, d.buf[0..], 0);
}
@ -165,19 +162,17 @@ fn Sha2_32(comptime params: Sha2Params32) type {
len >>= 8;
}
d.round(d.buf[0..]);
d.round(&d.buf);
// May truncate for possible 224 output
const rr = d.s[0 .. params.out_len / 32];
const rr = d.s[0 .. params.digest_bits / 32];
for (rr) |s, j| {
mem.writeIntBig(u32, out[4 * j ..][0..4], s);
}
}
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 64);
fn round(d: *Self, b: *const [64]u8) void {
var s: [64]u32 = undefined;
var i: usize = 0;
@ -204,70 +199,70 @@ fn Sha2_32(comptime params: Sha2Params32) type {
};
const round0 = comptime [_]RoundParam256{
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
roundParam256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
roundParam256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
roundParam256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
roundParam256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
roundParam256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
roundParam256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
roundParam256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
roundParam256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
};
inline for (round0) |r| {
v[r.h] = v[r.h] +% (math.rotr(u32, v[r.e], @as(u32, 6)) ^ math.rotr(u32, v[r.e], @as(u32, 11)) ^ math.rotr(u32, v[r.e], @as(u32, 25))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];
@ -366,7 +361,7 @@ const RoundParam512 = struct {
k: u64,
};
fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
fn roundParam512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) RoundParam512 {
return RoundParam512{
.a = a,
.b = b,
@ -390,7 +385,7 @@ const Sha2Params64 = struct {
iv5: u64,
iv6: u64,
iv7: u64,
out_len: usize,
digest_bits: usize,
};
const Sha384Params = Sha2Params64{
@ -402,7 +397,7 @@ const Sha384Params = Sha2Params64{
.iv5 = 0x8EB44A8768581511,
.iv6 = 0xDB0C2E0D64F98FA7,
.iv7 = 0x47B5481DBEFA4FA4,
.out_len = 384,
.digest_bits = 384,
};
const Sha512Params = Sha2Params64{
@ -414,7 +409,7 @@ const Sha512Params = Sha2Params64{
.iv5 = 0x9B05688C2B3E6C1F,
.iv6 = 0x1F83D9ABFB41BD6B,
.iv7 = 0x5BE0CD19137E2179,
.out_len = 512,
.digest_bits = 512,
};
const Sha512256Params = Sha2Params64{
@ -426,7 +421,7 @@ const Sha512256Params = Sha2Params64{
.iv5 = 0xBE5E1E2553863992,
.iv6 = 0x2B0199FC2C85B8AA,
.iv7 = 0x0EB72DDC81C52CA2,
.out_len = 256,
.digest_bits = 256,
};
const Sha512T256Params = Sha2Params64{
@ -438,26 +433,26 @@ const Sha512T256Params = Sha2Params64{
.iv5 = 0x9B05688C2B3E6C1F,
.iv6 = 0x1F83D9ABFB41BD6B,
.iv7 = 0x5BE0CD19137E2179,
.out_len = 256,
.digest_bits = 256,
};
/// SHA-384
pub const Sha384 = Sha2_64(Sha384Params);
pub const Sha384 = Sha2x64(Sha384Params);
/// SHA-512
pub const Sha512 = Sha2_64(Sha512Params);
pub const Sha512 = Sha2x64(Sha512Params);
/// SHA-512/256
pub const Sha512256 = Sha2_64(Sha512256Params);
pub const Sha512256 = Sha2x64(Sha512256Params);
/// Truncated SHA-512
pub const Sha512T256 = Sha2_64(Sha512T256Params);
pub const Sha512T256 = Sha2x64(Sha512T256Params);
fn Sha2_64(comptime params: Sha2Params64) type {
fn Sha2x64(comptime params: Sha2Params64) type {
return struct {
const Self = @This();
pub const block_length = 128;
pub const digest_length = params.out_len / 8;
pub const digest_length = params.digest_bits / 8;
pub const Options = struct {};
s: [8]u64,
@ -481,7 +476,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {
};
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Self.init(options);
d.update(b);
d.final(out);
@ -495,13 +490,13 @@ fn Sha2_64(comptime params: Sha2Params64) type {
off += 128 - d.buf_len;
mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
d.round(d.buf[0..]);
d.round(&d.buf);
d.buf_len = 0;
}
// Full middle blocks.
while (off + 128 <= b.len) : (off += 128) {
d.round(b[off .. off + 128]);
d.round(b[off..][0..128]);
}
// Copy any remainder for next pass.
@ -511,9 +506,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {
d.total_len += b.len;
}
pub fn final(d: *Self, out: []u8) void {
debug.assert(out.len >= params.out_len / 8);
pub fn final(d: *Self, out: *[digest_length]u8) void {
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -539,16 +532,14 @@ fn Sha2_64(comptime params: Sha2Params64) type {
d.round(d.buf[0..]);
// May truncate for possible 384 output
const rr = d.s[0 .. params.out_len / 64];
const rr = d.s[0 .. params.digest_bits / 64];
for (rr) |s, j| {
mem.writeIntBig(u64, out[8 * j ..][0..8], s);
}
}
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 128);
fn round(d: *Self, b: *const [128]u8) void {
var s: [80]u64 = undefined;
var i: usize = 0;
@ -581,86 +572,86 @@ fn Sha2_64(comptime params: Sha2Params64) type {
};
const round0 = comptime [_]RoundParam512{
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
roundParam512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
roundParam512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
roundParam512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
roundParam512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
roundParam512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
roundParam512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
roundParam512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
roundParam512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
};
inline for (round0) |r| {
v[r.h] = v[r.h] +% (math.rotr(u64, v[r.e], @as(u64, 14)) ^ math.rotr(u64, v[r.e], @as(u64, 18)) ^ math.rotr(u64, v[r.e], @as(u64, 41))) +% (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +% r.k +% s[r.i];

View File

@ -29,7 +29,7 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) };
}
pub fn hash(b: []const u8, out: []u8, options: Options) void {
pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
var d = Self.init(options);
d.update(b);
d.final(out);
@ -46,7 +46,7 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
for (d.s[offset .. offset + rate]) |*r, i|
r.* ^= b[ip..][i];
keccak_f(1600, d.s[0..]);
keccakF(1600, &d.s);
ip += rate;
len -= rate;
@ -60,12 +60,12 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
d.offset = offset + len;
}
pub fn final(d: *Self, out: []u8) void {
pub fn final(d: *Self, out: *[digest_length]u8) void {
// padding
d.s[d.offset] ^= delim;
d.s[d.rate - 1] ^= 0x80;
keccak_f(1600, d.s[0..]);
keccakF(1600, &d.s);
// squeeze
var op: usize = 0;
@ -73,7 +73,7 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
while (len >= d.rate) {
mem.copy(u8, out[op..], d.s[0..d.rate]);
keccak_f(1600, d.s[0..]);
keccakF(1600, &d.s);
op += d.rate;
len -= d.rate;
}
@ -104,9 +104,7 @@ const M5 = [_]usize{
0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
};
fn keccak_f(comptime F: usize, d: []u8) void {
debug.assert(d.len == F / 8);
fn keccakF(comptime F: usize, d: *[F / 8]u8) void {
const B = F / 25;
const no_rounds = comptime x: {
break :x 12 + 2 * math.log2(B);

View File

@ -51,8 +51,9 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
return struct {
const Self = @This();
const digest_size = 64;
const block_size = 64;
const block_length = 64;
const digest_length = 64;
const key_length = 16;
v0: u64,
v1: u64,
@ -60,9 +61,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
v3: u64,
msg_len: u8,
pub fn init(key: []const u8) Self {
assert(key.len >= 16);
pub fn init(key: *const [key_length]u8) Self {
const k0 = mem.readIntLittle(u64, key[0..8]);
const k1 = mem.readIntLittle(u64, key[8..16]);
@ -86,7 +85,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
var off: usize = 0;
while (off < b.len) : (off += 8) {
@call(.{ .modifier = .always_inline }, self.round, .{b[off .. off + 8]});
@call(.{ .modifier = .always_inline }, self.round, .{b[off..][0..8].*});
}
self.msg_len +%= @truncate(u8, b.len);
@ -100,7 +99,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
var buf = [_]u8{0} ** 8;
mem.copy(u8, buf[0..], b[0..]);
buf[7] = self.msg_len;
self.round(buf[0..]);
self.round(buf);
if (T == u128) {
self.v2 ^= 0xee;
@ -132,9 +131,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
return (@as(u128, b2) << 64) | b1;
}
fn round(self: *Self, b: []const u8) void {
assert(b.len == 8);
fn round(self: *Self, b: [8]u8) void {
const m = mem.readIntLittle(u64, b[0..8]);
self.v3 ^= m;
@ -165,7 +162,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
d.v2 = math.rotl(u64, d.v2, @as(u64, 32));
}
pub fn hash(msg: []const u8, key: []const u8) T {
pub fn hash(msg: []const u8, key: *const [key_length]u8) T {
const aligned_len = msg.len - (msg.len % 8);
var c = Self.init(key);
@call(.{ .modifier = .always_inline }, c.update, .{msg[0..aligned_len]});
@ -181,7 +178,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
return struct {
const State = SipHashStateless(T, c_rounds, d_rounds);
const Self = @This();
pub const minimum_key_length = 16;
pub const key_length = 16;
pub const mac_length = @sizeOf(T);
pub const block_length = 8;
@ -190,7 +187,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
buf_len: usize,
/// Initialize a state for a SipHash function
pub fn init(key: []const u8) Self {
pub fn init(key: *const [key_length]u8) Self {
return Self{
.state = State.init(key),
.buf = undefined,
@ -219,16 +216,15 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
/// Return an authentication tag for the current state
/// Assumes `out` is less than or equal to `mac_length`.
pub fn final(self: *Self, out: []u8) void {
std.debug.assert(out.len <= mac_length);
mem.writeIntLittle(T, out[0..mac_length], self.state.final(self.buf[0..self.buf_len]));
pub fn final(self: *Self, out: *[mac_length]u8) void {
mem.writeIntLittle(T, out, self.state.final(self.buf[0..self.buf_len]));
}
/// Return an authentication tag for a message and a key
pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
var ctx = Self.init(key);
ctx.update(msg);
ctx.final(out[0..]);
ctx.final(out);
}
/// Return an authentication tag for the current state, as an integer
@ -237,7 +233,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
}
/// Return an authentication tag for a message and a key, as an integer
pub fn toInt(msg: []const u8, key: []const u8) T {
pub fn toInt(msg: []const u8, key: *const [key_length]u8) T {
return State.hash(msg, key);
}
};

View File

@ -8,18 +8,18 @@ const testing = std.testing;
const fmt = std.fmt;
// Hash using the specified hasher `H` asserting `expected == H(input)`.
pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void {
var h: [expected.len / 2]u8 = undefined;
Hasher.hash(input, h[0..], .{});
pub fn assertEqualHash(comptime Hasher: anytype, comptime expected_hex: *const [Hasher.digest_length * 2:0]u8, input: []const u8) void {
var h: [Hasher.digest_length]u8 = undefined;
Hasher.hash(input, &h, .{});
assertEqual(expected, &h);
assertEqual(expected_hex, &h);
}
// Assert `expected` == `input` where `input` is a bytestring.
pub fn assertEqual(comptime expected: []const u8, input: []const u8) void {
var expected_bytes: [expected.len / 2]u8 = undefined;
// Assert `expected` == hex(`input`) where `input` is a bytestring
pub fn assertEqual(comptime expected_hex: [:0]const u8, input: []const u8) void {
var expected_bytes: [expected_hex.len / 2]u8 = undefined;
for (expected_bytes) |*r, i| {
r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable;
r.* = fmt.parseInt(u8, expected_hex[2 * i .. 2 * i + 2], 16) catch unreachable;
}
testing.expectEqualSlices(u8, &expected_bytes, input);

View File

@ -35,7 +35,7 @@ const manifest_file_size_max = 50 * 1024 * 1024;
pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);
/// Initial state, that can be copied.
pub const hasher_init: Hasher = Hasher.init(&[_]u8{0} ** Hasher.minimum_key_length);
pub const hasher_init: Hasher = Hasher.init(&[_]u8{0} ** Hasher.key_length);
pub const File = struct {
path: ?[]const u8,
@ -600,7 +600,7 @@ pub fn writeSmallFile(dir: fs.Dir, sub_path: []const u8, data: []const u8) !void
}
}
fn hashFile(file: fs.File, bin_digest: []u8) !void {
fn hashFile(file: fs.File, bin_digest: *[Hasher.mac_length]u8) !void {
var buf: [1024]u8 = undefined;
var hasher = hasher_init;