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

+404
View File
@@ -0,0 +1,404 @@
// 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 sha3 implements the 512, 384, 256, and 224
// bit hash algorithms and the 128 and 256 bit
// extended output functions as defined in
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf.
// Last updated: August 2015
module sha3
// size_224 is the size, in bytes, of a sha3 sum224 checksum.
pub const size_224 = 28
// size_256 is the size, in bytes, of a sha3 sum256 checksum.
pub const size_256 = 32
// size_384 is the size, in bytes, of a sha3 sum384 checksum.
pub const size_384 = 48
// size_512 is the size, in bytes, of a sha3 sum512 checksum.
pub const size_512 = 64
// rate_224 is the rate, in bytes, absorbed into the sponge on every permutation
pub const rate_224 = 144
// rate_256 is the rate, in bytes, absorbed into the sponge on every permutation
pub const rate_256 = 136
// rate_384 is the rate, in bytes, absorbed into the sponge on every permutation
pub const rate_384 = 104
// rate_512 is the rate, in bytes, absorbed into the sponge on every permutation
pub const rate_512 = 72
// xof_rate_128 is the capacity, in bytes, of a 128 bit extended output function sponge
pub const xof_rate_128 = 168
// xof_rate_256 is the capacity, in bytes, of a 256 bit extended output function sponge
pub const xof_rate_256 = 136
// new512 initializes the digest structure for a sha3 512 bit hash
pub fn new512() !&Digest {
return new_digest(rate_512, size_512)!
}
// new384 initializes the digest structure for a sha3 384 bit hash
pub fn new384() !&Digest {
return new_digest(rate_384, size_384)!
}
// new256 initializes the digest structure for a sha3 256 bit hash
pub fn new256() !&Digest {
return new_digest(rate_256, size_256)!
}
// new224 initializes the digest structure for a sha3 224 bit hash
pub fn new224() !&Digest {
return new_digest(rate_224, size_224)!
}
// new256keccak initializes the digest structure for a keccak 256 bit hash
pub fn new256keccak() !&Digest {
return new_digest(rate_256, size_256, padding: .keccak)!
}
// new512keccak initializes the digest structure for a keccak 512 bit hash
pub fn new512keccak() !&Digest {
return new_digest(rate_512, size_512, padding: .keccak)!
}
// new256_xof initializes the digest structure for a sha3 256 bit extended output function
pub fn new256xof(output_len int) !&Digest {
return new_xof_digest(xof_rate_256, output_len)!
}
// new128_xof initializes the digest structure for a sha3 128 bit extended output function
pub fn new128xof(output_len int) !&Digest {
return new_xof_digest(xof_rate_128, output_len)!
}
struct HashSizeError {
Error
size int
}
fn (err HashSizeError) msg() string {
return 'Hash size ' + err.size.str() + ' must be ' + size_224.str() + ', ' + size_256.str() +
', ' + size_384.str() + ', or ' + size_512.str()
}
struct AbsorptionRateError {
Error
size int
rate int
}
fn (err AbsorptionRateError) msg() string {
return 'Absorption rate ' + err.rate.str() + ' is not compatible with a hash size of ' +
err.size.str()
}
struct XOFRateError {
Error
rate int
}
fn (err XOFRateError) msg() string {
return 'Extended output rate ' + err.rate.str() + ' must be ' + xof_rate_128.str() + ' or ' +
xof_rate_256.str()
}
struct XOFSizeError {
Error
size int
}
fn (err XOFSizeError) msg() string {
return 'Extended output size ' + err.size.str() + ' must be > 0'
}
struct Digest {
rate int // the number of bytes absorbed per permutation
suffix u8 // the domain suffix, 0x06 for hash, 0x01 for keccak, 0x1f for extended output
output_len int // the number of bytes to output
mut:
input_buffer []u8 // temporary holding buffer for input bytes
s State // the state of a kaccak-p[1600, 24] sponge
}
// the low order pad bits for a hash function
pub enum Padding as u8 {
keccak = 0x01
sha3 = 0x06
xof = 0x1f
}
@[params]
pub struct PaddingConfig {
pub:
padding Padding = .sha3
}
// new_digest creates an initialized digest structure based on
// the hash size.
//
// absorption_rate is the number of bytes to be absorbed into the
// sponge per permutation.
//
// hash_size - the number if bytes in the generated hash.
// Legal values are 224, 256, 384, and 512.
//
// config - the padding setting for hash generation. .sha3 should be used for FIPS PUB 202 compliant SHA3-224, SHA3-256, SHA3-384 and SHA3-512. Use .keccak if you want a legacy Keccak-224, Keccak-256, Keccak-384 or Keccak-512 algorithm. .xof is for extended output functions.
pub fn new_digest(absorption_rate int, hash_size int, config PaddingConfig) !&Digest {
match config.padding {
.sha3, .keccak { validate_sha3(absorption_rate, hash_size)! }
.xof { validate_xof(absorption_rate, hash_size)! }
}
return new_digest_unchecked(absorption_rate, hash_size, config.padding)
}
fn new_digest_unchecked(absorption_rate int, hash_size int, padding Padding) &Digest {
d := Digest{
rate: absorption_rate
suffix: u8(padding)
output_len: hash_size
s: State{}
}
return &d
}
// new_xof_digest creates an initialized digest structure based on
// the absorption rate and how many bytes of output you need
//
// absorption_rate is the number of bytes to be absorbed into the
// sponge per permutation. Legal values are xof_rate_128 and
// xof_rate_256.
//
// hash_size - the number if bytes in the generated hash.
// Legal values are positive integers.
pub fn new_xof_digest(absorption_rate int, hash_size int) !&Digest {
return new_digest(absorption_rate, hash_size, padding: .xof)
}
fn validate_sha3(absorption_rate int, hash_size int) ! {
match hash_size {
size_224 {
if absorption_rate != rate_224 {
return AbsorptionRateError{
rate: absorption_rate
size: hash_size
}
}
}
size_256 {
if absorption_rate != rate_256 {
return AbsorptionRateError{
rate: absorption_rate
size: hash_size
}
}
}
size_384 {
if absorption_rate != rate_384 {
return AbsorptionRateError{
rate: absorption_rate
size: hash_size
}
}
}
size_512 {
if absorption_rate != rate_512 {
return AbsorptionRateError{
rate: absorption_rate
size: hash_size
}
}
}
else {
return HashSizeError{
size: hash_size
}
}
}
}
fn validate_xof(absorption_rate int, hash_size int) ! {
match absorption_rate {
xof_rate_128, xof_rate_256 {
if hash_size < 1 {
return XOFSizeError{
size: hash_size
}
}
}
else {
return XOFRateError{
rate: absorption_rate
}
}
}
}
// write adds bytes to the sponge.
//
// This is the absorption phase of the computation.
pub fn (mut d Digest) write(data []u8) ! {
d.write_bytes(data)
}
fn (mut d Digest) write_bytes(data []u8) {
// if no data is being added to the hash,
// just return
if data.len == 0 {
return
}
// absorb the input into the sponge
mut bytes_remaining := unsafe { data[..] }
if d.input_buffer.len != 0 {
// see if we can accumulate rate bytes to be absorbed
empty_space := d.rate - d.input_buffer.len
if bytes_remaining.len < empty_space {
d.input_buffer << bytes_remaining
// we have not accumulated rate bytes yet.
// just return.
return
} else {
// we have enough bytes to add rate bytes to the
// sponge.
d.input_buffer << bytes_remaining[..empty_space]
bytes_remaining = unsafe { bytes_remaining[empty_space..] }
// absorb them
d.s.xor_bytes(d.input_buffer[..d.rate], d.rate)
d.s.kaccak_p_1600_24()
d.input_buffer = ''.bytes()
}
}
// absorb the remaining bytes
for bytes_remaining.len >= d.rate {
d.s.xor_bytes(bytes_remaining[..d.rate], d.rate)
d.s.kaccak_p_1600_24()
bytes_remaining = unsafe { bytes_remaining[d.rate..] }
}
if bytes_remaining.len > 0 {
d.input_buffer = bytes_remaining.clone()
}
}
// checksum finalizes the hash and returns the generated bytes.
pub fn (mut d Digest) checksum() []u8 {
return d.checksum_internal()
}
fn (mut d Digest) checksum_internal() []u8 {
// pad the last input bytes to have rate bytes
if d.input_buffer.len == d.rate - 1 {
// a single byte pad needs to be handled specially
d.input_buffer << u8(0x80 | d.suffix)
} else {
zero_pads := (d.rate - d.input_buffer.len) - 2
// add the first byte of padding
d.input_buffer << d.suffix
// add intermediate zero pad bytes
for _ in 0 .. zero_pads {
d.input_buffer << u8(0x00)
}
// add the last pad byte
d.input_buffer << u8(0x80)
}
d.s.xor_bytes(d.input_buffer[..d.rate], d.rate)
d.s.kaccak_p_1600_24()
// absorption is done. on to squeezing.
// We know that we can extract rate bytes from the current
// state. If the output_len is <= rate, we don't need to
// iterate and can just return the bytes from the current
// state.
if d.output_len <= d.rate {
return d.s.to_bytes()[..d.output_len]
}
// we need to squeeze the sponge a little harder to get
// longer strings of bytes.
mut output_bytes := []u8{cap: d.output_len}
mut remaining_ouput_len := d.output_len
for remaining_ouput_len > 0 {
mut byte_len_this_round := int_min(remaining_ouput_len, d.rate)
output_bytes << d.s.to_bytes()[..byte_len_this_round]
remaining_ouput_len -= byte_len_this_round
if remaining_ouput_len > 0 {
d.s.kaccak_p_1600_24()
}
}
return output_bytes
}
// sum512 returns the sha3 512 bit checksum of the data.
pub fn sum512(data []u8) []u8 {
mut d := new_digest_unchecked(rate_512, size_512, .sha3)
d.write_bytes(data)
return d.checksum_internal()
}
// sum384 returns the sha3 384 bit checksum of the data.
pub fn sum384(data []u8) []u8 {
mut d := new_digest_unchecked(rate_384, size_384, .sha3)
d.write_bytes(data)
return d.checksum_internal()
}
// sum256 returns the sha3 256 bit checksum of the data.
pub fn sum256(data []u8) []u8 {
mut d := new_digest_unchecked(rate_256, size_256, .sha3)
d.write_bytes(data)
return d.checksum_internal()
}
// sum224 returns the sha3 224 bit checksum of the data.
pub fn sum224(data []u8) []u8 {
mut d := new_digest_unchecked(rate_224, size_224, .sha3)
d.write_bytes(data)
return d.checksum_internal()
}
// keccak256 returns the keccak 256 bit checksum of the data.
pub fn keccak256(data []u8) []u8 {
mut d := new_digest_unchecked(rate_256, size_256, .keccak)
d.write_bytes(data)
return d.checksum_internal()
}
// keccak512 returns the keccak 512 bit checksum of the data.
pub fn keccak512(data []u8) []u8 {
mut d := new_digest_unchecked(rate_512, size_512, .keccak)
d.write_bytes(data)
return d.checksum_internal()
}
// shake256 returns the sha3 shake256 bit extended output
pub fn shake256(data []u8, output_len int) []u8 {
mut d := new256xof(output_len) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal()
}
// shake128 returns the sha3 shake128 bit extended output
pub fn shake128(data []u8, output_len int) []u8 {
mut d := new128xof(output_len) or { panic(err) }
d.write(data) or { panic(err) }
return d.checksum_internal()
}
@@ -0,0 +1,197 @@
// 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 sha3 implements the 512, 384, 256, and 224
// bit hash algorithms and the 128 and 256 bit
// extended output functions as defined in
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf.
// Last updated: August 2015
module sha3
import math.bits
// when the state is 1600 bits, a lane is 64 bits
type Lane = u64
// the state is a 5 x 5 array of lanes
struct State {
mut:
a [5][5]Lane
}
@[direct_array_access; inline]
fn read_u64_le_at(b []u8, offset int) u64 {
_ = b[offset]
_ = b[offset + 7]
return u64(b[offset]) | (u64(b[offset + 1]) << 8) | (u64(b[offset + 2]) << 16) | (u64(b[
offset + 3]) << 24) | (u64(b[offset + 4]) << 32) | (u64(b[offset + 5]) << 40) | (u64(b[
offset + 6]) << 48) | (u64(b[offset + 7]) << 56)
}
@[direct_array_access; inline]
fn put_u64_le_at(mut b []u8, value u64, offset int) {
_ = b[offset]
_ = b[offset + 7]
b[offset] = u8(value)
b[offset + 1] = u8(value >> 8)
b[offset + 2] = u8(value >> 16)
b[offset + 3] = u8(value >> 24)
b[offset + 4] = u8(value >> 32)
b[offset + 5] = u8(value >> 40)
b[offset + 6] = u8(value >> 48)
b[offset + 7] = u8(value >> 56)
}
// to_bytes converts the state into a byte array
//
// A 1600 bit state fits into 200 bytes.
//
// The state consists of 25 u64 values arranged in a
// 5 x 5 array.
//
// The state is not modified by this method.
@[direct_array_access]
fn (s State) to_bytes() []u8 {
mut byte_array := []u8{len: 200}
mut index := 0
for y in 0 .. 5 {
for x in 0 .. 5 {
put_u64_le_at(mut byte_array, s.a[x][y], index)
index += 8
}
}
return byte_array
}
// from_bytes sets the state from an array of bytes
//
// A 1600 bit state fits into 200 bytes. It is expected
// that the input byte array is 200 bytes long.
//
// All 25 u64 values are set from the input byte array.
@[direct_array_access]
fn (mut s State) from_bytes(byte_array []u8) {
mut index := 0
for y in 0 .. 5 {
for x in 0 .. 5 {
s.a[x][y] = read_u64_le_at(byte_array, index)
index += 8
}
}
}
// xor_bytes xor's an array of bytes into the state
//
// This is how new data gets absorbed into the sponge.
//
// It is expected that the length of the byte array is
// the same as the rate. The rate is how many bytes
// can be absorbed at one permutation of the state.
//
// The rate must be less than the size of the state
// in bytes.
@[direct_array_access]
fn (mut s State) xor_bytes(byte_array []u8, rate int) {
mut index := 0
for y in 0 .. 5 {
for x in 0 .. 5 {
s.a[x][y] ^= read_u64_le_at(byte_array, index)
index += 8
if index >= rate {
return
}
}
}
}
// kaccak_p_1600_24 performs 24 rounnds on a 1600 bit state.
//
@[direct_array_access]
fn (mut s State) kaccak_p_1600_24() {
mut b := [5][5]Lane{}
for round_index in 0 .. 24 {
// theta
// C[x] = A[x,0] xor A[x,1] xor A[x,2] xor A[x,3] xor A[x,4], for x in 0…4
// D[x] = C[x-1] xor rot(C[x+1],1), for x in 0…4
// A[x,y] = A[x,y] xor D[x], for (x,y) in (0…4,0…4)
c0 := s.a[0][0] ^ s.a[0][1] ^ s.a[0][2] ^ s.a[0][3] ^ s.a[0][4]
c1 := s.a[1][0] ^ s.a[1][1] ^ s.a[1][2] ^ s.a[1][3] ^ s.a[1][4]
c2 := s.a[2][0] ^ s.a[2][1] ^ s.a[2][2] ^ s.a[2][3] ^ s.a[2][4]
c3 := s.a[3][0] ^ s.a[3][1] ^ s.a[3][2] ^ s.a[3][3] ^ s.a[3][4]
c4 := s.a[4][0] ^ s.a[4][1] ^ s.a[4][2] ^ s.a[4][3] ^ s.a[4][4]
d0 := c4 ^ bits.rotate_left_64(c1, 1)
d1 := c0 ^ bits.rotate_left_64(c2, 1)
d2 := c1 ^ bits.rotate_left_64(c3, 1)
d3 := c2 ^ bits.rotate_left_64(c4, 1)
d4 := c3 ^ bits.rotate_left_64(c0, 1)
// vfmt off
s.a[0][0] ^= d0 s.a[0][1] ^= d0 s.a[0][2] ^= d0 s.a[0][3] ^= d0 s.a[0][4] ^= d0
s.a[1][0] ^= d1 s.a[1][1] ^= d1 s.a[1][2] ^= d1 s.a[1][3] ^= d1 s.a[1][4] ^= d1
s.a[2][0] ^= d2 s.a[2][1] ^= d2 s.a[2][2] ^= d2 s.a[2][3] ^= d2 s.a[2][4] ^= d2
s.a[3][0] ^= d3 s.a[3][1] ^= d3 s.a[3][2] ^= d3 s.a[3][3] ^= d3 s.a[3][4] ^= d3
s.a[4][0] ^= d4 s.a[4][1] ^= d4 s.a[4][2] ^= d4 s.a[4][3] ^= d4 s.a[4][4] ^= d4
// vfmt on
// rho and pi
// B[y,2*x+3*y] = rot(A[x,y], r[x,y]), for (x,y) in (0…4,0…4)
b[0][0] = s.a[0][0]
b[0][1] = bits.rotate_left_64(s.a[3][0], 28)
b[0][2] = bits.rotate_left_64(s.a[1][0], 1)
b[0][3] = bits.rotate_left_64(s.a[4][0], 27)
b[0][4] = bits.rotate_left_64(s.a[2][0], 62)
b[1][0] = bits.rotate_left_64(s.a[1][1], 44)
b[1][1] = bits.rotate_left_64(s.a[4][1], 20)
b[1][2] = bits.rotate_left_64(s.a[2][1], 6)
b[1][3] = bits.rotate_left_64(s.a[0][1], 36)
b[1][4] = bits.rotate_left_64(s.a[3][1], 55)
b[2][0] = bits.rotate_left_64(s.a[2][2], 43)
b[2][1] = bits.rotate_left_64(s.a[0][2], 3)
b[2][2] = bits.rotate_left_64(s.a[3][2], 25)
b[2][3] = bits.rotate_left_64(s.a[1][2], 10)
b[2][4] = bits.rotate_left_64(s.a[4][2], 39)
b[3][0] = bits.rotate_left_64(s.a[3][3], 21)
b[3][1] = bits.rotate_left_64(s.a[1][3], 45)
b[3][2] = bits.rotate_left_64(s.a[4][3], 8)
b[3][3] = bits.rotate_left_64(s.a[2][3], 15)
b[3][4] = bits.rotate_left_64(s.a[0][3], 41)
b[4][0] = bits.rotate_left_64(s.a[4][4], 14)
b[4][1] = bits.rotate_left_64(s.a[2][4], 61)
b[4][2] = bits.rotate_left_64(s.a[0][4], 18)
b[4][3] = bits.rotate_left_64(s.a[3][4], 56)
b[4][4] = bits.rotate_left_64(s.a[1][4], 2)
// chi
// A[x,y] = B[x,y] xor ((not B[x+1,y]) and B[x+2,y]), for (x,y) in (0…4,0…4)
for y in 0 .. 5 {
s.a[0][y] = b[0][y] ^ (~b[1][y] & b[2][y])
s.a[1][y] = b[1][y] ^ (~b[2][y] & b[3][y])
s.a[2][y] = b[2][y] ^ (~b[3][y] & b[4][y])
s.a[3][y] = b[3][y] ^ (~b[4][y] & b[0][y])
s.a[4][y] = b[4][y] ^ (~b[0][y] & b[1][y])
}
// iota
// A[0,0] = A[0,0] xor RC
s.a[0][0] ^= iota_round_constants[round_index]
}
}
// iota_round_constants are precomputed xor masks for the iota function
const iota_round_constants = [u64(0x0000000000000001), 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081,
0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009,
0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a,
0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001,
0x8000000080008008]
@@ -0,0 +1,28 @@
module sha3
fn test_round_constants() {
assert iota_round_constants[0] == 0x0000000000000001
assert iota_round_constants[1] == 0x0000000000008082
assert iota_round_constants[2] == 0x800000000000808A
assert iota_round_constants[3] == 0x8000000080008000
assert iota_round_constants[4] == 0x000000000000808B
assert iota_round_constants[5] == 0x0000000080000001
assert iota_round_constants[6] == 0x8000000080008081
assert iota_round_constants[7] == 0x8000000000008009
assert iota_round_constants[8] == 0x000000000000008A
assert iota_round_constants[9] == 0x0000000000000088
assert iota_round_constants[10] == 0x0000000080008009
assert iota_round_constants[11] == 0x000000008000000A
assert iota_round_constants[12] == 0x000000008000808B
assert iota_round_constants[13] == 0x800000000000008B
assert iota_round_constants[14] == 0x8000000000008089
assert iota_round_constants[15] == 0x8000000000008003
assert iota_round_constants[16] == 0x8000000000008002
assert iota_round_constants[17] == 0x8000000000000080
assert iota_round_constants[18] == 0x000000000000800A
assert iota_round_constants[19] == 0x800000008000000A
assert iota_round_constants[20] == 0x8000000080008081
assert iota_round_constants[21] == 0x8000000000008080
assert iota_round_constants[22] == 0x0000000080000001
assert iota_round_constants[23] == 0x8000000080008008
}
+267
View File
@@ -0,0 +1,267 @@
module sha3
const empty_message_sha3_224 = [u8(0x6B), 0x4E, 0x03, 0x42, 0x36, 0x67, 0xDB, 0xB7, 0x3B, 0x6E,
0x15, 0x45, 0x4F, 0x0E, 0xB1, 0xAB, 0xD4, 0x59, 0x7F, 0x9A, 0x1B, 0x07, 0x8E, 0x3F, 0x5B, 0x5A,
0x6B, 0xC7]
const empty_message_sha3_256 = [u8(0xA7), 0xFF, 0xC6, 0xF8, 0xBF, 0x1E, 0xD7, 0x66, 0x51, 0xC1,
0x47, 0x56, 0xA0, 0x61, 0xD6, 0x62, 0xF5, 0x80, 0xFF, 0x4D, 0xE4, 0x3B, 0x49, 0xFA, 0x82, 0xD8,
0x0A, 0x4B, 0x80, 0xF8, 0x43, 0x4A]
const empty_message_sha3_384 = [u8(0x0C), 0x63, 0xA7, 0x5B, 0x84, 0x5E, 0x4F, 0x7D, 0x01, 0x10,
0x7D, 0x85, 0x2E, 0x4C, 0x24, 0x85, 0xC5, 0x1A, 0x50, 0xAA, 0xAA, 0x94, 0xFC, 0x61, 0x99, 0x5E,
0x71, 0xBB, 0xEE, 0x98, 0x3A, 0x2A, 0xC3, 0x71, 0x38, 0x31, 0x26, 0x4A, 0xDB, 0x47, 0xFB, 0x6B,
0xD1, 0xE0, 0x58, 0xD5, 0xF0, 0x04]
const empty_message_sha3_512 = [u8(0xA6), 0x9F, 0x73, 0xCC, 0xA2, 0x3A, 0x9A, 0xC5, 0xC8, 0xB5,
0x67, 0xDC, 0x18, 0x5A, 0x75, 0x6E, 0x97, 0xC9, 0x82, 0x16, 0x4F, 0xE2, 0x58, 0x59, 0xE0, 0xD1,
0xDC, 0xC1, 0x47, 0x5C, 0x80, 0xA6, 0x15, 0xB2, 0x12, 0x3A, 0xF1, 0xF5, 0xF9, 0x4C, 0x11, 0xE3,
0xE9, 0x40, 0x2C, 0x3A, 0xC5, 0x58, 0xF5, 0x00, 0x19, 0x9D, 0x95, 0xB6, 0xD3, 0xE3, 0x01, 0x75,
0x85, 0x86, 0x28, 0x1D, 0xCD, 0x26]
const empty_message_keccak_256 = [u8(0xC5), 0xD2, 0x46, 0x01, 0x86, 0xF7, 0x23, 0x3C, 0x92, 0x7E,
0x7D, 0xB2, 0xDC, 0xC7, 0x03, 0xC0, 0xE5, 0x00, 0xB6, 0x53, 0xCA, 0x82, 0x27, 0x3B, 0x7B, 0xFA,
0xD8, 0x04, 0x5D, 0x85, 0xA4, 0x70]
const empty_message_keccak_512 = [u8(0x0E), 0xAB, 0x42, 0xDE, 0x4C, 0x3C, 0xEB, 0x92, 0x35, 0xFC,
0x91, 0xAC, 0xFF, 0xE7, 0x46, 0xB2, 0x9C, 0x29, 0xA8, 0xC3, 0x66, 0xB7, 0xC6, 0x0E, 0x4E, 0x67,
0xC4, 0x66, 0xF3, 0x6A, 0x43, 0x04, 0xC0, 0x0F, 0xA9, 0xCA, 0xF9, 0xD8, 0x79, 0x76, 0xBA, 0x46,
0x9B, 0xCB, 0xE0, 0x67, 0x13, 0xB4, 0x35, 0xF0, 0x91, 0xEF, 0x27, 0x69, 0xFB, 0x16, 0x0C, 0xDA,
0xB3, 0x3D, 0x36, 0x70, 0x68, 0x0E]
fn test_0_length_hash() {
input := []u8{}
output_224 := sum224(input)
assert output_224 == empty_message_sha3_224
output_256 := sum256(input)
assert output_256 == empty_message_sha3_256
output_384 := sum384(input)
assert output_384 == empty_message_sha3_384
output_512 := sum512(input)
assert output_512 == empty_message_sha3_512
output_keccak_256 := keccak256(input)
assert output_keccak_256 == empty_message_keccak_256
output_keccak_512 := keccak512(input)
assert output_keccak_512 == empty_message_keccak_512
}
const input_200 = [u8(0xa3), 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3]
const test_200_message_sha3_224 = [u8(0x93), 0x76, 0x81, 0x6A, 0xBA, 0x50, 0x3F, 0x72, 0xF9, 0x6C,
0xE7, 0xEB, 0x65, 0xAC, 0x09, 0x5D, 0xEE, 0xE3, 0xBE, 0x4B, 0xF9, 0xBB, 0xC2, 0xA1, 0xCB, 0x7E,
0x11, 0xE0]
const test_200_message_sha3_256 = [u8(0x79), 0xF3, 0x8A, 0xDE, 0xC5, 0xC2, 0x03, 0x07, 0xA9, 0x8E,
0xF7, 0x6E, 0x83, 0x24, 0xAF, 0xBF, 0xD4, 0x6C, 0xFD, 0x81, 0xB2, 0x2E, 0x39, 0x73, 0xC6, 0x5F,
0xA1, 0xBD, 0x9D, 0xE3, 0x17, 0x87]
const test_200_message_sha3_384 = [u8(0x18), 0x81, 0xDE, 0x2C, 0xA7, 0xE4, 0x1E, 0xF9, 0x5D, 0xC4,
0x73, 0x2B, 0x8F, 0x5F, 0x00, 0x2B, 0x18, 0x9C, 0xC1, 0xE4, 0x2B, 0x74, 0x16, 0x8E, 0xD1, 0x73,
0x26, 0x49, 0xCE, 0x1D, 0xBC, 0xDD, 0x76, 0x19, 0x7A, 0x31, 0xFD, 0x55, 0xEE, 0x98, 0x9F, 0x2D,
0x70, 0x50, 0xDD, 0x47, 0x3E, 0x8F]
const test_200_message_sha3_512 = [u8(0xE7), 0x6D, 0xFA, 0xD2, 0x20, 0x84, 0xA8, 0xB1, 0x46, 0x7F,
0xCF, 0x2F, 0xFA, 0x58, 0x36, 0x1B, 0xEC, 0x76, 0x28, 0xED, 0xF5, 0xF3, 0xFD, 0xC0, 0xE4, 0x80,
0x5D, 0xC4, 0x8C, 0xAE, 0xEC, 0xA8, 0x1B, 0x7C, 0x13, 0xC3, 0x0A, 0xDF, 0x52, 0xA3, 0x65, 0x95,
0x84, 0x73, 0x9A, 0x2D, 0xF4, 0x6B, 0xE5, 0x89, 0xC5, 0x1C, 0xA1, 0xA4, 0xA8, 0x41, 0x6D, 0xF6,
0x54, 0x5A, 0x1C, 0xE8, 0xBA, 0x00]
// The values are taken from the output of Go's sha3 library
const test_200_message_keccak_256 = [u8(0x3A), 0x57, 0x66, 0x6B, 0x04, 0x87, 0x77, 0xF2, 0xC9,
0x53, 0xDC, 0x44, 0x56, 0xF4, 0x5A, 0x25, 0x88, 0xE1, 0xCB, 0x6F, 0x2D, 0xA7, 0x60, 0x12, 0x2D,
0x53, 0x0A, 0xC2, 0xCE, 0x60, 0x7D, 0x4A]
const test_200_message_keccak_512 = [u8(0xF4), 0xF8, 0x46, 0xD1, 0x40, 0x84, 0x75, 0x39, 0xF5,
0x3C, 0x3F, 0x08, 0x2C, 0xC4, 0xE6, 0x81, 0x0E, 0x14, 0x3A, 0x5B, 0x4F, 0xC6, 0x2A, 0x20, 0x59,
0x7B, 0x5D, 0x76, 0x04, 0x32, 0x46, 0xB8, 0x6B, 0xD7, 0x14, 0x9B, 0x90, 0x61, 0x40, 0xBB, 0x96,
0x65, 0xA6, 0xCE, 0x83, 0xD9, 0x91, 0xF0, 0x32, 0xF2, 0x29, 0x1D, 0x2F, 0xAE, 0x80, 0xEE, 0xDF,
0xC6, 0xF8, 0x45, 0xCC, 0x16, 0xD5, 0xAE]
fn test_200_length_hash() {
output_224 := sum224(input_200)
assert output_224 == test_200_message_sha3_224
output_256 := sum256(input_200)
assert output_256 == test_200_message_sha3_256
output_384 := sum384(input_200)
assert output_384 == test_200_message_sha3_384
output_512 := sum512(input_200)
assert output_512 == test_200_message_sha3_512
output_keccak_256 := keccak256(input_200)
assert output_keccak_256 == test_200_message_keccak_256
output_keccak_512 := keccak512(input_200)
assert output_keccak_512 == test_200_message_keccak_512
}
const empty_message_shake128 = [u8(0x7F), 0x9C, 0x2B, 0xA4, 0xE8, 0x8F, 0x82, 0x7D, 0x61, 0x60,
0x45, 0x50, 0x76, 0x05, 0x85, 0x3E, 0xD7, 0x3B, 0x80, 0x93, 0xF6, 0xEF, 0xBC, 0x88, 0xEB, 0x1A,
0x6E, 0xAC, 0xFA, 0x66, 0xEF, 0x26, 0x3C, 0xB1, 0xEE, 0xA9, 0x88, 0x00, 0x4B, 0x93, 0x10, 0x3C,
0xFB, 0x0A, 0xEE, 0xFD, 0x2A, 0x68, 0x6E, 0x01, 0xFA, 0x4A, 0x58, 0xE8, 0xA3, 0x63, 0x9C, 0xA8,
0xA1, 0xE3, 0xF9, 0xAE, 0x57, 0xE2, 0x35, 0xB8, 0xCC, 0x87, 0x3C, 0x23, 0xDC, 0x62, 0xB8, 0xD2,
0x60, 0x16, 0x9A, 0xFA, 0x2F, 0x75, 0xAB, 0x91, 0x6A, 0x58, 0xD9, 0x74, 0x91, 0x88, 0x35, 0xD2,
0x5E, 0x6A, 0x43, 0x50, 0x85, 0xB2, 0xBA, 0xDF, 0xD6, 0xDF, 0xAA, 0xC3, 0x59, 0xA5, 0xEF, 0xBB,
0x7B, 0xCC, 0x4B, 0x59, 0xD5, 0x38, 0xDF, 0x9A, 0x04, 0x30, 0x2E, 0x10, 0xC8, 0xBC, 0x1C, 0xBF,
0x1A, 0x0B, 0x3A, 0x51, 0x20, 0xEA, 0x17, 0xCD, 0xA7, 0xCF, 0xAD, 0x76, 0x5F, 0x56, 0x23, 0x47,
0x4D, 0x36, 0x8C, 0xCC, 0xA8, 0xAF, 0x00, 0x07, 0xCD, 0x9F, 0x5E, 0x4C, 0x84, 0x9F, 0x16, 0x7A,
0x58, 0x0B, 0x14, 0xAA, 0xBD, 0xEF, 0xAE, 0xE7, 0xEE, 0xF4, 0x7C, 0xB0, 0xFC, 0xA9, 0x76, 0x7B,
0xE1, 0xFD, 0xA6, 0x94, 0x19, 0xDF, 0xB9, 0x27, 0xE9, 0xDF, 0x07, 0x34, 0x8B, 0x19, 0x66, 0x91,
0xAB, 0xAE, 0xB5, 0x80, 0xB3, 0x2D, 0xEF, 0x58, 0x53, 0x8B, 0x8D, 0x23, 0xF8, 0x77, 0x32, 0xEA,
0x63, 0xB0, 0x2B, 0x4F, 0xA0, 0xF4, 0x87, 0x33, 0x60, 0xE2, 0x84, 0x19, 0x28, 0xCD, 0x60, 0xDD,
0x4C, 0xEE, 0x8C, 0xC0, 0xD4, 0xC9, 0x22, 0xA9, 0x61, 0x88, 0xD0, 0x32, 0x67, 0x5C, 0x8A, 0xC8,
0x50, 0x93, 0x3C, 0x7A, 0xFF, 0x15, 0x33, 0xB9, 0x4C, 0x83, 0x4A, 0xDB, 0xB6, 0x9C, 0x61, 0x15,
0xBA, 0xD4, 0x69, 0x2D, 0x86, 0x19, 0xF9, 0x0B, 0x0C, 0xDF, 0x8A, 0x7B, 0x9C, 0x26, 0x40, 0x29,
0xAC, 0x18, 0x5B, 0x70, 0xB8, 0x3F, 0x28, 0x01, 0xF2, 0xF4, 0xB3, 0xF7, 0x0C, 0x59, 0x3E, 0xA3,
0xAE, 0xEB, 0x61, 0x3A, 0x7F, 0x1B, 0x1D, 0xE3, 0x3F, 0xD7, 0x50, 0x81, 0xF5, 0x92, 0x30, 0x5F,
0x2E, 0x45, 0x26, 0xED, 0xC0, 0x96, 0x31, 0xB1, 0x09, 0x58, 0xF4, 0x64, 0xD8, 0x89, 0xF3, 0x1B,
0xA0, 0x10, 0x25, 0x0F, 0xDA, 0x7F, 0x13, 0x68, 0xEC, 0x29, 0x67, 0xFC, 0x84, 0xEF, 0x2A, 0xE9,
0xAF, 0xF2, 0x68, 0xE0, 0xB1, 0x70, 0x0A, 0xFF, 0xC6, 0x82, 0x0B, 0x52, 0x3A, 0x3D, 0x91, 0x71,
0x35, 0xF2, 0xDF, 0xF2, 0xEE, 0x06, 0xBF, 0xE7, 0x2B, 0x31, 0x24, 0x72, 0x1D, 0x4A, 0x26, 0xC0,
0x4E, 0x53, 0xA7, 0x5E, 0x30, 0xE7, 0x3A, 0x7A, 0x9C, 0x4A, 0x95, 0xD9, 0x1C, 0x55, 0xD4, 0x95,
0xE9, 0xF5, 0x1D, 0xD0, 0xB5, 0xE9, 0xD8, 0x3C, 0x6D, 0x5E, 0x8C, 0xE8, 0x03, 0xAA, 0x62, 0xB8,
0xD6, 0x54, 0xDB, 0x53, 0xD0, 0x9B, 0x8D, 0xCF, 0xF2, 0x73, 0xCD, 0xFE, 0xB5, 0x73, 0xFA, 0xD8,
0xBC, 0xD4, 0x55, 0x78, 0xBE, 0xC2, 0xE7, 0x70, 0xD0, 0x1E, 0xFD, 0xE8, 0x6E, 0x72, 0x1A, 0x3F,
0x7C, 0x6C, 0xCE, 0x27, 0x5D, 0xAB, 0xE6, 0xE2, 0x14, 0x3F, 0x1A, 0xF1, 0x8D, 0xA7, 0xEF, 0xDD,
0xC4, 0xC7, 0xB7, 0x0B, 0x5E, 0x34, 0x5D, 0xB9, 0x3C, 0xC9, 0x36, 0xBE, 0xA3, 0x23, 0x49, 0x1C,
0xCB, 0x38, 0xA3, 0x88, 0xF5, 0x46, 0xA9, 0xFF, 0x00, 0xDD, 0x4E, 0x13, 0x00, 0xB9, 0xB2, 0x15,
0x3D, 0x20, 0x41, 0xD2, 0x05, 0xB4, 0x43, 0xE4, 0x1B, 0x45, 0xA6, 0x53, 0xF2, 0xA5, 0xC4, 0x49,
0x2C, 0x1A, 0xDD, 0x54, 0x45, 0x12, 0xDD, 0xA2, 0x52, 0x98, 0x33, 0x46, 0x2B, 0x71, 0xA4, 0x1A,
0x45, 0xBE, 0x97, 0x29, 0x0B, 0x6F]
const empty_message_shake256 = [u8(0x46), 0xB9, 0xDD, 0x2B, 0x0B, 0xA8, 0x8D, 0x13, 0x23, 0x3B,
0x3F, 0xEB, 0x74, 0x3E, 0xEB, 0x24, 0x3F, 0xCD, 0x52, 0xEA, 0x62, 0xB8, 0x1B, 0x82, 0xB5, 0x0C,
0x27, 0x64, 0x6E, 0xD5, 0x76, 0x2F, 0xD7, 0x5D, 0xC4, 0xDD, 0xD8, 0xC0, 0xF2, 0x00, 0xCB, 0x05,
0x01, 0x9D, 0x67, 0xB5, 0x92, 0xF6, 0xFC, 0x82, 0x1C, 0x49, 0x47, 0x9A, 0xB4, 0x86, 0x40, 0x29,
0x2E, 0xAC, 0xB3, 0xB7, 0xC4, 0xBE, 0x14, 0x1E, 0x96, 0x61, 0x6F, 0xB1, 0x39, 0x57, 0x69, 0x2C,
0xC7, 0xED, 0xD0, 0xB4, 0x5A, 0xE3, 0xDC, 0x07, 0x22, 0x3C, 0x8E, 0x92, 0x93, 0x7B, 0xEF, 0x84,
0xBC, 0x0E, 0xAB, 0x86, 0x28, 0x53, 0x34, 0x9E, 0xC7, 0x55, 0x46, 0xF5, 0x8F, 0xB7, 0xC2, 0x77,
0x5C, 0x38, 0x46, 0x2C, 0x50, 0x10, 0xD8, 0x46, 0xC1, 0x85, 0xC1, 0x51, 0x11, 0xE5, 0x95, 0x52,
0x2A, 0x6B, 0xCD, 0x16, 0xCF, 0x86, 0xF3, 0xD1, 0x22, 0x10, 0x9E, 0x3B, 0x1F, 0xDD, 0x94, 0x3B,
0x6A, 0xEC, 0x46, 0x8A, 0x2D, 0x62, 0x1A, 0x7C, 0x06, 0xC6, 0xA9, 0x57, 0xC6, 0x2B, 0x54, 0xDA,
0xFC, 0x3B, 0xE8, 0x75, 0x67, 0xD6, 0x77, 0x23, 0x13, 0x95, 0xF6, 0x14, 0x72, 0x93, 0xB6, 0x8C,
0xEA, 0xB7, 0xA9, 0xE0, 0xC5, 0x8D, 0x86, 0x4E, 0x8E, 0xFD, 0xE4, 0xE1, 0xB9, 0xA4, 0x6C, 0xBE,
0x85, 0x47, 0x13, 0x67, 0x2F, 0x5C, 0xAA, 0xAE, 0x31, 0x4E, 0xD9, 0x08, 0x3D, 0xAB, 0x4B, 0x09,
0x9F, 0x8E, 0x30, 0x0F, 0x01, 0xB8, 0x65, 0x0F, 0x1F, 0x4B, 0x1D, 0x8F, 0xCF, 0x3F, 0x3C, 0xB5,
0x3F, 0xB8, 0xE9, 0xEB, 0x2E, 0xA2, 0x03, 0xBD, 0xC9, 0x70, 0xF5, 0x0A, 0xE5, 0x54, 0x28, 0xA9,
0x1F, 0x7F, 0x53, 0xAC, 0x26, 0x6B, 0x28, 0x41, 0x9C, 0x37, 0x78, 0xA1, 0x5F, 0xD2, 0x48, 0xD3,
0x39, 0xED, 0xE7, 0x85, 0xFB, 0x7F, 0x5A, 0x1A, 0xAA, 0x96, 0xD3, 0x13, 0xEA, 0xCC, 0x89, 0x09,
0x36, 0xC1, 0x73, 0xCD, 0xCD, 0x0F, 0xAB, 0x88, 0x2C, 0x45, 0x75, 0x5F, 0xEB, 0x3A, 0xED, 0x96,
0xD4, 0x77, 0xFF, 0x96, 0x39, 0x0B, 0xF9, 0xA6, 0x6D, 0x13, 0x68, 0xB2, 0x08, 0xE2, 0x1F, 0x7C,
0x10, 0xD0, 0x4A, 0x3D, 0xBD, 0x4E, 0x36, 0x06, 0x33, 0xE5, 0xDB, 0x4B, 0x60, 0x26, 0x01, 0xC1,
0x4C, 0xEA, 0x73, 0x7D, 0xB3, 0xDC, 0xF7, 0x22, 0x63, 0x2C, 0xC7, 0x78, 0x51, 0xCB, 0xDD, 0xE2,
0xAA, 0xF0, 0xA3, 0x3A, 0x07, 0xB3, 0x73, 0x44, 0x5D, 0xF4, 0x90, 0xCC, 0x8F, 0xC1, 0xE4, 0x16,
0x0F, 0xF1, 0x18, 0x37, 0x8F, 0x11, 0xF0, 0x47, 0x7D, 0xE0, 0x55, 0xA8, 0x1A, 0x9E, 0xDA, 0x57,
0xA4, 0xA2, 0xCF, 0xB0, 0xC8, 0x39, 0x29, 0xD3, 0x10, 0x91, 0x2F, 0x72, 0x9E, 0xC6, 0xCF, 0xA3,
0x6C, 0x6A, 0xC6, 0xA7, 0x58, 0x37, 0x14, 0x30, 0x45, 0xD7, 0x91, 0xCC, 0x85, 0xEF, 0xF5, 0xB2,
0x19, 0x32, 0xF2, 0x38, 0x61, 0xBC, 0xF2, 0x3A, 0x52, 0xB5, 0xDA, 0x67, 0xEA, 0xF7, 0xBA, 0xAE,
0x0F, 0x5F, 0xB1, 0x36, 0x9D, 0xB7, 0x8F, 0x3A, 0xC4, 0x5F, 0x8C, 0x4A, 0xC5, 0x67, 0x1D, 0x85,
0x73, 0x5C, 0xDD, 0xDB, 0x09, 0xD2, 0xB1, 0xE3, 0x4A, 0x1F, 0xC0, 0x66, 0xFF, 0x4A, 0x16, 0x2C,
0xB2, 0x63, 0xD6, 0x54, 0x12, 0x74, 0xAE, 0x2F, 0xCC, 0x86, 0x5F, 0x61, 0x8A, 0xBE, 0x27, 0xC1,
0x24, 0xCD, 0x8B, 0x07, 0x4C, 0xCD, 0x51, 0x63, 0x01, 0xB9, 0x18, 0x75, 0x82, 0x4D, 0x09, 0x95,
0x8F, 0x34, 0x1E, 0xF2, 0x74, 0xBD, 0xAB, 0x0B, 0xAE, 0x31, 0x63, 0x39, 0x89, 0x43, 0x04, 0xE3,
0x58, 0x77, 0xB0, 0xC2, 0x8A, 0x9B, 0x1F, 0xD1, 0x66, 0xC7, 0x96, 0xB9, 0xCC, 0x25, 0x8A, 0x06,
0x4A, 0x8F, 0x57, 0xE2, 0x7F, 0x2A]
fn test_0_length_xof() {
input := []u8{}
output_128 := shake128(input, 512)
assert output_128 == empty_message_shake128
output_256 := shake256(input, 512)
assert output_256 == empty_message_shake256
}
const test_200_message_shake128 = [u8(0x13), 0x1A, 0xB8, 0xD2, 0xB5, 0x94, 0x94, 0x6B, 0x9C, 0x81,
0x33, 0x3F, 0x9B, 0xB6, 0xE0, 0xCE, 0x75, 0xC3, 0xB9, 0x31, 0x04, 0xFA, 0x34, 0x69, 0xD3, 0x91,
0x74, 0x57, 0x38, 0x5D, 0xA0, 0x37, 0xCF, 0x23, 0x2E, 0xF7, 0x16, 0x4A, 0x6D, 0x1E, 0xB4, 0x48,
0xC8, 0x90, 0x81, 0x86, 0xAD, 0x85, 0x2D, 0x3F, 0x85, 0xA5, 0xCF, 0x28, 0xDA, 0x1A, 0xB6, 0xFE,
0x34, 0x38, 0x17, 0x19, 0x78, 0x46, 0x7F, 0x1C, 0x05, 0xD5, 0x8C, 0x7E, 0xF3, 0x8C, 0x28, 0x4C,
0x41, 0xF6, 0xC2, 0x22, 0x1A, 0x76, 0xF1, 0x2A, 0xB1, 0xC0, 0x40, 0x82, 0x66, 0x02, 0x50, 0x80,
0x22, 0x94, 0xFB, 0x87, 0x18, 0x02, 0x13, 0xFD, 0xEF, 0x5B, 0x0E, 0xCB, 0x7D, 0xF5, 0x0C, 0xA1,
0xF8, 0x55, 0x5B, 0xE1, 0x4D, 0x32, 0xE1, 0x0F, 0x6E, 0xDC, 0xDE, 0x89, 0x2C, 0x09, 0x42, 0x4B,
0x29, 0xF5, 0x97, 0xAF, 0xC2, 0x70, 0xC9, 0x04, 0x55, 0x6B, 0xFC, 0xB4, 0x7A, 0x7D, 0x40, 0x77,
0x8D, 0x39, 0x09, 0x23, 0x64, 0x2B, 0x3C, 0xBD, 0x05, 0x79, 0xE6, 0x09, 0x08, 0xD5, 0xA0, 0x00,
0xC1, 0xD0, 0x8B, 0x98, 0xEF, 0x93, 0x3F, 0x80, 0x64, 0x45, 0xBF, 0x87, 0xF8, 0xB0, 0x09, 0xBA,
0x9E, 0x94, 0xF7, 0x26, 0x61, 0x22, 0xED, 0x7A, 0xC2, 0x4E, 0x5E, 0x26, 0x6C, 0x42, 0xA8, 0x2F,
0xA1, 0xBB, 0xEF, 0xB7, 0xB8, 0xDB, 0x00, 0x66, 0xE1, 0x6A, 0x85, 0xE0, 0x49, 0x3F, 0x07, 0xDF,
0x48, 0x09, 0xAE, 0xC0, 0x84, 0xA5, 0x93, 0x74, 0x8A, 0xC3, 0xDD, 0xE5, 0xA6, 0xD7, 0xAA, 0xE1,
0xE8, 0xB6, 0xE5, 0x35, 0x2B, 0x2D, 0x71, 0xEF, 0xBB, 0x47, 0xD4, 0xCA, 0xEE, 0xD5, 0xE6, 0xD6,
0x33, 0x80, 0x5D, 0x2D, 0x32, 0x3E, 0x6F, 0xD8, 0x1B, 0x46, 0x84, 0xB9, 0x3A, 0x26, 0x77, 0xD4,
0x5E, 0x74, 0x21, 0xC2, 0xC6, 0xAE, 0xA2, 0x59, 0xB8, 0x55, 0xA6, 0x98, 0xFD, 0x7D, 0x13, 0x47,
0x7A, 0x1F, 0xE5, 0x3E, 0x5A, 0x4A, 0x61, 0x97, 0xDB, 0xEC, 0x5C, 0xE9, 0x5F, 0x50, 0x5B, 0x52,
0x0B, 0xCD, 0x95, 0x70, 0xC4, 0xA8, 0x26, 0x5A, 0x7E, 0x01, 0xF8, 0x9C, 0x0C, 0x00, 0x2C, 0x59,
0xBF, 0xEC, 0x6C, 0xD4, 0xA5, 0xC1, 0x09, 0x25, 0x89, 0x53, 0xEE, 0x5E, 0xE7, 0x0C, 0xD5, 0x77,
0xEE, 0x21, 0x7A, 0xF2, 0x1F, 0xA7, 0x01, 0x78, 0xF0, 0x94, 0x6C, 0x9B, 0xF6, 0xCA, 0x87, 0x51,
0x79, 0x34, 0x79, 0xF6, 0xB5, 0x37, 0x73, 0x7E, 0x40, 0xB6, 0xED, 0x28, 0x51, 0x1D, 0x8A, 0x2D,
0x7E, 0x73, 0xEB, 0x75, 0xF8, 0xDA, 0xAC, 0x91, 0x2F, 0xF9, 0x06, 0xE0, 0xAB, 0x95, 0x5B, 0x08,
0x3B, 0xAC, 0x45, 0xA8, 0xE5, 0xE9, 0xB7, 0x44, 0xC8, 0x50, 0x6F, 0x37, 0xE9, 0xB4, 0xE7, 0x49,
0xA1, 0x84, 0xB3, 0x0F, 0x43, 0xEB, 0x18, 0x8D, 0x85, 0x5F, 0x1B, 0x70, 0xD7, 0x1F, 0xF3, 0xE5,
0x0C, 0x53, 0x7A, 0xC1, 0xB0, 0xF8, 0x97, 0x4F, 0x0F, 0xE1, 0xA6, 0xAD, 0x29, 0x5B, 0xA4, 0x2F,
0x6A, 0xEC, 0x74, 0xD1, 0x23, 0xA7, 0xAB, 0xED, 0xDE, 0x6E, 0x2C, 0x07, 0x11, 0xCA, 0xB3, 0x6B,
0xE5, 0xAC, 0xB1, 0xA5, 0xA1, 0x1A, 0x4B, 0x1D, 0xB0, 0x8B, 0xA6, 0x98, 0x2E, 0xFC, 0xCD, 0x71,
0x69, 0x29, 0xA7, 0x74, 0x1C, 0xFC, 0x63, 0xAA, 0x44, 0x35, 0xE0, 0xB6, 0x9A, 0x90, 0x63, 0xE8,
0x80, 0x79, 0x5C, 0x3D, 0xC5, 0xEF, 0x32, 0x72, 0xE1, 0x1C, 0x49, 0x7A, 0x91, 0xAC, 0xF6, 0x99,
0xFE, 0xFE, 0xE2, 0x06, 0x22, 0x7A, 0x44, 0xC9, 0xFB, 0x35, 0x9F, 0xD5, 0x6A, 0xC0, 0xA9, 0xA7,
0x5A, 0x74, 0x3C, 0xFF, 0x68, 0x62, 0xF1, 0x7D, 0x72, 0x59, 0xAB, 0x07, 0x52, 0x16, 0xC0, 0x69,
0x95, 0x11, 0x64, 0x3B, 0x64, 0x39]
const test_200_message_shake256 = [u8(0xCD), 0x8A, 0x92, 0x0E, 0xD1, 0x41, 0xAA, 0x04, 0x07, 0xA2,
0x2D, 0x59, 0x28, 0x86, 0x52, 0xE9, 0xD9, 0xF1, 0xA7, 0xEE, 0x0C, 0x1E, 0x7C, 0x1C, 0xA6, 0x99,
0x42, 0x4D, 0xA8, 0x4A, 0x90, 0x4D, 0x2D, 0x70, 0x0C, 0xAA, 0xE7, 0x39, 0x6E, 0xCE, 0x96, 0x60,
0x44, 0x40, 0x57, 0x7D, 0xA4, 0xF3, 0xAA, 0x22, 0xAE, 0xB8, 0x85, 0x7F, 0x96, 0x1C, 0x4C, 0xD8,
0xE0, 0x6F, 0x0A, 0xE6, 0x61, 0x0B, 0x10, 0x48, 0xA7, 0xF6, 0x4E, 0x10, 0x74, 0xCD, 0x62, 0x9E,
0x85, 0xAD, 0x75, 0x66, 0x04, 0x8E, 0xFC, 0x4F, 0xB5, 0x00, 0xB4, 0x86, 0xA3, 0x30, 0x9A, 0x8F,
0x26, 0x72, 0x4C, 0x0E, 0xD6, 0x28, 0x00, 0x1A, 0x10, 0x99, 0x42, 0x24, 0x68, 0xDE, 0x72, 0x6F,
0x10, 0x61, 0xD9, 0x9E, 0xB9, 0xE9, 0x36, 0x04, 0xD5, 0xAA, 0x74, 0x67, 0xD4, 0xB1, 0xBD, 0x64,
0x84, 0x58, 0x2A, 0x38, 0x43, 0x17, 0xD7, 0xF4, 0x7D, 0x75, 0x0B, 0x8F, 0x54, 0x99, 0x51, 0x2B,
0xB8, 0x5A, 0x22, 0x6C, 0x42, 0x43, 0x55, 0x6E, 0x69, 0x6F, 0x6B, 0xD0, 0x72, 0xC5, 0xAA, 0x2D,
0x9B, 0x69, 0x73, 0x02, 0x44, 0xB5, 0x68, 0x53, 0xD1, 0x69, 0x70, 0xAD, 0x81, 0x7E, 0x21, 0x3E,
0x47, 0x06, 0x18, 0x17, 0x80, 0x01, 0xC9, 0xFB, 0x56, 0xC5, 0x4F, 0xEF, 0xA5, 0xFE, 0xE6, 0x7D,
0x2D, 0xA5, 0x24, 0xBB, 0x3B, 0x0B, 0x61, 0xEF, 0x0E, 0x91, 0x14, 0xA9, 0x2C, 0xDB, 0xB6, 0xCC,
0xCB, 0x98, 0x61, 0x5C, 0xFE, 0x76, 0xE3, 0x51, 0x0D, 0xD8, 0x8D, 0x1C, 0xC2, 0x8F, 0xF9, 0x92,
0x87, 0x51, 0x2F, 0x24, 0xBF, 0xAF, 0xA1, 0xA7, 0x68, 0x77, 0xB6, 0xF3, 0x71, 0x98, 0xE3, 0xA6,
0x41, 0xC6, 0x8A, 0x7C, 0x42, 0xD4, 0x5F, 0xA7, 0xAC, 0xC1, 0x0D, 0xAE, 0x5F, 0x3C, 0xEF, 0xB7,
0xB7, 0x35, 0xF1, 0x2D, 0x4E, 0x58, 0x9F, 0x7A, 0x45, 0x6E, 0x78, 0xC0, 0xF5, 0xE4, 0xC4, 0x47,
0x1F, 0xFF, 0xA5, 0xE4, 0xFA, 0x05, 0x14, 0xAE, 0x97, 0x4D, 0x8C, 0x26, 0x48, 0x51, 0x3B, 0x5D,
0xB4, 0x94, 0xCE, 0xA8, 0x47, 0x15, 0x6D, 0x27, 0x7A, 0xD0, 0xE1, 0x41, 0xC2, 0x4C, 0x78, 0x39,
0x06, 0x4C, 0xD0, 0x88, 0x51, 0xBC, 0x2E, 0x7C, 0xA1, 0x09, 0xFD, 0x4E, 0x25, 0x1C, 0x35, 0xBB,
0x0A, 0x04, 0xFB, 0x05, 0xB3, 0x64, 0xFF, 0x8C, 0x4D, 0x8B, 0x59, 0xBC, 0x30, 0x3E, 0x25, 0x32,
0x8C, 0x09, 0xA8, 0x82, 0xE9, 0x52, 0x51, 0x8E, 0x1A, 0x8A, 0xE0, 0xFF, 0x26, 0x5D, 0x61, 0xC4,
0x65, 0x89, 0x69, 0x73, 0xD7, 0x49, 0x04, 0x99, 0xDC, 0x63, 0x9F, 0xB8, 0x50, 0x2B, 0x39, 0x45,
0x67, 0x91, 0xB1, 0xB6, 0xEC, 0x5B, 0xCC, 0x5D, 0x9A, 0xC3, 0x6A, 0x6D, 0xF6, 0x22, 0xA0, 0x70,
0xD4, 0x3F, 0xED, 0x78, 0x1F, 0x5F, 0x14, 0x9F, 0x7B, 0x62, 0x67, 0x5E, 0x7D, 0x1A, 0x4D, 0x6D,
0xEC, 0x48, 0xC1, 0xC7, 0x16, 0x45, 0x86, 0xEA, 0xE0, 0x6A, 0x51, 0x20, 0x8C, 0x0B, 0x79, 0x12,
0x44, 0xD3, 0x07, 0x72, 0x65, 0x05, 0xC3, 0xAD, 0x4B, 0x26, 0xB6, 0x82, 0x23, 0x77, 0x25, 0x7A,
0xA1, 0x52, 0x03, 0x75, 0x60, 0xA7, 0x39, 0x71, 0x4A, 0x3C, 0xA7, 0x9B, 0xD6, 0x05, 0x54, 0x7C,
0x9B, 0x78, 0xDD, 0x1F, 0x59, 0x6F, 0x2D, 0x4F, 0x17, 0x91, 0xBC, 0x68, 0x9A, 0x0E, 0x9B, 0x79,
0x9A, 0x37, 0x33, 0x9C, 0x04, 0x27, 0x57, 0x33, 0x74, 0x01, 0x43, 0xEF, 0x5D, 0x2B, 0x58, 0xB9,
0x6A, 0x36, 0x3D, 0x4E, 0x08, 0x07, 0x6A, 0x1A, 0x9D, 0x78, 0x46, 0x43, 0x6E, 0x4D, 0xCA, 0x57,
0x28, 0xB6, 0xF7, 0x60, 0xEE, 0xF0, 0xCA, 0x92, 0xBF, 0x0B, 0xE5, 0x61, 0x5E, 0x96, 0x95, 0x9D,
0x76, 0x71, 0x97, 0xA0, 0xBE, 0xEB]
fn test_200_length_xof() {
input := []u8{}
output_128 := shake128(input_200, 512)
assert output_128 == test_200_message_shake128
output_256 := shake256(input_200, 512)
assert output_256 == test_200_message_shake256
}
+95
View File
@@ -0,0 +1,95 @@
import crypto.sha3
fn test_api_call() {
input := 'abc'.bytes()
// Digest generation
mut digest_224 := sha3.new_digest(sha3.rate_224, sha3.size_224)!
mut digest_256 := sha3.new_digest(sha3.rate_256, sha3.size_256)!
mut digest_384 := sha3.new_digest(sha3.rate_384, sha3.size_384)!
mut digest_512 := sha3.new_digest(sha3.rate_512, sha3.size_512)!
mut digest_keccak_224 := sha3.new_digest(sha3.rate_224, sha3.size_224, padding: .keccak)!
mut digest_keccak_256 := sha3.new_digest(sha3.rate_256, sha3.size_256, padding: .keccak)!
mut digest_keccak_384 := sha3.new_digest(sha3.rate_384, sha3.size_384, padding: .keccak)!
mut digest_keccak_512 := sha3.new_digest(sha3.rate_512, sha3.size_512, padding: .keccak)!
// Result should be same as shortened version
assert digest_224 == sha3.new224()!
assert digest_256 == sha3.new256()!
assert digest_384 == sha3.new384()!
assert digest_512 == sha3.new512()!
assert digest_keccak_256 == sha3.new256keccak()!
assert digest_keccak_512 == sha3.new512keccak()!
// Should not panic
digest_224.write(input)!
digest_256.write(input)!
digest_384.write(input)!
digest_512.write(input)!
digest_keccak_256.write(input)!
digest_keccak_512.write(input)!
// Result should be same as shortened version
assert digest_224.checksum() == sha3.sum224(input)
assert digest_256.checksum() == sha3.sum256(input)
assert digest_384.checksum() == sha3.sum384(input)
assert digest_512.checksum() == sha3.sum512(input)
assert digest_keccak_256.checksum() == sha3.keccak256(input)
assert digest_keccak_512.checksum() == sha3.keccak512(input)
for size in 1 .. 65 {
// Digest generation
mut digest_xof_128 := sha3.new_digest(sha3.xof_rate_128, size, padding: .xof)!
mut digest_xof_256 := sha3.new_digest(sha3.xof_rate_256, size, padding: .xof)!
// Result should be same as shortened version
assert digest_xof_128 == sha3.new_xof_digest(sha3.xof_rate_128, size)!
assert digest_xof_256 == sha3.new_xof_digest(sha3.xof_rate_256, size)!
assert digest_xof_128 == sha3.new128xof(size)!
assert digest_xof_256 == sha3.new256xof(size)!
// Should not panic
digest_xof_128.write(input)!
digest_xof_256.write(input)!
}
// Should be AbsorptionRateError
if should_be_error := sha3.new_digest(sha3.rate_224, sha3.size_256) {
assert false, 'new_digest(sha3.rate_224, sha3.size_256) should be error'
}
if should_be_error := sha3.new_digest(sha3.rate_224, sha3.size_256, padding: .keccak) {
assert false, 'new_digest(sha3.rate_224, sha3.size_256, padding: .keccak) should be error'
}
if should_be_error := sha3.new_digest(0, sha3.size_256) {
assert false, 'new_digest(0, sha3.size_256) should be error'
}
if should_be_error := sha3.new_digest(0, sha3.size_256, padding: .keccak) {
assert false, 'new_digest(0, sha3.size_256, padding: .keccak) should be error'
}
// Should be HashSizeError
if should_be_error := sha3.new_digest(sha3.rate_256, -1) {
assert false, 'new_digest(sha3.rate_256, -1) should be error'
}
if should_be_error := sha3.new_digest(sha3.rate_256, -1, padding: .keccak) {
assert false, 'new_digest(sha3.rate_256, -1, padding: .keccak) should be error'
}
if should_be_error := sha3.new_digest(sha3.rate_256, 100) {
assert false, 'new_digest(sha3.rate_256, -1) should be error'
}
if should_be_error := sha3.new_digest(sha3.rate_256, 100, padding: .keccak) {
assert false, 'new_digest(sha3.rate_256, -1, padding: .keccak) should be error'
}
// Should be XOFSizeError
if should_be_error := sha3.new128xof(-1) {
assert false, 'new128xof(-1) should be error'
}
if should_be_error := sha3.new256xof(-1) {
assert false, 'new256xof(-1) should be error'
}
// Shoud be XOFRateError
if should_be_error := sha3.new_xof_digest(0, sha3.size_256) {
assert false, 'new_xof_digest(0, sha3.size_256) should be error'
}
}
+135
View File
@@ -0,0 +1,135 @@
// 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.
// streaming shake-128/256 xof per FIPS 202
// https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
module sha3
@[noinit]
pub struct Shake {
rate int // bytes per permutation (168 for shake-128, 136 for shake-256)
mut:
s State
input_buffer []u8
finalized bool
squeeze_buf []u8
}
// new_shake128 returns a new Shake instance for SHAKE-128 extended output function.
pub fn new_shake128() &Shake {
return &Shake{
rate: xof_rate_128
}
}
// new_shake256 returns a new Shake instance for SHAKE-256 extended output function.
pub fn new_shake256() &Shake {
return &Shake{
rate: xof_rate_256
}
}
// write absorbs more data into the sponge state.
// Panics if called after `read`.
@[direct_array_access]
pub fn (mut s Shake) write(data []u8) {
if s.finalized {
panic('sha3: write after read on Shake')
}
if data.len == 0 {
return
}
// avoid cloning on each iteration
mut remaining := unsafe { data[..] }
if s.input_buffer.len != 0 {
empty_space := s.rate - s.input_buffer.len
if remaining.len < empty_space {
s.input_buffer << remaining
return
} else {
s.input_buffer << remaining[..empty_space]
remaining = unsafe { remaining[empty_space..] }
s.s.xor_bytes(s.input_buffer[..s.rate], s.rate)
s.s.kaccak_p_1600_24()
s.input_buffer = []u8{}
}
}
for remaining.len >= s.rate {
s.s.xor_bytes(remaining[..s.rate], s.rate)
s.s.kaccak_p_1600_24()
remaining = unsafe { remaining[s.rate..] }
}
if remaining.len > 0 {
s.input_buffer = remaining.clone()
}
}
fn (mut s Shake) finalize() {
if s.finalized {
return
}
s.finalized = true
// pad10*1 with xof domain separator 0x1f (FIPS 202 sec B.2)
mut padded := s.input_buffer.clone()
if padded.len == s.rate - 1 {
padded << u8(0x80 | 0x1f)
} else {
padded << u8(0x1f)
for padded.len < s.rate - 1 {
padded << u8(0x00)
}
padded << u8(0x80)
}
s.s.xor_bytes(padded[..s.rate], s.rate)
s.s.kaccak_p_1600_24()
state_bytes := s.s.to_bytes()
s.squeeze_buf = state_bytes[..s.rate].clone()
s.input_buffer = []u8{}
}
// read squeezes `out_len` bytes from the sponge state.
// Finalizes the sponge on first call; further calls to `write` will panic.
@[direct_array_access]
pub fn (mut s Shake) read(out_len int) []u8 {
if !s.finalized {
s.finalize()
}
mut result := []u8{cap: out_len}
mut remaining := out_len
for remaining > 0 {
if s.squeeze_buf.len == 0 {
s.s.kaccak_p_1600_24()
state_bytes := s.s.to_bytes()
s.squeeze_buf = state_bytes[..s.rate].clone()
}
take := if remaining < s.squeeze_buf.len { remaining } else { s.squeeze_buf.len }
result << s.squeeze_buf[..take]
s.squeeze_buf = s.squeeze_buf[take..].clone()
remaining -= take
}
return result
}
// reset clears the sponge state, allowing the Shake instance to be reused.
pub fn (mut s Shake) reset() {
s.s = State{}
s.input_buffer = []u8{}
s.finalized = false
s.squeeze_buf = []u8{}
}
+80
View File
@@ -0,0 +1,80 @@
module sha3
fn test_shake256_streaming_matches_oneshot() {
data := 'hello world'.bytes()
// oneshot
expected := shake256(data, 64)
// streaming
mut s := new_shake256()
s.write(data)
result := s.read(64)
assert result == expected, 'streaming SHAKE-256 output differs from one-shot'
}
fn test_shake128_streaming_matches_oneshot() {
data := 'hello world'.bytes()
expected := shake128(data, 64)
mut s := new_shake128()
s.write(data)
result := s.read(64)
assert result == expected, 'streaming SHAKE-128 output differs from one-shot'
}
fn test_shake256_incremental_write() {
data := 'the quick brown fox jumps over the lazy dog'.bytes()
expected := shake256(data, 128)
mut s := new_shake256()
s.write(data[..10])
s.write(data[10..25])
s.write(data[25..])
result := s.read(128)
assert result == expected, 'incremental write produced different output'
}
fn test_shake256_incremental_read() {
data := 'test data for incremental reads'.bytes()
// all at once
mut s1 := new_shake256()
s1.write(data)
all_at_once := s1.read(200)
// in chunks
mut s2 := new_shake256()
s2.write(data)
mut chunked := []u8{}
chunked << s2.read(50)
chunked << s2.read(80)
chunked << s2.read(70)
assert chunked == all_at_once, 'incremental read produced different output'
}
fn test_shake128_large_output() {
data := 'large output test'.bytes()
mut s := new_shake128()
s.write(data)
// more than one block (168 bytes in shake128)
result := s.read(500)
assert result.len == 500
}
fn test_shake_reset() {
data := 'reset test'.bytes()
mut s := new_shake256()
s.write(data)
first := s.read(32)
s.reset()
s.write(data)
second := s.read(32)
assert first == second, 'reset did not restore initial state'
}