Change crypto functions to fill a buffer

- Rename blake2x -> blake2
 - Fix blake2s truncated tests
master
Marc Tiehuis 2018-01-16 21:35:31 +13:00
parent 4cf86b4a94
commit fa7b33549e
6 changed files with 246 additions and 220 deletions

View File

@ -368,7 +368,7 @@ set(ZIG_STD_FILES
"crypto/md5.zig"
"crypto/sha1.zig"
"crypto/sha2.zig"
"crypto/blake2x.zig"
"crypto/blake2.zig"
"cstr.zig"
"debug/failing_allocator.zig"
"debug/index.zig"

View File

@ -1,7 +1,9 @@
const std = @import("std");
const mem = std.mem;
const math = std.math;
const debug = std.debug;
const mem = @import("../mem.zig");
const math = @import("../math/index.zig");
const endian = @import("../endian.zig");
const debug = @import("../debug/index.zig");
const builtin = @import("builtin");
const htest = @import("test.zig");
const RoundParam = struct {
a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
@ -19,7 +21,6 @@ pub const Blake2s256 = Blake2s(256);
fn Blake2s(comptime out_len: usize) -> type { return struct {
const Self = this;
const ReturnType = @IntType(false, out_len);
const iv = [8]u32 {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
@ -62,10 +63,10 @@ fn Blake2s(comptime out_len: usize) -> type { return struct {
d.buf_len = 0;
}
pub fn hash(b: []const u8) -> ReturnType {
pub fn hash(b: []const u8, out: []u8) {
var d = Self.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -91,22 +92,18 @@ fn Blake2s(comptime out_len: usize) -> type { return struct {
d.buf_len += u8(b[off..].len);
}
pub fn final(d: &Self) -> ReturnType {
pub fn final(d: &Self, out: []u8) {
debug.assert(out.len >= out_len / 8);
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];
// NOTE: mem.readIntLE or equivalent would be useful here.
var j: u8 = 0;
var r: ReturnType = 0;
for (rr) |p| {
r |= ReturnType(p) << j;
j +%= 32;
for (rr) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
}
return std.endian.swapIfLe(ReturnType, r);
}
fn round(d: &Self, b: []const u8, last: bool) {
@ -160,66 +157,74 @@ fn Blake2s(comptime out_len: usize) -> type { return struct {
}
};}
// TODO: bigint rem >1 digits for 224 integer output.
//
// test "blake2s224 single" {
// const hash1 = 0xa847d26c2f966c5c4cc222b174918a56037cdee34b3f872f;
// debug.assert(hash1 == Blake2s224.hash(""));
//
// const hash2 = 0x1e2ed10fcdbc46e0ab3ea3f268a6c288083ae04e3d63a8de;
// debug.assert(hash2 == Blake2s224.hash("abc"));
//
// const hash3 = 0xe486adf7b22d2944b434ae78ae64720c16ccf0479dab072d;
// debug.assert(hash3 == Blake2s224.hash("The quick brown fox jumps over the lazy dog"));
// }
//
// test "blake2s224 streaming" {
// var h = Blake2s224.init();
//
// const hash1 = 0xa847d26c2f966c5c4cc222b174918a56037cdee34b3f872f;
// debug.assert(hash1 == h.final());
//
// const hash2 = 0x1e2ed10fcdbc46e0ab3ea3f268a6c288083ae04e3d63a8de;
//
// h.reset();
// h.update("abc");
// debug.assert(hash2 == h.final());
//
// h.reset();
// h.update("a");
// h.update("b");
// h.update("c");
// debug.assert(hash2 == h.final());
// }
test "blake2s224 single" {
const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
htest.assertEqualHash(Blake2s224, h1, "");
test "blake2s256 single" {
const hash1 = 0x69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9;
debug.assert(hash1 == Blake2s256.hash(""));
const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
htest.assertEqualHash(Blake2s224, h2, "abc");
const hash2 = 0x508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982;
debug.assert(hash2 == Blake2s256.hash("abc"));
const hash3 = 0x606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812;
debug.assert(hash3 == Blake2s256.hash("The quick brown fox jumps over the lazy dog"));
const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
}
test "blake2s256 streaming" {
var h = Blake2s256.init();
test "blake2s224 streaming" {
var h = Blake2s224.init();
var out: [28]u8 = undefined;
const hash1 = 0x69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9;
debug.assert(hash1 == h.final());
const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
const hash2 = 0x508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982;
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
h.reset();
h.update("abc");
debug.assert(hash2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(hash2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}
test "blake2s256 single" {
const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
htest.assertEqualHash(Blake2s256, h1, "");
const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
htest.assertEqualHash(Blake2s256, h2, "abc");
const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
}
test "blake2s256 streaming" {
var h = Blake2s256.init();
var out: [32]u8 = undefined;
const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
h.reset();
h.update("abc");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}
@ -231,8 +236,6 @@ pub const Blake2b512 = Blake2b(512);
fn Blake2b(comptime out_len: usize) -> type { return struct {
const Self = this;
const ReturnType = @IntType(false, out_len);
const u9 = @IntType(false, 9);
const iv = [8]u64 {
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
@ -279,10 +282,10 @@ fn Blake2b(comptime out_len: usize) -> type { return struct {
d.buf_len = 0;
}
pub fn hash(b: []const u8) -> ReturnType {
pub fn hash(b: []const u8, out: []u8) {
var d = Self.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -308,21 +311,16 @@ fn Blake2b(comptime out_len: usize) -> type { return struct {
d.buf_len += u8(b[off..].len);
}
pub fn final(d: &Self) -> ReturnType {
pub fn final(d: &Self, out: []u8) {
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];
var j: u9 = 0;
var r: ReturnType = 0;
for (rr) |p| {
r |= ReturnType(p) << j;
j +%= 64;
for (rr) |s, j| {
mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
}
return std.endian.swapIfLe(ReturnType, r);
}
fn round(d: &Self, b: []const u8, last: bool) {
@ -376,64 +374,72 @@ fn Blake2b(comptime out_len: usize) -> type { return struct {
}
};}
// TODO: bigint rem >1 digits for 384 integer output.
test "blake2b384 single" {
const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
htest.assertEqualHash(Blake2b384, h1, "");
// test "blake2b384 single" {
// const hash1 = 0xb32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100;
// debug.assert(hash1 == Blake2b384.hash(""));
//
// const hash2 = 0x6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4;
// debug.assert(hash2 == Blake2b384.hash("abc"));
//
// const hash3 = 0xb7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d;
// debug.assert(hash3 == Blake2b384.hash("The quick brown fox jumps over the lazy dog"));
// }
//
// test "blake2b384 streaming" {
// var h = Blake2b384.init();
//
// const hash1 = 0xb32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100;
// debug.assert(hash1 == h.final());
//
// const hash2 = 0x6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4;
//
// h.reset();
// h.update("abc");
// debug.assert(hash2 == h.final());
//
// h.reset();
// h.update("a");
// h.update("b");
// h.update("c");
// debug.assert(hash2 == h.final());
// }
const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
htest.assertEqualHash(Blake2b384, h2, "abc");
test "blake2b512 single" {
const hash1 = 0x786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce;
debug.assert(hash1 == Blake2b512.hash(""));
const hash2 = 0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923;
debug.assert(hash2 == Blake2b512.hash("abc"));
const hash3 = 0xa8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918;
debug.assert(hash3 == Blake2b512.hash("The quick brown fox jumps over the lazy dog"));
const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
}
test "blake2b512 streaming" {
var h = Blake2b512.init();
test "blake2b384 streaming" {
var h = Blake2b384.init();
var out: [48]u8 = undefined;
const hash1 = 0x786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce;
debug.assert(hash1 == h.final());
const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
const hash2 = 0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923;
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
h.reset();
h.update("abc");
debug.assert(hash2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(hash2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}
test "blake2b512 single" {
const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
htest.assertEqualHash(Blake2b512, h1, "");
const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
htest.assertEqualHash(Blake2b512, h2, "abc");
const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
}
test "blake2b512 streaming" {
var h = Blake2b512.init();
var out: [64]u8 = undefined;
const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
h.reset();
h.update("abc");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}

View File

@ -7,15 +7,15 @@ pub const Sha256 = sha2.Sha256;
pub const Sha384 = sha2.Sha384;
pub const Sha512 = sha2.Sha512;
const blake2x = @import("blake2x.zig");
pub const Blake2s224 = blake2x.Blake2s224;
pub const Blake2s256 = blake2x.Blake2s256;
pub const Blake2b384 = blake2x.Blake2b384;
pub const Blake2b512 = blake2x.Blake2b512;
const blake2 = @import("blake2.zig");
pub const Blake2s224 = blake2.Blake2s224;
pub const Blake2s256 = blake2.Blake2s256;
pub const Blake2b384 = blake2.Blake2b384;
pub const Blake2b512 = blake2.Blake2b512;
test "crypto" {
_ = @import("md5.zig");
_ = @import("sha1.zig");
_ = @import("sha2.zig");
_ = @import("blake2x.zig");
_ = @import("blake2.zig");
}

View File

@ -1,7 +1,9 @@
const mem = @import("../mem.zig");
const math = @import("../math/index.zig");
const endian = @import("../endian.zig");
const builtin = @import("builtin");
const debug = @import("../debug/index.zig");
const fmt = @import("../fmt/index.zig");
const RoundParam = struct {
a: usize, b: usize, c: usize, d: usize,
@ -42,10 +44,10 @@ pub const Md5 = struct {
d.total_len = 0;
}
pub fn hash(b: []const u8) -> u128 {
pub fn hash(b: []const u8, out: []u8) {
var d = Md5.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -73,7 +75,9 @@ pub const Md5 = struct {
d.total_len +%= b.len;
}
pub fn final(d: &Self) -> u128 {
pub fn final(d: &Self, out: []u8) {
debug.assert(out.len >= 16);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -98,13 +102,9 @@ pub const Md5 = struct {
d.round(d.buf[0..]);
const r =
(u128(d.s[3]) << 96) |
(u128(d.s[2]) << 64) |
(u128(d.s[1]) << 32) |
(u128(d.s[0]) << 0);
return endian.swapIfLe(u128, r);
for (d.s) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
}
}
fn round(d: &Self, b: []const u8) {
@ -226,28 +226,35 @@ pub const Md5 = struct {
}
};
const htest = @import("test.zig");
test "md5 single" {
debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == Md5.hash(""));
debug.assert(0x0cc175b9c0f1b6a831c399e269772661 == Md5.hash("a"));
debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == Md5.hash("abc"));
debug.assert(0xf96b697d7cb7938d525a2f31aaf161d0 == Md5.hash("message digest"));
debug.assert(0xc3fcd3d76192e4007dfb496cca67e13b == Md5.hash("abcdefghijklmnopqrstuvwxyz"));
debug.assert(0xd174ab98d277d9f5a5611c2c9f419d9f == Md5.hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
debug.assert(0x57edf4a22be3c955ac49da2e2107b67a == Md5.hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
htest.assertEqualHash(Md5, "d41d8cd98f00b204e9800998ecf8427e", "");
htest.assertEqualHash(Md5, "0cc175b9c0f1b6a831c399e269772661", "a");
htest.assertEqualHash(Md5, "900150983cd24fb0d6963f7d28e17f72", "abc");
htest.assertEqualHash(Md5, "f96b697d7cb7938d525a2f31aaf161d0", "message digest");
htest.assertEqualHash(Md5, "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz");
htest.assertEqualHash(Md5, "d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
htest.assertEqualHash(Md5, "57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
}
test "md5 streaming" {
var h = Md5.init();
var out: [16]u8 = undefined;
debug.assert(0xd41d8cd98f00b204e9800998ecf8427e == h.final());
h.final(out[0..]);
htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
h.reset();
h.update("abc");
debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
h.final(out[0..]);
htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(0x900150983cd24fb0d6963f7d28e17f72 == h.final());
h.final(out[0..]);
htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
}

View File

@ -2,6 +2,7 @@ const mem = @import("../mem.zig");
const math = @import("../math/index.zig");
const endian = @import("../endian.zig");
const debug = @import("../debug/index.zig");
const builtin = @import("builtin");
pub const u160 = @IntType(false, 160);
@ -38,10 +39,10 @@ pub const Sha1 = struct {
d.total_len = 0;
}
pub fn hash(b: []const u8) -> u160 {
pub fn hash(b: []const u8, out: []u8) {
var d = Sha1.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -68,7 +69,9 @@ pub const Sha1 = struct {
d.total_len += b.len;
}
pub fn final(d: &Self) -> u160 {
pub fn final(d: &Self, out: []u8) {
debug.assert(out.len >= 20);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -93,14 +96,9 @@ pub const Sha1 = struct {
d.round(d.buf[0..]);
const r =
(u160(d.s[0]) << 128) |
(u160(d.s[1]) << 96) |
(u160(d.s[2]) << 64) |
(u160(d.s[3]) << 32) |
(u160(d.s[4]) << 0);
return endian.swapIfBe(u160, r);
for (d.s) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
}
}
fn round(d: &Self, b: []const u8) {
@ -257,24 +255,30 @@ pub const Sha1 = struct {
}
};
const htest = @import("test.zig");
test "sha1 single" {
debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == Sha1.hash(""));
debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == Sha1.hash("abc"));
debug.assert(0xa49b2446a02c645bf419f995b67091253a04a259 == Sha1.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "sha1 streaming" {
var h = Sha1.init();
var out: [20]u8 = undefined;
debug.assert(0xda39a3ee5e6b4b0d3255bfef95601890afd80709 == h.final());
h.final(out[0..]);
htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
h.reset();
h.update("abc");
debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
h.final(out[0..]);
htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(0xa9993e364706816aba3e25717850c26c9cd0d89d == h.final());
h.final(out[0..]);
htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
}

View File

@ -3,6 +3,7 @@ const math = @import("../math/index.zig");
const endian = @import("../endian.zig");
const debug = @import("../debug/index.zig");
const builtin = @import("builtin");
const htest = @import("test.zig");
/////////////////////
// Sha224 + Sha256
@ -57,7 +58,6 @@ pub const Sha256 = Sha2_32(Sha256Params);
fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
const Self = this;
const ReturnType = @IntType(false, params.out_len);
s: [8]u32,
// Streaming Cache
@ -84,10 +84,10 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
d.total_len = 0;
}
pub fn hash(b: []const u8) -> ReturnType {
pub fn hash(b: []const u8, out: []u8) {
var d = Self.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -114,7 +114,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
d.total_len += b.len;
}
pub fn final(d: &Self) -> ReturnType {
pub fn final(d: &Self, out: []u8) {
debug.assert(out.len >= params.out_len / 8);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -142,14 +144,9 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
// May truncate for possible 224 output
const rr = d.s[0 .. params.out_len / 32];
var j: u8 = u8(rr.len - 1) * 32;
var r: ReturnType = 0;
for (rr) |p| {
r |= ReturnType(p) << j;
j -%= 32;
for (rr) |s, j| {
mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
}
return endian.swapIfBe(ReturnType, r);
}
fn round(d: &Self, b: []const u8) {
@ -275,9 +272,9 @@ test "sha224 single" {
return;
}
debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == Sha224.hash(""));
debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == Sha224.hash("abc"));
debug.assert(0xc97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3 == Sha224.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "sha224 streaming" {
@ -287,18 +284,22 @@ test "sha224 streaming" {
}
var h = Sha224.init();
var out: [28]u8 = undefined;
debug.assert(0xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f == h.final());
h.final(out[0..]);
htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
h.reset();
h.update("abc");
debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
h.final(out[0..]);
htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(0x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 == h.final());
h.final(out[0..]);
htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
}
test "sha256 single" {
@ -307,9 +308,9 @@ test "sha256 single" {
return;
}
debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == Sha256.hash(""));
debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == Sha256.hash("abc"));
debug.assert(0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1 == Sha256.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "sha256 streaming" {
@ -319,18 +320,22 @@ test "sha256 streaming" {
}
var h = Sha256.init();
var out: [32]u8 = undefined;
debug.assert(0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 == h.final());
h.final(out[0..]);
htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
h.reset();
h.update("abc");
debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
h.final(out[0..]);
htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad == h.final());
h.final(out[0..]);
htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
}
@ -387,7 +392,6 @@ pub const Sha512 = Sha2_64(Sha512Params);
fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
const Self = this;
const ReturnType = @IntType(false, params.out_len);
const u9 = @IntType(false, 9);
s: [8]u64,
@ -415,10 +419,10 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
d.total_len = 0;
}
pub fn hash(b: []const u8) -> ReturnType {
pub fn hash(b: []const u8, out: []u8) {
var d = Self.init();
d.update(b);
return d.final();
d.final(out);
}
pub fn update(d: &Self, b: []const u8) {
@ -445,7 +449,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
d.total_len += b.len;
}
pub fn final(d: &Self) -> ReturnType {
pub fn final(d: &Self, out: []u8) {
debug.assert(out.len >= params.out_len / 8);
// The buffer here will never be completely full.
mem.set(u8, d.buf[d.buf_len..], 0);
@ -473,14 +479,9 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
// May truncate for possible 384 output
const rr = d.s[0 .. params.out_len / 64];
var j: u9 = u9(rr.len - 1) * 64;
var r: ReturnType = 0;
for (rr) |p| {
r |= ReturnType(p) << j;
j -%= 64;
for (rr) |s, j| {
mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
}
return endian.swapIfBe(ReturnType, r);
}
fn round(d: &Self, b: []const u8) {
@ -626,14 +627,14 @@ test "sha384 single" {
return;
}
const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
debug.assert(h1 == Sha384.hash(""));
const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
htest.assertEqualHash(Sha384, h1, "");
const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
debug.assert(h2 == Sha384.hash("abc"));
const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
htest.assertEqualHash(Sha384, h2, "abc");
const h3 = 0x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039;
debug.assert(h3 == Sha384.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "sha384 streaming" {
@ -643,21 +644,25 @@ test "sha384 streaming" {
}
var h = Sha384.init();
var out: [48]u8 = undefined;
const h1 = 0x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b;
debug.assert(h1 == h.final());
const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = 0xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7;
const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
h.reset();
h.update("abc");
debug.assert(h2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(h2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}
test "sha512 single" {
@ -666,14 +671,14 @@ test "sha512 single" {
return;
}
const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
debug.assert(h1 == Sha512.hash(""));
const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
htest.assertEqualHash(Sha512, h1, "");
const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
debug.assert(h2 == Sha512.hash("abc"));
const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
htest.assertEqualHash(Sha512, h2, "abc");
const h3 = 0x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909;
debug.assert(h3 == Sha512.hash("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"));
const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
}
test "sha512 streaming" {
@ -683,19 +688,23 @@ test "sha512 streaming" {
}
var h = Sha512.init();
var out: [64]u8 = undefined;
const h1 = 0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e;
debug.assert(h1 == h.final());
const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
h.final(out[0..]);
htest.assertEqual(h1, out[0..]);
const h2 = 0xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f;
const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
h.reset();
h.update("abc");
debug.assert(h2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
h.reset();
h.update("a");
h.update("b");
h.update("c");
debug.assert(h2 == h.final());
h.final(out[0..]);
htest.assertEqual(h2, out[0..]);
}