Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+376
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(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(size256, key)!
}
// new224 initializes the digest structure for a Blake2s 224 bit hash
pub fn new224() !&Digest {
return new_digest(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(size224, key)!
}
// new160 initializes the digest structure for a Blake2s 160 bit hash
pub fn new160() !&Digest {
return new_digest(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(size160, key)!
}
// new126 initializes the digest structure for a Blake2s 128 bit hash
pub fn new128() !&Digest {
return new_digest(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(size128, key)!
}
struct HashSizeError {
Error
size u8
}
fn (err HashSizeError) msg() string {
return 'Hash size ${err.size} must be between 1 and ${size256}'
}
struct KeySizeError {
Error
size i32
}
fn (err KeySizeError) msg() string {
return 'Key size ${err.size} must be between 0 and ${size256}'
}
struct InputBufferSizeError {
Error
size i32
}
fn (err InputBufferSizeError) msg() string {
return 'The input buffer size ${err.size} .must be between 0 and ${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 of 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 > size256 {
return HashSizeError{
size: hash_size
}
}
if key.len < 0 || key.len > size256 {
return KeySizeError{
size: i32(key.len)
}
}
mut d := Digest{
h: 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 := 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 > 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 < block_size {
pad_length := 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 >= 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 := 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 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[..block_size]
remaining_data = unsafe { remaining_data[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) }
}
@@ -0,0 +1,79 @@
// 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
@[direct_array_access; inline]
fn g(mut v [16]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
@[direct_array_access; inline]
fn (d Digest) mixing_round(mut v [16]u32, s [16]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
@[direct_array_access]
fn (mut d Digest) f(f bool) {
// initialize the working vector
mut v := [16]u32{}
for i in 0 .. 8 {
v[i] = d.h[i]
v[i + 8] = iv[i]
}
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]
}
@@ -0,0 +1,115 @@
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 15 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 := [16]u32{}
for i in 0 .. 8 {
v[i] = d.h[i]
v[i + 8] = iv[i]
}
// 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] == expected_v_initial_results[i], 'expeccted expected_v_initial_results[${i}] ${expected_v_initial_results[i]:08x} actual v[${i}] ${v[i]:08x}'
}
for i in 0 .. 16 {
assert d.m[i] == expected_m_results[i], 'expeccted expected_m_results[${i}] ${expected_m_results[i]:08x} actual d.m[${i}] ${d.m[i]:08x}'
}
for r in 0 .. expected_v_results.len {
d.mixing_round(mut v, sigma[r])
for i in 0 .. 16 {
assert v[i] == expected_v_results[r][i], 'expeccted expected_v_results[${r}][${i}] ${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] == expected_h_results[i], 'expeccted expected_h_results[${i}] ${expected_h_results[i]:08x} actual d.h[${i}] ${d.h[i]:08x}'
}
}
File diff suppressed because it is too large. Load diff
+7
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