hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit bdcabe65573c3fd5f63c01a963afb899dea2754d
parent f37b4746f4e762593d6a58997bcdff30b9f08a31
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Mon, 20 Dec 2021 18:57:27 +0100

implement version 1.3 of crypto::argon2

The implemenation is based on the rfc9106. Comments and parameter
choice guidelines have been taken or derived from the rfc.

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>
Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Acrypto/argon2/+test.ha | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acrypto/argon2/README | 21+++++++++++++++++++++
Acrypto/argon2/argon2.ha | 506+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/gen-stdlib | 13+++++++++++++
Mstdlib.mk | 33+++++++++++++++++++++++++++++++++
5 files changed, 701 insertions(+), 0 deletions(-)

diff --git a/crypto/argon2/+test.ha b/crypto/argon2/+test.ha @@ -0,0 +1,128 @@ +use bytes; + +@test fn mode_d_one_pass() void = { + let pass: [32]u8 = [1...]; + let salt: [16]u8 = [2...]; + let secret: [8]u8 = [3...]; + let data: [12]u8 = [4...]; + let result: [32]u8 = [0...]; + + let expected: [_]u8 = [ + 0xfa, 0x17, 0x75, 0xca, 0x80, 0x90, 0x64, 0x66, 0x18, 0xbe, + 0x70, 0xeb, 0x0f, 0xc9, 0xde, 0x43, 0x67, 0x58, 0xed, 0x0c, + 0xa5, 0x36, 0x83, 0x1a, 0xe9, 0xe1, 0x03, 0x48, 0x93, 0x81, + 0xc1, 0x79, + ]; + + let cfg = config { + secret = secret, + data = data, + passes = 1, + parallel = 4, + version = 0x13, + mem = 32, + ... + }; + + argon2d(result[..], pass, salt, cfg)!; + + assert(bytes::equal(result, expected)); +}; + +@test fn rfc_d_test_vector() void = { + let pass: [32]u8 = [1...]; + let salt: [16]u8 = [2...]; + let secret: [8]u8 = [3...]; + let data: [12]u8 = [4...]; + let result: [32]u8 = [0...]; + + let mem: *[32 * BLOCKSIZE]u64 = alloc([0...]); + defer free(mem); + + let expected: [_]u8 = [ + 0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97, 0x53, 0x71, + 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94, 0xf8, 0x68, 0xe3, 0xbe, + 0x39, 0x84, 0xf3, 0xc1, 0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, + 0x4a, 0xcb, + ]; + + let cfg = config { + secret = secret, + data = data, + passes = 3, + parallel = 4, + version = 0x13, + mem = mem[..], + ... + }; + + argon2d(result[..], pass, salt, cfg)!; + + assert(bytes::equal(result, expected)); +}; + + +@test fn rfc_i_test_vector() void = { + let pass: [32]u8 = [1...]; + let salt: [16]u8 = [2...]; + let secret: [8]u8 = [3...]; + let data: [12]u8 = [4...]; + let result: [32]u8 = [0...]; + + let mem: *[32 * BLOCKSIZE]u64 = alloc([0...]); + defer free(mem); + + let expected: [_]u8 = [ + 0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa, 0x13, 0xf0, + 0xd7, 0x7f, 0x24, 0x94, 0xbd, 0xa1, 0xc8, 0xde, 0x6b, 0x01, + 0x6d, 0xd3, 0x88, 0xd2, 0x99, 0x52, 0xa4, 0xc4, 0x67, 0x2b, + 0x6c, 0xe8, + ]; + + let cfg = config { + secret = secret, + data = data, + passes = 3, + parallel = 4, + version = 0x13, + mem = mem[..], + ... + }; + + argon2i(result[..], pass, salt, cfg)!; + + assert(bytes::equal(result, expected)); +}; + +@test fn rfc_id_test_vector() void = { + let pass: [32]u8 = [1...]; + let salt: [16]u8 = [2...]; + let secret: [8]u8 = [3...]; + let data: [12]u8 = [4...]; + let result: [32]u8 = [0...]; + + let mem: *[32 * BLOCKSIZE]u64 = alloc([0...]); + defer free(mem); + + let expected: [_]u8 = [ + 0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c, 0x08, 0xc0, + 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9, 0xd0, 0x1e, 0xf0, 0x45, + 0x2d, 0x75, 0xb6, 0x5e, 0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, + 0xe6, 0x59, + ]; + + let cfg = config { + secret = secret, + data = data, + passes = 3, + parallel = 4, + version = 0x13, + mem = mem[..], + ... + }; + + argon2id(result[..], pass, salt, cfg)!; + + assert(bytes::equal(result, expected)); +}; + diff --git a/crypto/argon2/README b/crypto/argon2/README @@ -0,0 +1,21 @@ +This module provides an implementation of the argon2 key derivation function as +described by RFC 9106. This is the recommended algorithm for password hashing in +Hare programs, and for deriving keys for use with other cryptographic +algorithms. Some thought must be given to the appropriate configuration for your +use case. Some general advice is provided here; if in doubt, consult the RFC. + +The argon2 parameters are configured via the [[config]] structure. To determine +the appropriate configuration parameters for a particular use-case, consult +section 4 of the RFC. Otherwise, sane defaults for common scenarios are provided +via [[default_config]] and [[low_mem_config]]; consult the docs of each +configuration for details. + +Once a suitable configuration has been selected, the user must provide a salt. +This salt should be stored alongside the hash, should be unique for each +password, and should be random: see [[crypto::random]]. The salt and hash +lengths are configurable, the recommended defaults are 16 and 32 bytes +respectively. + +Equipped with the necessary parameters, the user may call the appropriate argon2 +variant via [[argon2d]], [[argon2i]], or [[argon2id]]. If unsure which to use, +choose [[argon2i]]. diff --git a/crypto/argon2/argon2.ha b/crypto/argon2/argon2.ha @@ -0,0 +1,506 @@ +use bufio; +use bytes; +use crypto::blake2b; +use crypto::math; +use endian; +use errors::{nomem}; +use hash; +use io; +use rt; +use types; + +// Current implemented version of argon2 +export def VERSION: u8 = 0x13; + +// Number of u64 elements of one block. +export def BLOCKSIZE: u32 = 128; + +def SLICES: size = 4; + +type block64 = [BLOCKSIZE]u64; + +const zeroblock: block64 = [0...]; + +type mode = enum { + D = 0, + I = 1, + ID = 2, +}; + +// This type provides configuration options for the argon2 algorithm. Most users +// will find [[default_config]] or [[low_mem_config]] suitable for their needs +// without providing a custom configuration. If writing a custom configuration, +// consult the RFC for advice on selecting suitable values for your use-case. +// +// 'parallel' specifies the number of parallel processes. 'pass' configures the +// number of iterations. Both values must be at least one. Note: the Hare +// implementation of argon2 does not process hashes in parallel, though it will +// still compute the correct hash if this value is greater than one. +// +// 'version' specifies the version of the argon2 function. The implementation +// currently only supports version 1.3. Use [[argon2::VERSION]] here. +// +// 'secret' and 'data' are optional byte arrays that are applied to the initial +// state. Consult the RFC for details. +// +// The 'mem' parameter is used to configure working memory used during the +// computation. The argon2 algorithm requires a large amount of memory to +// compute hashes. If 'mem' set to a u32, it is interpreted as the desired +// number of 1024-byte blocks the implementation shall allocate for you. If the +// caller wants to manage the allocation itself, provide a []u8 instead. The +// length of this slice must be at least 8 times the value of 'parallel' in +// blocks, and must be a multiple of [[BLOCKSIZE]]. To have the implementation +// allocate 64 KiB, set 'mem' to 64. To use the same amount of caller-provided +// memory, provide a slice of length 64 * [[BLOCKSIZE]]. +export type config = struct { + mem: (u32 | []u64), + parallel: u32, + passes: u32, + version: u8, + secret: []u8, + data: []u8 +}; + +// The default recommended configuration for most use cases. This configuration +// uses 2 GiB of working memory. A 16-byte 'salt' and 32-byte 'dest' parameter +// is recommended in combination with this configuration. +export const default_config: config = config { + mem = 2 * 1024 * 1024, + passes = 1, + parallel = 4, + version = 0x13, + ... +}; + +// The default recommended configuration for memory-constrained use cases. This +// configuration uses 64 MiB of working memory. A 16-byte 'salt' and 32-byte +// 'dest' parameter is recommended in combination with this configuration. +export const low_mem_config: config = config { + mem = 64 * 1024, + passes = 3, + parallel = 4, + version = 0x13, + ... +}; + +type context = struct { + mode: mode, + cols: size, + rows: size, + sliceblocks: size, + mem: []u64, + pass: u32, + seedsinit: block64, + seedblock: block64, +}; + +// Computes an argon2d hash, writing the digest to 'dest'. A 'salt' length of 16 +// bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 bytes +// is recommended, and 4 bytes is the minimum. +// +// The argon2d mode uses data-dependent memory access and is suitable for +// applications with no threats of side-channel timing attacks. +export fn argon2d( + dest: []u8, + password: []u8, + salt: []u8, + cfg: config +) (void | nomem) = { + return argon2(dest, password, salt, cfg, mode::D); +}; + +// Computes an argon2i hash, writing the digest to 'dest'. A 'salt' length of 16 +// bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 bytes +// is recommended, and 4 bytes is the minimum. +// +// The argon2i mode uses data-independent memory access and is suitable for +// password hashing and key derivation. It makes more passes over memory to +// protect from trade-off attacks. +// +// If you are unsure which variant to use, argon2i is recommended. +export fn argon2i( + dest: []u8, + password: []u8, + salt: []u8, + cfg: config +) (void | nomem) = { + return argon2(dest, password, salt, cfg, mode::I); +}; + +// Computes an argon2id hash, writing the digest to 'dest'. A 'salt' length of +// 16 bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 +// bytes is recommended, and 4 bytes is the minimum. +// +// The argon2id mode works by using argon2i for the first half of the first pass +// and argon2d further on. It provides therefore protection from side-channel +// attacks and brute-force cost savings due to memory trade-offs. +export fn argon2id( + dest: []u8, + password: []u8, + salt: []u8, + cfg: config +) (void | nomem) = { + return argon2(dest, password, salt, cfg, mode::ID); +}; + +fn argon2( + dest: []u8, + password: []u8, + salt: []u8, + cfg: config, + mode: mode, +) (void | nomem) = { + assert(endian::host == &endian::little, "TODO big endian support"); + + assert(len(dest) >= 4 && len(dest) <= types::U32_MAX); + assert(len(password) <= types::U32_MAX); + assert(len(salt) >= 8 && len(salt) <= types::U32_MAX); + assert(cfg.parallel >= 1); + assert(cfg.passes >= 1); + assert(len(cfg.secret) <= types::U32_MAX); + assert(len(cfg.data) <= types::U32_MAX); + + let mem: []u64 = match (cfg.mem) { + case let mem: []u64 => + assert(len(mem) >= 8 * cfg.parallel * BLOCKSIZE + && len(mem) % BLOCKSIZE == 0 + && len(mem) / BLOCKSIZE <= types::U32_MAX); + yield mem; + case let memsize: u32 => + assert(memsize >= 8 * cfg.parallel + && memsize <= types::U32_MAX); + + // TODO https://todo.sr.ht/~sircmpwn/hare/285 + let membytes = memsize * BLOCKSIZE * 8; + let mem = match (rt::malloc(membytes): nullable *[*]u64) { + case null => + return nomem; + case let mem: *[*]u64 => + yield mem; + }; + yield mem[..membytes / 8]; + }; + // round down memory to nearest multiple of 4 times parallel + mem = mem[..len(mem) - len(mem) % (4 * cfg.parallel * BLOCKSIZE)]; + const memsize = (len(mem) / BLOCKSIZE): u32; + + let h0: [64]u8 = [0...]; + inithash(&h0, len(dest): u32, password, salt, cfg, mode, memsize); + + const cols = 4 * (memsize / (4 * cfg.parallel)); + let ctx = context { + rows = cfg.parallel, + cols = cols, + sliceblocks = cols / 4, + pass = 0, + mem = mem, + mode = mode, + seedsinit = [0...], + seedblock = [0...], + ... + }; + + // hash first and second blocks of each row + for (let i = 0z; i < ctx.rows; i += 1) { + let src: [72]u8 = [0...]; + src[..64] = h0[..]; + + endian::leputu32(src[64..68], 0); + endian::leputu32(src[68..], i: u32); + varhash(blocku8(&ctx, i, 0), src); + + endian::leputu32(src[64..68], 1); + endian::leputu32(src[68..], i: u32); + varhash(blocku8(&ctx, i, 1), src); + }; + + // process segments + for (ctx.pass < cfg.passes; ctx.pass += 1) { + for (let s = 0z; s < SLICES; s += 1) { + for (let i = 0z; i < ctx.rows; i += 1) { + segproc(&cfg, &ctx, i, s); + }; + }; + }; + + // final hash + let b = blocku8(&ctx, 0, ctx.cols - 1); + for (let i = 1z; i < ctx.rows; i += 1) { + math::xor(b, b, blocku8(&ctx, i, ctx.cols - 1)); + }; + + varhash(dest, b); + + bytes::zero((h0: []u64: *[*]u8)[..len(h0) * size(u64)]); + bytes::zero((ctx.mem: *[*]u8)[..len(ctx.mem) * size(u64)]); + + if (cfg.mem is u32) { + // mem was allocated internally + free(ctx.mem); + }; +}; + +fn block(ctx: *context, i: size, j: size) []u64 = { + let index = (ctx.cols * i + j) * BLOCKSIZE; + return ctx.mem[index..index + BLOCKSIZE]; +}; + +fn blocku8(ctx: *context, i: size, j: size) []u8 = { + return (block(ctx, i, j): *[*]u8)[..BLOCKSIZE * size(u64)]; +}; + +fn refblock(cfg: *config, ctx: *context, seed: u64, i: size, j: size) []u64 = { + const j1: u64 = seed & 0xffffffff; + const segstart = j - (j % ctx.sliceblocks); + + const l: u64 = if (segstart == 0 && ctx.pass == 0) { + yield 0; + } else { + yield (seed >> 32) % cfg.parallel; + }; + + let poolstart: u64 = 0; + let poolsize: u64 = segstart; + if (ctx.pass > 0) { + poolstart = (segstart + ctx.sliceblocks) % ctx.cols; + poolsize = 3 * ctx.sliceblocks; + }; + + if (l == i: u64) { + poolsize += (j - segstart); + }; + + if ((j - segstart) == 0 || l == i: u64) { + poolsize -= 1; + }; + + const x: u64 = (j1 * j1) >> 32; + const y: u64 = (poolsize * x) >> 32; + const z: u64 = (poolstart + poolsize - (y+1)) % ctx.cols: u64; + + return block(ctx, l: size, z: size); +}; + +fn inithash( + dest: *[64]u8, + taglen: u32, + password: []u8, + salt: []u8, + cfg: config, + mode: mode, + memsize: u32, +) void = { + let u32buf: [4]u8 = [0...]; + let h = blake2b::blake2b([], 64); + + hash_leputu32(&h, cfg.parallel); + hash_leputu32(&h, taglen); + hash_leputu32(&h, memsize); + hash_leputu32(&h, cfg.passes); + hash_leputu32(&h, cfg.version); + hash_leputu32(&h, mode: u32); + hash_leputu32(&h, len(password): u32); + hash::write(&h, password); + + hash_leputu32(&h, len(salt): u32); + hash::write(&h, salt); + + hash_leputu32(&h, len(cfg.secret): u32); + hash::write(&h, cfg.secret); + + hash_leputu32(&h, len(cfg.data): u32); + hash::write(&h, cfg.data); + + hash::finish(&h, dest[..]); +}; + +fn hash_leputu32(h: *hash::hash, u: u32) void = { + let buf: [4]u8 = [0...]; + endian::leputu32(buf, u); + hash::write(h, buf[..]); +}; + +// The variable hash function H' +fn varhash(dest: []u8, block: []u8) void = { + let u32buf: [4]u8 = [0...]; + + if (len(dest) <= 64) { + let h = blake2b::blake2b([], len(dest)); + hash_leputu32(&h, len(dest): u32); + hash::write(&h, block); + hash::finish(&h, dest); + return; + }; + + // TODO this may be replaced with a constant time divceil in future to + // avoid leaking the dest len. + const r = divceil(len(dest): u32, 32) - 2; + let v: [64]u8 = [0...]; + let h = blake2b::blake2b([], 64); + let destbuf = bufio::fixed(dest, io::mode::WRITE); + defer io::close(destbuf); + + hash_leputu32(&h, len(dest): u32); + hash::write(&h, block); + hash::sum(&h, v[..]); + + io::write(destbuf, v[..32])!; + + for (let i = 1z; i < r; i += 1) { + hash::reset(&h); + hash::write(&h, v[..]); + hash::sum(&h, v[..]); + io::write(destbuf, v[..32])!; + }; + + const remainder = len(dest) - 32 * r; + let hend = blake2b::blake2b([], remainder); + hash::write(&hend, v[..]); + hash::finish(&hend, v[..remainder]); + io::write(destbuf, v[..remainder])!; +}; + +fn divceil(dividend: u32, divisor: u32) u32 = { + let result = dividend / divisor; + if (dividend % divisor > 0) { + result += 1; + }; + return result; +}; + +fn xorblock(dest: []u64, x: []u64, y: []u64) void = { + math::xor((dest: *[*]u8)[..len(dest) * size(u64)], + (x: *[*]u8)[..len(dest) * size(u64)], + (y: *[*]u8)[..len(dest) * size(u64)]); +}; + +fn segproc(cfg: *config, ctx: *context, i: size, slice: size) void = { + const init = switch (ctx.mode) { + case mode::I => + yield true; + case mode::ID => + yield ctx.pass == 0 && slice <= 2; + case mode::D => + yield false; + }; + if (init) { + ctx.seedsinit[0] = ctx.pass; + ctx.seedsinit[1] = i; + ctx.seedsinit[2] = slice; + ctx.seedsinit[3] = len(ctx.mem) / BLOCKSIZE; + ctx.seedsinit[4] = cfg.passes; + ctx.seedsinit[5] = ctx.mode: u64; + ctx.seedsinit[6] = 0; + + if (ctx.pass == 0 && slice == 0) { + ctx.seedsinit[6] += 1; + compress(ctx.seedblock, ctx.seedsinit, zeroblock, + false); + compress(ctx.seedblock, ctx.seedblock, zeroblock, + false); + }; + }; + + for (let b = 0z; b < ctx.sliceblocks; b += 1) { + const j = slice * ctx.sliceblocks + b; + if (ctx.pass == 0 && j < 2) { + continue; + }; + + const dmodeseed = switch (ctx.mode) { + case mode::D => + yield true; + case mode::ID => + yield ctx.pass > 0 || slice > 1; + case mode::I => + yield false; + }; + const seed: u64 = if (dmodeseed) { + yield block(ctx, i, (j - 1) % ctx.cols)[0]; + } else { + if (b % BLOCKSIZE == 0) { + ctx.seedsinit[6] += 1; + compress(ctx.seedblock, ctx.seedsinit, + zeroblock, false); + compress(ctx.seedblock, ctx.seedblock, + zeroblock, false); + }; + yield ctx.seedblock[b % BLOCKSIZE]; + }; + compress(block(ctx, i, j), block(ctx, i, (j - 1) % ctx.cols), + refblock(cfg, ctx, seed, i, j), ctx.pass > 0); + }; +}; + +fn compress(dest: []u64, x: []u64, y: []u64, xor: bool) void = { + let r: block64 = [0...]; + xorblock(r, x, y); + + let z: block64 = [0...]; + z[..] = r[..]; + + for (let i = 0z; i < 128; i += 16) { + perm(&z[i], &z[i + 1], &z[i + 2], &z[i + 3], &z[i + 4], + &z[i + 5], &z[i + 6], &z[i + 7], &z[i + 8], &z[i + 9], + &z[i + 10], &z[i + 11], &z[i + 12], &z[i + 13], + &z[i + 14], &z[i + 15]); + }; + + for (let i = 0z; i < 16; i += 2) { + perm(&z[i], &z[i + 1], &z[i + 16], &z[i + 17], &z[i + 32], + &z[i + 33], &z[i + 48], &z[i + 49], &z[i + 64], + &z[i + 65], &z[i + 80], &z[i + 81], &z[i + 96], + &z[i + 97], &z[i + 112], &z[i + 113]); + }; + + if (xor) { + xorblock(r, r, dest); + }; + + xorblock(dest, z, r); +}; + +fn perm( + x0: *u64, + x1: *u64, + x2: *u64, + x3: *u64, + x4: *u64, + x5: *u64, + x6: *u64, + x7: *u64, + x8: *u64, + x9: *u64, + x10: *u64, + x11: *u64, + x12: *u64, + x13: *u64, + x14: *u64, + x15: *u64, +) void = { + mix(x0, x4, x8, x12); + mix(x1, x5, x9, x13); + mix(x2, x6, x10, x14); + mix(x3, x7, x11, x15); + + mix(x0, x5, x10, x15); + mix(x1, x6, x11, x12); + mix(x2, x7, x8, x13); + mix(x3, x4, x9, x14); +}; + +fn mix(a: *u64, b: *u64, c: *u64, d: *u64) void = { + *a = *a + *b + 2 * trunc(*a) * trunc(*b); + *d = math::rotr64(*d ^ *a, 32); + *c = *c + *d + 2 * trunc(*c) * trunc(*d); + *b = math::rotr64(*b ^ *c, 24); + + *a = *a + *b + 2 * trunc(*a) * trunc(*b); + *d = math::rotr64(*d ^ *a, 16); + *c = *c + *d + 2 * trunc(*c) * trunc(*d); + *b = math::rotr64(*b ^ *c, 63); +}; + +fn trunc(a: u64) u64 = { + return a & 0xffffffff; +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -202,6 +202,18 @@ crypto_aes() { fi } +crypto_argon2() { + if [ $testing -eq 0 ] + then + gen_srcs crypto::argon2 argon2.ha + else + gen_srcs crypto::argon2 argon2.ha +test.ha + fi + + gen_ssa crypto::argon2 bufio bytes crypto::blake2b \ + crypto::math endian errors hash io rt types +} + gensrcs_crypto_blake2b() { gen_srcs crypto::blake2b \ blake2b.ha \ @@ -1095,6 +1107,7 @@ bytes compress::flate compress::zlib crypto::aes +crypto::argon2 crypto::blake2b crypto::cipher crypto::hmac diff --git a/stdlib.mk b/stdlib.mk @@ -150,6 +150,12 @@ stdlib_deps_any+=$(stdlib_crypto_aes_any) stdlib_crypto_aes_linux=$(stdlib_crypto_aes_any) stdlib_crypto_aes_freebsd=$(stdlib_crypto_aes_any) +# gen_lib crypto::argon2 (any) +stdlib_crypto_argon2_any=$(HARECACHE)/crypto/argon2/crypto_argon2-any.o +stdlib_deps_any+=$(stdlib_crypto_argon2_any) +stdlib_crypto_argon2_linux=$(stdlib_crypto_argon2_any) +stdlib_crypto_argon2_freebsd=$(stdlib_crypto_argon2_any) + # gen_lib crypto::blake2b (any) stdlib_crypto_blake2b_any=$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.o stdlib_deps_any+=$(stdlib_crypto_blake2b_any) @@ -663,6 +669,16 @@ $(HARECACHE)/crypto/aes/crypto_aes-any.ssa: $(stdlib_crypto_aes_any_srcs) $(stdl @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::aes \ -t$(HARECACHE)/crypto/aes/crypto_aes.td $(stdlib_crypto_aes_any_srcs) +# crypto::argon2 (+any) +stdlib_crypto_argon2_any_srcs= \ + $(STDLIB)/crypto/argon2/argon2.ha + +$(HARECACHE)/crypto/argon2/crypto_argon2-any.ssa: $(stdlib_crypto_argon2_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_crypto_blake2b_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) + @printf 'HAREC \t$@\n' + @mkdir -p $(HARECACHE)/crypto/argon2 + @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::argon2 \ + -t$(HARECACHE)/crypto/argon2/crypto_argon2.td $(stdlib_crypto_argon2_any_srcs) + # crypto::blake2b (+any) stdlib_crypto_blake2b_any_srcs= \ $(STDLIB)/crypto/blake2b/blake2b.ha @@ -1864,6 +1880,12 @@ testlib_deps_any+=$(testlib_crypto_aes_any) testlib_crypto_aes_linux=$(testlib_crypto_aes_any) testlib_crypto_aes_freebsd=$(testlib_crypto_aes_any) +# gen_lib crypto::argon2 (any) +testlib_crypto_argon2_any=$(TESTCACHE)/crypto/argon2/crypto_argon2-any.o +testlib_deps_any+=$(testlib_crypto_argon2_any) +testlib_crypto_argon2_linux=$(testlib_crypto_argon2_any) +testlib_crypto_argon2_freebsd=$(testlib_crypto_argon2_any) + # gen_lib crypto::blake2b (any) testlib_crypto_blake2b_any=$(TESTCACHE)/crypto/blake2b/crypto_blake2b-any.o testlib_deps_any+=$(testlib_crypto_blake2b_any) @@ -2381,6 +2403,17 @@ $(TESTCACHE)/crypto/aes/crypto_aes-any.ssa: $(testlib_crypto_aes_any_srcs) $(tes @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::aes \ -t$(TESTCACHE)/crypto/aes/crypto_aes.td $(testlib_crypto_aes_any_srcs) +# crypto::argon2 (+any) +testlib_crypto_argon2_any_srcs= \ + $(STDLIB)/crypto/argon2/argon2.ha \ + $(STDLIB)/crypto/argon2/+test.ha + +$(TESTCACHE)/crypto/argon2/crypto_argon2-any.ssa: $(testlib_crypto_argon2_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_blake2b_$(PLATFORM)) $(testlib_crypto_math_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_types_$(PLATFORM)) + @printf 'HAREC \t$@\n' + @mkdir -p $(TESTCACHE)/crypto/argon2 + @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::argon2 \ + -t$(TESTCACHE)/crypto/argon2/crypto_argon2.td $(testlib_crypto_argon2_any_srcs) + # crypto::blake2b (+any) testlib_crypto_blake2b_any_srcs= \ $(STDLIB)/crypto/blake2b/blake2b.ha \