mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-18 11:52:22 -07:00
253 lines
7.8 KiB
Odin
253 lines
7.8 KiB
Odin
package vendor_siphash
|
|
|
|
/*
|
|
Copyright 2022 zhibog
|
|
Made available under the BSD-3 license.
|
|
|
|
List of contributors:
|
|
zhibog: Initial implementation.
|
|
|
|
Interface for the SipHash hashing algorithm.
|
|
The hash will be computed via bindings to the Botan crypto library
|
|
|
|
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
|
*/
|
|
|
|
import "core:crypto"
|
|
import "core:crypto/util"
|
|
|
|
import botan "../bindings"
|
|
|
|
KEY_SIZE :: 16
|
|
DIGEST_SIZE :: 8
|
|
|
|
// sum_string_1_3 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_string_1_3 :: proc(msg, key: string) -> u64 {
|
|
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
|
|
}
|
|
|
|
// sum_bytes_1_3 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
|
|
dst: [8]byte
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:], 1, 3)
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
return util.U64_LE(dst[:])
|
|
}
|
|
|
|
// sum_string_to_buffer_1_3 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
|
|
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
|
}
|
|
|
|
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
|
|
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:], 1, 3)
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
}
|
|
|
|
sum_1_3 :: proc {
|
|
sum_string_1_3,
|
|
sum_bytes_1_3,
|
|
sum_string_to_buffer_1_3,
|
|
sum_bytes_to_buffer_1_3,
|
|
}
|
|
|
|
// verify_u64_1_3 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
|
|
return sum_bytes_1_3(msg, key) == tag
|
|
}
|
|
|
|
// verify_bytes_1_3 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
|
|
derived_tag: [8]byte
|
|
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
|
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
|
}
|
|
|
|
verify_1_3 :: proc {
|
|
verify_bytes_1_3,
|
|
verify_u64_1_3,
|
|
}
|
|
|
|
// sum_string_2_4 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_string_2_4 :: proc(msg, key: string) -> u64 {
|
|
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
|
|
}
|
|
|
|
// sum_bytes_2_4 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
|
|
dst: [8]byte
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:])
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
return util.U64_LE(dst[:])
|
|
}
|
|
|
|
// sum_string_to_buffer_2_4 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
|
|
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
|
}
|
|
|
|
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
|
|
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:])
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
}
|
|
|
|
sum_2_4 :: proc {
|
|
sum_string_2_4,
|
|
sum_bytes_2_4,
|
|
sum_string_to_buffer_2_4,
|
|
sum_bytes_to_buffer_2_4,
|
|
}
|
|
|
|
sum_string :: sum_string_2_4
|
|
sum_bytes :: sum_bytes_2_4
|
|
sum_string_to_buffer :: sum_string_to_buffer_2_4
|
|
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
|
sum :: proc {
|
|
sum_string,
|
|
sum_bytes,
|
|
sum_string_to_buffer,
|
|
sum_bytes_to_buffer,
|
|
}
|
|
|
|
|
|
// verify_u64_2_4 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
|
|
return sum_bytes_2_4(msg, key) == tag
|
|
}
|
|
|
|
// verify_bytes_2_4 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
|
|
derived_tag: [8]byte
|
|
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
|
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
|
}
|
|
|
|
verify_2_4 :: proc {
|
|
verify_bytes_2_4,
|
|
verify_u64_2_4,
|
|
}
|
|
|
|
verify_bytes :: verify_bytes_2_4
|
|
verify_u64 :: verify_u64_2_4
|
|
verify :: proc {
|
|
verify_bytes,
|
|
verify_u64,
|
|
}
|
|
|
|
// sum_string_4_8 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_string_4_8 :: proc(msg, key: string) -> u64 {
|
|
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
|
|
}
|
|
|
|
// sum_bytes_4_8 will hash the given message with the key and return
|
|
// the computed hash as a u64
|
|
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
|
|
dst: [8]byte
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:], 4, 8)
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
return util.U64_LE(dst[:])
|
|
}
|
|
|
|
// sum_string_to_buffer_4_8 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
|
|
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
|
}
|
|
|
|
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
|
|
// the computed hash into the provided destination buffer
|
|
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
|
|
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
|
|
ctx: botan.mac_t
|
|
init(&ctx, key[:], 4, 8)
|
|
update(&ctx, msg[:])
|
|
final(&ctx, dst[:])
|
|
}
|
|
|
|
sum_4_8 :: proc {
|
|
sum_string_4_8,
|
|
sum_bytes_4_8,
|
|
sum_string_to_buffer_4_8,
|
|
sum_bytes_to_buffer_4_8,
|
|
}
|
|
|
|
// verify_u64_4_8 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
|
|
return sum_bytes_4_8(msg, key) == tag
|
|
}
|
|
|
|
// verify_bytes_4_8 will check if the supplied tag matches with the output you
|
|
// will get from the provided message and key
|
|
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
|
|
derived_tag: [8]byte
|
|
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
|
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
|
}
|
|
|
|
verify_4_8 :: proc {
|
|
verify_bytes_4_8,
|
|
verify_u64_4_8,
|
|
}
|
|
|
|
/*
|
|
Low level API
|
|
*/
|
|
|
|
Context :: botan.mac_t
|
|
|
|
init :: proc(ctx: ^botan.mac_t, key: []byte, c_rounds := 2, d_rounds := 4) {
|
|
assert(len(key) == KEY_SIZE, "vendor/botan: Invalid key size, want 16")
|
|
is_valid_setting := (c_rounds == 1 && d_rounds == 3) ||
|
|
(c_rounds == 2 && d_rounds == 4) ||
|
|
(c_rounds == 4 && d_rounds == 8)
|
|
assert(is_valid_setting, "vendor/botan: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
|
|
if c_rounds == 1 && d_rounds == 3 {
|
|
botan.mac_init(ctx, botan.MAC_SIPHASH_1_3, 0)
|
|
} else if c_rounds == 2 && d_rounds == 4 {
|
|
botan.mac_init(ctx, botan.MAC_SIPHASH_2_4, 0)
|
|
} else if c_rounds == 4 && d_rounds == 8 {
|
|
botan.mac_init(ctx, botan.MAC_SIPHASH_4_8, 0)
|
|
}
|
|
botan.mac_set_key(ctx^, len(key) == 0 ? nil : &key[0], uint(len(key)))
|
|
}
|
|
|
|
update :: proc "contextless" (ctx: ^botan.mac_t, data: []byte) {
|
|
botan.mac_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data)))
|
|
}
|
|
|
|
final :: proc(ctx: ^botan.mac_t, dst: []byte) {
|
|
botan.mac_final(ctx^, &dst[0])
|
|
reset(ctx)
|
|
}
|
|
|
|
reset :: proc(ctx: ^botan.mac_t) {
|
|
botan.mac_destroy(ctx^)
|
|
} |