瀏覽代碼

Removed context switching system from the crypto library to simplify the code

zhibog 3 年之前
父節點
當前提交
c24454ae70

+ 35 - 43
core/crypto/README.md

@@ -2,48 +2,43 @@
 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.
+This library offers various algorithms implemented in Odin.
 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`
+| Algorithm                                                                                                    |                  |
+|:-------------------------------------------------------------------------------------------------------------|:-----------------|
+| [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)                                            | ✔️ |
+| [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)  | ✔️ |
 
 #### High level API
-Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*\*\*.  
+Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.  
 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` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) 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.  
+\* 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(...)`.
 
@@ -51,13 +46,6 @@ Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.h
 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
@@ -67,12 +55,16 @@ import "core:crypto/md4"
 
 main :: proc() {
     input := "foo"
-    // Compute the hash via Odin implementation
+
+    // Compute the hash, using the high level API
     computed_hash := md4.hash(input)
-    // Switch to Botan
-    md4.use_botan()
-    // Compute the hash via Botan bindings
-    computed_hash_botan := md4.hash(input)
+
+    // Compute the hash, using the low level API
+    ctx: md4.Md4_Context
+    computed_hash_low: [16]byte
+    md4.init(&ctx)
+    md4.update(&ctx, transmute([]byte)input)
+    md4.final(&ctx, computed_hash_low[:])
 }
 ```
 For example uses of all available algorithms, please see the tests within `tests/core/crypto`.

+ 22 - 14
core/crypto/_blake2/_blake2.odin

@@ -6,7 +6,6 @@ package _blake2
 
     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 <https://datatracker.ietf.org/doc/html/rfc7693> and <https://www.blake2.net/>
 */
@@ -76,7 +75,7 @@ BLAKE2B_IV := [8]u64 {
 	0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
 }
 
-init_odin :: proc(ctx: ^$T) {
+init :: proc(ctx: ^$T) {
 	when T == Blake2s_Context {
 		block_size :: BLAKE2S_BLOCK_SIZE
 	} else when T == Blake2b_Context {
@@ -139,17 +138,17 @@ init_odin :: proc(ctx: ^$T) {
 	}
 	if len(ctx.cfg.key) > 0 {
 		copy(ctx.padded_key[:], ctx.cfg.key)
-		update_odin(ctx, ctx.padded_key[:])
+		update(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(ctx, ctx.padded_key[:])
 	}
 }
 
-update_odin :: proc(ctx: ^$T, p: []byte) {
+update :: proc "contextless" (ctx: ^$T, p: []byte) {
 	p := p
 	when T == Blake2s_Context {
 		block_size :: BLAKE2S_BLOCK_SIZE
@@ -161,7 +160,7 @@ update_odin :: proc(ctx: ^$T, p: []byte) {
 	if len(p) > left {
 		copy(ctx.x[ctx.nx:], p[:left])
 		p = p[left:]
-		blake2_blocks(ctx, ctx.x[:])
+		blocks(ctx, ctx.x[:])
 		ctx.nx = 0
 	}
 	if len(p) > block_size {
@@ -169,13 +168,22 @@ update_odin :: proc(ctx: ^$T, p: []byte) {
 		if n == len(p) {
 			n -= block_size
 		}
-		blake2_blocks(ctx, p[:n])
+		blocks(ctx, p[:n])
 		p = p[n:]
 	}
 	ctx.nx += copy(ctx.x[ctx.nx:], p)
 }
 
-blake2s_final_odin :: proc(ctx: $T, hash: []byte) {
+final :: proc "contextless" (ctx: ^$T, hash: []byte) {
+	when T == Blake2s_Context {
+		blake2s_final(ctx, hash)
+	}
+	when T == Blake2b_Context {
+		blake2b_final(ctx, hash)
+	}
+}
+
+blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
 	if ctx.is_keyed {
 		for i := 0; i < len(ctx.padded_key); i += 1 {
 			ctx.padded_key[i] = 0
@@ -193,7 +201,7 @@ blake2s_final_odin :: proc(ctx: $T, hash: []byte) {
 		ctx.f[1] = 0xffffffff
 	}
 
-	blake2_blocks(ctx, ctx.x[:])
+	blocks(ctx, ctx.x[:])
 
 	j := 0
 	for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] {
@@ -205,7 +213,7 @@ blake2s_final_odin :: proc(ctx: $T, hash: []byte) {
 	}
 }
 
-blake2b_final_odin :: proc(ctx: $T, hash: []byte) {
+blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
 	if ctx.is_keyed {
 		for i := 0; i < len(ctx.padded_key); i += 1 {
 			ctx.padded_key[i] = 0
@@ -223,7 +231,7 @@ blake2b_final_odin :: proc(ctx: $T, hash: []byte) {
 		ctx.f[1] = 0xffffffffffffffff
 	} 
 
-	blake2_blocks(ctx, ctx.x[:])
+	blocks(ctx, ctx.x[:])
 
 	j := 0
 	for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] {
@@ -239,7 +247,7 @@ blake2b_final_odin :: proc(ctx: $T, hash: []byte) {
 	}
 }
 
-blake2_blocks :: proc(ctx: ^$T, p: []byte) {
+blocks :: proc "contextless" (ctx: ^$T, p: []byte) {
 	when T == Blake2s_Context {
 		blake2s_blocks(ctx, p)
 	}
@@ -248,7 +256,7 @@ blake2_blocks :: proc(ctx: ^$T, p: []byte) {
 	}
 }
 
-blake2s_blocks :: #force_inline proc "contextless"(ctx: ^Blake2s_Context, p: []byte) {
+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 {
@@ -1404,7 +1412,7 @@ blake2s_blocks :: #force_inline proc "contextless"(ctx: ^Blake2s_Context, p: []b
 	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) {
+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 {

+ 0 - 79
core/crypto/_ctx/_ctx.odin

@@ -1,79 +0,0 @@
-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"
-import "core:os"
-
-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, hd: os.Handle, load_at_once := false) -> ([16]byte,  bool),
-    hash_file_20      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte,  bool),
-    hash_file_24      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte,  bool),
-    hash_file_28      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte,  bool),
-    hash_file_32      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte,  bool),
-    hash_file_40      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([40]byte,  bool),
-    hash_file_48      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte,  bool),
-    hash_file_64      : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte,  bool),
-    hash_file_128     : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([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, hd: os.Handle, out_size: int, load_at_once := false, 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
-}

+ 5 - 6
core/crypto/_sha3/_sha3.odin

@@ -6,7 +6,6 @@ package _sha3
 
     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 <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
     To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
@@ -115,14 +114,14 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
     }
 }
 
-init_odin :: proc "contextless" (c: ^Sha3_Context) {
+init :: 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) {
+update :: proc "contextless" (c: ^Sha3_Context, data: []byte) {
     j := c.pt
     for i := 0; i < len(data); i += 1 {
         c.st.b[j] ~= data[i]
@@ -135,7 +134,7 @@ update_odin :: proc "contextless" (c: ^Sha3_Context, data: []byte) {
     c.pt = j
 }
 
-final_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
+final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
     if c.is_keccak {
         c.st.b[c.pt] ~= 0x01
     } else {
@@ -149,14 +148,14 @@ final_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
     }
 }
 
-shake_xof_odin :: proc "contextless" (c: ^Sha3_Context) {
+shake_xof :: 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) {
+shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
     j := c.pt
     for i := 0; i < len(hash); i += 1 {
         if j >= c.rsiz {

+ 10 - 11
core/crypto/_tiger/_tiger.odin

@@ -6,7 +6,6 @@ package _tiger
 
     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 <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
 */
@@ -291,7 +290,7 @@ Tiger_Context :: struct {
 	ver:    int,
 }
 
-round :: #force_inline proc "contextless"(a, b, c, x, mul: u64) -> (u64, u64, u64) {
+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]
@@ -300,7 +299,7 @@ round :: #force_inline proc "contextless"(a, b, c, x, mul: u64) -> (u64, u64, u6
 	return a, b, c
 }
 
-pass :: #force_inline proc "contextless"(a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) {
+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)
@@ -312,7 +311,7 @@ pass :: #force_inline proc "contextless"(a, b, c: u64, d: []u64, mul: u64) -> (x
 	return
 }
 
-key_schedule :: #force_inline proc "contextless"(x: []u64) {
+key_schedule :: #force_inline proc "contextless" (x: []u64) {
 	x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5
 	x[1] ~= x[0]
 	x[2] += x[1]
@@ -331,7 +330,7 @@ key_schedule :: #force_inline proc "contextless"(x: []u64) {
 	x[7] -= x[6] ~ 0x0123456789abcdef
 }
 
-compress :: #force_inline proc "contextless"(ctx: ^Tiger_Context, data: []byte) {
+compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) {
 	a := ctx.a
 	b := ctx.b
 	c := ctx.c
@@ -346,13 +345,13 @@ compress :: #force_inline proc "contextless"(ctx: ^Tiger_Context, data: []byte)
 	ctx.c += c
 }
 
-init_odin :: proc(ctx: ^Tiger_Context) {
+init :: proc "contextless" (ctx: ^Tiger_Context) {
 	ctx.a = 0x0123456789abcdef
 	ctx.b = 0xfedcba9876543210
 	ctx.c = 0xf096a5b4c3b2e187
 }
 
-update_odin :: proc(ctx: ^Tiger_Context, input: []byte) {
+update :: proc(ctx: ^Tiger_Context, input: []byte) {
 	p := make([]byte, len(input))
 	copy(p, input)
 
@@ -380,7 +379,7 @@ update_odin :: proc(ctx: ^Tiger_Context, input: []byte) {
 	}
 }
 
-final_odin :: proc(ctx: ^Tiger_Context, hash: []byte) {
+final :: proc(ctx: ^Tiger_Context, hash: []byte) {
 	length := ctx.length
 	tmp: [64]byte
 	if ctx.ver == 1 {
@@ -391,16 +390,16 @@ final_odin :: proc(ctx: ^Tiger_Context, hash: []byte) {
 
 	size := length & 0x3f
 	if size < 56 {
-		update_odin(ctx, tmp[:56 - size])
+		update(ctx, tmp[:56 - size])
 	} else {
-		update_odin(ctx, tmp[:64 + 56 - size])
+		update(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])
+	update(ctx, tmp[:8])
 
 	for i := uint(0); i < 8; i += 1 {
 		tmp[i]      = byte(ctx.a >> (8 * i))

+ 289 - 486
core/crypto/blake/blake.odin

@@ -6,7 +6,6 @@ package blake
 
     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 <https://web.archive.org/web/20190915215948/https://131002.net/blake>
 */
@@ -14,102 +13,59 @@ package blake
 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 {
+hash_string_224 :: proc "contextless" (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_bytes_224 :: proc "contextless" (data: []byte) -> [28]byte {
+    hash: [28]byte
+    ctx: Blake256_Context
+    ctx.is224 = true
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [28]byte
+    ctx: Blake256_Context
+    ctx.is224 = true
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    _create_blake256_ctx(true, ._28)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -121,29 +77,53 @@ hash_224 :: proc {
 
 // hash_string_256 will hash the given input and return the
 // computed hash
-hash_string_256 :: proc(data: string) -> [32]byte {
+hash_string_256 :: proc "contextless" (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_bytes_256 :: proc "contextless" (data: []byte) -> [32]byte {
+    hash: [32]byte
+    ctx: Blake256_Context
+    ctx.is224 = false
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Blake256_Context
+    ctx.is224 = false
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_blake256_ctx(false, ._32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -155,29 +135,53 @@ hash_256 :: proc {
 
 // hash_string_384 will hash the given input and return the
 // computed hash
-hash_string_384 :: proc(data: string) -> [48]byte {
+hash_string_384 :: proc "contextless" (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_bytes_384 :: proc "contextless" (data: []byte) -> [48]byte {
+    hash: [48]byte
+    ctx: Blake512_Context
+    ctx.is384 = true
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [48]byte
+    ctx: Blake512_Context
+    ctx.is384 = true
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    _create_blake512_ctx(true, ._48)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -189,29 +193,53 @@ hash_384 :: proc {
 
 // hash_string_512 will hash the given input and return the
 // computed hash
-hash_string_512 :: proc(data: string) -> [64]byte {
+hash_string_512 :: proc "contextless" (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_bytes_512 :: proc "contextless" (data: []byte) -> [64]byte {
+    hash: [64]byte
+    ctx: Blake512_Context
+    ctx.is384 = false
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: Blake512_Context
+    ctx.is384 = false
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_blake512_ctx(false, ._64)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -225,231 +253,188 @@ hash_512 :: proc {
     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])
-            } 
+init :: proc "contextless" (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
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
-
-hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), ok
+    } 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
         }
     }
-    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])
-            } 
+update :: proc "contextless" (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:]
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
-
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
+        if len(data) >= BLOCKSIZE_256 {
+            n := len(data) &~ (BLOCKSIZE_256 - 1)
+            block256(ctx, data[:n])
+            data = data[n:]
         }
-    }
-    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])
-            } 
+        if len(data) > 0 {
+            ctx.nx = copy(ctx.x[:], data)
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
-
-hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), ok
+    } 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)
         }
     }
-    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[:])
+final :: proc "contextless" (ctx: ^$T, hash: []byte) {
+    when T == Blake256_Context {
+        tmp: [65]byte
+    } else when T == Blake512_Context {
+        tmp: [129]byte
     }
-    return hash
-}
+    nx     := u64(ctx.nx)
+    tmp[0]  = 0x80
+    length := (ctx.t + nx) << 3
 
-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])
-            } 
+    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})
+            }
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
 
-hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
+        for i : uint = 0; i < 8; i += 1 {
+            tmp[i] = byte(length >> (56 - 8 * i))
         }
-    }
-    return [64]byte{}, false
-}
+        write_additional(ctx, tmp[0:8])
 
-@(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)
+        h := ctx.h[:]
+        if ctx.is224 {
+            h = h[0:7]
         }
-        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)
+        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)
         }
-    }
-}
-
-@(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)
+    } else when T == Blake512_Context {
+        if nx == 111 {
+            if ctx.is384 {
+                write_additional(ctx, {0x80})
+            } else {
+                write_additional(ctx, {0x81})
             }
-    }
-}
-
-@(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)
+        } 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
             }
-        case ._48, ._64:
-            if c, ok := ctx.internal_ctx.(Blake512_Context); ok {
-                final_odin(&c, hash)
+            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)
+        }
     }
 }
 
-/*
-    BLAKE implementation
-*/
-
 SIZE_224 :: 28
 SIZE_256 :: 32
 SIZE_384 :: 48
@@ -542,8 +527,8 @@ G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int
     return a, b, c, d
 }
 
-block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) {
-    i, j: int = ---, ---
+block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check {
+    i, j: int     = ---, ---
     v, m: [16]u32 = ---, ---
     p := p
     for len(p) >= BLOCKSIZE_256 {
@@ -595,7 +580,7 @@ block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) {
 }
 
 block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check {
-    i, j: int = ---, ---
+    i, j: int     = ---, ---
     v, m: [16]u64 = ---, ---
     p := p
     for len(p) >= BLOCKSIZE_512 {
@@ -646,189 +631,7 @@ block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_ch
     }
 }
 
-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) {
+write_additional :: proc "contextless" (ctx: ^$T, data: []byte) {
 	ctx.t -= u64(len(data)) << 3
-    update_odin(ctx, data)
+    update(ctx, data)
 }

+ 41 - 126
core/crypto/blake2b/blake2b.odin

@@ -6,7 +6,6 @@ package blake2b
 
     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.
@@ -15,49 +14,8 @@ package blake2b
 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
 */
@@ -71,22 +29,50 @@ hash_string :: proc(data: string) -> [64]byte {
 // hash_bytes will hash the given input and return the
 // computed hash
 hash_bytes :: proc(data: []byte) -> [64]byte {
-    _create_blake2b_ctx()
-    return _hash_impl->hash_bytes_64(data)
+    hash: [64]byte
+    ctx: _blake2.Blake2b_Context
+    cfg: _blake2.Blake2_Config
+    cfg.size = _blake2.BLAKE2B_SIZE
+    ctx.cfg  = cfg
+    _blake2.init(&ctx)
+    _blake2.update(&ctx, data)
+    _blake2.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_blake2b_ctx()
-    return _hash_impl->hash_stream_64(s)
+    hash: [64]byte
+    ctx: _blake2.Blake2b_Context
+    cfg: _blake2.Blake2_Config
+    cfg.size = _blake2.BLAKE2B_SIZE
+    ctx.cfg  = cfg
+    _blake2.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _blake2.update(&ctx, buf[:read])
+        } 
+    }
+    _blake2.final(&ctx, hash[:])
+    return hash, true 
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_blake2b_ctx()
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash :: proc {
@@ -100,87 +86,16 @@ hash :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
-}
+Blake2b_Context :: _blake2.Blake2b_Context
 
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
+init :: proc(ctx: ^_blake2.Blake2b_Context) {
+    _blake2.init(ctx)
 }
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
+update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) {
+    _blake2.update(ctx, data)
 }
 
-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, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
-
-@(private)
-_create_blake2b_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_blake2b_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)
-    }
+final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) {
+    _blake2.final(ctx, hash)
 }

+ 41 - 126
core/crypto/blake2s/blake2s.odin

@@ -6,7 +6,6 @@ package blake2s
 
     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.
@@ -15,49 +14,8 @@ package blake2s
 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
 */
@@ -71,22 +29,50 @@ hash_string :: proc(data: string) -> [32]byte {
 // hash_bytes will hash the given input and return the
 // computed hash
 hash_bytes :: proc(data: []byte) -> [32]byte {
-    _create_blake2s_ctx()
-    return _hash_impl->hash_bytes_32(data)
+    hash: [32]byte
+    ctx: _blake2.Blake2s_Context
+    cfg: _blake2.Blake2_Config
+    cfg.size = _blake2.BLAKE2S_SIZE
+    ctx.cfg  = cfg
+    _blake2.init(&ctx)
+    _blake2.update(&ctx, data)
+    _blake2.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_blake2s_ctx()
-    return _hash_impl->hash_stream_32(s)
+    hash: [32]byte
+    ctx: _blake2.Blake2s_Context
+    cfg: _blake2.Blake2_Config
+    cfg.size = _blake2.BLAKE2S_SIZE
+    ctx.cfg  = cfg
+    _blake2.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _blake2.update(&ctx, buf[:read])
+        } 
+    }
+    _blake2.final(&ctx, hash[:])
+    return hash, true 
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_blake2s_ctx()
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash :: proc {
@@ -100,87 +86,16 @@ hash :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
-}
+Blake2s_Context :: _blake2.Blake2b_Context
 
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
+init :: proc(ctx: ^_blake2.Blake2s_Context) {
+    _blake2.init(ctx)
 }
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
+update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) {
+    _blake2.update(ctx, data)
 }
 
-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, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
-        }
-    }
-    return [32]byte{}, false
-}
-
-@(private)
-_create_blake2s_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_blake2s_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)
-    }
+final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) {
+    _blake2.final(ctx, hash)
 }

二進制
core/crypto/botan/botan.lib


+ 0 - 480
core/crypto/botan/botan.odin

@@ -1,480 +0,0 @@
-package botan
-
-/*
-    Copyright 2021 zhibog
-    Made available under the BSD-3 license.
-
-    List of contributors:
-        zhibog: Initial creation and testing of the bindings.
-
-    Bindings for the Botan crypto library.
-    Created for version 2.18.1, using the provided FFI header within Botan.
-
-    The "botan_" prefix has been stripped from the identifiers to remove redundancy,
-    since the package is already named botan.
-*/
-
-import "core:c"
-
-FFI_ERROR                           :: #type c.int
-FFI_SUCCESS                         :: FFI_ERROR(0)
-FFI_INVALID_VERIFIER                :: FFI_ERROR(1)
-FFI_ERROR_INVALID_INPUT             :: FFI_ERROR(-1)
-FFI_ERROR_BAD_MAC                   :: FFI_ERROR(-2)
-FFI_ERROR_INSUFFICIENT_BUFFER_SPACE :: FFI_ERROR(-10)
-FFI_ERROR_EXCEPTION_THROWN          :: FFI_ERROR(-20)
-FFI_ERROR_OUT_OF_MEMORY             :: FFI_ERROR(-21)
-FFI_ERROR_BAD_FLAG                  :: FFI_ERROR(-30)
-FFI_ERROR_NULL_POINTER              :: FFI_ERROR(-31)
-FFI_ERROR_BAD_PARAMETER             :: FFI_ERROR(-32)
-FFI_ERROR_KEY_NOT_SET               :: FFI_ERROR(-33)
-FFI_ERROR_INVALID_KEY_LENGTH        :: FFI_ERROR(-34)
-FFI_ERROR_NOT_IMPLEMENTED           :: FFI_ERROR(-40)
-FFI_ERROR_INVALID_OBJECT            :: FFI_ERROR(-50)
-FFI_ERROR_UNKNOWN_ERROR             :: FFI_ERROR(-100)
-
-FFI_HEX_LOWER_CASE              :: 1
-
-CIPHER_INIT_FLAG_MASK_DIRECTION :: 1
-CIPHER_INIT_FLAG_ENCRYPT        :: 0
-CIPHER_INIT_FLAG_DECRYPT        :: 1
-
-CIPHER_UPDATE_FLAG_FINAL        :: 1 << 0
-
-CHECK_KEY_EXPENSIVE_TESTS       :: 1
-
-PRIVKEY_EXPORT_FLAG_DER         :: 0
-PRIVKEY_EXPORT_FLAG_PEM         :: 1
-
-PUBKEY_DER_FORMAT_SIGNATURE     :: 1
-
-FPE_FLAG_FE1_COMPAT_MODE        :: 1
-
-x509_cert_key_constraints :: #type c.int
-NO_CONSTRAINTS            :: x509_cert_key_constraints(0)
-DIGITAL_SIGNATURE         :: x509_cert_key_constraints(32768)
-NON_REPUDIATION           :: x509_cert_key_constraints(16384)
-KEY_ENCIPHERMENT          :: x509_cert_key_constraints(8192)
-DATA_ENCIPHERMENT         :: x509_cert_key_constraints(4096)
-KEY_AGREEMENT             :: x509_cert_key_constraints(2048)
-KEY_CERT_SIGN             :: x509_cert_key_constraints(1024)
-CRL_SIGN                  :: x509_cert_key_constraints(512)
-ENCIPHER_ONLY             :: x509_cert_key_constraints(256)
-DECIPHER_ONLY             :: x509_cert_key_constraints(128)
-
-HASH_SHA1           :: "SHA1"
-HASH_SHA_224        :: "SHA-224"
-HASH_SHA_256        :: "SHA-256"
-HASH_SHA_384        :: "SHA-384"
-HASH_SHA_512        :: "SHA-512"
-HASH_SHA3_224       :: "SHA-3(224)"
-HASH_SHA3_256       :: "SHA-3(256)"
-HASH_SHA3_384       :: "SHA-3(384)"
-HASH_SHA3_512       :: "SHA-3(512)"
-HASH_SHAKE_128      :: "SHAKE-128"
-HASH_SHAKE_256      :: "SHAKE-256"
-HASH_KECCAK_224     :: "KECCAK(224)"
-HASH_KECCAK_256     :: "KECCAK(256)"
-HASH_KECCAK_384     :: "KECCAK(384)"
-HASH_KECCAK_512     :: "KECCAK(512)"
-HASH_RIPEMD_160     :: "RIPEMD-160"
-HASH_WHIRLPOOL      :: "Whirlpool"
-HASH_BLAKE2B        :: "BLAKE2b"
-HASH_MD4            :: "MD4"
-HASH_MD5            :: "MD5"
-HASH_TIGER_128      :: "Tiger(16,3)"
-HASH_TIGER_160      :: "Tiger(20,3)"
-HASH_TIGER_192      :: "Tiger(24,3)"
-HASH_GOST           :: "GOST-34.11"
-HASH_STREEBOG_256   :: "Streebog-256"
-HASH_STREEBOG_512   :: "Streebog-512"
-HASH_SM3            :: "SM3"
-HASH_SKEIN_512_256  :: "Skein-512(256)"
-HASH_SKEIN_512_512  :: "Skein-512(512)"
-HASH_SKEIN_512_1024 :: "Skein-512(1024)"
-
-// Not real values from Botan, only used for context setup within the crypto lib
-HASH_SHA2        :: "SHA2"
-HASH_SHA3        :: "SHA3"
-HASH_SHAKE       :: "SHAKE"
-HASH_KECCAK      :: "KECCAK"
-HASH_STREEBOG    :: "STREEBOG"
-HASH_TIGER       :: "TIGER"
-HASH_SKEIN_512   :: "SKEIN_512"
-
-MAC_HMAC_SHA1    :: "HMAC(SHA1)"
-MAC_HMAC_SHA_224 :: "HMAC(SHA-224)"
-MAC_HMAC_SHA_256 :: "HMAC(SHA-256)"
-MAC_HMAC_SHA_384 :: "HMAC(SHA-384)"
-MAC_HMAC_SHA_512 :: "HMAC(SHA-512)"
-MAC_HMAC_MD5     :: "HMAC(MD5)"
-
-hash_struct          :: struct{}
-hash_t               :: ^hash_struct
-rng_struct           :: struct{}
-rng_t                :: ^rng_struct
-mac_struct           :: struct{}
-mac_t                :: ^mac_struct
-cipher_struct        :: struct{}
-cipher_t             :: ^cipher_struct
-block_cipher_struct  :: struct{}
-block_cipher_t       :: ^block_cipher_struct
-mp_struct            :: struct{}
-mp_t                 :: ^mp_struct
-privkey_struct       :: struct{}
-privkey_t            :: ^privkey_struct
-pubkey_struct        :: struct{}
-pubkey_t             :: ^pubkey_struct
-pk_op_encrypt_struct :: struct{}
-pk_op_encrypt_t      :: ^pk_op_encrypt_struct
-pk_op_decrypt_struct :: struct{}
-pk_op_decrypt_t      :: ^pk_op_decrypt_struct
-pk_op_sign_struct    :: struct{}
-pk_op_sign_t         :: ^pk_op_sign_struct
-pk_op_verify_struct  :: struct{}
-pk_op_verify_t       :: ^pk_op_verify_struct
-pk_op_ka_struct      :: struct{}
-pk_op_ka_t           :: ^pk_op_ka_struct
-x509_cert_struct     :: struct{}
-x509_cert_t          :: ^x509_cert_struct
-x509_crl_struct      :: struct{}
-x509_crl_t           :: ^x509_crl_struct
-hotp_struct          :: struct{}
-hotp_t               :: ^hotp_struct
-totp_struct          :: struct{}
-totp_t               :: ^totp_struct
-fpe_struct           :: struct{}
-fpe_t                :: ^fpe_struct
-
-when ODIN_OS == "windows" {
-    foreign import botan_lib "botan.lib"
-} else when ODIN_OS == "linux" {
-    foreign import botan_lib "system:botan-2"
-} else when ODIN_OS == "darwin" {
-    foreign import botan_lib "system:botan-2"
-}
-
-@(default_calling_convention="c")
-@(link_prefix="botan_")
-foreign botan_lib {
-    error_description                   :: proc(err: c.int) -> 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 ---
-}

+ 0 - 498
core/crypto/botan/hash.odin

@@ -1,498 +0,0 @@
-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, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_16(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_16(ctx, buf[:]), ok
-        }
-    }
-    return [16]byte{}, false
-}
-
-hash_file_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    if !load_at_once {
-        return hash_stream_20(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_20(ctx, buf[:]), ok
-        }
-    }
-    return [20]byte{}, false
-}
-
-hash_file_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) {
-    if !load_at_once {
-        return hash_stream_24(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_24(ctx, buf[:]), ok
-        }
-    }
-    return [24]byte{}, false
-}
-
-hash_file_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_28(ctx, buf[:]), ok
-        }
-    }
-    return [28]byte{}, false
-}
-
-hash_file_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_32(ctx, buf[:]), ok
-        }
-    }
-    return [32]byte{}, false
-}
-
-hash_file_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_48(ctx, buf[:]), ok
-        }
-    }
-    return [48]byte{}, false
-}
-
-hash_file_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_64(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
-
-hash_file_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([128]byte, bool) {
-    if !load_at_once {
-        return hash_stream_128(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_128(ctx, buf[:]), ok
-        }
-    }
-    return [128]byte{}, false
-}
-
-hash_file_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    if !load_at_once {
-        return hash_stream_slice(ctx, os.stream_from_handle(hd), bit_size, allocator)
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_slice(ctx, buf[:], bit_size, allocator), ok
-        }
-    }
-    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
-}

+ 110 - 207
core/crypto/gost/gost.odin

@@ -6,7 +6,6 @@ package gost
 
     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 <https://datatracker.ietf.org/doc/html/rfc5831>
 */
@@ -15,42 +14,6 @@ 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
 */
@@ -64,22 +27,44 @@ hash_string :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Gost_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Gost_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_gost_ctx()
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash :: proc {
@@ -93,85 +78,77 @@ hash :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
-}
+init :: proc "contextless" (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 },
+    }
 
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
+    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)
+        }
+    }
 }
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
-}
+update :: proc(ctx: ^Gost_Context, data: []byte) {
+    length := byte(len(data))
+    j: byte
 
-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[:])
+    i := ctx.partial_bytes
+    for i < 32 && j < length {
+        ctx.partial[i] = data[j]
+        i, j = i + 1, j + 1
     }
-    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
+    if i < 32 {
+        ctx.partial_bytes = i
+        return
     }
-}
+    bytes(ctx, ctx.partial[:], 256)
 
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
-        }
+    for (j + 32) < length {
+        bytes(ctx, data[j:], 256)
+        j += 32
     }
-    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)
+    i = 0
+    for j < length {
+        ctx.partial[i] = data[j]
+        i, j = i + 1, j + 1
     }
+    ctx.partial_bytes = i
 }
 
-@(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)
+final :: proc(ctx: ^Gost_Context, hash: []byte) {
+    if ctx.partial_bytes > 0 {
+        mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes))
+        bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3)
     }
-}
+  
+    compress(ctx.hash[:], ctx.len[:])
+    compress(ctx.hash[:], ctx.sum[:])
 
-@(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)
+    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)
     }
 }
 
@@ -187,12 +164,12 @@ Gost_Context :: struct {
     partial_bytes: byte,
 }
 
-SBOX_1 : [256]u32
-SBOX_2 : [256]u32
-SBOX_3 : [256]u32
-SBOX_4 : [256]u32
+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) {
+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]
@@ -201,30 +178,30 @@ GOST_ENCRYPT_ROUND :: #force_inline proc "contextless"(l, r, t, k1, k2: u32) ->
     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])
+ENCRYPT :: #force_inline proc "contextless" (a, b, c: u32, key: []u32) -> (l, r, t: u32) {
+    l, r, t = ENCRYPT_ROUND(a, b, c, key[0], key[1])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[7], key[6])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[5], key[4])
+    l, r, t = ENCRYPT_ROUND(l, r, t, key[3], key[2])
+    l, r, t = 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) {
+bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) {
     a, c: u32
     m: [8]u32
 
@@ -237,14 +214,14 @@ gost_bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) {
         c = c < a ? 1 : 0
     }
 
-    gost_compress(ctx.hash[:], m[:])
+    compress(ctx.hash[:], m[:])
     ctx.len[0] += bits
     if ctx.len[0] < bits {
         ctx.len[1] += 1
     }
 }
 
-gost_compress :: proc(h, m: []u32) {
+compress :: proc(h, m: []u32) {
     key, u, v, w, s: [8]u32
 
     copy(u[:], h)
@@ -272,7 +249,7 @@ gost_compress :: proc(h, m: []u32) {
         r := h[i]
         l := h[i + 1]
         t: u32
-        l, r, t = GOST_ENCRYPT(l, r, 0, key[:])
+        l, r, t = ENCRYPT(l, r, 0, key[:])
 
         s[i] = r
         s[i + 1] = l
@@ -380,78 +357,4 @@ gost_compress :: proc(h, m: []u32) {
     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)
-    }
 }

+ 188 - 354
core/crypto/groestl/groestl.odin

@@ -6,7 +6,6 @@ package groestl
 
     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 <http://www.groestl.info/Groestl.zip>
 */
@@ -14,70 +13,6 @@ package groestl
 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
-    #partial switch size {
-        case ._28: ctx.hashbitlen = 224
-        case ._32: ctx.hashbitlen = 256
-        case ._48: ctx.hashbitlen = 384
-        case ._64: ctx.hashbitlen = 512
-    }
-    _hash_impl.internal_ctx = ctx
-    _hash_impl.hash_size    = size
-}
-
 /*
     High level API
 */
@@ -91,22 +26,46 @@ hash_string_224 :: proc(data: string) -> [28]byte {
 // 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: [28]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 224
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [28]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 224
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    _create_groestl_ctx(._28)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -125,22 +84,46 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 256
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 256
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_groestl_ctx(._32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -159,22 +142,46 @@ hash_string_384 :: proc(data: string) -> [48]byte {
 // 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: [48]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 384
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [48]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 384
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    _create_groestl_ctx(._48)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -193,22 +200,46 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 512
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: Groestl_Context
+    ctx.hashbitlen = 512
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_groestl_ctx(._64)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -222,201 +253,101 @@ hash_512 :: proc {
     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
+init :: proc(ctx: ^Groestl_Context) {
+    assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
+    if ctx.hashbitlen <= 256 {
+        ctx.rounds    = 10
+        ctx.columns   = 8
+        ctx.statesize = 64
     } else {
-        return hash, false
+        ctx.rounds    = 14
+        ctx.columns   = 16
+        ctx.statesize = 128
     }
-}
-
-hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), ok
-        }
+    for i := 8 - size_of(i32); i < 8; i += 1 {
+        ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i))))
     }
-    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
-}
+update :: proc(ctx: ^Groestl_Context, data: []byte) {
+    databitlen := len(data) * 8
+    msglen     := databitlen / 8
+    rem        := databitlen % 8
 
-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])
-            } 
+    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]
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
 
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
+        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
         }
-    }
-    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[:])
+        ctx.buf_ptr = 0
+        transform(ctx, ctx.buffer[:], u32(ctx.statesize))
     }
-    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
+    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
     }
-}
-
-hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), ok
-        }
+    
+    if rem != 0 {
+        ctx.bits_in_last_byte    = rem
+        ctx.buffer[ctx.buf_ptr]  = data[i]
+        ctx.buf_ptr             += 1
     }
-    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
-}
+final :: proc(ctx: ^Groestl_Context, hash: []byte) {
+    hashbytelen := ctx.hashbitlen / 8
 
-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
+    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 {
-        return hash, false
+        ctx.buffer[ctx.buf_ptr]  = 0x80
+        ctx.buf_ptr             += 1
     }
-}
 
-hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
+    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
     }
-    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)
+    for ctx.buf_ptr < ctx.statesize - 8 {
+        ctx.buffer[ctx.buf_ptr]  = 0
+        ctx.buf_ptr             += 1
     }
-}
 
-@(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)
+    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
     }
-}
 
-@(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)
+    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]
     }
 }
 
@@ -631,100 +562,3 @@ add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_V
             }
     }
 }
-
-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]
-    }
-}

File diff suppressed because it is too large
+ 574 - 390
core/crypto/haval/haval.odin


+ 210 - 376
core/crypto/jh/jh.odin

@@ -6,7 +6,6 @@ package jh
 
     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 <https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html>
 */
@@ -14,70 +13,6 @@ package jh
 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
-    #partial switch size {
-        case ._28: ctx.hashbitlen = 224
-        case ._32: ctx.hashbitlen = 256
-        case ._48: ctx.hashbitlen = 384
-        case ._64: ctx.hashbitlen = 512
-    }
-    _hash_impl.internal_ctx = ctx
-    _hash_impl.hash_size    = size
-}
-
 /*
     High level API
 */
@@ -91,22 +26,46 @@ hash_string_224 :: proc(data: string) -> [28]byte {
 // 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: [28]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 224
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [28]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 224
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    _create_jh_ctx(._28)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -125,22 +84,46 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 256
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 256
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_jh_ctx(._32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -159,22 +142,46 @@ hash_string_384 :: proc(data: string) -> [48]byte {
 // 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: [48]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 384
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [48]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 384
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    _create_jh_ctx(._48)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -193,22 +200,46 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 512
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: Jh_Context
+    ctx.hashbitlen = 512
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_jh_ctx(._64)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -222,201 +253,98 @@ hash_512 :: proc {
     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
+init :: proc(ctx: ^Jh_Context) {
+    assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
+    ctx.H[1] = byte(ctx.hashbitlen)      & 0xff
+    ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff
+    F8(ctx)
 }
 
-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
-    }
-}
+update :: proc(ctx: ^Jh_Context, data: []byte) {
+    databitlen     := u64(len(data)) * 8
+    ctx.databitlen += databitlen
+    i              := u64(0)
 
-hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), ok
-        }
+    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
     }
-    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[:])
+    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)
+        F8(ctx)
+        ctx.buffer_size = 0
     }
-    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
+    for databitlen >= 512 {
+        copy(ctx.buffer[:], data[i:i + 64])
+        F8(ctx)
+        i += 64
+        databitlen -= 512
     }
-}
 
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
+    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
     }
-    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 :: proc(ctx: ^Jh_Context, hash: []byte) {
+    if ctx.databitlen & 0x1ff == 0 {
+        for i := 0; i < 64; i += 1 {
+            ctx.buffer[i] = 0
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
-
-hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
+        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
+        F8(ctx)
     } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), 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])
-            } 
+        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
+            }
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
-
-hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
+        ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7))
+        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
+        F8(ctx)
     }
-    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)
+    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])
     }
 }
 
@@ -424,7 +352,7 @@ _final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
     JH implementation
 */
 
-JH_ROUNDCONSTANT_ZERO := [64]byte {
+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,
@@ -435,7 +363,7 @@ JH_ROUNDCONSTANT_ZERO := [64]byte {
     0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa,
 }
 
-JH_S := [2][16]byte {
+SBOX := [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},
 }
@@ -450,7 +378,7 @@ Jh_Context :: struct {
     buffer:        [64]byte,
 }
 
-JH_E8_finaldegroup :: proc(ctx: ^Jh_Context) {
+E8_finaldegroup :: proc(ctx: ^Jh_Context) {
     t0,t1,t2,t3: byte
     tem: [256]byte
     for i := 0; i < 128; i += 1 {
@@ -473,11 +401,11 @@ JH_E8_finaldegroup :: proc(ctx: ^Jh_Context) {
     }
 }
 
-jh_update_roundconstant :: proc(ctx: ^Jh_Context) {
+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]]
+        tem[i] = SBOX[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
@@ -499,14 +427,14 @@ jh_update_roundconstant :: proc(ctx: ^Jh_Context) {
     }
 }
 
-JH_R8 :: proc(ctx: ^Jh_Context) {
+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]]
+        tem[i] = SBOX[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
@@ -528,7 +456,7 @@ JH_R8 :: proc(ctx: ^Jh_Context) {
     }
 }
 
-JH_E8_initialgroup :: proc(ctx: ^Jh_Context) {
+E8_initialgroup :: proc(ctx: ^Jh_Context) {
     t0, t1, t2, t3: byte
     tem:            [256]byte
     for i := u32(0); i < 256; i += 1 {
@@ -544,118 +472,24 @@ JH_E8_initialgroup :: proc(ctx: ^Jh_Context) {
     }
 }
 
-JH_E8 :: proc(ctx: ^Jh_Context) {
+E8 :: proc(ctx: ^Jh_Context) {
     for i := 0; i < 64; i += 1 {
-        ctx.roundconstant[i] = JH_ROUNDCONSTANT_ZERO[i]
+        ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i]
     }
-    JH_E8_initialgroup(ctx)
+    E8_initialgroup(ctx)
     for i := 0; i < 42; i += 1 {
-        JH_R8(ctx)
-        jh_update_roundconstant(ctx)
+        R8(ctx)
+        update_roundconstant(ctx)
     }
-    JH_E8_finaldegroup(ctx)
+    E8_finaldegroup(ctx)
 }
 
-JH_F8 :: proc(ctx: ^Jh_Context) {
+F8 :: proc(ctx: ^Jh_Context) {
     for i := 0; i < 64; i += 1 {
         ctx.H[i] ~= ctx.buffer[i]
     }
-    JH_E8(ctx)
+    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])
-    }
-}

+ 136 - 284
core/crypto/keccak/keccak.odin

@@ -6,7 +6,6 @@ package keccak
 
     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.
@@ -15,57 +14,8 @@ package keccak
 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
@@ -80,22 +30,48 @@ hash_string_224 :: proc(data: string) -> [28]byte {
 // hash_bytes_224 will hash the given input and return the
 // computed hash
 hash_bytes_224 :: proc(data: []byte) -> [28]byte {
-    _create_keccak_ctx(28)
-    return _hash_impl->hash_bytes_28(data)
+    hash: [28]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 28
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_keccak_ctx(28)
-    return _hash_impl->hash_stream_28(s)
+    hash: [28]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 28
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    _create_keccak_ctx(28)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -114,22 +90,48 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // hash_bytes_256 will hash the given input and return the
 // computed hash
 hash_bytes_256 :: proc(data: []byte) -> [32]byte {
-    _create_keccak_ctx(32)
-    return _hash_impl->hash_bytes_32(data)
+    hash: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_keccak_ctx(32)
-    return _hash_impl->hash_stream_32(s)
+    hash: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_keccak_ctx(32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -148,22 +150,48 @@ hash_string_384 :: proc(data: string) -> [48]byte {
 // hash_bytes_384 will hash the given input and return the
 // computed hash
 hash_bytes_384 :: proc(data: []byte) -> [48]byte {
-    _create_keccak_ctx(48)
-    return _hash_impl->hash_bytes_48(data)
+    hash: [48]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 48
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_keccak_ctx(48)
-    return _hash_impl->hash_stream_48(s)
+    hash: [48]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 48
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    _create_keccak_ctx(48)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -182,22 +210,48 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // hash_bytes_512 will hash the given input and return the
 // computed hash
 hash_bytes_512 :: proc(data: []byte) -> [64]byte {
-    _create_keccak_ctx(64)
-    return _hash_impl->hash_bytes_64(data)
+    hash: [64]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 64
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_keccak_ctx(64)
-    return _hash_impl->hash_stream_64(s)
+    hash: [64]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 64
+    ctx.is_keccak = true
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_keccak_ctx(64)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -211,219 +265,17 @@ hash_512 :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
-}
+Sha3_Context :: _sha3.Sha3_Context
 
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
+init :: proc(ctx: ^_sha3.Sha3_Context) {
+    ctx.is_keccak = true
+    _sha3.init(ctx)
 }
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
+update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
+    _sha3.update(ctx, data)
 }
 
-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, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
-
-@(private)
-_create_keccak_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_keccak_ctx(28)
-        case ._32: _create_keccak_ctx(32)
-        case ._48: _create_keccak_ctx(48)
-        case ._64: _create_keccak_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)
-    }
+final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
+    _sha3.final(ctx, hash)
 }

+ 49 - 151
core/crypto/md2/md2.odin

@@ -6,7 +6,6 @@ package md2
 
     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 <https://datatracker.ietf.org/doc/html/rfc1319>
 */
@@ -14,48 +13,6 @@ package md2
 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
 */
@@ -69,22 +26,44 @@ hash_string :: proc(data: string) -> [16]byte {
 // 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: [16]byte
+	ctx: Md2_Context
+    // init(&ctx) No-op
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [16]byte
+	ctx: Md2_Context
+	// init(&ctx) No-op
+	buf := make([]byte, 512)
+	defer delete(buf)
+	read := 1
+	for read > 0 {
+	    read, _ = s->impl_read(buf)
+	    if read > 0 {
+			update(&ctx, buf[:read])
+	    } 
+	}
+	final(&ctx, hash[:])
+	return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-	_create_md2_ctx()
-    return _hash_impl->hash_file_16(hd, load_at_once)
+	if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash :: proc {
@@ -98,85 +77,32 @@ hash :: proc {
     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, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), 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
+@(warning="Init is a no-op for MD2")
+init :: proc(ctx: ^Md2_Context) {
+	// No action needed here
 }
 
-@(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)
-    }
+update :: 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
+		}
+	}
 }
 
-@(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)
+final :: 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
     }
-}
-
-@(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)
+	transform(ctx, ctx.data[:])
+	transform(ctx, ctx.checksum[:])
+    for i := 0; i < 16; i += 1 {
+        hash[i] = ctx.state[i]
     }
 }
 
@@ -232,31 +158,3 @@ transform :: proc(ctx: ^Md2_Context, data: []byte) {
 		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]
-    }
-}

+ 73 - 174
core/crypto/md4/md4.odin

@@ -16,47 +16,6 @@ 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
@@ -71,22 +30,44 @@ hash_string :: proc(data: string) -> [16]byte {
 // 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: [16]byte
+    ctx: Md4_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [16]byte
+    ctx: Md4_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_md4_ctx()
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash :: proc {
@@ -100,85 +81,61 @@ hash :: proc {
     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
+init :: proc(ctx: ^Md4_Context) {
+    ctx.state[0] = 0x67452301
+    ctx.state[1] = 0xefcdab89
+    ctx.state[2] = 0x98badcfe
+    ctx.state[3] = 0x10325476
 }
 
-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])
-            } 
+update :: 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(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
     }
 }
 
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
+final :: 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)
     }
-    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)
-    }
-}
+    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[:])
 
-@(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)
+    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
     }
 }
 
@@ -282,61 +239,3 @@ transform :: proc(ctx: ^Md4_Context, data: []byte) {
     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
-    }
-}

+ 75 - 177
core/crypto/md5/md5.odin

@@ -6,7 +6,6 @@ package md5
 
     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 <https://datatracker.ietf.org/doc/html/rfc1321>
 */
@@ -16,47 +15,6 @@ 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
@@ -71,22 +29,44 @@ hash_string :: proc(data: string) -> [16]byte {
 // 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: [16]byte
+    ctx: Md5_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [16]byte
+    ctx: Md5_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_md5_ctx()
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash :: proc {
@@ -100,85 +80,63 @@ hash :: proc {
     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
-    }
+init :: proc(ctx: ^Md5_Context) {
+    ctx.state[0] = 0x67452301
+    ctx.state[1] = 0xefcdab89
+    ctx.state[2] = 0x98badcfe
+    ctx.state[3] = 0x10325476
 }
 
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
+update :: 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
         }
     }
-    return [16]byte{}, false
 }
 
-@(private)
-_create_md5_ctx :: #force_inline proc() {
-    ctx: Md5_Context
-    _hash_impl.internal_ctx = ctx
-    _hash_impl.hash_size    = ._16
-}
+final :: proc(ctx: ^Md5_Context, hash: []byte){
+    i : u32
+    i = ctx.datalen
 
-@(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)
+    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)
     }
-}
 
-@(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)
-    }
-}
+    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[:])
 
-@(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)
+    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
     }
 }
 
@@ -303,63 +261,3 @@ transform :: proc(ctx: ^Md5_Context, data: []byte) {
     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
-    }
-}

+ 202 - 416
core/crypto/ripemd/ripemd.odin

@@ -6,7 +6,6 @@ package ripemd
 
     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 <https://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
 */
@@ -15,56 +14,6 @@ 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
@@ -79,22 +28,44 @@ hash_string_128 :: proc(data: string) -> [16]byte {
 // 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: [16]byte
+    ctx: Ripemd128_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [16]byte
+    ctx: Ripemd128_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_128 will read the file provided by the given handle
 // and compute a hash
 hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_ripemd_ctx(16)
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_128(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_128(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash_128 :: proc {
@@ -113,22 +84,44 @@ hash_string_160 :: proc(data: string) -> [20]byte {
 // 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: [20]byte
+    ctx: Ripemd160_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [20]byte
+    ctx: Ripemd160_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_160 will read the file provided by the given handle
 // and compute a hash
 hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    _create_ripemd_ctx(20)
-    return _hash_impl->hash_file_20(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_160(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_160(buf[:]), ok
+        }
+    }
+    return [20]byte{}, false
 }
 
 hash_160 :: proc {
@@ -147,22 +140,44 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Ripemd256_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Ripemd256_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_ripemd_ctx(32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -181,22 +196,44 @@ hash_string_320 :: proc(data: string) -> [40]byte {
 // 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: [40]byte
+    ctx: Ripemd320_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [40]byte
+    ctx: Ripemd320_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_320 will read the file provided by the given handle
 // and compute a hash
 hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([40]byte, bool) {
-    _create_ripemd_ctx(40)
-    return _hash_impl->hash_file_40(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_320(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_320(buf[:]), ok
+        }
+    }
+    return [40]byte{}, false
 }
 
 hash_320 :: proc {
@@ -206,261 +243,122 @@ hash_320 :: proc {
     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
-    }
-}
+/*
+    Low level API
+*/
 
-hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_16(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_16(ctx, buf[:]), ok
-        }
+init :: 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
     }
-    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
-}
+update :: proc(ctx: ^$T, data: []byte) {
+    ctx.tc += u64(len(data))
+    data := data
+    if ctx.nx > 0 {
+        n := len(data)
 
-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])
-            } 
+        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
+            }
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
-    }
-}
 
-hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_20(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_20(ctx, buf[:]), ok
+        for i := 0; i < n; i += 1 {
+            ctx.x[ctx.nx + i] = data[i]
         }
-    }
-    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])
-            } 
+        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
+            }
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
+        data = data[n:]
     }
-}
-
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
-        }
+    n := block(ctx, data)
+    data = data[n:]
+    if len(data) > 0 {
+        ctx.nx = copy(ctx.x[:], data)
     }
-    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
-}
+final :: proc(ctx: ^$T, hash: []byte) {
+    d := ctx
+    tc := d.tc
+    tmp: [64]byte
+    tmp[0] = 0x80
 
-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
+    if tc % 64 < 56 {
+        update(d, tmp[0:56 - tc % 64])
     } else {
-        return hash, false
+        update(d, tmp[0:64 + 56 - tc % 64])
     }
-}
 
-hash_file_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([40]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_40(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_40(ctx, buf[:]), ok
-        }
+    tc <<= 3
+    for i : u32 = 0; i < 8; i += 1 {
+        tmp[i] = byte(tc >> (8 * i))
     }
-    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
-    }
-}
+    update(d, tmp[0:8])
 
-@(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)
-            }
+    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
     }
-}
 
-@(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)
-            }
+    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[:])
 }
 
-@(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
@@ -574,20 +472,6 @@ RIPEMD_160_R1 := [80]uint {
 	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)
@@ -948,101 +832,3 @@ ripemd_320_block :: proc(ctx: ^$T, p: []byte) -> int {
 	}
 	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[:])
-}

+ 84 - 187
core/crypto/sha1/sha1.odin

@@ -6,7 +6,6 @@ package sha1
 
     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 <https://datatracker.ietf.org/doc/html/rfc3174>
 */
@@ -16,52 +15,10 @@ 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 {
@@ -71,22 +28,44 @@ hash_string :: proc(data: string) -> [20]byte {
 // 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: [20]byte
+    ctx: Sha1_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [20]byte
+    ctx: Sha1_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-	_create_sha1_ctx()
-    return _hash_impl->hash_file_20(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [20]byte{}, false
 }
 
 hash :: proc {
@@ -100,86 +79,70 @@ hash :: proc {
     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)
+init :: 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
 }
 
-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
+update :: 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
+		}
+	}
 }
 
-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
-    }
-}
+final :: proc(ctx: ^Sha1_Context, hash: []byte) {
+	i := ctx.datalen
 
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
+	if ctx.datalen < 56 {
+		ctx.data[i] = 0x80
+        i += 1
+        for i < 56 {
+            ctx.data[i] = 0x00
+            i += 1
         }
-    }
-    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)
-    }
-}
+	}
+	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)
+	}
 
-@(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)
-    }
-}
+	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[:])
 
-@(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)
-    }
+	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
+	}
 }
 
 /*
@@ -258,69 +221,3 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) {
 	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
-	}
-}

+ 215 - 407
core/crypto/sha2/sha2.odin

@@ -6,7 +6,6 @@ package sha2
 
     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 <https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf>
     and in RFC 3874 <https://datatracker.ietf.org/doc/html/rfc3874>
@@ -17,72 +16,6 @@ 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
@@ -97,22 +30,46 @@ hash_string_224 :: proc(data: string) -> [28]byte {
 // 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: [28]byte
+	ctx: Sha256_Context
+    ctx.is224 = true
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [28]byte
+    ctx: Sha512_Context
+    ctx.is384 = false
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-	_create_sha256_ctx(true)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -131,22 +88,46 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+	ctx: Sha256_Context
+    ctx.is224 = false
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Sha512_Context
+    ctx.is384 = false
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-	_create_sha256_ctx(false)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -165,22 +146,46 @@ hash_string_384 :: proc(data: string) -> [48]byte {
 // 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: [48]byte
+	ctx: Sha512_Context
+    ctx.is384 = true
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [48]byte
+    ctx: Sha512_Context
+    ctx.is384 = true
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-	_create_sha512_ctx(true)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -199,22 +204,46 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+	ctx: Sha512_Context
+    ctx.is384 = false
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: Sha512_Context
+    ctx.is384 = false
+	init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-	_create_sha512_ctx(false)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -228,225 +257,121 @@ hash_512 :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
-}
-
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
+init :: 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
+        }
+    }
 }
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
-}
+update :: proc(ctx: ^$T, data: []byte) {
+    length := uint(len(data))
+    block_nb: uint
+    new_len, rem_len, tmp_len: uint
+    shifted_message := make([]byte, length)
 
-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[:])
+    when T == Sha256_Context {
+        CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE
+    } else when T == Sha512_Context {
+        CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE
     }
-    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
-    }
-}
+    tmp_len = CURR_BLOCK_SIZE - ctx.length
+    rem_len = length < tmp_len ? length : tmp_len
+    copy(ctx.block[ctx.length:], data[:rem_len])
 
-hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), ok
-        }
+    if ctx.length + length < CURR_BLOCK_SIZE {
+        ctx.length += length
+        return
     }
-    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
-}
+    new_len = length - rem_len
+    block_nb = new_len / CURR_BLOCK_SIZE
+    shifted_message = data[rem_len:]
 
-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
-    }
-}
+    sha2_transf(ctx, ctx.block[:], 1)
+    sha2_transf(ctx, shifted_message, block_nb)
 
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
-        }
-    }
-    return [32]byte{}, false
-}
+    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])}
 
-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
+    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}
 }
 
-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
-    }
-}
+final :: proc(ctx: ^$T, hash: []byte) {
+    block_nb, pm_len, len_b: u32
+    i: i32
 
-hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), ok
-        }
-    }
-    return [48]byte{}, false
-}
+    when T == Sha256_Context      {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE}
+    else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE}
 
-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
-}
+    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)}
 
-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
-    }
-}
+    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}
 
-hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
+    mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length))
+    ctx.block[ctx.length] = 0x80
 
-@(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)
-        }
-    }
-}
+    util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b)
 
-@(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)
-            }
-    }
-}
+    sha2_transf(ctx, ctx.block[:], uint(block_nb))
 
-@(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)
-            }
-    }
+    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])}
+        } 
+    } 
 }
 
 /*
@@ -590,50 +515,6 @@ 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
@@ -710,76 +591,3 @@ sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) {
 		}
 	}
 }
-
-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])}
-		} 
-	} 
-}

+ 127 - 284
core/crypto/sha3/sha3.odin

@@ -6,7 +6,6 @@ package sha3
 
     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.
@@ -15,58 +14,8 @@ 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_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
 */
@@ -80,22 +29,46 @@ hash_string_224 :: proc(data: string) -> [28]byte {
 // 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: [28]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 28
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [28]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 28
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_224 will read the file provided by the given handle
 // and compute a hash
 hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    _create_sha3_ctx(28)
-    return _hash_impl->hash_file_28(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_224(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_224(buf[:]), ok
+        }
+    }
+    return [28]byte{}, false
 }
 
 hash_224 :: proc {
@@ -114,22 +87,46 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_sha3_ctx(32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -148,22 +145,46 @@ hash_string_384 :: proc(data: string) -> [48]byte {
 // 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: [48]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 48
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [48]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 48
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_384 will read the file provided by the given handle
 // and compute a hash
 hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    _create_sha3_ctx(48)
-    return _hash_impl->hash_file_48(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_384(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_384(buf[:]), ok
+        }
+    }
+    return [48]byte{}, false
 }
 
 hash_384 :: proc {
@@ -182,22 +203,46 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 64
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 64
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_sha3_ctx(64)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -211,218 +256,16 @@ hash_512 :: proc {
     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, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_28(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_28(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_48(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_48(ctx, buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
+Sha3_Context :: _sha3.Sha3_Context
 
-@(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
-    }
+init :: proc(ctx: ^_sha3.Sha3_Context) {
+    _sha3.init(ctx)
 }
 
-@(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)
-    }
+update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
+    _sha3.update(ctx, data)
 }
 
-@(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)
-    }
+final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
+    _sha3.final(ctx, hash)
 }

+ 72 - 185
core/crypto/shake/shake.odin

@@ -6,7 +6,6 @@ package shake
 
     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.
@@ -15,52 +14,8 @@ package shake
 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
 */
@@ -74,22 +29,48 @@ hash_string_128 :: proc(data: string) -> [16]byte {
 // hash_bytes_128 will hash the given input and return the
 // computed hash
 hash_bytes_128 :: proc(data: []byte) -> [16]byte {
-    _create_shake_ctx(16)
-    return _hash_impl->hash_bytes_16(data)
+    hash: [16]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 16
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.shake_xof(&ctx)
+    _sha3.shake_out(&ctx, hash[:])
+    return hash
 }
 
 // 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_shake_ctx(16)
-    return _hash_impl->hash_stream_16(s)
+    hash: [16]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 16
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.shake_xof(&ctx)
+    _sha3.shake_out(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_128 will read the file provided by the given handle
 // and compute a hash
 hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_shake_ctx(16)
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_128(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_128(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash_128 :: proc {
@@ -108,22 +89,48 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // hash_bytes_256 will hash the given input and return the
 // computed hash
 hash_bytes_256 :: proc(data: []byte) -> [32]byte {
-    _create_shake_ctx(32)
-    return _hash_impl->hash_bytes_32(data)
+    hash: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    _sha3.init(&ctx)
+    _sha3.update(&ctx, data)
+    _sha3.shake_xof(&ctx)
+    _sha3.shake_out(&ctx, hash[:])
+    return hash
 }
 
 // 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_shake_ctx(32)
-    return _hash_impl->hash_stream_32(s)
+    hash: [32]byte
+    ctx: _sha3.Sha3_Context
+    ctx.mdlen = 32
+    _sha3.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _sha3.update(&ctx, buf[:read])
+        } 
+    }
+    _sha3.shake_xof(&ctx)
+    _sha3.shake_out(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_shake_ctx(32)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -137,137 +144,17 @@ hash_256 :: proc {
     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
-}
+Sha3_Context :: _sha3.Sha3_Context
 
-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
-    }
+init :: proc(ctx: ^_sha3.Sha3_Context) {
+    _sha3.init(ctx)
 }
 
-hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_16(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_16(ctx, buf[:]), ok
-        }
-    }
-    return [16]byte{}, false
+update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
+    _sha3.update(ctx, data)
 }
 
-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, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
-        }
-    }
-    return [32]byte{}, false
-}
-
-@(private)
-_create_shake_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_shake_ctx(16)
-        case ._32: _create_shake_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[:])
-    }
+final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
+    _sha3.shake_xof(ctx)
+    _sha3.shake_out(ctx, hash[:])
 }

+ 0 - 487
core/crypto/skein/skein.odin

@@ -1,487 +0,0 @@
-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 <https://www.schneier.com/academic/skein/>
-    
-    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 read the file provided by the given handle
-// and compute a hash
-hash_skein256_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    _create_skein256_ctx(bit_size)
-    return _hash_impl->hash_file_slice(hd, 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 read the file provided by the given handle
-// and compute a hash
-hash_skein512_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    _create_skein512_ctx(bit_size)
-    return _hash_impl->hash_file_slice(hd, 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 read the file provided by the given handle
-// and compute a hash
-hash_skein1024_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    _create_skein1024_ctx(bit_size)
-    return _hash_impl->hash_file_slice(hd, 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, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    if !load_at_once {
-        return hash_stream_skein256_odin(ctx, os.stream_from_handle(hd), bit_size, allocator)
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_skein256_odin(ctx, buf[:], bit_size, allocator), 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, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    if !load_at_once {
-        return hash_stream_skein512_odin(ctx, os.stream_from_handle(hd), bit_size, allocator)
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_skein512_odin(ctx, buf[:], bit_size, allocator), 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, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) {
-    if !load_at_once {
-        return hash_stream_skein512_odin(ctx, os.stream_from_handle(hd), bit_size, allocator)
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_skein512_odin(ctx, buf[:], bit_size, allocator), 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) {
-
-}

+ 74 - 180
core/crypto/sm3/sm3.odin

@@ -6,7 +6,6 @@ package sm3
 
     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 <https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02>
 */
@@ -15,51 +14,6 @@ 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
@@ -70,22 +24,44 @@ hash_string :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Sm3_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Sm3_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true 
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    _create_sm3_ctx()
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash :: proc {
@@ -99,86 +75,64 @@ hash :: proc {
     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)
+init :: 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]
 }
 
-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
-}
+update :: proc(ctx: ^Sm3_Context, data: []byte) {
+    data := data
+    ctx.length += u64(len(data))
 
-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])
-            } 
+    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
         }
-        final_odin(&c, hash[:])
-        return hash, true
-    } else {
-        return hash, false
+        data = data[n:]
     }
-}
-
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
-        }
+    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[:]))
     }
-    return [32]byte{}, false
 }
 
-@(private)
-_create_sm3_ctx :: #force_inline proc() {
-    ctx: Sm3_Context
-    _hash_impl.internal_ctx = ctx
-    _hash_impl.hash_size    = ._32
-}
+final :: proc(ctx: ^Sm3_Context, hash: []byte) {
+    length := ctx.length
 
-@(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)
+    pad: [64]byte
+    pad[0] = 0x80
+    if length % 64 < 56 {
+        update(ctx, pad[0: 56 - length % 64])
+    } else {
+        update(ctx, pad[0: 64 + 56 - length % 64])
     }
-}
 
-@(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)
-    }
-}
+    length <<= 3
+    util.PUT_U64_BE(pad[:], length)
+    update(ctx, pad[0: 8])
+    assert(ctx.bitlength == 0)
 
-@(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)
-    }
+    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])
 }
 
 /*
@@ -200,17 +154,6 @@ IV := [8]u32 {
     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
 
@@ -282,52 +225,3 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) {
     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])
-}

+ 106 - 229
core/crypto/streebog/streebog.odin

@@ -6,7 +6,6 @@ package streebog
 
     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 <https://datatracker.ietf.org/doc/html/rfc6986>
 */
@@ -15,58 +14,6 @@ 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
@@ -81,22 +28,46 @@ hash_string_256 :: proc(data: string) -> [32]byte {
 // 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: [32]byte
+    ctx: Streebog_Context
+    ctx.is256 = true
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [32]byte
+    ctx: Streebog_Context
+    ctx.is256 = true
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_256 will read the file provided by the given handle
 // and compute a hash
 hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-	_create_streebog_ctx(true)
-    return _hash_impl->hash_file_32(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_256(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_256(buf[:]), ok
+        }
+    }
+    return [32]byte{}, false
 }
 
 hash_256 :: proc {
@@ -115,22 +86,44 @@ hash_string_512 :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+    ctx: Streebog_Context
+    init(&ctx)
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+    ctx: Streebog_Context
+    init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            update(&ctx, buf[:read])
+        } 
+    }
+    final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_512 will read the file provided by the given handle
 // and compute a hash
 hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-	_create_streebog_ctx(false)
-    return _hash_impl->hash_file_64(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_512(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_512(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash_512 :: proc {
@@ -144,120 +137,64 @@ hash_512 :: proc {
     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
+init :: 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
 }
 
-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
-    }
-}
+update :: 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
+	}
 
-hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_32(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_32(ctx, buf[:]), ok
-        }
-    }
-    return [32]byte{}, false
+	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
+		}
+	}
 }
 
-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
-}
+final :: 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
 
-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
-    }
-}
+	padding(ctx)
 
-hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_64(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_64(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
+	G(ctx.h[:], ctx.n[:], ctx.buffer[:])
 
-@(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)
-    }
-}
+	add_mod_512(ctx.n[:], t[:], ctx.n[:])
+	add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:])
 
-@(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)
-    }
-}
+	G(ctx.h[:], ctx.v_0[:], ctx.n[:])
+	G(ctx.h[:], ctx.v_0[:], ctx.sigma[:])
 
-@(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)
-    }
+	if ctx.is256 {
+		copy(hash[:], ctx.h[32:])
+	} else {
+		copy(hash[:], ctx.h[:])
+	}
 }
 
 /*
@@ -534,63 +471,3 @@ padding :: proc(ctx: ^Streebog_Context) {
 		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[:])
-	}
-}

+ 101 - 219
core/crypto/tiger/tiger.odin

@@ -6,7 +6,6 @@ package tiger
 
     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 <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
 */
@@ -14,55 +13,8 @@ package tiger
 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
 */
@@ -76,22 +28,46 @@ hash_string_128 :: proc(data: string) -> [16]byte {
 // hash_bytes_128 will hash the given input and return the
 // computed hash
 hash_bytes_128 :: proc(data: []byte) -> [16]byte {
-    _create_tiger_ctx(16)
-    return _hash_impl->hash_bytes_16(data)
+    hash: [16]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger_ctx(16)
-    return _hash_impl->hash_stream_16(s)
+    hash: [16]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_128 will read the file provided by the given handle
 // and compute a hash
 hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_tiger_ctx(16)
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_128(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_128(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash_128 :: proc {
@@ -110,22 +86,46 @@ hash_string_160 :: proc(data: string) -> [20]byte {
 // hash_bytes_160 will hash the given input and return the
 // computed hash
 hash_bytes_160 :: proc(data: []byte) -> [20]byte {
-    _create_tiger_ctx(20)
-    return _hash_impl->hash_bytes_20(data)
+    hash: [20]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger_ctx(20)
-    return _hash_impl->hash_stream_20(s)
+    hash: [20]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_160 will read the file provided by the given handle
 // and compute a hash
 hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    _create_tiger_ctx(20)
-    return _hash_impl->hash_file_20(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_160(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_160(buf[:]), ok
+        }
+    }
+    return [20]byte{}, false
 }
 
 hash_160 :: proc {
@@ -144,188 +144,70 @@ hash_string_192 :: proc(data: string) -> [24]byte {
 // hash_bytes_192 will hash the given input and return the
 // computed hash
 hash_bytes_192 :: proc(data: []byte) -> [24]byte {
-    _create_tiger_ctx(24)
-    return _hash_impl->hash_bytes_24(data)
+    hash: [24]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger_ctx(24)
-    return _hash_impl->hash_stream_24(s)
+    hash: [24]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 1
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_192 will read the file provided by the given handle
 // and compute a hash
 hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) {
-    _create_tiger_ctx(24)
-    return _hash_impl->hash_file_24(hd, 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, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
     if !load_at_once {
-        return hash_stream_odin_16(ctx, os.stream_from_handle(hd))
+        return hash_stream_192(os.stream_from_handle(hd))
     } else {
         if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_16(ctx, buf[:]), ok
+            return hash_bytes_192(buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_20(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_20(ctx, buf[:]), ok
-        }
-    }
-    return [20]byte{}, false
+    return [24]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_192 :: proc {
+    hash_stream_192,
+    hash_file_192,
+    hash_bytes_192,
+    hash_string_192,
 }
 
-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
-    }
-}
+/*
+    Low level API
+*/
 
-hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_24(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_24(ctx, buf[:]), ok
-        }
-    }
-    return [24]byte{}, false
-}
+Tiger_Context :: _tiger.Tiger_Context
 
-@(private)
-_create_tiger_ctx :: #force_inline proc(hash_size: int) {
-    ctx: _tiger.Tiger_Context
+init :: proc(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
-    }
+    _tiger.init(ctx)
 }
 
-@(private)
-_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) {
-    #partial switch ctx.hash_size {
-        case ._16: _create_tiger_ctx(16)
-        case ._20: _create_tiger_ctx(20)
-        case ._24: _create_tiger_ctx(24)
-    }
-    if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok {
-        _tiger.init_odin(&c)
-    }
+update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) {
+    _tiger.update(ctx, data)
 }
 
-@(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)
-    }
-}
+final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) {
+    _tiger.final(ctx, hash)
+}

+ 100 - 218
core/crypto/tiger2/tiger2.odin

@@ -6,7 +6,6 @@ package tiger2
 
     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 <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
 */
@@ -14,55 +13,8 @@ package tiger2
 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
 */
@@ -76,22 +28,46 @@ hash_string_128 :: proc(data: string) -> [16]byte {
 // hash_bytes_128 will hash the given input and return the
 // computed hash
 hash_bytes_128 :: proc(data: []byte) -> [16]byte {
-    _create_tiger2_ctx(16)
-    return _hash_impl->hash_bytes_16(data)
+    hash: [16]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger2_ctx(16)
-    return _hash_impl->hash_stream_16(s)
+    hash: [16]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_128 will read the file provided by the given handle
 // and compute a hash
 hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
-    _create_tiger2_ctx(16)
-    return _hash_impl->hash_file_16(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_128(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_128(buf[:]), ok
+        }
+    }
+    return [16]byte{}, false
 }
 
 hash_128 :: proc {
@@ -110,22 +86,46 @@ hash_string_160 :: proc(data: string) -> [20]byte {
 // hash_bytes_160 will hash the given input and return the
 // computed hash
 hash_bytes_160 :: proc(data: []byte) -> [20]byte {
-    _create_tiger2_ctx(20)
-    return _hash_impl->hash_bytes_20(data)
+    hash: [20]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger2_ctx(20)
-    return _hash_impl->hash_stream_20(s)
+    hash: [20]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_160 will read the file provided by the given handle
 // and compute a hash
 hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    _create_tiger2_ctx(20)
-    return _hash_impl->hash_file_20(hd, load_at_once)
+    if !load_at_once {
+        return hash_stream_160(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes_160(buf[:]), ok
+        }
+    }
+    return [20]byte{}, false
 }
 
 hash_160 :: proc {
@@ -144,188 +144,70 @@ hash_string_192 :: proc(data: string) -> [24]byte {
 // hash_bytes_192 will hash the given input and return the
 // computed hash
 hash_bytes_192 :: proc(data: []byte) -> [24]byte {
-    _create_tiger2_ctx(24)
-    return _hash_impl->hash_bytes_24(data)
+    hash: [24]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    _tiger.update(&ctx, data)
+    _tiger.final(&ctx, hash[:])
+    return hash
 }
 
 // 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_tiger2_ctx(24)
-    return _hash_impl->hash_stream_24(s)
+    hash: [24]byte
+    ctx: _tiger.Tiger_Context
+    ctx.ver = 2
+    _tiger.init(&ctx)
+    buf := make([]byte, 512)
+    defer delete(buf)
+    read := 1
+    for read > 0 {
+        read, _ = s->impl_read(buf)
+        if read > 0 {
+            _tiger.update(&ctx, buf[:read])
+        } 
+    }
+    _tiger.final(&ctx, hash[:])
+    return hash, true
 }
 
 // hash_file_192 will read the file provided by the given handle
 // and compute a hash
 hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) {
-    _create_tiger2_ctx(24)
-    return _hash_impl->hash_file_24(hd, 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, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) {
     if !load_at_once {
-        return hash_stream_odin_16(ctx, os.stream_from_handle(hd))
+        return hash_stream_192(os.stream_from_handle(hd))
     } else {
         if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_16(ctx, buf[:]), ok
+            return hash_bytes_192(buf[:]), 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, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_20(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_20(ctx, buf[:]), ok
-        }
-    }
-    return [20]byte{}, false
+    return [24]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_192 :: proc {
+    hash_stream_192,
+    hash_file_192,
+    hash_bytes_192,
+    hash_string_192,
 }
 
-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
-    }
-}
+/*
+    Low level API
+*/
 
-hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin_24(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin_24(ctx, buf[:]), ok
-        }
-    }
-    return [24]byte{}, false
-}
+Tiger_Context :: _tiger.Tiger_Context
 
-@(private)
-_create_tiger2_ctx :: #force_inline proc(hash_size: int) {
-    ctx: _tiger.Tiger_Context
+init :: proc(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
-    }
+    _tiger.init(ctx)
 }
 
-@(private)
-_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) {
-    #partial switch ctx.hash_size {
-        case ._16: _create_tiger2_ctx(16)
-        case ._20: _create_tiger2_ctx(20)
-        case ._24: _create_tiger2_ctx(24)
-    }
-    if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok {
-        _tiger.init_odin(&c)
-    }
+update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) {
+    _tiger.update(ctx, data)
 }
 
-@(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)
-    }
+final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) {
+    _tiger.final(ctx, hash)
 }

+ 115 - 201
core/crypto/whirlpool/whirlpool.odin

@@ -6,7 +6,6 @@ package whirlpool
 
     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 <https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html>
 */
@@ -14,48 +13,8 @@ package whirlpool
 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
 */
@@ -69,22 +28,44 @@ hash_string :: proc(data: string) -> [64]byte {
 // 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: [64]byte
+	ctx: Whirlpool_Context
+    // init(&ctx) No-op
+    update(&ctx, data)
+    final(&ctx, hash[:])
+    return hash
 }
 
 // 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: [64]byte
+	ctx: Whirlpool_Context
+	// init(&ctx) No-op
+	buf := make([]byte, 512)
+	defer delete(buf)
+	read := 1
+	for read > 0 {
+	    read, _ = s->impl_read(buf)
+	    if read > 0 {
+			update(&ctx, buf[:read])
+	    } 
+	}
+	final(&ctx, hash[:])
+	return hash, true
 }
 
 // hash_file will read the file provided by the given handle
 // and compute a hash
 hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    _create_whirlpool_ctx()
-    return _hash_impl->hash_file_64(hd, load_at_once)
+	if !load_at_once {
+        return hash_stream(os.stream_from_handle(hd))
+    } else {
+        if buf, ok := os.read_entire_file(hd); ok {
+            return hash_bytes(buf[:]), ok
+        }
+    }
+    return [64]byte{}, false
 }
 
 hash :: proc {
@@ -98,76 +79,103 @@ hash :: proc {
     Low level API
 */
 
-init :: proc(ctx: ^_ctx.Hash_Context) {
-    _hash_impl->init()
+@(warning="Init is a no-op for Whirlpool")
+init :: proc(ctx: ^Whirlpool_Context) {
+	// No action needed here
 }
 
-update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) {
-    _hash_impl->update(data)
-}
+update :: 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
 
-final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) {
-    _hash_impl->final(hash)
-}
+	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
+	}
 
-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
-}
+	for source_bits > 8 {
+		b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap)))
 
-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
-    }
-}
+		ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem)
+		ctx.buffer_pos += 1
+		ctx.buffer_bits += int(8 - buffer_rem)
 
-hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) {
-    if !load_at_once {
-        return hash_stream_odin(ctx, os.stream_from_handle(hd))
-    } else {
-        if buf, ok := os.read_entire_file(hd); ok {
-            return hash_bytes_odin(ctx, buf[:]), ok
-        }
-    }
-    return [64]byte{}, false
-}
+		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
+	}
 
-@(private)
-_create_whirlpool_ctx :: #force_inline proc() {
-    ctx: Whirlpool_Context
-    _hash_impl.internal_ctx = ctx
-    _hash_impl.hash_size    = ._64
-}
+	if source_bits > 0 {
+		b = u32((source[source_pos] << source_gap) & 0xff)
+		ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem
+	} else {b = 0}
 
-@(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)
-    }
+	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)
+	}
 }
 
-@(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)
-    }
+final :: 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])
+	}
 }
 
 /*
@@ -774,97 +782,3 @@ transform :: proc (ctx: ^Whirlpool_Context) {
 	}
 	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])
-	}
-}

二進制
tests/core/botan.dll


+ 0 - 183
tests/core/crypto/test_core_crypto.odin

@@ -33,7 +33,6 @@ 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"
@@ -102,7 +101,6 @@ main :: proc() {
     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)
@@ -171,13 +169,6 @@ test_md4 :: proc(t: ^testing.T) {
         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)
@@ -197,12 +188,6 @@ test_md5 :: proc(t: ^testing.T) {
         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)
@@ -225,15 +210,8 @@ test_sha1 :: proc(t: ^testing.T) {
         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 
@@ -250,12 +228,6 @@ test_sha224 :: proc(t: ^testing.T) {
         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)
@@ -274,13 +246,6 @@ test_sha256 :: proc(t: ^testing.T) {
         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)
@@ -299,13 +264,6 @@ test_sha384 :: proc(t: ^testing.T) {
         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)
@@ -324,15 +282,8 @@ test_sha512 :: proc(t: ^testing.T) {
         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 
@@ -353,12 +304,6 @@ test_sha3_224 :: proc(t: ^testing.T) {
         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)
@@ -381,12 +326,6 @@ test_sha3_256 :: proc(t: ^testing.T) {
         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)
@@ -409,12 +348,6 @@ test_sha3_384 :: proc(t: ^testing.T) {
         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)
@@ -437,12 +370,6 @@ test_sha3_512 :: proc(t: ^testing.T) {
         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)
@@ -457,12 +384,6 @@ test_shake_128 :: proc(t: ^testing.T) {
         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)
@@ -477,12 +398,6 @@ test_shake_256 :: proc(t: ^testing.T) {
         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)
@@ -499,12 +414,6 @@ test_keccak_224 :: proc(t: ^testing.T) {
         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)
@@ -521,12 +430,6 @@ test_keccak_256 :: proc(t: ^testing.T) {
         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)
@@ -543,12 +446,6 @@ test_keccak_384 :: proc(t: ^testing.T) {
         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)
@@ -565,12 +462,6 @@ test_keccak_512 :: proc(t: ^testing.T) {
         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)
@@ -597,12 +488,6 @@ test_whirlpool :: proc(t: ^testing.T) {
         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)
@@ -623,12 +508,6 @@ test_gost :: proc(t: ^testing.T) {
         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)
@@ -643,12 +522,6 @@ test_streebog_256 :: proc(t: ^testing.T) {
         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)
@@ -663,12 +536,6 @@ test_streebog_512 :: proc(t: ^testing.T) {
         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)
@@ -738,12 +605,6 @@ test_blake2b :: proc(t: ^testing.T) {
         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)
@@ -797,12 +658,6 @@ test_ripemd_160 :: proc(t: ^testing.T) {
         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)
@@ -863,12 +718,6 @@ test_tiger_128 :: proc(t: ^testing.T) {
         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)
@@ -889,12 +738,6 @@ test_tiger_160 :: proc(t: ^testing.T) {
         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)
@@ -915,12 +758,6 @@ test_tiger_192 :: proc(t: ^testing.T) {
         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)
@@ -979,26 +816,6 @@ test_sm3 :: proc(t: ^testing.T) {
         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)

Some files were not shown because too many files changed in this diff