From 77be7144c373ae28deb97a48822edf3909e7c2bd Mon Sep 17 00:00:00 2001 From: zhibog Date: Thu, 14 Oct 2021 22:20:55 +0200 Subject: [PATCH] Add crypto library. Additional information is included in the README.md --- core/crypto/README.md | 94 + core/crypto/_blake2/_blake2.odin | 2786 +++++++++++++++++++++++ core/crypto/_ctx/_ctx.odin | 78 + core/crypto/_sha3/_sha3.odin | 170 ++ core/crypto/_tiger/_tiger.odin | 411 ++++ core/crypto/blake/blake.odin | 846 +++++++ core/crypto/blake2b/blake2b.odin | 189 ++ core/crypto/blake2s/blake2s.odin | 189 ++ core/crypto/botan/botan.lib | Bin 0 -> 3298832 bytes core/crypto/botan/botan.odin | 480 ++++ core/crypto/botan/hash.odin | 471 ++++ core/crypto/gost/gost.odin | 460 ++++ core/crypto/groestl/groestl.odin | 742 ++++++ core/crypto/haval/haval.odin | 1372 +++++++++++ core/crypto/jh/jh.odin | 673 ++++++ core/crypto/keccak/keccak.odin | 441 ++++ core/crypto/md2/md2.odin | 265 +++ core/crypto/md4/md4.odin | 345 +++ core/crypto/md5/md5.odin | 368 +++ core/crypto/ripemd/ripemd.odin | 1060 +++++++++ core/crypto/sha1/sha1.odin | 329 +++ core/crypto/sha2/sha2.odin | 797 +++++++ core/crypto/sha3/sha3.odin | 440 ++++ core/crypto/shake/shake.odin | 279 +++ core/crypto/skein/skein.odin | 496 ++++ core/crypto/sm3/sm3.odin | 336 +++ core/crypto/streebog/streebog.odin | 602 +++++ core/crypto/tiger/tiger.odin | 340 +++ core/crypto/tiger2/tiger2.odin | 340 +++ core/crypto/util/util.odin | 144 ++ core/crypto/whirlpool/whirlpool.odin | 873 +++++++ tests/core/build.bat | 7 +- tests/core/crypto/test_core_crypto.odin | 1279 +++++++++++ 33 files changed, 17701 insertions(+), 1 deletion(-) create mode 100644 core/crypto/README.md create mode 100644 core/crypto/_blake2/_blake2.odin create mode 100644 core/crypto/_ctx/_ctx.odin create mode 100644 core/crypto/_sha3/_sha3.odin create mode 100644 core/crypto/_tiger/_tiger.odin create mode 100644 core/crypto/blake/blake.odin create mode 100644 core/crypto/blake2b/blake2b.odin create mode 100644 core/crypto/blake2s/blake2s.odin create mode 100644 core/crypto/botan/botan.lib create mode 100644 core/crypto/botan/botan.odin create mode 100644 core/crypto/botan/hash.odin create mode 100644 core/crypto/gost/gost.odin create mode 100644 core/crypto/groestl/groestl.odin create mode 100644 core/crypto/haval/haval.odin create mode 100644 core/crypto/jh/jh.odin create mode 100644 core/crypto/keccak/keccak.odin create mode 100644 core/crypto/md2/md2.odin create mode 100644 core/crypto/md4/md4.odin create mode 100644 core/crypto/md5/md5.odin create mode 100644 core/crypto/ripemd/ripemd.odin create mode 100644 core/crypto/sha1/sha1.odin create mode 100644 core/crypto/sha2/sha2.odin create mode 100644 core/crypto/sha3/sha3.odin create mode 100644 core/crypto/shake/shake.odin create mode 100644 core/crypto/skein/skein.odin create mode 100644 core/crypto/sm3/sm3.odin create mode 100644 core/crypto/streebog/streebog.odin create mode 100644 core/crypto/tiger/tiger.odin create mode 100644 core/crypto/tiger2/tiger2.odin create mode 100644 core/crypto/util/util.odin create mode 100644 core/crypto/whirlpool/whirlpool.odin create mode 100644 tests/core/crypto/test_core_crypto.odin diff --git a/core/crypto/README.md b/core/crypto/README.md new file mode 100644 index 000000000..362a6299b --- /dev/null +++ b/core/crypto/README.md @@ -0,0 +1,94 @@ +# crypto +A crypto library for the Odin language + +## Supported +This library offers various algorithms available in either native Odin or via bindings to the [Botan](https://botan.randombit.net/) crypto library. +Please see the chart below for the options. +**Note:** All crypto hash algorithms, offered by [Botan\'s FFI](https://botan.randombit.net/handbook/api_ref/hash.html), have been added. + +## Hashing algorithms +| Algorithm | Odin | Botan | +|:-------------------------------------------------------------------------------------------------------------|:-----------------|:---------------------| +| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ | | +| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | ✔️ | +| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | +| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | ✔️ | +| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ | | +| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | | +| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | | +| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | +| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | | +| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | ✔️ | +| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | ✔️ | +| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | ✔️\* | +| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | ✔️ | +| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | ✔️ | +| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | +| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | +| [Skein](https://www.schneier.com/academic/skein/) | | ✔️\*\* | +| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | ✔️ | +| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | ✔️ | +| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | ✔️ | +| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | +| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | ✔️ | + +\* Only `RIPEMD-160` +\*\* Only `SKEIN-512` + +#### High level API +Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*\*\*. +Included in these groups are four procedures. +* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally +* `hash_bytes` - Hash a given byte slice and return the computed hash +* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it +* `hash_file` - Hashes a file. A second boolean parameter controls if the file is streamed (set to false) or read at once (set to true) + +\*\*\* On some algorithms there is another part to the name, since they might offer control about additional parameters. +For instance, `HAVAL` offers different sizes as well as three different round amounts. +Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`. + +#### Low level API +The above mentioned procedures internally call three procedures: `init`, `update` and `final`. +You may also directly call them, if you wish. + +#### Context system +The library uses a context system internally to be able to switch between Odin / Botan implementations freely. +When an Odin implementation is available, it is the default. +You may change what is used during runtime by calling `foo.use_botan()` or `foo.use_odin()`. +It is also possible to set this during compile time via `USE_BOTAN_LIB=true`. +Internally a vtable is used to set the appropriate procedures when switching. This works for all the procedures mentioned in the APIs above. + +#### Example +```odin +package crypto_example + +// Import the desired package +import "core:crypto/md4" + +main :: proc() { + input := "foo" + // Compute the hash via Odin implementation + computed_hash := md4.hash(input) + // Switch to Botan + md4.use_botan() + // Compute the hash via Botan bindings + computed_hash_botan := md4.hash(input) +} +``` +For example uses of all available algorithms, please see the tests within `tests/core/crypto`. + +### Disclaimer +The algorithms were ported out of curiosity and due to interest in the field. +We have not had any of the code verified by a third party or tested/fuzzed by any automatic means. +Whereever we were able to find official test vectors, those were used to verify the implementation. +We do not recommend using them in a production environment, without any additional testing and/or verification. + +### ToDo +* Ciphers (Symmetric, Asymmetric) +* MACs (Message Authentication Code) +* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator) +* KDFs (Key Derivation Function) +* KEAs (Key Exchange Algorithm) + +### License +This library is made available under the BSD-3 license. \ No newline at end of file diff --git a/core/crypto/_blake2/_blake2.odin b/core/crypto/_blake2/_blake2.odin new file mode 100644 index 000000000..b2e18d6c7 --- /dev/null +++ b/core/crypto/_blake2/_blake2.odin @@ -0,0 +1,2786 @@ +package _blake2 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the BLAKE2 hashing algorithm, as defined in and +*/ + +import "../util" + +BLAKE2S_BLOCK_SIZE :: 64 +BLAKE2S_SIZE :: 32 +BLAKE2B_BLOCK_SIZE :: 128 +BLAKE2B_SIZE :: 64 + +Blake2s_Context :: struct { + h: [8]u32, + t: [2]u32, + f: [2]u32, + x: [BLAKE2S_BLOCK_SIZE]byte, + nx: int, + ih: [8]u32, + padded_key: [BLAKE2S_BLOCK_SIZE]byte, + is_keyed: bool, + size: byte, + is_last_node: bool, + cfg: Blake2_Config, +} + +Blake2b_Context :: struct { + h: [8]u64, + t: [2]u64, + f: [2]u64, + x: [BLAKE2B_BLOCK_SIZE]byte, + nx: int, + ih: [8]u64, + padded_key: [BLAKE2B_BLOCK_SIZE]byte, + is_keyed: bool, + size: byte, + is_last_node: bool, + cfg: Blake2_Config, +} + +Blake2_Config :: struct { + size: byte, + key: []byte, + salt: []byte, + person: []byte, + tree: union{Blake2_Tree}, +} + +Blake2_Tree :: struct { + fanout: byte, + max_depth: byte, + leaf_size: u32, + node_offset: u64, + node_depth: byte, + inner_hash_size: byte, + is_last_node: bool, +} + +BLAKE2S_IV := [8]u32 { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, +} + +BLAKE2B_IV := [8]u64 { + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +init_odin :: proc(ctx: ^$T) { + when T == Blake2s_Context { + block_size :: BLAKE2S_BLOCK_SIZE + } else when T == Blake2b_Context { + block_size :: BLAKE2B_BLOCK_SIZE + } + + p := make([]byte, block_size) + defer delete(p) + + p[0] = ctx.cfg.size + p[1] = byte(len(ctx.cfg.key)) + + if ctx.cfg.salt != nil { + when T == Blake2s_Context { + copy(p[16:], ctx.cfg.salt) + } else when T == Blake2b_Context { + copy(p[32:], ctx.cfg.salt) + } + } + if ctx.cfg.person != nil { + when T == Blake2s_Context { + copy(p[24:], ctx.cfg.person) + } else when T == Blake2b_Context { + copy(p[48:], ctx.cfg.person) + } + } + + if ctx.cfg.tree != nil { + p[2] = ctx.cfg.tree.(Blake2_Tree).fanout + p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth + util.PUT_U32_LE(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size) + when T == Blake2s_Context { + p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset) + p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8) + p[10] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 16) + p[11] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 24) + p[12] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 32) + p[13] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 40) + p[14] = ctx.cfg.tree.(Blake2_Tree).node_depth + p[15] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size + } else when T == Blake2b_Context { + util.PUT_U64_LE(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset) + p[16] = ctx.cfg.tree.(Blake2_Tree).node_depth + p[17] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size + } + } else { + p[2], p[3] = 1, 1 + } + ctx.size = ctx.cfg.size + for i := 0; i < 8; i += 1 { + when T == Blake2s_Context { + ctx.h[i] = BLAKE2S_IV[i] ~ util.U32_LE(p[i * 4:]) + } + when T == Blake2b_Context { + ctx.h[i] = BLAKE2B_IV[i] ~ util.U64_LE(p[i * 8:]) + } + } + if ctx.cfg.tree != nil && ctx.cfg.tree.(Blake2_Tree).is_last_node { + ctx.is_last_node = true + } + if len(ctx.cfg.key) > 0 { + copy(ctx.padded_key[:], ctx.cfg.key) + update_odin(ctx, ctx.padded_key[:]) + ctx.is_keyed = true + } + copy(ctx.ih[:], ctx.h[:]) + copy(ctx.h[:], ctx.ih[:]) + if ctx.is_keyed { + update_odin(ctx, ctx.padded_key[:]) + } +} + +update_odin :: proc(ctx: ^$T, p: []byte) { + p := p + when T == Blake2s_Context { + block_size :: BLAKE2S_BLOCK_SIZE + } else when T == Blake2b_Context { + block_size :: BLAKE2B_BLOCK_SIZE + } + + left := block_size - ctx.nx + if len(p) > left { + copy(ctx.x[ctx.nx:], p[:left]) + p = p[left:] + blake2_blocks(ctx, ctx.x[:]) + ctx.nx = 0 + } + if len(p) > block_size { + n := len(p) &~ (block_size - 1) + if n == len(p) { + n -= block_size + } + blake2_blocks(ctx, p[:n]) + p = p[n:] + } + ctx.nx += copy(ctx.x[ctx.nx:], p) +} + +blake2s_final_odin :: proc(ctx: $T, hash: []byte) { + if ctx.is_keyed { + for i := 0; i < len(ctx.padded_key); i += 1 { + ctx.padded_key[i] = 0 + } + } + + dec := BLAKE2S_BLOCK_SIZE - u32(ctx.nx) + if ctx.t[0] < dec { + ctx.t[1] -= 1 + } + ctx.t[0] -= dec + + ctx.f[0] = 0xffffffff + if ctx.is_last_node { + ctx.f[1] = 0xffffffff + } + + blake2_blocks(ctx, ctx.x[:]) + + j := 0 + for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] { + hash[j + 0] = byte(s >> 0) + hash[j + 1] = byte(s >> 8) + hash[j + 2] = byte(s >> 16) + hash[j + 3] = byte(s >> 24) + j += 4 + } +} + +blake2b_final_odin :: proc(ctx: $T, hash: []byte) { + if ctx.is_keyed { + for i := 0; i < len(ctx.padded_key); i += 1 { + ctx.padded_key[i] = 0 + } + } + + dec := BLAKE2B_BLOCK_SIZE - u64(ctx.nx) + if ctx.t[0] < dec { + ctx.t[1] -= 1 + } + ctx.t[0] -= dec + + ctx.f[0] = 0xffffffffffffffff + if ctx.is_last_node { + ctx.f[1] = 0xffffffffffffffff + } + + blake2_blocks(ctx, ctx.x[:]) + + j := 0 + for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] { + hash[j + 0] = byte(s >> 0) + hash[j + 1] = byte(s >> 8) + hash[j + 2] = byte(s >> 16) + hash[j + 3] = byte(s >> 24) + hash[j + 4] = byte(s >> 32) + hash[j + 5] = byte(s >> 40) + hash[j + 6] = byte(s >> 48) + hash[j + 7] = byte(s >> 56) + j += 8 + } +} + +blake2_blocks :: proc(ctx: ^$T, p: []byte) { + when T == Blake2s_Context { + blake2s_blocks(ctx, p) + } + when T == Blake2b_Context { + blake2b_blocks(ctx, p) + } +} + +blake2s_blocks :: #force_inline proc "contextless"(ctx: ^Blake2s_Context, p: []byte) { + h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] + p := p + for len(p) >= BLAKE2S_BLOCK_SIZE { + ctx.t[0] += BLAKE2S_BLOCK_SIZE + if ctx.t[0] < BLAKE2S_BLOCK_SIZE { + ctx.t[1] += 1 + } + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := BLAKE2S_IV[0] + v9 := BLAKE2S_IV[1] + v10 := BLAKE2S_IV[2] + v11 := BLAKE2S_IV[3] + v12 := BLAKE2S_IV[4] ~ ctx.t[0] + v13 := BLAKE2S_IV[5] ~ ctx.t[1] + v14 := BLAKE2S_IV[6] ~ ctx.f[0] + v15 := BLAKE2S_IV[7] ~ ctx.f[1] + m: [16]u32 + j := 0 + for i := 0; i < 16; i += 1 { + m[i] = u32(p[j]) | u32(p[j + 1]) << 8 | u32(p[j + 2]) << 16 | u32(p[j + 3]) << 24 + j += 4 + } + v0 += m[0] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[2] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[4] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[5] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[7] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[3] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[1] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[8] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[10] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[12] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[14] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[13] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[15] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[11] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[9] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[14] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[4] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[9] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[13] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[15] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[8] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[10] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[1] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[0] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[11] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[5] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[7] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[3] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[2] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[12] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[11] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[12] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[5] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[15] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[2] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[13] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[0] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[8] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[10] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[3] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[7] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[9] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[1] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[4] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[6] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[14] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[7] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[3] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[13] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[11] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[12] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[14] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[1] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[9] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[2] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[5] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[4] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[15] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[0] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[8] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[10] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[6] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[9] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[5] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[2] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[10] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[4] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[15] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[7] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[0] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[14] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[11] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[6] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[3] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[8] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[13] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[12] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[1] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[2] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[6] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[0] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[8] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[11] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[3] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[10] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[12] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[4] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[7] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[15] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[1] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[14] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[9] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[5] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[13] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[12] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[1] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[14] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[4] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[13] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[10] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[15] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[5] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[0] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[6] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[9] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[8] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[2] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[11] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[3] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[7] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[13] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[7] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[12] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[3] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[1] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[9] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[14] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[11] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[5] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[15] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[8] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[2] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[6] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[10] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[4] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[0] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[6] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[14] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[11] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[0] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[3] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[8] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[9] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[15] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[12] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[13] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[1] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[10] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[4] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[5] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[7] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[2] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[10] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 12) | v4 >> 12 + v1 += m[8] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 12) | v5 >> 12 + v2 += m[7] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 12) | v6 >> 12 + v3 += m[1] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 12) | v7 >> 12 + v2 += m[6] + v2 += v6 + v14 ~= v2 + v14 = v14 << (32 - 8) | v14 >> 8 + v10 += v14 + v6 ~= v10 + v6 = v6 << (32 - 7) | v6 >> 7 + v3 += m[5] + v3 += v7 + v15 ~= v3 + v15 = v15 << (32 - 8) | v15 >> 8 + v11 += v15 + v7 ~= v11 + v7 = v7 << (32 - 7) | v7 >> 7 + v1 += m[4] + v1 += v5 + v13 ~= v1 + v13 = v13 << (32 - 8) | v13 >> 8 + v9 += v13 + v5 ~= v9 + v5 = v5 << (32 - 7) | v5 >> 7 + v0 += m[2] + v0 += v4 + v12 ~= v0 + v12 = v12 << (32 - 8) | v12 >> 8 + v8 += v12 + v4 ~= v8 + v4 = v4 << (32 - 7) | v4 >> 7 + v0 += m[15] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 12) | v5 >> 12 + v1 += m[9] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 12) | v6 >> 12 + v2 += m[3] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 12) | v7 >> 12 + v3 += m[13] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 12) | v4 >> 12 + v2 += m[12] + v2 += v7 + v13 ~= v2 + v13 = v13 << (32 - 8) | v13 >> 8 + v8 += v13 + v7 ~= v8 + v7 = v7 << (32 - 7) | v7 >> 7 + v3 += m[0] + v3 += v4 + v14 ~= v3 + v14 = v14 << (32 - 8) | v14 >> 8 + v9 += v14 + v4 ~= v9 + v4 = v4 << (32 - 7) | v4 >> 7 + v1 += m[14] + v1 += v6 + v12 ~= v1 + v12 = v12 << (32 - 8) | v12 >> 8 + v11 += v12 + v6 ~= v11 + v6 = v6 << (32 - 7) | v6 >> 7 + v0 += m[11] + v0 += v5 + v15 ~= v0 + v15 = v15 << (32 - 8) | v15 >> 8 + v10 += v15 + v5 ~= v10 + v5 = v5 << (32 - 7) | v5 >> 7 + h0 ~= v0 ~ v8 + h1 ~= v1 ~ v9 + h2 ~= v2 ~ v10 + h3 ~= v3 ~ v11 + h4 ~= v4 ~ v12 + h5 ~= v5 ~ v13 + h6 ~= v6 ~ v14 + h7 ~= v7 ~ v15 + p = p[BLAKE2S_BLOCK_SIZE:] + } + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} + +blake2b_blocks :: #force_inline proc "contextless"(ctx: ^Blake2b_Context, p: []byte) { + h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] + p := p + for len(p) >= BLAKE2B_BLOCK_SIZE { + ctx.t[0] += BLAKE2B_BLOCK_SIZE + if ctx.t[0] < BLAKE2B_BLOCK_SIZE { + ctx.t[1]+=1 + } + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := BLAKE2B_IV[0] + v9 := BLAKE2B_IV[1] + v10 := BLAKE2B_IV[2] + v11 := BLAKE2B_IV[3] + v12 := BLAKE2B_IV[4] ~ ctx.t[0] + v13 := BLAKE2B_IV[5] ~ ctx.t[1] + v14 := BLAKE2B_IV[6] ~ ctx.f[0] + v15 := BLAKE2B_IV[7] ~ ctx.f[1] + m: [16]u64 = --- + j := 0 + for i := 0; i < 16; i+=1 { + m[i] = u64(p[j]) | u64(p[j + 1]) << 8 | u64(p[j + 2]) << 16 | u64(p[j + 3]) << 24 | + u64(p[j + 4]) << 32 | u64(p[j + 5]) << 40 | u64(p[j + 6]) << 48 | u64(p[j + 7]) << 56 + j += 8 + } + v0 += m[0] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[2] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[4] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[5] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[7] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[3] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[1] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[8] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[10] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[12] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[14] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[13] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[15] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[11] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[9] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[14] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[4] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[9] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[13] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[15] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[8] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[10] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[1] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[0] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[11] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[5] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[7] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[3] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[2] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[12] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[11] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[12] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[5] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[15] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[2] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[13] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[0] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[8] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[10] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[3] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[7] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[9] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[1] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[4] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[6] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[14] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[7] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[3] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[13] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[11] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[12] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[14] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[1] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[9] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[2] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[5] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[4] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[15] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[0] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[8] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[10] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[6] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[9] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[5] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[2] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[10] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[4] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[15] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[7] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[0] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[14] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[11] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[6] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[3] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[8] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[13] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[12] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[1] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[2] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[6] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[0] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[8] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[11] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[3] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[10] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[12] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[4] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[7] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[15] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[1] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[14] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[9] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[5] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[13] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[12] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[1] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[14] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[4] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[13] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[10] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[15] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[5] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[0] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[6] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[9] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[8] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[2] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[11] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[3] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[7] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[13] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[7] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[12] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[3] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[1] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[9] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[14] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[11] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[5] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[15] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[8] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[2] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[6] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[10] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[4] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[0] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[6] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[14] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[11] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[0] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[3] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[8] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[9] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[15] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[12] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[13] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[1] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[10] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[4] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[5] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[7] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[2] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[10] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[8] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[7] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[1] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[6] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[5] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[4] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[2] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[15] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[9] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[3] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[13] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[12] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[0] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[14] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[11] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[0] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[2] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[4] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[5] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[7] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[3] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[1] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[8] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[10] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[12] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[14] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[13] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[15] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[11] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[9] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[14] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 32) | v12 >> 32 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 24) | v4 >> 24 + v1 += m[4] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 32) | v13 >> 32 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 24) | v5 >> 24 + v2 += m[9] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 32) | v14 >> 32 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 24) | v6 >> 24 + v3 += m[13] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 32) | v15 >> 32 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 24) | v7 >> 24 + v2 += m[15] + v2 += v6 + v14 ~= v2 + v14 = v14 << (64 - 16) | v14 >> 16 + v10 += v14 + v6 ~= v10 + v6 = v6 << (64 - 63) | v6 >> 63 + v3 += m[6] + v3 += v7 + v15 ~= v3 + v15 = v15 << (64 - 16) | v15 >> 16 + v11 += v15 + v7 ~= v11 + v7 = v7 << (64 - 63) | v7 >> 63 + v1 += m[8] + v1 += v5 + v13 ~= v1 + v13 = v13 << (64 - 16) | v13 >> 16 + v9 += v13 + v5 ~= v9 + v5 = v5 << (64 - 63) | v5 >> 63 + v0 += m[10] + v0 += v4 + v12 ~= v0 + v12 = v12 << (64 - 16) | v12 >> 16 + v8 += v12 + v4 ~= v8 + v4 = v4 << (64 - 63) | v4 >> 63 + v0 += m[1] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 32) | v15 >> 32 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 24) | v5 >> 24 + v1 += m[0] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 32) | v12 >> 32 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 24) | v6 >> 24 + v2 += m[11] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 32) | v13 >> 32 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 24) | v7 >> 24 + v3 += m[5] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 32) | v14 >> 32 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 24) | v4 >> 24 + v2 += m[7] + v2 += v7 + v13 ~= v2 + v13 = v13 << (64 - 16) | v13 >> 16 + v8 += v13 + v7 ~= v8 + v7 = v7 << (64 - 63) | v7 >> 63 + v3 += m[3] + v3 += v4 + v14 ~= v3 + v14 = v14 << (64 - 16) | v14 >> 16 + v9 += v14 + v4 ~= v9 + v4 = v4 << (64 - 63) | v4 >> 63 + v1 += m[2] + v1 += v6 + v12 ~= v1 + v12 = v12 << (64 - 16) | v12 >> 16 + v11 += v12 + v6 ~= v11 + v6 = v6 << (64 - 63) | v6 >> 63 + v0 += m[12] + v0 += v5 + v15 ~= v0 + v15 = v15 << (64 - 16) | v15 >> 16 + v10 += v15 + v5 ~= v10 + v5 = v5 << (64 - 63) | v5 >> 63 + h0 ~= v0 ~ v8 + h1 ~= v1 ~ v9 + h2 ~= v2 ~ v10 + h3 ~= v3 ~ v11 + h4 ~= v4 ~ v12 + h5 ~= v5 ~ v13 + h6 ~= v6 ~ v14 + h7 ~= v7 ~ v15 + p = p[BLAKE2B_BLOCK_SIZE:] + } + ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} \ No newline at end of file diff --git a/core/crypto/_ctx/_ctx.odin b/core/crypto/_ctx/_ctx.odin new file mode 100644 index 000000000..2632e8c7e --- /dev/null +++ b/core/crypto/_ctx/_ctx.odin @@ -0,0 +1,78 @@ +package _ctx + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog: Initial creation and testing of the bindings. + + Implementation of the context, used internally by the crypto library. +*/ + +import "core:io" + +Hash_Size :: enum { + _16, + _20, + _24, + _28, + _32, + _40, + _48, + _64, + _128, +} + +Hash_Context :: struct { + botan_hash_algo: cstring, + external_ctx: any, + internal_ctx: any, + hash_size: Hash_Size, + hash_size_val: int, + is_using_odin: bool, + using vtbl: ^Hash_Context_Vtable, +} + +Hash_Context_Vtable :: struct { + hash_bytes_16 : proc (ctx: ^Hash_Context, input: []byte) -> [16]byte, + hash_bytes_20 : proc (ctx: ^Hash_Context, input: []byte) -> [20]byte, + hash_bytes_24 : proc (ctx: ^Hash_Context, input: []byte) -> [24]byte, + hash_bytes_28 : proc (ctx: ^Hash_Context, input: []byte) -> [28]byte, + hash_bytes_32 : proc (ctx: ^Hash_Context, input: []byte) -> [32]byte, + hash_bytes_40 : proc (ctx: ^Hash_Context, input: []byte) -> [40]byte, + hash_bytes_48 : proc (ctx: ^Hash_Context, input: []byte) -> [48]byte, + hash_bytes_64 : proc (ctx: ^Hash_Context, input: []byte) -> [64]byte, + hash_bytes_128 : proc (ctx: ^Hash_Context, input: []byte) -> [128]byte, + hash_file_16 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool), + hash_file_20 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool), + hash_file_24 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([24]byte, bool), + hash_file_28 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool), + hash_file_32 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool), + hash_file_40 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([40]byte, bool), + hash_file_48 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool), + hash_file_64 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool), + hash_file_128 : proc (ctx: ^Hash_Context, path: string, load_at_once: bool) -> ([128]byte, bool), + hash_stream_16 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([16]byte, bool), + hash_stream_20 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([20]byte, bool), + hash_stream_24 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([24]byte, bool), + hash_stream_28 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([28]byte, bool), + hash_stream_32 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([32]byte, bool), + hash_stream_40 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([40]byte, bool), + hash_stream_48 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([48]byte, bool), + hash_stream_64 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([64]byte, bool), + hash_stream_128 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([128]byte, bool), + hash_bytes_slice : proc (ctx: ^Hash_Context, input: []byte, out_size: int, allocator := context.allocator) -> []byte, + hash_file_slice : proc (ctx: ^Hash_Context, path: string, out_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool), + hash_stream_slice : proc (ctx: ^Hash_Context, s: io.Stream, out_size: int, allocator := context.allocator) -> ([]byte, bool), + init : proc (ctx: ^Hash_Context), + update : proc (ctx: ^Hash_Context, data: []byte), + final : proc (ctx: ^Hash_Context, hash: []byte), +} + +_init_vtable :: #force_inline proc() -> ^Hash_Context { + ctx := new(Hash_Context) + vtbl := new(Hash_Context_Vtable) + ctx.vtbl = vtbl + return ctx +} \ No newline at end of file diff --git a/core/crypto/_sha3/_sha3.odin b/core/crypto/_sha3/_sha3.odin new file mode 100644 index 000000000..1038eb77c --- /dev/null +++ b/core/crypto/_sha3/_sha3.odin @@ -0,0 +1,170 @@ +package _sha3 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the Keccak hashing algorithm, standardized as SHA3 in + To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding. +*/ + +import "../util" + +ROUNDS :: 24 + +Sha3_Context :: struct { + st: struct #raw_union { + b: [200]u8, + q: [25]u64, + }, + pt: int, + rsiz: int, + mdlen: int, + is_keccak: bool, +} + +keccakf :: proc "contextless" (st: ^[25]u64) { + keccakf_rndc := [?]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, + } + + keccakf_rotc := [?]i32 { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, + } + + keccakf_piln := [?]i32 { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, + } + + i, j, r: i32 = ---, ---, --- + t: u64 = --- + bc: [5]u64 = --- + + when ODIN_ENDIAN != "little" { + v: uintptr = --- + for i = 0; i < 25; i += 1 { + v := uintptr(&st[i]) + st[i] = u64((^u8)(v + 0)^ << 0) | u64((^u8)(v + 1)^ << 8) | + u64((^u8)(v + 2)^ << 16) | u64((^u8)(v + 3)^ << 24) | + u64((^u8)(v + 4)^ << 32) | u64((^u8)(v + 5)^ << 40) | + u64((^u8)(v + 6)^ << 48) | u64((^u8)(v + 7)^ << 56) + } + } + + for r = 0; r < ROUNDS; r += 1 { + // theta + for i = 0; i < 5; i += 1 { + bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20] + } + + for i = 0; i < 5; i += 1 { + t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1) + for j = 0; j < 25; j += 5 { + st[j + i] ~= t + } + } + + // rho pi + t = st[1] + for i = 0; i < 24; i += 1 { + j = keccakf_piln[i] + bc[0] = st[j] + st[j] = util.ROTL64(t, u64(keccakf_rotc[i])) + t = bc[0] + } + + // chi + for j = 0; j < 25; j += 5 { + for i = 0; i < 5; i += 1 { + bc[i] = st[j + i] + } + for i = 0; i < 5; i += 1 { + st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5] + } + } + + st[0] ~= keccakf_rndc[r] + } + + when ODIN_ENDIAN != "little" { + for i = 0; i < 25; i += 1 { + v = uintptr(&st[i]) + t = st[i] + (^u8)(v + 0)^ = (t >> 0) & 0xff + (^u8)(v + 1)^ = (t >> 8) & 0xff + (^u8)(v + 2)^ = (t >> 16) & 0xff + (^u8)(v + 3)^ = (t >> 24) & 0xff + (^u8)(v + 4)^ = (t >> 32) & 0xff + (^u8)(v + 5)^ = (t >> 40) & 0xff + (^u8)(v + 6)^ = (t >> 48) & 0xff + (^u8)(v + 7)^ = (t >> 56) & 0xff + } + } +} + +init_odin :: proc "contextless" (c: ^Sha3_Context) { + for i := 0; i < 25; i += 1 { + c.st.q[i] = 0 + } + c.rsiz = 200 - 2 * c.mdlen +} + +update_odin :: proc "contextless" (c: ^Sha3_Context, data: []byte) { + j := c.pt + for i := 0; i < len(data); i += 1 { + c.st.b[j] ~= data[i] + j += 1 + if j >= c.rsiz { + keccakf(&c.st.q) + j = 0 + } + } + c.pt = j +} + +final_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { + if c.is_keccak { + c.st.b[c.pt] ~= 0x01 + } else { + c.st.b[c.pt] ~= 0x06 + } + + c.st.b[c.rsiz - 1] ~= 0x80 + keccakf(&c.st.q) + for i := 0; i < c.mdlen; i += 1 { + hash[i] = c.st.b[i] + } +} + +shake_xof_odin :: proc "contextless" (c: ^Sha3_Context) { + c.st.b[c.pt] ~= 0x1F + c.st.b[c.rsiz - 1] ~= 0x80 + keccakf(&c.st.q) + c.pt = 0 +} + +shake_out_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { + j := c.pt + for i := 0; i < len(hash); i += 1 { + if j >= c.rsiz { + keccakf(&c.st.q) + j = 0 + } + hash[i] = c.st.b[j] + j += 1 + } + c.pt = j +} diff --git a/core/crypto/_tiger/_tiger.odin b/core/crypto/_tiger/_tiger.odin new file mode 100644 index 000000000..50caf0944 --- /dev/null +++ b/core/crypto/_tiger/_tiger.odin @@ -0,0 +1,411 @@ +package _tiger + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the Tiger hashing algorithm, as defined in +*/ + +import "../util" + +T1 := [?]u64 { + 0x02aab17cf7e90c5e, 0xac424b03e243a8ec, 0x72cd5be30dd5fcd3, 0x6d019b93f6f97f3a, + 0xcd9978ffd21f9193, 0x7573a1c9708029e2, 0xb164326b922a83c3, 0x46883eee04915870, + 0xeaace3057103ece6, 0xc54169b808a3535c, 0x4ce754918ddec47c, 0x0aa2f4dfdc0df40c, + 0x10b76f18a74dbefa, 0xc6ccb6235ad1ab6a, 0x13726121572fe2ff, 0x1a488c6f199d921e, + 0x4bc9f9f4da0007ca, 0x26f5e6f6e85241c7, 0x859079dbea5947b6, 0x4f1885c5c99e8c92, + 0xd78e761ea96f864b, 0x8e36428c52b5c17d, 0x69cf6827373063c1, 0xb607c93d9bb4c56e, + 0x7d820e760e76b5ea, 0x645c9cc6f07fdc42, 0xbf38a078243342e0, 0x5f6b343c9d2e7d04, + 0xf2c28aeb600b0ec6, 0x6c0ed85f7254bcac, 0x71592281a4db4fe5, 0x1967fa69ce0fed9f, + 0xfd5293f8b96545db, 0xc879e9d7f2a7600b, 0x860248920193194e, 0xa4f9533b2d9cc0b3, + 0x9053836c15957613, 0xdb6dcf8afc357bf1, 0x18beea7a7a370f57, 0x037117ca50b99066, + 0x6ab30a9774424a35, 0xf4e92f02e325249b, 0x7739db07061ccae1, 0xd8f3b49ceca42a05, + 0xbd56be3f51382f73, 0x45faed5843b0bb28, 0x1c813d5c11bf1f83, 0x8af0e4b6d75fa169, + 0x33ee18a487ad9999, 0x3c26e8eab1c94410, 0xb510102bc0a822f9, 0x141eef310ce6123b, + 0xfc65b90059ddb154, 0xe0158640c5e0e607, 0x884e079826c3a3cf, 0x930d0d9523c535fd, + 0x35638d754e9a2b00, 0x4085fccf40469dd5, 0xc4b17ad28be23a4c, 0xcab2f0fc6a3e6a2e, + 0x2860971a6b943fcd, 0x3dde6ee212e30446, 0x6222f32ae01765ae, 0x5d550bb5478308fe, + 0xa9efa98da0eda22a, 0xc351a71686c40da7, 0x1105586d9c867c84, 0xdcffee85fda22853, + 0xccfbd0262c5eef76, 0xbaf294cb8990d201, 0xe69464f52afad975, 0x94b013afdf133e14, + 0x06a7d1a32823c958, 0x6f95fe5130f61119, 0xd92ab34e462c06c0, 0xed7bde33887c71d2, + 0x79746d6e6518393e, 0x5ba419385d713329, 0x7c1ba6b948a97564, 0x31987c197bfdac67, + 0xde6c23c44b053d02, 0x581c49fed002d64d, 0xdd474d6338261571, 0xaa4546c3e473d062, + 0x928fce349455f860, 0x48161bbacaab94d9, 0x63912430770e6f68, 0x6ec8a5e602c6641c, + 0x87282515337ddd2b, 0x2cda6b42034b701b, 0xb03d37c181cb096d, 0xe108438266c71c6f, + 0x2b3180c7eb51b255, 0xdf92b82f96c08bbc, 0x5c68c8c0a632f3ba, 0x5504cc861c3d0556, + 0xabbfa4e55fb26b8f, 0x41848b0ab3baceb4, 0xb334a273aa445d32, 0xbca696f0a85ad881, + 0x24f6ec65b528d56c, 0x0ce1512e90f4524a, 0x4e9dd79d5506d35a, 0x258905fac6ce9779, + 0x2019295b3e109b33, 0xf8a9478b73a054cc, 0x2924f2f934417eb0, 0x3993357d536d1bc4, + 0x38a81ac21db6ff8b, 0x47c4fbf17d6016bf, 0x1e0faadd7667e3f5, 0x7abcff62938beb96, + 0xa78dad948fc179c9, 0x8f1f98b72911e50d, 0x61e48eae27121a91, 0x4d62f7ad31859808, + 0xeceba345ef5ceaeb, 0xf5ceb25ebc9684ce, 0xf633e20cb7f76221, 0xa32cdf06ab8293e4, + 0x985a202ca5ee2ca4, 0xcf0b8447cc8a8fb1, 0x9f765244979859a3, 0xa8d516b1a1240017, + 0x0bd7ba3ebb5dc726, 0xe54bca55b86adb39, 0x1d7a3afd6c478063, 0x519ec608e7669edd, + 0x0e5715a2d149aa23, 0x177d4571848ff194, 0xeeb55f3241014c22, 0x0f5e5ca13a6e2ec2, + 0x8029927b75f5c361, 0xad139fabc3d6e436, 0x0d5df1a94ccf402f, 0x3e8bd948bea5dfc8, + 0xa5a0d357bd3ff77e, 0xa2d12e251f74f645, 0x66fd9e525e81a082, 0x2e0c90ce7f687a49, + 0xc2e8bcbeba973bc5, 0x000001bce509745f, 0x423777bbe6dab3d6, 0xd1661c7eaef06eb5, + 0xa1781f354daacfd8, 0x2d11284a2b16affc, 0xf1fc4f67fa891d1f, 0x73ecc25dcb920ada, + 0xae610c22c2a12651, 0x96e0a810d356b78a, 0x5a9a381f2fe7870f, 0xd5ad62ede94e5530, + 0xd225e5e8368d1427, 0x65977b70c7af4631, 0x99f889b2de39d74f, 0x233f30bf54e1d143, + 0x9a9675d3d9a63c97, 0x5470554ff334f9a8, 0x166acb744a4f5688, 0x70c74caab2e4aead, + 0xf0d091646f294d12, 0x57b82a89684031d1, 0xefd95a5a61be0b6b, 0x2fbd12e969f2f29a, + 0x9bd37013feff9fe8, 0x3f9b0404d6085a06, 0x4940c1f3166cfe15, 0x09542c4dcdf3defb, + 0xb4c5218385cd5ce3, 0xc935b7dc4462a641, 0x3417f8a68ed3b63f, 0xb80959295b215b40, + 0xf99cdaef3b8c8572, 0x018c0614f8fcb95d, 0x1b14accd1a3acdf3, 0x84d471f200bb732d, + 0xc1a3110e95e8da16, 0x430a7220bf1a82b8, 0xb77e090d39df210e, 0x5ef4bd9f3cd05e9d, + 0x9d4ff6da7e57a444, 0xda1d60e183d4a5f8, 0xb287c38417998e47, 0xfe3edc121bb31886, + 0xc7fe3ccc980ccbef, 0xe46fb590189bfd03, 0x3732fd469a4c57dc, 0x7ef700a07cf1ad65, + 0x59c64468a31d8859, 0x762fb0b4d45b61f6, 0x155baed099047718, 0x68755e4c3d50baa6, + 0xe9214e7f22d8b4df, 0x2addbf532eac95f4, 0x32ae3909b4bd0109, 0x834df537b08e3450, + 0xfa209da84220728d, 0x9e691d9b9efe23f7, 0x0446d288c4ae8d7f, 0x7b4cc524e169785b, + 0x21d87f0135ca1385, 0xcebb400f137b8aa5, 0x272e2b66580796be, 0x3612264125c2b0de, + 0x057702bdad1efbb2, 0xd4babb8eacf84be9, 0x91583139641bc67b, 0x8bdc2de08036e024, + 0x603c8156f49f68ed, 0xf7d236f7dbef5111, 0x9727c4598ad21e80, 0xa08a0896670a5fd7, + 0xcb4a8f4309eba9cb, 0x81af564b0f7036a1, 0xc0b99aa778199abd, 0x959f1ec83fc8e952, + 0x8c505077794a81b9, 0x3acaaf8f056338f0, 0x07b43f50627a6778, 0x4a44ab49f5eccc77, + 0x3bc3d6e4b679ee98, 0x9cc0d4d1cf14108c, 0x4406c00b206bc8a0, 0x82a18854c8d72d89, + 0x67e366b35c3c432c, 0xb923dd61102b37f2, 0x56ab2779d884271d, 0xbe83e1b0ff1525af, + 0xfb7c65d4217e49a9, 0x6bdbe0e76d48e7d4, 0x08df828745d9179e, 0x22ea6a9add53bd34, + 0xe36e141c5622200a, 0x7f805d1b8cb750ee, 0xafe5c7a59f58e837, 0xe27f996a4fb1c23c, + 0xd3867dfb0775f0d0, 0xd0e673de6e88891a, 0x123aeb9eafb86c25, 0x30f1d5d5c145b895, + 0xbb434a2dee7269e7, 0x78cb67ecf931fa38, 0xf33b0372323bbf9c, 0x52d66336fb279c74, + 0x505f33ac0afb4eaa, 0xe8a5cd99a2cce187, 0x534974801e2d30bb, 0x8d2d5711d5876d90, + 0x1f1a412891bc038e, 0xd6e2e71d82e56648, 0x74036c3a497732b7, 0x89b67ed96361f5ab, + 0xffed95d8f1ea02a2, 0xe72b3bd61464d43d, 0xa6300f170bdc4820, 0xebc18760ed78a77a, +} + +T2 := [?]u64 { + 0xe6a6be5a05a12138, 0xb5a122a5b4f87c98, 0x563c6089140b6990, 0x4c46cb2e391f5dd5, + 0xd932addbc9b79434, 0x08ea70e42015aff5, 0xd765a6673e478cf1, 0xc4fb757eab278d99, + 0xdf11c6862d6e0692, 0xddeb84f10d7f3b16, 0x6f2ef604a665ea04, 0x4a8e0f0ff0e0dfb3, + 0xa5edeef83dbcba51, 0xfc4f0a2a0ea4371e, 0xe83e1da85cb38429, 0xdc8ff882ba1b1ce2, + 0xcd45505e8353e80d, 0x18d19a00d4db0717, 0x34a0cfeda5f38101, 0x0be77e518887caf2, + 0x1e341438b3c45136, 0xe05797f49089ccf9, 0xffd23f9df2591d14, 0x543dda228595c5cd, + 0x661f81fd99052a33, 0x8736e641db0f7b76, 0x15227725418e5307, 0xe25f7f46162eb2fa, + 0x48a8b2126c13d9fe, 0xafdc541792e76eea, 0x03d912bfc6d1898f, 0x31b1aafa1b83f51b, + 0xf1ac2796e42ab7d9, 0x40a3a7d7fcd2ebac, 0x1056136d0afbbcc5, 0x7889e1dd9a6d0c85, + 0xd33525782a7974aa, 0xa7e25d09078ac09b, 0xbd4138b3eac6edd0, 0x920abfbe71eb9e70, + 0xa2a5d0f54fc2625c, 0xc054e36b0b1290a3, 0xf6dd59ff62fe932b, 0x3537354511a8ac7d, + 0xca845e9172fadcd4, 0x84f82b60329d20dc, 0x79c62ce1cd672f18, 0x8b09a2add124642c, + 0xd0c1e96a19d9e726, 0x5a786a9b4ba9500c, 0x0e020336634c43f3, 0xc17b474aeb66d822, + 0x6a731ae3ec9baac2, 0x8226667ae0840258, 0x67d4567691caeca5, 0x1d94155c4875adb5, + 0x6d00fd985b813fdf, 0x51286efcb774cd06, 0x5e8834471fa744af, 0xf72ca0aee761ae2e, + 0xbe40e4cdaee8e09a, 0xe9970bbb5118f665, 0x726e4beb33df1964, 0x703b000729199762, + 0x4631d816f5ef30a7, 0xb880b5b51504a6be, 0x641793c37ed84b6c, 0x7b21ed77f6e97d96, + 0x776306312ef96b73, 0xae528948e86ff3f4, 0x53dbd7f286a3f8f8, 0x16cadce74cfc1063, + 0x005c19bdfa52c6dd, 0x68868f5d64d46ad3, 0x3a9d512ccf1e186a, 0x367e62c2385660ae, + 0xe359e7ea77dcb1d7, 0x526c0773749abe6e, 0x735ae5f9d09f734b, 0x493fc7cc8a558ba8, + 0xb0b9c1533041ab45, 0x321958ba470a59bd, 0x852db00b5f46c393, 0x91209b2bd336b0e5, + 0x6e604f7d659ef19f, 0xb99a8ae2782ccb24, 0xccf52ab6c814c4c7, 0x4727d9afbe11727b, + 0x7e950d0c0121b34d, 0x756f435670ad471f, 0xf5add442615a6849, 0x4e87e09980b9957a, + 0x2acfa1df50aee355, 0xd898263afd2fd556, 0xc8f4924dd80c8fd6, 0xcf99ca3d754a173a, + 0xfe477bacaf91bf3c, 0xed5371f6d690c12d, 0x831a5c285e687094, 0xc5d3c90a3708a0a4, + 0x0f7f903717d06580, 0x19f9bb13b8fdf27f, 0xb1bd6f1b4d502843, 0x1c761ba38fff4012, + 0x0d1530c4e2e21f3b, 0x8943ce69a7372c8a, 0xe5184e11feb5ce66, 0x618bdb80bd736621, + 0x7d29bad68b574d0b, 0x81bb613e25e6fe5b, 0x071c9c10bc07913f, 0xc7beeb7909ac2d97, + 0xc3e58d353bc5d757, 0xeb017892f38f61e8, 0xd4effb9c9b1cc21a, 0x99727d26f494f7ab, + 0xa3e063a2956b3e03, 0x9d4a8b9a4aa09c30, 0x3f6ab7d500090fb4, 0x9cc0f2a057268ac0, + 0x3dee9d2dedbf42d1, 0x330f49c87960a972, 0xc6b2720287421b41, 0x0ac59ec07c00369c, + 0xef4eac49cb353425, 0xf450244eef0129d8, 0x8acc46e5caf4deb6, 0x2ffeab63989263f7, + 0x8f7cb9fe5d7a4578, 0x5bd8f7644e634635, 0x427a7315bf2dc900, 0x17d0c4aa2125261c, + 0x3992486c93518e50, 0xb4cbfee0a2d7d4c3, 0x7c75d6202c5ddd8d, 0xdbc295d8e35b6c61, + 0x60b369d302032b19, 0xce42685fdce44132, 0x06f3ddb9ddf65610, 0x8ea4d21db5e148f0, + 0x20b0fce62fcd496f, 0x2c1b912358b0ee31, 0xb28317b818f5a308, 0xa89c1e189ca6d2cf, + 0x0c6b18576aaadbc8, 0xb65deaa91299fae3, 0xfb2b794b7f1027e7, 0x04e4317f443b5beb, + 0x4b852d325939d0a6, 0xd5ae6beefb207ffc, 0x309682b281c7d374, 0xbae309a194c3b475, + 0x8cc3f97b13b49f05, 0x98a9422ff8293967, 0x244b16b01076ff7c, 0xf8bf571c663d67ee, + 0x1f0d6758eee30da1, 0xc9b611d97adeb9b7, 0xb7afd5887b6c57a2, 0x6290ae846b984fe1, + 0x94df4cdeacc1a5fd, 0x058a5bd1c5483aff, 0x63166cc142ba3c37, 0x8db8526eb2f76f40, + 0xe10880036f0d6d4e, 0x9e0523c9971d311d, 0x45ec2824cc7cd691, 0x575b8359e62382c9, + 0xfa9e400dc4889995, 0xd1823ecb45721568, 0xdafd983b8206082f, 0xaa7d29082386a8cb, + 0x269fcd4403b87588, 0x1b91f5f728bdd1e0, 0xe4669f39040201f6, 0x7a1d7c218cf04ade, + 0x65623c29d79ce5ce, 0x2368449096c00bb1, 0xab9bf1879da503ba, 0xbc23ecb1a458058e, + 0x9a58df01bb401ecc, 0xa070e868a85f143d, 0x4ff188307df2239e, 0x14d565b41a641183, + 0xee13337452701602, 0x950e3dcf3f285e09, 0x59930254b9c80953, 0x3bf299408930da6d, + 0xa955943f53691387, 0xa15edecaa9cb8784, 0x29142127352be9a0, 0x76f0371fff4e7afb, + 0x0239f450274f2228, 0xbb073af01d5e868b, 0xbfc80571c10e96c1, 0xd267088568222e23, + 0x9671a3d48e80b5b0, 0x55b5d38ae193bb81, 0x693ae2d0a18b04b8, 0x5c48b4ecadd5335f, + 0xfd743b194916a1ca, 0x2577018134be98c4, 0xe77987e83c54a4ad, 0x28e11014da33e1b9, + 0x270cc59e226aa213, 0x71495f756d1a5f60, 0x9be853fb60afef77, 0xadc786a7f7443dbf, + 0x0904456173b29a82, 0x58bc7a66c232bd5e, 0xf306558c673ac8b2, 0x41f639c6b6c9772a, + 0x216defe99fda35da, 0x11640cc71c7be615, 0x93c43694565c5527, 0xea038e6246777839, + 0xf9abf3ce5a3e2469, 0x741e768d0fd312d2, 0x0144b883ced652c6, 0xc20b5a5ba33f8552, + 0x1ae69633c3435a9d, 0x97a28ca4088cfdec, 0x8824a43c1e96f420, 0x37612fa66eeea746, + 0x6b4cb165f9cf0e5a, 0x43aa1c06a0abfb4a, 0x7f4dc26ff162796b, 0x6cbacc8e54ed9b0f, + 0xa6b7ffefd2bb253e, 0x2e25bc95b0a29d4f, 0x86d6a58bdef1388c, 0xded74ac576b6f054, + 0x8030bdbc2b45805d, 0x3c81af70e94d9289, 0x3eff6dda9e3100db, 0xb38dc39fdfcc8847, + 0x123885528d17b87e, 0xf2da0ed240b1b642, 0x44cefadcd54bf9a9, 0x1312200e433c7ee6, + 0x9ffcc84f3a78c748, 0xf0cd1f72248576bb, 0xec6974053638cfe4, 0x2ba7b67c0cec4e4c, + 0xac2f4df3e5ce32ed, 0xcb33d14326ea4c11, 0xa4e9044cc77e58bc, 0x5f513293d934fcef, + 0x5dc9645506e55444, 0x50de418f317de40a, 0x388cb31a69dde259, 0x2db4a83455820a86, + 0x9010a91e84711ae9, 0x4df7f0b7b1498371, 0xd62a2eabc0977179, 0x22fac097aa8d5c0e, +} + +T3 := [?]u64 { + 0xf49fcc2ff1daf39b, 0x487fd5c66ff29281, 0xe8a30667fcdca83f, 0x2c9b4be3d2fcce63, + 0xda3ff74b93fbbbc2, 0x2fa165d2fe70ba66, 0xa103e279970e93d4, 0xbecdec77b0e45e71, + 0xcfb41e723985e497, 0xb70aaa025ef75017, 0xd42309f03840b8e0, 0x8efc1ad035898579, + 0x96c6920be2b2abc5, 0x66af4163375a9172, 0x2174abdcca7127fb, 0xb33ccea64a72ff41, + 0xf04a4933083066a5, 0x8d970acdd7289af5, 0x8f96e8e031c8c25e, 0xf3fec02276875d47, + 0xec7bf310056190dd, 0xf5adb0aebb0f1491, 0x9b50f8850fd58892, 0x4975488358b74de8, + 0xa3354ff691531c61, 0x0702bbe481d2c6ee, 0x89fb24057deded98, 0xac3075138596e902, + 0x1d2d3580172772ed, 0xeb738fc28e6bc30d, 0x5854ef8f63044326, 0x9e5c52325add3bbe, + 0x90aa53cf325c4623, 0xc1d24d51349dd067, 0x2051cfeea69ea624, 0x13220f0a862e7e4f, + 0xce39399404e04864, 0xd9c42ca47086fcb7, 0x685ad2238a03e7cc, 0x066484b2ab2ff1db, + 0xfe9d5d70efbf79ec, 0x5b13b9dd9c481854, 0x15f0d475ed1509ad, 0x0bebcd060ec79851, + 0xd58c6791183ab7f8, 0xd1187c5052f3eee4, 0xc95d1192e54e82ff, 0x86eea14cb9ac6ca2, + 0x3485beb153677d5d, 0xdd191d781f8c492a, 0xf60866baa784ebf9, 0x518f643ba2d08c74, + 0x8852e956e1087c22, 0xa768cb8dc410ae8d, 0x38047726bfec8e1a, 0xa67738b4cd3b45aa, + 0xad16691cec0dde19, 0xc6d4319380462e07, 0xc5a5876d0ba61938, 0x16b9fa1fa58fd840, + 0x188ab1173ca74f18, 0xabda2f98c99c021f, 0x3e0580ab134ae816, 0x5f3b05b773645abb, + 0x2501a2be5575f2f6, 0x1b2f74004e7e8ba9, 0x1cd7580371e8d953, 0x7f6ed89562764e30, + 0xb15926ff596f003d, 0x9f65293da8c5d6b9, 0x6ecef04dd690f84c, 0x4782275fff33af88, + 0xe41433083f820801, 0xfd0dfe409a1af9b5, 0x4325a3342cdb396b, 0x8ae77e62b301b252, + 0xc36f9e9f6655615a, 0x85455a2d92d32c09, 0xf2c7dea949477485, 0x63cfb4c133a39eba, + 0x83b040cc6ebc5462, 0x3b9454c8fdb326b0, 0x56f56a9e87ffd78c, 0x2dc2940d99f42bc6, + 0x98f7df096b096e2d, 0x19a6e01e3ad852bf, 0x42a99ccbdbd4b40b, 0xa59998af45e9c559, + 0x366295e807d93186, 0x6b48181bfaa1f773, 0x1fec57e2157a0a1d, 0x4667446af6201ad5, + 0xe615ebcacfb0f075, 0xb8f31f4f68290778, 0x22713ed6ce22d11e, 0x3057c1a72ec3c93b, + 0xcb46acc37c3f1f2f, 0xdbb893fd02aaf50e, 0x331fd92e600b9fcf, 0xa498f96148ea3ad6, + 0xa8d8426e8b6a83ea, 0xa089b274b7735cdc, 0x87f6b3731e524a11, 0x118808e5cbc96749, + 0x9906e4c7b19bd394, 0xafed7f7e9b24a20c, 0x6509eadeeb3644a7, 0x6c1ef1d3e8ef0ede, + 0xb9c97d43e9798fb4, 0xa2f2d784740c28a3, 0x7b8496476197566f, 0x7a5be3e6b65f069d, + 0xf96330ed78be6f10, 0xeee60de77a076a15, 0x2b4bee4aa08b9bd0, 0x6a56a63ec7b8894e, + 0x02121359ba34fef4, 0x4cbf99f8283703fc, 0x398071350caf30c8, 0xd0a77a89f017687a, + 0xf1c1a9eb9e423569, 0x8c7976282dee8199, 0x5d1737a5dd1f7abd, 0x4f53433c09a9fa80, + 0xfa8b0c53df7ca1d9, 0x3fd9dcbc886ccb77, 0xc040917ca91b4720, 0x7dd00142f9d1dcdf, + 0x8476fc1d4f387b58, 0x23f8e7c5f3316503, 0x032a2244e7e37339, 0x5c87a5d750f5a74b, + 0x082b4cc43698992e, 0xdf917becb858f63c, 0x3270b8fc5bf86dda, 0x10ae72bb29b5dd76, + 0x576ac94e7700362b, 0x1ad112dac61efb8f, 0x691bc30ec5faa427, 0xff246311cc327143, + 0x3142368e30e53206, 0x71380e31e02ca396, 0x958d5c960aad76f1, 0xf8d6f430c16da536, + 0xc8ffd13f1be7e1d2, 0x7578ae66004ddbe1, 0x05833f01067be646, 0xbb34b5ad3bfe586d, + 0x095f34c9a12b97f0, 0x247ab64525d60ca8, 0xdcdbc6f3017477d1, 0x4a2e14d4decad24d, + 0xbdb5e6d9be0a1eeb, 0x2a7e70f7794301ab, 0xdef42d8a270540fd, 0x01078ec0a34c22c1, + 0xe5de511af4c16387, 0x7ebb3a52bd9a330a, 0x77697857aa7d6435, 0x004e831603ae4c32, + 0xe7a21020ad78e312, 0x9d41a70c6ab420f2, 0x28e06c18ea1141e6, 0xd2b28cbd984f6b28, + 0x26b75f6c446e9d83, 0xba47568c4d418d7f, 0xd80badbfe6183d8e, 0x0e206d7f5f166044, + 0xe258a43911cbca3e, 0x723a1746b21dc0bc, 0xc7caa854f5d7cdd3, 0x7cac32883d261d9c, + 0x7690c26423ba942c, 0x17e55524478042b8, 0xe0be477656a2389f, 0x4d289b5e67ab2da0, + 0x44862b9c8fbbfd31, 0xb47cc8049d141365, 0x822c1b362b91c793, 0x4eb14655fb13dfd8, + 0x1ecbba0714e2a97b, 0x6143459d5cde5f14, 0x53a8fbf1d5f0ac89, 0x97ea04d81c5e5b00, + 0x622181a8d4fdb3f3, 0xe9bcd341572a1208, 0x1411258643cce58a, 0x9144c5fea4c6e0a4, + 0x0d33d06565cf620f, 0x54a48d489f219ca1, 0xc43e5eac6d63c821, 0xa9728b3a72770daf, + 0xd7934e7b20df87ef, 0xe35503b61a3e86e5, 0xcae321fbc819d504, 0x129a50b3ac60bfa6, + 0xcd5e68ea7e9fb6c3, 0xb01c90199483b1c7, 0x3de93cd5c295376c, 0xaed52edf2ab9ad13, + 0x2e60f512c0a07884, 0xbc3d86a3e36210c9, 0x35269d9b163951ce, 0x0c7d6e2ad0cdb5fa, + 0x59e86297d87f5733, 0x298ef221898db0e7, 0x55000029d1a5aa7e, 0x8bc08ae1b5061b45, + 0xc2c31c2b6c92703a, 0x94cc596baf25ef42, 0x0a1d73db22540456, 0x04b6a0f9d9c4179a, + 0xeffdafa2ae3d3c60, 0xf7c8075bb49496c4, 0x9cc5c7141d1cd4e3, 0x78bd1638218e5534, + 0xb2f11568f850246a, 0xedfabcfa9502bc29, 0x796ce5f2da23051b, 0xaae128b0dc93537c, + 0x3a493da0ee4b29ae, 0xb5df6b2c416895d7, 0xfcabbd25122d7f37, 0x70810b58105dc4b1, + 0xe10fdd37f7882a90, 0x524dcab5518a3f5c, 0x3c9e85878451255b, 0x4029828119bd34e2, + 0x74a05b6f5d3ceccb, 0xb610021542e13eca, 0x0ff979d12f59e2ac, 0x6037da27e4f9cc50, + 0x5e92975a0df1847d, 0xd66de190d3e623fe, 0x5032d6b87b568048, 0x9a36b7ce8235216e, + 0x80272a7a24f64b4a, 0x93efed8b8c6916f7, 0x37ddbff44cce1555, 0x4b95db5d4b99bd25, + 0x92d3fda169812fc0, 0xfb1a4a9a90660bb6, 0x730c196946a4b9b2, 0x81e289aa7f49da68, + 0x64669a0f83b1a05f, 0x27b3ff7d9644f48b, 0xcc6b615c8db675b3, 0x674f20b9bcebbe95, + 0x6f31238275655982, 0x5ae488713e45cf05, 0xbf619f9954c21157, 0xeabac46040a8eae9, + 0x454c6fe9f2c0c1cd, 0x419cf6496412691c, 0xd3dc3bef265b0f70, 0x6d0e60f5c3578a9e, +} + +T4 := [?]u64 { + 0x5b0e608526323c55, 0x1a46c1a9fa1b59f5, 0xa9e245a17c4c8ffa, 0x65ca5159db2955d7, + 0x05db0a76ce35afc2, 0x81eac77ea9113d45, 0x528ef88ab6ac0a0d, 0xa09ea253597be3ff, + 0x430ddfb3ac48cd56, 0xc4b3a67af45ce46f, 0x4ececfd8fbe2d05e, 0x3ef56f10b39935f0, + 0x0b22d6829cd619c6, 0x17fd460a74df2069, 0x6cf8cc8e8510ed40, 0xd6c824bf3a6ecaa7, + 0x61243d581a817049, 0x048bacb6bbc163a2, 0xd9a38ac27d44cc32, 0x7fddff5baaf410ab, + 0xad6d495aa804824b, 0xe1a6a74f2d8c9f94, 0xd4f7851235dee8e3, 0xfd4b7f886540d893, + 0x247c20042aa4bfda, 0x096ea1c517d1327c, 0xd56966b4361a6685, 0x277da5c31221057d, + 0x94d59893a43acff7, 0x64f0c51ccdc02281, 0x3d33bcc4ff6189db, 0xe005cb184ce66af1, + 0xff5ccd1d1db99bea, 0xb0b854a7fe42980f, 0x7bd46a6a718d4b9f, 0xd10fa8cc22a5fd8c, + 0xd31484952be4bd31, 0xc7fa975fcb243847, 0x4886ed1e5846c407, 0x28cddb791eb70b04, + 0xc2b00be2f573417f, 0x5c9590452180f877, 0x7a6bddfff370eb00, 0xce509e38d6d9d6a4, + 0xebeb0f00647fa702, 0x1dcc06cf76606f06, 0xe4d9f28ba286ff0a, 0xd85a305dc918c262, + 0x475b1d8732225f54, 0x2d4fb51668ccb5fe, 0xa679b9d9d72bba20, 0x53841c0d912d43a5, + 0x3b7eaa48bf12a4e8, 0x781e0e47f22f1ddf, 0xeff20ce60ab50973, 0x20d261d19dffb742, + 0x16a12b03062a2e39, 0x1960eb2239650495, 0x251c16fed50eb8b8, 0x9ac0c330f826016e, + 0xed152665953e7671, 0x02d63194a6369570, 0x5074f08394b1c987, 0x70ba598c90b25ce1, + 0x794a15810b9742f6, 0x0d5925e9fcaf8c6c, 0x3067716cd868744e, 0x910ab077e8d7731b, + 0x6a61bbdb5ac42f61, 0x93513efbf0851567, 0xf494724b9e83e9d5, 0xe887e1985c09648d, + 0x34b1d3c675370cfd, 0xdc35e433bc0d255d, 0xd0aab84234131be0, 0x08042a50b48b7eaf, + 0x9997c4ee44a3ab35, 0x829a7b49201799d0, 0x263b8307b7c54441, 0x752f95f4fd6a6ca6, + 0x927217402c08c6e5, 0x2a8ab754a795d9ee, 0xa442f7552f72943d, 0x2c31334e19781208, + 0x4fa98d7ceaee6291, 0x55c3862f665db309, 0xbd0610175d53b1f3, 0x46fe6cb840413f27, + 0x3fe03792df0cfa59, 0xcfe700372eb85e8f, 0xa7be29e7adbce118, 0xe544ee5cde8431dd, + 0x8a781b1b41f1873e, 0xa5c94c78a0d2f0e7, 0x39412e2877b60728, 0xa1265ef3afc9a62c, + 0xbcc2770c6a2506c5, 0x3ab66dd5dce1ce12, 0xe65499d04a675b37, 0x7d8f523481bfd216, + 0x0f6f64fcec15f389, 0x74efbe618b5b13c8, 0xacdc82b714273e1d, 0xdd40bfe003199d17, + 0x37e99257e7e061f8, 0xfa52626904775aaa, 0x8bbbf63a463d56f9, 0xf0013f1543a26e64, + 0xa8307e9f879ec898, 0xcc4c27a4150177cc, 0x1b432f2cca1d3348, 0xde1d1f8f9f6fa013, + 0x606602a047a7ddd6, 0xd237ab64cc1cb2c7, 0x9b938e7225fcd1d3, 0xec4e03708e0ff476, + 0xfeb2fbda3d03c12d, 0xae0bced2ee43889a, 0x22cb8923ebfb4f43, 0x69360d013cf7396d, + 0x855e3602d2d4e022, 0x073805bad01f784c, 0x33e17a133852f546, 0xdf4874058ac7b638, + 0xba92b29c678aa14a, 0x0ce89fc76cfaadcd, 0x5f9d4e0908339e34, 0xf1afe9291f5923b9, + 0x6e3480f60f4a265f, 0xeebf3a2ab29b841c, 0xe21938a88f91b4ad, 0x57dfeff845c6d3c3, + 0x2f006b0bf62caaf2, 0x62f479ef6f75ee78, 0x11a55ad41c8916a9, 0xf229d29084fed453, + 0x42f1c27b16b000e6, 0x2b1f76749823c074, 0x4b76eca3c2745360, 0x8c98f463b91691bd, + 0x14bcc93cf1ade66a, 0x8885213e6d458397, 0x8e177df0274d4711, 0xb49b73b5503f2951, + 0x10168168c3f96b6b, 0x0e3d963b63cab0ae, 0x8dfc4b5655a1db14, 0xf789f1356e14de5c, + 0x683e68af4e51dac1, 0xc9a84f9d8d4b0fd9, 0x3691e03f52a0f9d1, 0x5ed86e46e1878e80, + 0x3c711a0e99d07150, 0x5a0865b20c4e9310, 0x56fbfc1fe4f0682e, 0xea8d5de3105edf9b, + 0x71abfdb12379187a, 0x2eb99de1bee77b9c, 0x21ecc0ea33cf4523, 0x59a4d7521805c7a1, + 0x3896f5eb56ae7c72, 0xaa638f3db18f75dc, 0x9f39358dabe9808e, 0xb7defa91c00b72ac, + 0x6b5541fd62492d92, 0x6dc6dee8f92e4d5b, 0x353f57abc4beea7e, 0x735769d6da5690ce, + 0x0a234aa642391484, 0xf6f9508028f80d9d, 0xb8e319a27ab3f215, 0x31ad9c1151341a4d, + 0x773c22a57bef5805, 0x45c7561a07968633, 0xf913da9e249dbe36, 0xda652d9b78a64c68, + 0x4c27a97f3bc334ef, 0x76621220e66b17f4, 0x967743899acd7d0b, 0xf3ee5bcae0ed6782, + 0x409f753600c879fc, 0x06d09a39b5926db6, 0x6f83aeb0317ac588, 0x01e6ca4a86381f21, + 0x66ff3462d19f3025, 0x72207c24ddfd3bfb, 0x4af6b6d3e2ece2eb, 0x9c994dbec7ea08de, + 0x49ace597b09a8bc4, 0xb38c4766cf0797ba, 0x131b9373c57c2a75, 0xb1822cce61931e58, + 0x9d7555b909ba1c0c, 0x127fafdd937d11d2, 0x29da3badc66d92e4, 0xa2c1d57154c2ecbc, + 0x58c5134d82f6fe24, 0x1c3ae3515b62274f, 0xe907c82e01cb8126, 0xf8ed091913e37fcb, + 0x3249d8f9c80046c9, 0x80cf9bede388fb63, 0x1881539a116cf19e, 0x5103f3f76bd52457, + 0x15b7e6f5ae47f7a8, 0xdbd7c6ded47e9ccf, 0x44e55c410228bb1a, 0xb647d4255edb4e99, + 0x5d11882bb8aafc30, 0xf5098bbb29d3212a, 0x8fb5ea14e90296b3, 0x677b942157dd025a, + 0xfb58e7c0a390acb5, 0x89d3674c83bd4a01, 0x9e2da4df4bf3b93b, 0xfcc41e328cab4829, + 0x03f38c96ba582c52, 0xcad1bdbd7fd85db2, 0xbbb442c16082ae83, 0xb95fe86ba5da9ab0, + 0xb22e04673771a93f, 0x845358c9493152d8, 0xbe2a488697b4541e, 0x95a2dc2dd38e6966, + 0xc02c11ac923c852b, 0x2388b1990df2a87b, 0x7c8008fa1b4f37be, 0x1f70d0c84d54e503, + 0x5490adec7ece57d4, 0x002b3c27d9063a3a, 0x7eaea3848030a2bf, 0xc602326ded2003c0, + 0x83a7287d69a94086, 0xc57a5fcb30f57a8a, 0xb56844e479ebe779, 0xa373b40f05dcbce9, + 0xd71a786e88570ee2, 0x879cbacdbde8f6a0, 0x976ad1bcc164a32f, 0xab21e25e9666d78b, + 0x901063aae5e5c33c, 0x9818b34448698d90, 0xe36487ae3e1e8abb, 0xafbdf931893bdcb4, + 0x6345a0dc5fbbd519, 0x8628fe269b9465ca, 0x1e5d01603f9c51ec, 0x4de44006a15049b7, + 0xbf6c70e5f776cbb1, 0x411218f2ef552bed, 0xcb0c0708705a36a3, 0xe74d14754f986044, + 0xcd56d9430ea8280e, 0xc12591d7535f5065, 0xc83223f1720aef96, 0xc3a0396f7363a51f, +} + +Tiger_Context :: struct { + a: u64, + b: u64, + c: u64, + x: [64]byte, + nx: int, + length: u64, + ver: int, +} + +round :: #force_inline proc "contextless"(a, b, c, x, mul: u64) -> (u64, u64, u64) { + a, b, c := a, b, c + c ~= x + a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff] + b += T4[(c >> 8) & 0xff] ~ T3[(c >> 24) & 0xff] ~ T2[(c >> 40) & 0xff] ~ T1[(c >> 56) & 0xff] + b *= mul + return a, b, c +} + +pass :: #force_inline proc "contextless"(a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) { + x, y, z = round(a, b, c, d[0], mul) + y, z, x = round(y, z, x, d[1], mul) + z, x, y = round(z, x, y, d[2], mul) + x, y, z = round(x, y, z, d[3], mul) + y, z, x = round(y, z, x, d[4], mul) + z, x, y = round(z, x, y, d[5], mul) + x, y, z = round(x, y, z, d[6], mul) + y, z, x = round(y, z, x, d[7], mul) + return +} + +key_schedule :: #force_inline proc "contextless"(x: []u64) { + x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5 + x[1] ~= x[0] + x[2] += x[1] + x[3] -= x[2] ~ ((~x[1]) << 19) + x[4] ~= x[3] + x[5] += x[4] + x[6] -= x[5] ~ ((~x[4]) >> 23) + x[7] ~= x[6] + x[0] += x[7] + x[1] -= x[0] ~ ((~x[7]) << 19) + x[2] ~= x[1] + x[3] += x[2] + x[4] -= x[3] ~ ((~x[2]) >> 23) + x[5] ~= x[4] + x[6] += x[5] + x[7] -= x[6] ~ 0x0123456789abcdef +} + +compress :: #force_inline proc "contextless"(ctx: ^Tiger_Context, data: []byte) { + a := ctx.a + b := ctx.b + c := ctx.c + x := util.cast_slice([]u64, data) + ctx.a, ctx.b, ctx.c = pass(ctx.a, ctx.b, ctx.c, x, 5) + key_schedule(x) + ctx.c, ctx.a, ctx.b = pass(ctx.c, ctx.a, ctx.b, x, 7) + key_schedule(x) + ctx.b, ctx.c, ctx.a = pass(ctx.b, ctx.c, ctx.a, x, 9) + ctx.a ~= a + ctx.b -= b + ctx.c += c +} + +init_odin :: proc(ctx: ^Tiger_Context) { + ctx.a = 0x0123456789abcdef + ctx.b = 0xfedcba9876543210 + ctx.c = 0xf096a5b4c3b2e187 +} + +update_odin :: proc(ctx: ^Tiger_Context, input: []byte) { + p := make([]byte, len(input)) + copy(p, input) + + length := len(p) + ctx.length += u64(length) + if ctx.nx > 0 { + n := len(p) + if n > 64 - ctx.nx { + n = 64 - ctx.nx + } + copy(ctx.x[ctx.nx:ctx.nx + n], p[:n]) + ctx.nx += n + if ctx.nx == 64 { + compress(ctx, ctx.x[:64 - 1]) + ctx.nx = 0 + } + p = p[n:] + } + for len(p) >= 64 { + compress(ctx, p[:64]) + p = p[64:] + } + if len(p) > 0 { + ctx.nx = copy(ctx.x[:], p) + } +} + +final_odin :: proc(ctx: ^Tiger_Context, hash: []byte) { + length := ctx.length + tmp: [64]byte + if ctx.ver == 1 { + tmp[0] = 0x01 + } else { + tmp[0] = 0x80 + } + + size := length & 0x3f + if size < 56 { + update_odin(ctx, tmp[:56 - size]) + } else { + update_odin(ctx, tmp[:64 + 56 - size]) + } + + length <<= 3 + for i := uint(0); i < 8; i += 1 { + tmp[i] = byte(length >> (8 * i)) + } + update_odin(ctx, tmp[:8]) + + for i := uint(0); i < 8; i += 1 { + tmp[i] = byte(ctx.a >> (8 * i)) + tmp[i + 8] = byte(ctx.b >> (8 * i)) + tmp[i + 16] = byte(ctx.c >> (8 * i)) + } + copy(hash[:], tmp[:len(hash)]) +} \ No newline at end of file diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin new file mode 100644 index 000000000..aecd57ab1 --- /dev/null +++ b/core/crypto/blake/blake.odin @@ -0,0 +1,846 @@ +package blake + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the BLAKE hashing algorithm, as defined in +*/ + +import "core:os" +import "core:io" + +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since BLAKE is not available in Botan +@(warning="BLAKE is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_blake256_ctx :: #force_inline proc(is224: bool, size: _ctx.Hash_Size) { + ctx: Blake256_Context + ctx.is224 = is224 + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = size +} + +@(private) +_create_blake512_ctx :: #force_inline proc(is384: bool, size: _ctx.Hash_Size) { + ctx: Blake512_Context + ctx.is384 = is384 + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = size +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_blake256_ctx(true, ._28) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_blake256_ctx(true, ._28) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_blake256_ctx(true, ._28) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_blake256_ctx(false, ._32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_blake256_ctx(false, ._32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_blake256_ctx(false, ._32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_blake512_ctx(true, ._48) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_blake512_ctx(true, ._48) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_blake512_ctx(true, ._48) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_blake512_ctx(false, ._64) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_blake512_ctx(false, ._64) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_blake512_ctx(false, ._64) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + if ctx.hash_size == ._28 || ctx.hash_size == ._32 { + _create_blake256_ctx(ctx.hash_size == ._28, ctx.hash_size) + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + init_odin(&c) + } + return + } + if ctx.hash_size == ._48 || ctx.hash_size == ._64 { + _create_blake512_ctx(ctx.hash_size == ._48, ctx.hash_size) + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + init_odin(&c) + } + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + #partial switch ctx.hash_size { + case ._28, ._32: + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + update_odin(&c, data) + } + case ._48, ._64: + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + update_odin(&c, data) + } + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + #partial switch ctx.hash_size { + case ._28, ._32: + if c, ok := ctx.internal_ctx.(Blake256_Context); ok { + final_odin(&c, hash) + } + case ._48, ._64: + if c, ok := ctx.internal_ctx.(Blake512_Context); ok { + final_odin(&c, hash) + } + } +} + +/* + BLAKE implementation +*/ + +SIZE_224 :: 28 +SIZE_256 :: 32 +SIZE_384 :: 48 +SIZE_512 :: 64 +BLOCKSIZE_256 :: 64 +BLOCKSIZE_512 :: 128 + +Blake256_Context :: struct { + h: [8]u32, + s: [4]u32, + t: u64, + x: [64]byte, + nx: int, + is224: bool, + nullt: bool, +} + +Blake512_Context :: struct { + h: [8]u64, + s: [4]u64, + t: u64, + x: [128]byte, + nx: int, + is384: bool, + nullt: bool, +} + +SIGMA := [?]int { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, + 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, + 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, + 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, + 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, + 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, + 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, + 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, + 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, +} + +U256 := [16]u32 { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, +} + +U512 := [16]u64 { + 0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89, + 0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917, + 0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96, + 0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69, +} + +G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) { + a, b, c, d := a, b, c, d + a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]] + a += b + d ~= a + d = d << (32 - 16) | d >> 16 + c += d + b ~= c + b = b << (32 - 12) | b >> 12 + a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]] + a += b + d ~= a + d = d << (32 - 8) | d >> 8 + c += d + b ~= c + b = b << (32 - 7) | b >> 7 + return a, b, c, d +} + +G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) { + a, b, c, d := a, b, c, d + a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]] + a += b + d ~= a + d = d << (64 - 32) | d >> 32 + c += d + b ~= c + b = b << (64 - 25) | b >> 25 + a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]] + a += b + d ~= a + d = d << (64 - 16) | d >> 16 + c += d + b ~= c + b = b << (64 - 11) | b >> 11 + return a, b, c, d +} + +block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) { + i, j: int = ---, --- + v, m: [16]u32 = ---, --- + p := p + for len(p) >= BLOCKSIZE_256 { + v[0] = ctx.h[0] + v[1] = ctx.h[1] + v[2] = ctx.h[2] + v[3] = ctx.h[3] + v[4] = ctx.h[4] + v[5] = ctx.h[5] + v[6] = ctx.h[6] + v[7] = ctx.h[7] + v[8] = ctx.s[0] ~ U256[0] + v[9] = ctx.s[1] ~ U256[1] + v[10] = ctx.s[2] ~ U256[2] + v[11] = ctx.s[3] ~ U256[3] + v[12] = U256[4] + v[13] = U256[5] + v[14] = U256[6] + v[15] = U256[7] + + ctx.t += 512 + if !ctx.nullt { + v[12] ~= u32(ctx.t) + v[13] ~= u32(ctx.t) + v[14] ~= u32(ctx.t >> 32) + v[15] ~= u32(ctx.t >> 32) + } + + for i, j = 0, 0; i < 16; i, j = i+1, j+4 { + m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3]) + } + + for i = 0; i < 14; i += 1 { + v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0) + v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1) + v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2) + v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3) + v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4) + v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5) + v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6) + v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7) + } + + for i = 0; i < 8; i += 1 { + ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8] + } + p = p[BLOCKSIZE_256:] + } +} + +block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check { + i, j: int = ---, --- + v, m: [16]u64 = ---, --- + p := p + for len(p) >= BLOCKSIZE_512 { + v[0] = ctx.h[0] + v[1] = ctx.h[1] + v[2] = ctx.h[2] + v[3] = ctx.h[3] + v[4] = ctx.h[4] + v[5] = ctx.h[5] + v[6] = ctx.h[6] + v[7] = ctx.h[7] + v[8] = ctx.s[0] ~ U512[0] + v[9] = ctx.s[1] ~ U512[1] + v[10] = ctx.s[2] ~ U512[2] + v[11] = ctx.s[3] ~ U512[3] + v[12] = U512[4] + v[13] = U512[5] + v[14] = U512[6] + v[15] = U512[7] + + ctx.t += 1024 + if !ctx.nullt { + v[12] ~= ctx.t + v[13] ~= ctx.t + v[14] ~= 0 + v[15] ~= 0 + } + + for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 { + m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 | + u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7]) + } + for i = 0; i < 16; i += 1 { + v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0) + v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1) + v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2) + v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3) + v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4) + v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5) + v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6) + v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7) + } + + for i = 0; i < 8; i += 1 { + ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8] + } + p = p[BLOCKSIZE_512:] + } +} + +init_odin :: proc(ctx: ^$T) { + when T == Blake256_Context { + if ctx.is224 { + ctx.h[0] = 0xc1059ed8 + ctx.h[1] = 0x367cd507 + ctx.h[2] = 0x3070dd17 + ctx.h[3] = 0xf70e5939 + ctx.h[4] = 0xffc00b31 + ctx.h[5] = 0x68581511 + ctx.h[6] = 0x64f98fa7 + ctx.h[7] = 0xbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667 + ctx.h[1] = 0xbb67ae85 + ctx.h[2] = 0x3c6ef372 + ctx.h[3] = 0xa54ff53a + ctx.h[4] = 0x510e527f + ctx.h[5] = 0x9b05688c + ctx.h[6] = 0x1f83d9ab + ctx.h[7] = 0x5be0cd19 + } + } else when T == Blake512_Context { + if ctx.is384 { + ctx.h[0] = 0xcbbb9d5dc1059ed8 + ctx.h[1] = 0x629a292a367cd507 + ctx.h[2] = 0x9159015a3070dd17 + ctx.h[3] = 0x152fecd8f70e5939 + ctx.h[4] = 0x67332667ffc00b31 + ctx.h[5] = 0x8eb44a8768581511 + ctx.h[6] = 0xdb0c2e0d64f98fa7 + ctx.h[7] = 0x47b5481dbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667f3bcc908 + ctx.h[1] = 0xbb67ae8584caa73b + ctx.h[2] = 0x3c6ef372fe94f82b + ctx.h[3] = 0xa54ff53a5f1d36f1 + ctx.h[4] = 0x510e527fade682d1 + ctx.h[5] = 0x9b05688c2b3e6c1f + ctx.h[6] = 0x1f83d9abfb41bd6b + ctx.h[7] = 0x5be0cd19137e2179 + } + } +} + +update_odin :: proc(ctx: ^$T, data: []byte) { + data := data + when T == Blake256_Context { + if ctx.nx > 0 { + n := copy(ctx.x[ctx.nx:], data) + ctx.nx += n + if ctx.nx == BLOCKSIZE_256 { + block256(ctx, ctx.x[:]) + ctx.nx = 0 + } + data = data[n:] + } + if len(data) >= BLOCKSIZE_256 { + n := len(data) &~ (BLOCKSIZE_256 - 1) + block256(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.nx = copy(ctx.x[:], data) + } + } else when T == Blake512_Context { + if ctx.nx > 0 { + n := copy(ctx.x[ctx.nx:], data) + ctx.nx += n + if ctx.nx == BLOCKSIZE_512 { + block512(ctx, ctx.x[:]) + ctx.nx = 0 + } + data = data[n:] + } + if len(data) >= BLOCKSIZE_512 { + n := len(data) &~ (BLOCKSIZE_512 - 1) + block512(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.nx = copy(ctx.x[:], data) + } + } +} + +final_odin :: proc(ctx: ^$T, hash: []byte) { + when T == Blake256_Context { + tmp: [65]byte + } else when T == Blake512_Context { + tmp: [129]byte + } + nx := u64(ctx.nx) + tmp[0] = 0x80 + length := (ctx.t + nx) << 3 + + when T == Blake256_Context { + if nx == 55 { + if ctx.is224 { + write_additional(ctx, {0x80}) + } else { + write_additional(ctx, {0x81}) + } + } else { + if nx < 55 { + if nx == 0 { + ctx.nullt = true + } + write_additional(ctx, tmp[0 : 55 - nx]) + } else { + write_additional(ctx, tmp[0 : 64 - nx]) + write_additional(ctx, tmp[1:56]) + ctx.nullt = true + } + if ctx.is224 { + write_additional(ctx, {0x00}) + } else { + write_additional(ctx, {0x01}) + } + } + + for i : uint = 0; i < 8; i += 1 { + tmp[i] = byte(length >> (56 - 8 * i)) + } + write_additional(ctx, tmp[0:8]) + + h := ctx.h[:] + if ctx.is224 { + h = h[0:7] + } + for s, i in h { + hash[i * 4] = byte(s >> 24) + hash[i * 4 + 1] = byte(s >> 16) + hash[i * 4 + 2] = byte(s >> 8) + hash[i * 4 + 3] = byte(s) + } + } else when T == Blake512_Context { + if nx == 111 { + if ctx.is384 { + write_additional(ctx, {0x80}) + } else { + write_additional(ctx, {0x81}) + } + } else { + if nx < 111 { + if nx == 0 { + ctx.nullt = true + } + write_additional(ctx, tmp[0 : 111 - nx]) + } else { + write_additional(ctx, tmp[0 : 128 - nx]) + write_additional(ctx, tmp[1:112]) + ctx.nullt = true + } + if ctx.is384 { + write_additional(ctx, {0x00}) + } else { + write_additional(ctx, {0x01}) + } + } + + for i : uint = 0; i < 16; i += 1 { + tmp[i] = byte(length >> (120 - 8 * i)) + } + write_additional(ctx, tmp[0:16]) + + h := ctx.h[:] + if ctx.is384 { + h = h[0:6] + } + for s, i in h { + hash[i * 8] = byte(s >> 56) + hash[i * 8 + 1] = byte(s >> 48) + hash[i * 8 + 2] = byte(s >> 40) + hash[i * 8 + 3] = byte(s >> 32) + hash[i * 8 + 4] = byte(s >> 24) + hash[i * 8 + 5] = byte(s >> 16) + hash[i * 8 + 6] = byte(s >> 8) + hash[i * 8 + 7] = byte(s) + } + } +} + +write_additional :: proc(ctx: ^$T, data: []byte) { + ctx.t -= u64(len(data)) << 3 + update_odin(ctx, data) +} diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin new file mode 100644 index 000000000..3db3d0e7b --- /dev/null +++ b/core/crypto/blake2b/blake2b.odin @@ -0,0 +1,189 @@ +package blake2b + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the BLAKE2B hashing algorithm. + BLAKE2B and BLAKE2B share the implementation in the _blake2 package. +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../_blake2" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_64 = hash_bytes_odin + ctx.hash_file_64 = hash_file_odin + ctx.hash_stream_64 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_BLAKE2B) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [64]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [64]byte { + _create_blake2_ctx() + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_blake2_ctx() + return _hash_impl->hash_stream_64(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_blake2_ctx() + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { + _blake2.init_odin(&c) + _blake2.update_odin(&c, data) + _blake2.blake2b_final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { + _blake2.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _blake2.update_odin(&c, buf[:read]) + } + } + _blake2.blake2b_final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_create_blake2_ctx :: #force_inline proc() { + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._64 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_blake2_ctx() + if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { + _blake2.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { + _blake2.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { + _blake2.blake2b_final_odin(&c, hash) + } +} diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin new file mode 100644 index 000000000..41a964472 --- /dev/null +++ b/core/crypto/blake2s/blake2s.odin @@ -0,0 +1,189 @@ +package blake2s + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the BLAKE2S hashing algorithm. + BLAKE2B and BLAKE2B share the implementation in the _blake2 package. +*/ + +import "core:os" +import "core:io" + +import "../_ctx" +import "../_blake2" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_32 = hash_bytes_odin + ctx.hash_file_32 = hash_file_odin + ctx.hash_stream_32 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since Blake2s is not available in Botan +@(warning="Blake2s is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [32]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [32]byte { + _create_blake2_ctx() + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_blake2_ctx() + return _hash_impl->hash_stream_32(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_blake2_ctx() + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { + _blake2.init_odin(&c) + _blake2.update_odin(&c, data) + _blake2.blake2s_final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { + _blake2.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _blake2.update_odin(&c, buf[:read]) + } + } + _blake2.blake2s_final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +@(private) +_create_blake2_ctx :: #force_inline proc() { + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._32 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_blake2_ctx() + if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { + _blake2.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { + _blake2.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { + _blake2.blake2s_final_odin(&c, hash) + } +} diff --git a/core/crypto/botan/botan.lib b/core/crypto/botan/botan.lib new file mode 100644 index 0000000000000000000000000000000000000000..5731855cb19dff1909cc06aa464f5770cf956253 GIT binary patch literal 3298832 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

CR)&w!H<$h8O-Y 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%0AaP?91QxRLSSqlsKo%n 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

*z#JZ>_GPI>nQ4{r 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 z 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∾ve1w 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

%UjSP7 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�^k`U9&@3a)2`AXOuolQWKcFcmy(lrS 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 cstring --- + ffi_api_version :: proc() -> c.int --- + ffi_supports_api :: proc(api_version: c.int) -> c.int --- + version_string :: proc() -> cstring --- + version_major :: proc() -> c.int --- + version_minor :: proc() -> c.int --- + version_patch :: proc() -> c.int --- + version_datestamp :: proc() -> c.int --- + + constant_time_compare :: proc(x, y: ^c.char, length: c.size_t) -> c.int --- + same_mem :: proc(x, y: ^c.char, length: c.size_t) -> c.int --- + scrub_mem :: proc(mem: rawptr, bytes: c.size_t) -> c.int --- + + hex_encode :: proc(x: ^c.char, length: c.size_t, out: ^c.char, flags: c.uint) -> c.int --- + hex_decode :: proc(hex_str: cstring, in_len: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- + + base64_encode :: proc(x: ^c.char, length: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- + base64_decode :: proc(base64_str: cstring, in_len: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- + + rng_init :: proc(rng: ^rng_t, rng_type: cstring) -> c.int --- + rng_init_custom :: proc(rng_out: ^rng_t, rng_name: cstring, ctx: rawptr, + get_cb: proc(ctx: rawptr, out: ^c.char, out_len: c.size_t) -> ^c.int, + add_entropy_cb: proc(ctx: rawptr, input: ^c.char, length: c.size_t) -> ^c.int, + destroy_cb: proc(ctx: rawptr) -> rawptr) -> c.int --- + rng_get :: proc(rng: rng_t, out: ^c.char, out_len: c.size_t) -> c.int --- + rng_reseed :: proc(rng: rng_t, bits: c.size_t) -> c.int --- + rng_reseed_from_rng :: proc(rng, source_rng: rng_t, bits: c.size_t) -> c.int --- + rng_add_entropy :: proc(rng: rng_t, entropy: ^c.char, entropy_len: c.size_t) -> c.int --- + rng_destroy :: proc(rng: rng_t) -> c.int --- + + hash_init :: proc(hash: ^hash_t, hash_name: cstring, flags: c.uint) -> c.int --- + hash_copy_state :: proc(dest: ^hash_t, source: hash_t) -> c.int --- + hash_output_length :: proc(hash: hash_t, output_length: ^c.size_t) -> c.int --- + hash_block_size :: proc(hash: hash_t, block_size: ^c.size_t) -> c.int --- + hash_update :: proc(hash: hash_t, input: ^c.char, input_len: c.size_t) -> c.int --- + hash_final :: proc(hash: hash_t, out: ^c.char) -> c.int --- + hash_clear :: proc(hash: hash_t) -> c.int --- + hash_destroy :: proc(hash: hash_t) -> c.int --- + hash_name :: proc(hash: hash_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- + + mac_init :: proc(mac: ^mac_t, hash_name: cstring, flags: c.uint) -> c.int --- + mac_output_length :: proc(mac: mac_t, output_length: ^c.size_t) -> c.int --- + mac_set_key :: proc(mac: mac_t, key: ^c.char, key_len: c.size_t) -> c.int --- + mac_update :: proc(mac: mac_t, buf: ^c.char, length: c.size_t) -> c.int --- + mac_final :: proc(mac: mac_t, out: ^c.char) -> c.int --- + mac_clear :: proc(mac: mac_t) -> c.int --- + mac_name :: proc(mac: mac_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- + mac_get_keyspec :: proc(mac: mac_t, out_minimum_keylength, out_maximum_keylength, out_keylength_modulo: ^c.size_t) -> c.int --- + mac_destroy :: proc(mac: mac_t) -> c.int --- + + cipher_init :: proc(cipher: ^cipher_t, name: cstring, flags: c.uint) -> c.int --- + cipher_name :: proc(cipher: cipher_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- + cipher_output_length :: proc(cipher: cipher_t, output_length: ^c.size_t) -> c.int --- + cipher_valid_nonce_length :: proc(cipher: cipher_t, nl: c.size_t) -> c.int --- + cipher_get_tag_length :: proc(cipher: cipher_t, tag_size: ^c.size_t) -> c.int --- + cipher_get_default_nonce_length :: proc(cipher: cipher_t, nl: ^c.size_t) -> c.int --- + cipher_get_update_granularity :: proc(cipher: cipher_t, ug: ^c.size_t) -> c.int --- + cipher_query_keylen :: proc(cipher: cipher_t, out_minimum_keylength, out_maximum_keylength: ^c.size_t) -> c.int --- + cipher_get_keyspec :: proc(cipher: cipher_t, min_keylen, max_keylen, mod_keylen: ^c.size_t) -> c.int --- + cipher_set_key :: proc(cipher: cipher_t, key: ^c.char, key_len: c.size_t) -> c.int --- + cipher_reset :: proc(cipher: cipher_t) -> c.int --- + cipher_set_associated_data :: proc(cipher: cipher_t, ad: ^c.char, ad_len: c.size_t) -> c.int --- + cipher_start :: proc(cipher: cipher_t, nonce: ^c.char, nonce_len: c.size_t) -> c.int --- + cipher_update :: proc(cipher: cipher_t, flags: c.uint, output: ^c.char, output_size: c.size_t, output_written: ^c.size_t, + input_bytes: ^c.char, input_size: c.size_t, input_consumed: ^c.size_t) -> c.int --- + cipher_clear :: proc(hash: cipher_t) -> c.int --- + cipher_destroy :: proc(cipher: cipher_t) -> c.int --- + + @(deprecated="Use botan.pwdhash") + pbkdf :: proc(pbkdf_algo: cstring, out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, + salt_len, iterations: c.size_t) -> c.int --- + @(deprecated="Use botan.pwdhash_timed") + pbkdf_timed :: proc(pbkdf_algo: cstring, out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, + salt_len, milliseconds_to_run: c.size_t, out_iterations_used: ^c.size_t) -> c.int --- + pwdhash :: proc(algo: cstring, param1, param2, param3: c.size_t, out: ^c.char, out_len: c.size_t, passphrase: cstring, + passphrase_len: c.size_t, salt: ^c.char, salt_len: c.size_t) -> c.int --- + pwdhash_timed :: proc(algo: cstring, msec: c.uint, param1, param2, param3: c.size_t, out: ^c.char, out_len: c.size_t, + passphrase: cstring, passphrase_len: c.size_t, salt: ^c.char, salt_len: c.size_t) -> c.int --- + @(deprecated="Use botan.pwdhash") + scrypt :: proc(out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, salt_len, N, r, p: c.size_t) -> c.int --- + kdf :: proc(kdf_algo: cstring, out: ^c.char, out_len: c.size_t, secret: ^c.char, secret_lent: c.size_t, salt: ^c.char, + salt_len: c.size_t, label: ^c.char, label_len: c.size_t) -> c.int --- + + block_cipher_init :: proc(bc: ^block_cipher_t, name: cstring) -> c.int --- + block_cipher_destroy :: proc(bc: block_cipher_t) -> c.int --- + block_cipher_clear :: proc(bc: block_cipher_t) -> c.int --- + block_cipher_set_key :: proc(bc: block_cipher_t, key: ^c.char, key_len: c.size_t) -> c.int --- + block_cipher_block_size :: proc(bc: block_cipher_t) -> c.int --- + block_cipher_encrypt_blocks :: proc(bc: block_cipher_t, input, out: ^c.char, blocks: c.size_t) -> c.int --- + block_cipher_decrypt_blocks :: proc(bc: block_cipher_t, input, out: ^c.char, blocks: c.size_t) -> c.int --- + block_cipher_name :: proc(bc: block_cipher_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- + block_cipher_get_keyspec :: proc(bc: block_cipher_t, out_minimum_keylength, out_maximum_keylength, out_keylength_modulo: ^c.size_t) -> c.int --- + + mp_init :: proc(mp: ^mp_t) -> c.int --- + mp_destroy :: proc(mp: mp_t) -> c.int --- + mp_to_hex :: proc(mp: mp_t, out: ^c.char) -> c.int --- + mp_to_str :: proc(mp: mp_t, base: c.char, out: ^c.char, out_len: ^c.size_t) -> c.int --- + mp_clear :: proc(mp: mp_t) -> c.int --- + mp_set_from_int :: proc(mp: mp_t, initial_value: c.int) -> c.int --- + mp_set_from_mp :: proc(dest, source: mp_t) -> c.int --- + mp_set_from_str :: proc(dest: mp_t, str: cstring) -> c.int --- + mp_set_from_radix_str :: proc(mp: mp_t, str: cstring, radix: c.size_t) -> c.int --- + mp_num_bits :: proc(n: mp_t, bits: ^c.size_t) -> c.int --- + mp_num_bytes :: proc(n: mp_t, bytes: ^c.size_t) -> c.int --- + mp_to_bin :: proc(mp: mp_t, vec: ^c.char) -> c.int --- + mp_from_bin :: proc(mp: mp_t, vec: ^c.char, vec_len: c.size_t) -> c.int --- + mp_to_uint32 :: proc(mp: mp_t, val: ^c.uint) -> c.int --- + mp_is_positive :: proc(mp: mp_t) -> c.int --- + mp_is_negative :: proc(mp: mp_t) -> c.int --- + mp_flip_sign :: proc(mp: mp_t) -> c.int --- + mp_is_zero :: proc(mp: mp_t) -> c.int --- + @(deprecated="Use botan.mp_get_bit(0)") + mp_is_odd :: proc(mp: mp_t) -> c.int --- + @(deprecated="Use botan.mp_get_bit(0)") + mp_is_even :: proc(mp: mp_t) -> c.int --- + mp_add_u32 :: proc(result, x: mp_t, y: c.uint) -> c.int --- + mp_sub_u32 :: proc(result, x: mp_t, y: c.uint) -> c.int --- + mp_add :: proc(result, x, y: mp_t) -> c.int --- + mp_sub :: proc(result, x, y: mp_t) -> c.int --- + mp_mul :: proc(result, x, y: mp_t) -> c.int --- + mp_div :: proc(quotient, remainder, x, y: mp_t) -> c.int --- + mp_mod_mul :: proc(result, x, y, mod: mp_t) -> c.int --- + mp_equal :: proc(x, y: mp_t) -> c.int --- + mp_cmp :: proc(result: ^c.int, x, y: mp_t) -> c.int --- + mp_swap :: proc(x, y: mp_t) -> c.int --- + mp_powmod :: proc(out, base, exponent, modulus: mp_t) -> c.int --- + mp_lshift :: proc(out, input: mp_t, shift: c.size_t) -> c.int --- + mp_rshift :: proc(out, input: mp_t, shift: c.size_t) -> c.int --- + mp_mod_inverse :: proc(out, input, modulus: mp_t) -> c.int --- + mp_rand_bits :: proc(rand_out: mp_t, rng: rng_t, bits: c.size_t) -> c.int --- + mp_rand_range :: proc(rand_out: mp_t, rng: rng_t, lower_bound, upper_bound: mp_t) -> c.int --- + mp_gcd :: proc(out, x, y: mp_t) -> c.int --- + mp_is_prime :: proc(n: mp_t, rng: rng_t, test_prob: c.size_t) -> c.int --- + mp_get_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- + mp_set_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- + mp_clear_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- + + bcrypt_generate :: proc(out: ^c.char, out_len: ^c.size_t, password: cstring, rng: rng_t, work_factor: c.size_t, flags: c.uint) -> c.int --- + bcrypt_is_valid :: proc(pass, hash: cstring) -> c.int --- + + privkey_create :: proc(key: ^privkey_t, algo_name, algo_params: cstring, rng: rng_t) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_check_key :: proc(key: privkey_t, rng: rng_t, flags: c.uint) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_create_rsa :: proc(key: ^privkey_t, rng: rng_t, bits: c.size_t) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_create_ecdsa :: proc(key: ^privkey_t, rng: rng_t, params: cstring) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_create_ecdh :: proc(key: ^privkey_t, rng: rng_t, params: cstring) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_create_mceliece :: proc(key: ^privkey_t, rng: rng_t, n, t: c.size_t) -> c.int --- + @(deprecated="Use botan.privkey_create") + privkey_create_dh :: proc(key: ^privkey_t, rng: rng_t, param: cstring) -> c.int --- + privkey_create_dsa :: proc(key: ^privkey_t, rng: rng_t, pbits, qbits: c.size_t) -> c.int --- + privkey_create_elgamal :: proc(key: ^privkey_t, rng: rng_t, pbits, qbits: c.size_t) -> c.int --- + privkey_load :: proc(key: ^privkey_t, rng: rng_t, bits: ^c.char, length: c.size_t, password: cstring) -> c.int --- + privkey_destroy :: proc(key: privkey_t) -> c.int --- + privkey_export :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- + privkey_algo_name :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + @(deprecated="Use botan.privkey_export_encrypted_pbkdf_{msec,iter}") + privkey_export_encrypted :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase, encryption_algo: cstring, flags: c.uint) -> c.int --- + privkey_export_encrypted_pbkdf_msec :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase: cstring, pbkdf_msec_runtime: c.uint, + pbkdf_iterations_out: ^c.size_t, cipher_algo, pbkdf_algo: cstring, flags: c.uint) -> c.int --- + privkey_export_encrypted_pbkdf_iter :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase: cstring, pbkdf_iterations: c.size_t, + cipher_algo, pbkdf_algo: cstring, flags: c.uint) -> c.int --- + pubkey_load :: proc(key: ^pubkey_t, bits: ^c.char, length: c.size_t) -> c.int --- + privkey_export_pubkey :: proc(out: ^pubkey_t, input: privkey_t) -> c.int --- + pubkey_export :: proc(key: pubkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- + pubkey_algo_name :: proc(key: pubkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + pubkey_check_key :: proc(key: pubkey_t, rng: rng_t, flags: c.uint) -> c.int --- + pubkey_estimated_strength :: proc(key: pubkey_t, estimate: ^c.size_t) -> c.int --- + pubkey_fingerprint :: proc(key: pubkey_t, hash: cstring, out: ^c.char, out_len: ^c.size_t) -> c.int --- + pubkey_destroy :: proc(key: pubkey_t) -> c.int --- + pubkey_get_field :: proc(output: mp_t, key: pubkey_t, field_name: cstring) -> c.int --- + privkey_get_field :: proc(output: mp_t, key: privkey_t, field_name: cstring) -> c.int --- + + privkey_load_rsa :: proc(key: ^privkey_t, p, q, e: mp_t) -> c.int --- + privkey_load_rsa_pkcs1 :: proc(key: ^privkey_t, bits: ^c.char, length: c.size_t) -> c.int --- + @(deprecated="Use botan.privkey_get_field") + privkey_rsa_get_p :: proc(p: mp_t, rsa_key: privkey_t) -> c.int --- + @(deprecated="Use botan.privkey_get_field") + privkey_rsa_get_q :: proc(q: mp_t, rsa_key: privkey_t) -> c.int --- + @(deprecated="Use botan.privkey_get_field") + privkey_rsa_get_d :: proc(d: mp_t, rsa_key: privkey_t) -> c.int --- + @(deprecated="Use botan.privkey_get_field") + privkey_rsa_get_n :: proc(n: mp_t, rsa_key: privkey_t) -> c.int --- + @(deprecated="Use botan.privkey_get_field") + privkey_rsa_get_e :: proc(e: mp_t, rsa_key: privkey_t) -> c.int --- + privkey_rsa_get_privkey :: proc(rsa_key: privkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- + pubkey_load_rsa :: proc(key: ^pubkey_t, n, e: mp_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_rsa_get_e :: proc(e: mp_t, rsa_key: pubkey_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_rsa_get_n :: proc(n: mp_t, rsa_key: pubkey_t) -> c.int --- + + privkey_load_dsa :: proc(key: ^privkey_t, p, q, g, x: mp_t) -> c.int --- + pubkey_load_dsa :: proc(key: ^pubkey_t, p, q, g, y: mp_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + privkey_dsa_get_x :: proc(n: mp_t, key: privkey_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_dsa_get_p :: proc(p: mp_t, key: pubkey_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_dsa_get_q :: proc(q: mp_t, key: pubkey_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_dsa_get_g :: proc(d: mp_t, key: pubkey_t) -> c.int --- + @(deprecated="Use botan.pubkey_get_field") + pubkey_dsa_get_y :: proc(y: mp_t, key: pubkey_t) -> c.int --- + + privkey_load_dh :: proc(key: ^privkey_t, p, g, y: mp_t) -> c.int --- + pubkey_load_dh :: proc(key: ^pubkey_t, p, g, x: mp_t) -> c.int --- + + privkey_load_elgamal :: proc(key: ^privkey_t, p, g, y: mp_t) -> c.int --- + pubkey_load_elgamal :: proc(key: ^pubkey_t, p, g, x: mp_t) -> c.int --- + + privkey_load_ed25519 :: proc(key: ^privkey_t, privkey: [32]c.char) -> c.int --- + pubkey_load_ed25519 :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- + privkey_ed25519_get_privkey :: proc(key: ^privkey_t, output: [64]c.char) -> c.int --- + pubkey_ed25519_get_pubkey :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- + + privkey_load_x25519 :: proc(key: ^privkey_t, privkey: [32]c.char) -> c.int --- + pubkey_load_x25519 :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- + privkey_x25519_get_privkey :: proc(key: ^privkey_t, output: [32]c.char) -> c.int --- + pubkey_x25519_get_pubkey :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- + + privkey_load_ecdsa :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- + pubkey_load_ecdsa :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- + pubkey_load_ecdh :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- + privkey_load_ecdh :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- + pubkey_load_sm2 :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- + privkey_load_sm2 :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- + @(deprecated="Use botan.pubkey_load_sm2") + pubkey_load_sm2_enc :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- + @(deprecated="Use botan.privkey_load_sm2") + privkey_load_sm2_enc :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- + pubkey_sm2_compute_za :: proc(out: ^c.char, out_len: ^c.size_t, ident, hash_algo: cstring, key: pubkey_t) -> c.int --- + + pk_op_encrypt_create :: proc(op: ^pk_op_encrypt_t, key: pubkey_t, padding: cstring, flags: c.uint) -> c.int --- + pk_op_encrypt_destroy :: proc(op: pk_op_encrypt_t) -> c.int --- + pk_op_encrypt_output_length :: proc(op: pk_op_encrypt_t, ptext_len: c.size_t, ctext_len: ^c.size_t) -> c.int --- + pk_op_encrypt :: proc(op: pk_op_encrypt_t, rng: rng_t, out: ^c.char, out_len: ^c.size_t, plaintext: cstring, plaintext_len: c.size_t) -> c.int --- + + pk_op_decrypt_create :: proc(op: ^pk_op_decrypt_t, key: privkey_t, padding: cstring, flags: c.uint) -> c.int --- + pk_op_decrypt_destroy :: proc(op: pk_op_decrypt_t) -> c.int --- + pk_op_decrypt_output_length :: proc(op: pk_op_decrypt_t, ptext_len: c.size_t, ctext_len: ^c.size_t) -> c.int --- + pk_op_decrypt :: proc(op: pk_op_decrypt_t, rng: rng_t, out: ^c.char, out_len: ^c.size_t, ciphertext: cstring, ciphertext_len: c.size_t) -> c.int --- + + pk_op_sign_create :: proc(op: ^pk_op_sign_t, key: privkey_t, hash_and_padding: cstring, flags: c.uint) -> c.int --- + pk_op_sign_destroy :: proc(op: pk_op_sign_t) -> c.int --- + pk_op_sign_output_length :: proc(op: pk_op_sign_t, olen: ^c.size_t) -> c.int --- + pk_op_sign_update :: proc(op: pk_op_sign_t, input: ^c.char, input_len: c.size_t) -> c.int --- + pk_op_sign_finish :: proc(op: pk_op_sign_t, rng: rng_t, sig: ^c.char, sig_len: ^c.size_t) -> c.int --- + + pk_op_verify_create :: proc(op: ^pk_op_verify_t, hash_and_padding: cstring, flags: c.uint) -> c.int --- + pk_op_verify_destroy :: proc(op: pk_op_verify_t) -> c.int --- + pk_op_verify_update :: proc(op: pk_op_verify_t, input: ^c.char, input_len: c.size_t) -> c.int --- + pk_op_verify_finish :: proc(op: pk_op_verify_t, sig: ^c.char, sig_len: c.size_t) -> c.int --- + + pk_op_key_agreement_create :: proc(op: ^pk_op_ka_t, kdf: cstring, flags: c.uint) -> c.int --- + pk_op_key_agreement_destroy :: proc(op: pk_op_ka_t) -> c.int --- + pk_op_key_agreement_export_public :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + pk_op_key_agreement_size :: proc(op: pk_op_ka_t, out_len: ^c.size_t) -> c.int --- + pk_op_key_agreement :: proc(op: pk_op_ka_t, out: ^c.char, out_len: ^c.size_t, other_key: ^c.char, other_key_len: c.size_t, salt: ^c.char, + salt_len: c.size_t) -> c.int --- + + pkcs_hash_id :: proc(hash_name: cstring, pkcs_id: ^c.char, pkcs_id_len: ^c.size_t) -> c.int --- + + @(deprecated="Poorly specified, avoid in new code") + mceies_encrypt :: proc(mce_key: pubkey_t, rng: rng_t, aead: cstring, pt: ^c.char, pt_len: c.size_t, ad: ^c.char, ad_len: c.size_t, + ct: ^c.char, ct_len: ^c.size_t) -> c.int --- + @(deprecated="Poorly specified, avoid in new code") + mceies_decrypt :: proc(mce_key: privkey_t, aead: cstring, ct: ^c.char, ct_len: c.size_t, ad: ^c.char, ad_len: c.size_t, pt: ^c.char, + pt_len: ^c.size_t) -> c.int --- + + x509_cert_load :: proc(cert_obj: ^x509_cert_t, cert: ^c.char, cert_len: c.size_t) -> c.int --- + x509_cert_load_file :: proc(cert_obj: ^x509_cert_t, filename: cstring) -> c.int --- + x509_cert_destroy :: proc(cert: x509_cert_t) -> c.int --- + x509_cert_dup :: proc(new_cert: ^x509_cert_t, cert: x509_cert_t) -> c.int --- + x509_cert_get_time_starts :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_time_expires :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_not_before :: proc(cert: x509_cert_t, time_since_epoch: ^c.ulonglong) -> c.int --- + x509_cert_not_after :: proc(cert: x509_cert_t, time_since_epoch: ^c.ulonglong) -> c.int --- + x509_cert_get_fingerprint :: proc(cert: x509_cert_t, hash: cstring, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_serial_number :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_authority_key_id :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_subject_key_id :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_public_key_bits :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_public_key :: proc(cert: x509_cert_t, key: ^pubkey_t) -> c.int --- + x509_cert_get_issuer_dn :: proc(cert: x509_cert_t, key: ^c.char, index: c.size_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_get_subject_dn :: proc(cert: x509_cert_t, key: ^c.char, index: c.size_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_to_string :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- + x509_cert_allowed_usage :: proc(cert: x509_cert_t, key_usage: c.uint) -> c.int --- + x509_cert_hostname_match :: proc(cert: x509_cert_t, hostname: cstring) -> c.int --- + x509_cert_verify :: proc(validation_result: ^c.int, cert: x509_cert_t, intermediates: ^x509_cert_t, intermediates_len: c.size_t, trusted: ^x509_cert_t, + trusted_len: c.size_t, trusted_path: cstring, required_strength: c.size_t, hostname: cstring, reference_time: c.ulonglong) -> c.int --- + x509_cert_validation_status :: proc(code: c.int) -> cstring --- + x509_crl_load_file :: proc(crl_obj: ^x509_crl_t, crl_path: cstring) -> c.int --- + x509_crl_load :: proc(crl_obj: ^x509_crl_t, crl_bits: ^c.char, crl_bits_len: c.size_t) -> c.int --- + x509_crl_destroy :: proc(crl: x509_crl_t) -> c.int --- + x509_is_revoked :: proc(crl: x509_crl_t, cert: x509_cert_t) -> c.int --- + x509_cert_verify_with_crl :: proc(validation_result: ^c.int, cert: x509_cert_t, intermediates: ^x509_cert_t, intermediates_len: c.size_t, trusted: ^x509_cert_t, + trusted_len: c.size_t, crls: ^x509_crl_t, crls_len: c.size_t, trusted_path: cstring, required_strength: c.size_t, + hostname: cstring, reference_time: c.ulonglong) -> c.int --- + + key_wrap3394 :: proc(key: ^c.char, key_len: c.size_t, kek: ^c.char, kek_len: c.size_t, wrapped_key: ^c.char, wrapped_key_len: ^c.size_t) -> c.int --- + key_unwrap3394 :: proc(wrapped_key: ^c.char, wrapped_key_len: c.size_t, kek: ^c.char, kek_len: c.size_t, key: ^c.char, key_len: ^c.size_t) -> c.int --- + + hotp_init :: proc(hotp: ^hotp_t, key: ^c.char, key_len: c.size_t, hash_algo: cstring, digits: c.size_t) -> c.int --- + hotp_destroy :: proc(hotp: hotp_t) -> c.int --- + hotp_generate :: proc(hotp: hotp_t, hotp_code: ^c.uint, hotp_counter: c.ulonglong) -> c.int --- + hotp_check :: proc(hotp: hotp_t, next_hotp_counter: ^c.ulonglong, hotp_code: c.uint, hotp_counter: c.ulonglong, resync_range: c.size_t) -> c.int --- + + totp_init :: proc(totp: ^totp_t, key: ^c.char, key_len: c.size_t, hash_algo: cstring, digits, time_step: c.size_t) -> c.int --- + totp_destroy :: proc(totp: totp_t) -> c.int --- + totp_generate :: proc(totp: totp_t, totp_code: ^c.uint, timestamp: c.ulonglong) -> c.int --- + totp_check :: proc(totp: totp_t, totp_code: ^c.uint, timestamp: c.ulonglong, acceptable_clock_drift: c.size_t) -> c.int --- + + fpe_fe1_init :: proc(fpe: ^fpe_t, n: mp_t, key: ^c.char, key_len, rounds: c.size_t, flags: c.uint) -> c.int --- + fpe_destroy :: proc(fpe: fpe_t) -> c.int --- + fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- + fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- +} \ No newline at end of file diff --git a/core/crypto/botan/hash.odin b/core/crypto/botan/hash.odin new file mode 100644 index 000000000..8f12f871c --- /dev/null +++ b/core/crypto/botan/hash.odin @@ -0,0 +1,471 @@ +package botan + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog: Initial creation and testing of the bindings. + + Implementation of the context for the Botan side. +*/ + +import "core:os" +import "core:io" +import "core:fmt" +import "core:strings" + +import "../_ctx" + +hash_bytes_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._16, 16), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._20, 20), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { + hash: [24]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._24, 24), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._28, 28), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._32, 32), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._48, 48), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._64, 64), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [128]byte { + hash: [128]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._128, 128), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash +} + +hash_bytes_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + hash := make([]byte, bit_size, allocator) + c: hash_t + hash_init(&c, _check_ctx(ctx, nil, bit_size), 0) + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + hash_final(c, &hash[0]) + hash_destroy(c) + return hash[:] +} + +hash_file_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_16(ctx, os.stream_from_handle(hd)) + } else { + return [16]byte{}, false + } +} + +hash_file_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_20(ctx, os.stream_from_handle(hd)) + } else { + return [20]byte{}, false + } +} + +hash_file_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([24]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_24(ctx, os.stream_from_handle(hd)) + } else { + return [24]byte{}, false + } +} + +hash_file_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_28(ctx, os.stream_from_handle(hd)) + } else { + return [28]byte{}, false + } +} + +hash_file_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_32(ctx, os.stream_from_handle(hd)) + } else { + return [32]byte{}, false + } +} + +hash_file_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_48(ctx, os.stream_from_handle(hd)) + } else { + return [48]byte{}, false + } +} + +hash_file_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_64(ctx, os.stream_from_handle(hd)) + } else { + return [64]byte{}, false + } +} + +hash_file_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([128]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_128(ctx, os.stream_from_handle(hd)) + } else { + return [128]byte{}, false + } +} + +hash_file_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + return hash_stream_slice(ctx, os.stream_from_handle(hd), bit_size, allocator) + } else { + return nil, false + } +} + +hash_stream_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._16, 16), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._20, 20), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([24]byte, bool) { + hash: [24]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._24, 24), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._28, 28), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._32, 32), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._48, 48), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._64, 64), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([128]byte, bool) { + hash: [128]byte + c: hash_t + hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._128, 128), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash, true +} + +hash_stream_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + hash := make([]byte, bit_size, allocator) + c: hash_t + hash_init(&c, _check_ctx(ctx, nil, bit_size), 0) + buf := make([]byte, 512) + defer delete(buf) + i := 1 + for i > 0 { + i, _ = s->impl_read(buf) + if i > 0 { + hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) + } + } + hash_final(c, &hash[0]) + hash_destroy(c) + return hash[:], true +} + +init :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + c: hash_t + hash_init(&c, ctx.botan_hash_algo, 0) + ctx.external_ctx = c +} + +update :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.external_ctx.(hash_t); ok { + hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) + } +} + +final :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.external_ctx.(hash_t); ok { + hash_final(c, &hash[0]) + hash_destroy(c) + } +} + +assign_hash_vtable :: proc(ctx: ^_ctx.Hash_Context, hash_algo: cstring) { + ctx.init = init + ctx.update = update + ctx.final = final + ctx.botan_hash_algo = hash_algo + + switch hash_algo { + case HASH_MD4, HASH_MD5: + ctx.hash_bytes_16 = hash_bytes_16 + ctx.hash_file_16 = hash_file_16 + ctx.hash_stream_16 = hash_stream_16 + + case HASH_SHA1, HASH_RIPEMD_160: + ctx.hash_bytes_20 = hash_bytes_20 + ctx.hash_file_20 = hash_file_20 + ctx.hash_stream_20 = hash_stream_20 + + case HASH_SHA2, HASH_SHA3: + ctx.hash_bytes_28 = hash_bytes_28 + ctx.hash_file_28 = hash_file_28 + ctx.hash_stream_28 = hash_stream_28 + ctx.hash_bytes_32 = hash_bytes_32 + ctx.hash_file_32 = hash_file_32 + ctx.hash_stream_32 = hash_stream_32 + ctx.hash_bytes_48 = hash_bytes_48 + ctx.hash_file_48 = hash_file_48 + ctx.hash_stream_48 = hash_stream_48 + ctx.hash_bytes_64 = hash_bytes_64 + ctx.hash_file_64 = hash_file_64 + ctx.hash_stream_64 = hash_stream_64 + + case HASH_GOST, HASH_WHIRLPOOL, HASH_SM3: + ctx.hash_bytes_32 = hash_bytes_32 + ctx.hash_file_32 = hash_file_32 + ctx.hash_stream_32 = hash_stream_32 + + case HASH_STREEBOG: + ctx.hash_bytes_32 = hash_bytes_32 + ctx.hash_file_32 = hash_file_32 + ctx.hash_stream_32 = hash_stream_32 + ctx.hash_bytes_64 = hash_bytes_64 + ctx.hash_file_64 = hash_file_64 + ctx.hash_stream_64 = hash_stream_64 + + case HASH_BLAKE2B: + ctx.hash_bytes_64 = hash_bytes_64 + ctx.hash_file_64 = hash_file_64 + ctx.hash_stream_64 = hash_stream_64 + + case HASH_TIGER: + ctx.hash_bytes_16 = hash_bytes_16 + ctx.hash_file_16 = hash_file_16 + ctx.hash_stream_16 = hash_stream_16 + ctx.hash_bytes_20 = hash_bytes_20 + ctx.hash_file_20 = hash_file_20 + ctx.hash_stream_20 = hash_stream_20 + ctx.hash_bytes_24 = hash_bytes_24 + ctx.hash_file_24 = hash_file_24 + ctx.hash_stream_24 = hash_stream_24 + + case HASH_SKEIN_512: + ctx.hash_bytes_slice = hash_bytes_slice + ctx.hash_file_slice = hash_file_slice + ctx.hash_stream_slice = hash_stream_slice + } +} + +_check_ctx :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash_size: _ctx.Hash_Size, hash_size_val: int) -> cstring { + ctx.hash_size = hash_size + ctx.hash_size_val = hash_size_val + switch ctx.botan_hash_algo { + case HASH_SHA2: + #partial switch hash_size { + case ._28: return HASH_SHA_224 + case ._32: return HASH_SHA_256 + case ._48: return HASH_SHA_384 + case ._64: return HASH_SHA_512 + } + case HASH_SHA3: + #partial switch hash_size { + case ._28: return HASH_SHA3_224 + case ._32: return HASH_SHA3_256 + case ._48: return HASH_SHA3_384 + case ._64: return HASH_SHA3_512 + } + case HASH_KECCAK: + #partial switch hash_size { + case ._28: return HASH_KECCAK_224 + case ._32: return HASH_KECCAK_256 + case ._48: return HASH_KECCAK_384 + case ._64: return HASH_KECCAK_512 + } + case HASH_STREEBOG: + #partial switch hash_size { + case ._32: return HASH_STREEBOG_256 + case ._64: return HASH_STREEBOG_512 + } + case HASH_TIGER: + #partial switch hash_size { + case ._16: return HASH_TIGER_128 + case ._20: return HASH_TIGER_160 + case ._24: return HASH_TIGER_192 + } + case HASH_SKEIN_512: + return strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", hash_size_val * 8)) + case: return ctx.botan_hash_algo + } + return nil +} \ No newline at end of file diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin new file mode 100644 index 000000000..210c7f862 --- /dev/null +++ b/core/crypto/gost/gost.odin @@ -0,0 +1,460 @@ +package gost + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the GOST hashing algorithm, as defined in RFC 5831 +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + _assign_hash_vtable(ctx) + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_32 = hash_bytes_odin + ctx.hash_file_32 = hash_file_odin + ctx.hash_stream_32 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since MD2 is not available in Botan +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_GOST) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [32]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [32]byte { + _create_gost_ctx() + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_gost_ctx() + return _hash_impl->hash_stream_32(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_gost_ctx() + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Gost_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Gost_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +@(private) +_create_gost_ctx :: #force_inline proc() { + ctx: Gost_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._32 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_gost_ctx() + if c, ok := ctx.internal_ctx.(Gost_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Gost_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Gost_Context); ok { + final_odin(&c, hash) + } +} + +/* + GOST implementation +*/ + +Gost_Context :: struct { + sum: [8]u32, + hash: [8]u32, + len: [8]u32, + partial: [32]byte, + partial_bytes: byte, +} + +SBOX_1 : [256]u32 +SBOX_2 : [256]u32 +SBOX_3 : [256]u32 +SBOX_4 : [256]u32 + +GOST_ENCRYPT_ROUND :: #force_inline proc "contextless"(l, r, t, k1, k2: u32) -> (u32, u32, u32) { + l, r, t := l, r, t + t = (k1) + r + l ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24] + t = (k2) + l + r ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24] + return l, r, t +} + +GOST_ENCRYPT :: #force_inline proc "contextless"(a, b, c: u32, key: []u32) -> (l, r, t: u32) { + l, r, t = GOST_ENCRYPT_ROUND(a, b, c, key[0], key[1]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[0], key[1]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[0], key[1]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[7], key[6]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[5], key[4]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[3], key[2]) + l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[1], key[0]) + t = r + r = l + l = t + return +} + +gost_bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) { + a, c: u32 + m: [8]u32 + + for i, j := 0, 0; i < 8; i += 1 { + a = u32(buf[j]) | u32(buf[j + 1]) << 8 | u32(buf[j + 2]) << 16 | u32(buf[j + 3]) << 24 + j += 4 + m[i] = a + c = a + c + ctx.sum[i] + ctx.sum[i] = c + c = c < a ? 1 : 0 + } + + gost_compress(ctx.hash[:], m[:]) + ctx.len[0] += bits + if ctx.len[0] < bits { + ctx.len[1] += 1 + } +} + +gost_compress :: proc(h, m: []u32) { + key, u, v, w, s: [8]u32 + + copy(u[:], h) + copy(v[:], m) + + for i := 0; i < 8; i += 2 { + w[0] = u[0] ~ v[0] + w[1] = u[1] ~ v[1] + w[2] = u[2] ~ v[2] + w[3] = u[3] ~ v[3] + w[4] = u[4] ~ v[4] + w[5] = u[5] ~ v[5] + w[6] = u[6] ~ v[6] + w[7] = u[7] ~ v[7] + + key[0] = (w[0] & 0x000000ff) | (w[2] & 0x000000ff) << 8 | (w[4] & 0x000000ff) << 16 | (w[6] & 0x000000ff) << 24 + key[1] = (w[0] & 0x0000ff00) >> 8 | (w[2] & 0x0000ff00) | (w[4] & 0x0000ff00) << 8 | (w[6] & 0x0000ff00) << 16 + key[2] = (w[0] & 0x00ff0000) >> 16 | (w[2] & 0x00ff0000) >> 8 | (w[4] & 0x00ff0000) | (w[6] & 0x00ff0000) << 8 + key[3] = (w[0] & 0xff000000) >> 24 | (w[2] & 0xff000000) >> 16 | (w[4] & 0xff000000) >> 8 | (w[6] & 0xff000000) + key[4] = (w[1] & 0x000000ff) | (w[3] & 0x000000ff) << 8 | (w[5] & 0x000000ff) << 16 | (w[7] & 0x000000ff) << 24 + key[5] = (w[1] & 0x0000ff00) >> 8 | (w[3] & 0x0000ff00) | (w[5] & 0x0000ff00) << 8 | (w[7] & 0x0000ff00) << 16 + key[6] = (w[1] & 0x00ff0000) >> 16 | (w[3] & 0x00ff0000) >> 8 | (w[5] & 0x00ff0000) | (w[7] & 0x00ff0000) << 8 + key[7] = (w[1] & 0xff000000) >> 24 | (w[3] & 0xff000000) >> 16 | (w[5] & 0xff000000) >> 8 | (w[7] & 0xff000000) + + r := h[i] + l := h[i + 1] + t: u32 + l, r, t = GOST_ENCRYPT(l, r, 0, key[:]) + + s[i] = r + s[i + 1] = l + + if i == 6 { + break + } + + l = u[0] ~ u[2] + r = u[1] ~ u[3] + u[0] = u[2] + u[1] = u[3] + u[2] = u[4] + u[3] = u[5] + u[4] = u[6] + u[5] = u[7] + u[6] = l + u[7] = r + + if i == 2 { + u[0] ~= 0xff00ff00 + u[1] ~= 0xff00ff00 + u[2] ~= 0x00ff00ff + u[3] ~= 0x00ff00ff + u[4] ~= 0x00ffff00 + u[5] ~= 0xff0000ff + u[6] ~= 0x000000ff + u[7] ~= 0xff00ffff + } + + l = v[0] + r = v[2] + v[0] = v[4] + v[2] = v[6] + v[4] = l ~ r + v[6] = v[0] ~ r + l = v[1] + r = v[3] + v[1] = v[5] + v[3] = v[7] + v[5] = l ~ r + v[7] = v[1] ~ r + } + + u[0] = m[0] ~ s[6] + u[1] = m[1] ~ s[7] + u[2] = m[2] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff) ~ + (s[1] & 0xffff) ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[6] ~ (s[6] << 16) ~ + (s[7] & 0xffff0000) ~ (s[7] >> 16) + u[3] = m[3] ~ (s[0] & 0xffff) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~ + (s[1] << 16) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~ + (s[3] << 16) ~ s[6] ~ (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~ + (s[7] << 16) ~ (s[7] >> 16) + u[4] = m[4] ~ + (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[0] >> 16) ~ + (s[1] & 0xffff0000) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~ + (s[3] << 16) ~ (s[3] >> 16) ~ (s[4] << 16) ~ (s[6] << 16) ~ + (s[6] >> 16) ~(s[7] & 0xffff) ~ (s[7] << 16) ~ (s[7] >> 16) + u[5] = m[5] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff0000) ~ + (s[1] & 0xffff) ~ s[2] ~ (s[2] >> 16) ~ (s[3] << 16) ~ (s[3] >> 16) ~ + (s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[6] << 16) ~ + (s[6] >> 16) ~ (s[7] & 0xffff0000) ~ (s[7] << 16) ~ (s[7] >> 16) + u[6] = m[6] ~ s[0] ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[3] ~ (s[3] >> 16) ~ + (s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[5] >> 16) ~ s[6] ~ + (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] << 16) + u[7] = m[7] ~ (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~ + (s[1] << 16) ~ (s[2] >> 16) ~ (s[3] << 16) ~ s[4] ~ (s[4] >> 16) ~ + (s[5] << 16) ~ (s[5] >> 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~ + (s[7] << 16) ~ (s[7] >> 16) + + v[0] = h[0] ~ (u[1] << 16) ~ (u[0] >> 16) + v[1] = h[1] ~ (u[2] << 16) ~ (u[1] >> 16) + v[2] = h[2] ~ (u[3] << 16) ~ (u[2] >> 16) + v[3] = h[3] ~ (u[4] << 16) ~ (u[3] >> 16) + v[4] = h[4] ~ (u[5] << 16) ~ (u[4] >> 16) + v[5] = h[5] ~ (u[6] << 16) ~ (u[5] >> 16) + v[6] = h[6] ~ (u[7] << 16) ~ (u[6] >> 16) + v[7] = h[7] ~ (u[0] & 0xffff0000) ~ (u[0] << 16) ~ (u[7] >> 16) ~ (u[1] & 0xffff0000) ~ (u[1] << 16) ~ (u[6] << 16) ~ (u[7] & 0xffff0000) + + h[0] = (v[0] & 0xffff0000) ~ (v[0] << 16) ~ (v[0] >> 16) ~ (v[1] >> 16) ~ + (v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ (v[4] << 16) ~ + (v[5] >> 16) ~ v[5] ~ (v[6] >> 16) ~ (v[7] << 16) ~ (v[7] >> 16) ~ + (v[7] & 0xffff) + h[1] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ (v[1] & 0xffff) ~ + v[2] ~ (v[2] >> 16) ~ (v[3] << 16) ~ (v[4] >> 16) ~ (v[5] << 16) ~ + (v[6] << 16) ~ v[6] ~ (v[7] & 0xffff0000) ~ (v[7] >> 16) + h[2] = (v[0] & 0xffff) ~ (v[0] << 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ + (v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ + (v[5] >> 16) ~ v[6] ~ (v[6] >> 16) ~ (v[7] & 0xffff) ~ (v[7] << 16) ~ + (v[7] >> 16) + h[3] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ + (v[1] & 0xffff0000) ~ (v[1] >> 16) ~ (v[2] << 16) ~ (v[2] >> 16) ~ v[2] ~ + (v[3] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~ + (v[7] & 0xffff) ~ (v[7] >> 16) + h[4] = (v[0] >> 16) ~ (v[1] << 16) ~ v[1] ~ (v[2] >> 16) ~ v[2] ~ + (v[3] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ (v[5] >> 16) ~ + v[5] ~ (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) + h[5] = (v[0] << 16) ~ (v[0] & 0xffff0000) ~ (v[1] << 16) ~ (v[1] >> 16) ~ + (v[1] & 0xffff0000) ~ (v[2] << 16) ~ v[2] ~ (v[3] >> 16) ~ v[3] ~ + (v[4] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~ + (v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ (v[7] >> 16) ~ (v[7] & 0xffff0000) + h[6] = v[0] ~ v[2] ~ (v[2] >> 16) ~ v[3] ~ (v[3] << 16) ~ v[4] ~ + (v[4] >> 16) ~ (v[5] << 16) ~ (v[5] >> 16) ~ v[5] ~ (v[6] << 16) ~ + (v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ v[7] + h[7] = v[0] ~ (v[0] >> 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ (v[2] << 16) ~ + (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ v[4] ~ (v[5] >> 16) ~ v[5] ~ + (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) ~ v[7] +} + +init_odin :: proc(ctx: ^Gost_Context) { + sbox: [8][16]u32 = { + { 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 }, + { 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 }, + { 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 }, + { 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 }, + { 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 }, + { 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 }, + { 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 }, + { 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 }, + } + + i := 0 + for a := 0; a < 16; a += 1 { + ax := sbox[1][a] << 15 + bx := sbox[3][a] << 23 + cx := sbox[5][a] + cx = (cx >> 1) | (cx << 31) + dx := sbox[7][a] << 7 + for b := 0; b < 16; b, i = b + 1, i + 1 { + SBOX_1[i] = ax | (sbox[0][b] << 11) + SBOX_2[i] = bx | (sbox[2][b] << 19) + SBOX_3[i] = cx | (sbox[4][b] << 27) + SBOX_4[i] = dx | (sbox[6][b] << 3) + } + } +} + +update_odin :: proc(ctx: ^Gost_Context, data: []byte) { + length := byte(len(data)) + j: byte + + i := ctx.partial_bytes + for i < 32 && j < length { + ctx.partial[i] = data[j] + i, j = i + 1, j + 1 + } + + if i < 32 { + ctx.partial_bytes = i + return + } + gost_bytes(ctx, ctx.partial[:], 256) + + for (j + 32) < length { + gost_bytes(ctx, data[j:], 256) + j += 32 + } + + i = 0 + for j < length { + ctx.partial[i] = data[j] + i, j = i + 1, j + 1 + } + ctx.partial_bytes = i +} + +final_odin :: proc(ctx: ^Gost_Context, hash: []byte) { + if ctx.partial_bytes > 0 { + mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes)) + gost_bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3) + } + + gost_compress(ctx.hash[:], ctx.len[:]) + gost_compress(ctx.hash[:], ctx.sum[:]) + + for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 { + hash[j] = byte(ctx.hash[i]) + hash[j + 1] = byte(ctx.hash[i] >> 8) + hash[j + 2] = byte(ctx.hash[i] >> 16) + hash[j + 3] = byte(ctx.hash[i] >> 24) + } +} \ No newline at end of file diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin new file mode 100644 index 000000000..8f9f4547c --- /dev/null +++ b/core/crypto/groestl/groestl.odin @@ -0,0 +1,742 @@ +package groestl + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the GROESTL hashing algorithm, as defined in +*/ + +import "core:os" +import "core:io" + +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since GROESTL is not available in Botan +@(warning="GROESTL is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_groestl_ctx :: #force_inline proc(size: _ctx.Hash_Size) { + ctx: Groestl_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = size + #partial switch size { + case ._28: ctx.hashbitlen = 224 + case ._32: ctx.hashbitlen = 256 + case ._48: ctx.hashbitlen = 384 + case ._64: ctx.hashbitlen = 512 + } +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_groestl_ctx(._28) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_groestl_ctx(._28) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_groestl_ctx(._28) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_groestl_ctx(._32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_groestl_ctx(._32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_groestl_ctx(._32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_groestl_ctx(._48) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_groestl_ctx(._48) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_groestl_ctx(._48) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_groestl_ctx(._64) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_groestl_ctx(._64) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_groestl_ctx(._64) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_groestl_ctx(ctx.hash_size) + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Groestl_Context); ok { + final_odin(&c, hash) + } +} + +/* + GROESTL implementation +*/ + +SBOX := [256]byte { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +} + +SHIFT := [2][2][8]int { + {{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6}}, + {{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}}, +} + +Groestl_Context :: struct { + chaining: [8][16]byte, + block_counter: u64, + hashbitlen: int, + buffer: [128]byte, + buf_ptr: int, + bits_in_last_byte: int, + columns: int, + rounds: int, + statesize: int, +} + +Groestl_Variant :: enum { + P512 = 0, + Q512 = 1, + P1024 = 2, + Q1024 = 3, +} + +MUL2 :: #force_inline proc "contextless"(b: byte) -> byte { + return (b >> 7) != 0 ? (b << 1) ~ 0x1b : (b << 1) +} + +MUL3 :: #force_inline proc "contextless"(b: byte) -> byte { + return MUL2(b) ~ b +} + +MUL4 :: #force_inline proc "contextless"(b: byte) -> byte { + return MUL2(MUL2(b)) +} + +MUL5 :: #force_inline proc "contextless"(b: byte) -> byte { + return MUL4(b) ~ b +} + +MUL6 :: #force_inline proc "contextless"(b: byte) -> byte { + return MUL4(b) ~ MUL2(b) +} + +MUL7 :: #force_inline proc "contextless"(b: byte) -> byte { + return MUL4(b) ~ MUL2(b) ~ b +} + +sub_bytes :: #force_inline proc (x: [][16]byte, columns: int) { + for i := 0; i < 8; i += 1 { + for j := 0; j < columns; j += 1 { + x[i][j] = SBOX[x[i][j]] + } + } +} + +shift_bytes :: #force_inline proc (x: [][16]byte, columns: int, v: Groestl_Variant) { + temp: [16]byte + R := &SHIFT[int(v) / 2][int(v) & 1] + + for i := 0; i < 8; i += 1 { + for j := 0; j < columns; j += 1 { + temp[j] = x[i][(j + R[i]) % columns] + } + for j := 0; j < columns; j += 1 { + x[i][j] = temp[j] + } + } +} + +mix_bytes :: #force_inline proc (x: [][16]byte, columns: int) { + temp: [8]byte + + for i := 0; i < columns; i += 1 { + for j := 0; j < 8; j += 1 { + temp[j] = MUL2(x[(j + 0) % 8][i]) ~ + MUL2(x[(j + 1) % 8][i]) ~ + MUL3(x[(j + 2) % 8][i]) ~ + MUL4(x[(j + 3) % 8][i]) ~ + MUL5(x[(j + 4) % 8][i]) ~ + MUL3(x[(j + 5) % 8][i]) ~ + MUL5(x[(j + 6) % 8][i]) ~ + MUL7(x[(j + 7) % 8][i]) + } + for j := 0; j < 8; j += 1 { + x[j][i] = temp[j] + } + } +} + +p :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) { + v := ctx.columns == 8 ? Groestl_Variant.P512 : Groestl_Variant.P1024 + for i := 0; i < ctx.rounds; i += 1 { + add_roundconstant(x, ctx.columns, byte(i), v) + sub_bytes(x, ctx.columns) + shift_bytes(x, ctx.columns, v) + mix_bytes(x, ctx.columns) + } +} + +q :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) { + v := ctx.columns == 8 ? Groestl_Variant.Q512 : Groestl_Variant.Q1024 + for i := 0; i < ctx.rounds; i += 1 { + add_roundconstant(x, ctx.columns, byte(i), v) + sub_bytes(x, ctx.columns) + shift_bytes(x, ctx.columns, v) + mix_bytes(x, ctx.columns) + } +} + +transform :: proc(ctx: ^Groestl_Context, input: []byte, msglen: u32) { + tmp1, tmp2: [8][16]byte + input, msglen := input, msglen + + for msglen >= u32(ctx.statesize) { + for i := 0; i < 8; i += 1 { + for j := 0; j < ctx.columns; j += 1 { + tmp1[i][j] = ctx.chaining[i][j] ~ input[j * 8 + i] + tmp2[i][j] = input[j * 8 + i] + } + } + + p(ctx, tmp1[:]) + q(ctx, tmp2[:]) + + for i := 0; i < 8; i += 1 { + for j := 0; j < ctx.columns; j += 1 { + ctx.chaining[i][j] ~= tmp1[i][j] ~ tmp2[i][j] + } + } + + ctx.block_counter += 1 + msglen -= u32(ctx.statesize) + input = input[ctx.statesize:] + } +} + +output_transformation :: proc(ctx: ^Groestl_Context) { + temp: [8][16]byte + + for i := 0; i < 8; i += 1 { + for j := 0; j < ctx.columns; j += 1 { + temp[i][j] = ctx.chaining[i][j] + } + } + + p(ctx, temp[:]) + + for i := 0; i < 8; i += 1 { + for j := 0; j < ctx.columns; j += 1 { + ctx.chaining[i][j] ~= temp[i][j] + } + } +} + +add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_Variant) { + switch (i32(v) & 1) { + case 0: + for i := 0; i < columns; i += 1 { + x[0][i] ~= byte(i << 4) ~ round + } + case 1: + for i := 0; i < columns; i += 1 { + for j := 0; j < 7; j += 1 { + x[j][i] ~= 0xff + } + } + for i := 0; i < columns; i += 1 { + x[7][i] ~= byte(i << 4) ~ 0xff ~ round + } + } +} + +init_odin :: proc(ctx: ^Groestl_Context) { + if ctx.hashbitlen <= 256 { + ctx.rounds = 10 + ctx.columns = 8 + ctx.statesize = 64 + } else { + ctx.rounds = 14 + ctx.columns = 16 + ctx.statesize = 128 + } + for i := 8 - size_of(i32); i < 8; i += 1 { + ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i)))) + } +} + +update_odin :: proc(ctx: ^Groestl_Context, data: []byte) { + databitlen := len(data) * 8 + msglen := databitlen / 8 + rem := databitlen % 8 + + i: int + assert(ctx.bits_in_last_byte == 0) + + if ctx.buf_ptr != 0 { + for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 { + ctx.buffer[ctx.buf_ptr] = data[i] + } + + if ctx.buf_ptr < ctx.statesize { + if rem != 0 { + ctx.bits_in_last_byte = rem + ctx.buffer[ctx.buf_ptr] = data[i] + ctx.buf_ptr += 1 + } + return + } + + ctx.buf_ptr = 0 + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + } + + transform(ctx, data[i:], u32(msglen - i)) + i += ((msglen - i) / ctx.statesize) * ctx.statesize + for i < msglen { + ctx.buffer[ctx.buf_ptr] = data[i] + i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 + } + + if rem != 0 { + ctx.bits_in_last_byte = rem + ctx.buffer[ctx.buf_ptr] = data[i] + ctx.buf_ptr += 1 + } +} + +final_odin :: proc(ctx: ^Groestl_Context, hash: []byte) { + hashbytelen := ctx.hashbitlen / 8 + + if ctx.bits_in_last_byte != 0 { + ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte)) + ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte)) + } else { + ctx.buffer[ctx.buf_ptr] = 0x80 + ctx.buf_ptr += 1 + } + + if ctx.buf_ptr > ctx.statesize - 8 { + for ctx.buf_ptr < ctx.statesize { + ctx.buffer[ctx.buf_ptr] = 0 + ctx.buf_ptr += 1 + } + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + ctx.buf_ptr = 0 + } + + for ctx.buf_ptr < ctx.statesize - 8 { + ctx.buffer[ctx.buf_ptr] = 0 + ctx.buf_ptr += 1 + } + + ctx.block_counter += 1 + ctx.buf_ptr = ctx.statesize + + for ctx.buf_ptr > ctx.statesize - 8 { + ctx.buf_ptr -= 1 + ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter) + ctx.block_counter >>= 8 + } + + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + output_transformation(ctx) + + for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 { + hash[j] = ctx.chaining[i % 8][i / 8] + } +} \ No newline at end of file diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin new file mode 100644 index 000000000..943a54a23 --- /dev/null +++ b/core/crypto/haval/haval.odin @@ -0,0 +1,1372 @@ +package haval + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation for the HAVAL hashing algorithm as defined in +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../util" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin_16 + ctx.hash_file_16 = hash_file_odin_16 + ctx.hash_stream_16 = hash_stream_odin_16 + ctx.hash_bytes_20 = hash_bytes_odin_20 + ctx.hash_file_20 = hash_file_odin_20 + ctx.hash_stream_20 = hash_stream_odin_20 + ctx.hash_bytes_24 = hash_bytes_odin_24 + ctx.hash_file_24 = hash_file_odin_24 + ctx.hash_stream_24 = hash_stream_odin_24 + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since HAVAL is not available in Botan +@(warning="HAVAL is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_haval_ctx :: #force_inline proc(size: _ctx.Hash_Size, rounds: u32) { + ctx: Haval_Context + ctx.rounds = rounds + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = size + #partial switch size { + case ._16: ctx.hashbitlen = 128 + case ._20: ctx.hashbitlen = 160 + case ._24: ctx.hashbitlen = 192 + case ._28: ctx.hashbitlen = 224 + case ._32: ctx.hashbitlen = 256 + } +} + +/* + High level API +*/ + +// hash_string_128_3 will hash the given input and return the +// computed hash +hash_string_128_3 :: proc(data: string) -> [16]byte { + return hash_bytes_128_3(transmute([]byte)(data)) +} + +// hash_bytes_128_3 will hash the given input and return the +// computed hash +hash_bytes_128_3 :: proc(data: []byte) -> [16]byte { + _create_haval_ctx(._16, 3) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128_3 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128_3 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_haval_ctx(._16, 3) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128_3 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128_3 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_haval_ctx(._16, 3) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128_3 :: proc { + hash_stream_128_3, + hash_file_128_3, + hash_bytes_128_3, + hash_string_128_3, +} + +// hash_string_128_4 will hash the given input and return the +// computed hash +hash_string_128_4 :: proc(data: string) -> [16]byte { + return hash_bytes_128_4(transmute([]byte)(data)) +} + +// hash_bytes_128_4 will hash the given input and return the +// computed hash +hash_bytes_128_4 :: proc(data: []byte) -> [16]byte { + _create_haval_ctx(._16, 4) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128_4 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128_4 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_haval_ctx(._16, 4) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128_4 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128_4 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_haval_ctx(._16, 4) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128_4 :: proc { + hash_stream_128_4, + hash_file_128_4, + hash_bytes_128_4, + hash_string_128_4, +} + +// hash_string_128_5 will hash the given input and return the +// computed hash +hash_string_128_5 :: proc(data: string) -> [16]byte { + return hash_bytes_128_5(transmute([]byte)(data)) +} + +// hash_bytes_128_5 will hash the given input and return the +// computed hash +hash_bytes_128_5 :: proc(data: []byte) -> [16]byte { + _create_haval_ctx(._16, 5) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128_5 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128_5 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_haval_ctx(._16, 5) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128_5 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128_5 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_haval_ctx(._16, 5) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128_5 :: proc { + hash_stream_128_5, + hash_file_128_5, + hash_bytes_128_5, + hash_string_128_5, +} + +// hash_string_160_3 will hash the given input and return the +// computed hash +hash_string_160_3 :: proc(data: string) -> [20]byte { + return hash_bytes_160_3(transmute([]byte)(data)) +} + +// hash_bytes_160_3 will hash the given input and return the +// computed hash +hash_bytes_160_3 :: proc(data: []byte) -> [20]byte { + _create_haval_ctx(._20, 3) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160_3 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160_3 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_haval_ctx(._20, 3) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160_3 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160_3 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_haval_ctx(._20, 3) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160_3 :: proc { + hash_stream_160_3, + hash_file_160_3, + hash_bytes_160_3, + hash_string_160_3, +} + +// hash_string_160_4 will hash the given input and return the +// computed hash +hash_string_160_4 :: proc(data: string) -> [20]byte { + return hash_bytes_160_4(transmute([]byte)(data)) +} + +// hash_bytes_160_4 will hash the given input and return the +// computed hash +hash_bytes_160_4 :: proc(data: []byte) -> [20]byte { + _create_haval_ctx(._20, 4) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160_4 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160_4 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_haval_ctx(._20, 4) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160_4 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160_4 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_haval_ctx(._20, 4) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160_4 :: proc { + hash_stream_160_4, + hash_file_160_4, + hash_bytes_160_4, + hash_string_160_4, +} + +// hash_string_160_5 will hash the given input and return the +// computed hash +hash_string_160_5 :: proc(data: string) -> [20]byte { + return hash_bytes_160_5(transmute([]byte)(data)) +} + +// hash_bytes_160_5 will hash the given input and return the +// computed hash +hash_bytes_160_5 :: proc(data: []byte) -> [20]byte { + _create_haval_ctx(._20, 5) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160_5 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160_5 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_haval_ctx(._20, 5) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160_5 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160_5 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_haval_ctx(._20, 5) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160_5 :: proc { + hash_stream_160_5, + hash_file_160_5, + hash_bytes_160_5, + hash_string_160_5, +} + +// hash_string_192_3 will hash the given input and return the +// computed hash +hash_string_192_3 :: proc(data: string) -> [24]byte { + return hash_bytes_192_3(transmute([]byte)(data)) +} + +// hash_bytes_192_3 will hash the given input and return the +// computed hash +hash_bytes_192_3 :: proc(data: []byte) -> [24]byte { + _create_haval_ctx(._24, 3) + return _hash_impl->hash_bytes_24(data) +} + +// hash_stream_192_3 will read the stream in chunks and compute a +// hash from its contents +hash_stream_192_3 :: proc(s: io.Stream) -> ([24]byte, bool) { + _create_haval_ctx(._24, 3) + return _hash_impl->hash_stream_24(s) +} + +// hash_file_192_3 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_192_3 :: proc(path: string, load_at_once: bool) -> ([24]byte, bool) { + _create_haval_ctx(._24, 3) + return _hash_impl->hash_file_24(path, load_at_once) +} + +hash_192_3 :: proc { + hash_stream_192_3, + hash_file_192_3, + hash_bytes_192_3, + hash_string_192_3, +} + +// hash_string_192_4 will hash the given input and return the +// computed hash +hash_string_192_4 :: proc(data: string) -> [24]byte { + return hash_bytes_192_4(transmute([]byte)(data)) +} + +// hash_bytes_192_4 will hash the given input and return the +// computed hash +hash_bytes_192_4 :: proc(data: []byte) -> [24]byte { + _create_haval_ctx(._24, 4) + return _hash_impl->hash_bytes_24(data) +} + +// hash_stream_192_4 will read the stream in chunks and compute a +// hash from its contents +hash_stream_192_4 :: proc(s: io.Stream) -> ([24]byte, bool) { + _create_haval_ctx(._24, 4) + return _hash_impl->hash_stream_24(s) +} + +// hash_file_192_4 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_192_4 :: proc(path: string, load_at_once: bool) -> ([24]byte, bool) { + _create_haval_ctx(._24, 4) + return _hash_impl->hash_file_24(path, load_at_once) +} + +hash_192_4 :: proc { + hash_stream_192_4, + hash_file_192_4, + hash_bytes_192_4, + hash_string_192_4, +} + +// hash_string_192_5 will hash the given input and return the +// computed hash +hash_string_192_5 :: proc(data: string) -> [24]byte { + return hash_bytes_192_5(transmute([]byte)(data)) +} + +// hash_bytes_224_5 will hash the given input and return the +// computed hash +hash_bytes_192_5 :: proc(data: []byte) -> [24]byte { + _create_haval_ctx(._24, 5) + return _hash_impl->hash_bytes_24(data) +} + +// hash_stream_192_5 will read the stream in chunks and compute a +// hash from its contents +hash_stream_192_5 :: proc(s: io.Stream) -> ([24]byte, bool) { + _create_haval_ctx(._24, 5) + return _hash_impl->hash_stream_24(s) +} + +// hash_file_192_5 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_192_5 :: proc(path: string, load_at_once: bool) -> ([24]byte, bool) { + _create_haval_ctx(._24, 5) + return _hash_impl->hash_file_24(path, load_at_once) +} + +hash_192_5 :: proc { + hash_stream_192_5, + hash_file_192_5, + hash_bytes_192_5, + hash_string_192_5, +} + +// hash_string_224_3 will hash the given input and return the +// computed hash +hash_string_224_3 :: proc(data: string) -> [28]byte { + return hash_bytes_224_3(transmute([]byte)(data)) +} + +// hash_bytes_224_3 will hash the given input and return the +// computed hash +hash_bytes_224_3 :: proc(data: []byte) -> [28]byte { + _create_haval_ctx(._28, 3) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224_3 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224_3 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_haval_ctx(._28, 3) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224_3 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224_3 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_haval_ctx(._28, 3) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224_3 :: proc { + hash_stream_224_3, + hash_file_224_3, + hash_bytes_224_3, + hash_string_224_3, +} + +// hash_string_224_4 will hash the given input and return the +// computed hash +hash_string_224_4 :: proc(data: string) -> [28]byte { + return hash_bytes_224_4(transmute([]byte)(data)) +} + +// hash_bytes_224_4 will hash the given input and return the +// computed hash +hash_bytes_224_4 :: proc(data: []byte) -> [28]byte { + _create_haval_ctx(._28, 4) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224_4 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224_4 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_haval_ctx(._28, 4) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224_4 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224_4 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_haval_ctx(._28, 4) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224_4 :: proc { + hash_stream_224_4, + hash_file_224_4, + hash_bytes_224_4, + hash_string_224_4, +} + +// hash_string_224_5 will hash the given input and return the +// computed hash +hash_string_224_5 :: proc(data: string) -> [28]byte { + return hash_bytes_224_5(transmute([]byte)(data)) +} + +// hash_bytes_224_5 will hash the given input and return the +// computed hash +hash_bytes_224_5 :: proc(data: []byte) -> [28]byte { + _create_haval_ctx(._28, 5) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224_5 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224_5 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_haval_ctx(._28, 5) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224_5 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224_5 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_haval_ctx(._28, 5) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224_5 :: proc { + hash_stream_224_5, + hash_file_224_5, + hash_bytes_224_5, + hash_string_224_5, +} + +// hash_string_256_3 will hash the given input and return the +// computed hash +hash_string_256_3 :: proc(data: string) -> [32]byte { + return hash_bytes_256_3(transmute([]byte)(data)) +} + +// hash_bytes_256_3 will hash the given input and return the +// computed hash +hash_bytes_256_3 :: proc(data: []byte) -> [32]byte { + _create_haval_ctx(._32, 3) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256_3 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256_3 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_haval_ctx(._32, 3) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256_3 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256_3 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_haval_ctx(._32, 3) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256_3 :: proc { + hash_stream_256_3, + hash_file_256_3, + hash_bytes_256_3, + hash_string_256_3, +} + +// hash_string_256_4 will hash the given input and return the +// computed hash +hash_string_256_4 :: proc(data: string) -> [32]byte { + return hash_bytes_256_4(transmute([]byte)(data)) +} + +// hash_bytes_256_4 will hash the given input and return the +// computed hash +hash_bytes_256_4 :: proc(data: []byte) -> [32]byte { + _create_haval_ctx(._32, 4) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256_4 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256_4 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_haval_ctx(._32, 4) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256_4 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256_4 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_haval_ctx(._32, 4) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256_4 :: proc { + hash_stream_256_4, + hash_file_256_4, + hash_bytes_256_4, + hash_string_256_4, +} + +// hash_string_256_5 will hash the given input and return the +// computed hash +hash_string_256_5 :: proc(data: string) -> [32]byte { + return hash_bytes_256_5(transmute([]byte)(data)) +} + +// hash_bytes_256_5 will hash the given input and return the +// computed hash +hash_bytes_256_5 :: proc(data: []byte) -> [32]byte { + _create_haval_ctx(._32, 5) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256_5 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256_5 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_haval_ctx(._32, 5) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256_5 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256_5 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_haval_ctx(._32, 5) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256_5 :: proc { + hash_stream_256_5, + hash_file_256_5, + hash_bytes_256_5, + hash_string_256_5, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + c.str_len = u32(len(data)) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + c.str_len = u32(len(buf[:read])) + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_16(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + c.str_len = u32(len(data)) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + c.str_len = u32(len(buf[:read])) + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_20(ctx, buf[:]), read_ok + } + } + } + return [20]byte{}, false +} + +hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { + hash: [24]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + c.str_len = u32(len(data)) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { + hash: [24]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + c.str_len = u32(len(buf[:read])) + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([24]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_24(ctx, buf[:]), read_ok + } + } + } + return [24]byte{}, false +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + c.str_len = u32(len(data)) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + c.str_len = u32(len(buf[:read])) + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + c.str_len = u32(len(data)) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + c.str_len = u32(len(buf[:read])) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + c.str_len = u32(len(data)) + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Haval_Context); ok { + final_odin(&c, hash) + } +} + +/* + HAVAL implementation +*/ + +HAVAL_VERSION :: 1 + +Haval_Context :: struct { + count: [2]u32, + fingerprint: [8]u32, + block: [32]u32, + remainder: [128]byte, + rounds: u32, + hashbitlen: u32, + str_len: u32, +} + +PADDING := [128]byte { + 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +} + +F_1 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { + return ((x1) & ((x0) ~ (x4)) ~ (x2) & (x5) ~ (x3) & (x6) ~ (x0)) +} + +F_2 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { + return ((x2) & ((x1) & ~(x3) ~ (x4) & (x5) ~ (x6) ~ (x0)) ~ (x4) & ((x1) ~ (x5)) ~ (x3) & (x5) ~ (x0)) +} + +F_3 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { + return ((x3) & ((x1) & (x2) ~ (x6) ~ (x0)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x0)) +} + +F_4 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { + return ((x4) & ((x5) & ~(x2) ~ (x3) & ~(x6) ~ (x1) ~ (x6) ~ (x0)) ~ (x3) & ((x1) & (x2) ~ (x5) ~ (x6)) ~ (x2) & (x6) ~ (x0)) +} + +F_5 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { + return ((x0) & ((x1) & (x2) & (x3) ~ ~(x5)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x3) & (x6)) +} + +FPHI_1 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { + switch rounds { + case 3: return F_1(x1, x0, x3, x5, x6, x2, x4) + case 4: return F_1(x2, x6, x1, x4, x5, x3, x0) + case 5: return F_1(x3, x4, x1, x0, x5, x2, x6) + case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") + } + return 0 +} + +FPHI_2 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { + switch rounds { + case 3: return F_2(x4, x2, x1, x0, x5, x3, x6) + case 4: return F_2(x3, x5, x2, x0, x1, x6, x4) + case 5: return F_2(x6, x2, x1, x0, x3, x4, x5) + case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") + } + return 0 +} + +FPHI_3 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { + switch rounds { + case 3: return F_3(x6, x1, x2, x3, x4, x5, x0) + case 4: return F_3(x1, x4, x3, x6, x0, x2, x5) + case 5: return F_3(x2, x6, x0, x4, x3, x1, x5) + case: assert(rounds < 3 || rounds > 5, "Rounds count not supported!") + } + return 0 +} + +FPHI_4 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { + switch rounds { + case 4: return F_4(x6, x4, x0, x5, x2, x1, x3) + case 5: return F_4(x1, x5, x3, x2, x0, x4, x6) + case: assert(rounds < 4 || rounds > 5, "Rounds count not supported!") + } + return 0 +} + +FPHI_5 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0, rounds: u32) -> u32 { + switch rounds { + case 5: return F_5(x2, x5, x0, x6, x4, x3, x1) + case: assert(rounds != 5, "Rounds count not supported!") + } + return 0 +} + +FF_1 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, rounds: u32) -> u32 { + tmp := FPHI_1(x6, x5, x4, x3, x2, x1, x0, rounds) + x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + return x8 +} + +FF_2 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { + tmp := FPHI_2(x6, x5, x4, x3, x2, x1, x0, rounds) + x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c + return x8 +} + +FF_3 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { + tmp := FPHI_3(x6, x5, x4, x3, x2, x1, x0, rounds) + x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c + return x8 +} + +FF_4 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { + tmp := FPHI_4(x6, x5, x4, x3, x2, x1, x0, rounds) + x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c + return x8 +} + +FF_5 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> u32 { + tmp := FPHI_5(x6, x5, x4, x3, x2, x1, x0, rounds) + x8 := util.ROTR32(tmp, 7) + util.ROTR32(x7, 11) + w + c + return x8 +} + +HAVAL_CH2UINT :: #force_inline proc (str: []byte, word: []u32) { + for _, i in word[:32] { + word[i] = u32(str[i*4+0]) << 0 | u32(str[i*4+1]) << 8 | u32(str[i*4+2]) << 16 | u32(str[i*4+3]) << 24 + } +} + +HAVAL_UINT2CH :: #force_inline proc(word: []u32, str: []byte, wlen: u32) { + for _, i in word[:wlen] { + str[i*4+0] = byte(word[i] >> 0) & 0xff + str[i*4+1] = byte(word[i] >> 8) & 0xff + str[i*4+2] = byte(word[i] >> 16) & 0xff + str[i*4+3] = byte(word[i] >> 24) & 0xff + } +} + +haval_block :: proc(ctx: ^Haval_Context, rounds: u32) { + t0, t1, t2, t3 := ctx.fingerprint[0], ctx.fingerprint[1], ctx.fingerprint[2], ctx.fingerprint[3] + t4, t5, t6, t7 := ctx.fingerprint[4], ctx.fingerprint[5], ctx.fingerprint[6], ctx.fingerprint[7] + w := ctx.block + + t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[ 0], rounds) + t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[ 1], rounds) + t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[ 2], rounds) + t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[ 3], rounds) + t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[ 4], rounds) + t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[ 5], rounds) + t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[ 6], rounds) + t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[ 7], rounds) + + t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[ 8], rounds) + t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], rounds) + t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[10], rounds) + t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[11], rounds) + t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[12], rounds) + t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[13], rounds) + t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[14], rounds) + t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[15], rounds) + + t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[16], rounds) + t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[17], rounds) + t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[18], rounds) + t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[19], rounds) + t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[20], rounds) + t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[21], rounds) + t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[22], rounds) + t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[23], rounds) + + t7 = FF_1(t7, t6, t5, t4, t3, t2, t1, t0, w[24], rounds) + t6 = FF_1(t6, t5, t4, t3, t2, t1, t0, t7, w[25], rounds) + t5 = FF_1(t5, t4, t3, t2, t1, t0, t7, t6, w[26], rounds) + t4 = FF_1(t4, t3, t2, t1, t0, t7, t6, t5, w[27], rounds) + t3 = FF_1(t3, t2, t1, t0, t7, t6, t5, t4, w[28], rounds) + t2 = FF_1(t2, t1, t0, t7, t6, t5, t4, t3, w[29], rounds) + t1 = FF_1(t1, t0, t7, t6, t5, t4, t3, t2, w[30], rounds) + t0 = FF_1(t0, t7, t6, t5, t4, t3, t2, t1, w[31], rounds) + + t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[ 5], 0x452821e6, rounds) + t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[14], 0x38d01377, rounds) + t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[26], 0xbe5466cf, rounds) + t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[18], 0x34e90c6c, rounds) + t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[11], 0xc0ac29b7, rounds) + t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[28], 0xc97c50dd, rounds) + t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[ 7], 0x3f84d5b5, rounds) + t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[16], 0xb5470917, rounds) + + t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[ 0], 0x9216d5d9, rounds) + t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[23], 0x8979fb1b, rounds) + t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[20], 0xd1310ba6, rounds) + t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[22], 0x98dfb5ac, rounds) + t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[ 1], 0x2ffd72db, rounds) + t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[10], 0xd01adfb7, rounds) + t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[ 4], 0xb8e1afed, rounds) + t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[ 8], 0x6a267e96, rounds) + + t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[30], 0xba7c9045, rounds) + t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[ 3], 0xf12c7f99, rounds) + t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0x24a19947, rounds) + t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[ 9], 0xb3916cf7, rounds) + t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x0801f2e2, rounds) + t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[24], 0x858efc16, rounds) + t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[29], 0x636920d8, rounds) + t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[ 6], 0x71574e69, rounds) + + t7 = FF_2(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0xa458fea3, rounds) + t6 = FF_2(t6, t5, t4, t3, t2, t1, t0, t7, w[12], 0xf4933d7e, rounds) + t5 = FF_2(t5, t4, t3, t2, t1, t0, t7, t6, w[15], 0x0d95748f, rounds) + t4 = FF_2(t4, t3, t2, t1, t0, t7, t6, t5, w[13], 0x728eb658, rounds) + t3 = FF_2(t3, t2, t1, t0, t7, t6, t5, t4, w[ 2], 0x718bcd58, rounds) + t2 = FF_2(t2, t1, t0, t7, t6, t5, t4, t3, w[25], 0x82154aee, rounds) + t1 = FF_2(t1, t0, t7, t6, t5, t4, t3, t2, w[31], 0x7b54a41d, rounds) + t0 = FF_2(t0, t7, t6, t5, t4, t3, t2, t1, w[27], 0xc25a59b5, rounds) + + t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0x9c30d539, rounds) + t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], 0x2af26013, rounds) + t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[ 4], 0xc5d1b023, rounds) + t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[20], 0x286085f0, rounds) + t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[28], 0xca417918, rounds) + t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[17], 0xb8db38ef, rounds) + t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[ 8], 0x8e79dcb0, rounds) + t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[22], 0x603a180e, rounds) + + t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[29], 0x6c9e0e8b, rounds) + t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[14], 0xb01e8a3e, rounds) + t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[25], 0xd71577c1, rounds) + t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[12], 0xbd314b27, rounds) + t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[24], 0x78af2fda, rounds) + t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[30], 0x55605c60, rounds) + t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[16], 0xe65525f3, rounds) + t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[26], 0xaa55ab94, rounds) + + t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[31], 0x57489862, rounds) + t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[15], 0x63e81440, rounds) + t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[ 7], 0x55ca396a, rounds) + t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[ 3], 0x2aab10b6, rounds) + t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[ 1], 0xb4cc5c34, rounds) + t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[ 0], 0x1141e8ce, rounds) + t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[18], 0xa15486af, rounds) + t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[27], 0x7c72e993, rounds) + + t7 = FF_3(t7, t6, t5, t4, t3, t2, t1, t0, w[13], 0xb3ee1411, rounds) + t6 = FF_3(t6, t5, t4, t3, t2, t1, t0, t7, w[ 6], 0x636fbc2a, rounds) + t5 = FF_3(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0x2ba9c55d, rounds) + t4 = FF_3(t4, t3, t2, t1, t0, t7, t6, t5, w[10], 0x741831f6, rounds) + t3 = FF_3(t3, t2, t1, t0, t7, t6, t5, t4, w[23], 0xce5c3e16, rounds) + t2 = FF_3(t2, t1, t0, t7, t6, t5, t4, t3, w[11], 0x9b87931e, rounds) + t1 = FF_3(t1, t0, t7, t6, t5, t4, t3, t2, w[ 5], 0xafd6ba33, rounds) + t0 = FF_3(t0, t7, t6, t5, t4, t3, t2, t1, w[ 2], 0x6c24cf5c, rounds) + + if rounds >= 4 { + t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[24], 0x7a325381, rounds) + t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[ 4], 0x28958677, rounds) + t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[ 0], 0x3b8f4898, rounds) + t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[14], 0x6b4bb9af, rounds) + t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[ 2], 0xc4bfe81b, rounds) + t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[ 7], 0x66282193, rounds) + t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[28], 0x61d809cc, rounds) + t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[23], 0xfb21a991, rounds) + + t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[26], 0x487cac60, rounds) + t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[ 6], 0x5dec8032, rounds) + t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[30], 0xef845d5d, rounds) + t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[20], 0xe98575b1, rounds) + t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[18], 0xdc262302, rounds) + t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[25], 0xeb651b88, rounds) + t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[19], 0x23893e81, rounds) + t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[ 3], 0xd396acc5, rounds) + + t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[22], 0x0f6d6ff3, rounds) + t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[11], 0x83f44239, rounds) + t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[31], 0x2e0b4482, rounds) + t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[21], 0xa4842004, rounds) + t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[ 8], 0x69c8f04a, rounds) + t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[27], 0x9e1f9b5e, rounds) + t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[12], 0x21c66842, rounds) + t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[ 9], 0xf6e96c9a, rounds) + + t7 = FF_4(t7, t6, t5, t4, t3, t2, t1, t0, w[ 1], 0x670c9c61, rounds) + t6 = FF_4(t6, t5, t4, t3, t2, t1, t0, t7, w[29], 0xabd388f0, rounds) + t5 = FF_4(t5, t4, t3, t2, t1, t0, t7, t6, w[ 5], 0x6a51a0d2, rounds) + t4 = FF_4(t4, t3, t2, t1, t0, t7, t6, t5, w[15], 0xd8542f68, rounds) + t3 = FF_4(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x960fa728, rounds) + t2 = FF_4(t2, t1, t0, t7, t6, t5, t4, t3, w[10], 0xab5133a3, rounds) + t1 = FF_4(t1, t0, t7, t6, t5, t4, t3, t2, w[16], 0x6eef0b6c, rounds) + t0 = FF_4(t0, t7, t6, t5, t4, t3, t2, t1, w[13], 0x137a3be4, rounds) + } + + if rounds == 5 { + t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[27], 0xba3bf050, rounds) + t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 3], 0x7efb2a98, rounds) + t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[21], 0xa1f1651d, rounds) + t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[26], 0x39af0176, rounds) + t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[17], 0x66ca593e, rounds) + t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[11], 0x82430e88, rounds) + t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[20], 0x8cee8619, rounds) + t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[29], 0x456f9fb4, rounds) + + t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[19], 0x7d84a5c3, rounds) + t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 0], 0x3b8b5ebe, rounds) + t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[12], 0xe06f75d8, rounds) + t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[ 7], 0x85c12073, rounds) + t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[13], 0x401a449f, rounds) + t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 8], 0x56c16aa6, rounds) + t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[31], 0x4ed3aa62, rounds) + t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[10], 0x363f7706, rounds) + + t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[ 5], 0x1bfedf72, rounds) + t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[ 9], 0x429b023d, rounds) + t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[14], 0x37d0d724, rounds) + t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[30], 0xd00a1248, rounds) + t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[18], 0xdb0fead3, rounds) + t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 6], 0x49f1c09b, rounds) + t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[28], 0x075372c9, rounds) + t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[24], 0x80991b7b, rounds) + + t7 = FF_5(t7, t6, t5, t4, t3, t2, t1, t0, w[ 2], 0x25d479d8, rounds) + t6 = FF_5(t6, t5, t4, t3, t2, t1, t0, t7, w[23], 0xf6e8def7, rounds) + t5 = FF_5(t5, t4, t3, t2, t1, t0, t7, t6, w[16], 0xe3fe501a, rounds) + t4 = FF_5(t4, t3, t2, t1, t0, t7, t6, t5, w[22], 0xb6794c3b, rounds) + t3 = FF_5(t3, t2, t1, t0, t7, t6, t5, t4, w[ 4], 0x976ce0bd, rounds) + t2 = FF_5(t2, t1, t0, t7, t6, t5, t4, t3, w[ 1], 0x04c006ba, rounds) + t1 = FF_5(t1, t0, t7, t6, t5, t4, t3, t2, w[25], 0xc1a94fb6, rounds) + t0 = FF_5(t0, t7, t6, t5, t4, t3, t2, t1, w[15], 0x409f60c4, rounds) + } + + ctx.fingerprint[0] += t0 + ctx.fingerprint[1] += t1 + ctx.fingerprint[2] += t2 + ctx.fingerprint[3] += t3 + ctx.fingerprint[4] += t4 + ctx.fingerprint[5] += t5 + ctx.fingerprint[6] += t6 + ctx.fingerprint[7] += t7 +} + +haval_tailor :: proc(ctx: ^Haval_Context, size: u32) { + temp: u32 + switch size { + case 128: + temp = (ctx.fingerprint[7] & 0x000000ff) | + (ctx.fingerprint[6] & 0xff000000) | + (ctx.fingerprint[5] & 0x00ff0000) | + (ctx.fingerprint[4] & 0x0000ff00) + ctx.fingerprint[0] += util.ROTR32(temp, 8) + + temp = (ctx.fingerprint[7] & 0x0000ff00) | + (ctx.fingerprint[6] & 0x000000ff) | + (ctx.fingerprint[5] & 0xff000000) | + (ctx.fingerprint[4] & 0x00ff0000) + ctx.fingerprint[1] += util.ROTR32(temp, 16) + + temp = (ctx.fingerprint[7] & 0x00ff0000) | + (ctx.fingerprint[6] & 0x0000ff00) | + (ctx.fingerprint[5] & 0x000000ff) | + (ctx.fingerprint[4] & 0xff000000) + ctx.fingerprint[2] += util.ROTR32(temp, 24) + + temp = (ctx.fingerprint[7] & 0xff000000) | + (ctx.fingerprint[6] & 0x00ff0000) | + (ctx.fingerprint[5] & 0x0000ff00) | + (ctx.fingerprint[4] & 0x000000ff) + ctx.fingerprint[3] += temp + case 160: + temp = (ctx.fingerprint[7] & u32(0x3f)) | + (ctx.fingerprint[6] & u32(0x7f << 25)) | + (ctx.fingerprint[5] & u32(0x3f << 19)) + ctx.fingerprint[0] += util.ROTR32(temp, 19) + + temp = (ctx.fingerprint[7] & u32(0x3f << 6)) | + (ctx.fingerprint[6] & u32(0x3f)) | + (ctx.fingerprint[5] & u32(0x7f << 25)) + ctx.fingerprint[1] += util.ROTR32(temp, 25) + + temp = (ctx.fingerprint[7] & u32(0x7f << 12)) | + (ctx.fingerprint[6] & u32(0x3f << 6)) | + (ctx.fingerprint[5] & u32(0x3f)) + ctx.fingerprint[2] += temp + + temp = (ctx.fingerprint[7] & u32(0x3f << 19)) | + (ctx.fingerprint[6] & u32(0x7f << 12)) | + (ctx.fingerprint[5] & u32(0x3f << 6)) + ctx.fingerprint[3] += temp >> 6 + + temp = (ctx.fingerprint[7] & u32(0x7f << 25)) | + (ctx.fingerprint[6] & u32(0x3f << 19)) | + (ctx.fingerprint[5] & u32(0x7f << 12)) + ctx.fingerprint[4] += temp >> 12 + case 192: + temp = (ctx.fingerprint[7] & u32(0x1f)) | + (ctx.fingerprint[6] & u32(0x3f << 26)) + ctx.fingerprint[0] += util.ROTR32(temp, 26) + + temp = (ctx.fingerprint[7] & u32(0x1f << 5)) | + (ctx.fingerprint[6] & u32(0x1f)) + ctx.fingerprint[1] += temp + + temp = (ctx.fingerprint[7] & u32(0x3f << 10)) | + (ctx.fingerprint[6] & u32(0x1f << 5)) + ctx.fingerprint[2] += temp >> 5 + + temp = (ctx.fingerprint[7] & u32(0x1f << 16)) | + (ctx.fingerprint[6] & u32(0x3f << 10)) + ctx.fingerprint[3] += temp >> 10 + + temp = (ctx.fingerprint[7] & u32(0x1f << 21)) | + (ctx.fingerprint[6] & u32(0x1f << 16)) + ctx.fingerprint[4] += temp >> 16 + + temp = (ctx.fingerprint[7] & u32(0x3f << 26)) | + (ctx.fingerprint[6] & u32(0x1f << 21)) + ctx.fingerprint[5] += temp >> 21 + case 224: + ctx.fingerprint[0] += (ctx.fingerprint[7] >> 27) & 0x1f + ctx.fingerprint[1] += (ctx.fingerprint[7] >> 22) & 0x1f + ctx.fingerprint[2] += (ctx.fingerprint[7] >> 18) & 0x0f + ctx.fingerprint[3] += (ctx.fingerprint[7] >> 13) & 0x1f + ctx.fingerprint[4] += (ctx.fingerprint[7] >> 9) & 0x0f + ctx.fingerprint[5] += (ctx.fingerprint[7] >> 4) & 0x1f + ctx.fingerprint[6] += ctx.fingerprint[7] & 0x0f + } +} + +init_odin :: proc(ctx: ^Haval_Context) { + ctx.fingerprint[0] = 0x243f6a88 + ctx.fingerprint[1] = 0x85a308d3 + ctx.fingerprint[2] = 0x13198a2e + ctx.fingerprint[3] = 0x03707344 + ctx.fingerprint[4] = 0xa4093822 + ctx.fingerprint[5] = 0x299f31d0 + ctx.fingerprint[6] = 0x082efa98 + ctx.fingerprint[7] = 0xec4e6c89 +} + +update_odin :: proc(ctx: ^Haval_Context, data: []byte) { + i: u32 + rmd_len := u32((ctx.count[0] >> 3) & 0x7f) + fill_len := 128 - rmd_len + str_len := ctx.str_len + + ctx.count[0] += str_len << 3 + if ctx.count[0] < (str_len << 3) { + ctx.count[1] += 1 + } + ctx.count[1] += str_len >> 29 + + when ODIN_ENDIAN == "little" { + if rmd_len + str_len >= 128 { + copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len]) + haval_block(ctx, ctx.rounds) + for i = fill_len; i + 127 < str_len; i += 128 { + copy(util.slice_to_bytes(ctx.block[:]), data[i:128]) + haval_block(ctx, ctx.rounds) + } + rmd_len = 0 + } else { + i = 0 + } + copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[i:]) + } else { + if rmd_len + str_len >= 128 { + copy(ctx.remainder[rmd_len:], data[:fill_len]) + HAVAL_CH2UINT(ctx.remainder[:], ctx.block[:]) + haval_block(ctx, ctx.rounds) + for i = fill_len; i + 127 < str_len; i += 128 { + copy(ctx.remainder[:], data[i:128]) + HAVAL_CH2UINT(ctx.remainder[:], ctx.block[:]) + haval_block(ctx, ctx.rounds) + } + rmd_len = 0 + } else { + i = 0 + } + copy(ctx.remainder[rmd_len:], data[i:]) + } +} + +final_odin :: proc(ctx: ^Haval_Context, hash: []byte) { + pad_len: u32 + tail: [10]byte + + tail[0] = byte(ctx.hashbitlen & 0x3) << 6 | byte(ctx.rounds & 0x7) << 3 | (HAVAL_VERSION & 0x7) + tail[1] = byte(ctx.hashbitlen >> 2) & 0xff + + HAVAL_UINT2CH(ctx.count[:], util.slice_to_bytes(tail[2:]), 2) + rmd_len := (ctx.count[0] >> 3) & 0x7f + if rmd_len < 118 { + pad_len = 118 - rmd_len + } else { + pad_len = 246 - rmd_len + } + + ctx.str_len = pad_len + update_odin(ctx, PADDING[:]) + ctx.str_len = 10 + update_odin(ctx, tail[:]) + haval_tailor(ctx, ctx.hashbitlen) + HAVAL_UINT2CH(ctx.fingerprint[:], hash, ctx.hashbitlen >> 5) + + mem.set(ctx, 0, size_of(ctx)) +} diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin new file mode 100644 index 000000000..725411d42 --- /dev/null +++ b/core/crypto/jh/jh.odin @@ -0,0 +1,673 @@ +package jh + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the JH hashing algorithm, as defined in +*/ + +import "core:os" +import "core:io" + +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since JH is not available in Botan +@(warning="JH is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_jh_ctx :: #force_inline proc(size: _ctx.Hash_Size) { + ctx: Jh_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = size + #partial switch size { + case ._28: ctx.hashbitlen = 224 + case ._32: ctx.hashbitlen = 256 + case ._48: ctx.hashbitlen = 384 + case ._64: ctx.hashbitlen = 512 + } +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_jh_ctx(._28) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_jh_ctx(._28) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_jh_ctx(._28) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_jh_ctx(._32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_jh_ctx(._32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_jh_ctx(._32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_jh_ctx(._48) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_jh_ctx(._48) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_jh_ctx(._48) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_jh_ctx(._64) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_jh_ctx(._64) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_jh_ctx(._64) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_jh_ctx(ctx.hash_size) + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Jh_Context); ok { + final_odin(&c, hash) + } +} + +/* + JH implementation +*/ + +JH_ROUNDCONSTANT_ZERO := [64]byte { + 0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7, + 0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8, + 0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6, + 0xe, 0xa, 0x9, 0x5, 0x7, 0xd, 0x3, 0xe, + 0x3, 0xa, 0xd, 0xe, 0xc, 0x1, 0x7, 0x5, + 0x1, 0x2, 0x7, 0x7, 0x5, 0x0, 0x9, 0x9, + 0xd, 0xa, 0x2, 0xf, 0x5, 0x9, 0x0, 0xb, + 0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa, +} + +JH_S := [2][16]byte { + {9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14}, + {3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8}, +} + +Jh_Context :: struct { + hashbitlen: int, + databitlen: u64, + buffer_size: u64, + H: [128]byte, + A: [256]byte, + roundconstant: [64]byte, + buffer: [64]byte, +} + +JH_E8_finaldegroup :: proc(ctx: ^Jh_Context) { + t0,t1,t2,t3: byte + tem: [256]byte + for i := 0; i < 128; i += 1 { + tem[i] = ctx.A[i << 1] + tem[i + 128] = ctx.A[(i << 1) + 1] + } + for i := 0; i < 128; i += 1 { + ctx.H[i] = 0 + } + for i := 0; i < 256; i += 1 { + t0 = (tem[i] >> 3) & 1 + t1 = (tem[i] >> 2) & 1 + t2 = (tem[i] >> 1) & 1 + t3 = (tem[i] >> 0) & 1 + + ctx.H[uint(i) >> 3] |= t0 << (7 - (uint(i) & 7)) + ctx.H[(uint(i) + 256) >> 3] |= t1 << (7 - (uint(i) & 7)) + ctx.H[(uint(i) + 512) >> 3] |= t2 << (7 - (uint(i) & 7)) + ctx.H[(uint(i) + 768) >> 3] |= t3 << (7 - (uint(i) & 7)) + } +} + +jh_update_roundconstant :: proc(ctx: ^Jh_Context) { + tem: [64]byte + t: byte + for i := 0; i < 64; i += 1 { + tem[i] = JH_S[0][ctx.roundconstant[i]] + } + for i := 0; i < 64; i += 2 { + tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf + tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf + } + for i := 0; i < 64; i += 4 { + t = tem[i + 2] + tem[i + 2] = tem[i + 3] + tem[i + 3] = t + } + for i := 0; i < 32; i += 1 { + ctx.roundconstant[i] = tem[i << 1] + ctx.roundconstant[i + 32] = tem[(i << 1) + 1] + } + for i := 32; i < 64; i += 2 { + t = ctx.roundconstant[i] + ctx.roundconstant[i] = ctx.roundconstant[i + 1] + ctx.roundconstant[i + 1] = t + } +} + +JH_R8 :: proc(ctx: ^Jh_Context) { + t: byte + tem, roundconstant_expanded: [256]byte + for i := u32(0); i < 256; i += 1 { + roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1 + } + for i := 0; i < 256; i += 1 { + tem[i] = JH_S[roundconstant_expanded[i]][ctx.A[i]] + } + for i := 0; i < 256; i += 2 { + tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf + tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf + } + for i := 0; i < 256; i += 4 { + t = tem[i + 2] + tem[i+2] = tem[i + 3] + tem[i+3] = t + } + for i := 0; i < 128; i += 1 { + ctx.A[i] = tem[i << 1] + ctx.A[i + 128] = tem[(i << 1) + 1] + } + for i := 128; i < 256; i += 2 { + t = ctx.A[i] + ctx.A[i] = ctx.A[i + 1] + ctx.A[i + 1] = t + } +} + +JH_E8_initialgroup :: proc(ctx: ^Jh_Context) { + t0, t1, t2, t3: byte + tem: [256]byte + for i := u32(0); i < 256; i += 1 { + t0 = (ctx.H[i >> 3] >> (7 - (i & 7))) & 1 + t1 = (ctx.H[(i + 256) >> 3] >> (7 - (i & 7))) & 1 + t2 = (ctx.H[(i + 512) >> 3] >> (7 - (i & 7))) & 1 + t3 = (ctx.H[(i + 768) >> 3] >> (7 - (i & 7))) & 1 + tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0) + } + for i := 0; i < 128; i += 1 { + ctx.A[i << 1] = tem[i] + ctx.A[(i << 1) + 1] = tem[i + 128] + } +} + +JH_E8 :: proc(ctx: ^Jh_Context) { + for i := 0; i < 64; i += 1 { + ctx.roundconstant[i] = JH_ROUNDCONSTANT_ZERO[i] + } + JH_E8_initialgroup(ctx) + for i := 0; i < 42; i += 1 { + JH_R8(ctx) + jh_update_roundconstant(ctx) + } + JH_E8_finaldegroup(ctx) +} + +JH_F8 :: proc(ctx: ^Jh_Context) { + for i := 0; i < 64; i += 1 { + ctx.H[i] ~= ctx.buffer[i] + } + JH_E8(ctx) + for i := 0; i < 64; i += 1 { + ctx.H[i + 64] ~= ctx.buffer[i] + } +} + +init_odin :: proc(ctx: ^Jh_Context) { + ctx.H[1] = byte(ctx.hashbitlen) & 0xff + ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff + JH_F8(ctx) +} + +update_odin :: proc(ctx: ^Jh_Context, data: []byte) { + databitlen := u64(len(data)) * 8 + ctx.databitlen += databitlen + i := u64(0) + + if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) { + if (databitlen & 7) == 0 { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) + } else { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1]) + } + ctx.buffer_size += databitlen + databitlen = 0 + } + + if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) + i = 64 - (ctx.buffer_size >> 3) + databitlen = databitlen - (512 - ctx.buffer_size) + JH_F8(ctx) + ctx.buffer_size = 0 + } + + for databitlen >= 512 { + copy(ctx.buffer[:], data[i:i + 64]) + JH_F8(ctx) + i += 64 + databitlen -= 512 + } + + if databitlen > 0 { + if (databitlen & 7) == 0 { + copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)]) + } else { + copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1]) + } + ctx.buffer_size = databitlen + } +} + +final_odin :: proc(ctx: ^Jh_Context, hash: []byte) { + if ctx.databitlen & 0x1ff == 0 { + for i := 0; i < 64; i += 1 { + ctx.buffer[i] = 0 + } + ctx.buffer[0] = 0x80 + ctx.buffer[63] = byte(ctx.databitlen) & 0xff + ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff + ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff + ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff + ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff + ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff + ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff + ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff + JH_F8(ctx) + } else { + if ctx.buffer_size & 7 == 0 { + for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 { + ctx.buffer[i] = 0 + } + } else { + for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 { + ctx.buffer[i] = 0 + } + } + ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7)) + JH_F8(ctx) + for i := 0; i < 64; i += 1 { + ctx.buffer[i] = 0 + } + ctx.buffer[63] = byte(ctx.databitlen) & 0xff + ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff + ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff + ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff + ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff + ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff + ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff + ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff + JH_F8(ctx) + } + switch ctx.hashbitlen { + case 224: copy(hash[:], ctx.H[100:128]) + case 256: copy(hash[:], ctx.H[96:128]) + case 384: copy(hash[:], ctx.H[80:128]) + case 512: copy(hash[:], ctx.H[64:128]) + } +} diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin new file mode 100644 index 000000000..a4e5a227a --- /dev/null +++ b/core/crypto/keccak/keccak.odin @@ -0,0 +1,441 @@ +package keccak + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the Keccak hashing algorithm. + This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output. +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../_sha3" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_KECCAK) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_sha3_ctx(28) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_sha3_ctx(28) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_sha3_ctx(28) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_sha3_ctx(32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_sha3_ctx(48) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_sha3_ctx(48) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_sha3_ctx(48) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_sha3_ctx(64) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_sha3_ctx(64) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_sha3_ctx(64) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_create_sha3_ctx :: #force_inline proc(mdlen: int) { + ctx: _sha3.Sha3_Context + ctx.mdlen = mdlen + ctx.is_keccak = true + _hash_impl.internal_ctx = ctx + switch mdlen { + case 28: _hash_impl.hash_size = ._28 + case 32: _hash_impl.hash_size = ._32 + case 48: _hash_impl.hash_size = ._48 + case 64: _hash_impl.hash_size = ._64 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._28: _create_sha3_ctx(28) + case ._32: _create_sha3_ctx(32) + case ._48: _create_sha3_ctx(48) + case ._64: _create_sha3_ctx(64) + } + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.final_odin(&c, hash) + } +} diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin new file mode 100644 index 000000000..a5ae0251c --- /dev/null +++ b/core/crypto/md2/md2.odin @@ -0,0 +1,265 @@ +package md2 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the MD2 hashing algorithm, as defined in RFC 1319 +*/ + +import "core:os" +import "core:io" + +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin + ctx.hash_file_16 = hash_file_odin + ctx.hash_stream_16 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since MD2 is not available in Botan +@(warning="MD2 is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [16]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [16]byte { + _create_md2_ctx() + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_md2_ctx() + return _hash_impl->hash_stream_16(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_md2_ctx() + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md2_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md2_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +@(private) +_create_md2_ctx :: #force_inline proc() { + ctx: Md2_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._16 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_md2_ctx() + if c, ok := ctx.internal_ctx.(Md2_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Md2_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Md2_Context); ok { + final_odin(&c, hash) + } +} + +/* + MD2 implementation +*/ + +Md2_Context :: struct { + data: [16]byte, + state: [16 * 3]byte, + checksum: [16]byte, + datalen: int, +} + +PI_TABLE := [?]byte { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, + 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, + 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, + 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, + 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, + 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, + 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, + 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, + 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, + 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, + 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, + 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, + 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, + 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, + 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, + 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, + 20, +} + +transform :: proc(ctx: ^Md2_Context, data: []byte) { + j,k,t: byte + for j = 0; j < 16; j += 1 { + ctx.state[j + 16] = data[j] + ctx.state[j + 16 * 2] = (ctx.state[j + 16] ~ ctx.state[j]) + } + t = 0 + for j = 0; j < 16 + 2; j += 1 { + for k = 0; k < 16 * 3; k += 1 { + ctx.state[k] ~= PI_TABLE[t] + t = ctx.state[k] + } + t = (t + j) & 0xff + } + t = ctx.checksum[16 - 1] + for j = 0; j < 16; j += 1 { + ctx.checksum[j] ~= PI_TABLE[data[j] ~ t] + t = ctx.checksum[j] + } +} + +init_odin :: proc(ctx: ^Md2_Context) { + // No action needed here +} + +update_odin :: proc(ctx: ^Md2_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if (ctx.datalen == 16) { + transform(ctx, ctx.data[:]) + ctx.datalen = 0 + } + } +} + +final_odin :: proc(ctx: ^Md2_Context, hash: []byte) { + to_pad := byte(16 - ctx.datalen) + for ctx.datalen < 16 { + ctx.data[ctx.datalen] = to_pad + ctx.datalen += 1 + } + transform(ctx, ctx.data[:]) + transform(ctx, ctx.checksum[:]) + for i := 0; i < 16; i += 1 { + hash[i] = ctx.state[i] + } +} \ No newline at end of file diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin new file mode 100644 index 000000000..b25ad82c7 --- /dev/null +++ b/core/crypto/md4/md4.odin @@ -0,0 +1,345 @@ +package md4 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the MD4 hashing algorithm, as defined in RFC 1320 +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin + ctx.hash_file_16 = hash_file_odin + ctx.hash_stream_16 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_MD4) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [16]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [16]byte { + _create_md4_ctx() + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_md4_ctx() + return _hash_impl->hash_stream_16(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_md4_ctx() + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md4_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md4_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +@(private) +_create_md4_ctx :: #force_inline proc() { + ctx: Md4_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._16 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_md4_ctx() + if c, ok := ctx.internal_ctx.(Md4_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Md4_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Md4_Context); ok { + final_odin(&c, hash) + } +} + +/* + MD4 implementation +*/ + +BLOCK_SIZE :: 64 + +Md4_Context :: struct { + data: [64]byte, + state: [4]u32, + bitlen: u64, + datalen: u32, +} + +/* + @note(zh): F, G and H, as mentioned in the RFC, have been inlined into FF, GG + and HH respectively, instead of declaring them separately. +*/ + +FF :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { + return util.ROTL32(a + ((b & c) | (~b & d)) + x, s) +} + +GG :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { + return util.ROTL32(a + ((b & c) | (b & d) | (c & d)) + x + 0x5a827999, s) +} + +HH :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { + return util.ROTL32(a + (b ~ c ~ d) + x + 0x6ed9eba1, s) +} + +transform :: proc(ctx: ^Md4_Context, data: []byte) { + a, b, c, d, i, j: u32 + m: [16]u32 + + for i, j = 0, 0; i < 16; i += 1 { + m[i] = u32(data[j]) | (u32(data[j + 1]) << 8) | (u32(data[j + 2]) << 16) | (u32(data[j + 3]) << 24) + j += 4 + } + + a = ctx.state[0] + b = ctx.state[1] + c = ctx.state[2] + d = ctx.state[3] + + a = FF(a, b, c, d, m[0], 3) + d = FF(d, a, b, c, m[1], 7) + c = FF(c, d, a, b, m[2], 11) + b = FF(b, c, d, a, m[3], 19) + a = FF(a, b, c, d, m[4], 3) + d = FF(d, a, b, c, m[5], 7) + c = FF(c, d, a, b, m[6], 11) + b = FF(b, c, d, a, m[7], 19) + a = FF(a, b, c, d, m[8], 3) + d = FF(d, a, b, c, m[9], 7) + c = FF(c, d, a, b, m[10], 11) + b = FF(b, c, d, a, m[11], 19) + a = FF(a, b, c, d, m[12], 3) + d = FF(d, a, b, c, m[13], 7) + c = FF(c, d, a, b, m[14], 11) + b = FF(b, c, d, a, m[15], 19) + + a = GG(a, b, c, d, m[0], 3) + d = GG(d, a, b, c, m[4], 5) + c = GG(c, d, a, b, m[8], 9) + b = GG(b, c, d, a, m[12], 13) + a = GG(a, b, c, d, m[1], 3) + d = GG(d, a, b, c, m[5], 5) + c = GG(c, d, a, b, m[9], 9) + b = GG(b, c, d, a, m[13], 13) + a = GG(a, b, c, d, m[2], 3) + d = GG(d, a, b, c, m[6], 5) + c = GG(c, d, a, b, m[10], 9) + b = GG(b, c, d, a, m[14], 13) + a = GG(a, b, c, d, m[3], 3) + d = GG(d, a, b, c, m[7], 5) + c = GG(c, d, a, b, m[11], 9) + b = GG(b, c, d, a, m[15], 13) + + a = HH(a, b, c, d, m[0], 3) + d = HH(d, a, b, c, m[8], 9) + c = HH(c, d, a, b, m[4], 11) + b = HH(b, c, d, a, m[12], 15) + a = HH(a, b, c, d, m[2], 3) + d = HH(d, a, b, c, m[10], 9) + c = HH(c, d, a, b, m[6], 11) + b = HH(b, c, d, a, m[14], 15) + a = HH(a, b, c, d, m[1], 3) + d = HH(d, a, b, c, m[9], 9) + c = HH(c, d, a, b, m[5], 11) + b = HH(b, c, d, a, m[13], 15) + a = HH(a, b, c, d, m[3], 3) + d = HH(d, a, b, c, m[11], 9) + c = HH(c, d, a, b, m[7], 11) + b = HH(b, c, d, a, m[15], 15) + + ctx.state[0] += a + ctx.state[1] += b + ctx.state[2] += c + ctx.state[3] += d +} + +init_odin :: proc(ctx: ^Md4_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 +} + +update_odin :: proc(ctx: ^Md4_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if(ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 + } + } +} + +final_odin :: proc(ctx: ^Md4_Context, hash: []byte) { + i := ctx.datalen + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else if ctx.datalen >= 56 { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) + } + + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[56] = byte(ctx.bitlen) + ctx.data[57] = byte(ctx.bitlen >> 8) + ctx.data[58] = byte(ctx.bitlen >> 16) + ctx.data[59] = byte(ctx.bitlen >> 24) + ctx.data[60] = byte(ctx.bitlen >> 32) + ctx.data[61] = byte(ctx.bitlen >> 40) + ctx.data[62] = byte(ctx.bitlen >> 48) + ctx.data[63] = byte(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) + + for i = 0; i < 4; i += 1 { + hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff + hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff + hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff + hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff + } +} diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin new file mode 100644 index 000000000..037bb17f1 --- /dev/null +++ b/core/crypto/md5/md5.odin @@ -0,0 +1,368 @@ +package md5 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the MD5 hashing algorithm, as defined in RFC 1321 +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin + ctx.hash_file_16 = hash_file_odin + ctx.hash_stream_16 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_MD5) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [16]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [16]byte { + _create_md5_ctx() + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_md5_ctx() + return _hash_impl->hash_stream_16(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_md5_ctx() + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md5_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Md5_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +@(private) +_create_md5_ctx :: #force_inline proc() { + ctx: Md5_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._16 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_md5_ctx() + if c, ok := ctx.internal_ctx.(Md5_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Md5_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Md5_Context); ok { + final_odin(&c, hash) + } +} + +/* + MD4 implementation +*/ + +BLOCK_SIZE :: 64 + +Md5_Context :: struct { + data: [BLOCK_SIZE]byte, + state: [4]u32, + bitlen: u64, + datalen: u32, +} + +/* + @note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH + and II respectively, instead of declaring them separately. +*/ + +FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { + return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s) +} + +GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { + return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s) +} + +HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { + return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s) +} + +II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 { + return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s) +} + +transform :: proc(ctx: ^Md5_Context, data: []byte) { + i, j: u32 + m: [16]u32 + + for i, j = 0, 0; i < 16; i+=1 { + m[i] = u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24 + j += 4 + } + + a := ctx.state[0] + b := ctx.state[1] + c := ctx.state[2] + d := ctx.state[3] + + a = FF(a, b, c, d, m[0], 7, 0xd76aa478) + d = FF(d, a, b, c, m[1], 12, 0xe8c7b756) + c = FF(c, d, a, b, m[2], 17, 0x242070db) + b = FF(b, c, d, a, m[3], 22, 0xc1bdceee) + a = FF(a, b, c, d, m[4], 7, 0xf57c0faf) + d = FF(d, a, b, c, m[5], 12, 0x4787c62a) + c = FF(c, d, a, b, m[6], 17, 0xa8304613) + b = FF(b, c, d, a, m[7], 22, 0xfd469501) + a = FF(a, b, c, d, m[8], 7, 0x698098d8) + d = FF(d, a, b, c, m[9], 12, 0x8b44f7af) + c = FF(c, d, a, b, m[10], 17, 0xffff5bb1) + b = FF(b, c, d, a, m[11], 22, 0x895cd7be) + a = FF(a, b, c, d, m[12], 7, 0x6b901122) + d = FF(d, a, b, c, m[13], 12, 0xfd987193) + c = FF(c, d, a, b, m[14], 17, 0xa679438e) + b = FF(b, c, d, a, m[15], 22, 0x49b40821) + + a = GG(a, b, c, d, m[1], 5, 0xf61e2562) + d = GG(d, a, b, c, m[6], 9, 0xc040b340) + c = GG(c, d, a, b, m[11], 14, 0x265e5a51) + b = GG(b, c, d, a, m[0], 20, 0xe9b6c7aa) + a = GG(a, b, c, d, m[5], 5, 0xd62f105d) + d = GG(d, a, b, c, m[10], 9, 0x02441453) + c = GG(c, d, a, b, m[15], 14, 0xd8a1e681) + b = GG(b, c, d, a, m[4], 20, 0xe7d3fbc8) + a = GG(a, b, c, d, m[9], 5, 0x21e1cde6) + d = GG(d, a, b, c, m[14], 9, 0xc33707d6) + c = GG(c, d, a, b, m[3], 14, 0xf4d50d87) + b = GG(b, c, d, a, m[8], 20, 0x455a14ed) + a = GG(a, b, c, d, m[13], 5, 0xa9e3e905) + d = GG(d, a, b, c, m[2], 9, 0xfcefa3f8) + c = GG(c, d, a, b, m[7], 14, 0x676f02d9) + b = GG(b, c, d, a, m[12], 20, 0x8d2a4c8a) + + a = HH(a, b, c, d, m[5], 4, 0xfffa3942) + d = HH(d, a, b, c, m[8], 11, 0x8771f681) + c = HH(c, d, a, b, m[11], 16, 0x6d9d6122) + b = HH(b, c, d, a, m[14], 23, 0xfde5380c) + a = HH(a, b, c, d, m[1], 4, 0xa4beea44) + d = HH(d, a, b, c, m[4], 11, 0x4bdecfa9) + c = HH(c, d, a, b, m[7], 16, 0xf6bb4b60) + b = HH(b, c, d, a, m[10], 23, 0xbebfbc70) + a = HH(a, b, c, d, m[13], 4, 0x289b7ec6) + d = HH(d, a, b, c, m[0], 11, 0xeaa127fa) + c = HH(c, d, a, b, m[3], 16, 0xd4ef3085) + b = HH(b, c, d, a, m[6], 23, 0x04881d05) + a = HH(a, b, c, d, m[9], 4, 0xd9d4d039) + d = HH(d, a, b, c, m[12], 11, 0xe6db99e5) + c = HH(c, d, a, b, m[15], 16, 0x1fa27cf8) + b = HH(b, c, d, a, m[2], 23, 0xc4ac5665) + + a = II(a, b, c, d, m[0], 6, 0xf4292244) + d = II(d, a, b, c, m[7], 10, 0x432aff97) + c = II(c, d, a, b, m[14], 15, 0xab9423a7) + b = II(b, c, d, a, m[5], 21, 0xfc93a039) + a = II(a, b, c, d, m[12], 6, 0x655b59c3) + d = II(d, a, b, c, m[3], 10, 0x8f0ccc92) + c = II(c, d, a, b, m[10], 15, 0xffeff47d) + b = II(b, c, d, a, m[1], 21, 0x85845dd1) + a = II(a, b, c, d, m[8], 6, 0x6fa87e4f) + d = II(d, a, b, c, m[15], 10, 0xfe2ce6e0) + c = II(c, d, a, b, m[6], 15, 0xa3014314) + b = II(b, c, d, a, m[13], 21, 0x4e0811a1) + a = II(a, b, c, d, m[4], 6, 0xf7537e82) + d = II(d, a, b, c, m[11], 10, 0xbd3af235) + c = II(c, d, a, b, m[2], 15, 0x2ad7d2bb) + b = II(b, c, d, a, m[9], 21, 0xeb86d391) + + ctx.state[0] += a + ctx.state[1] += b + ctx.state[2] += c + ctx.state[3] += d +} + +init_odin :: proc(ctx: ^Md5_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 +} + +update_odin :: proc(ctx: ^Md5_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if(ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 + } + } +} + +final_odin :: proc(ctx: ^Md5_Context, hash: []byte){ + i : u32 + i = ctx.datalen + + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else if ctx.datalen >= 56 { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) + } + + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[56] = byte(ctx.bitlen) + ctx.data[57] = byte(ctx.bitlen >> 8) + ctx.data[58] = byte(ctx.bitlen >> 16) + ctx.data[59] = byte(ctx.bitlen >> 24) + ctx.data[60] = byte(ctx.bitlen >> 32) + ctx.data[61] = byte(ctx.bitlen >> 40) + ctx.data[62] = byte(ctx.bitlen >> 48) + ctx.data[63] = byte(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) + + for i = 0; i < 4; i += 1 { + hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff + hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff + hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff + hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff + } +} \ No newline at end of file diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin new file mode 100644 index 000000000..2ba2f0884 --- /dev/null +++ b/core/crypto/ripemd/ripemd.odin @@ -0,0 +1,1060 @@ +package ripemd + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation for the RIPEMD hashing algorithm as defined in +*/ + +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin_16 + ctx.hash_file_16 = hash_file_odin_16 + ctx.hash_stream_16 = hash_stream_odin_16 + ctx.hash_bytes_20 = hash_bytes_odin_20 + ctx.hash_file_20 = hash_file_odin_20 + ctx.hash_stream_20 = hash_stream_odin_20 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_40 = hash_bytes_odin_40 + ctx.hash_file_40 = hash_file_odin_40 + ctx.hash_stream_40 = hash_stream_odin_40 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_RIPEMD_160) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_128 will hash the given input and return the +// computed hash +hash_string_128 :: proc(data: string) -> [16]byte { + return hash_bytes_128(transmute([]byte)(data)) +} + +// hash_bytes_128 will hash the given input and return the +// computed hash +hash_bytes_128 :: proc(data: []byte) -> [16]byte { + _create_ripemd_ctx(16) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128 :: proc { + hash_stream_128, + hash_file_128, + hash_bytes_128, + hash_string_128, +} + +// hash_string_160 will hash the given input and return the +// computed hash +hash_string_160 :: proc(data: string) -> [20]byte { + return hash_bytes_160(transmute([]byte)(data)) +} + +// hash_bytes_160 will hash the given input and return the +// computed hash +hash_bytes_160 :: proc(data: []byte) -> [20]byte { + _create_ripemd_ctx(20) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160 :: proc { + hash_stream_160, + hash_file_160, + hash_bytes_160, + hash_string_160, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_ripemd_ctx(32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_ripemd_ctx(32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_ripemd_ctx(32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_320 will hash the given input and return the +// computed hash +hash_string_320 :: proc(data: string) -> [40]byte { + return hash_bytes_320(transmute([]byte)(data)) +} + +// hash_bytes_320 will hash the given input and return the +// computed hash +hash_bytes_320 :: proc(data: []byte) -> [40]byte { + _create_ripemd_ctx(40) + return _hash_impl->hash_bytes_40(data) +} + +// hash_stream_320 will read the stream in chunks and compute a +// hash from its contents +hash_stream_320 :: proc(s: io.Stream) -> ([40]byte, bool) { + _create_ripemd_ctx(40) + return _hash_impl->hash_stream_40(s) +} + +// hash_file_320 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_320 :: proc(path: string, load_at_once: bool) -> ([40]byte, bool) { + _create_ripemd_ctx(40) + return _hash_impl->hash_file_40(path, load_at_once) +} + +hash_320 :: proc { + hash_stream_320, + hash_file_320, + hash_bytes_320, + hash_string_320, +} + +hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_16(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_20(ctx, buf[:]), read_ok + } + } + } + return [20]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [40]byte { + hash: [40]byte + if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([40]byte, bool) { + hash: [40]byte + if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([40]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_40(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_40(ctx, buf[:]), read_ok + } + } + } + return [40]byte{}, false +} + +@(private) +_create_ripemd_ctx :: #force_inline proc(hash_size: int) { + switch hash_size { + case 16: + ctx: Ripemd128_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._16 + case 20: + ctx: Ripemd160_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._20 + case 32: + ctx: Ripemd256_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._32 + case 40: + ctx: Ripemd320_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._40 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._16: + _create_ripemd_ctx(16) + if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { + init_odin(&c) + } + case ._20: + _create_ripemd_ctx(20) + if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { + init_odin(&c) + } + case ._32: + _create_ripemd_ctx(32) + if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { + init_odin(&c) + } + case ._40: + _create_ripemd_ctx(40) + if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { + init_odin(&c) + } + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + #partial switch ctx.hash_size { + case ._16: + if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { + update_odin(&c, data) + } + case ._20: + if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { + update_odin(&c, data) + } + case ._32: + if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { + update_odin(&c, data) + } + case ._40: + if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { + update_odin(&c, data) + } + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + #partial switch ctx.hash_size { + case ._16: + if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { + final_odin(&c, hash) + } + case ._20: + if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { + final_odin(&c, hash) + } + case ._32: + if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { + final_odin(&c, hash) + } + case ._40: + if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { + final_odin(&c, hash) + } + } +} + +/* + RIPEMD implementation +*/ + +Ripemd128_Context :: struct { + s: [4]u32, + x: [RIPEMD_128_BLOCK_SIZE]byte, + nx: int, + tc: u64, +} + +Ripemd160_Context :: struct { + s: [5]u32, + x: [RIPEMD_160_BLOCK_SIZE]byte, + nx: int, + tc: u64, +} + +Ripemd256_Context :: struct { + s: [8]u32, + x: [RIPEMD_256_BLOCK_SIZE]byte, + nx: int, + tc: u64, +} + +Ripemd320_Context :: struct { + s: [10]u32, + x: [RIPEMD_320_BLOCK_SIZE]byte, + nx: int, + tc: u64, +} + +RIPEMD_128_SIZE :: 16 +RIPEMD_128_BLOCK_SIZE :: 64 +RIPEMD_160_SIZE :: 20 +RIPEMD_160_BLOCK_SIZE :: 64 +RIPEMD_256_SIZE :: 32 +RIPEMD_256_BLOCK_SIZE :: 64 +RIPEMD_320_SIZE :: 40 +RIPEMD_320_BLOCK_SIZE :: 64 + +S0 :: 0x67452301 +S1 :: 0xefcdab89 +S2 :: 0x98badcfe +S3 :: 0x10325476 +S4 :: 0xc3d2e1f0 +S5 :: 0x76543210 +S6 :: 0xfedcba98 +S7 :: 0x89abcdef +S8 :: 0x01234567 +S9 :: 0x3c2d1e0f + +RIPEMD_128_N0 := [64]uint { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, +} + +RIPEMD_128_R0 := [64]uint { + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, +} + +RIPEMD_128_N1 := [64]uint { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, +} + +RIPEMD_128_R1 := [64]uint { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, +} + +RIPEMD_160_N0 := [80]uint { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13, +} + +RIPEMD_160_R0 := [80]uint { + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6, +} + +RIPEMD_160_N1 := [80]uint { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11, +} + +RIPEMD_160_R1 := [80]uint { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11, +} + +init_odin :: proc(ctx: ^$T) { + when T == Ripemd128_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 + } else when T == Ripemd160_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 + } else when T == Ripemd256_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 + ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] = S5, S6, S7, S8 + } else when T == Ripemd320_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 + ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] = S5, S6, S7, S8, S9 + } +} + +block :: #force_inline proc (ctx: ^$T, p: []byte) -> int { + when T == Ripemd128_Context { + return ripemd_128_block(ctx, p) + } + else when T == Ripemd160_Context { + return ripemd_160_block(ctx, p) + } + else when T == Ripemd256_Context { + return ripemd_256_block(ctx, p) + } + else when T == Ripemd320_Context { + return ripemd_320_block(ctx, p) + } +} + +ripemd_128_block :: proc(ctx: ^$T, p: []byte) -> int { + n := 0 + x: [16]u32 = --- + alpha: u32 = --- + p := p + for len(p) >= RIPEMD_128_BLOCK_SIZE { + a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] + aa, bb, cc, dd := a, b, c, d + for i,j := 0, 0; i < 16; i, j = i+1, j+4 { + x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 + } + i := 0 + for i < 16 { + alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]] + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd= dd, alpha, bb, cc + i += 1 + } + for i < 32 { + alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999 + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + for i < 48 { + alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1 + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + for i < 64 { + alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]] + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + c = ctx.s[1] + c + dd + ctx.s[1] = ctx.s[2] + d + aa + ctx.s[2] = ctx.s[3] + a + bb + ctx.s[3] = ctx.s[0] + b + cc + ctx.s[0] = c + p = p[RIPEMD_128_BLOCK_SIZE:] + n += RIPEMD_128_BLOCK_SIZE + } + return n +} + +ripemd_160_block :: proc(ctx: ^$T, p: []byte) -> int { + n := 0 + x: [16]u32 = --- + alpha, beta: u32 = ---, --- + p := p + for len(p) >= RIPEMD_160_BLOCK_SIZE { + a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] + aa, bb, cc, dd, ee := a, b, c, d, e + for i,j := 0, 0; i < 16; i, j = i+1, j+4 { + x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 + } + i := 0 + for i < 16 { + alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]] + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + for i < 32 { + alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999 + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + for i < 48 { + alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1 + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + for i < 64 { + alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + for i < 80 { + alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]] + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + dd += c + ctx.s[1] + ctx.s[1] = ctx.s[2] + d + ee + ctx.s[2] = ctx.s[3] + e + aa + ctx.s[3] = ctx.s[4] + a + bb + ctx.s[4] = ctx.s[0] + b + cc + ctx.s[0] = dd + p = p[RIPEMD_160_BLOCK_SIZE:] + n += RIPEMD_160_BLOCK_SIZE + } + return n +} + +ripemd_256_block :: proc(ctx: ^$T, p: []byte) -> int { + n := 0 + x: [16]u32 = --- + alpha: u32 = --- + p := p + for len(p) >= RIPEMD_256_BLOCK_SIZE { + a, b, c, d := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] + aa, bb, cc, dd := ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] + for i,j := 0, 0; i < 16; i, j = i+1, j+4 { + x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 + } + i := 0 + for i < 16 { + alpha = a + (b ~ c ~ d) + x[RIPEMD_128_N0[i]] + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (bb & dd | cc &~ dd) + x[RIPEMD_128_N1[i]] + 0x50a28be6 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd= dd, alpha, bb, cc + i += 1 + } + t := a + a = aa + aa = t + for i < 32 { + alpha = a + (d ~ (b & (c~d))) + x[RIPEMD_128_N0[i]] + 0x5a827999 + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (dd ~ (bb | ~cc)) + x[RIPEMD_128_N1[i]] + 0x5c4dd124 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + t = b + b = bb + bb = t + for i < 48 { + alpha = a + (d ~ (b | ~c)) + x[RIPEMD_128_N0[i]] + 0x6ed9eba1 + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (dd ~ (bb & (cc~dd))) + x[RIPEMD_128_N1[i]] + 0x6d703ef3 + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + t = c + c = cc + cc = t + for i < 64 { + alpha = a + (c ~ (d & (b~c))) + x[RIPEMD_128_N0[i]] + 0x8f1bbcdc + s := int(RIPEMD_128_R0[i]) + alpha = util.ROTL32(alpha, s) + a, b, c, d = d, alpha, b, c + alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_128_N1[i]] + s = int(RIPEMD_128_R1[i]) + alpha = util.ROTL32(alpha, s) + aa, bb, cc, dd = dd, alpha, bb, cc + i += 1 + } + t = d + d = dd + dd = t + ctx.s[0] += a + ctx.s[1] += b + ctx.s[2] += c + ctx.s[3] += d + ctx.s[4] += aa + ctx.s[5] += bb + ctx.s[6] += cc + ctx.s[7] += dd + p = p[RIPEMD_256_BLOCK_SIZE:] + n += RIPEMD_256_BLOCK_SIZE + } + return n +} + +ripemd_320_block :: proc(ctx: ^$T, p: []byte) -> int { + n := 0 + x: [16]u32 = --- + alpha, beta: u32 = ---, --- + p := p + for len(p) >= RIPEMD_320_BLOCK_SIZE { + a, b, c, d, e := ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] + aa, bb, cc, dd, ee := ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] + for i,j := 0, 0; i < 16; i, j = i+1, j+4 { + x[i] = u32(p[j]) | u32(p[j+1])<<8 | u32(p[j+2])<<16 | u32(p[j+3])<<24 + } + i := 0 + for i < 16 { + alpha = a + (b ~ c ~ d) + x[RIPEMD_160_N0[i]] + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb ~ (cc | ~dd)) + x[RIPEMD_160_N1[i]] + 0x50a28be6 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + t := b + b = bb + bb = t + for i < 32 { + alpha = a + (b&c | ~b&d) + x[RIPEMD_160_N0[i]] + 0x5a827999 + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb&dd | cc&~dd) + x[RIPEMD_160_N1[i]] + 0x5c4dd124 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + t = d + d = dd + dd = t + for i < 48 { + alpha = a + (b | ~c ~ d) + x[RIPEMD_160_N0[i]] + 0x6ed9eba1 + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb | ~cc ~ dd) + x[RIPEMD_160_N1[i]] + 0x6d703ef3 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + t = a + a = aa + aa = t + for i < 64 { + alpha = a + (b&d | c&~d) + x[RIPEMD_160_N0[i]] + 0x8f1bbcdc + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb&cc | ~bb&dd) + x[RIPEMD_160_N1[i]] + 0x7a6d76e9 + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + t = c + c = cc + cc = t + for i < 80 { + alpha = a + (b ~ (c | ~d)) + x[RIPEMD_160_N0[i]] + 0xa953fd4e + s := int(RIPEMD_160_R0[i]) + alpha = util.ROTL32(alpha, s) + e + beta = util.ROTL32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + alpha = aa + (bb ~ cc ~ dd) + x[RIPEMD_160_N1[i]] + s = int(RIPEMD_160_R1[i]) + alpha = util.ROTL32(alpha, s) + ee + beta = util.ROTL32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + i += 1 + } + t = e + e = ee + ee = t + ctx.s[0] += a + ctx.s[1] += b + ctx.s[2] += c + ctx.s[3] += d + ctx.s[4] += e + ctx.s[5] += aa + ctx.s[6] += bb + ctx.s[7] += cc + ctx.s[8] += dd + ctx.s[9] += ee + p = p[RIPEMD_320_BLOCK_SIZE:] + n += RIPEMD_320_BLOCK_SIZE + } + return n +} + +update_odin :: proc(ctx: ^$T, p: []byte) { + ctx.tc += u64(len(p)) + p := p + if ctx.nx > 0 { + n := len(p) + + when T == Ripemd128_Context { + if n > RIPEMD_128_BLOCK_SIZE - ctx.nx { + n = RIPEMD_128_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd160_Context { + if n > RIPEMD_160_BLOCK_SIZE - ctx.nx { + n = RIPEMD_160_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd256_Context{ + if n > RIPEMD_256_BLOCK_SIZE - ctx.nx { + n = RIPEMD_256_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd320_Context{ + if n > RIPEMD_320_BLOCK_SIZE - ctx.nx { + n = RIPEMD_320_BLOCK_SIZE - ctx.nx + } + } + + for i := 0; i < n; i += 1 { + ctx.x[ctx.nx + i] = p[i] + } + + ctx.nx += n + when T == Ripemd128_Context { + if ctx.nx == RIPEMD_128_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd160_Context { + if ctx.nx == RIPEMD_160_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd256_Context{ + if ctx.nx == RIPEMD_256_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd320_Context{ + if ctx.nx == RIPEMD_320_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } + p = p[n:] + } + n := block(ctx, p) + p = p[n:] + if len(p) > 0 { + ctx.nx = copy(ctx.x[:], p) + } +} + +final_odin :: proc(ctx: ^$T, hash: []byte) { + d := ctx + tc := d.tc + tmp: [64]byte + tmp[0] = 0x80 + + if tc % 64 < 56 { + update_odin(d, tmp[0:56 - tc % 64]) + } else { + update_odin(d, tmp[0:64 + 56 - tc % 64]) + } + + tc <<= 3 + for i : u32 = 0; i < 8; i += 1 { + tmp[i] = byte(tc >> (8 * i)) + } + + update_odin(d, tmp[0:8]) + + when T == Ripemd128_Context { + size :: RIPEMD_128_SIZE + } else when T == Ripemd160_Context { + size :: RIPEMD_160_SIZE + } else when T == Ripemd256_Context{ + size :: RIPEMD_256_SIZE + } else when T == Ripemd320_Context{ + size :: RIPEMD_320_SIZE + } + + digest: [size]byte + for s, i in d.s { + digest[i * 4] = byte(s) + digest[i * 4 + 1] = byte(s >> 8) + digest[i * 4 + 2] = byte(s >> 16) + digest[i * 4 + 3] = byte(s >> 24) + } + copy(hash[:], digest[:]) +} diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin new file mode 100644 index 000000000..fe2d732da --- /dev/null +++ b/core/crypto/sha1/sha1.odin @@ -0,0 +1,329 @@ +package sha1 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_20 = hash_bytes_odin + ctx.hash_file_20 = hash_file_odin + ctx.hash_stream_20 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA1) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [20]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [20]byte { + _create_sha1_ctx() + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_sha1_ctx() + return _hash_impl->hash_stream_20(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_sha1_ctx() + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Sha1_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + if c, ok := ctx.internal_ctx.(Sha1_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [20]byte{}, false +} + +@(private) +_create_sha1_ctx :: #force_inline proc() { + ctx: Sha1_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._20 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_sha1_ctx() + if c, ok := ctx.internal_ctx.(Sha1_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Sha1_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Sha1_Context); ok { + final_odin(&c, hash) + } +} + +/* + SHA1 implementation +*/ + +BLOCK_SIZE :: 64 + +Sha1_Context :: struct { + data: [BLOCK_SIZE]byte, + datalen: u32, + bitlen: u64, + state: [5]u32, + k: [4]u32, +} + +transform :: proc(ctx: ^Sha1_Context, data: []byte) { + a, b, c, d, e, i, j, t: u32 + m: [80]u32 + + for i, j = 0, 0; i < 16; i += 1 { + m[i] = u32(data[j]) << 24 + u32(data[j + 1]) << 16 + u32(data[j + 2]) << 8 + u32(data[j + 3]) + j += 4 + } + for i < 80 { + m[i] = (m[i - 3] ~ m[i - 8] ~ m[i - 14] ~ m[i - 16]) + m[i] = (m[i] << 1) | (m[i] >> 31) + i += 1 + } + + a = ctx.state[0] + b = ctx.state[1] + c = ctx.state[2] + d = ctx.state[3] + e = ctx.state[4] + + for i = 0; i < 20; i += 1 { + t = util.ROTL32(a, 5) + ((b & c) ~ (~b & d)) + e + ctx.k[0] + m[i] + e = d + d = c + c = util.ROTL32(b, 30) + b = a + a = t + } + for i < 40 { + t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[1] + m[i] + e = d + d = c + c = util.ROTL32(b, 30) + b = a + a = t + i += 1 + } + for i < 60 { + t = util.ROTL32(a, 5) + ((b & c) ~ (b & d) ~ (c & d)) + e + ctx.k[2] + m[i] + e = d + d = c + c = util.ROTL32(b, 30) + b = a + a = t + i += 1 + } + for i < 80 { + t = util.ROTL32(a, 5) + (b ~ c ~ d) + e + ctx.k[3] + m[i] + e = d + d = c + c = util.ROTL32(b, 30) + b = a + a = t + i += 1 + } + + ctx.state[0] += a + ctx.state[1] += b + ctx.state[2] += c + ctx.state[3] += d + ctx.state[4] += e +} + +init_odin :: proc(ctx: ^Sha1_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 + ctx.state[4] = 0xc3d2e1f0 + ctx.k[0] = 0x5a827999 + ctx.k[1] = 0x6ed9eba1 + ctx.k[2] = 0x8f1bbcdc + ctx.k[3] = 0xca62c1d6 +} + +update_odin :: proc(ctx: ^Sha1_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if (ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 + } + } +} + +final_odin :: proc(ctx: ^Sha1_Context, hash: []byte) { + i := ctx.datalen + + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } + else { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) + } + + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[63] = u8(ctx.bitlen) + ctx.data[62] = u8(ctx.bitlen >> 8) + ctx.data[61] = u8(ctx.bitlen >> 16) + ctx.data[60] = u8(ctx.bitlen >> 24) + ctx.data[59] = u8(ctx.bitlen >> 32) + ctx.data[58] = u8(ctx.bitlen >> 40) + ctx.data[57] = u8(ctx.bitlen >> 48) + ctx.data[56] = u8(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) + + for j: u32 = 0; j < 4; j += 1 { + hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff + hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff + hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff + hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff + hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff + } +} \ No newline at end of file diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin new file mode 100644 index 000000000..ad23b473c --- /dev/null +++ b/core/crypto/sha2/sha2.odin @@ -0,0 +1,797 @@ +package sha2 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the SHA2 hashing algorithm, as defined in + and in RFC 3874 +*/ + +import "core:mem" +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA2) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_sha256_ctx :: #force_inline proc(is224: bool) { + ctx: Sha256_Context + ctx.is224 = is224 + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = is224 ? ._28 : ._32 +} + +@(private) +_create_sha512_ctx :: #force_inline proc(is384: bool) { + ctx: Sha512_Context + ctx.is384 = is384 + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = is384 ? ._48 : ._64 +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_sha256_ctx(true) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_sha256_ctx(true) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_sha256_ctx(true) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_sha256_ctx(false) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_sha256_ctx(false) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_sha256_ctx(false) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_sha512_ctx(true) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_sha512_ctx(true) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_sha512_ctx(true) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_sha512_ctx(false) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_sha512_ctx(false) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_sha512_ctx(false) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + if ctx.hash_size == ._28 || ctx.hash_size == ._32 { + _create_sha256_ctx(ctx.hash_size == ._28) + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + init_odin(&c) + } + return + } + if ctx.hash_size == ._48 || ctx.hash_size == ._64 { + _create_sha512_ctx(ctx.hash_size == ._48) + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + init_odin(&c) + } + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + #partial switch ctx.hash_size { + case ._28, ._32: + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + update_odin(&c, data) + } + case ._48, ._64: + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + update_odin(&c, data) + } + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + #partial switch ctx.hash_size { + case ._28, ._32: + if c, ok := ctx.internal_ctx.(Sha256_Context); ok { + final_odin(&c, hash) + } + case ._48, ._64: + if c, ok := ctx.internal_ctx.(Sha512_Context); ok { + final_odin(&c, hash) + } + } +} + +/* + SHA2 implementation +*/ + +SHA256_BLOCK_SIZE :: 64 +SHA512_BLOCK_SIZE :: 128 + +Sha256_Context :: struct { + tot_len: uint, + length: uint, + block: [128]byte, + h: [8]u32, + is224: bool, +} + +Sha512_Context :: struct { + tot_len: uint, + length: uint, + block: [256]byte, + h: [8]u64, + is384: bool, +} + +sha256_k := [64]u32 { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +} + +sha512_k := [80]u64 { + 0x428a2f98d728ae22, 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, + 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, + 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, + 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +} + +SHA256_CH :: #force_inline proc "contextless"(x, y, z: u32) -> u32 { + return (x & y) ~ (~x & z) +} + +SHA256_MAJ :: #force_inline proc "contextless"(x, y, z: u32) -> u32 { + return (x & y) ~ (x & z) ~ (y & z) +} + +SHA512_CH :: #force_inline proc "contextless"(x, y, z: u64) -> u64 { + return (x & y) ~ (~x & z) +} + +SHA512_MAJ :: #force_inline proc "contextless"(x, y, z: u64) -> u64 { + return (x & y) ~ (x & z) ~ (y & z) +} + +SHA256_F1 :: #force_inline proc "contextless"(x: u32) -> u32 { + return util.ROTR32(x, 2) ~ util.ROTR32(x, 13) ~ util.ROTR32(x, 22) +} + +SHA256_F2 :: #force_inline proc "contextless"(x: u32) -> u32 { + return util.ROTR32(x, 6) ~ util.ROTR32(x, 11) ~ util.ROTR32(x, 25) +} + +SHA256_F3 :: #force_inline proc "contextless"(x: u32) -> u32 { + return util.ROTR32(x, 7) ~ util.ROTR32(x, 18) ~ (x >> 3) +} + +SHA256_F4 :: #force_inline proc "contextless"(x: u32) -> u32 { + return util.ROTR32(x, 17) ~ util.ROTR32(x, 19) ~ (x >> 10) +} + +SHA512_F1 :: #force_inline proc "contextless"(x: u64) -> u64 { + return util.ROTR64(x, 28) ~ util.ROTR64(x, 34) ~ util.ROTR64(x, 39) +} + +SHA512_F2 :: #force_inline proc "contextless"(x: u64) -> u64 { + return util.ROTR64(x, 14) ~ util.ROTR64(x, 18) ~ util.ROTR64(x, 41) +} + +SHA512_F3 :: #force_inline proc "contextless"(x: u64) -> u64 { + return util.ROTR64(x, 1) ~ util.ROTR64(x, 8) ~ (x >> 7) +} + +SHA512_F4 :: #force_inline proc "contextless"(x: u64) -> u64 { + return util.ROTR64(x, 19) ~ util.ROTR64(x, 61) ~ (x >> 6) +} + +PACK32 :: #force_inline proc "contextless"(b: []byte, x: ^u32) { + x^ = u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24 +} + +PACK64 :: #force_inline proc "contextless"(b: []byte, x: ^u64) { + x^ = u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 +} + +init_odin :: proc(ctx: ^$T) { + when T == Sha256_Context { + if ctx.is224 { + ctx.h[0] = 0xc1059ed8 + ctx.h[1] = 0x367cd507 + ctx.h[2] = 0x3070dd17 + ctx.h[3] = 0xf70e5939 + ctx.h[4] = 0xffc00b31 + ctx.h[5] = 0x68581511 + ctx.h[6] = 0x64f98fa7 + ctx.h[7] = 0xbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667 + ctx.h[1] = 0xbb67ae85 + ctx.h[2] = 0x3c6ef372 + ctx.h[3] = 0xa54ff53a + ctx.h[4] = 0x510e527f + ctx.h[5] = 0x9b05688c + ctx.h[6] = 0x1f83d9ab + ctx.h[7] = 0x5be0cd19 + } + } else when T == Sha512_Context { + if ctx.is384 { + ctx.h[0] = 0xcbbb9d5dc1059ed8 + ctx.h[1] = 0x629a292a367cd507 + ctx.h[2] = 0x9159015a3070dd17 + ctx.h[3] = 0x152fecd8f70e5939 + ctx.h[4] = 0x67332667ffc00b31 + ctx.h[5] = 0x8eb44a8768581511 + ctx.h[6] = 0xdb0c2e0d64f98fa7 + ctx.h[7] = 0x47b5481dbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667f3bcc908 + ctx.h[1] = 0xbb67ae8584caa73b + ctx.h[2] = 0x3c6ef372fe94f82b + ctx.h[3] = 0xa54ff53a5f1d36f1 + ctx.h[4] = 0x510e527fade682d1 + ctx.h[5] = 0x9b05688c2b3e6c1f + ctx.h[6] = 0x1f83d9abfb41bd6b + ctx.h[7] = 0x5be0cd19137e2179 + } + } +} + +sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { + when T == Sha256_Context { + w: [64]u32 + wv: [8]u32 + t1, t2: u32 + } else when T == Sha512_Context { + w: [80]u64 + wv: [8]u64 + t1, t2: u64 + } + + sub_block := make([]byte, len(data)) + i, j: i32 + + for i = 0; i < i32(block_nb); i += 1 { + when T == Sha256_Context { + sub_block = data[i << 6:] + } else when T == Sha512_Context { + sub_block = data[i << 7:] + } + + for j = 0; j < 16; j += 1 { + when T == Sha256_Context { + PACK32(sub_block[j << 2:], &w[j]) + } else when T == Sha512_Context { + PACK64(sub_block[j << 3:], &w[j]) + } + } + + when T == Sha256_Context { + for j = 16; j < 64; j += 1 { + w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16] + } + } else when T == Sha512_Context { + for j = 16; j < 80; j += 1 { + w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16] + } + } + + for j = 0; j < 8; j += 1 { + wv[j] = ctx.h[j] + } + + when T == Sha256_Context { + for j = 0; j < 64; j += 1 { + t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j] + t2 = SHA256_F1(wv[0]) + SHA256_MAJ(wv[0], wv[1], wv[2]) + wv[7] = wv[6] + wv[6] = wv[5] + wv[5] = wv[4] + wv[4] = wv[3] + t1 + wv[3] = wv[2] + wv[2] = wv[1] + wv[1] = wv[0] + wv[0] = t1 + t2 + } + } else when T == Sha512_Context { + for j = 0; j < 80; j += 1 { + t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j] + t2 = SHA512_F1(wv[0]) + SHA512_MAJ(wv[0], wv[1], wv[2]) + wv[7] = wv[6] + wv[6] = wv[5] + wv[5] = wv[4] + wv[4] = wv[3] + t1 + wv[3] = wv[2] + wv[2] = wv[1] + wv[1] = wv[0] + wv[0] = t1 + t2 + } + } + + for j = 0; j < 8; j += 1 { + ctx.h[j] += wv[j] + } + } +} + +update_odin :: proc(ctx: ^$T, data: []byte) { + length := uint(len(data)) + block_nb: uint + new_len, rem_len, tmp_len: uint + shifted_message := make([]byte, length) + + when T == Sha256_Context { + CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE + } else when T == Sha512_Context { + CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE + } + + tmp_len = CURR_BLOCK_SIZE - ctx.length + rem_len = length < tmp_len ? length : tmp_len + copy(ctx.block[ctx.length:], data[:rem_len]) + + if ctx.length + length < CURR_BLOCK_SIZE { + ctx.length += length + return + } + + new_len = length - rem_len + block_nb = new_len / CURR_BLOCK_SIZE + shifted_message = data[rem_len:] + + sha2_transf(ctx, ctx.block[:], 1) + sha2_transf(ctx, shifted_message, block_nb) + + rem_len = new_len % CURR_BLOCK_SIZE + when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} + else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} + + ctx.length = rem_len + when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} + else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} +} + +final_odin :: proc(ctx: ^$T, hash: []byte) { + block_nb, pm_len, len_b: u32 + i: i32 + + when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} + else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} + + when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + + len_b = u32(ctx.tot_len + ctx.length) << 3 + when T == Sha256_Context {pm_len = block_nb << 6} + else when T == Sha512_Context {pm_len = block_nb << 7} + + mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) + ctx.block[ctx.length] = 0x80 + + util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) + + sha2_transf(ctx, ctx.block[:], uint(block_nb)) + + when T == Sha256_Context { + if ctx.is224 { + for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } + } else when T == Sha512_Context { + if ctx.is384 { + for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } + } +} \ No newline at end of file diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin new file mode 100644 index 000000000..184bd5358 --- /dev/null +++ b/core/crypto/sha3/sha3.odin @@ -0,0 +1,440 @@ +package sha3 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the SHA3 hashing algorithm. The SHAKE functionality can be found in package shake. + If you wish to compute a Keccak hash, you can use the keccak package, it will use the original padding. +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../_sha3" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_28 = hash_bytes_odin_28 + ctx.hash_file_28 = hash_file_odin_28 + ctx.hash_stream_28 = hash_stream_odin_28 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_48 = hash_bytes_odin_48 + ctx.hash_file_48 = hash_file_odin_48 + ctx.hash_stream_48 = hash_stream_odin_48 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA3) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_224 will hash the given input and return the +// computed hash +hash_string_224 :: proc(data: string) -> [28]byte { + return hash_bytes_224(transmute([]byte)(data)) +} + +// hash_bytes_224 will hash the given input and return the +// computed hash +hash_bytes_224 :: proc(data: []byte) -> [28]byte { + _create_sha3_ctx(28) + return _hash_impl->hash_bytes_28(data) +} + +// hash_stream_224 will read the stream in chunks and compute a +// hash from its contents +hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { + _create_sha3_ctx(28) + return _hash_impl->hash_stream_28(s) +} + +// hash_file_224 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_224 :: proc(path: string, load_at_once: bool) -> ([28]byte, bool) { + _create_sha3_ctx(28) + return _hash_impl->hash_file_28(path, load_at_once) +} + +hash_224 :: proc { + hash_stream_224, + hash_file_224, + hash_bytes_224, + hash_string_224, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_sha3_ctx(32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_384 will hash the given input and return the +// computed hash +hash_string_384 :: proc(data: string) -> [48]byte { + return hash_bytes_384(transmute([]byte)(data)) +} + +// hash_bytes_384 will hash the given input and return the +// computed hash +hash_bytes_384 :: proc(data: []byte) -> [48]byte { + _create_sha3_ctx(48) + return _hash_impl->hash_bytes_48(data) +} + +// hash_stream_384 will read the stream in chunks and compute a +// hash from its contents +hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { + _create_sha3_ctx(48) + return _hash_impl->hash_stream_48(s) +} + +// hash_file_384 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_384 :: proc(path: string, load_at_once: bool) -> ([48]byte, bool) { + _create_sha3_ctx(48) + return _hash_impl->hash_file_48(path, load_at_once) +} + +hash_384 :: proc { + hash_stream_384, + hash_file_384, + hash_bytes_384, + hash_string_384, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_sha3_ctx(64) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_sha3_ctx(64) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_sha3_ctx(64) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { + hash: [28]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { + hash: [28]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([28]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_28(ctx, buf[:]), read_ok + } + } + } + return [28]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { + hash: [48]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { + hash: [48]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([48]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_48(ctx, buf[:]), read_ok + } + } + } + return [48]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_create_sha3_ctx :: #force_inline proc(mdlen: int) { + ctx: _sha3.Sha3_Context + ctx.mdlen = mdlen + _hash_impl.internal_ctx = ctx + switch mdlen { + case 28: _hash_impl.hash_size = ._28 + case 32: _hash_impl.hash_size = ._32 + case 48: _hash_impl.hash_size = ._48 + case 64: _hash_impl.hash_size = ._64 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._28: _create_sha3_ctx(28) + case ._32: _create_sha3_ctx(32) + case ._48: _create_sha3_ctx(48) + case ._64: _create_sha3_ctx(64) + } + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.final_odin(&c, hash) + } +} diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin new file mode 100644 index 000000000..ed6517751 --- /dev/null +++ b/core/crypto/shake/shake.odin @@ -0,0 +1,279 @@ +package shake + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the SHAKE hashing algorithm. + The SHA3 functionality can be found in package sha3. +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../_sha3" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin_16 + ctx.hash_file_16 = hash_file_odin_16 + ctx.hash_stream_16 = hash_stream_odin_16 + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_SHAKE) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_128 will hash the given input and return the +// computed hash +hash_string_128 :: proc(data: string) -> [16]byte { + return hash_bytes_128(transmute([]byte)(data)) +} + +// hash_bytes_128 will hash the given input and return the +// computed hash +hash_bytes_128 :: proc(data: []byte) -> [16]byte { + _create_sha3_ctx(16) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_sha3_ctx(16) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_sha3_ctx(16) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128 :: proc { + hash_stream_128, + hash_file_128, + hash_bytes_128, + hash_string_128, +} + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_sha3_ctx(32) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_sha3_ctx(32) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.shake_xof_odin(&c) + _sha3.shake_out_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.shake_xof_odin(&c) + _sha3.shake_out_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_16(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + _sha3.update_odin(&c, data) + _sha3.shake_xof_odin(&c) + _sha3.shake_out_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _sha3.update_odin(&c, buf[:read]) + } + } + _sha3.shake_xof_odin(&c) + _sha3.shake_out_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +@(private) +_create_sha3_ctx :: #force_inline proc(mdlen: int) { + ctx: _sha3.Sha3_Context + ctx.mdlen = mdlen + _hash_impl.internal_ctx = ctx + switch mdlen { + case 16: _hash_impl.hash_size = ._16 + case 32: _hash_impl.hash_size = ._32 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._16: _create_sha3_ctx(16) + case ._32: _create_sha3_ctx(32) + } + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { + _sha3.shake_xof_odin(&c) + _sha3.shake_out_odin(&c, hash[:]) + } +} diff --git a/core/crypto/skein/skein.odin b/core/crypto/skein/skein.odin new file mode 100644 index 000000000..08c53415a --- /dev/null +++ b/core/crypto/skein/skein.odin @@ -0,0 +1,496 @@ +package skein + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the SKEIN hashing algorithm, as defined in + + This package offers the internal state sizes of 256, 512 and 1024 bits and arbitrary output size. +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + ctx.is_using_odin = false + } else { + _assign_hash_vtable(ctx) + ctx.is_using_odin = true + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + // @note(zh): Default to SKEIN-512 + ctx.hash_bytes_slice = hash_bytes_skein512_odin + ctx.hash_file_slice = hash_file_skein512_odin + ctx.hash_stream_slice = hash_stream_skein512_odin + ctx.init = _init_skein512_odin + ctx.update = _update_skein512_odin + ctx.final = _final_skein512_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + _hash_impl.is_using_odin = false + // @note(zh): Botan only supports SKEIN-512. + botan.assign_hash_vtable(_hash_impl, botan.HASH_SKEIN_512) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +@(warning="SKEIN is not yet implemented in Odin. Botan bindings will be used") +use_odin :: #force_inline proc() { + // _hash_impl.is_using_odin = true + // _assign_hash_vtable(_hash_impl) + use_botan() +} + +@(private) +_create_skein256_ctx :: #force_inline proc(size: int) { + _hash_impl.hash_size_val = size + if _hash_impl.is_using_odin { + ctx: Skein256_Context + ctx.h.bit_length = u64(size) + _hash_impl.internal_ctx = ctx + _hash_impl.hash_bytes_slice = hash_bytes_skein256_odin + _hash_impl.hash_file_slice = hash_file_skein256_odin + _hash_impl.hash_stream_slice = hash_stream_skein256_odin + _hash_impl.init = _init_skein256_odin + _hash_impl.update = _update_skein256_odin + _hash_impl.final = _final_skein256_odin + } +} + +@(private) +_create_skein512_ctx :: #force_inline proc(size: int) { + _hash_impl.hash_size_val = size + if _hash_impl.is_using_odin { + ctx: Skein512_Context + ctx.h.bit_length = u64(size) + _hash_impl.internal_ctx = ctx + _hash_impl.hash_bytes_slice = hash_bytes_skein512_odin + _hash_impl.hash_file_slice = hash_file_skein512_odin + _hash_impl.hash_stream_slice = hash_stream_skein512_odin + _hash_impl.init = _init_skein512_odin + _hash_impl.update = _update_skein512_odin + _hash_impl.final = _final_skein512_odin + } +} + +@(private) +_create_skein1024_ctx :: #force_inline proc(size: int) { + _hash_impl.hash_size_val = size + if _hash_impl.is_using_odin { + ctx: Skein1024_Context + ctx.h.bit_length = u64(size) + _hash_impl.internal_ctx = ctx + _hash_impl.hash_bytes_slice = hash_bytes_skein1024_odin + _hash_impl.hash_file_slice = hash_file_skein1024_odin + _hash_impl.hash_stream_slice = hash_stream_skein1024_odin + _hash_impl.init = _init_skein1024_odin + _hash_impl.update = _update_skein1024_odin + _hash_impl.final = _final_skein1024_odin + } +} + +/* + High level API +*/ + +// hash_skein256_string will hash the given input and return the +// computed hash +hash_skein256_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { + return hash_skein256_bytes(transmute([]byte)(data), bit_size, allocator) +} + +// hash_skein256_bytes will hash the given input and return the +// computed hash +hash_skein256_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + _create_skein256_ctx(bit_size) + return _hash_impl->hash_bytes_slice(data, bit_size, allocator) +} + +// hash_skein256_stream will read the stream in chunks and compute a +// hash from its contents +hash_skein256_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + _create_skein256_ctx(bit_size) + return _hash_impl->hash_stream_slice(s, bit_size, allocator) +} + +// hash_skein256_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_skein256_file :: proc(path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + _create_skein256_ctx(bit_size) + return _hash_impl->hash_file_slice(path, bit_size, load_at_once, allocator) +} + +hash_skein256 :: proc { + hash_skein256_stream, + hash_skein256_file, + hash_skein256_bytes, + hash_skein256_string, +} + +// hash_skein512_string will hash the given input and return the +// computed hash +hash_skein512_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { + return hash_skein512_bytes(transmute([]byte)(data), bit_size, allocator) +} + +// hash_skein512_bytes will hash the given input and return the +// computed hash +hash_skein512_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + _create_skein512_ctx(bit_size) + return _hash_impl->hash_bytes_slice(data, bit_size, allocator) +} + +// hash_skein512_stream will read the stream in chunks and compute a +// hash from its contents +hash_skein512_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + _create_skein512_ctx(bit_size) + return _hash_impl->hash_stream_slice(s, bit_size, allocator) +} + +// hash_skein512_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_skein512_file :: proc(path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + _create_skein512_ctx(bit_size) + return _hash_impl->hash_file_slice(path, bit_size, load_at_once, allocator) +} + +hash_skein512 :: proc { + hash_skein512_stream, + hash_skein512_file, + hash_skein512_bytes, + hash_skein512_string, +} + +// hash_skein1024_string will hash the given input and return the +// computed hash +hash_skein1024_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { + return hash_skein1024_bytes(transmute([]byte)(data), bit_size, allocator) +} + +// hash_skein1024_bytes will hash the given input and return the +// computed hash +hash_skein1024_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + _create_skein1024_ctx(bit_size) + return _hash_impl->hash_bytes_slice(data, bit_size, allocator) +} + +// hash_skein1024_stream will read the stream in chunks and compute a +// hash from its contents +hash_skein1024_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + _create_skein1024_ctx(bit_size) + return _hash_impl->hash_stream_slice(s, bit_size, allocator) +} + +// hash_skein1024_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_skein1024_file :: proc(path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + _create_skein1024_ctx(bit_size) + return _hash_impl->hash_file_slice(path, bit_size, load_at_once, allocator) +} + +hash_skein1024 :: proc { + hash_skein1024_stream, + hash_skein1024_file, + hash_skein1024_bytes, + hash_skein1024_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein256_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + return hash + } else { + delete(hash) + return nil + } +} + +hash_stream_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein256_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + delete(hash) + return nil, false + } +} + +hash_file_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_skein256_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_skein256_odin(ctx, buf[:], bit_size), read_ok + } + } + } + return nil, false +} + +hash_bytes_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein512_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + return hash + } else { + delete(hash) + return nil + } +} + +hash_stream_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein512_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + delete(hash) + return nil, false + } +} + +hash_file_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_skein512_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_skein512_odin(ctx, buf[:], bit_size), read_ok + } + } + } + return nil, false +} + +hash_bytes_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + return hash + } else { + delete(hash) + return nil + } +} + +hash_stream_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { + hash := make([]byte, bit_size, allocator) + if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + delete(hash) + return nil, false + } +} + +hash_file_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, bit_size: int, load_at_once: bool, allocator := context.allocator) -> ([]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_skein1024_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_skein1024_odin(ctx, buf[:], bit_size), read_ok + } + } + } + return nil, false +} + +@(private) +_init_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_skein256_ctx(ctx.hash_size_val) + if c, ok := ctx.internal_ctx.(Skein256_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Skein256_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Skein256_Context); ok { + final_odin(&c, hash) + } +} + +@(private) +_init_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_skein512_ctx(ctx.hash_size_val) + if c, ok := ctx.internal_ctx.(Skein512_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Skein512_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Skein512_Context); ok { + final_odin(&c, hash) + } +} + +@(private) +_init_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_skein1024_ctx(ctx.hash_size_val) + if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { + final_odin(&c, hash) + } +} + +/* + SKEIN implementation +*/ + +STATE_WORDS_256 :: 4 +STATE_WORDS_512 :: 8 +STATE_WORDS_1024 :: 16 + +STATE_BYTES_256 :: 32 +STATE_BYTES_512 :: 64 +STATE_BYTES_1024 :: 128 + +Skein_Header :: struct { + bit_length: u64, + bcnt: u64, + t: [2]u64, +} + +Skein256_Context :: struct { + h: Skein_Header, + x: [STATE_WORDS_256]u64, + b: [STATE_BYTES_256]byte, +} + +Skein512_Context :: struct { + h: Skein_Header, + x: [STATE_WORDS_512]u64, + b: [STATE_BYTES_512]byte, +} + +Skein1024_Context :: struct { + h: Skein_Header, + x: [STATE_WORDS_1024]u64, + b: [STATE_BYTES_1024]byte, +} + + +init_odin :: proc(ctx: ^$T) { + +} + +update_odin :: proc(ctx: ^$T, data: []byte) { + +} + +final_odin :: proc(ctx: ^$T, hash: []byte) { + +} \ No newline at end of file diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin new file mode 100644 index 000000000..979c792f1 --- /dev/null +++ b/core/crypto/sm3/sm3.odin @@ -0,0 +1,336 @@ +package sm3 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the SM3 hashing algorithm, as defined in +*/ + +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_32 = hash_bytes_odin + ctx.hash_file_32 = hash_file_odin + ctx.hash_stream_32 = hash_stream_odin + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_SM3) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [32]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [32]byte { + _create_sm3_ctx() + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_sm3_ctx() + return _hash_impl->hash_stream_32(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_sm3_ctx() + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Sm3_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Sm3_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +@(private) +_create_sm3_ctx :: #force_inline proc() { + ctx: Sm3_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._32 +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_sm3_ctx() + if c, ok := ctx.internal_ctx.(Sm3_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Sm3_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Sm3_Context); ok { + final_odin(&c, hash) + } +} + +/* + SM3 implementation +*/ + +Sm3_Context :: struct { + state: [8]u32, + x: [64]byte, + bitlength: u64, + length: u64, +} + +BLOCK_SIZE_IN_BYTES :: 64 +BLOCK_SIZE_IN_32 :: 16 + +IV := [8]u32 { + 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, + 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, +} + +init_odin :: proc(ctx: ^Sm3_Context) { + ctx.state[0] = IV[0] + ctx.state[1] = IV[1] + ctx.state[2] = IV[2] + ctx.state[3] = IV[3] + ctx.state[4] = IV[4] + ctx.state[5] = IV[5] + ctx.state[6] = IV[6] + ctx.state[7] = IV[7] +} + +block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { + buf := buf + + w: [68]u32 + wp: [64]u32 + + state0, state1, state2, state3 := ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] + state4, state5, state6, state7 := ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] + + for len(buf) >= 64 { + for i := 0; i < 16; i += 1 { + j := i * 4 + w[i] = u32(buf[j]) << 24 | u32(buf[j + 1]) << 16 | u32(buf[j + 2]) << 8 | u32(buf[j + 3]) + } + for i := 16; i < 68; i += 1 { + p1v := w[i - 16] ~ w[i - 9] ~ util.ROTL32(w[i - 3], 15) + // @note(zh): inlined P1 + w[i] = p1v ~ util.ROTL32(p1v, 15) ~ util.ROTL32(p1v, 23) ~ util.ROTL32(w[i - 13], 7) ~ w[i - 6] + } + for i := 0; i < 64; i += 1 { + wp[i] = w[i] ~ w[i + 4] + } + + a, b, c, d := state0, state1, state2, state3 + e, f, g, h := state4, state5, state6, state7 + + for i := 0; i < 16; i += 1 { + v1 := util.ROTL32(u32(a), 12) + ss1 := util.ROTL32(v1 + u32(e) + util.ROTL32(0x79cc4519, i), 7) + ss2 := ss1 ~ v1 + + // @note(zh): inlined FF1 + tt1 := u32(a ~ b ~ c) + u32(d) + ss2 + wp[i] + // @note(zh): inlined GG1 + tt2 := u32(e ~ f ~ g) + u32(h) + ss1 + w[i] + + a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + // @note(zh): inlined P0 + e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + } + + for i := 16; i < 64; i += 1 { + v := util.ROTL32(u32(a), 12) + ss1 := util.ROTL32(v + u32(e) + util.ROTL32(0x7a879d8a, i % 32), 7) + ss2 := ss1 ~ v + + // @note(zh): inlined FF2 + tt1 := u32(((a & b) | (a & c) | (b & c)) + d) + ss2 + wp[i] + // @note(zh): inlined GG2 + tt2 := u32(((e & f) | ((~e) & g)) + h) + ss1 + w[i] + + a, b, c, d = tt1, a, util.ROTL32(u32(b), 9), c + // @note(zh): inlined P0 + e, f, g, h = (tt2 ~ util.ROTL32(tt2, 9) ~ util.ROTL32(tt2, 17)), e, util.ROTL32(u32(f), 19), g + } + + state0 ~= a + state1 ~= b + state2 ~= c + state3 ~= d + state4 ~= e + state5 ~= f + state6 ~= g + state7 ~= h + + buf = buf[64:] + } + + ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3 + ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] = state4, state5, state6, state7 +} + +update_odin :: proc(ctx: ^Sm3_Context, data: []byte) { + data := data + ctx.length += u64(len(data)) + + if ctx.bitlength > 0 { + n := copy(ctx.x[ctx.bitlength:], data[:]) + ctx.bitlength += u64(n) + if ctx.bitlength == 64 { + block(ctx, ctx.x[:]) + ctx.bitlength = 0 + } + data = data[n:] + } + if len(data) >= 64 { + n := len(data) &~ (64 - 1) + block(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.bitlength = u64(copy(ctx.x[:], data[:])) + } +} + +final_odin :: proc(ctx: ^Sm3_Context, hash: []byte) { + length := ctx.length + + pad: [64]byte + pad[0] = 0x80 + if length % 64 < 56 { + update_odin(ctx, pad[0: 56 - length % 64]) + } else { + update_odin(ctx, pad[0: 64 + 56 - length % 64]) + } + + length <<= 3 + util.PUT_U64_BE(pad[:], length) + update_odin(ctx, pad[0: 8]) + assert(ctx.bitlength == 0) + + util.PUT_U32_BE(hash[0:], ctx.state[0]) + util.PUT_U32_BE(hash[4:], ctx.state[1]) + util.PUT_U32_BE(hash[8:], ctx.state[2]) + util.PUT_U32_BE(hash[12:], ctx.state[3]) + util.PUT_U32_BE(hash[16:], ctx.state[4]) + util.PUT_U32_BE(hash[20:], ctx.state[5]) + util.PUT_U32_BE(hash[24:], ctx.state[6]) + util.PUT_U32_BE(hash[28:], ctx.state[7]) +} diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin new file mode 100644 index 000000000..801e6dbc7 --- /dev/null +++ b/core/crypto/streebog/streebog.odin @@ -0,0 +1,602 @@ +package streebog + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the Streebog hashing algorithm, standardized as GOST R 34.11-2012 in RFC 6986 +*/ + +import "core:os" +import "core:io" + +import "../util" +import "../botan" +import "../_ctx" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_32 = hash_bytes_odin_32 + ctx.hash_file_32 = hash_file_odin_32 + ctx.hash_stream_32 = hash_stream_odin_32 + ctx.hash_bytes_64 = hash_bytes_odin_64 + ctx.hash_file_64 = hash_file_odin_64 + ctx.hash_stream_64 = hash_stream_odin_64 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_STREEBOG) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +@(private) +_create_streebog_ctx :: #force_inline proc(is256: bool) { + ctx: Streebog_Context + ctx.is256 = is256 + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = is256 ? ._32 : ._64 +} + +/* + High level API +*/ + +// hash_string_256 will hash the given input and return the +// computed hash +hash_string_256 :: proc(data: string) -> [32]byte { + return hash_bytes_256(transmute([]byte)(data)) +} + +// hash_bytes_256 will hash the given input and return the +// computed hash +hash_bytes_256 :: proc(data: []byte) -> [32]byte { + _create_streebog_ctx(true) + return _hash_impl->hash_bytes_32(data) +} + +// hash_stream_256 will read the stream in chunks and compute a +// hash from its contents +hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { + _create_streebog_ctx(true) + return _hash_impl->hash_stream_32(s) +} + +// hash_file_256 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_256 :: proc(path: string, load_at_once: bool) -> ([32]byte, bool) { + _create_streebog_ctx(true) + return _hash_impl->hash_file_32(path, load_at_once) +} + +hash_256 :: proc { + hash_stream_256, + hash_file_256, + hash_bytes_256, + hash_string_256, +} + +// hash_string_512 will hash the given input and return the +// computed hash +hash_string_512 :: proc(data: string) -> [64]byte { + return hash_bytes_512(transmute([]byte)(data)) +} + +// hash_bytes_512 will hash the given input and return the +// computed hash +hash_bytes_512 :: proc(data: []byte) -> [64]byte { + _create_streebog_ctx(false) + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream_512 will read the stream in chunks and compute a +// hash from its contents +hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_streebog_ctx(false) + return _hash_impl->hash_stream_64(s) +} + +// hash_file_512 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_512 :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_streebog_ctx(false) + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash_512 :: proc { + hash_stream_512, + hash_file_512, + hash_bytes_512, + hash_string_512, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { + hash: [32]byte + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([32]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_32(ctx, buf[:]), read_ok + } + } + } + return [32]byte{}, false +} + +hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + init_odin(&c) + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_64(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + _create_streebog_ctx(ctx.hash_size == ._32) + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Streebog_Context); ok { + final_odin(&c, hash) + } +} + +/* + Streebog implementation +*/ + +PI := [256]byte { + 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77, + 233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, + 249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, + 5, 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, + 235, 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, + 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, + 21, 161, 150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, + 50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, + 223, 245, 36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, + 224, 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, + 167, 151, 96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, + 173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, + 7, 88, 179, 64, 134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, + 225, 27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, + 32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, + 89, 166, 116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182, +} + +TAU := [64]byte { + 0, 8, 16, 24, 32, 40, 48, 56, + 1, 9, 17, 25, 33, 41, 49, 57, + 2, 10, 18, 26, 34, 42, 50, 58, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63, +} + +STREEBOG_A := [64]u64 { + 0x8e20faa72ba0b470, 0x47107ddd9b505a38, 0xad08b0e0c3282d1c, 0xd8045870ef14980e, + 0x6c022c38f90a4c07, 0x3601161cf205268d, 0x1b8e0b0e798c13c8, 0x83478b07b2468764, + 0xa011d380818e8f40, 0x5086e740ce47c920, 0x2843fd2067adea10, 0x14aff010bdd87508, + 0x0ad97808d06cb404, 0x05e23c0468365a02, 0x8c711e02341b2d01, 0x46b60f011a83988e, + 0x90dab52a387ae76f, 0x486dd4151c3dfdb9, 0x24b86a840e90f0d2, 0x125c354207487869, + 0x092e94218d243cba, 0x8a174a9ec8121e5d, 0x4585254f64090fa0, 0xaccc9ca9328a8950, + 0x9d4df05d5f661451, 0xc0a878a0a1330aa6, 0x60543c50de970553, 0x302a1e286fc58ca7, + 0x18150f14b9ec46dd, 0x0c84890ad27623e0, 0x0642ca05693b9f70, 0x0321658cba93c138, + 0x86275df09ce8aaa8, 0x439da0784e745554, 0xafc0503c273aa42a, 0xd960281e9d1d5215, + 0xe230140fc0802984, 0x71180a8960409a42, 0xb60c05ca30204d21, 0x5b068c651810a89e, + 0x456c34887a3805b9, 0xac361a443d1c8cd2, 0x561b0d22900e4669, 0x2b838811480723ba, + 0x9bcf4486248d9f5d, 0xc3e9224312c8c1a0, 0xeffa11af0964ee50, 0xf97d86d98a327728, + 0xe4fa2054a80b329c, 0x727d102a548b194e, 0x39b008152acb8227, 0x9258048415eb419d, + 0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18, + 0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8, + 0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083, +} + +STREEBOG_C := [12][64]byte { + { + 0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd, + 0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05, + 0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2, + 0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b, + 0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71, + 0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f, + 0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb, + 0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1, + }, + { + 0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6, + 0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55, + 0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c, + 0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a, + 0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61, + 0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3, + 0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f, + 0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f, + }, + { + 0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99, + 0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2, + 0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1, + 0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3, + 0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2, + 0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06, + 0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a, + 0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5, + }, + { + 0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22, + 0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34, + 0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8, + 0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9, + 0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d, + 0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48, + 0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9, + 0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef, + }, + { + 0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60, + 0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a, + 0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf, + 0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf, + 0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35, + 0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f, + 0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a, + 0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b, + }, + { + 0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa, + 0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf, + 0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a, + 0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf, + 0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18, + 0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d, + 0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f, + 0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae, + }, + { + 0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88, + 0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35, + 0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06, + 0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09, + 0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3, + 0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39, + 0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51, + 0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4, + }, + { + 0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4, + 0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36, + 0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69, + 0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4, + 0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89, + 0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e, + 0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03, + 0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b, + }, + { + 0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72, + 0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e, + 0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b, + 0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80, + 0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c, + 0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a, + 0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94, + 0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37, + }, + { + 0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74, + 0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36, + 0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a, + 0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f, + 0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f, + 0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89, + 0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38, + 0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab, + }, + { + 0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b, + 0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde, + 0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef, + 0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a, + 0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20, + 0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8, + 0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30, + 0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b, + }, + { + 0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48, + 0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa, + 0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7, + 0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d, + 0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8, + 0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd, + 0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2, + 0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37, + }, +} + +Streebog_Context :: struct { + buffer: [64]byte, + h: [64]byte, + n: [64]byte, + sigma: [64]byte, + v_0: [64]byte, + v_512: [64]byte, + buf_size: u64, + hash_size: int, + is256: bool, +} + +add_mod_512 :: proc(first_vector, second_vector, result_vector: []byte) { + t: i32 = 0 + for i: i32 = 0; i < 64; i += 1 { + t = i32(first_vector[i]) + i32(second_vector[i]) + (t >> 8) + result_vector[i] = byte(t & 0xff) + } +} + +X :: #force_inline proc(a, k, out: []byte) { + for i := 0; i < 64; i += 1 { + out[i] = a[i] ~ k[i] + } +} + +S :: #force_inline proc(state: []byte) { + t: [64]byte + for i: i32 = 63; i >= 0; i -= 1 { + t[i] = PI[state[i]] + } + copy(state, t[:]) +} + +P :: #force_inline proc(state: []byte) { + t: [64]byte + for i: i32 = 63; i >= 0; i -= 1 { + t[i] = state[TAU[i]] + } + copy(state, t[:]) +} + +L :: #force_inline proc(state: []byte) { + ins := util.cast_slice([]u64, state) + out: [8]u64 + for i: i32 = 7; i >= 0; i -= 1 { + for j: i32 = 63; j >= 0; j -= 1 { + if (ins[i] >> u32(j)) & 1 != 0 { + out[i] ~= STREEBOG_A[63 - j] + } + } + } + copy(state, util.cast_slice([]byte, out[:])) +} + +E :: #force_inline proc(K, m, state: []byte) { + X(m, K, state) + for i: i32 = 0; i < 12; i += 1 { + S(state) + P(state) + L(state) + get_key(K, i) + X(state, K, state) + } +} + +get_key :: #force_inline proc(K: []byte, i: i32) { + X(K, STREEBOG_C[i][:], K) + S(K) + P(K) + L(K) +} + +G :: #force_inline proc(h, N, m: []byte) { + t, K: [64]byte + X(N, h, K[:]) + S(K[:]) + P(K[:]) + L(K[:]) + E(K[:], m, t[:]) + X(t[:], h, t[:]) + X(t[:], m, h) +} + +stage2 :: proc(ctx: ^Streebog_Context, m: []byte) { + G(ctx.h[:], ctx.n[:], m) + add_mod_512(ctx.n[:], ctx.v_512[:], ctx.n[:]) + add_mod_512(ctx.sigma[:], m, ctx.sigma[:]) +} + +padding :: proc(ctx: ^Streebog_Context) { + if ctx.buf_size < 64 { + t: [64]byte + copy(t[:], ctx.buffer[:int(ctx.buf_size)]) + t[ctx.buf_size] = 0x01 + copy(ctx.buffer[:], t[:]) + } +} + +init_odin :: proc(ctx: ^Streebog_Context) { + if ctx.is256 { + ctx.hash_size = 256 + for _, i in ctx.h { + ctx.h[i] = 0x01 + } + } else { + ctx.hash_size = 512 + } + ctx.v_512[1] = 0x02 +} + +update_odin :: proc(ctx: ^Streebog_Context, data: []byte) { + length := u64(len(data)) + chk_size: u64 + data := data + for (length > 63) && (ctx.buf_size == 0) { + stage2(ctx, data) + data = data[64:] + length -= 64 + } + + for length != 0 { + chk_size = 64 - ctx.buf_size + if chk_size > length { + chk_size = length + } + copy(ctx.buffer[ctx.buf_size:], data[:chk_size]) + ctx.buf_size += chk_size + length -= chk_size + data = data[chk_size:] + if ctx.buf_size == 64 { + stage2(ctx, ctx.buffer[:]) + ctx.buf_size = 0 + } + } +} + +final_odin :: proc(ctx: ^Streebog_Context, hash: []byte) { + t: [64]byte + t[1] = byte((ctx.buf_size * 8) >> 8) & 0xff + t[0] = byte((ctx.buf_size) * 8) & 0xff + + padding(ctx) + + G(ctx.h[:], ctx.n[:], ctx.buffer[:]) + + add_mod_512(ctx.n[:], t[:], ctx.n[:]) + add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:]) + + G(ctx.h[:], ctx.v_0[:], ctx.n[:]) + G(ctx.h[:], ctx.v_0[:], ctx.sigma[:]) + + if ctx.is256 { + copy(hash[:], ctx.h[32:]) + } else { + copy(hash[:], ctx.h[:]) + } +} \ No newline at end of file diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin new file mode 100644 index 000000000..bcc1a4a31 --- /dev/null +++ b/core/crypto/tiger/tiger.odin @@ -0,0 +1,340 @@ +package tiger + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the Tiger1 variant of the Tiger hashing algorithm as defined in +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../_tiger" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin_16 + ctx.hash_file_16 = hash_file_odin_16 + ctx.hash_stream_16 = hash_stream_odin_16 + ctx.hash_bytes_20 = hash_bytes_odin_20 + ctx.hash_file_20 = hash_file_odin_20 + ctx.hash_stream_20 = hash_stream_odin_20 + ctx.hash_bytes_24 = hash_bytes_odin_24 + ctx.hash_file_24 = hash_file_odin_24 + ctx.hash_stream_24 = hash_stream_odin_24 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_TIGER) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_128 will hash the given input and return the +// computed hash +hash_string_128 :: proc(data: string) -> [16]byte { + return hash_bytes_128(transmute([]byte)(data)) +} + +// hash_bytes_128 will hash the given input and return the +// computed hash +hash_bytes_128 :: proc(data: []byte) -> [16]byte { + _create_ripemd_ctx(16) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128 :: proc { + hash_stream_128, + hash_file_128, + hash_bytes_128, + hash_string_128, +} + +// hash_string_160 will hash the given input and return the +// computed hash +hash_string_160 :: proc(data: string) -> [20]byte { + return hash_bytes_160(transmute([]byte)(data)) +} + +// hash_bytes_160 will hash the given input and return the +// computed hash +hash_bytes_160 :: proc(data: []byte) -> [20]byte { + _create_ripemd_ctx(20) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160 :: proc { + hash_stream_160, + hash_file_160, + hash_bytes_160, + hash_string_160, +} + +// hash_string_192 will hash the given input and return the +// computed hash +hash_string_192 :: proc(data: string) -> [24]byte { + return hash_bytes_192(transmute([]byte)(data)) +} + +// hash_bytes_192 will hash the given input and return the +// computed hash +hash_bytes_192 :: proc(data: []byte) -> [24]byte { + _create_ripemd_ctx(24) + return _hash_impl->hash_bytes_24(data) +} + +// hash_stream_192 will read the stream in chunks and compute a +// hash from its contents +hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { + _create_ripemd_ctx(24) + return _hash_impl->hash_stream_24(s) +} + +// hash_file_192 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_192 :: proc(path: string, load_at_once: bool) -> ([24]byte, bool) { + _create_ripemd_ctx(24) + return _hash_impl->hash_file_24(path, load_at_once) +} + +hash_192 :: proc { + hash_stream_192, + hash_file_192, + hash_bytes_192, + hash_string_192, +} + +hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_16(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_20(ctx, buf[:]), read_ok + } + } + } + return [20]byte{}, false +} + +hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { + hash: [24]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { + hash: [24]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([24]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_24(ctx, buf[:]), read_ok + } + } + } + return [24]byte{}, false +} + +@(private) +_create_ripemd_ctx :: #force_inline proc(hash_size: int) { + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _hash_impl.internal_ctx = ctx + switch hash_size { + case 16: _hash_impl.hash_size = ._16 + case 20: _hash_impl.hash_size = ._20 + case 24: _hash_impl.hash_size = ._24 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._16: _create_ripemd_ctx(16) + case ._20: _create_ripemd_ctx(20) + case ._24: _create_ripemd_ctx(24) + } + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.final_odin(&c, hash) + } +} diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin new file mode 100644 index 000000000..46ec25b2d --- /dev/null +++ b/core/crypto/tiger2/tiger2.odin @@ -0,0 +1,340 @@ +package tiger2 + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Interface for the Tiger2 variant of the Tiger hashing algorithm as defined in +*/ + +import "core:os" +import "core:io" + +import "../_ctx" +import "../_tiger" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_16 = hash_bytes_odin_16 + ctx.hash_file_16 = hash_file_odin_16 + ctx.hash_stream_16 = hash_stream_odin_16 + ctx.hash_bytes_20 = hash_bytes_odin_20 + ctx.hash_file_20 = hash_file_odin_20 + ctx.hash_stream_20 = hash_stream_odin_20 + ctx.hash_bytes_24 = hash_bytes_odin_24 + ctx.hash_file_24 = hash_file_odin_24 + ctx.hash_stream_24 = hash_stream_odin_24 + ctx.init = _init_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan does nothing, since Tiger2 is not available in Botan +@(warning="Tiger2 is not provided by the Botan API. Odin implementation will be used") +use_botan :: #force_inline proc() { + use_odin() +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string_128 will hash the given input and return the +// computed hash +hash_string_128 :: proc(data: string) -> [16]byte { + return hash_bytes_128(transmute([]byte)(data)) +} + +// hash_bytes_128 will hash the given input and return the +// computed hash +hash_bytes_128 :: proc(data: []byte) -> [16]byte { + _create_ripemd_ctx(16) + return _hash_impl->hash_bytes_16(data) +} + +// hash_stream_128 will read the stream in chunks and compute a +// hash from its contents +hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_stream_16(s) +} + +// hash_file_128 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_128 :: proc(path: string, load_at_once: bool) -> ([16]byte, bool) { + _create_ripemd_ctx(16) + return _hash_impl->hash_file_16(path, load_at_once) +} + +hash_128 :: proc { + hash_stream_128, + hash_file_128, + hash_bytes_128, + hash_string_128, +} + +// hash_string_160 will hash the given input and return the +// computed hash +hash_string_160 :: proc(data: string) -> [20]byte { + return hash_bytes_160(transmute([]byte)(data)) +} + +// hash_bytes_160 will hash the given input and return the +// computed hash +hash_bytes_160 :: proc(data: []byte) -> [20]byte { + _create_ripemd_ctx(20) + return _hash_impl->hash_bytes_20(data) +} + +// hash_stream_160 will read the stream in chunks and compute a +// hash from its contents +hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_stream_20(s) +} + +// hash_file_160 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_160 :: proc(path: string, load_at_once: bool) -> ([20]byte, bool) { + _create_ripemd_ctx(20) + return _hash_impl->hash_file_20(path, load_at_once) +} + +hash_160 :: proc { + hash_stream_160, + hash_file_160, + hash_bytes_160, + hash_string_160, +} + +// hash_string_192 will hash the given input and return the +// computed hash +hash_string_192 :: proc(data: string) -> [24]byte { + return hash_bytes_192(transmute([]byte)(data)) +} + +// hash_bytes_192 will hash the given input and return the +// computed hash +hash_bytes_192 :: proc(data: []byte) -> [24]byte { + _create_ripemd_ctx(24) + return _hash_impl->hash_bytes_24(data) +} + +// hash_stream_192 will read the stream in chunks and compute a +// hash from its contents +hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { + _create_ripemd_ctx(24) + return _hash_impl->hash_stream_24(s) +} + +// hash_file_192 will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file_192 :: proc(path: string, load_at_once: bool) -> ([24]byte, bool) { + _create_ripemd_ctx(24) + return _hash_impl->hash_file_24(path, load_at_once) +} + +hash_192 :: proc { + hash_stream_192, + hash_file_192, + hash_bytes_192, + hash_string_192, +} + +hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { + hash: [16]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([16]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_16(ctx, buf[:]), read_ok + } + } + } + return [16]byte{}, false +} + +hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { + hash: [20]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { + hash: [20]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([20]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_20(ctx, buf[:]), read_ok + } + } + } + return [20]byte{}, false +} + +hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { + hash: [24]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + _tiger.update_odin(&c, data) + _tiger.final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { + hash: [24]byte + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + _tiger.update_odin(&c, buf[:read]) + } + } + _tiger.final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([24]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin_24(ctx, buf[:]), read_ok + } + } + } + return [24]byte{}, false +} + +@(private) +_create_ripemd_ctx :: #force_inline proc(hash_size: int) { + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _hash_impl.internal_ctx = ctx + switch hash_size { + case 16: _hash_impl.hash_size = ._16 + case 20: _hash_impl.hash_size = ._20 + case 24: _hash_impl.hash_size = ._24 + } +} + +@(private) +_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + #partial switch ctx.hash_size { + case ._16: _create_ripemd_ctx(16) + case ._20: _create_ripemd_ctx(20) + case ._24: _create_ripemd_ctx(24) + } + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.init_odin(&c) + } +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { + _tiger.final_odin(&c, hash) + } +} \ No newline at end of file diff --git a/core/crypto/util/util.odin b/core/crypto/util/util.odin new file mode 100644 index 000000000..ce0e9a164 --- /dev/null +++ b/core/crypto/util/util.odin @@ -0,0 +1,144 @@ +package util + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + + Various utility procedures +*/ + +import "core:mem" + +// @note(bp): this can replace the other two +cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D { + src := src + dst := (^mem.Raw_Slice)(&src) + + when size_of(DE) < size_of(SE) { + when size_of(DE) % size_of(SE) == 0 { + dst.len /= size_of(SE) / size_of(DE) + } else { + dst.len *= size_of(SE) + dst.len /= size_of(DE) + } + } else when size_of(DE) > size_of(SE) { + when size_of(DE) % size_of(SE) == 0 { + dst.len *= size_of(DE) / size_of(SE) + } else { + dst.len *= size_of(SE) + dst.len /= size_of(DE) + } + } else when size_of(DE) != size_of(SE) { + #assert(size_of(DE) % size_of(SE) == 0, "Different size detected") + dst.len *= size_of(SE) + dst.len /= size_of(DE) + } + + return (^D)(dst)^ +} + +bytes_to_slice :: #force_inline proc "contextless" ($T: typeid/[]$E, bytes: []byte) -> T { + s := transmute(mem.Raw_Slice)bytes + s.len /= size_of(E) + return transmute(T)s +} + +slice_to_bytes :: #force_inline proc "contextless" (slice: $E/[]$T) -> []byte { + s := transmute(mem.Raw_Slice)slice + s.len *= size_of(T) + return transmute([]byte)s +} + +ROTL16 :: #force_inline proc "contextless" (a, b: u16) -> u16 { + return ((a << b) | (a >> (16 - b))) +} + +ROTR16 :: #force_inline proc "contextless" (a, b: u16) -> u16 { + return ((a >> b) | (a << (16 - b))) +} + +ROTL32 :: #force_inline proc "contextless"(a: u32, b: int) -> u32 { + s := uint(b) & 31 + return (a << s) | (a >> (32 - s)) +} + +ROTR32 :: #force_inline proc "contextless" (a: u32, b: int) -> u32 { + s := uint(b) & 31 + return (a >> s) | (a << (32 - s)) +} + +ROTL64 :: #force_inline proc "contextless" (a, b: u64) -> u64 { + return ((a << b) | (a >> (64 - b))) +} + +ROTR64 :: #force_inline proc "contextless" (a, b: u64) -> u64 { + return ((a >> b) | (a << (64 - b))) +} + +ROTL128 :: #force_inline proc "contextless" (a, b, c, d: ^u32, n: uint) { + a, b, c, d := a, b, c, d + t := a^ >> (32 - n) + a^ = ((a^ << n) | (b^ >> (32 - n))) + b^ = ((b^ << n) | (c^ >> (32 - n))) + c^ = ((c^ << n) | (d^ >> (32 - n))) + d^ = ((d^ << n) | t) +} + +U32_LE :: #force_inline proc "contextless" (b: []byte) -> u32 { + return u32(b[0]) | u32(b[1]) << 8 | u32(b[2]) << 16 | u32(b[3]) << 24 +} + +U64_LE :: #force_inline proc "contextless" (b: []byte) -> u64 { + return u64(b[0]) | u64(b[1]) << 8 | u64(b[2]) << 16 | u64(b[3]) << 24 | + u64(b[4]) << 32 | u64(b[5]) << 40 | u64(b[6]) << 48 | u64(b[7]) << 56 +} + +U64_BE :: #force_inline proc "contextless" (b: []byte) -> u64 { + return u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | + u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 +} + +PUT_U64_LE :: #force_inline proc "contextless" (b: []byte, v: u64) { + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) +} + +PUT_U32_LE :: #force_inline proc "contextless" (b: []byte, v: u32) { + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) +} + +PUT_U32_BE :: #force_inline proc "contextless" (b: []byte, v: u32) { + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) +} + +PUT_U64_BE :: #force_inline proc "contextless" (b: []byte, v: u64) { + b[0] = byte(v >> 56) + b[1] = byte(v >> 48) + b[2] = byte(v >> 40) + b[3] = byte(v >> 32) + b[4] = byte(v >> 24) + b[5] = byte(v >> 16) + b[6] = byte(v >> 8) + b[7] = byte(v) +} + +XOR_BUF :: #force_inline proc "contextless" (input, output: []byte) { + for i := 0; i < len(input); i += 1 { + output[i] ~= input[i] + } +} \ No newline at end of file diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin new file mode 100644 index 000000000..e74d4fe8e --- /dev/null +++ b/core/crypto/whirlpool/whirlpool.odin @@ -0,0 +1,873 @@ +package whirlpool + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. + + Implementation of the Whirlpool hashing algorithm, as defined in +*/ + +import "core:os" +import "core:io" + +import "../botan" +import "../_ctx" +import "../util" + +/* + Context initialization and switching between the Odin implementation and the bindings +*/ + +USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) + +@(private) +_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { + ctx := _ctx._init_vtable() + when USE_BOTAN_LIB { + use_botan() + } else { + _assign_hash_vtable(ctx) + } + return ctx +} + +@(private) +_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { + ctx.hash_bytes_64 = hash_bytes_odin + ctx.hash_file_64 = hash_file_odin + ctx.hash_stream_64 = hash_stream_odin + ctx.update = _update_odin + ctx.final = _final_odin +} + +_hash_impl := _init_vtable() + +// use_botan assigns the internal vtable of the hash context to use the Botan bindings +use_botan :: #force_inline proc() { + botan.assign_hash_vtable(_hash_impl, botan.HASH_WHIRLPOOL) +} + +// use_odin assigns the internal vtable of the hash context to use the Odin implementation +use_odin :: #force_inline proc() { + _assign_hash_vtable(_hash_impl) +} + +/* + High level API +*/ + +// hash_string will hash the given input and return the +// computed hash +hash_string :: proc(data: string) -> [64]byte { + return hash_bytes(transmute([]byte)(data)) +} + +// hash_bytes will hash the given input and return the +// computed hash +hash_bytes :: proc(data: []byte) -> [64]byte { + _create_whirlpool_ctx() + return _hash_impl->hash_bytes_64(data) +} + +// hash_stream will read the stream in chunks and compute a +// hash from its contents +hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { + _create_whirlpool_ctx() + return _hash_impl->hash_stream_64(s) +} + +// hash_file will try to open the file provided by the given +// path and pass it to hash_stream to compute a hash +hash_file :: proc(path: string, load_at_once: bool) -> ([64]byte, bool) { + _create_whirlpool_ctx() + return _hash_impl->hash_file_64(path, load_at_once) +} + +hash :: proc { + hash_stream, + hash_file, + hash_bytes, + hash_string, +} + +/* + Low level API +*/ + +init :: proc(ctx: ^_ctx.Hash_Context) { + _hash_impl->init() +} + +update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { + _hash_impl->update(data) +} + +final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + _hash_impl->final(hash) +} + +hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { + update_odin(&c, data) + final_odin(&c, hash[:]) + } + return hash +} + +hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { + hash: [64]byte + if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = fs->impl_read(buf) + if read > 0 { + update_odin(&c, buf[:read]) + } + } + final_odin(&c, hash[:]) + return hash, true + } else { + return hash, false + } +} + +hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, path: string, load_at_once: bool) -> ([64]byte, bool) { + if hd, err := os.open(path); err == os.ERROR_NONE { + defer os.close(hd) + if !load_at_once { + return hash_stream_odin(ctx, os.stream_from_handle(hd)) + } else { + if buf, read_ok := os.read_entire_file(path); read_ok { + return hash_bytes_odin(ctx, buf[:]), read_ok + } + } + } + return [64]byte{}, false +} + +@(private) +_create_whirlpool_ctx :: #force_inline proc() { + ctx: Whirlpool_Context + _hash_impl.internal_ctx = ctx + _hash_impl.hash_size = ._64 +} + +@(private) +_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { + if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { + update_odin(&c, data) + } +} + +@(private) +_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { + if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { + final_odin(&c, hash) + } +} + +/* + Whirlpool implementation +*/ + +ROUNDS :: 10 + +Whirlpool_Context :: struct { + bitlength: [32]byte, + buffer: [64]byte, + buffer_bits: int, + buffer_pos: int, + hash: [8]u64, +} + +C0 := [256]u64 { + 0x18186018c07830d8, 0x23238c2305af4626, 0xc6c63fc67ef991b8, 0xe8e887e8136fcdfb, + 0x878726874ca113cb, 0xb8b8dab8a9626d11, 0x0101040108050209, 0x4f4f214f426e9e0d, + 0x3636d836adee6c9b, 0xa6a6a2a6590451ff, 0xd2d26fd2debdb90c, 0xf5f5f3f5fb06f70e, + 0x7979f979ef80f296, 0x6f6fa16f5fcede30, 0x91917e91fcef3f6d, 0x52525552aa07a4f8, + 0x60609d6027fdc047, 0xbcbccabc89766535, 0x9b9b569baccd2b37, 0x8e8e028e048c018a, + 0xa3a3b6a371155bd2, 0x0c0c300c603c186c, 0x7b7bf17bff8af684, 0x3535d435b5e16a80, + 0x1d1d741de8693af5, 0xe0e0a7e05347ddb3, 0xd7d77bd7f6acb321, 0xc2c22fc25eed999c, + 0x2e2eb82e6d965c43, 0x4b4b314b627a9629, 0xfefedffea321e15d, 0x575741578216aed5, + 0x15155415a8412abd, 0x7777c1779fb6eee8, 0x3737dc37a5eb6e92, 0xe5e5b3e57b56d79e, + 0x9f9f469f8cd92313, 0xf0f0e7f0d317fd23, 0x4a4a354a6a7f9420, 0xdada4fda9e95a944, + 0x58587d58fa25b0a2, 0xc9c903c906ca8fcf, 0x2929a429558d527c, 0x0a0a280a5022145a, + 0xb1b1feb1e14f7f50, 0xa0a0baa0691a5dc9, 0x6b6bb16b7fdad614, 0x85852e855cab17d9, + 0xbdbdcebd8173673c, 0x5d5d695dd234ba8f, 0x1010401080502090, 0xf4f4f7f4f303f507, + 0xcbcb0bcb16c08bdd, 0x3e3ef83eedc67cd3, 0x0505140528110a2d, 0x676781671fe6ce78, + 0xe4e4b7e47353d597, 0x27279c2725bb4e02, 0x4141194132588273, 0x8b8b168b2c9d0ba7, + 0xa7a7a6a7510153f6, 0x7d7de97dcf94fab2, 0x95956e95dcfb3749, 0xd8d847d88e9fad56, + 0xfbfbcbfb8b30eb70, 0xeeee9fee2371c1cd, 0x7c7ced7cc791f8bb, 0x6666856617e3cc71, + 0xdddd53dda68ea77b, 0x17175c17b84b2eaf, 0x4747014702468e45, 0x9e9e429e84dc211a, + 0xcaca0fca1ec589d4, 0x2d2db42d75995a58, 0xbfbfc6bf9179632e, 0x07071c07381b0e3f, + 0xadad8ead012347ac, 0x5a5a755aea2fb4b0, 0x838336836cb51bef, 0x3333cc3385ff66b6, + 0x636391633ff2c65c, 0x02020802100a0412, 0xaaaa92aa39384993, 0x7171d971afa8e2de, + 0xc8c807c80ecf8dc6, 0x19196419c87d32d1, 0x494939497270923b, 0xd9d943d9869aaf5f, + 0xf2f2eff2c31df931, 0xe3e3abe34b48dba8, 0x5b5b715be22ab6b9, 0x88881a8834920dbc, + 0x9a9a529aa4c8293e, 0x262698262dbe4c0b, 0x3232c8328dfa64bf, 0xb0b0fab0e94a7d59, + 0xe9e983e91b6acff2, 0x0f0f3c0f78331e77, 0xd5d573d5e6a6b733, 0x80803a8074ba1df4, + 0xbebec2be997c6127, 0xcdcd13cd26de87eb, 0x3434d034bde46889, 0x48483d487a759032, + 0xffffdbffab24e354, 0x7a7af57af78ff48d, 0x90907a90f4ea3d64, 0x5f5f615fc23ebe9d, + 0x202080201da0403d, 0x6868bd6867d5d00f, 0x1a1a681ad07234ca, 0xaeae82ae192c41b7, + 0xb4b4eab4c95e757d, 0x54544d549a19a8ce, 0x93937693ece53b7f, 0x222288220daa442f, + 0x64648d6407e9c863, 0xf1f1e3f1db12ff2a, 0x7373d173bfa2e6cc, 0x12124812905a2482, + 0x40401d403a5d807a, 0x0808200840281048, 0xc3c32bc356e89b95, 0xecec97ec337bc5df, + 0xdbdb4bdb9690ab4d, 0xa1a1bea1611f5fc0, 0x8d8d0e8d1c830791, 0x3d3df43df5c97ac8, + 0x97976697ccf1335b, 0x0000000000000000, 0xcfcf1bcf36d483f9, 0x2b2bac2b4587566e, + 0x7676c57697b3ece1, 0x8282328264b019e6, 0xd6d67fd6fea9b128, 0x1b1b6c1bd87736c3, + 0xb5b5eeb5c15b7774, 0xafaf86af112943be, 0x6a6ab56a77dfd41d, 0x50505d50ba0da0ea, + 0x45450945124c8a57, 0xf3f3ebf3cb18fb38, 0x3030c0309df060ad, 0xefef9bef2b74c3c4, + 0x3f3ffc3fe5c37eda, 0x55554955921caac7, 0xa2a2b2a2791059db, 0xeaea8fea0365c9e9, + 0x656589650fecca6a, 0xbabad2bab9686903, 0x2f2fbc2f65935e4a, 0xc0c027c04ee79d8e, + 0xdede5fdebe81a160, 0x1c1c701ce06c38fc, 0xfdfdd3fdbb2ee746, 0x4d4d294d52649a1f, + 0x92927292e4e03976, 0x7575c9758fbceafa, 0x06061806301e0c36, 0x8a8a128a249809ae, + 0xb2b2f2b2f940794b, 0xe6e6bfe66359d185, 0x0e0e380e70361c7e, 0x1f1f7c1ff8633ee7, + 0x6262956237f7c455, 0xd4d477d4eea3b53a, 0xa8a89aa829324d81, 0x96966296c4f43152, + 0xf9f9c3f99b3aef62, 0xc5c533c566f697a3, 0x2525942535b14a10, 0x59597959f220b2ab, + 0x84842a8454ae15d0, 0x7272d572b7a7e4c5, 0x3939e439d5dd72ec, 0x4c4c2d4c5a619816, + 0x5e5e655eca3bbc94, 0x7878fd78e785f09f, 0x3838e038ddd870e5, 0x8c8c0a8c14860598, + 0xd1d163d1c6b2bf17, 0xa5a5aea5410b57e4, 0xe2e2afe2434dd9a1, 0x616199612ff8c24e, + 0xb3b3f6b3f1457b42, 0x2121842115a54234, 0x9c9c4a9c94d62508, 0x1e1e781ef0663cee, + 0x4343114322528661, 0xc7c73bc776fc93b1, 0xfcfcd7fcb32be54f, 0x0404100420140824, + 0x51515951b208a2e3, 0x99995e99bcc72f25, 0x6d6da96d4fc4da22, 0x0d0d340d68391a65, + 0xfafacffa8335e979, 0xdfdf5bdfb684a369, 0x7e7ee57ed79bfca9, 0x242490243db44819, + 0x3b3bec3bc5d776fe, 0xabab96ab313d4b9a, 0xcece1fce3ed181f0, 0x1111441188552299, + 0x8f8f068f0c890383, 0x4e4e254e4a6b9c04, 0xb7b7e6b7d1517366, 0xebeb8beb0b60cbe0, + 0x3c3cf03cfdcc78c1, 0x81813e817cbf1ffd, 0x94946a94d4fe3540, 0xf7f7fbf7eb0cf31c, + 0xb9b9deb9a1676f18, 0x13134c13985f268b, 0x2c2cb02c7d9c5851, 0xd3d36bd3d6b8bb05, + 0xe7e7bbe76b5cd38c, 0x6e6ea56e57cbdc39, 0xc4c437c46ef395aa, 0x03030c03180f061b, + 0x565645568a13acdc, 0x44440d441a49885e, 0x7f7fe17fdf9efea0, 0xa9a99ea921374f88, + 0x2a2aa82a4d825467, 0xbbbbd6bbb16d6b0a, 0xc1c123c146e29f87, 0x53535153a202a6f1, + 0xdcdc57dcae8ba572, 0x0b0b2c0b58271653, 0x9d9d4e9d9cd32701, 0x6c6cad6c47c1d82b, + 0x3131c43195f562a4, 0x7474cd7487b9e8f3, 0xf6f6fff6e309f115, 0x464605460a438c4c, + 0xacac8aac092645a5, 0x89891e893c970fb5, 0x14145014a04428b4, 0xe1e1a3e15b42dfba, + 0x16165816b04e2ca6, 0x3a3ae83acdd274f7, 0x6969b9696fd0d206, 0x09092409482d1241, + 0x7070dd70a7ade0d7, 0xb6b6e2b6d954716f, 0xd0d067d0ceb7bd1e, 0xeded93ed3b7ec7d6, + 0xcccc17cc2edb85e2, 0x424215422a578468, 0x98985a98b4c22d2c, 0xa4a4aaa4490e55ed, + 0x2828a0285d885075, 0x5c5c6d5cda31b886, 0xf8f8c7f8933fed6b, 0x8686228644a411c2, +} + +C1 := [256]u64 { + 0xd818186018c07830, 0x2623238c2305af46, 0xb8c6c63fc67ef991, 0xfbe8e887e8136fcd, + 0xcb878726874ca113, 0x11b8b8dab8a9626d, 0x0901010401080502, 0x0d4f4f214f426e9e, + 0x9b3636d836adee6c, 0xffa6a6a2a6590451, 0x0cd2d26fd2debdb9, 0x0ef5f5f3f5fb06f7, + 0x967979f979ef80f2, 0x306f6fa16f5fcede, 0x6d91917e91fcef3f, 0xf852525552aa07a4, + 0x4760609d6027fdc0, 0x35bcbccabc897665, 0x379b9b569baccd2b, 0x8a8e8e028e048c01, + 0xd2a3a3b6a371155b, 0x6c0c0c300c603c18, 0x847b7bf17bff8af6, 0x803535d435b5e16a, + 0xf51d1d741de8693a, 0xb3e0e0a7e05347dd, 0x21d7d77bd7f6acb3, 0x9cc2c22fc25eed99, + 0x432e2eb82e6d965c, 0x294b4b314b627a96, 0x5dfefedffea321e1, 0xd5575741578216ae, + 0xbd15155415a8412a, 0xe87777c1779fb6ee, 0x923737dc37a5eb6e, 0x9ee5e5b3e57b56d7, + 0x139f9f469f8cd923, 0x23f0f0e7f0d317fd, 0x204a4a354a6a7f94, 0x44dada4fda9e95a9, + 0xa258587d58fa25b0, 0xcfc9c903c906ca8f, 0x7c2929a429558d52, 0x5a0a0a280a502214, + 0x50b1b1feb1e14f7f, 0xc9a0a0baa0691a5d, 0x146b6bb16b7fdad6, 0xd985852e855cab17, + 0x3cbdbdcebd817367, 0x8f5d5d695dd234ba, 0x9010104010805020, 0x07f4f4f7f4f303f5, + 0xddcbcb0bcb16c08b, 0xd33e3ef83eedc67c, 0x2d0505140528110a, 0x78676781671fe6ce, + 0x97e4e4b7e47353d5, 0x0227279c2725bb4e, 0x7341411941325882, 0xa78b8b168b2c9d0b, + 0xf6a7a7a6a7510153, 0xb27d7de97dcf94fa, 0x4995956e95dcfb37, 0x56d8d847d88e9fad, + 0x70fbfbcbfb8b30eb, 0xcdeeee9fee2371c1, 0xbb7c7ced7cc791f8, 0x716666856617e3cc, + 0x7bdddd53dda68ea7, 0xaf17175c17b84b2e, 0x454747014702468e, 0x1a9e9e429e84dc21, + 0xd4caca0fca1ec589, 0x582d2db42d75995a, 0x2ebfbfc6bf917963, 0x3f07071c07381b0e, + 0xacadad8ead012347, 0xb05a5a755aea2fb4, 0xef838336836cb51b, 0xb63333cc3385ff66, + 0x5c636391633ff2c6, 0x1202020802100a04, 0x93aaaa92aa393849, 0xde7171d971afa8e2, + 0xc6c8c807c80ecf8d, 0xd119196419c87d32, 0x3b49493949727092, 0x5fd9d943d9869aaf, + 0x31f2f2eff2c31df9, 0xa8e3e3abe34b48db, 0xb95b5b715be22ab6, 0xbc88881a8834920d, + 0x3e9a9a529aa4c829, 0x0b262698262dbe4c, 0xbf3232c8328dfa64, 0x59b0b0fab0e94a7d, + 0xf2e9e983e91b6acf, 0x770f0f3c0f78331e, 0x33d5d573d5e6a6b7, 0xf480803a8074ba1d, + 0x27bebec2be997c61, 0xebcdcd13cd26de87, 0x893434d034bde468, 0x3248483d487a7590, + 0x54ffffdbffab24e3, 0x8d7a7af57af78ff4, 0x6490907a90f4ea3d, 0x9d5f5f615fc23ebe, + 0x3d202080201da040, 0x0f6868bd6867d5d0, 0xca1a1a681ad07234, 0xb7aeae82ae192c41, + 0x7db4b4eab4c95e75, 0xce54544d549a19a8, 0x7f93937693ece53b, 0x2f222288220daa44, + 0x6364648d6407e9c8, 0x2af1f1e3f1db12ff, 0xcc7373d173bfa2e6, 0x8212124812905a24, + 0x7a40401d403a5d80, 0x4808082008402810, 0x95c3c32bc356e89b, 0xdfecec97ec337bc5, + 0x4ddbdb4bdb9690ab, 0xc0a1a1bea1611f5f, 0x918d8d0e8d1c8307, 0xc83d3df43df5c97a, + 0x5b97976697ccf133, 0x0000000000000000, 0xf9cfcf1bcf36d483, 0x6e2b2bac2b458756, + 0xe17676c57697b3ec, 0xe68282328264b019, 0x28d6d67fd6fea9b1, 0xc31b1b6c1bd87736, + 0x74b5b5eeb5c15b77, 0xbeafaf86af112943, 0x1d6a6ab56a77dfd4, 0xea50505d50ba0da0, + 0x5745450945124c8a, 0x38f3f3ebf3cb18fb, 0xad3030c0309df060, 0xc4efef9bef2b74c3, + 0xda3f3ffc3fe5c37e, 0xc755554955921caa, 0xdba2a2b2a2791059, 0xe9eaea8fea0365c9, + 0x6a656589650fecca, 0x03babad2bab96869, 0x4a2f2fbc2f65935e, 0x8ec0c027c04ee79d, + 0x60dede5fdebe81a1, 0xfc1c1c701ce06c38, 0x46fdfdd3fdbb2ee7, 0x1f4d4d294d52649a, + 0x7692927292e4e039, 0xfa7575c9758fbcea, 0x3606061806301e0c, 0xae8a8a128a249809, + 0x4bb2b2f2b2f94079, 0x85e6e6bfe66359d1, 0x7e0e0e380e70361c, 0xe71f1f7c1ff8633e, + 0x556262956237f7c4, 0x3ad4d477d4eea3b5, 0x81a8a89aa829324d, 0x5296966296c4f431, + 0x62f9f9c3f99b3aef, 0xa3c5c533c566f697, 0x102525942535b14a, 0xab59597959f220b2, + 0xd084842a8454ae15, 0xc57272d572b7a7e4, 0xec3939e439d5dd72, 0x164c4c2d4c5a6198, + 0x945e5e655eca3bbc, 0x9f7878fd78e785f0, 0xe53838e038ddd870, 0x988c8c0a8c148605, + 0x17d1d163d1c6b2bf, 0xe4a5a5aea5410b57, 0xa1e2e2afe2434dd9, 0x4e616199612ff8c2, + 0x42b3b3f6b3f1457b, 0x342121842115a542, 0x089c9c4a9c94d625, 0xee1e1e781ef0663c, + 0x6143431143225286, 0xb1c7c73bc776fc93, 0x4ffcfcd7fcb32be5, 0x2404041004201408, + 0xe351515951b208a2, 0x2599995e99bcc72f, 0x226d6da96d4fc4da, 0x650d0d340d68391a, + 0x79fafacffa8335e9, 0x69dfdf5bdfb684a3, 0xa97e7ee57ed79bfc, 0x19242490243db448, + 0xfe3b3bec3bc5d776, 0x9aabab96ab313d4b, 0xf0cece1fce3ed181, 0x9911114411885522, + 0x838f8f068f0c8903, 0x044e4e254e4a6b9c, 0x66b7b7e6b7d15173, 0xe0ebeb8beb0b60cb, + 0xc13c3cf03cfdcc78, 0xfd81813e817cbf1f, 0x4094946a94d4fe35, 0x1cf7f7fbf7eb0cf3, + 0x18b9b9deb9a1676f, 0x8b13134c13985f26, 0x512c2cb02c7d9c58, 0x05d3d36bd3d6b8bb, + 0x8ce7e7bbe76b5cd3, 0x396e6ea56e57cbdc, 0xaac4c437c46ef395, 0x1b03030c03180f06, + 0xdc565645568a13ac, 0x5e44440d441a4988, 0xa07f7fe17fdf9efe, 0x88a9a99ea921374f, + 0x672a2aa82a4d8254, 0x0abbbbd6bbb16d6b, 0x87c1c123c146e29f, 0xf153535153a202a6, + 0x72dcdc57dcae8ba5, 0x530b0b2c0b582716, 0x019d9d4e9d9cd327, 0x2b6c6cad6c47c1d8, + 0xa43131c43195f562, 0xf37474cd7487b9e8, 0x15f6f6fff6e309f1, 0x4c464605460a438c, + 0xa5acac8aac092645, 0xb589891e893c970f, 0xb414145014a04428, 0xbae1e1a3e15b42df, + 0xa616165816b04e2c, 0xf73a3ae83acdd274, 0x066969b9696fd0d2, 0x4109092409482d12, + 0xd77070dd70a7ade0, 0x6fb6b6e2b6d95471, 0x1ed0d067d0ceb7bd, 0xd6eded93ed3b7ec7, + 0xe2cccc17cc2edb85, 0x68424215422a5784, 0x2c98985a98b4c22d, 0xeda4a4aaa4490e55, + 0x752828a0285d8850, 0x865c5c6d5cda31b8, 0x6bf8f8c7f8933fed, 0xc28686228644a411, +} + +C2 := [256]u64 { + 0x30d818186018c078, 0x462623238c2305af, 0x91b8c6c63fc67ef9, 0xcdfbe8e887e8136f, + 0x13cb878726874ca1, 0x6d11b8b8dab8a962, 0x0209010104010805, 0x9e0d4f4f214f426e, + 0x6c9b3636d836adee, 0x51ffa6a6a2a65904, 0xb90cd2d26fd2debd, 0xf70ef5f5f3f5fb06, + 0xf2967979f979ef80, 0xde306f6fa16f5fce, 0x3f6d91917e91fcef, 0xa4f852525552aa07, + 0xc04760609d6027fd, 0x6535bcbccabc8976, 0x2b379b9b569baccd, 0x018a8e8e028e048c, + 0x5bd2a3a3b6a37115, 0x186c0c0c300c603c, 0xf6847b7bf17bff8a, 0x6a803535d435b5e1, + 0x3af51d1d741de869, 0xddb3e0e0a7e05347, 0xb321d7d77bd7f6ac, 0x999cc2c22fc25eed, + 0x5c432e2eb82e6d96, 0x96294b4b314b627a, 0xe15dfefedffea321, 0xaed5575741578216, + 0x2abd15155415a841, 0xeee87777c1779fb6, 0x6e923737dc37a5eb, 0xd79ee5e5b3e57b56, + 0x23139f9f469f8cd9, 0xfd23f0f0e7f0d317, 0x94204a4a354a6a7f, 0xa944dada4fda9e95, + 0xb0a258587d58fa25, 0x8fcfc9c903c906ca, 0x527c2929a429558d, 0x145a0a0a280a5022, + 0x7f50b1b1feb1e14f, 0x5dc9a0a0baa0691a, 0xd6146b6bb16b7fda, 0x17d985852e855cab, + 0x673cbdbdcebd8173, 0xba8f5d5d695dd234, 0x2090101040108050, 0xf507f4f4f7f4f303, + 0x8bddcbcb0bcb16c0, 0x7cd33e3ef83eedc6, 0x0a2d050514052811, 0xce78676781671fe6, + 0xd597e4e4b7e47353, 0x4e0227279c2725bb, 0x8273414119413258, 0x0ba78b8b168b2c9d, + 0x53f6a7a7a6a75101, 0xfab27d7de97dcf94, 0x374995956e95dcfb, 0xad56d8d847d88e9f, + 0xeb70fbfbcbfb8b30, 0xc1cdeeee9fee2371, 0xf8bb7c7ced7cc791, 0xcc716666856617e3, + 0xa77bdddd53dda68e, 0x2eaf17175c17b84b, 0x8e45474701470246, 0x211a9e9e429e84dc, + 0x89d4caca0fca1ec5, 0x5a582d2db42d7599, 0x632ebfbfc6bf9179, 0x0e3f07071c07381b, + 0x47acadad8ead0123, 0xb4b05a5a755aea2f, 0x1bef838336836cb5, 0x66b63333cc3385ff, + 0xc65c636391633ff2, 0x041202020802100a, 0x4993aaaa92aa3938, 0xe2de7171d971afa8, + 0x8dc6c8c807c80ecf, 0x32d119196419c87d, 0x923b494939497270, 0xaf5fd9d943d9869a, + 0xf931f2f2eff2c31d, 0xdba8e3e3abe34b48, 0xb6b95b5b715be22a, 0x0dbc88881a883492, + 0x293e9a9a529aa4c8, 0x4c0b262698262dbe, 0x64bf3232c8328dfa, 0x7d59b0b0fab0e94a, + 0xcff2e9e983e91b6a, 0x1e770f0f3c0f7833, 0xb733d5d573d5e6a6, 0x1df480803a8074ba, + 0x6127bebec2be997c, 0x87ebcdcd13cd26de, 0x68893434d034bde4, 0x903248483d487a75, + 0xe354ffffdbffab24, 0xf48d7a7af57af78f, 0x3d6490907a90f4ea, 0xbe9d5f5f615fc23e, + 0x403d202080201da0, 0xd00f6868bd6867d5, 0x34ca1a1a681ad072, 0x41b7aeae82ae192c, + 0x757db4b4eab4c95e, 0xa8ce54544d549a19, 0x3b7f93937693ece5, 0x442f222288220daa, + 0xc86364648d6407e9, 0xff2af1f1e3f1db12, 0xe6cc7373d173bfa2, 0x248212124812905a, + 0x807a40401d403a5d, 0x1048080820084028, 0x9b95c3c32bc356e8, 0xc5dfecec97ec337b, + 0xab4ddbdb4bdb9690, 0x5fc0a1a1bea1611f, 0x07918d8d0e8d1c83, 0x7ac83d3df43df5c9, + 0x335b97976697ccf1, 0x0000000000000000, 0x83f9cfcf1bcf36d4, 0x566e2b2bac2b4587, + 0xece17676c57697b3, 0x19e68282328264b0, 0xb128d6d67fd6fea9, 0x36c31b1b6c1bd877, + 0x7774b5b5eeb5c15b, 0x43beafaf86af1129, 0xd41d6a6ab56a77df, 0xa0ea50505d50ba0d, + 0x8a5745450945124c, 0xfb38f3f3ebf3cb18, 0x60ad3030c0309df0, 0xc3c4efef9bef2b74, + 0x7eda3f3ffc3fe5c3, 0xaac755554955921c, 0x59dba2a2b2a27910, 0xc9e9eaea8fea0365, + 0xca6a656589650fec, 0x6903babad2bab968, 0x5e4a2f2fbc2f6593, 0x9d8ec0c027c04ee7, + 0xa160dede5fdebe81, 0x38fc1c1c701ce06c, 0xe746fdfdd3fdbb2e, 0x9a1f4d4d294d5264, + 0x397692927292e4e0, 0xeafa7575c9758fbc, 0x0c3606061806301e, 0x09ae8a8a128a2498, + 0x794bb2b2f2b2f940, 0xd185e6e6bfe66359, 0x1c7e0e0e380e7036, 0x3ee71f1f7c1ff863, + 0xc4556262956237f7, 0xb53ad4d477d4eea3, 0x4d81a8a89aa82932, 0x315296966296c4f4, + 0xef62f9f9c3f99b3a, 0x97a3c5c533c566f6, 0x4a102525942535b1, 0xb2ab59597959f220, + 0x15d084842a8454ae, 0xe4c57272d572b7a7, 0x72ec3939e439d5dd, 0x98164c4c2d4c5a61, + 0xbc945e5e655eca3b, 0xf09f7878fd78e785, 0x70e53838e038ddd8, 0x05988c8c0a8c1486, + 0xbf17d1d163d1c6b2, 0x57e4a5a5aea5410b, 0xd9a1e2e2afe2434d, 0xc24e616199612ff8, + 0x7b42b3b3f6b3f145, 0x42342121842115a5, 0x25089c9c4a9c94d6, 0x3cee1e1e781ef066, + 0x8661434311432252, 0x93b1c7c73bc776fc, 0xe54ffcfcd7fcb32b, 0x0824040410042014, + 0xa2e351515951b208, 0x2f2599995e99bcc7, 0xda226d6da96d4fc4, 0x1a650d0d340d6839, + 0xe979fafacffa8335, 0xa369dfdf5bdfb684, 0xfca97e7ee57ed79b, 0x4819242490243db4, + 0x76fe3b3bec3bc5d7, 0x4b9aabab96ab313d, 0x81f0cece1fce3ed1, 0x2299111144118855, + 0x03838f8f068f0c89, 0x9c044e4e254e4a6b, 0x7366b7b7e6b7d151, 0xcbe0ebeb8beb0b60, + 0x78c13c3cf03cfdcc, 0x1ffd81813e817cbf, 0x354094946a94d4fe, 0xf31cf7f7fbf7eb0c, + 0x6f18b9b9deb9a167, 0x268b13134c13985f, 0x58512c2cb02c7d9c, 0xbb05d3d36bd3d6b8, + 0xd38ce7e7bbe76b5c, 0xdc396e6ea56e57cb, 0x95aac4c437c46ef3, 0x061b03030c03180f, + 0xacdc565645568a13, 0x885e44440d441a49, 0xfea07f7fe17fdf9e, 0x4f88a9a99ea92137, + 0x54672a2aa82a4d82, 0x6b0abbbbd6bbb16d, 0x9f87c1c123c146e2, 0xa6f153535153a202, + 0xa572dcdc57dcae8b, 0x16530b0b2c0b5827, 0x27019d9d4e9d9cd3, 0xd82b6c6cad6c47c1, + 0x62a43131c43195f5, 0xe8f37474cd7487b9, 0xf115f6f6fff6e309, 0x8c4c464605460a43, + 0x45a5acac8aac0926, 0x0fb589891e893c97, 0x28b414145014a044, 0xdfbae1e1a3e15b42, + 0x2ca616165816b04e, 0x74f73a3ae83acdd2, 0xd2066969b9696fd0, 0x124109092409482d, + 0xe0d77070dd70a7ad, 0x716fb6b6e2b6d954, 0xbd1ed0d067d0ceb7, 0xc7d6eded93ed3b7e, + 0x85e2cccc17cc2edb, 0x8468424215422a57, 0x2d2c98985a98b4c2, 0x55eda4a4aaa4490e, + 0x50752828a0285d88, 0xb8865c5c6d5cda31, 0xed6bf8f8c7f8933f, 0x11c28686228644a4, +} + +C3 := [256]u64 { + 0x7830d818186018c0, 0xaf462623238c2305, 0xf991b8c6c63fc67e, 0x6fcdfbe8e887e813, + 0xa113cb878726874c, 0x626d11b8b8dab8a9, 0x0502090101040108, 0x6e9e0d4f4f214f42, + 0xee6c9b3636d836ad, 0x0451ffa6a6a2a659, 0xbdb90cd2d26fd2de, 0x06f70ef5f5f3f5fb, + 0x80f2967979f979ef, 0xcede306f6fa16f5f, 0xef3f6d91917e91fc, 0x07a4f852525552aa, + 0xfdc04760609d6027, 0x766535bcbccabc89, 0xcd2b379b9b569bac, 0x8c018a8e8e028e04, + 0x155bd2a3a3b6a371, 0x3c186c0c0c300c60, 0x8af6847b7bf17bff, 0xe16a803535d435b5, + 0x693af51d1d741de8, 0x47ddb3e0e0a7e053, 0xacb321d7d77bd7f6, 0xed999cc2c22fc25e, + 0x965c432e2eb82e6d, 0x7a96294b4b314b62, 0x21e15dfefedffea3, 0x16aed55757415782, + 0x412abd15155415a8, 0xb6eee87777c1779f, 0xeb6e923737dc37a5, 0x56d79ee5e5b3e57b, + 0xd923139f9f469f8c, 0x17fd23f0f0e7f0d3, 0x7f94204a4a354a6a, 0x95a944dada4fda9e, + 0x25b0a258587d58fa, 0xca8fcfc9c903c906, 0x8d527c2929a42955, 0x22145a0a0a280a50, + 0x4f7f50b1b1feb1e1, 0x1a5dc9a0a0baa069, 0xdad6146b6bb16b7f, 0xab17d985852e855c, + 0x73673cbdbdcebd81, 0x34ba8f5d5d695dd2, 0x5020901010401080, 0x03f507f4f4f7f4f3, + 0xc08bddcbcb0bcb16, 0xc67cd33e3ef83eed, 0x110a2d0505140528, 0xe6ce78676781671f, + 0x53d597e4e4b7e473, 0xbb4e0227279c2725, 0x5882734141194132, 0x9d0ba78b8b168b2c, + 0x0153f6a7a7a6a751, 0x94fab27d7de97dcf, 0xfb374995956e95dc, 0x9fad56d8d847d88e, + 0x30eb70fbfbcbfb8b, 0x71c1cdeeee9fee23, 0x91f8bb7c7ced7cc7, 0xe3cc716666856617, + 0x8ea77bdddd53dda6, 0x4b2eaf17175c17b8, 0x468e454747014702, 0xdc211a9e9e429e84, + 0xc589d4caca0fca1e, 0x995a582d2db42d75, 0x79632ebfbfc6bf91, 0x1b0e3f07071c0738, + 0x2347acadad8ead01, 0x2fb4b05a5a755aea, 0xb51bef838336836c, 0xff66b63333cc3385, + 0xf2c65c636391633f, 0x0a04120202080210, 0x384993aaaa92aa39, 0xa8e2de7171d971af, + 0xcf8dc6c8c807c80e, 0x7d32d119196419c8, 0x70923b4949394972, 0x9aaf5fd9d943d986, + 0x1df931f2f2eff2c3, 0x48dba8e3e3abe34b, 0x2ab6b95b5b715be2, 0x920dbc88881a8834, + 0xc8293e9a9a529aa4, 0xbe4c0b262698262d, 0xfa64bf3232c8328d, 0x4a7d59b0b0fab0e9, + 0x6acff2e9e983e91b, 0x331e770f0f3c0f78, 0xa6b733d5d573d5e6, 0xba1df480803a8074, + 0x7c6127bebec2be99, 0xde87ebcdcd13cd26, 0xe468893434d034bd, 0x75903248483d487a, + 0x24e354ffffdbffab, 0x8ff48d7a7af57af7, 0xea3d6490907a90f4, 0x3ebe9d5f5f615fc2, + 0xa0403d202080201d, 0xd5d00f6868bd6867, 0x7234ca1a1a681ad0, 0x2c41b7aeae82ae19, + 0x5e757db4b4eab4c9, 0x19a8ce54544d549a, 0xe53b7f93937693ec, 0xaa442f222288220d, + 0xe9c86364648d6407, 0x12ff2af1f1e3f1db, 0xa2e6cc7373d173bf, 0x5a24821212481290, + 0x5d807a40401d403a, 0x2810480808200840, 0xe89b95c3c32bc356, 0x7bc5dfecec97ec33, + 0x90ab4ddbdb4bdb96, 0x1f5fc0a1a1bea161, 0x8307918d8d0e8d1c, 0xc97ac83d3df43df5, + 0xf1335b97976697cc, 0x0000000000000000, 0xd483f9cfcf1bcf36, 0x87566e2b2bac2b45, + 0xb3ece17676c57697, 0xb019e68282328264, 0xa9b128d6d67fd6fe, 0x7736c31b1b6c1bd8, + 0x5b7774b5b5eeb5c1, 0x2943beafaf86af11, 0xdfd41d6a6ab56a77, 0x0da0ea50505d50ba, + 0x4c8a574545094512, 0x18fb38f3f3ebf3cb, 0xf060ad3030c0309d, 0x74c3c4efef9bef2b, + 0xc37eda3f3ffc3fe5, 0x1caac75555495592, 0x1059dba2a2b2a279, 0x65c9e9eaea8fea03, + 0xecca6a656589650f, 0x686903babad2bab9, 0x935e4a2f2fbc2f65, 0xe79d8ec0c027c04e, + 0x81a160dede5fdebe, 0x6c38fc1c1c701ce0, 0x2ee746fdfdd3fdbb, 0x649a1f4d4d294d52, + 0xe0397692927292e4, 0xbceafa7575c9758f, 0x1e0c360606180630, 0x9809ae8a8a128a24, + 0x40794bb2b2f2b2f9, 0x59d185e6e6bfe663, 0x361c7e0e0e380e70, 0x633ee71f1f7c1ff8, + 0xf7c4556262956237, 0xa3b53ad4d477d4ee, 0x324d81a8a89aa829, 0xf4315296966296c4, + 0x3aef62f9f9c3f99b, 0xf697a3c5c533c566, 0xb14a102525942535, 0x20b2ab59597959f2, + 0xae15d084842a8454, 0xa7e4c57272d572b7, 0xdd72ec3939e439d5, 0x6198164c4c2d4c5a, + 0x3bbc945e5e655eca, 0x85f09f7878fd78e7, 0xd870e53838e038dd, 0x8605988c8c0a8c14, + 0xb2bf17d1d163d1c6, 0x0b57e4a5a5aea541, 0x4dd9a1e2e2afe243, 0xf8c24e616199612f, + 0x457b42b3b3f6b3f1, 0xa542342121842115, 0xd625089c9c4a9c94, 0x663cee1e1e781ef0, + 0x5286614343114322, 0xfc93b1c7c73bc776, 0x2be54ffcfcd7fcb3, 0x1408240404100420, + 0x08a2e351515951b2, 0xc72f2599995e99bc, 0xc4da226d6da96d4f, 0x391a650d0d340d68, + 0x35e979fafacffa83, 0x84a369dfdf5bdfb6, 0x9bfca97e7ee57ed7, 0xb44819242490243d, + 0xd776fe3b3bec3bc5, 0x3d4b9aabab96ab31, 0xd181f0cece1fce3e, 0x5522991111441188, + 0x8903838f8f068f0c, 0x6b9c044e4e254e4a, 0x517366b7b7e6b7d1, 0x60cbe0ebeb8beb0b, + 0xcc78c13c3cf03cfd, 0xbf1ffd81813e817c, 0xfe354094946a94d4, 0x0cf31cf7f7fbf7eb, + 0x676f18b9b9deb9a1, 0x5f268b13134c1398, 0x9c58512c2cb02c7d, 0xb8bb05d3d36bd3d6, + 0x5cd38ce7e7bbe76b, 0xcbdc396e6ea56e57, 0xf395aac4c437c46e, 0x0f061b03030c0318, + 0x13acdc565645568a, 0x49885e44440d441a, 0x9efea07f7fe17fdf, 0x374f88a9a99ea921, + 0x8254672a2aa82a4d, 0x6d6b0abbbbd6bbb1, 0xe29f87c1c123c146, 0x02a6f153535153a2, + 0x8ba572dcdc57dcae, 0x2716530b0b2c0b58, 0xd327019d9d4e9d9c, 0xc1d82b6c6cad6c47, + 0xf562a43131c43195, 0xb9e8f37474cd7487, 0x09f115f6f6fff6e3, 0x438c4c464605460a, + 0x2645a5acac8aac09, 0x970fb589891e893c, 0x4428b414145014a0, 0x42dfbae1e1a3e15b, + 0x4e2ca616165816b0, 0xd274f73a3ae83acd, 0xd0d2066969b9696f, 0x2d12410909240948, + 0xade0d77070dd70a7, 0x54716fb6b6e2b6d9, 0xb7bd1ed0d067d0ce, 0x7ec7d6eded93ed3b, + 0xdb85e2cccc17cc2e, 0x578468424215422a, 0xc22d2c98985a98b4, 0x0e55eda4a4aaa449, + 0x8850752828a0285d, 0x31b8865c5c6d5cda, 0x3fed6bf8f8c7f893, 0xa411c28686228644, +} + +C4 := [256]u64 { + 0xc07830d818186018, 0x05af462623238c23, 0x7ef991b8c6c63fc6, 0x136fcdfbe8e887e8, + 0x4ca113cb87872687, 0xa9626d11b8b8dab8, 0x0805020901010401, 0x426e9e0d4f4f214f, + 0xadee6c9b3636d836, 0x590451ffa6a6a2a6, 0xdebdb90cd2d26fd2, 0xfb06f70ef5f5f3f5, + 0xef80f2967979f979, 0x5fcede306f6fa16f, 0xfcef3f6d91917e91, 0xaa07a4f852525552, + 0x27fdc04760609d60, 0x89766535bcbccabc, 0xaccd2b379b9b569b, 0x048c018a8e8e028e, + 0x71155bd2a3a3b6a3, 0x603c186c0c0c300c, 0xff8af6847b7bf17b, 0xb5e16a803535d435, + 0xe8693af51d1d741d, 0x5347ddb3e0e0a7e0, 0xf6acb321d7d77bd7, 0x5eed999cc2c22fc2, + 0x6d965c432e2eb82e, 0x627a96294b4b314b, 0xa321e15dfefedffe, 0x8216aed557574157, + 0xa8412abd15155415, 0x9fb6eee87777c177, 0xa5eb6e923737dc37, 0x7b56d79ee5e5b3e5, + 0x8cd923139f9f469f, 0xd317fd23f0f0e7f0, 0x6a7f94204a4a354a, 0x9e95a944dada4fda, + 0xfa25b0a258587d58, 0x06ca8fcfc9c903c9, 0x558d527c2929a429, 0x5022145a0a0a280a, + 0xe14f7f50b1b1feb1, 0x691a5dc9a0a0baa0, 0x7fdad6146b6bb16b, 0x5cab17d985852e85, + 0x8173673cbdbdcebd, 0xd234ba8f5d5d695d, 0x8050209010104010, 0xf303f507f4f4f7f4, + 0x16c08bddcbcb0bcb, 0xedc67cd33e3ef83e, 0x28110a2d05051405, 0x1fe6ce7867678167, + 0x7353d597e4e4b7e4, 0x25bb4e0227279c27, 0x3258827341411941, 0x2c9d0ba78b8b168b, + 0x510153f6a7a7a6a7, 0xcf94fab27d7de97d, 0xdcfb374995956e95, 0x8e9fad56d8d847d8, + 0x8b30eb70fbfbcbfb, 0x2371c1cdeeee9fee, 0xc791f8bb7c7ced7c, 0x17e3cc7166668566, + 0xa68ea77bdddd53dd, 0xb84b2eaf17175c17, 0x02468e4547470147, 0x84dc211a9e9e429e, + 0x1ec589d4caca0fca, 0x75995a582d2db42d, 0x9179632ebfbfc6bf, 0x381b0e3f07071c07, + 0x012347acadad8ead, 0xea2fb4b05a5a755a, 0x6cb51bef83833683, 0x85ff66b63333cc33, + 0x3ff2c65c63639163, 0x100a041202020802, 0x39384993aaaa92aa, 0xafa8e2de7171d971, + 0x0ecf8dc6c8c807c8, 0xc87d32d119196419, 0x7270923b49493949, 0x869aaf5fd9d943d9, + 0xc31df931f2f2eff2, 0x4b48dba8e3e3abe3, 0xe22ab6b95b5b715b, 0x34920dbc88881a88, + 0xa4c8293e9a9a529a, 0x2dbe4c0b26269826, 0x8dfa64bf3232c832, 0xe94a7d59b0b0fab0, + 0x1b6acff2e9e983e9, 0x78331e770f0f3c0f, 0xe6a6b733d5d573d5, 0x74ba1df480803a80, + 0x997c6127bebec2be, 0x26de87ebcdcd13cd, 0xbde468893434d034, 0x7a75903248483d48, + 0xab24e354ffffdbff, 0xf78ff48d7a7af57a, 0xf4ea3d6490907a90, 0xc23ebe9d5f5f615f, + 0x1da0403d20208020, 0x67d5d00f6868bd68, 0xd07234ca1a1a681a, 0x192c41b7aeae82ae, + 0xc95e757db4b4eab4, 0x9a19a8ce54544d54, 0xece53b7f93937693, 0x0daa442f22228822, + 0x07e9c86364648d64, 0xdb12ff2af1f1e3f1, 0xbfa2e6cc7373d173, 0x905a248212124812, + 0x3a5d807a40401d40, 0x4028104808082008, 0x56e89b95c3c32bc3, 0x337bc5dfecec97ec, + 0x9690ab4ddbdb4bdb, 0x611f5fc0a1a1bea1, 0x1c8307918d8d0e8d, 0xf5c97ac83d3df43d, + 0xccf1335b97976697, 0x0000000000000000, 0x36d483f9cfcf1bcf, 0x4587566e2b2bac2b, + 0x97b3ece17676c576, 0x64b019e682823282, 0xfea9b128d6d67fd6, 0xd87736c31b1b6c1b, + 0xc15b7774b5b5eeb5, 0x112943beafaf86af, 0x77dfd41d6a6ab56a, 0xba0da0ea50505d50, + 0x124c8a5745450945, 0xcb18fb38f3f3ebf3, 0x9df060ad3030c030, 0x2b74c3c4efef9bef, + 0xe5c37eda3f3ffc3f, 0x921caac755554955, 0x791059dba2a2b2a2, 0x0365c9e9eaea8fea, + 0x0fecca6a65658965, 0xb9686903babad2ba, 0x65935e4a2f2fbc2f, 0x4ee79d8ec0c027c0, + 0xbe81a160dede5fde, 0xe06c38fc1c1c701c, 0xbb2ee746fdfdd3fd, 0x52649a1f4d4d294d, + 0xe4e0397692927292, 0x8fbceafa7575c975, 0x301e0c3606061806, 0x249809ae8a8a128a, + 0xf940794bb2b2f2b2, 0x6359d185e6e6bfe6, 0x70361c7e0e0e380e, 0xf8633ee71f1f7c1f, + 0x37f7c45562629562, 0xeea3b53ad4d477d4, 0x29324d81a8a89aa8, 0xc4f4315296966296, + 0x9b3aef62f9f9c3f9, 0x66f697a3c5c533c5, 0x35b14a1025259425, 0xf220b2ab59597959, + 0x54ae15d084842a84, 0xb7a7e4c57272d572, 0xd5dd72ec3939e439, 0x5a6198164c4c2d4c, + 0xca3bbc945e5e655e, 0xe785f09f7878fd78, 0xddd870e53838e038, 0x148605988c8c0a8c, + 0xc6b2bf17d1d163d1, 0x410b57e4a5a5aea5, 0x434dd9a1e2e2afe2, 0x2ff8c24e61619961, + 0xf1457b42b3b3f6b3, 0x15a5423421218421, 0x94d625089c9c4a9c, 0xf0663cee1e1e781e, + 0x2252866143431143, 0x76fc93b1c7c73bc7, 0xb32be54ffcfcd7fc, 0x2014082404041004, + 0xb208a2e351515951, 0xbcc72f2599995e99, 0x4fc4da226d6da96d, 0x68391a650d0d340d, + 0x8335e979fafacffa, 0xb684a369dfdf5bdf, 0xd79bfca97e7ee57e, 0x3db4481924249024, + 0xc5d776fe3b3bec3b, 0x313d4b9aabab96ab, 0x3ed181f0cece1fce, 0x8855229911114411, + 0x0c8903838f8f068f, 0x4a6b9c044e4e254e, 0xd1517366b7b7e6b7, 0x0b60cbe0ebeb8beb, + 0xfdcc78c13c3cf03c, 0x7cbf1ffd81813e81, 0xd4fe354094946a94, 0xeb0cf31cf7f7fbf7, + 0xa1676f18b9b9deb9, 0x985f268b13134c13, 0x7d9c58512c2cb02c, 0xd6b8bb05d3d36bd3, + 0x6b5cd38ce7e7bbe7, 0x57cbdc396e6ea56e, 0x6ef395aac4c437c4, 0x180f061b03030c03, + 0x8a13acdc56564556, 0x1a49885e44440d44, 0xdf9efea07f7fe17f, 0x21374f88a9a99ea9, + 0x4d8254672a2aa82a, 0xb16d6b0abbbbd6bb, 0x46e29f87c1c123c1, 0xa202a6f153535153, + 0xae8ba572dcdc57dc, 0x582716530b0b2c0b, 0x9cd327019d9d4e9d, 0x47c1d82b6c6cad6c, + 0x95f562a43131c431, 0x87b9e8f37474cd74, 0xe309f115f6f6fff6, 0x0a438c4c46460546, + 0x092645a5acac8aac, 0x3c970fb589891e89, 0xa04428b414145014, 0x5b42dfbae1e1a3e1, + 0xb04e2ca616165816, 0xcdd274f73a3ae83a, 0x6fd0d2066969b969, 0x482d124109092409, + 0xa7ade0d77070dd70, 0xd954716fb6b6e2b6, 0xceb7bd1ed0d067d0, 0x3b7ec7d6eded93ed, + 0x2edb85e2cccc17cc, 0x2a57846842421542, 0xb4c22d2c98985a98, 0x490e55eda4a4aaa4, + 0x5d8850752828a028, 0xda31b8865c5c6d5c, 0x933fed6bf8f8c7f8, 0x44a411c286862286, +} + +C5 := [256]u64 { + 0x18c07830d8181860, 0x2305af462623238c, 0xc67ef991b8c6c63f, 0xe8136fcdfbe8e887, + 0x874ca113cb878726, 0xb8a9626d11b8b8da, 0x0108050209010104, 0x4f426e9e0d4f4f21, + 0x36adee6c9b3636d8, 0xa6590451ffa6a6a2, 0xd2debdb90cd2d26f, 0xf5fb06f70ef5f5f3, + 0x79ef80f2967979f9, 0x6f5fcede306f6fa1, 0x91fcef3f6d91917e, 0x52aa07a4f8525255, + 0x6027fdc04760609d, 0xbc89766535bcbcca, 0x9baccd2b379b9b56, 0x8e048c018a8e8e02, + 0xa371155bd2a3a3b6, 0x0c603c186c0c0c30, 0x7bff8af6847b7bf1, 0x35b5e16a803535d4, + 0x1de8693af51d1d74, 0xe05347ddb3e0e0a7, 0xd7f6acb321d7d77b, 0xc25eed999cc2c22f, + 0x2e6d965c432e2eb8, 0x4b627a96294b4b31, 0xfea321e15dfefedf, 0x578216aed5575741, + 0x15a8412abd151554, 0x779fb6eee87777c1, 0x37a5eb6e923737dc, 0xe57b56d79ee5e5b3, + 0x9f8cd923139f9f46, 0xf0d317fd23f0f0e7, 0x4a6a7f94204a4a35, 0xda9e95a944dada4f, + 0x58fa25b0a258587d, 0xc906ca8fcfc9c903, 0x29558d527c2929a4, 0x0a5022145a0a0a28, + 0xb1e14f7f50b1b1fe, 0xa0691a5dc9a0a0ba, 0x6b7fdad6146b6bb1, 0x855cab17d985852e, + 0xbd8173673cbdbdce, 0x5dd234ba8f5d5d69, 0x1080502090101040, 0xf4f303f507f4f4f7, + 0xcb16c08bddcbcb0b, 0x3eedc67cd33e3ef8, 0x0528110a2d050514, 0x671fe6ce78676781, + 0xe47353d597e4e4b7, 0x2725bb4e0227279c, 0x4132588273414119, 0x8b2c9d0ba78b8b16, + 0xa7510153f6a7a7a6, 0x7dcf94fab27d7de9, 0x95dcfb374995956e, 0xd88e9fad56d8d847, + 0xfb8b30eb70fbfbcb, 0xee2371c1cdeeee9f, 0x7cc791f8bb7c7ced, 0x6617e3cc71666685, + 0xdda68ea77bdddd53, 0x17b84b2eaf17175c, 0x4702468e45474701, 0x9e84dc211a9e9e42, + 0xca1ec589d4caca0f, 0x2d75995a582d2db4, 0xbf9179632ebfbfc6, 0x07381b0e3f07071c, + 0xad012347acadad8e, 0x5aea2fb4b05a5a75, 0x836cb51bef838336, 0x3385ff66b63333cc, + 0x633ff2c65c636391, 0x02100a0412020208, 0xaa39384993aaaa92, 0x71afa8e2de7171d9, + 0xc80ecf8dc6c8c807, 0x19c87d32d1191964, 0x497270923b494939, 0xd9869aaf5fd9d943, + 0xf2c31df931f2f2ef, 0xe34b48dba8e3e3ab, 0x5be22ab6b95b5b71, 0x8834920dbc88881a, + 0x9aa4c8293e9a9a52, 0x262dbe4c0b262698, 0x328dfa64bf3232c8, 0xb0e94a7d59b0b0fa, + 0xe91b6acff2e9e983, 0x0f78331e770f0f3c, 0xd5e6a6b733d5d573, 0x8074ba1df480803a, + 0xbe997c6127bebec2, 0xcd26de87ebcdcd13, 0x34bde468893434d0, 0x487a75903248483d, + 0xffab24e354ffffdb, 0x7af78ff48d7a7af5, 0x90f4ea3d6490907a, 0x5fc23ebe9d5f5f61, + 0x201da0403d202080, 0x6867d5d00f6868bd, 0x1ad07234ca1a1a68, 0xae192c41b7aeae82, + 0xb4c95e757db4b4ea, 0x549a19a8ce54544d, 0x93ece53b7f939376, 0x220daa442f222288, + 0x6407e9c86364648d, 0xf1db12ff2af1f1e3, 0x73bfa2e6cc7373d1, 0x12905a2482121248, + 0x403a5d807a40401d, 0x0840281048080820, 0xc356e89b95c3c32b, 0xec337bc5dfecec97, + 0xdb9690ab4ddbdb4b, 0xa1611f5fc0a1a1be, 0x8d1c8307918d8d0e, 0x3df5c97ac83d3df4, + 0x97ccf1335b979766, 0x0000000000000000, 0xcf36d483f9cfcf1b, 0x2b4587566e2b2bac, + 0x7697b3ece17676c5, 0x8264b019e6828232, 0xd6fea9b128d6d67f, 0x1bd87736c31b1b6c, + 0xb5c15b7774b5b5ee, 0xaf112943beafaf86, 0x6a77dfd41d6a6ab5, 0x50ba0da0ea50505d, + 0x45124c8a57454509, 0xf3cb18fb38f3f3eb, 0x309df060ad3030c0, 0xef2b74c3c4efef9b, + 0x3fe5c37eda3f3ffc, 0x55921caac7555549, 0xa2791059dba2a2b2, 0xea0365c9e9eaea8f, + 0x650fecca6a656589, 0xbab9686903babad2, 0x2f65935e4a2f2fbc, 0xc04ee79d8ec0c027, + 0xdebe81a160dede5f, 0x1ce06c38fc1c1c70, 0xfdbb2ee746fdfdd3, 0x4d52649a1f4d4d29, + 0x92e4e03976929272, 0x758fbceafa7575c9, 0x06301e0c36060618, 0x8a249809ae8a8a12, + 0xb2f940794bb2b2f2, 0xe66359d185e6e6bf, 0x0e70361c7e0e0e38, 0x1ff8633ee71f1f7c, + 0x6237f7c455626295, 0xd4eea3b53ad4d477, 0xa829324d81a8a89a, 0x96c4f43152969662, + 0xf99b3aef62f9f9c3, 0xc566f697a3c5c533, 0x2535b14a10252594, 0x59f220b2ab595979, + 0x8454ae15d084842a, 0x72b7a7e4c57272d5, 0x39d5dd72ec3939e4, 0x4c5a6198164c4c2d, + 0x5eca3bbc945e5e65, 0x78e785f09f7878fd, 0x38ddd870e53838e0, 0x8c148605988c8c0a, + 0xd1c6b2bf17d1d163, 0xa5410b57e4a5a5ae, 0xe2434dd9a1e2e2af, 0x612ff8c24e616199, + 0xb3f1457b42b3b3f6, 0x2115a54234212184, 0x9c94d625089c9c4a, 0x1ef0663cee1e1e78, + 0x4322528661434311, 0xc776fc93b1c7c73b, 0xfcb32be54ffcfcd7, 0x0420140824040410, + 0x51b208a2e3515159, 0x99bcc72f2599995e, 0x6d4fc4da226d6da9, 0x0d68391a650d0d34, + 0xfa8335e979fafacf, 0xdfb684a369dfdf5b, 0x7ed79bfca97e7ee5, 0x243db44819242490, + 0x3bc5d776fe3b3bec, 0xab313d4b9aabab96, 0xce3ed181f0cece1f, 0x1188552299111144, + 0x8f0c8903838f8f06, 0x4e4a6b9c044e4e25, 0xb7d1517366b7b7e6, 0xeb0b60cbe0ebeb8b, + 0x3cfdcc78c13c3cf0, 0x817cbf1ffd81813e, 0x94d4fe354094946a, 0xf7eb0cf31cf7f7fb, + 0xb9a1676f18b9b9de, 0x13985f268b13134c, 0x2c7d9c58512c2cb0, 0xd3d6b8bb05d3d36b, + 0xe76b5cd38ce7e7bb, 0x6e57cbdc396e6ea5, 0xc46ef395aac4c437, 0x03180f061b03030c, + 0x568a13acdc565645, 0x441a49885e44440d, 0x7fdf9efea07f7fe1, 0xa921374f88a9a99e, + 0x2a4d8254672a2aa8, 0xbbb16d6b0abbbbd6, 0xc146e29f87c1c123, 0x53a202a6f1535351, + 0xdcae8ba572dcdc57, 0x0b582716530b0b2c, 0x9d9cd327019d9d4e, 0x6c47c1d82b6c6cad, + 0x3195f562a43131c4, 0x7487b9e8f37474cd, 0xf6e309f115f6f6ff, 0x460a438c4c464605, + 0xac092645a5acac8a, 0x893c970fb589891e, 0x14a04428b4141450, 0xe15b42dfbae1e1a3, + 0x16b04e2ca6161658, 0x3acdd274f73a3ae8, 0x696fd0d2066969b9, 0x09482d1241090924, + 0x70a7ade0d77070dd, 0xb6d954716fb6b6e2, 0xd0ceb7bd1ed0d067, 0xed3b7ec7d6eded93, + 0xcc2edb85e2cccc17, 0x422a578468424215, 0x98b4c22d2c98985a, 0xa4490e55eda4a4aa, + 0x285d8850752828a0, 0x5cda31b8865c5c6d, 0xf8933fed6bf8f8c7, 0x8644a411c2868622, +} + +C6 := [256]u64 { + 0x6018c07830d81818, 0x8c2305af46262323, 0x3fc67ef991b8c6c6, 0x87e8136fcdfbe8e8, + 0x26874ca113cb8787, 0xdab8a9626d11b8b8, 0x0401080502090101, 0x214f426e9e0d4f4f, + 0xd836adee6c9b3636, 0xa2a6590451ffa6a6, 0x6fd2debdb90cd2d2, 0xf3f5fb06f70ef5f5, + 0xf979ef80f2967979, 0xa16f5fcede306f6f, 0x7e91fcef3f6d9191, 0x5552aa07a4f85252, + 0x9d6027fdc0476060, 0xcabc89766535bcbc, 0x569baccd2b379b9b, 0x028e048c018a8e8e, + 0xb6a371155bd2a3a3, 0x300c603c186c0c0c, 0xf17bff8af6847b7b, 0xd435b5e16a803535, + 0x741de8693af51d1d, 0xa7e05347ddb3e0e0, 0x7bd7f6acb321d7d7, 0x2fc25eed999cc2c2, + 0xb82e6d965c432e2e, 0x314b627a96294b4b, 0xdffea321e15dfefe, 0x41578216aed55757, + 0x5415a8412abd1515, 0xc1779fb6eee87777, 0xdc37a5eb6e923737, 0xb3e57b56d79ee5e5, + 0x469f8cd923139f9f, 0xe7f0d317fd23f0f0, 0x354a6a7f94204a4a, 0x4fda9e95a944dada, + 0x7d58fa25b0a25858, 0x03c906ca8fcfc9c9, 0xa429558d527c2929, 0x280a5022145a0a0a, + 0xfeb1e14f7f50b1b1, 0xbaa0691a5dc9a0a0, 0xb16b7fdad6146b6b, 0x2e855cab17d98585, + 0xcebd8173673cbdbd, 0x695dd234ba8f5d5d, 0x4010805020901010, 0xf7f4f303f507f4f4, + 0x0bcb16c08bddcbcb, 0xf83eedc67cd33e3e, 0x140528110a2d0505, 0x81671fe6ce786767, + 0xb7e47353d597e4e4, 0x9c2725bb4e022727, 0x1941325882734141, 0x168b2c9d0ba78b8b, + 0xa6a7510153f6a7a7, 0xe97dcf94fab27d7d, 0x6e95dcfb37499595, 0x47d88e9fad56d8d8, + 0xcbfb8b30eb70fbfb, 0x9fee2371c1cdeeee, 0xed7cc791f8bb7c7c, 0x856617e3cc716666, + 0x53dda68ea77bdddd, 0x5c17b84b2eaf1717, 0x014702468e454747, 0x429e84dc211a9e9e, + 0x0fca1ec589d4caca, 0xb42d75995a582d2d, 0xc6bf9179632ebfbf, 0x1c07381b0e3f0707, + 0x8ead012347acadad, 0x755aea2fb4b05a5a, 0x36836cb51bef8383, 0xcc3385ff66b63333, + 0x91633ff2c65c6363, 0x0802100a04120202, 0x92aa39384993aaaa, 0xd971afa8e2de7171, + 0x07c80ecf8dc6c8c8, 0x6419c87d32d11919, 0x39497270923b4949, 0x43d9869aaf5fd9d9, + 0xeff2c31df931f2f2, 0xabe34b48dba8e3e3, 0x715be22ab6b95b5b, 0x1a8834920dbc8888, + 0x529aa4c8293e9a9a, 0x98262dbe4c0b2626, 0xc8328dfa64bf3232, 0xfab0e94a7d59b0b0, + 0x83e91b6acff2e9e9, 0x3c0f78331e770f0f, 0x73d5e6a6b733d5d5, 0x3a8074ba1df48080, + 0xc2be997c6127bebe, 0x13cd26de87ebcdcd, 0xd034bde468893434, 0x3d487a7590324848, + 0xdbffab24e354ffff, 0xf57af78ff48d7a7a, 0x7a90f4ea3d649090, 0x615fc23ebe9d5f5f, + 0x80201da0403d2020, 0xbd6867d5d00f6868, 0x681ad07234ca1a1a, 0x82ae192c41b7aeae, + 0xeab4c95e757db4b4, 0x4d549a19a8ce5454, 0x7693ece53b7f9393, 0x88220daa442f2222, + 0x8d6407e9c8636464, 0xe3f1db12ff2af1f1, 0xd173bfa2e6cc7373, 0x4812905a24821212, + 0x1d403a5d807a4040, 0x2008402810480808, 0x2bc356e89b95c3c3, 0x97ec337bc5dfecec, + 0x4bdb9690ab4ddbdb, 0xbea1611f5fc0a1a1, 0x0e8d1c8307918d8d, 0xf43df5c97ac83d3d, + 0x6697ccf1335b9797, 0x0000000000000000, 0x1bcf36d483f9cfcf, 0xac2b4587566e2b2b, + 0xc57697b3ece17676, 0x328264b019e68282, 0x7fd6fea9b128d6d6, 0x6c1bd87736c31b1b, + 0xeeb5c15b7774b5b5, 0x86af112943beafaf, 0xb56a77dfd41d6a6a, 0x5d50ba0da0ea5050, + 0x0945124c8a574545, 0xebf3cb18fb38f3f3, 0xc0309df060ad3030, 0x9bef2b74c3c4efef, + 0xfc3fe5c37eda3f3f, 0x4955921caac75555, 0xb2a2791059dba2a2, 0x8fea0365c9e9eaea, + 0x89650fecca6a6565, 0xd2bab9686903baba, 0xbc2f65935e4a2f2f, 0x27c04ee79d8ec0c0, + 0x5fdebe81a160dede, 0x701ce06c38fc1c1c, 0xd3fdbb2ee746fdfd, 0x294d52649a1f4d4d, + 0x7292e4e039769292, 0xc9758fbceafa7575, 0x1806301e0c360606, 0x128a249809ae8a8a, + 0xf2b2f940794bb2b2, 0xbfe66359d185e6e6, 0x380e70361c7e0e0e, 0x7c1ff8633ee71f1f, + 0x956237f7c4556262, 0x77d4eea3b53ad4d4, 0x9aa829324d81a8a8, 0x6296c4f431529696, + 0xc3f99b3aef62f9f9, 0x33c566f697a3c5c5, 0x942535b14a102525, 0x7959f220b2ab5959, + 0x2a8454ae15d08484, 0xd572b7a7e4c57272, 0xe439d5dd72ec3939, 0x2d4c5a6198164c4c, + 0x655eca3bbc945e5e, 0xfd78e785f09f7878, 0xe038ddd870e53838, 0x0a8c148605988c8c, + 0x63d1c6b2bf17d1d1, 0xaea5410b57e4a5a5, 0xafe2434dd9a1e2e2, 0x99612ff8c24e6161, + 0xf6b3f1457b42b3b3, 0x842115a542342121, 0x4a9c94d625089c9c, 0x781ef0663cee1e1e, + 0x1143225286614343, 0x3bc776fc93b1c7c7, 0xd7fcb32be54ffcfc, 0x1004201408240404, + 0x5951b208a2e35151, 0x5e99bcc72f259999, 0xa96d4fc4da226d6d, 0x340d68391a650d0d, + 0xcffa8335e979fafa, 0x5bdfb684a369dfdf, 0xe57ed79bfca97e7e, 0x90243db448192424, + 0xec3bc5d776fe3b3b, 0x96ab313d4b9aabab, 0x1fce3ed181f0cece, 0x4411885522991111, + 0x068f0c8903838f8f, 0x254e4a6b9c044e4e, 0xe6b7d1517366b7b7, 0x8beb0b60cbe0ebeb, + 0xf03cfdcc78c13c3c, 0x3e817cbf1ffd8181, 0x6a94d4fe35409494, 0xfbf7eb0cf31cf7f7, + 0xdeb9a1676f18b9b9, 0x4c13985f268b1313, 0xb02c7d9c58512c2c, 0x6bd3d6b8bb05d3d3, + 0xbbe76b5cd38ce7e7, 0xa56e57cbdc396e6e, 0x37c46ef395aac4c4, 0x0c03180f061b0303, + 0x45568a13acdc5656, 0x0d441a49885e4444, 0xe17fdf9efea07f7f, 0x9ea921374f88a9a9, + 0xa82a4d8254672a2a, 0xd6bbb16d6b0abbbb, 0x23c146e29f87c1c1, 0x5153a202a6f15353, + 0x57dcae8ba572dcdc, 0x2c0b582716530b0b, 0x4e9d9cd327019d9d, 0xad6c47c1d82b6c6c, + 0xc43195f562a43131, 0xcd7487b9e8f37474, 0xfff6e309f115f6f6, 0x05460a438c4c4646, + 0x8aac092645a5acac, 0x1e893c970fb58989, 0x5014a04428b41414, 0xa3e15b42dfbae1e1, + 0x5816b04e2ca61616, 0xe83acdd274f73a3a, 0xb9696fd0d2066969, 0x2409482d12410909, + 0xdd70a7ade0d77070, 0xe2b6d954716fb6b6, 0x67d0ceb7bd1ed0d0, 0x93ed3b7ec7d6eded, + 0x17cc2edb85e2cccc, 0x15422a5784684242, 0x5a98b4c22d2c9898, 0xaaa4490e55eda4a4, + 0xa0285d8850752828, 0x6d5cda31b8865c5c, 0xc7f8933fed6bf8f8, 0x228644a411c28686, +} + +C7 := [256]u64 { + 0x186018c07830d818, 0x238c2305af462623, 0xc63fc67ef991b8c6, 0xe887e8136fcdfbe8, + 0x8726874ca113cb87, 0xb8dab8a9626d11b8, 0x0104010805020901, 0x4f214f426e9e0d4f, + 0x36d836adee6c9b36, 0xa6a2a6590451ffa6, 0xd26fd2debdb90cd2, 0xf5f3f5fb06f70ef5, + 0x79f979ef80f29679, 0x6fa16f5fcede306f, 0x917e91fcef3f6d91, 0x525552aa07a4f852, + 0x609d6027fdc04760, 0xbccabc89766535bc, 0x9b569baccd2b379b, 0x8e028e048c018a8e, + 0xa3b6a371155bd2a3, 0x0c300c603c186c0c, 0x7bf17bff8af6847b, 0x35d435b5e16a8035, + 0x1d741de8693af51d, 0xe0a7e05347ddb3e0, 0xd77bd7f6acb321d7, 0xc22fc25eed999cc2, + 0x2eb82e6d965c432e, 0x4b314b627a96294b, 0xfedffea321e15dfe, 0x5741578216aed557, + 0x155415a8412abd15, 0x77c1779fb6eee877, 0x37dc37a5eb6e9237, 0xe5b3e57b56d79ee5, + 0x9f469f8cd923139f, 0xf0e7f0d317fd23f0, 0x4a354a6a7f94204a, 0xda4fda9e95a944da, + 0x587d58fa25b0a258, 0xc903c906ca8fcfc9, 0x29a429558d527c29, 0x0a280a5022145a0a, + 0xb1feb1e14f7f50b1, 0xa0baa0691a5dc9a0, 0x6bb16b7fdad6146b, 0x852e855cab17d985, + 0xbdcebd8173673cbd, 0x5d695dd234ba8f5d, 0x1040108050209010, 0xf4f7f4f303f507f4, + 0xcb0bcb16c08bddcb, 0x3ef83eedc67cd33e, 0x05140528110a2d05, 0x6781671fe6ce7867, + 0xe4b7e47353d597e4, 0x279c2725bb4e0227, 0x4119413258827341, 0x8b168b2c9d0ba78b, + 0xa7a6a7510153f6a7, 0x7de97dcf94fab27d, 0x956e95dcfb374995, 0xd847d88e9fad56d8, + 0xfbcbfb8b30eb70fb, 0xee9fee2371c1cdee, 0x7ced7cc791f8bb7c, 0x66856617e3cc7166, + 0xdd53dda68ea77bdd, 0x175c17b84b2eaf17, 0x47014702468e4547, 0x9e429e84dc211a9e, + 0xca0fca1ec589d4ca, 0x2db42d75995a582d, 0xbfc6bf9179632ebf, 0x071c07381b0e3f07, + 0xad8ead012347acad, 0x5a755aea2fb4b05a, 0x8336836cb51bef83, 0x33cc3385ff66b633, + 0x6391633ff2c65c63, 0x020802100a041202, 0xaa92aa39384993aa, 0x71d971afa8e2de71, + 0xc807c80ecf8dc6c8, 0x196419c87d32d119, 0x4939497270923b49, 0xd943d9869aaf5fd9, + 0xf2eff2c31df931f2, 0xe3abe34b48dba8e3, 0x5b715be22ab6b95b, 0x881a8834920dbc88, + 0x9a529aa4c8293e9a, 0x2698262dbe4c0b26, 0x32c8328dfa64bf32, 0xb0fab0e94a7d59b0, + 0xe983e91b6acff2e9, 0x0f3c0f78331e770f, 0xd573d5e6a6b733d5, 0x803a8074ba1df480, + 0xbec2be997c6127be, 0xcd13cd26de87ebcd, 0x34d034bde4688934, 0x483d487a75903248, + 0xffdbffab24e354ff, 0x7af57af78ff48d7a, 0x907a90f4ea3d6490, 0x5f615fc23ebe9d5f, + 0x2080201da0403d20, 0x68bd6867d5d00f68, 0x1a681ad07234ca1a, 0xae82ae192c41b7ae, + 0xb4eab4c95e757db4, 0x544d549a19a8ce54, 0x937693ece53b7f93, 0x2288220daa442f22, + 0x648d6407e9c86364, 0xf1e3f1db12ff2af1, 0x73d173bfa2e6cc73, 0x124812905a248212, + 0x401d403a5d807a40, 0x0820084028104808, 0xc32bc356e89b95c3, 0xec97ec337bc5dfec, + 0xdb4bdb9690ab4ddb, 0xa1bea1611f5fc0a1, 0x8d0e8d1c8307918d, 0x3df43df5c97ac83d, + 0x976697ccf1335b97, 0x0000000000000000, 0xcf1bcf36d483f9cf, 0x2bac2b4587566e2b, + 0x76c57697b3ece176, 0x82328264b019e682, 0xd67fd6fea9b128d6, 0x1b6c1bd87736c31b, + 0xb5eeb5c15b7774b5, 0xaf86af112943beaf, 0x6ab56a77dfd41d6a, 0x505d50ba0da0ea50, + 0x450945124c8a5745, 0xf3ebf3cb18fb38f3, 0x30c0309df060ad30, 0xef9bef2b74c3c4ef, + 0x3ffc3fe5c37eda3f, 0x554955921caac755, 0xa2b2a2791059dba2, 0xea8fea0365c9e9ea, + 0x6589650fecca6a65, 0xbad2bab9686903ba, 0x2fbc2f65935e4a2f, 0xc027c04ee79d8ec0, + 0xde5fdebe81a160de, 0x1c701ce06c38fc1c, 0xfdd3fdbb2ee746fd, 0x4d294d52649a1f4d, + 0x927292e4e0397692, 0x75c9758fbceafa75, 0x061806301e0c3606, 0x8a128a249809ae8a, + 0xb2f2b2f940794bb2, 0xe6bfe66359d185e6, 0x0e380e70361c7e0e, 0x1f7c1ff8633ee71f, + 0x62956237f7c45562, 0xd477d4eea3b53ad4, 0xa89aa829324d81a8, 0x966296c4f4315296, + 0xf9c3f99b3aef62f9, 0xc533c566f697a3c5, 0x25942535b14a1025, 0x597959f220b2ab59, + 0x842a8454ae15d084, 0x72d572b7a7e4c572, 0x39e439d5dd72ec39, 0x4c2d4c5a6198164c, + 0x5e655eca3bbc945e, 0x78fd78e785f09f78, 0x38e038ddd870e538, 0x8c0a8c148605988c, + 0xd163d1c6b2bf17d1, 0xa5aea5410b57e4a5, 0xe2afe2434dd9a1e2, 0x6199612ff8c24e61, + 0xb3f6b3f1457b42b3, 0x21842115a5423421, 0x9c4a9c94d625089c, 0x1e781ef0663cee1e, + 0x4311432252866143, 0xc73bc776fc93b1c7, 0xfcd7fcb32be54ffc, 0x0410042014082404, + 0x515951b208a2e351, 0x995e99bcc72f2599, 0x6da96d4fc4da226d, 0x0d340d68391a650d, + 0xfacffa8335e979fa, 0xdf5bdfb684a369df, 0x7ee57ed79bfca97e, 0x2490243db4481924, + 0x3bec3bc5d776fe3b, 0xab96ab313d4b9aab, 0xce1fce3ed181f0ce, 0x1144118855229911, + 0x8f068f0c8903838f, 0x4e254e4a6b9c044e, 0xb7e6b7d1517366b7, 0xeb8beb0b60cbe0eb, + 0x3cf03cfdcc78c13c, 0x813e817cbf1ffd81, 0x946a94d4fe354094, 0xf7fbf7eb0cf31cf7, + 0xb9deb9a1676f18b9, 0x134c13985f268b13, 0x2cb02c7d9c58512c, 0xd36bd3d6b8bb05d3, + 0xe7bbe76b5cd38ce7, 0x6ea56e57cbdc396e, 0xc437c46ef395aac4, 0x030c03180f061b03, + 0x5645568a13acdc56, 0x440d441a49885e44, 0x7fe17fdf9efea07f, 0xa99ea921374f88a9, + 0x2aa82a4d8254672a, 0xbbd6bbb16d6b0abb, 0xc123c146e29f87c1, 0x535153a202a6f153, + 0xdc57dcae8ba572dc, 0x0b2c0b582716530b, 0x9d4e9d9cd327019d, 0x6cad6c47c1d82b6c, + 0x31c43195f562a431, 0x74cd7487b9e8f374, 0xf6fff6e309f115f6, 0x4605460a438c4c46, + 0xac8aac092645a5ac, 0x891e893c970fb589, 0x145014a04428b414, 0xe1a3e15b42dfbae1, + 0x165816b04e2ca616, 0x3ae83acdd274f73a, 0x69b9696fd0d20669, 0x092409482d124109, + 0x70dd70a7ade0d770, 0xb6e2b6d954716fb6, 0xd067d0ceb7bd1ed0, 0xed93ed3b7ec7d6ed, + 0xcc17cc2edb85e2cc, 0x4215422a57846842, 0x985a98b4c22d2c98, 0xa4aaa4490e55eda4, + 0x28a0285d88507528, 0x5c6d5cda31b8865c, 0xf8c7f8933fed6bf8, 0x86228644a411c286, +} + +RC := [ROUNDS + 1]u64 { + 0x0000000000000000, + 0x1823c6e887b8014f, + 0x36a6d2f5796f9152, + 0x60bc9b8ea30c7b35, + 0x1de0d7c22e4bfe57, + 0x157737e59ff04ada, + 0x58c9290ab1a06b85, + 0xbd5d10f4cb3e0567, + 0xe427418ba77d95d8, + 0xfbee7c66dd17479e, + 0xca2dbf07ad5a8333, +} + +transform :: proc (ctx: ^Whirlpool_Context) { + K, block, state, L: [8]u64 + + for i := 0; i < 8; i += 1 {block[i] = util.U64_BE(ctx.buffer[8 * i:])} + + for i := 0; i < 8; i += 1 { + K[i] = ctx.hash[i] + state[i] = block[i] ~ K[i] + } + + for r := 1; r <= ROUNDS; r += 1 { + for i := 0; i < 8; i += 1 { + L[i] = C0[byte(K[i % 8] >> 56)] ~ + C1[byte(K[(i + 7) % 8] >> 48)] ~ + C2[byte(K[(i + 6) % 8] >> 40)] ~ + C3[byte(K[(i + 5) % 8] >> 32)] ~ + C4[byte(K[(i + 4) % 8] >> 24)] ~ + C5[byte(K[(i + 3) % 8] >> 16)] ~ + C6[byte(K[(i + 2) % 8] >> 8)] ~ + C7[byte(K[(i + 1) % 8])] + } + L[0] ~= RC[r] + + for i := 0; i < 8; i += 1 {K[i] = L[i]} + + for i := 0; i < 8; i += 1 { + L[i] = C0[byte(state[i % 8] >> 56)] ~ + C1[byte(state[(i + 7) % 8] >> 48)] ~ + C2[byte(state[(i + 6) % 8] >> 40)] ~ + C3[byte(state[(i + 5) % 8] >> 32)] ~ + C4[byte(state[(i + 4) % 8] >> 24)] ~ + C5[byte(state[(i + 3) % 8] >> 16)] ~ + C6[byte(state[(i + 2) % 8] >> 8)] ~ + C7[byte(state[(i + 1) % 8])] ~ + K[i % 8] + } + for i := 0; i < 8; i += 1 {state[i] = L[i]} + } + for i := 0; i < 8; i += 1 {ctx.hash[i] ~= state[i] ~ block[i]} +} + +update_odin :: proc(ctx: ^Whirlpool_Context, source: []byte) { + source_pos: int + nn := len(source) + source_bits := u64(nn * 8) + source_gap := u32((8 - (int(source_bits & 7))) & 7) + buffer_rem := uint(ctx.buffer_bits & 7) + b: u32 + + for i, carry, value := 31, u32(0), u32(source_bits); i >= 0 && (carry != 0 || value != 0); i -= 1 { + carry += u32(ctx.bitlength[i]) + (u32(value & 0xff)) + ctx.bitlength[i] = byte(carry) + carry >>= 8 + value >>= 8 + } + + for source_bits > 8 { + b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap))) + + ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem) + ctx.buffer_pos += 1 + ctx.buffer_bits += int(8 - buffer_rem) + + if ctx.buffer_bits == 512 { + transform(ctx) + ctx.buffer_bits = 0 + ctx.buffer_pos = 0 + } + ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) + ctx.buffer_bits += int(buffer_rem) + source_bits -= 8 + source_pos += 1 + } + + if source_bits > 0 { + b = u32((source[source_pos] << source_gap) & 0xff) + ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem + } else {b = 0} + + if u64(buffer_rem) + source_bits < 8 { + ctx.buffer_bits += int(source_bits) + } else { + ctx.buffer_pos += 1 + ctx.buffer_bits += 8 - int(buffer_rem) + source_bits -= u64(8 - buffer_rem) + + if ctx.buffer_bits == 512 { + transform(ctx) + ctx.buffer_bits = 0 + ctx.buffer_pos = 0 + } + ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) + ctx.buffer_bits += int(source_bits) + } +} + +final_odin :: proc(ctx: ^Whirlpool_Context, hash: []byte) { + n := ctx + n.buffer[n.buffer_pos] |= 0x80 >> (uint(n.buffer_bits) & 7) + n.buffer_pos += 1 + + if n.buffer_pos > 64 - 32 { + if n.buffer_pos < 64 { + for i := 0; i < 64 - n.buffer_pos; i += 1 { + n.buffer[n.buffer_pos + i] = 0 + } + } + transform(ctx) + n.buffer_pos = 0 + } + + if n.buffer_pos < 64 - 32 { + for i := 0; i < (64 - 32) - n.buffer_pos; i += 1 { + n.buffer[n.buffer_pos + i] = 0 + } + } + n.buffer_pos = 64 - 32 + + for i := 0; i < 32; i += 1 { + n.buffer[n.buffer_pos + i] = n.bitlength[i] + } + transform(ctx) + + for i := 0; i < 8; i += 1 { + hash[i * 8] = byte(n.hash[i] >> 56) + hash[i * 8 + 1] = byte(n.hash[i] >> 48) + hash[i * 8 + 2] = byte(n.hash[i] >> 40) + hash[i * 8 + 3] = byte(n.hash[i] >> 32) + hash[i * 8 + 4] = byte(n.hash[i] >> 24) + hash[i * 8 + 5] = byte(n.hash[i] >> 16) + hash[i * 8 + 6] = byte(n.hash[i] >> 8) + hash[i * 8 + 7] = byte(n.hash[i]) + } +} \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index d90759841..e0a98eeb1 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -25,4 +25,9 @@ echo --- echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size \ No newline at end of file +%PATH_TO_ODIN% run odin %COMMON% -o:size + +echo --- +echo Running core:crypto hash tests +echo --- +%PATH_TO_ODIN% run crypto %COMMON% \ No newline at end of file diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin new file mode 100644 index 000000000..a50d67ddf --- /dev/null +++ b/tests/core/crypto/test_core_crypto.odin @@ -0,0 +1,1279 @@ +package test_core_crypto + +/* + Copyright 2021 zhibog + Made available under the BSD-3 license. + + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Test runner setup. + + Tests for the hashing algorithms within the crypto library. + Where possible, the official test vectors are used to validate the implementation. +*/ + +import "core:testing" +import "core:fmt" + +import "core:crypto/md2" +import "core:crypto/md4" +import "core:crypto/md5" +import "core:crypto/sha1" +import "core:crypto/sha2" +import "core:crypto/sha3" +import "core:crypto/keccak" +import "core:crypto/shake" +import "core:crypto/whirlpool" +import "core:crypto/ripemd" +import "core:crypto/blake" +import "core:crypto/blake2b" +import "core:crypto/blake2s" +import "core:crypto/tiger" +import "core:crypto/tiger2" +import "core:crypto/gost" +import "core:crypto/streebog" +import "core:crypto/sm3" +import "core:crypto/skein" +import "core:crypto/jh" +import "core:crypto/groestl" +import "core:crypto/haval" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + test_md2(&t) + test_md4(&t) + test_md5(&t) + test_sha1(&t) + test_sha224(&t) + test_sha256(&t) + test_sha384(&t) + test_sha512(&t) + test_sha3_224(&t) + test_sha3_256(&t) + test_sha3_384(&t) + test_sha3_512(&t) + test_shake_128(&t) + test_shake_256(&t) + test_keccak_224(&t) + test_keccak_256(&t) + test_keccak_384(&t) + test_keccak_512(&t) + test_whirlpool(&t) + test_gost(&t) + test_streebog_256(&t) + test_streebog_512(&t) + test_blake_224(&t) + test_blake_256(&t) + test_blake_384(&t) + test_blake_512(&t) + test_blake2b(&t) + test_blake2s(&t) + test_ripemd_128(&t) + test_ripemd_160(&t) + test_ripemd_256(&t) + test_ripemd_320(&t) + test_tiger_128(&t) + test_tiger_160(&t) + test_tiger_192(&t) + test_tiger2_128(&t) + test_tiger2_160(&t) + test_tiger2_192(&t) + test_sm3(&t) + test_skein512(&t) + test_jh_224(&t) + test_jh_256(&t) + test_jh_384(&t) + test_jh_512(&t) + test_groestl_224(&t) + test_groestl_256(&t) + test_groestl_384(&t) + test_groestl_512(&t) + test_haval_128(&t) + test_haval_160(&t) + test_haval_192(&t) + test_haval_224(&t) + test_haval_256(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +TestHash :: struct { + hash: string, + str: string, +} + +hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string { + lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} + buf := make([]byte, len(bytes) * 2, allocator) + for i := 0; i < len(bytes); i += 1 { + buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] + buf[i * 2 + 1] = lut[bytes[i] & 0xf] + } + return string(buf) +} + +@(test) +test_md2 :: proc(t: ^testing.T) { + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 + test_vectors := [?]TestHash { + TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, + TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, + TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, + TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, + TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md2.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_md4 :: proc(t: ^testing.T) { + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 + test_vectors := [?]TestHash { + TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, + TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, + TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, + TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, + TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md4.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + md4.use_botan() + for v, _ in test_vectors { + computed := md4.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + +} + +@(test) +test_md5 :: proc(t: ^testing.T) { + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 + test_vectors := [?]TestHash { + TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, + TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, + TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, + TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, + TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md5.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + md5.use_botan() + for v, _ in test_vectors { + computed := md5.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sha1 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, + TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, + TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, + TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, + TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha1.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha1.use_botan() + for v, _ in test_vectors { + computed := sha1.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + + +@(test) +test_sha224 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, + TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, + TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha2.use_botan() + for v, _ in test_vectors { + computed := sha2.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sha256 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, + TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, + TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha2.use_botan() + for v, _ in test_vectors { + computed := sha2.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + +} + +@(test) +test_sha384 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, + TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, + TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha2.use_botan() + for v, _ in test_vectors { + computed := sha2.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + +} + +@(test) +test_sha512 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, + TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, + TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha2.use_botan() + for v, _ in test_vectors { + computed := sha2.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + + +@(test) +test_sha3_224 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, + TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, + TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, + TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, + TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := sha3.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sha3_256 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, + TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, + TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, + TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, + TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := sha3.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sha3_384 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, + TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, + TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, + TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, + TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := sha3.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sha3_512 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, + TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, + TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, + TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, + TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := sha3.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_shake_128 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, + TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, + TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := shake.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_shake_256 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, + TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, + TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sha3.use_botan() + for v, _ in test_vectors { + computed := shake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_keccak_224 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, + TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + keccak.use_botan() + for v, _ in test_vectors { + computed := keccak.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_keccak_256 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, + TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + keccak.use_botan() + for v, _ in test_vectors { + computed := keccak.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_keccak_384 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, + TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + keccak.use_botan() + for v, _ in test_vectors { + computed := keccak.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_keccak_512 :: proc(t: ^testing.T) { + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, + TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + keccak.use_botan() + for v, _ in test_vectors { + computed := keccak.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_whirlpool :: proc(t: ^testing.T) { + // Test vectors from + // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html + test_vectors := [?]TestHash { + TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, + TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, + TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, + TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, + TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, + TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, + TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, + TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, + TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, + TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, + TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, + TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, + TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, + } + for v, _ in test_vectors { + computed := whirlpool.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + whirlpool.use_botan() + for v, _ in test_vectors { + computed := whirlpool.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_gost :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, + TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, + TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, + TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, + TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, + TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, + TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, + } + for v, _ in test_vectors { + computed := gost.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + gost.use_botan() + for v, _ in test_vectors { + computed := gost.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_streebog_256 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, + TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, + TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + streebog.use_botan() + for v, _ in test_vectors { + computed := streebog.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_streebog_512 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, + TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, + TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + streebog.use_botan() + for v, _ in test_vectors { + computed := streebog.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake_224 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, + TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, + TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake_256 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, + TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, + TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake_384 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, + TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, + TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake_512 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, + TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, + TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake2b :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, + TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2b.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + blake2b.use_botan() + for v, _ in test_vectors { + computed := blake2b.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_blake2s :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, + TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2s.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_ripemd_128 :: proc(t: ^testing.T) { + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, + TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, + TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, + TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, + TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_ripemd_160 :: proc(t: ^testing.T) { + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, + TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, + TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, + TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, + TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + ripemd.use_botan() + for v, _ in test_vectors { + computed := ripemd.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_ripemd_256 :: proc(t: ^testing.T) { + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, + TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, + TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, + TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, + TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_ripemd_320 :: proc(t: ^testing.T) { + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, + TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, + TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, + TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, + TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_320(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger_128 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + tiger.use_botan() + for v, _ in test_vectors { + computed := tiger.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger_160 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + tiger.use_botan() + for v, _ in test_vectors { + computed := tiger.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger_192 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + tiger.use_botan() + for v, _ in test_vectors { + computed := tiger.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger2_128 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b92", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger2_160 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_tiger2_192 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_sm3 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, + TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, + TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, + TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, + TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := sm3.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + sm3.use_botan() + for v, _ in test_vectors { + computed := sm3.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_skein512 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a", ""}, + TestHash{"94c2ae036dba8783d0b3f7d6cc111ff810702f5c77707999be7e1c9486ff238a7044de734293147359b4ac7e1d09cd247c351d69826b78dcddd951f0ef912713", "The quick brown fox jumps over the lazy dog"}, + } + skein.use_botan() + for v, _ in test_vectors { + computed := skein.hash_skein512(v.str, 64) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_jh_224 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, + TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, + TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_jh_256 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, + TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, + TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_jh_384 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, + TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, + TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_jh_512 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, + TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, + TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_groestl_224 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, + TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, + TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_groestl_256 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, + TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, + TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_groestl_384 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, + TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, + TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_groestl_512 :: proc(t: ^testing.T) { + test_vectors := [?]TestHash { + TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, + TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, + TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_haval_128 :: proc(t: ^testing.T) { + test_vectors_3 := [?]TestHash { + TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, + TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, + TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, + TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, + TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_128_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, + TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_128_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, + TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_128_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_haval_160 :: proc(t: ^testing.T) { + test_vectors_3 := [?]TestHash { + TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, + TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, + TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, + TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, + TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_160_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, + TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_160_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, + TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_160_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_haval_192 :: proc(t: ^testing.T) { + test_vectors_3 := [?]TestHash { + TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, + TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_192_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, + TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_192_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, + TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_192_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_haval_224 :: proc(t: ^testing.T) { + test_vectors_3 := [?]TestHash { + TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, + TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_224_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, + TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_224_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, + TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_224_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +} + +@(test) +test_haval_256 :: proc(t: ^testing.T) { + test_vectors_3 := [?]TestHash { + TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, + TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_256_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, + TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_256_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, + TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_256_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } +}