crypto: add blake2s and blake2b hashes (#20149)

This commit is contained in:
Kim Shrier 2023-12-11 03:40:07 -07:00 committed by GitHub
parent 850e76857d
commit e6a30dc4ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 17809 additions and 22 deletions

View file

@ -0,0 +1,377 @@
// Copyright (c) 2023 Kim Shrier. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// Package blake2b implements the Blake2b 512, 384, 256, and
// 160 bit hash algorithms
// as defined in IETF RFC 7693.
// Based off: https://datatracker.ietf.org/doc/html/rfc7693
// Last updated: November 2015
module blake2b
import encoding.binary
import math.unsigned
// size160 is the size, in bytes, of a Blake2b 160 checksum.
pub const size160 = 20
// size256 is the size, in bytes, of a Blake2b 256 checksum.
pub const size256 = 32
// size384 is the size, in bytes, of a Blake2b 384 checksum.
pub const size384 = 48
// size512 is the size, in bytes, of a Blake2b 512 checksum.
pub const size512 = 64
// block_size is the block size, in bytes, of the Blake2b hash functions.
pub const block_size = 128
// G rotation constants
const r1 = 32
const r2 = 24
const r3 = 16
const r4 = 63
// negative G rotation constants so we can rotate right.
const nr1 = -1 * r1
const nr2 = -1 * r2
const nr3 = -1 * r3
const nr4 = -1 * r4
// initialization vector
const iv = [
u64(0x6a09e667f3bcc908),
u64(0xbb67ae8584caa73b),
u64(0x3c6ef372fe94f82b),
u64(0xa54ff53a5f1d36f1),
u64(0x510e527fade682d1),
u64(0x9b05688c2b3e6c1f),
u64(0x1f83d9abfb41bd6b),
u64(0x5be0cd19137e2179),
]
// message word schedule permutations
const sigma = [
[u8(0), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[u8(14), 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[u8(11), 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[u8(7), 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[u8(9), 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[u8(2), 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[u8(12), 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[u8(13), 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[u8(6), 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[u8(10), 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
]
struct Digest {
hash_size u8
mut:
input_buffer []u8
h []u64
m [16]u64
t unsigned.Uint128
}
// string makes a formatted string representation of a Digest structure
pub fn (d Digest) str() string {
return 'blake2b.Digest{\n hash_size: ${d.hash_size}\n input_buffer: ${d.input_buffer}\n input_buffer.len: ${d.input_buffer.len}\n h: [0x${d.h[0]:016x}, 0x${d.h[1]:016x}, 0x${d.h[2]:016x}, 0x${d.h[3]:016x},\n 0x${d.h[4]:016x}, 0x${d.h[5]:016x}, 0x${d.h[6]:016x}, 0x${d.h[7]:016x}]\n m: [0x${d.m[0]:016x}, 0x${d.m[1]:016x}, 0x${d.m[2]:016x}, 0x${d.m[3]:016x},\n 0x${d.m[4]:016x}, 0x${d.m[5]:016x}, 0x${d.m[6]:016x}, 0x${d.m[7]:016x},\n 0x${d.m[8]:016x}, 0x${d.m[9]:016x}, 0x${d.m[10]:016x}, 0x${d.m[11]:016x},\n 0x${d.m[12]:016x}, 0x${d.m[13]:016x}, 0x${d.m[14]:016x}, 0x${d.m[15]:016x}]\n t: ${d.t}\n}'
}
// new512 initializes the digest structure for a Blake2b 512 bit hash
pub fn new512() !&Digest {
return new_digest(blake2b.size512, []u8{})!
}
// new_pmac512 initializes the digest structure for a Blake2b 512 bit prefix MAC
pub fn new_pmac512(key []u8) !&Digest {
return new_digest(blake2b.size512, key)!
}
// new384 initializes the digest structure for a Blake2b 384 bit hash
pub fn new384() !&Digest {
return new_digest(blake2b.size384, []u8{})!
}
// new_pmac384 initializes the digest structure for a Blake2b 384 bit prefix MAC
pub fn new_pmac384(key []u8) !&Digest {
return new_digest(blake2b.size384, key)!
}
// new256 initializes the digest structure for a Blake2b 256 bit hash
pub fn new256() !&Digest {
return new_digest(blake2b.size256, []u8{})!
}
// new_pmac256 initializes the digest structure for a Blake2b 256 bit prefix MAC
pub fn new_pmac256(key []u8) !&Digest {
return new_digest(blake2b.size256, key)!
}
// new160 initializes the digest structure for a Blake2b 160 bit hash
pub fn new160() !&Digest {
return new_digest(blake2b.size160, []u8{})!
}
// new_pmac160 initializes the digest structure for a Blake2b 160 bit prefix MAC
pub fn new_pmac160(key []u8) !&Digest {
return new_digest(blake2b.size160, key)!
}
struct HashSizeError {
Error
size u8
}
fn (err HashSizeError) msg() string {
return 'Hash size ${err.size} must be between 1 and ${blake2b.size512}'
}
struct KeySizeError {
Error
size i32
}
fn (err KeySizeError) msg() string {
return 'Key size ${err.size} must be between 0 and ${blake2b.size512}'
}
struct InputBufferSizeError {
Error
size i32
}
fn (err InputBufferSizeError) msg() string {
return 'The input buffer size ${err.size} .must be between 0 and ${blake2b.block_size}'
}
// new_digest creates an initialized digest structure based on
// the hash size and whether or not you specify a MAC key.
//
// hash_size - the number if bytes in the generated hash.
// Legal values are between 1 and 64.
//
// key - key used for generating a prefix MAC. A zero length
// key is used for just generating a hash. A key of 1 to
// 64 bytes can be used for generating a prefix MAC.
pub fn new_digest(hash_size u8, key []u8) !&Digest {
if hash_size < 1 || hash_size > blake2b.size512 {
return HashSizeError{
size: hash_size
}
}
if key.len < 0 || key.len > blake2b.size512 {
return KeySizeError{
size: i32(key.len)
}
}
mut d := Digest{
h: blake2b.iv.clone()
t: unsigned.uint128_zero
hash_size: hash_size
}
if key.len > 0 {
p0 := 0x0000000001010000 ^ u64(key.len) << 8 ^ u64(hash_size)
d.h[0] ^= p0
d.input_buffer.clear()
d.input_buffer << key
pad_length := blake2b.block_size - key.len
for _ in 0 .. pad_length {
d.input_buffer << 0
}
} else {
p0 := 0x0000000001010000 ^ u64(hash_size)
d.h[0] ^= p0
}
return &d
}
// The intent is to only use this method
// when the input buffer is full or when
// the last data to be hashed is in the
// input buffer.
//
// If the input buffer does not contain enough
// data to fill all the message blocks, the
// input buffer is padded with 0 bytes until
// it is full prior to moving the data into
// the message blocks.
//
// The input buffer is emptied.
//
// The total byte count is incremented by the
// number of bytes in the input buffer.
fn (mut d Digest) move_input_to_message_blocks() ! {
// the number of bytes in the input buffer
// should never exceed the block size.
if d.input_buffer.len < 0 || d.input_buffer.len > blake2b.block_size {
return InputBufferSizeError{
size: i32(d.input_buffer.len)
}
}
// keep the hashed data length up to date
d.t = d.t.add_64(u64(d.input_buffer.len))
// pad the input buffer if necessary
if d.input_buffer.len < blake2b.block_size {
pad_length := blake2b.block_size - d.input_buffer.len
for _ in 0 .. pad_length {
d.input_buffer << 0
}
}
// treat the input bytes as little endian u64 values
for i in 0 .. 16 {
d.m[i] = binary.little_endian_u64_at(d.input_buffer, i * 8)
}
// empty the input buffer
d.input_buffer.clear()
return
}
// write adds bytes to the hash
pub fn (mut d Digest) write(data []u8) ! {
// if no data is being added to the hash,
// just return
if data.len == 0 {
return
}
// if the input buffer is already full,
// process the existing input bytes first.
// this is not the final input.
if d.input_buffer.len >= blake2b.block_size {
d.move_input_to_message_blocks()!
d.f(false)
}
// add data to the input buffer until you
// run out of space in the input buffer or
// run out of data, whichever comes first.
empty_space := blake2b.block_size - d.input_buffer.len
mut remaining_data := unsafe { data[..] }
if empty_space >= data.len {
// ran out of data first
// just add it to the input buffer and return
d.input_buffer << data
return
} else {
// ran out of input buffer space first
// fill it up and process it.
d.input_buffer << data[..empty_space]
remaining_data = unsafe { remaining_data[empty_space..] }
d.move_input_to_message_blocks()!
d.f(false)
}
// process the data in block size amounts until
// all the data has been processed
for remaining_data.len > 0 {
if blake2b.block_size >= remaining_data.len {
// running out of data
// just add it to the input buffer and return
d.input_buffer << remaining_data
return
}
// add block size bytes to the input buffer
// and process it
d.input_buffer << remaining_data[..blake2b.block_size]
remaining_data = unsafe { remaining_data[blake2b.block_size..] }
d.move_input_to_message_blocks()!
d.f(false)
}
return
}
fn (mut d Digest) checksum_internal() ![]u8 {
// process the last input bytes
d.move_input_to_message_blocks()!
d.f(true)
// get the hash into the proper byte order
mut hash_bytes := []u8{}
for hash in d.h {
mut h_bytes := []u8{len: 8, cap: 8}
binary.little_endian_put_u64(mut h_bytes, hash)
hash_bytes << h_bytes
}
// return the appropriate number of hash bytes
return hash_bytes[..d.hash_size]
}
// checksum finalizes the hash and returns the generated bytes.
pub fn (mut d Digest) checksum() []u8 {
return d.checksum_internal() or { panic(err) }
}
// sum512 returns the Blake2b 512 bit checksum of the data.
pub fn sum512(data []u8) []u8 {
mut d := new512() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum384 returns the Blake2b 384 bit checksum of the data.
pub fn sum384(data []u8) []u8 {
mut d := new384() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum256 returns the Blake2b 256 bit checksum of the data.
pub fn sum256(data []u8) []u8 {
mut d := new256() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum160 returns the Blake2b 160 bit checksum of the data.
pub fn sum160(data []u8) []u8 {
mut d := new160() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac512 returns the Blake2b 512 bit prefix MAC of the data.
pub fn pmac512(data []u8, key []u8) []u8 {
mut d := new_pmac512(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac384 returns the Blake2b 384 bit prefix MAC of the data.
pub fn pmac384(data []u8, key []u8) []u8 {
mut d := new_pmac384(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac256 returns the Blake2b 256 bit prefix MAC of the data.
pub fn pmac256(data []u8, key []u8) []u8 {
mut d := new_pmac256(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac160 returns the Blake2b 160 bit prefix MAC of the data.
pub fn pmac160(data []u8, key []u8) []u8 {
mut d := new_pmac160(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}

View file

@ -0,0 +1,78 @@
// Copyright (c) 2023 Kim Shrier. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// Package blake2b implements the Blake2b 512, 384, 256, and
// 160 bit hash algorithms
// as defined in IETF RFC 7693.
// Based off: https://datatracker.ietf.org/doc/html/rfc7693
// Last updated: November 2015
module blake2b
import math.bits
// mixing function g
@[inline]
fn g(mut v []u64, a u8, b u8, c u8, d u8, x u64, y u64) {
v[a] = v[a] + v[b] + x
v[d] = bits.rotate_left_64((v[d] ^ v[a]), nr1)
v[c] = v[c] + v[d]
v[b] = bits.rotate_left_64((v[b] ^ v[c]), nr2)
v[a] = v[a] + v[b] + y
v[d] = bits.rotate_left_64((v[d] ^ v[a]), nr3)
v[c] = v[c] + v[d]
v[b] = bits.rotate_left_64((v[b] ^ v[c]), nr4)
}
// one complete mixing round with the function g
@[inline]
fn (d Digest) mixing_round(mut v []u64, s []u8) {
g(mut v, 0, 4, 8, 12, d.m[s[0]], d.m[s[1]])
g(mut v, 1, 5, 9, 13, d.m[s[2]], d.m[s[3]])
g(mut v, 2, 6, 10, 14, d.m[s[4]], d.m[s[5]])
g(mut v, 3, 7, 11, 15, d.m[s[6]], d.m[s[7]])
g(mut v, 0, 5, 10, 15, d.m[s[8]], d.m[s[9]])
g(mut v, 1, 6, 11, 12, d.m[s[10]], d.m[s[11]])
g(mut v, 2, 7, 8, 13, d.m[s[12]], d.m[s[13]])
g(mut v, 3, 4, 9, 14, d.m[s[14]], d.m[s[15]])
}
// compression function f
fn (mut d Digest) f(f bool) {
// initialize the working vector
mut v := []u64{len: 0, cap: 16}
v << d.h[..8]
v << iv[..8]
v[12] ^= d.t.lo
v[13] ^= d.t.hi
if f {
v[14] = ~v[14]
}
// go 12 rounds of cryptographic mixing
d.mixing_round(mut v, sigma[0])
d.mixing_round(mut v, sigma[1])
d.mixing_round(mut v, sigma[2])
d.mixing_round(mut v, sigma[3])
d.mixing_round(mut v, sigma[4])
d.mixing_round(mut v, sigma[5])
d.mixing_round(mut v, sigma[6])
d.mixing_round(mut v, sigma[7])
d.mixing_round(mut v, sigma[8])
d.mixing_round(mut v, sigma[9])
d.mixing_round(mut v, sigma[0])
d.mixing_round(mut v, sigma[1])
// combine internal hash state with both halves of the working vector
d.h[0] = d.h[0] ^ v[0] ^ v[8]
d.h[1] = d.h[1] ^ v[1] ^ v[9]
d.h[2] = d.h[2] ^ v[2] ^ v[10]
d.h[3] = d.h[3] ^ v[3] ^ v[11]
d.h[4] = d.h[4] ^ v[4] ^ v[12]
d.h[5] = d.h[5] ^ v[5] ^ v[13]
d.h[6] = d.h[6] ^ v[6] ^ v[14]
d.h[7] = d.h[7] ^ v[7] ^ v[15]
}

View file

@ -0,0 +1,136 @@
module blake2b
// from RFC-7693 Appendix A
const expected_m_results = [u64(0x0000000000636261), 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000]
// from RFC-7693 Appendix A
const expected_v_initial_results = [u64(0x6a09e667f2bdc948), 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b,
0x5be0cd19137e2179, 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1, 0x510e527fade682d2, 0x9b05688c2b3e6c1f, 0xe07c265404be4294,
0x5be0cd19137e2179]
// from RFC-7693 Appendix A
const expected_v_results = [
[u64(0x86b7c1568029bb79), 0xc12cbcc809ff59f3, 0xc6a5214cc0eaca8e, 0x0c87cd524c14cc5d,
0x44ee6039bd86a9f7, 0xa447c850aa694a7e, 0xde080f1bb1c0f84b, 0x595cb8a9a1aca66c,
0xbec3ae837eac4887, 0x6267fc79df9d6ad1, 0xfa87b01273fa6dbe, 0x521a715c63e08d8a,
0xe02d0975b8d37a83, 0x1c7b754f08b7d193, 0x8f885a76b6e578fe, 0x2318a24e2140fc64],
[u64(0x53281e83806010f2), 0x3594b403f81b4393, 0x8cd63c7462de0dff, 0x85f693f3da53f974,
0xbaabdbb2f386d9ae, 0xca5425aec65a10a8, 0xc6a22e2ff0f7aa48, 0xc6a56a51cb89c595,
0x224e6a3369224f96, 0x500e125e58a92923, 0xe9e4ad0d0e1a0d48, 0x85df9dc143c59a74,
0x92a3aaaa6d952b7f, 0xc5fdf71090fae853, 0x2a8a40f15a462dd0, 0x572d17effdd37358],
[u64(0x60ed96aa7ad41725), 0xe46a743c71800b9d, 0x1a04b543a01f156b, 0xa2f8716e775c4877,
0xda0a61bcde4267ea, 0xb1dd230754d7bdee, 0x25a1422779e06d14, 0xe6823ae4c3ff58a5,
0xa1677e19f37fd5da, 0x22bdce6976b08c51, 0xf1de8696bec11bf1, 0xa0ebd586a4a1d2c8,
0xc804ebab11c99fa9, 0x8e0cec959c715793, 0x7c45557fae0d4d89, 0x716343f52fdd265e],
[u64(0xbb2a77d3a8382351), 0x45eb47971f23b103, 0x98be297f6e45c684, 0xa36077dee3370b89,
0x8a03c4cb7e97590a, 0x24192e49ebf54ea0, 0x4f82c9401cb32d7a, 0x8ccd013726420dc4,
0xa9c9a8f17b1fc614, 0x55908187977514a0, 0x5b44273e66b19d27, 0xb6d5c9fca2579327,
0x086092cfb858437e, 0x5c4be2156dbeecf9, 0x2efede99ed4eff16, 0x3e7b5f234cd1f804],
[u64(0xc79c15b3d423b099), 0x2da2224e8da97556, 0x77d2b26df1c45c55, 0x8934eb09a3456052,
0x0f6d9eeed157da2a, 0x6fe66467af88c0a9, 0x4eb0b76284c7aafb, 0x299c8e725d954697,
0xb2240b59e6d567d3, 0x2643c2370e49ebfd, 0x79e02eef20cdb1ae, 0x64b3eed7bb602f39,
0xb97d2d439e4df63d, 0xc718e755294c9111, 0x1f0893f2772bb373, 0x1205ea4a7859807d],
[u64(0xe58f97d6385baee4), 0x7640aa9764da137a, 0xdeb4c7c23efe287e, 0x70f6f41c8783c9f6,
0x7127cd48c76a7708, 0x9e472af0be3db3f6, 0x0f244c62ddf71788, 0x219828aa83880842,
0x41cca9073c8c4d0d, 0x5c7912bc10df3b4b, 0xa2c3abbd37510ee2, 0xcb5668cc2a9f7859,
0x8733794f07ac1500, 0xc67a6be42335aa6f, 0xacb22b28681e4c82, 0xdb2161604cbc9828],
[u64(0x6e2d286eeadedc81), 0xbcf02c0787e86358, 0x57d56a56dd015edf, 0x55d899d40a5d0d0a,
0x819415b56220c459, 0xb63c479a6a769f02, 0x258e55e0ec1f362a, 0x3a3b4ec60e19dfdc,
0x04d769b3fcb048db, 0xb78a9a33e9bff4dd, 0x5777272ae1e930c0, 0x5a387849e578dbf6,
0x92aac307cf2c0afc, 0x30aaccc4f06dafaa, 0x483893cc094f8863, 0xe03c6cc89c26bf92],
[u64(0xffc83ece76024d01), 0x1be7bffb8c5cc5f9, 0xa35a18cbac4c65b7, 0xb7c2c7e6d88c285f,
0x81937da314a50838, 0xe1179523a2541963, 0x3a1fad7106232b8f, 0x1c7ede92ab8b9c46,
0xa3c2d35e4f685c10, 0xa53d3f73aa619624, 0x30bbcc0285a22f65, 0xbcefbb6a81539e5d,
0x3841def6f4c9848a, 0x98662c85fba726d4, 0x7762439bd5a851bd, 0xb0b9f0d443d1a889],
[u64(0x753a70a1e8faeadd), 0x6b0d43ca2c25d629, 0xf8343ba8b94f8c0b, 0xbc7d062b0db5cf35,
0x58540ee1b1aebc47, 0x63c5b9b80d294cb9, 0x490870ecad27debd, 0xb2a90ddf667287fe,
0x316cc9ebeefad8fc, 0x4a466bcd021526a4, 0x5da7f7638cec5669, 0xd9c8826727d306fc,
0x88ed6c4f3bd7a537, 0x19ae688ddf67f026, 0x4d8707aab40f7e6d, 0xfd3f572687fea4f1],
[u64(0xe630c747ccd59c4f), 0xbc713d41127571ca, 0x46db183025025078, 0x6727e81260610140,
0x2d04185eac2a8cba, 0x5f311b88904056ec, 0x40bd313009201aab, 0x0099d4f82a2a1eab,
0x6dd4fbc1de60165d, 0xb3b0b51de3c86270, 0x900aee2f233b08e5, 0xa07199d87ad058d8,
0x2c6b25593d717852, 0x37e8ca471beaa5f8, 0x2cfc1bac10ef4457, 0x01369ec18746e775],
[u64(0xe801f73b9768c760), 0x35c6d22320be511d, 0x306f27584f65495e, 0xb51776adf569a77b,
0xf4f1be86690b3c34, 0x3cc88735d1475e4b, 0x5dac67921ff76949, 0x1cdb9d31ad70cc4e,
0x35ba354a9c7df448, 0x4929cbe45679d73e, 0x733d1a17248f39db, 0x92d57b736f5f170a,
0x61b5c0a41d491399, 0xb5c333457e12844a, 0xbd696be010d0d889, 0x02231e1a917fe0bd],
[u64(0x12ef8a641ec4f6d6), 0xbced5de977c9faf5, 0x733ca476c5148639, 0x97df596b0610f6fc,
0xf42c16519ad5afa7, 0xaa5ac1888e10467e, 0x217d930aa51787f3, 0x906a6ff19e573942,
0x75ab709bd3dcbf24, 0xee7ce1f345947aa4, 0xf8960d6c2faf5f5e, 0xe332538a36b6d246,
0x885bef040ef6aa0b, 0xa4939a417bfb78a3, 0x646cbb7af6dce980, 0xe813a23c60af3b82],
]
// from RFC-7693 Appendix A
const expected_h_results = [u64(0x0d4d1c983fa580ba), 0xe9f6129fb697276a, 0xb7c45a68142f214c,
0xd1a2ffdb6fbb124b, 0x2d79ab2a39c5877d, 0x95cc3345ded552c2, 0x5a92f1dba88ad318,
0x239900d4ed8623b9]
fn test_mixing_function_g() {
mut d := new512() or {
assert false, 'unable to create new 512 bit hash digest: ${err}'
return
}
// set up the message blocks with the value 'abc'
// the firet block will have the 3 bytes of the text to hash
// and the rest of the first block and the other 7 blocks
// will be all zeros. d.m[1..16] should already be zero.
d.m[0] = 0x0000000000636261
// indicate that we have 3 bytes in the message block
d.t = d.t.add_64(3)
// indicate that the message block contains the end of the
// text being hashed.
f := true
// initialize the working vector from the digest and IV values
mut v := []u64{len: 0, cap: 16}
v << d.h[..8]
v << iv[..8]
// fold in the 128-bit message length
v[12] ^= d.t.lo
v[13] ^= d.t.hi
// and flip the bits in v[14] because this is the end of the
// text being hashed.
if f {
v[14] = ~v[14]
}
for i in 0 .. 16 {
assert v[i] == blake2b.expected_v_initial_results[i], 'expeccted expected_v_initial_results[${i}] ${blake2b.expected_v_initial_results[i]:016x} actual v[${i}] ${v[i]:016x}'
}
for i in 0 .. 16 {
assert d.m[i] == blake2b.expected_m_results[i], 'expeccted expected_m_results[${i}] ${blake2b.expected_m_results[i]:016x} actual d.m[${i}] ${d.m[i]:016x}'
}
for r in 0 .. blake2b.expected_v_results.len {
d.mixing_round(mut v, sigma[r % 10])
for i in 0 .. 16 {
assert v[i] == blake2b.expected_v_results[r][i], 'expeccted expected_v_results[${r}][${i}] ${blake2b.expected_v_results[r][i]:016x} actual v[${i}] ${v[i]:016x}'
}
}
d.h[0] = d.h[0] ^ v[0] ^ v[8]
d.h[1] = d.h[1] ^ v[1] ^ v[9]
d.h[2] = d.h[2] ^ v[2] ^ v[10]
d.h[3] = d.h[3] ^ v[3] ^ v[11]
d.h[4] = d.h[4] ^ v[4] ^ v[12]
d.h[5] = d.h[5] ^ v[5] ^ v[13]
d.h[6] = d.h[6] ^ v[6] ^ v[14]
d.h[7] = d.h[7] ^ v[7] ^ v[15]
for i in 0 .. 8 {
assert d.h[i] == blake2b.expected_h_results[i], 'expeccted expected_h_results[${i}] ${blake2b.expected_h_results[i]:016x} actual d.h[${i}] ${d.h[i]:016x}'
}
}

File diff suppressed because it is too large Load diff

12
vlib/crypto/blake2b/testdata/README vendored Normal file
View file

@ -0,0 +1,12 @@
These test vectors are extracted from
https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2-kat.json
All json objects that contain '"hash": "blake2b"' have been extracted and
saved in blake2b_test_vectors.json.
Using the blake2b.awk program on blake2b_test_vectors.json, we can
generate v code that can initialize an array of TestVector structures.
awk -f blake2b.awk blake2b_test_vectors.json >test_vectors.v
Copy the contents of test_vectors.v into ../blake2b_test.v

View file

@ -0,0 +1,7 @@
/\[/ { print ("const vectors = [") }
/]/ { print ("]") }
/"hash": "blake2b"/ { print ("\tTestVector{") }
/"in":/ { gsub(/"|,/, "", $2); print ("\t\tinput: '" $2 "',") }
/"key":/ { gsub(/"|,/, "", $2); print ("\t\tkey: '" $2 "',") }
/"out":/ { gsub(/"|,/, "", $2); print ("\t\toutput: '" $2 "',") }
/}/ { print (" },") }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,376 @@
// Copyright (c) 2023 Kim Shrier. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// Package blake2s implements the Blake2s 256, 224, 160, and
// 128 bit hash algorithms
// as defined in IETF RFC 7693.
// Based off: https://datatracker.ietf.org/doc/html/rfc7693
// Last updated: November 2015
module blake2s
import encoding.binary
// size128 is the size, in bytes, of a Blake2s 128 checksum.
pub const size128 = 16
// size160 is the size, in bytes, of a Blake2s 160 checksum.
pub const size160 = 20
// size224 is the size, in bytes, of a Blake2s 224 checksum.
pub const size224 = 28
// size256 is the size, in bytes, of a Blake2s 256 checksum.
pub const size256 = 32
// block_size is the block size, in bytes, of the Blake2s hash functions.
pub const block_size = 64
// G rotation constants
const r1 = 16
const r2 = 12
const r3 = 8
const r4 = 7
// negative G rotation constants so we can rotate right.
const nr1 = -1 * r1
const nr2 = -1 * r2
const nr3 = -1 * r3
const nr4 = -1 * r4
// initialization vector
const iv = [
u32(0x6a09e667),
u32(0xbb67ae85),
u32(0x3c6ef372),
u32(0xa54ff53a),
u32(0x510e527f),
u32(0x9b05688c),
u32(0x1f83d9ab),
u32(0x5be0cd19),
]
// message word schedule permutations
const sigma = [
[u8(0), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[u8(14), 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[u8(11), 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[u8(7), 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[u8(9), 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[u8(2), 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[u8(12), 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[u8(13), 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[u8(6), 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[u8(10), 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
]
struct Digest {
hash_size u8
mut:
input_buffer []u8
h []u32
m [16]u32
t u64
}
// string makes a formatted string representation of a Digest structure
pub fn (d Digest) str() string {
return 'blake2s.Digest{\n hash_size: ${d.hash_size}\n input_buffer: ${d.input_buffer}\n input_buffer.len: ${d.input_buffer.len}\n h: [0x${d.h[0]:016x}, 0x${d.h[1]:016x}, 0x${d.h[2]:016x}, 0x${d.h[3]:016x},\n 0x${d.h[4]:016x}, 0x${d.h[5]:016x}, 0x${d.h[6]:016x}, 0x${d.h[7]:016x}]\n m: [0x${d.m[0]:016x}, 0x${d.m[1]:016x}, 0x${d.m[2]:016x}, 0x${d.m[3]:016x},\n 0x${d.m[4]:016x}, 0x${d.m[5]:016x}, 0x${d.m[6]:016x}, 0x${d.m[7]:016x},\n 0x${d.m[8]:016x}, 0x${d.m[9]:016x}, 0x${d.m[10]:016x}, 0x${d.m[11]:016x},\n 0x${d.m[12]:016x}, 0x${d.m[13]:016x}, 0x${d.m[14]:016x}, 0x${d.m[15]:016x}]\n t: ${d.t}\n}'
}
// new256 initializes the digest structure for a Blake2s 256 bit hash
pub fn new256() !&Digest {
return new_digest(blake2s.size256, []u8{})!
}
// new_pmac256 initializes the digest structure for a Blake2s 256 bit prefix MAC
pub fn new_pmac256(key []u8) !&Digest {
return new_digest(blake2s.size256, key)!
}
// new224 initializes the digest structure for a Blake2s 224 bit hash
pub fn new224() !&Digest {
return new_digest(blake2s.size224, []u8{})!
}
// new_pmac224 initializes the digest structure for a Blake2s 224 bit prefix MAC
pub fn new_pmac224(key []u8) !&Digest {
return new_digest(blake2s.size224, key)!
}
// new160 initializes the digest structure for a Blake2s 160 bit hash
pub fn new160() !&Digest {
return new_digest(blake2s.size160, []u8{})!
}
// new_pmac160 initializes the digest structure for a Blake2s 160 bit prefix MAC
pub fn new_pmac160(key []u8) !&Digest {
return new_digest(blake2s.size160, key)!
}
// new126 initializes the digest structure for a Blake2s 128 bit hash
pub fn new128() !&Digest {
return new_digest(blake2s.size128, []u8{})!
}
// new_pmac128 initializes the digest structure for a Blake2s 128 bit prefix MAC
pub fn new_pmac128(key []u8) !&Digest {
return new_digest(blake2s.size128, key)!
}
struct HashSizeError {
Error
size u8
}
fn (err HashSizeError) msg() string {
return 'Hash size ${err.size} must be between 1 and ${blake2s.size256}'
}
struct KeySizeError {
Error
size i32
}
fn (err KeySizeError) msg() string {
return 'Key size ${err.size} must be between 0 and ${blake2s.size256}'
}
struct InputBufferSizeError {
Error
size i32
}
fn (err InputBufferSizeError) msg() string {
return 'The input buffer size ${err.size} .must be between 0 and ${blake2s.block_size}'
}
// new_digest creates an initialized digest structure based on
// the hash size and whether or not you specify a MAC key.
//
// hash_size - the number if bytes in the generated hash.
// Legal values are between 1 and 32.
//
// key - key used for generating a prefix MAC. A zero length
// key is used for just generating a hash. A key of 1 to
// 32 bytes can be used for generating a prefix MAC.
pub fn new_digest(hash_size u8, key []u8) !&Digest {
if hash_size < 1 || hash_size > blake2s.size256 {
return HashSizeError{
size: hash_size
}
}
if key.len < 0 || key.len > blake2s.size256 {
return KeySizeError{
size: i32(key.len)
}
}
mut d := Digest{
h: blake2s.iv.clone()
t: 0
hash_size: hash_size
}
if key.len > 0 {
p0 := 0x01010000 ^ u32(key.len) << 8 ^ u32(hash_size)
d.h[0] ^= p0
d.input_buffer.clear()
d.input_buffer << key
pad_length := blake2s.block_size - key.len
for _ in 0 .. pad_length {
d.input_buffer << 0
}
} else {
p0 := 0x01010000 ^ u32(hash_size)
d.h[0] ^= p0
}
return &d
}
// The intent is to only use this method
// when the input buffer is full or when
// the last data to be hashed is in the
// input buffer.
//
// If the input buffer does not contain enough
// data to fill all the message blocks, the
// input buffer is padded with 0 bytes until
// it is full prior to moving the data into
// the message blocks.
//
// The input buffer is emptied.
//
// The total byte count is incremented by the
// number of bytes in the input buffer.
fn (mut d Digest) move_input_to_message_blocks() ! {
// the number of bytes in the input buffer
// should never exceed the block size.
if d.input_buffer.len < 0 || d.input_buffer.len > blake2s.block_size {
return InputBufferSizeError{
size: i32(d.input_buffer.len)
}
}
// keep the hashed data length up to date
d.t += u64(d.input_buffer.len)
// pad the input buffer if necessary
if d.input_buffer.len < blake2s.block_size {
pad_length := blake2s.block_size - d.input_buffer.len
for _ in 0 .. pad_length {
d.input_buffer << 0
}
}
// treat the input bytes as little endian u32 values
for i in 0 .. 16 {
d.m[i] = binary.little_endian_u32_at(d.input_buffer, i * 4)
}
// empty the input buffer
d.input_buffer.clear()
return
}
// write adds bytes to the hash
pub fn (mut d Digest) write(data []u8) ! {
// if no data is being added to the hash,
// just return
if data.len == 0 {
return
}
// if the input buffer is already full,
// process the existing input bytes first.
// this is not the final input.
if d.input_buffer.len >= blake2s.block_size {
d.move_input_to_message_blocks()!
d.f(false)
}
// add data to the input buffer until you
// run out of space in the input buffer or
// run out of data, whichever comes first.
empty_space := blake2s.block_size - d.input_buffer.len
mut remaining_data := unsafe { data[..] }
if empty_space >= data.len {
// ran out of data first
// just add it to the input buffer and return
d.input_buffer << data
return
} else {
// ran out of input buffer space first
// fill it up and process it.
d.input_buffer << data[..empty_space]
remaining_data = unsafe { remaining_data[empty_space..] }
d.move_input_to_message_blocks()!
d.f(false)
}
// process the data in block size amounts until
// all the data has been processed
for remaining_data.len > 0 {
if blake2s.block_size >= remaining_data.len {
// running out of data
// just add it to the input buffer and return
d.input_buffer << remaining_data
return
}
// add block size bytes to the input buffer
// and process it
d.input_buffer << remaining_data[..blake2s.block_size]
remaining_data = unsafe { remaining_data[blake2s.block_size..] }
d.move_input_to_message_blocks()!
d.f(false)
}
return
}
fn (mut d Digest) checksum_internal() ![]u8 {
// process the last input bytes
d.move_input_to_message_blocks()!
d.f(true)
// get the hash into the proper byte order
mut hash_bytes := []u8{}
for hash in d.h {
mut h_bytes := []u8{len: 4, cap: 4}
binary.little_endian_put_u32(mut h_bytes, hash)
hash_bytes << h_bytes
}
// return the appropriate number of hash bytes
return hash_bytes[..d.hash_size]
}
// checksum finalizes the hash and returns the generated bytes.
pub fn (mut d Digest) checksum() []u8 {
return d.checksum_internal() or { panic(err) }
}
// sum256 returns the Blake2s 256 bit checksum of the data.
pub fn sum256(data []u8) []u8 {
mut d := new256() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum224 returns the Blake2s 224 bit checksum of the data.
pub fn sum224(data []u8) []u8 {
mut d := new224() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum160 returns the Blake2s 160 bit checksum of the data.
pub fn sum160(data []u8) []u8 {
mut d := new160() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// sum128 returns the Blake2s 128 bit checksum of the data.
pub fn sum128(data []u8) []u8 {
mut d := new128() or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac256 returns the Blake2s 256 bit prefix MAC of the data.
pub fn pmac256(data []u8, key []u8) []u8 {
mut d := new_pmac256(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac224 returns the Blake2s 224 bit prefix MAC of the data.
pub fn pmac224(data []u8, key []u8) []u8 {
mut d := new_pmac224(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac160 returns the Blake2s 160 bit prefix MAC of the data.
pub fn pmac160(data []u8, key []u8) []u8 {
mut d := new_pmac160(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}
// pmac128 returns the Blake2s 128 bit prefix MAC of the data.
pub fn pmac128(data []u8, key []u8) []u8 {
mut d := new_pmac128(key) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal() or { panic(err) }
}

View file

@ -0,0 +1,76 @@
// Copyright (c) 2023 Kim Shrier. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// Package blake2s implements the Blake2s 256, 224, 160, and
// 128 bit hash algorithms
// as defined in IETF RFC 7693.
// Based off: https://datatracker.ietf.org/doc/html/rfc7693
// Last updated: November 2015
module blake2s
import math.bits
// mixing function g
@[inline]
fn g(mut v []u32, a u8, b u8, c u8, d u8, x u32, y u32) {
v[a] = v[a] + v[b] + x
v[d] = bits.rotate_left_32((v[d] ^ v[a]), nr1)
v[c] = v[c] + v[d]
v[b] = bits.rotate_left_32((v[b] ^ v[c]), nr2)
v[a] = v[a] + v[b] + y
v[d] = bits.rotate_left_32((v[d] ^ v[a]), nr3)
v[c] = v[c] + v[d]
v[b] = bits.rotate_left_32((v[b] ^ v[c]), nr4)
}
// one complete mixing round with the function g
@[inline]
fn (d Digest) mixing_round(mut v []u32, s []u8) {
g(mut v, 0, 4, 8, 12, d.m[s[0]], d.m[s[1]])
g(mut v, 1, 5, 9, 13, d.m[s[2]], d.m[s[3]])
g(mut v, 2, 6, 10, 14, d.m[s[4]], d.m[s[5]])
g(mut v, 3, 7, 11, 15, d.m[s[6]], d.m[s[7]])
g(mut v, 0, 5, 10, 15, d.m[s[8]], d.m[s[9]])
g(mut v, 1, 6, 11, 12, d.m[s[10]], d.m[s[11]])
g(mut v, 2, 7, 8, 13, d.m[s[12]], d.m[s[13]])
g(mut v, 3, 4, 9, 14, d.m[s[14]], d.m[s[15]])
}
// compression function f
fn (mut d Digest) f(f bool) {
// initialize the working vector
mut v := []u32{len: 0, cap: 16}
v << d.h[..8]
v << iv[..8]
v[12] ^= u32(d.t & 0x00000000ffffffff)
v[13] ^= u32(d.t >> 32)
if f {
v[14] = ~v[14]
}
// go 10 rounds of cryptographic mixing
d.mixing_round(mut v, sigma[0])
d.mixing_round(mut v, sigma[1])
d.mixing_round(mut v, sigma[2])
d.mixing_round(mut v, sigma[3])
d.mixing_round(mut v, sigma[4])
d.mixing_round(mut v, sigma[5])
d.mixing_round(mut v, sigma[6])
d.mixing_round(mut v, sigma[7])
d.mixing_round(mut v, sigma[8])
d.mixing_round(mut v, sigma[9])
// combine internal hash state with both halves of the working vector
d.h[0] = d.h[0] ^ v[0] ^ v[8]
d.h[1] = d.h[1] ^ v[1] ^ v[9]
d.h[2] = d.h[2] ^ v[2] ^ v[10]
d.h[3] = d.h[3] ^ v[3] ^ v[11]
d.h[4] = d.h[4] ^ v[4] ^ v[12]
d.h[5] = d.h[5] ^ v[5] ^ v[13]
d.h[6] = d.h[6] ^ v[6] ^ v[14]
d.h[7] = d.h[7] ^ v[7] ^ v[15]
}

View file

@ -0,0 +1,113 @@
module blake2s
// from RFC-7693 Appendix B
const expected_m_results = [u32(0x00636261), 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000]
// from RFC-7693 Appendix B
const expected_v_initial_results = [u32(0x6b08e647), 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f,
0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527c,
0x9b05688c, 0xe07c2654, 0x5be0cd19]
// from RFC-7693 Appendix B
const expected_v_results = [
[u32(0x16a3242e), 0xd7b5e238, 0xce8ce24b, 0x927aede1, 0xa7b430d9, 0x93a4a14e, 0xa44e7c31,
0x41d4759b, 0x95bf33d3, 0x9a99c181, 0x608a3a6b, 0xb666383e, 0x7a8dd50f, 0xbe378ed7,
0x353d1ee6, 0x3bb44c6b],
[u32(0x3ae30fe3), 0x0982a96b, 0xe88185b4, 0x3e339b16, 0xf24338cd, 0x0e66d326, 0xe005ed0c,
0xd591a277, 0x180b1f3a, 0xfcf43914, 0x30db62d6, 0x4847831c, 0x7f00c58e, 0xfb847886,
0xc544e836, 0x524ab0e2],
[u32(0x7a3be783), 0x997546c1, 0xd45246df, 0xedb5f821, 0x7f98a742, 0x10e864e2, 0xd4ab70d0,
0xc63cb1ab, 0x6038da9e, 0x414594b0, 0xf2c218b5, 0x8da0dcb7, 0xd7cd7af5, 0xab4909df,
0x85031a52, 0xc4edfc98],
[u32(0x2a8b8cb7), 0x1aca82b2, 0x14045d7f, 0xcc7258ed, 0x383cf67c, 0xe090e7f9, 0x3025d276,
0x57d04de4, 0x994bacf0, 0xf0982759, 0xf17ee300, 0xd48fc2d5, 0xdc854c10, 0x523898a9,
0xc03a0f89, 0x47d6cd88],
[u32(0xc4aa2ddb), 0x111343a3, 0xd54a700a, 0x574a00a9, 0x857d5a48, 0xb1e11989, 0x6f5c52df,
0xdd2c53a3, 0x678e5f8e, 0x9718d4e9, 0x622cb684, 0x92976076, 0x0e41a517, 0x359dc2be,
0x87a87ddd, 0x643f9cec],
[u32(0x3453921c), 0xd7595ee1, 0x592e776d, 0x3ed6a974, 0x4d997cb3, 0xde9212c3, 0x35adf5c9,
0x9916fd65, 0x96562e89, 0x4ead0792, 0xebfc2712, 0x2385f5b2, 0xf34600fb, 0xd7bc20fb,
0xeb452a7b, 0xece1aa40],
[u32(0xbe851b2d), 0xa85f6358, 0x81e6fc3b, 0x0bb28000, 0xfa55a33a, 0x87be1fad, 0x4119370f,
0x1e2261aa, 0xa1318fd3, 0xf4329816, 0x071783c2, 0x6e536a8d, 0x9a81a601, 0xe7ec80f1,
0xacc09948, 0xf849a584],
[u32(0x07e5b85a), 0x069cc164, 0xf9de3141, 0xa56f4680, 0x9e440ad2, 0x9ab659ea, 0x3c84b971,
0x21dbd9cf, 0x46699f8c, 0x765257ec, 0xaf1d998c, 0x75e4c3b6, 0x523878dc, 0x30715015,
0x397fee81, 0x4f1fa799],
[u32(0x435148c4), 0xa5aa2d11, 0x4b354173, 0xd543bc9e, 0xbda2591c, 0xbf1d2569, 0x4fcb3120,
0x707ada48, 0x565b3fde, 0x32c9c916, 0xeaf4a1ab, 0xb1018f28, 0x8078d978, 0x68ade4b5,
0x9778fda3, 0x2863b92e],
[u32(0xd9c994aa), 0xcfec3aa6, 0x700d0ab2, 0x2c38670e, 0xaf6a1f66, 0x1d023ef3, 0x1d9ec27d,
0x945357a5, 0x3e9ffebd, 0x969fe811, 0xef485e21, 0xa632797a, 0xdeef082e, 0xaf3d80e1,
0x4e86829b, 0x4deafd3a],
]
// from RFC-7693 Appendix B
const expected_h_results = [u32(0x8c5e8c50), 0xe2147c32, 0xa32ba7e1, 0x2f45eb4e, 0x208b4537,
0x293ad69e, 0x4c9b994d, 0x82596786]
fn test_mixing_function_g() {
mut d := new256() or {
assert false, 'unable to create new 256 bit hash digest: ${err}'
return
}
// set up the message blocks with the value 'abc'
// the firet block will have the 3 bytes of the text to hash
// and the rest of the first block and the other 7 blocks
// will be all zeros. d.m[1..16] should already be zero.
d.m[0] = 0x00636261
// indicate that we have 3 bytes in the message block
d.t += 3
// indicate that the message block contains the end of the
// text being hashed.
f := true
// initialize the working vector from the digest and IV values
mut v := []u32{len: 0, cap: 16}
v << d.h[..8]
v << iv[..8]
// fold in the 64-bit message length
v[12] ^= u32(d.t & 0x00000000ffffffff)
v[13] ^= u32(d.t >> 32)
// and flip the bits in v[14] because this is the end of the
// text being hashed.
if f {
v[14] = ~v[14]
}
for i in 0 .. 16 {
assert v[i] == blake2s.expected_v_initial_results[i], 'expeccted expected_v_initial_results[${i}] ${blake2s.expected_v_initial_results[i]:08x} actual v[${i}] ${v[i]:08x}'
}
for i in 0 .. 16 {
assert d.m[i] == blake2s.expected_m_results[i], 'expeccted expected_m_results[${i}] ${blake2s.expected_m_results[i]:08x} actual d.m[${i}] ${d.m[i]:08x}'
}
for r in 0 .. blake2s.expected_v_results.len {
d.mixing_round(mut v, sigma[r])
for i in 0 .. 16 {
assert v[i] == blake2s.expected_v_results[r][i], 'expeccted expected_v_results[${r}][${i}] ${blake2s.expected_v_results[r][i]:08x} actual v[${i}] ${v[i]:08x}'
}
}
d.h[0] = d.h[0] ^ v[0] ^ v[8]
d.h[1] = d.h[1] ^ v[1] ^ v[9]
d.h[2] = d.h[2] ^ v[2] ^ v[10]
d.h[3] = d.h[3] ^ v[3] ^ v[11]
d.h[4] = d.h[4] ^ v[4] ^ v[12]
d.h[5] = d.h[5] ^ v[5] ^ v[13]
d.h[6] = d.h[6] ^ v[6] ^ v[14]
d.h[7] = d.h[7] ^ v[7] ^ v[15]
for i in 0 .. 8 {
assert d.h[i] == blake2s.expected_h_results[i], 'expeccted expected_h_results[${i}] ${blake2s.expected_h_results[i]:08x} actual d.h[${i}] ${d.h[i]:08x}'
}
}

File diff suppressed because it is too large Load diff

12
vlib/crypto/blake2s/testdata/README vendored Normal file
View file

@ -0,0 +1,12 @@
These test vectors are extracted from
https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2-kat.json
All json objects that contain '"hash": "blake2s"' have been extracted and
saved in blake2s_test_vectors.json.
Using the blake2s.awk program on blake2s_test_vectors.json, we can
generate v code that can initialize an array of TestVector structures.
awk -f blake2s.awk blake2s_test_vectors.json >test_vectors.v
Copy the contents of test_vectors.v into ../blake2s_test.v

View file

@ -0,0 +1,7 @@
/\[/ { print ("const vectors = [") }
/]/ { print ("]") }
/"hash": "blake2s"/ { print ("\tTestVector{") }
/"in":/ { gsub(/"|,/, "", $2); print ("\t\tinput: '" $2 "',") }
/"key":/ { gsub(/"|,/, "", $2); print ("\t\tkey: '" $2 "',") }
/"out":/ { gsub(/"|,/, "", $2); print ("\t\toutput: '" $2 "',") }
/}/ { print (" },") }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,8 @@ import crypto.md5
import crypto.sha1
import crypto.sha256
import crypto.sha512
import crypto.blake2s
import crypto.blake2b
// not yet supported
// import crypto.md4
@ -14,10 +16,7 @@ import crypto.sha512
// import crypto.sha3_256
// import crypto.sha3_384
// import crypto.sha3_512
// import crypto.blake2s_256
// import crypto.blake2b_256
// import crypto.blake2b_384
// import crypto.blake2b_512
const keys = [
[u8(0xb), 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb],
'Jefe'.bytes(),
@ -154,6 +153,142 @@ fn test_hmac_sha512() {
}
}
fn test_hmac_blake2s_256() {
blake2s_256_expected_results := [
'139cd736b926dae4853aab90655120e0305c476fde978166e472c7c8698c21b1',
'90b6281e2f3038c9056af0b4a7e763cae6fe5d9eb4386a0ec95237890c104ff0',
'92394bc2486bea31db01c74be46332edd1499e9700ea41df0670df79fcc0f7c6',
'464434dcbece095d456a1d62d6ec56f898e625a39e5c52bdf94daf111bad83aa',
'97a771b4e4e2fd4d4d0fd8aca2a0663ad8ad4a463cabbf603bf837dd84dec050',
'41202b7be1fd03f84658f4c18a08b43ddbbd73eb012750c8d1ebc8601f1e064c',
'467201ef5997a3442932b318083488cf9aa1d89bef2146154b4816d34863e33d',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2s.sum256, blake2s.block_size).hex()
assert result == blake2s_256_expected_results[i]
}
}
fn test_hmac_blake2s_224() {
blake2s_224_expected_results := [
'c0f46dbc41ffafb1d0caf1756cfb19177c78571d0d187e83f8683b3b',
'c33653634100f77a9359bfc4b3bd40a4a629766fb1da794dbb5cc45b',
'eeff700c648c71f8648077862d2aeb5108e7887adc2aaa2ee25aefab',
'42c6a6688981f6f33c02ceafb0439a496748d45d99fdde22d95313ac',
'fa78ffd75f2cdc6dc1304b874affd069783cfa8e6ae00dcb99de31f7',
'99d1e80dbc842755776ae32309e19020bbb54834c5c7d0c49fee7df2',
'17b9ebb1426a5a3dd6aa91567bd9cb9c19b3dc007adb726e55b98926',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2s.sum224, blake2s.block_size).hex()
assert result == blake2s_224_expected_results[i]
}
}
fn test_hmac_blake2s_160() {
blake2s_160_expected_results := [
'e53d35df4b62a18e0f9f65be35db58ffd84f4cf7',
'8356d437404c027ab98bf581190a96ca83ac7dc0',
'f9631e19deb77bd9ac0761015b7fddfafe14af12',
'63a8d39896fa7c4c5dac8c82ac20c783d7865e0c',
'05db15418a3b7938fcab45bf760a88e842033556',
'580927d927e9279e3f3f95d19b1c79564a0d6326',
'6f3127fcba040fe6ea552b22c39b0fd83abca19a',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2s.sum160, blake2s.block_size).hex()
assert result == blake2s_160_expected_results[i]
}
}
fn test_hmac_blake2s_128() {
blake2s_128_expected_results := [
'78a8c08a89de396ba4a75c543e6415f8',
'5edb7b76d61965470774a215034e8b18',
'77e6870fa0e9dd65751d29204086bed0',
'b43e3298ab9be441dd3cd26c70208b4a',
'43f416bd5d0933b4ad35aeef9c6680a7',
'39c14a9cebb8e2d8d19594783aed29e4',
'96a72e3adf5e0b02d4e6d4e8a7342a77',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2s.sum128, blake2s.block_size).hex()
assert result == blake2s_128_expected_results[i]
}
}
fn test_hmac_blake2b_512() {
blake2b_512_expected_results := [
'be2c398cbd5eef033031f9cee2caba52b280604f4afabf86de21973398c821fd120de5277f08955234182989c68b640af7dfa8cb9228eef4b48ffe768ef595eb',
'6ff884f8ddc2a6586b3c98a4cd6ebdf14ec10204b6710073eb5865ade37a2643b8807c1335d107ecdb9ffeaeb6828c4625ba172c66379efcd222c2de11727ab4',
'548fc7c3d5bd5a0ac74c5fe582037a259c774b81fb791d6c86e675d03b361939e21ea0fb9c6401df22170ebf8017d908675bbcf65911025a1ab5d271a372f43f',
'e5dbb6de2fee42a1caa06e4e7b84ce408ffa5c4a9de2632eca769cde8875014c72d0720feaf53f76e6a180357f528d7bf484fa3a14e8cc1f0f3bada717b43491',
'057f3bcc3511aa9627d96ab2ad02ec3dc86741514d19a3c9b10e539b0ca7c2587d9d04118636a67e18871633ecf8705a3ef6697cf6b64339f71b8cdffab89e34',
'368aba23ca42648157771936b436a0ecb3d83e5fe21e020fef2a08dc9e59739ea919a8d0f46c45b99491f426f1e7c62352d9d67c066571d74e191b69bedaf718',
'f1c9b64e121330c512dc31e0d4a2fc84b7ca5be64e08934a7fc4640c4a1f5cc3c1f34d811c8079cc2df65a4e5d68baf833a1ec558546abeaa7d564840618db7b',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2b.sum512, blake2b.block_size).hex()
assert result == blake2b_512_expected_results[i]
}
}
fn test_hmac_blake2b_384() {
blake2b_384_expected_results := [
'ce5d294bf1a260a93d29d4380fb5b66ebff87bc5b5d97c8889c115848ac0c559ef5b257c7ea1af05e6794e540a07d29a',
'e87f61624bc6c1db706a1efcc98e7e98c0ab8fea0978dbd87e2852406fdd313c87968c5b825847f3c04d975b8b88598d',
'9a24ae99bdddb091e966897c9ed3866d403c8d57bb99288aba05c0586304163ff1917420c746edaa327c99c419249799',
'123edcc587acf610f9f063c8873b94af1ca814e83b65abfd30bcfc4dbc2cc0bc6f1cd8460e5970cc375842bee91f0acb',
'08fb6e2930399c032169428b86c6799284fe3d42ac950698ecf61c08a1b40d7e84627ac578332947f661c2fe2e5f03c9',
'18666044866b52e2d76276a803222cdeb4ee18b41e8a535dca6b14723a7a5031c09463faa88a64d6a5e448220e20e676',
'c9d0155de83454f0720b5310b4b891ddc9ab702b8260b15aa6f7291efec95b7e7a2c986019814b7c28c105c22f0ef961',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2b.sum384, blake2b.block_size).hex()
assert result == blake2b_384_expected_results[i]
}
}
fn test_hmac_blake2b_256() {
blake2b_256_expected_results := [
'1a8becea07bab690945471ff79895bfbec032a3957bc9142a4778811915931ba',
'3cf096eeeb2202a250db168c4823a44ef4618ebabb225789386fed316131e3a0',
'efa4e41fcd8c0f6a568d5d274121095ff9676e6c1eb04fdd679d9c119669d778',
'8cdc727af11f390abd2323aac291c11054ac64352cdd9b5218afcd3e8d6fab45',
'7fe6b268c08631ac118a149b92348e02c640d1804291cc695f89f41ff9aeaee6',
'c093736a225e9f315fc3af8ca018f6e9b0a1c7c9974b116bfa63e2b7faf96a71',
'dce7f41e3db51656ffc97259ca0ef3358cbfb41ac3e74e2dd9cd8639ab4996a0',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2b.sum256, blake2b.block_size).hex()
assert result == blake2b_256_expected_results[i]
}
}
fn test_hmac_blake2b_160() {
blake2b_160_expected_results := [
'5e9e7dc73976e03bbb71ea70d4bebf692c49ecbe',
'c4728ccc2f7600f89d9a480514910b9f5daf3dd6',
'b178e2dfd75d74645c326fac538758d53e305d56',
'253d365a8930b7ff30ae85e862c464b7309056f8',
'a41030927a208f3234251c8ca54731adc58c3c81',
'e8f1b365fd6a63ca64e306901604aa33ea018c8b',
'fc5fb8ec933174d97c7712fa8f8802467ac42b1e',
]
mut result := ''
for i, key in hmac.keys {
result = new(key, hmac.data[i], blake2b.sum160, blake2b.block_size).hex()
assert result == blake2b_160_expected_results[i]
}
}
fn test_hmac_equal() {
mac1_1 := '7641c48a3b4aa8f887c07b3e83f96affb89c978fed8c96fcbbf4ad596eebfe496f9f16da6cd080ba393c6f365ad72b50d15c71bfb1d6b81f66a911786c6ce932'.bytes()
mac1_2 := '7641c48a3b4aa8f887c07b3e83f96affb89c978fed8c96fcbbf4ad596eebfe496f9f16da6cd080ba393c6f365ad72b50d15c71bfb1d6b81f66a911786c6ce932'.bytes()
@ -202,21 +337,3 @@ fn test_hmac_equal() {
// 'eea495d39d9a07154b1266b028e233b9fd84de884ac8f0578e679f095ef14da96d0a355ed4738565884aec755c1b3f5ff09a918b437f6526e17dd8e77f425b95'
// '1488670c683959b5304fa17c172bea81724a249b44981a3eb52cfc66ff0758b7cd1204745131b8adbc714db7fc4550ce26af5f2326067ad1e699f05cae8bb792'
// ]
// blake2b_expected_results := [
// 'be2c398cbd5eef033031f9cee2caba52b280604f4afabf86de21973398c821fd120de5277f08955234182989c68b640af7dfa8cb9228eef4b48ffe768ef595eb'
// '6ff884f8ddc2a6586b3c98a4cd6ebdf14ec10204b6710073eb5865ade37a2643b8807c1335d107ecdb9ffeaeb6828c4625ba172c66379efcd222c2de11727ab4'
// '548fc7c3d5bd5a0ac74c5fe582037a259c774b81fb791d6c86e675d03b361939e21ea0fb9c6401df22170ebf8017d908675bbcf65911025a1ab5d271a372f43f'
// 'e5dbb6de2fee42a1caa06e4e7b84ce408ffa5c4a9de2632eca769cde8875014c72d0720feaf53f76e6a180357f528d7bf484fa3a14e8cc1f0f3bada717b43491'
// '057f3bcc3511aa9627d96ab2ad02ec3dc86741514d19a3c9b10e539b0ca7c2587d9d04118636a67e18871633ecf8705a3ef6697cf6b64339f71b8cdffab89e34'
// '368aba23ca42648157771936b436a0ecb3d83e5fe21e020fef2a08dc9e59739ea919a8d0f46c45b99491f426f1e7c62352d9d67c066571d74e191b69bedaf718'
// 'f1c9b64e121330c512dc31e0d4a2fc84b7ca5be64e08934a7fc4640c4a1f5cc3c1f34d811c8079cc2df65a4e5d68baf833a1ec558546abeaa7d564840618db7b'
// ]
// blake2s_expected_results := [
// '139cd736b926dae4853aab90655120e0305c476fde978166e472c7c8698c21b1'
// '464434dcbece095d456a1d62d6ec56f898e625a39e5c52bdf94daf111bad83aa'
// '90b6281e2f3038c9056af0b4a7e763cae6fe5d9eb4386a0ec95237890c104ff0'
// '92394bc2486bea31db01c74be46332edd1499e9700ea41df0670df79fcc0f7c6'
// '97a771b4e4e2fd4d4d0fd8aca2a0663ad8ad4a463cabbf603bf837dd84dec050'
// '41202b7be1fd03f84658f4c18a08b43ddbbd73eb012750c8d1ebc8601f1e064c'
// '467201ef5997a3442932b318083488cf9aa1d89bef2146154b4816d34863e33d'
// ]