diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-09-15 20:05:44 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-09-15 20:06:07 +0200 |
| commit | 662d27b79650176d27cdc5589a0862a33dbcc313 (patch) | |
| tree | 617abf65fd96de7cae8db4883027f325a44c8212 | |
| parent | de00c7c9a8e428d3510fb81ea09f4c3519509d18 (diff) | |
Finish xxHash implementation.
| -rw-r--r-- | core/hash/xxhash/common.odin | 2 | ||||
| -rw-r--r-- | core/hash/xxhash/streaming.odin | 372 | ||||
| -rw-r--r-- | core/hash/xxhash/xxhash_3.odin | 596 | ||||
| -rw-r--r-- | core/hash/xxhash/xxhash_32.odin | 10 | ||||
| -rw-r--r-- | core/hash/xxhash/xxhash_64.odin | 10 |
5 files changed, 439 insertions, 551 deletions
diff --git a/core/hash/xxhash/common.odin b/core/hash/xxhash/common.odin index 434ebb905..908dfaa87 100644 --- a/core/hash/xxhash/common.odin +++ b/core/hash/xxhash/common.odin @@ -41,7 +41,7 @@ Alignment :: enum { } Error :: enum { - Okay = 0, + None = 0, Error, } diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin new file mode 100644 index 000000000..95ff38f78 --- /dev/null +++ b/core/hash/xxhash/streaming.odin @@ -0,0 +1,372 @@ +/* + An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/). + Copyright 2021 Jeroen van Rijn <nom@duclavier.com>. + + Made available under Odin's BSD-3 license, based on the original C code. + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +package xxhash + +import "core:mem" +import "core:intrinsics" + +/* + === XXH3 128-bit streaming === + + All the functions are actually the same as for 64-bit streaming variant. + The only difference is the finalization routine. +*/ +XXH3_128_reset :: proc(state: ^XXH3_state) -> (err: Error) { + if state == nil { + return .Error + } + XXH3_reset_internal(state, 0, XXH3_kSecret[:]) + return .None +} +XXH3_64_reset :: XXH3_128_reset + +XXH3_128_reset_with_secret :: proc(state: ^XXH3_state, secret: []u8) -> (err: Error) { + if state == nil { + return .Error + } + if secret == nil || len(secret) < XXH3_SECRET_SIZE_MIN { + return .Error + } + XXH3_reset_internal(state, 0, secret) + return .None +} +XXH3_64_reset_with_secret :: XXH3_128_reset_with_secret + +XXH3_128_reset_with_seed :: proc(state: ^XXH3_state, seed: XXH64_hash) -> (err: Error) { + if seed == 0 { + return XXH3_128_reset(state) + } + if seed != state.seed { + XXH3_init_custom_secret(state.custom_secret[:], seed) + } + + XXH3_reset_internal(state, seed, nil) + return .None +} +XXH3_64_reset_with_seed :: XXH3_128_reset_with_seed + +XXH3_128_update :: proc(state: ^XXH3_state, input: []u8) -> (err: Error) { + return XXH3_update(state, input, XXH3_accumulate_512, XXH3_scramble_accumulator) +} + +XXH3_128_digest :: proc(state: ^XXH3_state) -> (hash: XXH3_128_hash) { + secret := state.custom_secret[:] if len(state.external_secret) == 0 else state.external_secret[:] + + if state.total_length > XXH3_MIDSIZE_MAX { + acc: [XXH_ACC_NB]XXH64_hash + XXH3_digest_long(acc[:], state, secret) + + assert(state.secret_limit + XXH_STRIPE_LEN >= XXH_ACC_NB + XXH_SECRET_MERGEACCS_START) + { + h128 := XXH128_hash_t{} + + h128.low = XXH3_mergeAccs( + acc[:], + secret[XXH_SECRET_MERGEACCS_START:], + state.total_length * XXH_PRIME64_1) + + h128.high = XXH3_mergeAccs( + acc[:], + secret[state.secret_limit + XXH_STRIPE_LEN - size_of(acc) - XXH_SECRET_MERGEACCS_START:], + ~(u64(state.total_length) * XXH_PRIME64_2)) + + return h128.h + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if state.seed != 0 { + return XXH3_128_with_seed(state.buffer[:state.total_length], state.seed) + } + return XXH3_128_with_secret(state.buffer[:state.total_length], secret[:state.secret_limit + XXH_STRIPE_LEN]) +} + +/*====== Canonical representation ======*/ + +XXH3_128_canonical_from_hash :: proc(hash: XXH128_hash_t) -> (canonical: XXH128_canonical) { + #assert(size_of(XXH128_canonical) == size_of(XXH128_hash_t)) + + t := hash + when ODIN_ENDIAN == "little" { + t.high = byte_swap(t.high) + t.low = byte_swap(t.low) + } + mem_copy(&canonical.digest, &t.high, size_of(u64)) + mem_copy(&canonical.digest[8], &t.low, size_of(u64)) + return +} + +XXH3_128_hash_from_canonical :: proc(src: ^XXH128_canonical) -> (hash: u128) { + h := XXH128_hash_t{} + + high := (^u64be)(&src.digest[0])^ + low := (^u64be)(&src.digest[8])^ + + h.high = u64(high) + h.low = u64(low) + return h.h +} + +/* === XXH3 streaming === */ + +XXH3_init_state :: proc(state: ^XXH3_state) { + state.seed = 0 +} + +XXH3_create_state :: proc(allocator := context.allocator) -> (res: ^XXH3_state, err: Error) { + state, mem_error := mem.new_aligned(XXH3_state, 64, allocator) + err = nil if mem_error == nil else .Error + + XXH3_init_state(state) + return state, nil +} + +XXH3_destroy_state :: proc(state: ^XXH3_state, allocator := context.allocator) -> (err: Error) { + free(state) + return .None +} + +XXH3_copy_state :: proc(dest, src: ^XXH3_state) { + assert(dest != nil && src != nil) + mem_copy(dest, src, size_of(XXH3_state)) +} + +XXH3_reset_internal :: proc(state: ^XXH3_state, seed: XXH64_hash, secret: []u8) { + assert(state != nil) + + init_start := offset_of(XXH3_state, buffered_size) + init_length := offset_of(XXH3_state, stripes_per_block) - init_start + + assert(offset_of(XXH3_state, stripes_per_block) > init_start) + + /* + Set members from buffered_size to stripes_per_block (excluded) to 0 + */ + offset := rawptr(uintptr(state) + uintptr(init_start)) + intrinsics.mem_zero(offset, init_length) + + state.acc[0] = XXH_PRIME32_3 + state.acc[1] = XXH_PRIME64_1 + state.acc[2] = XXH_PRIME64_2 + state.acc[3] = XXH_PRIME64_3 + state.acc[4] = XXH_PRIME64_4 + state.acc[5] = XXH_PRIME32_2 + state.acc[6] = XXH_PRIME64_5 + state.acc[7] = XXH_PRIME32_1 + state.seed = seed + state.external_secret = secret + + secret_length := uint(len(secret)) + assert(secret_length > XXH3_SECRET_SIZE_MIN) + + state.secret_limit = secret_length - XXH_STRIPE_LEN + state.stripes_per_block = state.secret_limit / XXH_SECRET_CONSUME_RATE +} + +/* + Note: when XXH3_consumeStripes() is invoked, there must be a guarantee that at least + one more byte must be consumed from input so that the function can blindly consume + all stripes using the "normal" secret segment. +*/ + +XXH3_consume_stripes :: #force_inline proc( + acc: []xxh_u64, stripes_so_far: ^uint, stripes_per_block: uint, input: []u8, + number_of_stripes: uint, secret: []u8, secret_limit: uint, + f_acc512: XXH3_accumulate_512_f, f_scramble: XXH3_scramble_accumulator_f) { + + assert(number_of_stripes <= stripes_per_block) /* can handle max 1 scramble per invocation */ + assert(stripes_so_far^ < stripes_per_block) + + if stripes_per_block - stripes_so_far^ <= number_of_stripes { + /* need a scrambling operation */ + stripes_to_end_of_block := stripes_per_block - stripes_so_far^ + stripes_after_block := number_of_stripes - stripes_to_end_of_block + + XXH3_accumulate(acc, input, secret[stripes_so_far^ * XXH_SECRET_CONSUME_RATE:], stripes_to_end_of_block, f_acc512) + + f_scramble(acc, secret[secret_limit:]) + XXH3_accumulate(acc, input[stripes_to_end_of_block * XXH_STRIPE_LEN:], secret, stripes_after_block, f_acc512) + stripes_so_far^ = stripes_after_block + } else { + XXH3_accumulate(acc, input, secret[stripes_so_far^ * XXH_SECRET_CONSUME_RATE:], number_of_stripes, f_acc512) + stripes_so_far^ += number_of_stripes + } +} + +/* + Both XXH3_64bits_update and XXH3_128bits_update use this routine. +*/ +XXH3_update :: #force_inline proc( + state: ^XXH3_state, input: []u8, + f_acc512: XXH3_accumulate_512_f, + f_scramble: XXH3_scramble_accumulator_f) -> (err: Error) { + + input := input + length := len(input) + secret := state.custom_secret[:] if len(state.external_secret) == 0 else state.external_secret[:] + + state.total_length += u64(length) + assert(state.buffered_size <= XXH3_INTERNAL_BUFFER_SIZE) + + if int(state.buffered_size) + length <= XXH3_INTERNAL_BUFFER_SIZE { /* fill in tmp buffer */ + mem_copy(&state.buffer[state.buffered_size], &input[0], length) + state.buffered_size += u32(length) + return .None + } + + /* total input is now > XXH3_INTERNAL_BUFFER_SIZE */ + XXH3_INTERNAL_BUFFER_STRIPES :: XXH3_INTERNAL_BUFFER_SIZE / XXH_STRIPE_LEN + #assert(XXH3_INTERNAL_BUFFER_SIZE % XXH_STRIPE_LEN == 0) /* clean multiple */ + + /* + Internal buffer is partially filled (always, except at beginning) + Complete it, then consume it. + */ + if state.buffered_size > 0 { + load_size := int(XXH3_INTERNAL_BUFFER_SIZE - state.buffered_size) + mem_copy(&state.buffer[state.buffered_size], &input[0], load_size) + input = input[load_size:] + + XXH3_consume_stripes( + state.acc[:], &state.stripes_so_far, state.stripes_per_block, + state.buffer[:], XXH3_INTERNAL_BUFFER_STRIPES, + secret, state.secret_limit, f_acc512, f_scramble) + state.buffered_size = 0 + } + assert(len(input) > 0) + + /* Consume input by a multiple of internal buffer size */ + if len(input) > XXH3_INTERNAL_BUFFER_SIZE { + tail := input[:len(input) - XXH_STRIPE_LEN] + for len(input) > XXH3_INTERNAL_BUFFER_SIZE { + XXH3_consume_stripes( + state.acc[:], &state.stripes_so_far, state.stripes_per_block, + input, XXH3_INTERNAL_BUFFER_STRIPES, + secret, state.secret_limit, f_acc512, f_scramble) + + input = input[XXH3_INTERNAL_BUFFER_SIZE:] + } + /* for last partial stripe */ + mem_copy(&state.buffer[XXH3_INTERNAL_BUFFER_SIZE - XXH_STRIPE_LEN], &tail[0], XXH_STRIPE_LEN) + } + + length = len(input) + assert(length > 0) + + /* Some remaining input (always) : buffer it */ + mem_copy(&state.buffer[0], &input[0], length) + state.buffered_size = u32(length) + return .None +} + +XXH3_64_update :: proc(state: ^XXH3_state, input: []u8) -> (err: Error) { + return XXH3_update(state, input, XXH3_accumulate_512, XXH3_scramble_accumulator) +} + +XXH3_digest_long :: #force_inline proc(acc: []u64, state: ^XXH3_state, secret: []u8) { + /* + Digest on a local copy. This way, the state remains unaltered, and it can + continue ingesting more input afterwards. + */ + mem_copy(&acc[0], &state.acc[0], size_of(state.acc)) + + if state.buffered_size >= XXH_STRIPE_LEN { + number_of_stripes := uint((state.buffered_size - 1) / XXH_STRIPE_LEN) + stripes_so_far := state.stripes_so_far + + XXH3_consume_stripes( + acc[:], &stripes_so_far, state.stripes_per_block, state.buffer[:], number_of_stripes, + secret, state.secret_limit, XXH3_accumulate_512, XXH3_scramble_accumulator) + + /* last stripe */ + XXH3_accumulate_512( + acc[:], + state.buffer[state.buffered_size - XXH_STRIPE_LEN:], + secret[state.secret_limit - XXH_SECRET_LASTACC_START:]) + + } else { /* bufferedSize < XXH_STRIPE_LEN */ + last_stripe: [XXH_STRIPE_LEN]u8 + catchup_size := int(XXH_STRIPE_LEN) - int(state.buffered_size) + assert(state.buffered_size > 0) /* there is always some input buffered */ + + mem_copy(&last_stripe[0], &state.buffer[XXH3_INTERNAL_BUFFER_SIZE - catchup_size], catchup_size) + mem_copy(&last_stripe[catchup_size], &state.buffer[0], int(state.buffered_size)) + XXH3_accumulate_512(acc[:], last_stripe[:], secret[state.secret_limit - XXH_SECRET_LASTACC_START:]) + } +} + +XXH3_64_digest :: proc(state: ^XXH3_state) -> (hash: XXH64_hash) { + secret := state.custom_secret[:] if len(state.external_secret) == 0 else state.external_secret[:] + + if state.total_length > XXH3_MIDSIZE_MAX { + acc: [XXH_ACC_NB]xxh_u64 + XXH3_digest_long(acc[:], state, secret[:]) + + return XXH3_mergeAccs(acc[:], secret[ XXH_SECRET_MERGEACCS_START:], state.total_length * XXH_PRIME64_1) + } + + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if state.seed == 0 { + return XXH3_64_with_seed(state.buffer[:state.total_length], state.seed) + } + return XXH3_64_with_secret(state.buffer[:state.total_length], secret[:state.secret_limit + XXH_STRIPE_LEN]) +} + +XXH3_generate_secret :: proc(secret_buffer: []u8, custom_seed: []u8) { + secret_length := len(secret_buffer) + assert(secret_length >= XXH3_SECRET_SIZE_MIN) + + custom_seed_size := len(custom_seed) + if custom_seed_size == 0 { + k := XXH3_kSecret + mem_copy(&secret_buffer[0], &k[0], XXH_SECRET_DEFAULT_SIZE) + return + } + + { + segment_size :: size_of(XXH128_hash_t) + number_of_segments := u64(XXH_SECRET_DEFAULT_SIZE / segment_size) + + seeds: [12]u64le + assert(number_of_segments == 12) + assert(segment_size * number_of_segments == XXH_SECRET_DEFAULT_SIZE) /* exact multiple */ + + scrambler := XXH3_128_canonical_from_hash(XXH128_hash_t{h=XXH3_128(custom_seed[:])}) + + /* + Copy customSeed to seeds[], truncating or repeating as necessary. + TODO: Convert `mem_copy` to slice copies. + */ + { + to_fill := min(custom_seed_size, size_of(seeds)) + filled := to_fill + mem_copy(&seeds[0], &custom_seed[0], to_fill) + for filled < size_of(seeds) { + to_fill = min(filled, size_of(seeds) - filled) + seed_offset := rawptr(uintptr(&seeds[0]) + uintptr(filled)) + mem_copy(seed_offset, &seeds[0], to_fill) + filled += to_fill + } + } + + /* + Generate secret + */ + mem_copy(&secret_buffer[0], &scrambler, size_of(scrambler)) + + for segment_number := u64(1); segment_number < number_of_segments; segment_number += 1 { + segment_start := segment_number * segment_size + + this_seed := u64(seeds[segment_number]) + segment_number + segment := XXH3_128_canonical_from_hash(XXH128_hash_t{h=XXH3_128(scrambler.digest[:], this_seed)}) + + mem_copy(&secret_buffer[segment_start], &segment, size_of(segment)) + } + } +}
\ No newline at end of file diff --git a/core/hash/xxhash/xxhash_3.odin b/core/hash/xxhash/xxhash_3.odin index b43a72005..5bd5537b1 100644 --- a/core/hash/xxhash/xxhash_3.odin +++ b/core/hash/xxhash/xxhash_3.odin @@ -30,7 +30,7 @@ import "core:intrinsics" XXH_SECRET_DEFAULT_SIZE :: max(XXH3_SECRET_SIZE_MIN, #config(XXH_SECRET_DEFAULT_SIZE, 192)) #assert(XXH_SECRET_DEFAULT_SIZE % 64 == 0) -XXH3_kSecret :: [?]u8{ +XXH3_kSecret := [XXH_SECRET_DEFAULT_SIZE]u8{ 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, @@ -48,7 +48,7 @@ XXH3_kSecret :: [?]u8{ Do not change this constant. */ XXH3_SECRET_SIZE_MIN :: 136 -#assert(size_of(XXH3_kSecret) == 192 && size_of(XXH3_kSecret) > XXH3_SECRET_SIZE_MIN) +#assert(len(XXH3_kSecret) == 192 && len(XXH3_kSecret) > XXH3_SECRET_SIZE_MIN) XXH_ACC_ALIGN :: 8 /* scalar */ @@ -71,15 +71,15 @@ XXH3_state :: struct { buffered_size: u32, reserved32: u32, stripes_so_far: uint, - total_len: u64, + total_length: u64, stripes_per_block: uint, secret_limit: uint, seed: u64, reserved64: u64, - external_secret: ^[]u8, + external_secret: []u8, } #assert(offset_of(XXH3_state, acc) % 64 == 0 && offset_of(XXH3_state, custom_secret) % 64 == 0 && - offset_of(XXH3_state, buffer) % 64 == 0) + offset_of(XXH3_state, buffer) % 64 == 0) /************************************************************************ * XXH3 128-bit variant @@ -100,6 +100,10 @@ XXH128_hash_t :: struct #raw_union { } #assert(size_of(xxh_u128) == size_of(XXH128_hash_t)) +XXH128_canonical :: struct { + digest: [size_of(XXH128_hash_t)]u8, +} + /* The reason for the separate function is to prevent passing too many structs around by value. This will hopefully inline the multiply, but we don't force it. @@ -146,12 +150,12 @@ XXH3_rrmxmx :: #force_inline proc(h64, length: xxh_u64) -> (res: xxh_u64) { /* ========================================== - XXH3 128 bits (a.k.a XXH128) + XXH3 128 bits (a.k.a XXH128) ========================================== XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, even without counting the significantly larger output size. - For example, extra steps are taken to avoid the seed-dependent collisions + For example, extra steps are taken to avoid the seed-dependent collisions in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). This strength naturally comes at the cost of some speed, especially on short @@ -289,9 +293,6 @@ XXH128_mix32B :: #force_inline proc(acc: xxh_u128, input_1: []u8, input_2: []u8, } } - - - @(optimization_mode="speed") XXH3_len_17to128_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) @@ -335,18 +336,18 @@ XXH3_len_129to240_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xx i: int #no_bounds_check for i = 0; i < 4; i += 1 { acc.h = XXH128_mix32B(acc.h, - input[32 * i:], - input [32 * i + 16:], - secret[32 * i:], - seed) + input[32 * i:], + input [32 * i + 16:], + secret[32 * i:], + seed) } acc.low = XXH3_avalanche(acc.low) acc.high = XXH3_avalanche(acc.high) #no_bounds_check for i = 4; i < nbRounds; i += 1 { acc.h = XXH128_mix32B(acc.h, - input[32 * i:], input[32 * i + 16:], - secret[XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)):], + input[32 * i:], input[32 * i + 16:], + secret[XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)):], seed) } /* last bytes */ @@ -360,9 +361,9 @@ XXH3_len_129to240_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xx h128 := XXH128_hash_t{} h128.low = acc.low + acc.high h128.high = u64( - u128(acc.low * XXH_PRIME64_1) \ - + u128(acc.high * XXH_PRIME64_4) \ - + u128((u64(length) - seed) * XXH_PRIME64_2)) + u128(acc.low * XXH_PRIME64_1) \ + + u128(acc.high * XXH_PRIME64_4) \ + + u128((u64(length) - seed) * XXH_PRIME64_2)) h128.low = XXH3_avalanche(h128.low) h128.high = u64(i64(0) - i64(XXH3_avalanche(h128.high))) return h128.h @@ -406,18 +407,20 @@ XXH3_hashLong_128b_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ +@(optimization_mode="speed") XXH3_hashLong_128b_default :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { - k_secret := XXH3_kSecret - return XXH3_hashLong_128b_internal(input, k_secret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) + return XXH3_hashLong_128b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } /* * It's important for performance that XXH3_hashLong is not inlined. */ +@(optimization_mode="speed") XXH3_hashLong_128b_withSecret :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } +@(optimization_mode="speed") XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( input: []u8, seed: xxh_u64, secret: []u8, f_acc512: XXH3_accumulate_512_f, @@ -425,8 +428,7 @@ XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( f_initSec: XXH3_init_custom_secret_f) -> (res: XXH3_128_hash) { if seed == 0 { - k := XXH3_kSecret - return XXH3_hashLong_128b_internal(input, k[:], f_acc512, f_scramble) + return XXH3_hashLong_128b_internal(input, XXH3_kSecret[:], f_acc512, f_scramble) } { @@ -439,12 +441,14 @@ XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ + @(optimization_mode="speed") XXH3_hashLong_128b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_withSeed_internal(input, seed, secret, XXH3_accumulate_512, XXH3_scramble_accumulator , XXH3_init_custom_secret) } XXH3_hashLong128_f :: #type proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) +@(optimization_mode="speed") XXH3_128bits_internal :: #force_inline proc( input: []u8, seed: xxh_u64, secret: []u8, f_hl128: XXH3_hashLong128_f) -> (res: XXH3_128_hash) { @@ -470,150 +474,22 @@ XXH3_128bits_internal :: #force_inline proc( } /* === Public XXH128 API === */ - +@(optimization_mode="speed") XXH3_128_default :: proc(input: []u8) -> (hash: XXH3_128_hash) { - k := XXH3_kSecret - return XXH3_128bits_internal(input, 0, k[:], XXH3_hashLong_128b_withSeed) + return XXH3_128bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_128b_withSeed) } +@(optimization_mode="speed") XXH3_128_with_seed :: proc(input: []u8, seed: xxh_u64) -> (hash: XXH3_128_hash) { - k := XXH3_kSecret - return XXH3_128bits_internal(input, seed, k[:], XXH3_hashLong_128b_withSeed) + return XXH3_128bits_internal(input, seed, XXH3_kSecret[:], XXH3_hashLong_128b_withSeed) } +@(optimization_mode="speed") XXH3_128_with_secret :: proc(input: []u8, secret: []u8) -> (hash: XXH3_128_hash) { return XXH3_128bits_internal(input, 0, secret, XXH3_hashLong_128b_withSecret) } XXH3_128 :: proc { XXH3_128_default, XXH3_128_with_seed, XXH3_128_with_secret } -/* === XXH3 128-bit streaming === */ - -/* - All the functions are actually the same as for 64-bit streaming variant. - The only difference is the finalization routine. -*/ - -/* - -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset(XXH3_state_t* statePtr) -{ - if (statePtr == NULL) return XXH_ERROR; - XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) -{ - if (statePtr == NULL) return XXH_ERROR; - XXH3_reset_internal(statePtr, 0, secret, secretSize); - if (secret == NULL) return XXH_ERROR; - if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) -{ - if (statePtr == NULL) return XXH_ERROR; - if (seed==0) return XXH3_128bits_reset(statePtr); - if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); - XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) -{ - return XXH3_update(state, (const xxh_u8*)input, len, - XXH3_accumulate_512, XXH3_scrambleAcc); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) -{ - const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; - if (state->totalLen > XXH3_MIDSIZE_MAX) { - XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; - XXH3_digest_long(acc, state, secret); - XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); - { XXH128_hash_t h128; - h128.low64 = XXH3_mergeAccs(acc, - secret + XXH_SECRET_MERGEACCS_START, - (xxh_u64)state->totalLen * XXH_PRIME64_1); - h128.high64 = XXH3_mergeAccs(acc, - secret + state->secretLimit + XXH_STRIPE_LEN - - sizeof(acc) - XXH_SECRET_MERGEACCS_START, - ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); - return h128; - } - } - /* len <= XXH3_MIDSIZE_MAX : short code */ - if (state->seed) - return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); - return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), - secret, state->secretLimit + XXH_STRIPE_LEN); -} - -/* 128-bit utility functions */ - -#include <string.h> /* memcmp, memcpy */ - -/* return : 1 is equal, 0 if different */ -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) -{ - /* note : XXH128_hash_t is compact, it has no padding byte */ - return !(memcmp(&h1, &h2, sizeof(h1))); -} - -/* This prototype is compatible with stdlib's qsort(). - * return : >0 if *h128_1 > *h128_2 - * <0 if *h128_1 < *h128_2 - * =0 if *h128_1 == *h128_2 */ -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) -{ - XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; - XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; - int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); - /* note : bets that, in most cases, hash values are different */ - if (hcmp) return hcmp; - return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); -} - - -/*====== Canonical representation ======*/ -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API void -XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) -{ - XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); - if (XXH_CPU_LITTLE_ENDIAN) { - hash.high64 = XXH_swap64(hash.high64); - hash.low64 = XXH_swap64(hash.low64); - } - memcpy(dst, &hash.high64, sizeof(hash.high64)); - memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH128_hash_t -XXH128_hashFromCanonical(const XXH128_canonical_t* src) -{ - XXH128_hash_t h; - h.high64 = XXH_readBE64(src); - h.low64 = XXH_readBE64(src->digest + 8); - return h; -} - -*/ - - /* ========================================== Short keys @@ -818,9 +694,10 @@ XXH3_len_129to240_64b :: proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: /* ======= Long Keys ======= */ -XXH_STRIPE_LEN :: 64 -XXH_SECRET_CONSUME_RATE :: 8 /* nb of secret bytes consumed at each accumulation */ -XXH_ACC_NB :: (XXH_STRIPE_LEN / size_of(xxh_u64)) +XXH_STRIPE_LEN :: 64 +XXH_SECRET_CONSUME_RATE :: 8 /* nb of secret bytes consumed at each accumulation */ +XXH_ACC_NB :: (XXH_STRIPE_LEN / size_of(xxh_u64)) +XXH_SECRET_LASTACC_START :: 7 /* not aligned on 8, last secret is different from acc & scrambler */ @(optimization_mode="speed") XXH_writeLE64 :: #force_inline proc(dst: []u8, v64: u64le) { @@ -870,9 +747,10 @@ XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, se #no_bounds_check for i := uint(0); i < XXH_ACC_NB; i += 1 { data_val := XXH64_read64(xinput[8 * i:]) - data_key := data_val ~ XXH64_read64(xsecret[8 * i:]) + sec := XXH64_read64(xsecret[8 * i:]) + data_key := data_val ~ sec xacc[i ~ 1] += data_val /* swap adjacent lanes */ - xacc[i ] += u64(u32(data_key)) * u64(data_key >> 32) + xacc[i ] += u64(u128(u32(data_key)) * u128(u64(data_key >> 32))) } } @@ -897,12 +775,10 @@ XXH3_scramble_accumulator_scalar :: #force_inline proc(acc: []xxh_u64, secret: [ XXH3_init_custom_secret_scalar :: #force_inline proc(custom_secret: []u8, seed64: xxh_u64) { #assert((XXH_SECRET_DEFAULT_SIZE & 15) == 0) - kSecretPtr := XXH3_kSecret - nbRounds := XXH_SECRET_DEFAULT_SIZE / 16 #no_bounds_check for i := 0; i < nbRounds; i += 1 { - lo := XXH64_read64(kSecretPtr[16 * i: ]) + seed64 - hi := XXH64_read64(kSecretPtr[16 * i + 8:]) - seed64 + lo := XXH64_read64(XXH3_kSecret[16 * i: ]) + seed64 + hi := XXH64_read64(XXH3_kSecret[16 * i + 8:]) - seed64 XXH_writeLE64(custom_secret[16 * i: ], u64le(lo)) XXH_writeLE64(custom_secret[16 * i + 8:], u64le(hi)) } @@ -916,8 +792,8 @@ XXH_PREFETCH_DIST :: 320 * Assumption: nbStripes will not overflow the secret size */ @(optimization_mode="speed") -XXH3_accumulate :: #force_inline proc(acc: []xxh_u64, input: []u8, secret: []u8, nbStripes: uint, - f_acc512: XXH3_accumulate_512_f) { +XXH3_accumulate :: #force_inline proc( + acc: []xxh_u64, input: []u8, secret: []u8, nbStripes: uint, f_acc512: XXH3_accumulate_512_f) { for n := uint(0); n < nbStripes; n += 1 { when !XXH_DISABLE_PREFETCH { @@ -952,7 +828,6 @@ XXH3_hashLong_internal_loop :: #force_inline proc(acc: []xxh_u64, input: []u8, s /* last stripe */ #no_bounds_check { p := input[length - XXH_STRIPE_LEN:] - XXH_SECRET_LASTACC_START :: 7 /* not aligned on 8, last secret is different from acc & scrambler */ f_acc512(acc, p, secret[secret_size - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START:]) } } @@ -993,6 +868,7 @@ XXH3_hashLong_64b_internal :: #force_inline proc(input: []u8, secret: []u8, /* It's important for performance that XXH3_hashLong is not inlined. */ +@(optimization_mode="speed") XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -1004,9 +880,9 @@ XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u This variant enforces that the compiler can detect that, and uses this opportunity to streamline the generated code for better performance. */ +@(optimization_mode="speed") XXH3_hashLong_64b_default :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { - k := XXH3_kSecret - return XXH3_hashLong_64b_internal(input, k[:], XXH3_accumulate_512, XXH3_scramble_accumulator) + return XXH3_hashLong_64b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } /* @@ -1020,14 +896,14 @@ XXH3_hashLong_64b_default :: #force_no_inline proc(input: []u8, seed64: xxh_u64, It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe?), but the difference is large and easily measurable. */ +@(optimization_mode="speed") XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc(input: []u8, seed: xxh_u64, f_acc512: XXH3_accumulate_512_f, f_scramble: XXH3_scramble_accumulator_f, f_init_sec: XXH3_init_custom_secret_f) -> (hash: xxh_u64) { if seed == 0 { - k := XXH3_kSecret - return XXH3_hashLong_64b_internal(input, k[:], f_acc512, f_scramble) + return XXH3_hashLong_64b_internal(input, XXH3_kSecret[:], f_acc512, f_scramble) } { secret: [XXH_SECRET_DEFAULT_SIZE]u8 @@ -1039,6 +915,7 @@ XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc(input: []u8, /* It's important for performance that XXH3_hashLong is not inlined. */ +@(optimization_mode="speed") XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_withSeed_internal(input, seed, XXH3_accumulate_512, XXH3_scramble_accumulator, XXH3_init_custom_secret) } @@ -1046,11 +923,8 @@ XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, XXH3_hashLong64_f :: #type proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: xxh_u64) +@(optimization_mode="speed") XXH3_64bits_internal :: proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLong: XXH3_hashLong64_f) -> (hash: xxh_u64) { - - - - assert(len(secret) >= XXH3_SECRET_SIZE_MIN) /* If an action is to be taken if len(secret) condition is not respected, it should be done here. @@ -1069,377 +943,19 @@ XXH3_64bits_internal :: proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLon } /* === Public entry point === */ - +@(optimization_mode="speed") XXH3_64_default :: proc(input: []u8) -> (hash: xxh_u64) { - k := XXH3_kSecret - return XXH3_64bits_internal(input, 0, k[:], XXH3_hashLong_64b_default) + return XXH3_64bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_64b_default) } +@(optimization_mode="speed") XXH3_64_with_seed :: proc(input: []u8, seed: xxh_u64) -> (hash: xxh_u64) { - k := XXH3_kSecret - return XXH3_64bits_internal(input, seed, k[:], XXH3_hashLong_64b_withSeed) + return XXH3_64bits_internal(input, seed, XXH3_kSecret[:], XXH3_hashLong_64b_withSeed) } +@(optimization_mode="speed") XXH3_64_with_secret :: proc(input, secret: []u8) -> (hash: xxh_u64) { return XXH3_64bits_internal(input, 0, secret, XXH3_hashLong_64b_withSecret) } -XXH3_64 :: proc { XXH3_64_default, XXH3_64_with_seed, XXH3_64_with_secret } - -/* - -/* === XXH3 streaming === */ - -/* - * Malloc's a pointer that is always aligned to align. - * - * This must be freed with `XXH_alignedFree()`. - * - * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte - * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 - * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. - * - * This underalignment previously caused a rather obvious crash which went - * completely unnoticed due to XXH3_createState() not actually being tested. - * Credit to RedSpah for noticing this bug. - * - * The alignment is done manually: Functions like posix_memalign or _mm_malloc - * are avoided: To maintain portability, we would have to write a fallback - * like this anyways, and besides, testing for the existence of library - * functions without relying on external build tools is impossible. - * - * The method is simple: Overallocate, manually align, and store the offset - * to the original behind the returned pointer. - * - * Align must be a power of 2 and 8 <= align <= 128. - */ -static void* XXH_alignedMalloc(size_t s, size_t align) -{ - XXH_ASSERT(align <= 128 && align >= 8); /* range check */ - XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ - XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ - { /* Overallocate to make room for manual realignment and an offset byte */ - xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); - if (base != NULL) { - /* - * Get the offset needed to align this pointer. - * - * Even if the returned pointer is aligned, there will always be - * at least one byte to store the offset to the original pointer. - */ - size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ - /* Add the offset for the now-aligned pointer */ - xxh_u8* ptr = base + offset; - - XXH_ASSERT((size_t)ptr % align == 0); - - /* Store the offset immediately before the returned pointer. */ - ptr[-1] = (xxh_u8)offset; - return ptr; - } - return NULL; - } -} -/* - * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass - * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. - */ -static void XXH_alignedFree(void* p) -{ - if (p != NULL) { - xxh_u8* ptr = (xxh_u8*)p; - /* Get the offset byte we added in XXH_malloc. */ - xxh_u8 offset = ptr[-1]; - /* Free the original malloc'd pointer */ - xxh_u8* base = ptr - offset; - XXH_free(base); - } -} -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) -{ - XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); - if (state==NULL) return NULL; - XXH3_INITSTATE(state); - return state; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) -{ - XXH_alignedFree(statePtr); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API void -XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) -{ - memcpy(dst_state, src_state, sizeof(*dst_state)); -} - -static void -XXH3_reset_internal(XXH3_state_t* statePtr, - XXH64_hash_t seed, - const void* secret, size_t secretSize) -{ - size_t const initStart = offsetof(XXH3_state_t, bufferedSize); - size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; - XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); - XXH_ASSERT(statePtr != NULL); - /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ - memset((char*)statePtr + initStart, 0, initLength); - statePtr->acc[0] = XXH_XXH_PRIME32_3; - statePtr->acc[1] = XXH_PRIME64_1; - statePtr->acc[2] = XXH_PRIME64_2; - statePtr->acc[3] = XXH_PRIME64_3; - statePtr->acc[4] = XXH_PRIME64_4; - statePtr->acc[5] = XXH_XXH_PRIME32_2; - statePtr->acc[6] = XXH_PRIME64_5; - statePtr->acc[7] = XXH_XXH_PRIME32_1; - statePtr->seed = seed; - statePtr->extSecret = (const unsigned char*)secret; - XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); - statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; - statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset(XXH3_state_t* statePtr) -{ - if (statePtr == NULL) return XXH_ERROR; - XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) -{ - if (statePtr == NULL) return XXH_ERROR; - XXH3_reset_internal(statePtr, 0, secret, secretSize); - if (secret == NULL) return XXH_ERROR; - if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) -{ - if (statePtr == NULL) return XXH_ERROR; - if (seed==0) return XXH3_64bits_reset(statePtr); - if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed); - XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); - return XXH_OK; -} - -/* Note : when XXH3_consumeStripes() is invoked, - * there must be a guarantee that at least one more byte must be consumed from input - * so that the function can blindly consume all stripes using the "normal" secret segment */ -XXH_FORCE_INLINE void -XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, - size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, - const xxh_u8* XXH_RESTRICT input, size_t nbStripes, - const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, - XXH3_f_accumulate_512 f_acc512, - XXH3_f_scrambleAcc f_scramble) -{ - XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ - XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); - if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { - /* need a scrambling operation */ - size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; - size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; - XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); - f_scramble(acc, secret + secretLimit); - XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); - *nbStripesSoFarPtr = nbStripesAfterBlock; - } else { - XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); - *nbStripesSoFarPtr += nbStripes; - } -} - -/* - * Both XXH3_64bits_update and XXH3_128bits_update use this routine. - */ -XXH_FORCE_INLINE XXH_errorcode -XXH3_update(XXH3_state_t* state, - const xxh_u8* input, size_t len, - XXH3_f_accumulate_512 f_acc512, - XXH3_f_scrambleAcc f_scramble) -{ - if (input==NULL) -#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) - return XXH_OK; -#else - return XXH_ERROR; -#endif - - { const xxh_u8* const bEnd = input + len; - const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; - - state->totalLen += len; - XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); - - if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */ - XXH_memcpy(state->buffer + state->bufferedSize, input, len); - state->bufferedSize += (XXH32_hash_t)len; - return XXH_OK; - } - /* total input is now > XXH3_INTERNALBUFFER_SIZE */ - - #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) - XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ - - /* - * Internal buffer is partially filled (always, except at beginning) - * Complete it, then consume it. - */ - if (state->bufferedSize) { - size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; - XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); - input += loadSize; - XXH3_consumeStripes(state->acc, - &state->nbStripesSoFar, state->nbStripesPerBlock, - state->buffer, XXH3_INTERNALBUFFER_STRIPES, - secret, state->secretLimit, - f_acc512, f_scramble); - state->bufferedSize = 0; - } - XXH_ASSERT(input < bEnd); - - /* Consume input by a multiple of internal buffer size */ - if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { - const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; - do { - XXH3_consumeStripes(state->acc, - &state->nbStripesSoFar, state->nbStripesPerBlock, - input, XXH3_INTERNALBUFFER_STRIPES, - secret, state->secretLimit, - f_acc512, f_scramble); - input += XXH3_INTERNALBUFFER_SIZE; - } while (input<limit); - /* for last partial stripe */ - memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); - } - XXH_ASSERT(input < bEnd); - - /* Some remaining input (always) : buffer it */ - XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); - state->bufferedSize = (XXH32_hash_t)(bEnd-input); - } - - return XXH_OK; -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH_errorcode -XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) -{ - return XXH3_update(state, (const xxh_u8*)input, len, - XXH3_accumulate_512, XXH3_scrambleAcc); -} - - -XXH_FORCE_INLINE void -XXH3_digest_long (XXH64_hash_t* acc, - const XXH3_state_t* state, - const unsigned char* secret) -{ - /* - * Digest on a local copy. This way, the state remains unaltered, and it can - * continue ingesting more input afterwards. - */ - memcpy(acc, state->acc, sizeof(state->acc)); - if (state->bufferedSize >= XXH_STRIPE_LEN) { - size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; - size_t nbStripesSoFar = state->nbStripesSoFar; - XXH3_consumeStripes(acc, - &nbStripesSoFar, state->nbStripesPerBlock, - state->buffer, nbStripes, - secret, state->secretLimit, - XXH3_accumulate_512, XXH3_scrambleAcc); - /* last stripe */ - XXH3_accumulate_512(acc, - state->buffer + state->bufferedSize - XXH_STRIPE_LEN, - secret + state->secretLimit - XXH_SECRET_LASTACC_START); - } else { /* bufferedSize < XXH_STRIPE_LEN */ - xxh_u8 lastStripe[XXH_STRIPE_LEN]; - size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; - XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ - memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); - memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); - XXH3_accumulate_512(acc, - lastStripe, - secret + state->secretLimit - XXH_SECRET_LASTACC_START); - } -} - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) -{ - const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; - if (state->totalLen > XXH3_MIDSIZE_MAX) { - XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; - XXH3_digest_long(acc, state, secret); - return XXH3_mergeAccs(acc, - secret + XXH_SECRET_MERGEACCS_START, - (xxh_u64)state->totalLen * XXH_PRIME64_1); - } - /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ - if (state->seed) - return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); - return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), - secret, state->secretLimit + XXH_STRIPE_LEN); -} - - -#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) - -/*! @ingroup xxh3_family */ -XXH_PUBLIC_API void -XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize) -{ - XXH_ASSERT(secretBuffer != NULL); - if (customSeedSize == 0) { - memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); - return; - } - XXH_ASSERT(customSeed != NULL); - - { size_t const segmentSize = sizeof(XXH128_hash_t); - size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize; - XXH128_canonical_t scrambler; - XXH64_hash_t seeds[12]; - size_t segnb; - XXH_ASSERT(nbSegments == 12); - XXH_ASSERT(segmentSize * nbSegments == XXH_SECRET_DEFAULT_SIZE); /* exact multiple */ - XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); - - /* - * Copy customSeed to seeds[], truncating or repeating as necessary. - */ - { size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds)); - size_t filled = toFill; - memcpy(seeds, customSeed, toFill); - while (filled < sizeof(seeds)) { - toFill = XXH_MIN(filled, sizeof(seeds) - filled); - memcpy((char*)seeds + filled, seeds, toFill); - filled += toFill; - } } - - /* generate secret */ - memcpy(secretBuffer, &scrambler, sizeof(scrambler)); - for (segnb=1; segnb < nbSegments; segnb++) { - size_t const segmentStart = segnb * segmentSize; - XXH128_canonical_t segment; - XXH128_canonicalFromHash(&segment, - XXH128(&scrambler, sizeof(scrambler), XXH64_read64(seeds + segnb) + segnb) ); - memcpy((char*)secretBuffer + segmentStart, &segment, sizeof(segment)); - } } -} - -*/ +XXH3_64 :: proc { XXH3_64_default, XXH3_64_with_seed, XXH3_64_with_secret }
\ No newline at end of file diff --git a/core/hash/xxhash/xxhash_32.odin b/core/hash/xxhash/xxhash_32.odin index f41161133..e63d998dd 100644 --- a/core/hash/xxhash/xxhash_32.odin +++ b/core/hash/xxhash/xxhash_32.odin @@ -197,12 +197,12 @@ XXH32 :: proc(input: []u8, seed := XXH32_DEFAULT_SEED) -> (digest: XXH32_hash) { */ XXH32_create_state :: proc(allocator := context.allocator) -> (res: ^XXH32_state, err: Error) { state := new(XXH32_state, allocator) - return state, nil if state != nil else .Error + return state, .None if state != nil else .Error } XXH32_destroy_state :: proc(state: ^XXH32_state, allocator := context.allocator) -> (err: Error) { free(state, allocator) - return nil + return .None } XXH32_copy_state :: proc(dest, src: ^XXH32_state) { @@ -221,7 +221,7 @@ XXH32_reset_state :: proc(state_ptr: ^XXH32_state, seed := XXH32_DEFAULT_SEED) - Do not write into reserved, planned to be removed in a future version. */ mem_copy(state_ptr, &state, size_of(state) - size_of(state.reserved)) - return nil + return .None } XXH32_update :: proc(state: ^XXH32_state, input: []u8) -> (err: Error) { @@ -236,7 +236,7 @@ XXH32_update :: proc(state: ^XXH32_state, input: []u8) -> (err: Error) { ptr := uintptr(raw_data(state.mem32[:])) + uintptr(state.memsize) mem_copy(rawptr(ptr), raw_data(input), int(length)) state.memsize += XXH32_hash(length) - return nil + return .None } if state.memsize > 0 {/* Some data left from previous update */ @@ -276,7 +276,7 @@ XXH32_update :: proc(state: ^XXH32_state, input: []u8) -> (err: Error) { mem_copy(raw_data(state.mem32[:]), raw_data(buf[:]), int(length)) state.memsize = u32(length) } - return nil + return .None } XXH32_digest :: proc(state: ^XXH32_state) -> (res: XXH32_hash) { diff --git a/core/hash/xxhash/xxhash_64.odin b/core/hash/xxhash/xxhash_64.odin index d535a134c..e95842168 100644 --- a/core/hash/xxhash/xxhash_64.odin +++ b/core/hash/xxhash/xxhash_64.odin @@ -163,12 +163,12 @@ XXH64 :: proc(input: []u8, seed := XXH64_DEFAULT_SEED) -> (digest: XXH64_hash) { */ XXH64_create_state :: proc(allocator := context.allocator) -> (res: ^XXH64_state, err: Error) { state := new(XXH64_state, allocator) - return state, nil if state != nil else .Error + return state, .None if state != nil else .Error } XXH64_destroy_state :: proc(state: ^XXH64_state, allocator := context.allocator) -> (err: Error) { free(state, allocator) - return nil + return .None } XXH64_copy_state :: proc(dest, src: ^XXH64_state) { @@ -187,7 +187,7 @@ XXH64_reset_state :: proc(state_ptr: ^XXH64_state, seed := XXH64_DEFAULT_SEED) - Fo not write into reserved64, might be removed in a future version. */ mem_copy(state_ptr, &state, size_of(state) - size_of(state.reserved64)) - return nil + return .None } @(optimization_mode="speed") @@ -201,7 +201,7 @@ XXH64_update :: proc(state: ^XXH64_state, input: []u8) -> (err: Error) { ptr := uintptr(raw_data(state.mem64[:])) + uintptr(state.memsize) mem_copy(rawptr(ptr), raw_data(input), int(length)) state.memsize += u32(length) - return nil + return .None } if state.memsize > 0 { /* tmp buffer is full */ @@ -241,7 +241,7 @@ XXH64_update :: proc(state: ^XXH64_state, input: []u8) -> (err: Error) { mem_copy(raw_data(state.mem64[:]), raw_data(buf[:]), int(length)) state.memsize = u32(length) } - return nil + return .None } @(optimization_mode="speed") |