Skip to content

Instantly share code, notes, and snippets.

@Egor-Skriptunoff
Last active March 15, 2022 07:36
Show Gist options
  • Save Egor-Skriptunoff/50683d024cf6acdb89100564dc819b05 to your computer and use it in GitHub Desktop.
Save Egor-Skriptunoff/50683d024cf6acdb89100564dc819b05 to your computer and use it in GitHub Desktop.
BLAKE3 for LuaJIT
--------------------------------------------------------------------------------------------------------------------------
-- BLAKE3 for LuaJIT
--------------------------------------------------------------------------------------------------------------------------
-- Compatible with:
-- LuaJIT 2.x (FFI must be enabled, both little-endian and big-endian systems are supported)
-- This module contains functions:
-- blake3 (message, key, digest_size_in_bytes)
-- blake3_derive_key (key_material, context_string, derived_key_size_in_bytes)
-- hex_to_bin (hex_string)
-- bin_to_hex (binary_string)
-- Usage examples:
-- See "Tutorial" section in the file "blake3_for_luajit.test.lua"
-----------------------------------------------------------------------------
local table_concat, byte, char, rep, sub, gsub, format, floor, ceil, math_min, tonumber, type, math_huge =
table.concat, string.byte, string.char, string.rep, string.sub, string.gsub, string.format, math.floor, math.ceil, math.min, tonumber, type, math.huge
local ffi = require("ffi")
local AND = bit.band
local OR = bit.bor
local XOR = bit.bxor
local SHL = bit.lshift
local SHR = bit.rshift
local ROL = bit.rol
local ROR = bit.ror
local NOT = bit.bnot
local NORM = bit.tobit
local HEX = bit.tohex
local BSWAP = bit.bswap
local sha2_H = {
NORM(0x6a09e667),
NORM(0xbb67ae85),
NORM(0x3c6ef372),
NORM(0xa54ff53a),
NORM(0x510e527f),
NORM(0x9b05688c),
NORM(0x1f83d9ab),
NORM(0x5be0cd19),
}
local perm_blake3 = ffi.new("uint8_t[?]", 28,
0, 2, 3, 10, 12, 9, 11, 5,
0, 2, 3, 10, 12, 9,
1, 6, 4, 7, 13, 14, 15, 8,
1, 6, 4, 7, 13, 14
)
local W = ffi.new("int32_t[?]", 16)
local v = ffi.new("int32_t[?]", 16)
local function G(a, b, c, d, k1, k2)
local va, vb, vc, vd = v[a], v[b], v[c], v[d]
va = NORM(W[k1] + (va + vb))
vd = ROR(XOR(vd, va), 16)
vc = NORM(vc + vd)
vb = ROR(XOR(vb, vc), 12)
va = NORM(W[k2] + (va + vb))
vd = ROR(XOR(vd, va), 8)
vc = NORM(vc + vd)
vb = ROR(XOR(vb, vc), 7)
v[a], v[b], v[c], v[d] = va, vb, vc, vd
end
local function blake3_feed_64(str, offs, size, flags, chunk_index, H_in, H_out, wide_output, block_length)
-- offs >= 0, size >= 0, size is multiple of 64
block_length = block_length or 64
local h1, h2, h3, h4, h5, h6, h7, h8 = H_in[1], H_in[2], H_in[3], H_in[4], H_in[5], H_in[6], H_in[7], H_in[8]
H_out = H_out or H_in
for pos = offs, offs + size - 1, 64 do
if str then
for j = 0, 15 do
pos = pos + 4
local a, b, c, d = byte(str, pos-3, pos)
W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)
end
end
v[0x0], v[0x1], v[0x2], v[0x3], v[0x4], v[0x5], v[0x6], v[0x7] = h1, h2, h3, h4, h5, h6, h7, h8
v[0x8], v[0x9], v[0xA], v[0xB] = sha2_H[1], sha2_H[2], sha2_H[3], sha2_H[4]
v[0xC] = NORM(chunk_index % 2^32) -- t0 = low_4_bytes(chunk_index)
v[0xD] = floor(chunk_index / 2^32) -- t1 = high_4_bytes(chunk_index)
v[0xE], v[0xF] = block_length, flags
for j = 0, 6 do
G(0, 4, 8, 12, perm_blake3[j], perm_blake3[j + 14])
G(1, 5, 9, 13, perm_blake3[j + 1], perm_blake3[j + 2])
G(2, 6, 10, 14, perm_blake3[j + 16], perm_blake3[j + 7])
G(3, 7, 11, 15, perm_blake3[j + 15], perm_blake3[j + 17])
G(0, 5, 10, 15, perm_blake3[j + 21], perm_blake3[j + 5])
G(1, 6, 11, 12, perm_blake3[j + 3], perm_blake3[j + 6])
G(2, 7, 8, 13, perm_blake3[j + 4], perm_blake3[j + 18])
G(3, 4, 9, 14, perm_blake3[j + 19], perm_blake3[j + 20])
end
if wide_output then
H_out[ 9] = XOR(h1, v[0x8])
H_out[10] = XOR(h2, v[0x9])
H_out[11] = XOR(h3, v[0xA])
H_out[12] = XOR(h4, v[0xB])
H_out[13] = XOR(h5, v[0xC])
H_out[14] = XOR(h6, v[0xD])
H_out[15] = XOR(h7, v[0xE])
H_out[16] = XOR(h8, v[0xF])
end
h1 = XOR(v[0x0], v[0x8])
h2 = XOR(v[0x1], v[0x9])
h3 = XOR(v[0x2], v[0xA])
h4 = XOR(v[0x3], v[0xB])
h5 = XOR(v[0x4], v[0xC])
h6 = XOR(v[0x5], v[0xD])
h7 = XOR(v[0x6], v[0xE])
h8 = XOR(v[0x7], v[0xF])
end
H_out[1], H_out[2], H_out[3], H_out[4], H_out[5], H_out[6], H_out[7], H_out[8] = h1, h2, h3, h4, h5, h6, h7, h8
end
local function blake3(message, key, digest_size_in_bytes, message_flags, K, return_array)
-- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode)
-- key: (optional) binary string up to 32 bytes, by default empty string
-- digest_size_in_bytes: (optional) by default 32
-- 0,1,2,3,4,... = get finite digest as single Lua string
-- (-1) = get infinite digest in "chunk-by-chunk" output mode
-- -2,-3,-4,... = get finite digest in "chunk-by-chunk" output mode
-- The last three parameters "message_flags", "K" and "return_array" are for internal use only, user must omit them (or pass nil)
key = key or ""
digest_size_in_bytes = digest_size_in_bytes or 32
message_flags = message_flags or 0
if key == "" then
K = K or sha2_H
else
local key_length = #key
if key_length > 32 then
error("BLAKE3 key length must not exceed 32 bytes", 2)
end
key = key..rep("\0", 32 - key_length)
K = {}
for j = 1, 8 do
local a, b, c, d = byte(key, 4*j-3, 4*j)
K[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)
end
message_flags = message_flags + 16 -- flag:KEYED_HASH
end
local tail, H, chunk_index, blocks_in_chunk, stack_size, stack = "", {}, 0, 0, 0, {}
local final_H_in, final_block_length, chunk_by_chunk_output, result, wide_output = K
local final_compression_flags = 3 -- flags:CHUNK_START,CHUNK_END
local function feed_blocks(str, offs, size)
-- size >= 0, size is multiple of 64
while size > 0 do
local part_size_in_blocks, block_flags, H_in = 1, 0, H
if blocks_in_chunk == 0 then
block_flags = 1 -- flag:CHUNK_START
H_in, final_H_in = K, H
final_compression_flags = 2 -- flag:CHUNK_END
elseif blocks_in_chunk == 15 then
block_flags = 2 -- flag:CHUNK_END
final_compression_flags = 3 -- flags:CHUNK_START,CHUNK_END
final_H_in = K
else
part_size_in_blocks = math_min(size / 64, 15 - blocks_in_chunk)
end
local part_size = part_size_in_blocks * 64
blake3_feed_64(str, offs, part_size, message_flags + block_flags, chunk_index, H_in, H)
offs, size = offs + part_size, size - part_size
blocks_in_chunk = (blocks_in_chunk + part_size_in_blocks) % 16
if blocks_in_chunk == 0 then
-- completing the currect chunk
chunk_index = chunk_index + 1
local divider = 2
while chunk_index % divider == 0 do
divider = divider * 2
stack_size = stack_size - 8
for j = 0, 7 do
W[j] = stack[stack_size + j + 1]
end
for j = 0, 7 do
W[j + 8] = H[j + 1]
end
blake3_feed_64(nil, 0, 64, message_flags + 4, 0, K, H) -- flag:PARENT
end
for j = 1, 8 do
stack[stack_size + j] = H[j]
end
stack_size = stack_size + 8
end
end
end
local function get_hash_block(block_no)
local size = math_min(64, digest_size_in_bytes - block_no * 64)
if block_no < 0 or size <= 0 then
return ""
end
if chunk_by_chunk_output then
for j = 0, 15 do
W[j] = stack[j + 17]
end
end
blake3_feed_64(nil, 0, 64, final_compression_flags, block_no, final_H_in, stack, wide_output, final_block_length)
if return_array then
return stack
end
local max_reg = ceil(size / 4)
for j = 1, max_reg do
stack[j] = HEX(BSWAP(stack[j]))
end
return sub(table_concat(stack, "", 1, max_reg), 1, size * 2)
end
local function partial(message_part)
if message_part then
if tail then
local offs = 0
if tail ~= "" and #tail + #message_part > 64 then
offs = 64 - #tail
feed_blocks(tail..sub(message_part, 1, offs), 0, 64)
tail = ""
end
local size = #message_part - offs
local size_tail = size > 0 and (size - 1) % 64 + 1 or 0
feed_blocks(message_part, offs, size - size_tail)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
final_block_length = #tail
tail = tail..rep("\0", 64 - #tail)
for j = 0, 15 do
local a, b, c, d = byte(tail, 4*j+1, 4*j+4)
W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)
end
tail = nil
for stack_size = stack_size - 8, 0, -8 do
blake3_feed_64(nil, 0, 64, message_flags + final_compression_flags, chunk_index, final_H_in, H, nil, final_block_length)
chunk_index, final_block_length, final_H_in, final_compression_flags = 0, 64, K, 4 -- flag:PARENT
for j = 0, 7 do
W[j] = stack[stack_size + j + 1]
end
for j = 0, 7 do
W[j + 8] = H[j + 1]
end
end
final_compression_flags = message_flags + final_compression_flags + 8 -- flag:ROOT
if digest_size_in_bytes < 0 then
if digest_size_in_bytes == -1 then -- infinite digest
digest_size_in_bytes = math_huge
else
digest_size_in_bytes = -digest_size_in_bytes
end
chunk_by_chunk_output = true
for j = 0, 15 do
stack[j + 17] = W[j]
end
end
digest_size_in_bytes = math_min(2^53, digest_size_in_bytes)
wide_output = digest_size_in_bytes > 32
if chunk_by_chunk_output then
local pos, cached_block_no, cached_block = 0
local function get_next_part_of_digest(arg1, arg2)
if arg1 == "seek" then
-- Usage #1: get_next_part_of_digest("seek", new_pos)
pos = arg2
else
-- Usage #2: hex_string = get_next_part_of_digest(size)
local size, index = arg1 or 1, 32
while size > 0 do
local block_offset = pos % 64
local block_no = floor(pos / 64)
local part_size = math_min(size, 64 - block_offset)
if cached_block_no ~= block_no then
cached_block_no = block_no
cached_block = get_hash_block(block_no)
end
index = index + 1
stack[index] = sub(cached_block, block_offset * 2 + 1, (block_offset + part_size) * 2)
size = size - part_size
pos = pos + part_size
end
return table_concat(stack, "", 33, index)
end
end
result = get_next_part_of_digest
elseif digest_size_in_bytes <= 64 then
result = get_hash_block(0)
else
local last_block_no = ceil(digest_size_in_bytes / 64) - 1
for block_no = 0, last_block_no do
stack[33 + block_no] = get_hash_block(block_no)
end
result = table_concat(stack, "", 33, 33 + last_block_no)
end
end
return result
end
end
if message then
-- Actually perform calculations and return the BLAKE3 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get BLAKE3 digest by invoking this function without an argument
return partial
end
end
local function blake3_derive_key(key_material, context_string, derived_key_size_in_bytes)
-- key_material: (string) your source of entropy to derive a key from (for example, it can be a master password)
-- set to nil for feeding the key material in "chunk-by-chunk" input mode
-- context_string: (string) unique description of the derived key
-- digest_size_in_bytes: (optional) by default 32
-- 0,1,2,3,4,... = get finite derived key as single Lua string
-- (-1) = get infinite derived key in "chunk-by-chunk" output mode
-- -2,-3,-4,... = get finite derived key in "chunk-by-chunk" output mode
if type(context_string) ~= "string" then
error("'context_string' parameter must be a Lua string", 2)
end
local K = blake3(context_string, nil, nil, 32, nil, true) -- flag:DERIVE_KEY_CONTEXT
return blake3(key_material, nil, derived_key_size_in_bytes, 64, K) -- flag:DERIVE_KEY_MATERIAL
end
local function hex_to_bin(hex_string)
return (gsub(hex_string, "%x%x",
function (hh)
return char(tonumber(hh, 16))
end
))
end
local function bin_to_hex(binary_string)
return (gsub(binary_string, ".",
function (c)
return format("%02x", byte(c))
end
))
end
return {
-- BLAKE3 hash function
blake3 = blake3, -- BLAKE3
blake3_derive_key = blake3_derive_key, -- BLAKE3_KDF
-- misc utilities
hex_to_bin = hex_to_bin, -- converts hexadecimal representation to binary string
bin_to_hex = bin_to_hex, -- converts binary string to hexadecimal representation
}
--------------------------------------------------------------------------------
-- TESTS of the module "blake3_for_luajit.lua"
--------------------------------------------------------------------------------
local b3 = require("blake3_for_luajit")
--------------------------------------------------------------------------------
-- Tutorial
--------------------------------------------------------------------------------
-- By default BLAKE3 digest size is 32 bytes = 256 bits = 64 hexadecimal characters
assert(b3.blake3("message") == "4bd766dabadb76f246b13b877e09eeca2c5e74a55d3e6828cbaf9edcaa4e055a")
-- Feed long message
local append_input_message = b3.blake3()
append_input_message("mes")
append_input_message("sa")
append_input_message("ge")
assert(append_input_message() == "4bd766dabadb76f246b13b877e09eeca2c5e74a55d3e6828cbaf9edcaa4e055a")
-- Specify digest length in bytes: 132 bytes = 1056 bits = 264 hexadecimal characters
assert(b3.blake3("message", nil, 132) == "4bd766dabadb76f246b13b877e09eeca2c5e74a55d3e6828cbaf9edcaa4e055aa2f85cc9d1ca73cf2ed0991c14f76e176b7625d5e0df216ee3222954fb2164210ebb392bbe596b9b111dc8fc65b09f18f64c2d2eb9b1753694564a933bc8f169434742c2fd7c002d267d2ec1447d8a246dae450b58328e71e52e619873e988713e261bbc")
-- Produce infinite digest
local get_next_part_of_digest = b3.blake3("message", nil, -1)
assert(get_next_part_of_digest(4) == "4bd766da")
assert(get_next_part_of_digest(4) == "badb76f2")
assert(get_next_part_of_digest(4) == "46b13b87") -- and so on
-- Calculate hash with a key or salt
assert(b3.blake3("message", "key") == "d6c4acea3d08d217ffa77c4f821c866945165173c996ce997f808956185a776f")
assert(b3.blake3("message", "key", 132) == "d6c4acea3d08d217ffa77c4f821c866945165173c996ce997f808956185a776fa261099f68a44266ed335362b6c12ad20b61800fe66fe7f0d74dd7c1ba777e60f229aaabe2300c8ac8856ab0c7f0f5df1a06fc2a7131257d729805334f032065d5a4934e86e51e080785cc63d192f57d53e45f192226bd24998ed99064a0b73ef003ab0b")
assert(b3.blake3("message", "salt") == "0b28ff073e5c22c352515466304d53ab6c5aa605af0cb9a7fcd47bf881d0f800")
assert(b3.blake3("message", "salt", 132) == "0b28ff073e5c22c352515466304d53ab6c5aa605af0cb9a7fcd47bf881d0f80091d7d71b85811f81bd85ad58f85ece83a20faf0a134aa96a8354c7debe90526eb194453ce52a03cdd349923a8816d57eedfcfa95a7871c7e2b5b0ad2b9061ddf809f83ccd08d8cdd4dc579ed38cb4ec8303886c2aa32ee34696d9b1a0373f94d62669585")
-- Derive personalized key from your master key
do
-- Derive 256-bit application key from your secret
local context = "my unique personalization string" -- describe your application here
local master_key = "my master key" -- secret (password or key material) of any length
local derived_key = b3.hex_to_bin(b3.blake3_derive_key(master_key, context))
-- Use the application key
assert(b3.blake3("my message", derived_key) == "707e579854238b4dc510048808b47e94327b1f3898613e24806a5b047d78d0ed")
end
--------------------------------------------------------------------------------
-- (End of tutorial)
--------------------------------------------------------------------------------
assert(b3.blake3("") == "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")
assert(b3.blake3(("€"):rep(100)) == "20b089f9099e151d25649583b1dc1517c7cb29f7dcdad5e87daae10a41a3ff10")
assert(b3.blake3(("€"):rep(100), "100 euro") == "5d3b88a45654617dc1aed27c3a230e42e9d4a15951572f542a005278e480c831")
assert(b3.blake3(("\255"):rep(999), ("\255"):rep(32)) == "18f4ea688d82cbcd7ad4db10a14d9eea1cde44573b8111835de95b2ede26a652")
do
local function create_personalized_keyed_hash_function(key, personalization_string, digest_size_in_bytes)
-- create personalized 256-bit key
local derived_key = b3.hex_to_bin(b3.blake3_derive_key(key, personalization_string))
return function (message)
-- pass the personalized key to BLAKE3
return b3.blake3(message, derived_key, digest_size_in_bytes)
end
end
local password = "password"
-- create two different 160-bit hash functions depending on common password
local H1 = create_personalized_keyed_hash_function(password, "personalization string 1", 20)
local H2 = create_personalized_keyed_hash_function(password, "personalization string 2", 20)
-- usual BLAKE3 without personalization
assert(b3.blake3("message", password, 20) == "aff235a529b0251acef680e643aabef619cb45bf")
-- personalized BLAKE3
assert(H1("message") == "b66b08dec065ef767baa56457e3591cfa9232554")
assert(H2("message") == "12f6db5e20d6cb492ba6c56f5521343f345a0aeb")
end
assert(b3.blake3("The quick brown fox jumps over the lazy dog") == "2f1514181aadccd913abd94cfa592701a5686ab23f8df1dff1b74710febc6d4a")
assert(b3.blake3("The quick brown fox jumps over the lazy dog", nil, 70) == "2f1514181aadccd913abd94cfa592701a5686ab23f8df1dff1b74710febc6d4ac0615cd845be939b4ef6aec25e799aaa450c63f8d9e333cdb0dd79b70ee698793ca5d743d5be")
local get_next_part_of_digest = b3.blake3("The quick brown fox jumps over the lazy dog", nil, -11)
assert(get_next_part_of_digest(5) == "2f1514181a") -- 5 bytes in hexadecimal representation
assert(get_next_part_of_digest() == "ad") -- size=1 is assumed when omitted
assert(get_next_part_of_digest(0) == "") -- size=0 is a valid size
assert(get_next_part_of_digest(3) == "ccd913") -- next 3 bytes
assert(get_next_part_of_digest(3) == "abd9") -- last 2 bytes (although 3 were requested)
assert(get_next_part_of_digest(3) == "") -- empty strings beyond the end of the 11-byte digest
get_next_part_of_digest("seek", 0) -- jump to the beginning
assert(get_next_part_of_digest(7) == "2f1514181aadcc")
assert(get_next_part_of_digest(7) == "d913abd9")
assert(get_next_part_of_digest(7) == "")
local append_input_message = b3.blake3(nil, nil, -1) -- infinite digest, "chunk-by-chunk" input mode, "chunk-by-chunk" output mode
append_input_message("The quick brown fox")
append_input_message(" jumps over the lazy dog")
local get_next_part_of_digest = append_input_message() -- input stream is terminated, now we can start receiving the output stream
assert(get_next_part_of_digest(10) == "2f1514181aadccd913ab")
get_next_part_of_digest("seek", -5555)
assert(get_next_part_of_digest(5555 + 10) == "2f1514181aadccd913ab")
get_next_part_of_digest("seek", 2^31-10)
assert(get_next_part_of_digest(20) == "a224c58b681656471bb49c5773c9f545cbd338e3")
get_next_part_of_digest("seek", 2^32-10)
assert(get_next_part_of_digest(20) == "85ae3f8181acb602df2a104ffc4b1faf9e5156d3")
get_next_part_of_digest("seek", 64*2^31-10)
assert(get_next_part_of_digest(20) == "473705d164998022de631a525db16245e363eb78")
get_next_part_of_digest("seek", 64*2^32-10)
assert(get_next_part_of_digest(20) == "ce1b8f63b57d26fd525debe3bdd15ac2a0aeb975")
get_next_part_of_digest("seek", 2^53-10)
assert(get_next_part_of_digest(20) == "db5aa1a73e9386ab0c05")
get_next_part_of_digest("seek", 2^53)
assert(get_next_part_of_digest(1) == "")
-- useless special case: digest of length 0
assert(b3.blake3("The quick brown fox jumps over the lazy dog", nil, 0) == "")
local append_input_message = b3.blake3(nil, nil, 0) -- "chunk-by-chunk" input mode
append_input_message("The quick brown fox")
append_input_message(" jumps over the lazy dog")
assert(append_input_message() == "")
-- test vectors published by BLAKE3 authors
do
local test_vectors = [[
{
"input_len": 0,
"hash": "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262e00f03e7b69af26b7faaf09fcd333050338ddfe085b8cc869ca98b206c08243a26f5487789e8f660afe6c99ef9e0c52b92e7393024a80459cf91f476f9ffdbda7001c22e159b402631f277ca96f2defdf1078282314e763699a31c5363165421cce14d",
"keyed_hash": "92b2b75604ed3c761f9d6f62392c8a9227ad0ea3f09573e783f1498a4ed60d26b18171a2f22a4b94822c701f107153dba24918c4bae4d2945c20ece13387627d3b73cbf97b797d5e59948c7ef788f54372df45e45e4293c7dc18c1d41144a9758be58960856be1eabbe22c2653190de560ca3b2ac4aa692a9210694254c371e851bc8f",
"derive_key": "2cc39783c223154fea8dfb7c1b1660f2ac2dcbd1c1de8277b0b0dd39b7e50d7d905630c8be290dfcf3e6842f13bddd573c098c3f17361f1f206b8cad9d088aa4a3f746752c6b0ce6a83b0da81d59649257cdf8eb3e9f7d4998e41021fac119deefb896224ac99f860011f73609e6e0e4540f93b273e56547dfd3aa1a035ba6689d89a0"
},
{
"input_len": 1,
"hash": "2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213c3a6cb8bf623e20cdb535f8d1a5ffb86342d9c0b64aca3bce1d31f60adfa137b358ad4d79f97b47c3d5e79f179df87a3b9776ef8325f8329886ba42f07fb138bb502f4081cbcec3195c5871e6c23e2cc97d3c69a613eba131e5f1351f3f1da786545e5",
"keyed_hash": "6d7878dfff2f485635d39013278ae14f1454b8c0a3a2d34bc1ab38228a80c95b6568c0490609413006fbd428eb3fd14e7756d90f73a4725fad147f7bf70fd61c4e0cf7074885e92b0e3f125978b4154986d4fb202a3f331a3fb6cf349a3a70e49990f98fe4289761c8602c4e6ab1138d31d3b62218078b2f3ba9a88e1d08d0dd4cea11",
"derive_key": "b3e2e340a117a499c6cf2398a19ee0d29cca2bb7404c73063382693bf66cb06c5827b91bf889b6b97c5477f535361caefca0b5d8c4746441c57617111933158950670f9aa8a05d791daae10ac683cbef8faf897c84e6114a59d2173c3f417023a35d6983f2c7dfa57e7fc559ad751dbfb9ffab39c2ef8c4aafebc9ae973a64f0c76551"
},
{
"input_len": 2,
"hash": "7b7015bb92cf0b318037702a6cdd81dee41224f734684c2c122cd6359cb1ee63d8386b22e2ddc05836b7c1bb693d92af006deb5ffbc4c70fb44d0195d0c6f252faac61659ef86523aa16517f87cb5f1340e723756ab65efb2f91964e14391de2a432263a6faf1d146937b35a33621c12d00be8223a7f1919cec0acd12097ff3ab00ab1",
"keyed_hash": "5392ddae0e0a69d5f40160462cbd9bd889375082ff224ac9c758802b7a6fd20a9ffbf7efd13e989a6c246f96d3a96b9d279f2c4e63fb0bdff633957acf50ee1a5f658be144bab0f6f16500dee4aa5967fc2c586d85a04caddec90fffb7633f46a60786024353b9e5cebe277fcd9514217fee2267dcda8f7b31697b7c54fab6a939bf8f",
"derive_key": "1f166565a7df0098ee65922d7fea425fb18b9943f19d6161e2d17939356168e6daa59cae19892b2d54f6fc9f475d26031fd1c22ae0a3e8ef7bdb23f452a15e0027629d2e867b1bb1e6ab21c71297377750826c404dfccc2406bd57a83775f89e0b075e59a7732326715ef912078e213944f490ad68037557518b79c0086de6d6f6cdd2"
},
{
"input_len": 3,
"hash": "e1be4d7a8ab5560aa4199eea339849ba8e293d55ca0a81006726d184519e647f5b49b82f805a538c68915c1ae8035c900fd1d4b13902920fd05e1450822f36de9454b7e9996de4900c8e723512883f93f4345f8a58bfe64ee38d3ad71ab027765d25cdd0e448328a8e7a683b9a6af8b0af94fa09010d9186890b096a08471e4230a134",
"keyed_hash": "39e67b76b5a007d4921969779fe666da67b5213b096084ab674742f0d5ec62b9b9142d0fab08e1b161efdbb28d18afc64d8f72160c958e53a950cdecf91c1a1bbab1a9c0f01def762a77e2e8545d4dec241e98a89b6db2e9a5b070fc110caae2622690bd7b76c02ab60750a3ea75426a6bb8803c370ffe465f07fb57def95df772c39f",
"derive_key": "440aba35cb006b61fc17c0529255de438efc06a8c9ebf3f2ddac3b5a86705797f27e2e914574f4d87ec04c379e12789eccbfbc15892626042707802dbe4e97c3ff59dca80c1e54246b6d055154f7348a39b7d098b2b4824ebe90e104e763b2a447512132cede16243484a55a4e40a85790038bb0dcf762e8c053cabae41bbe22a5bff7"
},
{
"input_len": 4,
"hash": "f30f5ab28fe047904037f77b6da4fea1e27241c5d132638d8bedce9d40494f328f603ba4564453e06cdcee6cbe728a4519bbe6f0d41e8a14b5b225174a566dbfa61b56afb1e452dc08c804f8c3143c9e2cc4a31bb738bf8c1917b55830c6e65797211701dc0b98daa1faeaa6ee9e56ab606ce03a1a881e8f14e87a4acf4646272cfd12",
"keyed_hash": "7671dde590c95d5ac9616651ff5aa0a27bee5913a348e053b8aa9108917fe070116c0acff3f0d1fa97ab38d813fd46506089118147d83393019b068a55d646251ecf81105f798d76a10ae413f3d925787d6216a7eb444e510fd56916f1d753a5544ecf0072134a146b2615b42f50c179f56b8fae0788008e3e27c67482349e249cb86a",
"derive_key": "f46085c8190d69022369ce1a18880e9b369c135eb93f3c63550d3e7630e91060fbd7d8f4258bec9da4e05044f88b91944f7cab317a2f0c18279629a3867fad0662c9ad4d42c6f27e5b124da17c8c4f3a94a025ba5d1b623686c6099d202a7317a82e3d95dae46a87de0555d727a5df55de44dab799a20dffe239594d6e99ed17950910"
},
{
"input_len": 5,
"hash": "b40b44dfd97e7a84a996a91af8b85188c66c126940ba7aad2e7ae6b385402aa2ebcfdac6c5d32c31209e1f81a454751280db64942ce395104e1e4eaca62607de1c2ca748251754ea5bbe8c20150e7f47efd57012c63b3c6a6632dc1c7cd15f3e1c999904037d60fac2eb9397f2adbe458d7f264e64f1e73aa927b30988e2aed2f03620",
"keyed_hash": "73ac69eecf286894d8102018a6fc729f4b1f4247d3703f69bdc6a5fe3e0c84616ab199d1f2f3e53bffb17f0a2209fe8b4f7d4c7bae59c2bc7d01f1ff94c67588cc6b38fa6024886f2c078bfe09b5d9e6584cd6c521c3bb52f4de7687b37117a2dbbec0d59e92fa9a8cc3240d4432f91757aabcae03e87431dac003e7d73574bfdd8218",
"derive_key": "1f24eda69dbcb752847ec3ebb5dd42836d86e58500c7c98d906ecd82ed9ae47f6f48a3f67e4e43329c9a89b1ca526b9b35cbf7d25c1e353baffb590fd79be58ddb6c711f1a6b60e98620b851c688670412fcb0435657ba6b638d21f0f2a04f2f6b0bd8834837b10e438d5f4c7c2c71299cf7586ea9144ed09253d51f8f54dd6bff719d"
},
{
"input_len": 6,
"hash": "06c4e8ffb6872fad96f9aaca5eee1553eb62aed0ad7198cef42e87f6a616c844611a30c4e4f37fe2fe23c0883cde5cf7059d88b657c7ed2087e3d210925ede716435d6d5d82597a1e52b9553919e804f5656278bd739880692c94bff2824d8e0b48cac1d24682699e4883389dc4f2faa2eb3b4db6e39debd5061ff3609916f3e07529a",
"keyed_hash": "82d3199d0013035682cc7f2a399d4c212544376a839aa863a0f4c91220ca7a6dc2ffb3aa05f2631f0fa9ac19b6e97eb7e6669e5ec254799350c8b8d189e8807800842a5383c4d907c932f34490aaf00064de8cdb157357bde37c1504d2960034930887603abc5ccb9f5247f79224baff6120a3c622a46d7b1bcaee02c5025460941256",
"derive_key": "be96b30b37919fe4379dfbe752ae77b4f7e2ab92f7ff27435f76f2f065f6a5f435ae01a1d14bd5a6b3b69d8cbd35f0b01ef2173ff6f9b640ca0bd4748efa398bf9a9c0acd6a66d9332fdc9b47ffe28ba7ab6090c26747b85f4fab22f936b71eb3f64613d8bd9dfabe9bb68da19de78321b481e5297df9e40ec8a3d662f3e1479c65de0"
},
{
"input_len": 7,
"hash": "3f8770f387faad08faa9d8414e9f449ac68e6ff0417f673f602a646a891419fe66036ef6e6d1a8f54baa9fed1fc11c77cfb9cff65bae915045027046ebe0c01bf5a941f3bb0f73791d3fc0b84370f9f30af0cd5b0fc334dd61f70feb60dad785f070fef1f343ed933b49a5ca0d16a503f599a365a4296739248b28d1a20b0e2cc8975c",
"keyed_hash": "af0a7ec382aedc0cfd626e49e7628bc7a353a4cb108855541a5651bf64fbb28a7c5035ba0f48a9c73dabb2be0533d02e8fd5d0d5639a18b2803ba6bf527e1d145d5fd6406c437b79bcaad6c7bdf1cf4bd56a893c3eb9510335a7a798548c6753f74617bede88bef924ba4b334f8852476d90b26c5dc4c3668a2519266a562c6c8034a6",
"derive_key": "dc3b6485f9d94935329442916b0d059685ba815a1fa2a14107217453a7fc9f0e66266db2ea7c96843f9d8208e600a73f7f45b2f55b9e6d6a7ccf05daae63a3fdd10b25ac0bd2e224ce8291f88c05976d575df998477db86fb2cfbbf91725d62cb57acfeb3c2d973b89b503c2b60dde85a7802b69dc1ac2007d5623cbea8cbfb6b181f5"
},
{
"input_len": 8,
"hash": "2351207d04fc16ade43ccab08600939c7c1fa70a5c0aaca76063d04c3228eaeb725d6d46ceed8f785ab9f2f9b06acfe398c6699c6129da084cb531177445a682894f9685eaf836999221d17c9a64a3a057000524cd2823986db378b074290a1a9b93a22e135ed2c14c7e20c6d045cd00b903400374126676ea78874d79f2dd7883cf5c",
"keyed_hash": "be2f5495c61cba1bb348a34948c004045e3bd4dae8f0fe82bf44d0da245a060048eb5e68ce6dea1eb0229e144f578b3aa7e9f4f85febd135df8525e6fe40c6f0340d13dd09b255ccd5112a94238f2be3c0b5b7ecde06580426a93e0708555a265305abf86d874e34b4995b788e37a823491f25127a502fe0704baa6bfdf04e76c13276",
"derive_key": "2b166978cef14d9d438046c720519d8b1cad707e199746f1562d0c87fbd32940f0e2545a96693a66654225ebbaac76d093bfa9cd8f525a53acb92a861a98c42e7d1c4ae82e68ab691d510012edd2a728f98cd4794ef757e94d6546961b4f280a51aac339cc95b64a92b83cc3f26d8af8dfb4c091c240acdb4d47728d23e7148720ef04"
},
{
"input_len": 63,
"hash": "e9bc37a594daad83be9470df7f7b3798297c3d834ce80ba85d6e207627b7db7b1197012b1e7d9af4d7cb7bdd1f3bb49a90a9b5dec3ea2bbc6eaebce77f4e470cbf4687093b5352f04e4a4570fba233164e6acc36900e35d185886a827f7ea9bdc1e5c3ce88b095a200e62c10c043b3e9bc6cb9b6ac4dfa51794b02ace9f98779040755",
"keyed_hash": "bb1eb5d4afa793c1ebdd9fb08def6c36d10096986ae0cfe148cd101170ce37aea05a63d74a840aecd514f654f080e51ac50fd617d22610d91780fe6b07a26b0847abb38291058c97474ef6ddd190d30fc318185c09ca1589d2024f0a6f16d45f11678377483fa5c005b2a107cb9943e5da634e7046855eaa888663de55d6471371d55d",
"derive_key": "b6451e30b953c206e34644c6803724e9d2725e0893039cfc49584f991f451af3b89e8ff572d3da4f4022199b9563b9d70ebb616efff0763e9abec71b550f1371e233319c4c4e74da936ba8e5bbb29a598e007a0bbfa929c99738ca2cc098d59134d11ff300c39f82e2fce9f7f0fa266459503f64ab9913befc65fddc474f6dc1c67669"
},
{
"input_len": 64,
"hash": "4eed7141ea4a5cd4b788606bd23f46e212af9cacebacdc7d1f4c6dc7f2511b98fc9cc56cb831ffe33ea8e7e1d1df09b26efd2767670066aa82d023b1dfe8ab1b2b7fbb5b97592d46ffe3e05a6a9b592e2949c74160e4674301bc3f97e04903f8c6cf95b863174c33228924cdef7ae47559b10b294acd660666c4538833582b43f82d74",
"keyed_hash": "ba8ced36f327700d213f120b1a207a3b8c04330528586f414d09f2f7d9ccb7e68244c26010afc3f762615bbac552a1ca909e67c83e2fd5478cf46b9e811efccc93f77a21b17a152ebaca1695733fdb086e23cd0eb48c41c034d52523fc21236e5d8c9255306e48d52ba40b4dac24256460d56573d1312319afcf3ed39d72d0bfc69acb",
"derive_key": "a5c4a7053fa86b64746d4bb688d06ad1f02a18fce9afd3e818fefaa7126bf73e9b9493a9befebe0bf0c9509fb3105cfa0e262cde141aa8e3f2c2f77890bb64a4cca96922a21ead111f6338ad5244f2c15c44cb595443ac2ac294231e31be4a4307d0a91e874d36fc9852aeb1265c09b6e0cda7c37ef686fbbcab97e8ff66718be048bb"
},
{
"input_len": 65,
"hash": "de1e5fa0be70df6d2be8fffd0e99ceaa8eb6e8c93a63f2d8d1c30ecb6b263dee0e16e0a4749d6811dd1d6d1265c29729b1b75a9ac346cf93f0e1d7296dfcfd4313b3a227faaaaf7757cc95b4e87a49be3b8a270a12020233509b1c3632b3485eef309d0abc4a4a696c9decc6e90454b53b000f456a3f10079072baaf7a981653221f2c",
"keyed_hash": "c0a4edefa2d2accb9277c371ac12fcdbb52988a86edc54f0716e1591b4326e72d5e795f46a596b02d3d4bfb43abad1e5d19211152722ec1f20fef2cd413e3c22f2fc5da3d73041275be6ede3517b3b9f0fc67ade5956a672b8b75d96cb43294b9041497de92637ed3f2439225e683910cb3ae923374449ca788fb0f9bea92731bc26ad",
"derive_key": "51fd05c3c1cfbc8ed67d139ad76f5cf8236cd2acd26627a30c104dfd9d3ff8a82b02e8bd36d8498a75ad8c8e9b15eb386970283d6dd42c8ae7911cc592887fdbe26a0a5f0bf821cd92986c60b2502c9be3f98a9c133a7e8045ea867e0828c7252e739321f7c2d65daee4468eb4429efae469a42763f1f94977435d10dccae3e3dce88d"
},
{
"input_len": 127,
"hash": "d81293fda863f008c09e92fc382a81f5a0b4a1251cba1634016a0f86a6bd640de3137d477156d1fde56b0cf36f8ef18b44b2d79897bece12227539ac9ae0a5119da47644d934d26e74dc316145dcb8bb69ac3f2e05c242dd6ee06484fcb0e956dc44355b452c5e2bbb5e2b66e99f5dd443d0cbcaaafd4beebaed24ae2f8bb672bcef78",
"keyed_hash": "c64200ae7dfaf35577ac5a9521c47863fb71514a3bcad18819218b818de85818ee7a317aaccc1458f78d6f65f3427ec97d9c0adb0d6dacd4471374b621b7b5f35cd54663c64dbe0b9e2d95632f84c611313ea5bd90b71ce97b3cf645776f3adc11e27d135cbadb9875c2bf8d3ae6b02f8a0206aba0c35bfe42574011931c9a255ce6dc",
"derive_key": "c91c090ceee3a3ac81902da31838012625bbcd73fcb92e7d7e56f78deba4f0c3feeb3974306966ccb3e3c69c337ef8a45660ad02526306fd685c88542ad00f759af6dd1adc2e50c2b8aac9f0c5221ff481565cf6455b772515a69463223202e5c371743e35210bbbbabd89651684107fd9fe493c937be16e39cfa7084a36207c99bea3"
},
{
"input_len": 128,
"hash": "f17e570564b26578c33bb7f44643f539624b05df1a76c81f30acd548c44b45efa69faba091427f9c5c4caa873aa07828651f19c55bad85c47d1368b11c6fd99e47ecba5820a0325984d74fe3e4058494ca12e3f1d3293d0010a9722f7dee64f71246f75e9361f44cc8e214a100650db1313ff76a9f93ec6e84edb7add1cb4a95019b0c",
"keyed_hash": "b04fe15577457267ff3b6f3c947d93be581e7e3a4b018679125eaf86f6a628ecd86bbe0001f10bda47e6077b735016fca8119da11348d93ca302bbd125bde0db2b50edbe728a620bb9d3e6f706286aedea973425c0b9eedf8a38873544cf91badf49ad92a635a93f71ddfcee1eae536c25d1b270956be16588ef1cfef2f1d15f650bd5",
"derive_key": "81720f34452f58a0120a58b6b4608384b5c51d11f39ce97161a0c0e442ca022550e7cd651e312f0b4c6afb3c348ae5dd17d2b29fab3b894d9a0034c7b04fd9190cbd90043ff65d1657bbc05bfdecf2897dd894c7a1b54656d59a50b51190a9da44db426266ad6ce7c173a8c0bbe091b75e734b4dadb59b2861cd2518b4e7591e4b83c9"
},
{
"input_len": 129,
"hash": "683aaae9f3c5ba37eaaf072aed0f9e30bac0865137bae68b1fde4ca2aebdcb12f96ffa7b36dd78ba321be7e842d364a62a42e3746681c8bace18a4a8a79649285c7127bf8febf125be9de39586d251f0d41da20980b70d35e3dac0eee59e468a894fa7e6a07129aaad09855f6ad4801512a116ba2b7841e6cfc99ad77594a8f2d181a7",
"keyed_hash": "d4a64dae6cdccbac1e5287f54f17c5f985105457c1a2ec1878ebd4b57e20d38f1c9db018541eec241b748f87725665b7b1ace3e0065b29c3bcb232c90e37897fa5aaee7e1e8a2ecfcd9b51463e42238cfdd7fee1aecb3267fa7f2128079176132a412cd8aaf0791276f6b98ff67359bd8652ef3a203976d5ff1cd41885573487bcd683",
"derive_key": "938d2d4435be30eafdbb2b7031f7857c98b04881227391dc40db3c7b21f41fc18d72d0f9c1de5760e1941aebf3100b51d64644cb459eb5d20258e233892805eb98b07570ef2a1787cd48e117c8d6a63a68fd8fc8e59e79dbe63129e88352865721c8d5f0cf183f85e0609860472b0d6087cefdd186d984b21542c1c780684ed6832d8d"
},
{
"input_len": 1023,
"hash": "10108970eeda3eb932baac1428c7a2163b0e924c9a9e25b35bba72b28f70bd11a182d27a591b05592b15607500e1e8dd56bc6c7fc063715b7a1d737df5bad3339c56778957d870eb9717b57ea3d9fb68d1b55127bba6a906a4a24bbd5acb2d123a37b28f9e9a81bbaae360d58f85e5fc9d75f7c370a0cc09b6522d9c8d822f2f28f485",
"keyed_hash": "c951ecdf03288d0fcc96ee3413563d8a6d3589547f2c2fb36d9786470f1b9d6e890316d2e6d8b8c25b0a5b2180f94fb1a158ef508c3cde45e2966bd796a696d3e13efd86259d756387d9becf5c8bf1ce2192b87025152907b6d8cc33d17826d8b7b9bc97e38c3c85108ef09f013e01c229c20a83d9e8efac5b37470da28575fd755a10",
"derive_key": "74a16c1c3d44368a86e1ca6df64be6a2f64cce8f09220787450722d85725dea59c413264404661e9e4d955409dfe4ad3aa487871bcd454ed12abfe2c2b1eb7757588cf6cb18d2eccad49e018c0d0fec323bec82bf1644c6325717d13ea712e6840d3e6e730d35553f59eff5377a9c350bcc1556694b924b858f329c44ee64b884ef00d"
},
{
"input_len": 1024,
"hash": "42214739f095a406f3fc83deb889744ac00df831c10daa55189b5d121c855af71cf8107265ecdaf8505b95d8fcec83a98a6a96ea5109d2c179c47a387ffbb404756f6eeae7883b446b70ebb144527c2075ab8ab204c0086bb22b7c93d465efc57f8d917f0b385c6df265e77003b85102967486ed57db5c5ca170ba441427ed9afa684e",
"keyed_hash": "75c46f6f3d9eb4f55ecaaee480db732e6c2105546f1e675003687c31719c7ba4a78bc838c72852d4f49c864acb7adafe2478e824afe51c8919d06168414c265f298a8094b1ad813a9b8614acabac321f24ce61c5a5346eb519520d38ecc43e89b5000236df0597243e4d2493fd626730e2ba17ac4d8824d09d1a4a8f57b8227778e2de",
"derive_key": "7356cd7720d5b66b6d0697eb3177d9f8d73a4a5c5e968896eb6a6896843027066c23b601d3ddfb391e90d5c8eccdef4ae2a264bce9e612ba15e2bc9d654af1481b2e75dbabe615974f1070bba84d56853265a34330b4766f8e75edd1f4a1650476c10802f22b64bd3919d246ba20a17558bc51c199efdec67e80a227251808d8ce5bad"
},
{
"input_len": 1025,
"hash": "d00278ae47eb27b34faecf67b4fe263f82d5412916c1ffd97c8cb7fb814b8444f4c4a22b4b399155358a994e52bf255de60035742ec71bd08ac275a1b51cc6bfe332b0ef84b409108cda080e6269ed4b3e2c3f7d722aa4cdc98d16deb554e5627be8f955c98e1d5f9565a9194cad0c4285f93700062d9595adb992ae68ff12800ab67a",
"keyed_hash": "357dc55de0c7e382c900fd6e320acc04146be01db6a8ce7210b7189bd664ea69362396b77fdc0d2634a552970843722066c3c15902ae5097e00ff53f1e116f1cd5352720113a837ab2452cafbde4d54085d9cf5d21ca613071551b25d52e69d6c81123872b6f19cd3bc1333edf0c52b94de23ba772cf82636cff4542540a7738d5b930",
"derive_key": "effaa245f065fbf82ac186839a249707c3bddf6d3fdda22d1b95a3c970379bcb5d31013a167509e9066273ab6e2123bc835b408b067d88f96addb550d96b6852dad38e320b9d940f86db74d398c770f462118b35d2724efa13da97194491d96dd37c3c09cbef665953f2ee85ec83d88b88d11547a6f911c8217cca46defa2751e7f3ad"
},
{
"input_len": 2048,
"hash": "e776b6028c7cd22a4d0ba182a8bf62205d2ef576467e838ed6f2529b85fba24a9a60bf80001410ec9eea6698cd537939fad4749edd484cb541aced55cd9bf54764d063f23f6f1e32e12958ba5cfeb1bf618ad094266d4fc3c968c2088f677454c288c67ba0dba337b9d91c7e1ba586dc9a5bc2d5e90c14f53a8863ac75655461cea8f9",
"keyed_hash": "879cf1fa2ea0e79126cb1063617a05b6ad9d0b696d0d757cf053439f60a99dd10173b961cd574288194b23ece278c330fbb8585485e74967f31352a8183aa782b2b22f26cdcadb61eed1a5bc144b8198fbb0c13abbf8e3192c145d0a5c21633b0ef86054f42809df823389ee40811a5910dcbd1018af31c3b43aa55201ed4edaac74fe",
"derive_key": "7b2945cb4fef70885cc5d78a87bf6f6207dd901ff239201351ffac04e1088a23e2c11a1ebffcea4d80447867b61badb1383d842d4e79645d48dd82ccba290769caa7af8eaa1bd78a2a5e6e94fbdab78d9c7b74e894879f6a515257ccf6f95056f4e25390f24f6b35ffbb74b766202569b1d797f2d4bd9d17524c720107f985f4ddc583"
},
{
"input_len": 2049,
"hash": "5f4d72f40d7a5f82b15ca2b2e44b1de3c2ef86c426c95c1af0b687952256303096de31d71d74103403822a2e0bc1eb193e7aecc9643a76b7bbc0c9f9c52e8783aae98764ca468962b5c2ec92f0c74eb5448d519713e09413719431c802f948dd5d90425a4ecdadece9eb178d80f26efccae630734dff63340285adec2aed3b51073ad3",
"keyed_hash": "9f29700902f7c86e514ddc4df1e3049f258b2472b6dd5267f61bf13983b78dd5f9a88abfefdfa1e00b418971f2b39c64ca621e8eb37fceac57fd0c8fc8e117d43b81447be22d5d8186f8f5919ba6bcc6846bd7d50726c06d245672c2ad4f61702c646499ee1173daa061ffe15bf45a631e2946d616a4c345822f1151284712f76b2b0e",
"derive_key": "2ea477c5515cc3dd606512ee72bb3e0e758cfae7232826f35fb98ca1bcbdf27316d8e9e79081a80b046b60f6a263616f33ca464bd78d79fa18200d06c7fc9bffd808cc4755277a7d5e09da0f29ed150f6537ea9bed946227ff184cc66a72a5f8c1e4bd8b04e81cf40fe6dc4427ad5678311a61f4ffc39d195589bdbc670f63ae70f4b6"
},
{
"input_len": 3072,
"hash": "b98cb0ff3623be03326b373de6b9095218513e64f1ee2edd2525c7ad1e5cffd29a3f6b0b978d6608335c09dc94ccf682f9951cdfc501bfe47b9c9189a6fc7b404d120258506341a6d802857322fbd20d3e5dae05b95c88793fa83db1cb08e7d8008d1599b6209d78336e24839724c191b2a52a80448306e0daa84a3fdb566661a37e11",
"keyed_hash": "044a0e7b172a312dc02a4c9a818c036ffa2776368d7f528268d2e6b5df19177022f302d0529e4174cc507c463671217975e81dab02b8fdeb0d7ccc7568dd22574c783a76be215441b32e91b9a904be8ea81f7a0afd14bad8ee7c8efc305ace5d3dd61b996febe8da4f56ca0919359a7533216e2999fc87ff7d8f176fbecb3d6f34278b",
"derive_key": "050df97f8c2ead654d9bb3ab8c9178edcd902a32f8495949feadcc1e0480c46b3604131bbd6e3ba573b6dd682fa0a63e5b165d39fc43a625d00207607a2bfeb65ff1d29292152e26b298868e3b87be95d6458f6f2ce6118437b632415abe6ad522874bcd79e4030a5e7bad2efa90a7a7c67e93f0a18fb28369d0a9329ab5c24134ccb0"
},
{
"input_len": 3073,
"hash": "7124b49501012f81cc7f11ca069ec9226cecb8a2c850cfe644e327d22d3e1cd39a27ae3b79d68d89da9bf25bc27139ae65a324918a5f9b7828181e52cf373c84f35b639b7fccbb985b6f2fa56aea0c18f531203497b8bbd3a07ceb5926f1cab74d14bd66486d9a91eba99059a98bd1cd25876b2af5a76c3e9eed554ed72ea952b603bf",
"keyed_hash": "68dede9bef00ba89e43f31a6825f4cf433389fedae75c04ee9f0cf16a427c95a96d6da3fe985054d3478865be9a092250839a697bbda74e279e8a9e69f0025e4cfddd6cfb434b1cd9543aaf97c635d1b451a4386041e4bb100f5e45407cbbc24fa53ea2de3536ccb329e4eb9466ec37093a42cf62b82903c696a93a50b702c80f3c3c5",
"derive_key": "72613c9ec9ff7e40f8f5c173784c532ad852e827dba2bf85b2ab4b76f7079081576288e552647a9d86481c2cae75c2dd4e7c5195fb9ada1ef50e9c5098c249d743929191441301c69e1f48505a4305ec1778450ee48b8e69dc23a25960fe33070ea549119599760a8a2d28aeca06b8c5e9ba58bc19e11fe57b6ee98aa44b2a8e6b14a5"
},
{
"input_len": 4096,
"hash": "015094013f57a5277b59d8475c0501042c0b642e531b0a1c8f58d2163229e9690289e9409ddb1b99768eafe1623da896faf7e1114bebeadc1be30829b6f8af707d85c298f4f0ff4d9438aef948335612ae921e76d411c3a9111df62d27eaf871959ae0062b5492a0feb98ef3ed4af277f5395172dbe5c311918ea0074ce0036454f620",
"keyed_hash": "befc660aea2f1718884cd8deb9902811d332f4fc4a38cf7c7300d597a081bfc0bbb64a36edb564e01e4b4aaf3b060092a6b838bea44afebd2deb8298fa562b7b597c757b9df4c911c3ca462e2ac89e9a787357aaf74c3b56d5c07bc93ce899568a3eb17d9250c20f6c5f6c1e792ec9a2dcb715398d5a6ec6d5c54f586a00403a1af1de",
"derive_key": "1e0d7f3db8c414c97c6307cbda6cd27ac3b030949da8e23be1a1a924ad2f25b9d78038f7b198596c6cc4a9ccf93223c08722d684f240ff6569075ed81591fd93f9fff1110b3a75bc67e426012e5588959cc5a4c192173a03c00731cf84544f65a2fb9378989f72e9694a6a394a8a30997c2e67f95a504e631cd2c5f55246024761b245"
},
{
"input_len": 4097,
"hash": "9b4052b38f1c5fc8b1f9ff7ac7b27cd242487b3d890d15c96a1c25b8aa0fb99505f91b0b5600a11251652eacfa9497b31cd3c409ce2e45cfe6c0a016967316c426bd26f619eab5d70af9a418b845c608840390f361630bd497b1ab44019316357c61dbe091ce72fc16dc340ac3d6e009e050b3adac4b5b2c92e722cffdc46501531956",
"keyed_hash": "00df940cd36bb9fa7cbbc3556744e0dbc8191401afe70520ba292ee3ca80abbc606db4976cfdd266ae0abf667d9481831ff12e0caa268e7d3e57260c0824115a54ce595ccc897786d9dcbf495599cfd90157186a46ec800a6763f1c59e36197e9939e900809f7077c102f888caaf864b253bc41eea812656d46742e4ea42769f89b83f",
"derive_key": "aca51029626b55fda7117b42a7c211f8c6e9ba4fe5b7a8ca922f34299500ead8a897f66a400fed9198fd61dd2d58d382458e64e100128075fc54b860934e8de2e84170734b06e1d212a117100820dbc48292d148afa50567b8b84b1ec336ae10d40c8c975a624996e12de31abbe135d9d159375739c333798a80c64ae895e51e22f3ad"
},
{
"input_len": 5120,
"hash": "9cadc15fed8b5d854562b26a9536d9707cadeda9b143978f319ab34230535833acc61c8fdc114a2010ce8038c853e121e1544985133fccdd0a2d507e8e615e611e9a0ba4f47915f49e53d721816a9198e8b30f12d20ec3689989175f1bf7a300eee0d9321fad8da232ece6efb8e9fd81b42ad161f6b9550a069e66b11b40487a5f5059",
"keyed_hash": "2c493e48e9b9bf31e0553a22b23503c0a3388f035cece68eb438d22fa1943e209b4dc9209cd80ce7c1f7c9a744658e7e288465717ae6e56d5463d4f80cdb2ef56495f6a4f5487f69749af0c34c2cdfa857f3056bf8d807336a14d7b89bf62bef2fb54f9af6a546f818dc1e98b9e07f8a5834da50fa28fb5874af91bf06020d1bf0120e",
"derive_key": "7a7acac8a02adcf3038d74cdd1d34527de8a0fcc0ee3399d1262397ce5817f6055d0cefd84d9d57fe792d65a278fd20384ac6c30fdb340092f1a74a92ace99c482b28f0fc0ef3b923e56ade20c6dba47e49227166251337d80a037e987ad3a7f728b5ab6dfafd6e2ab1bd583a95d9c895ba9c2422c24ea0f62961f0dca45cad47bfa0d"
},
{
"input_len": 5121,
"hash": "628bd2cb2004694adaab7bbd778a25df25c47b9d4155a55f8fbd79f2fe154cff96adaab0613a6146cdaabe498c3a94e529d3fc1da2bd08edf54ed64d40dcd6777647eac51d8277d70219a9694334a68bc8f0f23e20b0ff70ada6f844542dfa32cd4204ca1846ef76d811cdb296f65e260227f477aa7aa008bac878f72257484f2b6c95",
"keyed_hash": "6ccf1c34753e7a044db80798ecd0782a8f76f33563accaddbfbb2e0ea4b2d0240d07e63f13667a8d1490e5e04f13eb617aea16a8c8a5aaed1ef6fbde1b0515e3c81050b361af6ead126032998290b563e3caddeaebfab592e155f2e161fb7cba939092133f23f9e65245e58ec23457b78a2e8a125588aad6e07d7f11a85b88d375b72d",
"derive_key": "b07f01e518e702f7ccb44a267e9e112d403a7b3f4883a47ffbed4b48339b3c341a0add0ac032ab5aaea1e4e5b004707ec5681ae0fcbe3796974c0b1cf31a194740c14519273eedaabec832e8a784b6e7cfc2c5952677e6c3f2c3914454082d7eb1ce1766ac7d75a4d3001fc89544dd46b5147382240d689bbbaefc359fb6ae30263165"
},
{
"input_len": 6144,
"hash": "3e2e5b74e048f3add6d21faab3f83aa44d3b2278afb83b80b3c35164ebeca2054d742022da6fdda444ebc384b04a54c3ac5839b49da7d39f6d8a9db03deab32aade156c1c0311e9b3435cde0ddba0dce7b26a376cad121294b689193508dd63151603c6ddb866ad16c2ee41585d1633a2cea093bea714f4c5d6b903522045b20395c83",
"keyed_hash": "3d6b6d21281d0ade5b2b016ae4034c5dec10ca7e475f90f76eac7138e9bc8f1dc35754060091dc5caf3efabe0603c60f45e415bb3407db67e6beb3d11cf8e4f7907561f05dace0c15807f4b5f389c841eb114d81a82c02a00b57206b1d11fa6e803486b048a5ce87105a686dee041207e095323dfe172df73deb8c9532066d88f9da7e",
"derive_key": "2a95beae63ddce523762355cf4b9c1d8f131465780a391286a5d01abb5683a1597099e3c6488aab6c48f3c15dbe1942d21dbcdc12115d19a8b8465fb54e9053323a9178e4275647f1a9927f6439e52b7031a0b465c861a3fc531527f7758b2b888cf2f20582e9e2c593709c0a44f9c6e0f8b963994882ea4168827823eef1f64169fef"
},
{
"input_len": 6145,
"hash": "f1323a8631446cc50536a9f705ee5cb619424d46887f3c376c695b70e0f0507f18a2cfdd73c6e39dd75ce7c1c6e3ef238fd54465f053b25d21044ccb2093beb015015532b108313b5829c3621ce324b8e14229091b7c93f32db2e4e63126a377d2a63a3597997d4f1cba59309cb4af240ba70cebff9a23d5e3ff0cdae2cfd54e070022",
"keyed_hash": "9ac301e9e39e45e3250a7e3b3df701aa0fb6889fbd80eeecf28dbc6300fbc539f3c184ca2f59780e27a576c1d1fb9772e99fd17881d02ac7dfd39675aca918453283ed8c3169085ef4a466b91c1649cc341dfdee60e32231fc34c9c4e0b9a2ba87ca8f372589c744c15fd6f985eec15e98136f25beeb4b13c4e43dc84abcc79cd4646c",
"derive_key": "379bcc61d0051dd489f686c13de00d5b14c505245103dc040d9e4dd1facab8e5114493d029bdbd295aaa744a59e31f35c7f52dba9c3642f773dd0b4262a9980a2aef811697e1305d37ba9d8b6d850ef07fe41108993180cf779aeece363704c76483458603bbeeb693cffbbe5588d1f3535dcad888893e53d977424bb707201569a8d2"
},
{
"input_len": 7168,
"hash": "61da957ec2499a95d6b8023e2b0e604ec7f6b50e80a9678b89d2628e99ada77a5707c321c83361793b9af62a40f43b523df1c8633cecb4cd14d00bdc79c78fca5165b863893f6d38b02ff7236c5a9a8ad2dba87d24c547cab046c29fc5bc1ed142e1de4763613bb162a5a538e6ef05ed05199d751f9eb58d332791b8d73fb74e4fce95",
"keyed_hash": "b42835e40e9d4a7f42ad8cc04f85a963a76e18198377ed84adddeaecacc6f3fca2f01d5277d69bb681c70fa8d36094f73ec06e452c80d2ff2257ed82e7ba348400989a65ee8daa7094ae0933e3d2210ac6395c4af24f91c2b590ef87d7788d7066ea3eaebca4c08a4f14b9a27644f99084c3543711b64a070b94f2c9d1d8a90d035d52",
"derive_key": "11c37a112765370c94a51415d0d651190c288566e295d505defdad895dae223730d5a5175a38841693020669c7638f40b9bc1f9f39cf98bda7a5b54ae24218a800a2116b34665aa95d846d97ea988bfcb53dd9c055d588fa21ba78996776ea6c40bc428b53c62b5f3ccf200f647a5aae8067f0ea1976391fcc72af1945100e2a6dcb88"
},
{
"input_len": 7169,
"hash": "a003fc7a51754a9b3c7fae0367ab3d782dccf28855a03d435f8cfe74605e781798a8b20534be1ca9eb2ae2df3fae2ea60e48c6fb0b850b1385b5de0fe460dbe9d9f9b0d8db4435da75c601156df9d047f4ede008732eb17adc05d96180f8a73548522840779e6062d643b79478a6e8dbce68927f36ebf676ffa7d72d5f68f050b119c8",
"keyed_hash": "ed9b1a922c046fdb3d423ae34e143b05ca1bf28b710432857bf738bcedbfa5113c9e28d72fcbfc020814ce3f5d4fc867f01c8f5b6caf305b3ea8a8ba2da3ab69fabcb438f19ff11f5378ad4484d75c478de425fb8e6ee809b54eec9bdb184315dc856617c09f5340451bf42fd3270a7b0b6566169f242e533777604c118a6358250f54",
"derive_key": "554b0a5efea9ef183f2f9b931b7497995d9eb26f5c5c6dad2b97d62fc5ac31d99b20652c016d88ba2a611bbd761668d5eda3e568e940faae24b0d9991c3bd25a65f770b89fdcadabcb3d1a9c1cb63e69721cacf1ae69fefdcef1e3ef41bc5312ccc17222199e47a26552c6adc460cf47a72319cb5039369d0060eaea59d6c65130f1dd"
},
{
"input_len": 8192,
"hash": "aae792484c8efe4f19e2ca7d371d8c467ffb10748d8a5a1ae579948f718a2a635fe51a27db045a567c1ad51be5aa34c01c6651c4d9b5b5ac5d0fd58cf18dd61a47778566b797a8c67df7b1d60b97b19288d2d877bb2df417ace009dcb0241ca1257d62712b6a4043b4ff33f690d849da91ea3bf711ed583cb7b7a7da2839ba71309bbf",
"keyed_hash": "dc9637c8845a770b4cbf76b8daec0eebf7dc2eac11498517f08d44c8fc00d58a4834464159dcbc12a0ba0c6d6eb41bac0ed6585cabfe0aca36a375e6c5480c22afdc40785c170f5a6b8a1107dbee282318d00d915ac9ed1143ad40765ec120042ee121cd2baa36250c618adaf9e27260fda2f94dea8fb6f08c04f8f10c78292aa46102",
"derive_key": "ad01d7ae4ad059b0d33baa3c01319dcf8088094d0359e5fd45d6aeaa8b2d0c3d4c9e58958553513b67f84f8eac653aeeb02ae1d5672dcecf91cd9985a0e67f4501910ecba25555395427ccc7241d70dc21c190e2aadee875e5aae6bf1912837e53411dabf7a56cbf8e4fb780432b0d7fe6cec45024a0788cf5874616407757e9e6bef7"
},
{
"input_len": 8193,
"hash": "bab6c09cb8ce8cf459261398d2e7aef35700bf488116ceb94a36d0f5f1b7bc3bb2282aa69be089359ea1154b9a9286c4a56af4de975a9aa4a5c497654914d279bea60bb6d2cf7225a2fa0ff5ef56bbe4b149f3ed15860f78b4e2ad04e158e375c1e0c0b551cd7dfc82f1b155c11b6b3ed51ec9edb30d133653bb5709d1dbd55f4e1ff6",
"keyed_hash": "954a2a75420c8d6547e3ba5b98d963e6fa6491addc8c023189cc519821b4a1f5f03228648fd983aef045c2fa8290934b0866b615f585149587dda2299039965328835a2b18f1d63b7e300fc76ff260b571839fe44876a4eae66cbac8c67694411ed7e09df51068a22c6e67d6d3dd2cca8ff12e3275384006c80f4db68023f24eebba57",
"derive_key": "af1e0346e389b17c23200270a64aa4e1ead98c61695d917de7d5b00491c9b0f12f20a01d6d622edf3de026a4db4e4526225debb93c1237934d71c7340bb5916158cbdafe9ac3225476b6ab57a12357db3abbad7a26c6e66290e44034fb08a20a8d0ec264f309994d2810c49cfba6989d7abb095897459f5425adb48aba07c5fb3c83c0"
},
{
"input_len": 16384,
"hash": "f875d6646de28985646f34ee13be9a576fd515f76b5b0a26bb324735041ddde49d764c270176e53e97bdffa58d549073f2c660be0e81293767ed4e4929f9ad34bbb39a529334c57c4a381ffd2a6d4bfdbf1482651b172aa883cc13408fa67758a3e47503f93f87720a3177325f7823251b85275f64636a8f1d599c2e49722f42e93893",
"keyed_hash": "9e9fc4eb7cf081ea7c47d1807790ed211bfec56aa25bb7037784c13c4b707b0df9e601b101e4cf63a404dfe50f2e1865bb12edc8fca166579ce0c70dba5a5c0fc960ad6f3772183416a00bd29d4c6e651ea7620bb100c9449858bf14e1ddc9ecd35725581ca5b9160de04060045993d972571c3e8f71e9d0496bfa744656861b169d65",
"derive_key": "160e18b5878cd0df1c3af85eb25a0db5344d43a6fbd7a8ef4ed98d0714c3f7e160dc0b1f09caa35f2f417b9ef309dfe5ebd67f4c9507995a531374d099cf8ae317542e885ec6f589378864d3ea98716b3bbb65ef4ab5e0ab5bb298a501f19a41ec19af84a5e6b428ecd813b1a47ed91c9657c3fba11c406bc316768b58f6802c9e9b57"
},
{
"input_len": 31744,
"hash": "62b6960e1a44bcc1eb1a611a8d6235b6b4b78f32e7abc4fb4c6cdcce94895c47860cc51f2b0c28a7b77304bd55fe73af663c02d3f52ea053ba43431ca5bab7bfea2f5e9d7121770d88f70ae9649ea713087d1914f7f312147e247f87eb2d4ffef0ac978bf7b6579d57d533355aa20b8b77b13fd09748728a5cc327a8ec470f4013226f",
"keyed_hash": "efa53b389ab67c593dba624d898d0f7353ab99e4ac9d42302ee64cbf9939a4193a7258db2d9cd32a7a3ecfce46144114b15c2fcb68a618a976bd74515d47be08b628be420b5e830fade7c080e351a076fbc38641ad80c736c8a18fe3c66ce12f95c61c2462a9770d60d0f77115bbcd3782b593016a4e728d4c06cee4505cb0c08a42ec",
"derive_key": "39772aef80e0ebe60596361e45b061e8f417429d529171b6764468c22928e28e9759adeb797a3fbf771b1bcea30150a020e317982bf0d6e7d14dd9f064bc11025c25f31e81bd78a921db0174f03dd481d30e93fd8e90f8b2fee209f849f2d2a52f31719a490fb0ba7aea1e09814ee912eba111a9fde9d5c274185f7bae8ba85d300a2b"
},
{
"input_len": 102400,
"hash": "bc3e3d41a1146b069abffad3c0d44860cf664390afce4d9661f7902e7943e085e01c59dab908c04c3342b816941a26d69c2605ebee5ec5291cc55e15b76146e6745f0601156c3596cb75065a9c57f35585a52e1ac70f69131c23d611ce11ee4ab1ec2c009012d236648e77be9295dd0426f29b764d65de58eb7d01dd42248204f45f8e",
"keyed_hash": "1c35d1a5811083fd7119f5d5d1ba027b4d01c0c6c49fb6ff2cf75393ea5db4a7f9dbdd3e1d81dcbca3ba241bb18760f207710b751846faaeb9dff8262710999a59b2aa1aca298a032d94eacfadf1aa192418eb54808db23b56e34213266aa08499a16b354f018fc4967d05f8b9d2ad87a7278337be9693fc638a3bfdbe314574ee6fc4",
"derive_key": "4652cff7a3f385a6103b5c260fc1593e13c778dbe608efb092fe7ee69df6e9c6d83a3e041bc3a48df2879f4a0a3ed40e7c961c73eff740f3117a0504c2dff4786d44fb17f1549eb0ba585e40ec29bf7732f0b7e286ff8acddc4cb1e23b87ff5d824a986458dcc6a04ac83969b80637562953df51ed1a7e90a7926924d2763778be8560"
}
]]
local key = "whats the Elvish word for friend"
local context_string = "BLAKE3 2019-12-27 16:29:52 test vectors context"
local input = ("\0"..("."):rep(250):gsub("().", string.char)):rep(math.ceil(102400 / 251))
local cnt = 0
for vec in test_vectors:gmatch'%b{}' do
local input_len, hash, keyed_hash, derive_key = assert(vec:match'"input_len": (%d+),%s*"hash": "(%x+)",%s*"keyed_hash": "(%x+)",%s*"derive_key": "(%x+)"')
local input = input:sub(1, tonumber(input_len))
assert(hash == b3.blake3(input, nil, #hash / 2))
assert(keyed_hash == b3.blake3(input, key, #keyed_hash / 2))
assert(derive_key == b3.blake3_derive_key(input, context_string, #derive_key / 2))
cnt = cnt + 1
end
assert(cnt == 35)
end
print"All BLAKE3 tests were passed successfully"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment