From f72d345f0d4e175ad319f546ab6f499fca4c42c0 Mon Sep 17 00:00:00 2001 From: Dmitrii Krosh Date: Fri, 14 Aug 2026 04:26:43 +0300 Subject: [PATCH] add t1ha2 hash and test results --- .../new_testing/hash_funcs/t1ha2/bin_hash | Bin 0 -> 21240 bytes .../new_testing/hash_funcs/t1ha2/bin_hash.c | 113 ++ .../hash_funcs/t1ha2/upstream/LICENSE | 23 + .../hash_funcs/t1ha2/upstream/src/t1ha2.c | 383 +++++ .../hash_funcs/t1ha2/upstream/src/t1ha_bits.h | 1254 +++++++++++++++++ .../t1ha2/upstream/src/t1ha_selfcheck.h | 76 + .../hash_funcs/t1ha2/upstream/t1ha.h | 719 ++++++++++ hash_testing/new_testing/probability_map.py | 1 + .../probability_maps/jenkinsOAAT.csv | 8 + .../probability_maps/jenkinsOAAT_bits.png | Bin 0 -> 38786 bytes .../jenkinsOAAT_deviation.png | Bin 0 -> 24640 bytes .../new_testing/probability_maps/t1ha2.csv | 8 + .../probability_maps/t1ha2_bits.png | Bin 0 -> 34872 bytes .../probability_maps/t1ha2_deviation.png | Bin 0 -> 24040 bytes .../new_testing/probability_maps/xxh64.csv | 8 + .../probability_maps/xxh64_bits.png | Bin 0 -> 35711 bytes .../probability_maps/xxh64_deviation.png | Bin 0 -> 24576 bytes .../new_testing/tests/test_t1ha2_bin_hash.py | 115 ++ 18 files changed, 2708 insertions(+) create mode 100755 hash_testing/new_testing/hash_funcs/t1ha2/bin_hash create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/bin_hash.c create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/upstream/LICENSE create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha2.c create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_bits.h create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_selfcheck.h create mode 100644 hash_testing/new_testing/hash_funcs/t1ha2/upstream/t1ha.h create mode 100644 hash_testing/new_testing/probability_maps/jenkinsOAAT.csv create mode 100644 hash_testing/new_testing/probability_maps/jenkinsOAAT_bits.png create mode 100644 hash_testing/new_testing/probability_maps/jenkinsOAAT_deviation.png create mode 100644 hash_testing/new_testing/probability_maps/t1ha2.csv create mode 100644 hash_testing/new_testing/probability_maps/t1ha2_bits.png create mode 100644 hash_testing/new_testing/probability_maps/t1ha2_deviation.png create mode 100644 hash_testing/new_testing/probability_maps/xxh64.csv create mode 100644 hash_testing/new_testing/probability_maps/xxh64_bits.png create mode 100644 hash_testing/new_testing/probability_maps/xxh64_deviation.png create mode 100644 hash_testing/new_testing/tests/test_t1ha2_bin_hash.py diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/bin_hash b/hash_testing/new_testing/hash_funcs/t1ha2/bin_hash new file mode 100755 index 0000000000000000000000000000000000000000..e9686e9af25ab01ee9a84867fb61ae4cfa135b1f GIT binary patch literal 21240 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 literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/bin_hash.c b/hash_testing/new_testing/hash_funcs/t1ha2/bin_hash.c new file mode 100644 index 0000000..40d8da3 --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/bin_hash.c @@ -0,0 +1,113 @@ +/* + * Standalone t1ha2_atonce command-line wrapper for avalanche testing. + * + * Upstream: https://gitflic.ru/project/erthink/t1ha + * Commit: 00eb779b6c042ccd831ec2f1ae757409c73f39f6 + * Algorithm: t1ha2_atonce(data, length, seed=0), stable portable 64-bit mode. + * + * The vendored upstream implementation is licensed under the zlib License; + * see upstream/LICENSE. This wrapper is an altered integration file and is not + * represented as an original upstream source file. + */ + +#include +#include +#include +#include +#include + +#define T1HA0_DISABLED +#define T1HA1_DISABLED +#define T1HA_SYS_UNALIGNED_ACCESS 0 +#define T1HA_USE_FAST_ONESHOT_READ 0 +#include "upstream/src/t1ha2.c" + +#define T1HA2_SEED UINT64_C(0) + +static int is_ascii_trailing_space(unsigned char character) +{ + return character == ' ' || character == '\t' || character == '\n' || + character == '\r' || character == '\v' || character == '\f'; +} + +static int read_stdin(unsigned char **data, size_t *length) +{ + size_t capacity = 256; + unsigned char *buffer = malloc(capacity); + + if (buffer == NULL) { + return -1; + } + + *length = 0; + for (;;) { + size_t available = capacity - *length; + size_t bytes_read = fread(buffer + *length, 1, available, stdin); + *length += bytes_read; + + if (bytes_read < available) { + if (ferror(stdin)) { + free(buffer); + return -1; + } + break; + } + + if (capacity > SIZE_MAX / 2U) { + free(buffer); + return -1; + } + capacity *= 2U; + + { + unsigned char *larger_buffer = realloc(buffer, capacity); + if (larger_buffer == NULL) { + free(buffer); + return -1; + } + buffer = larger_buffer; + } + } + + *data = buffer; + return 0; +} + +int main(int argc, char **argv) +{ + const unsigned char *word; + unsigned char *stdin_buffer = NULL; + size_t length; + + if (argc > 2) { + fprintf(stderr, "usage: %s [ASCII_WORD]\n", argv[0]); + return EXIT_FAILURE; + } + + if (argc == 2) { + word = (const unsigned char *)argv[1]; + length = strlen(argv[1]); + } else { + if (read_stdin(&stdin_buffer, &length) != 0) { + fprintf(stderr, "failed to read input\n"); + return EXIT_FAILURE; + } + word = stdin_buffer; + } + + while (length > 0U && is_ascii_trailing_space(word[length - 1U])) { + --length; + } + + for (size_t index = 0; index < length; ++index) { + if (word[index] > 0x7fU) { + fprintf(stderr, "input must contain ASCII characters only\n"); + free(stdin_buffer); + return EXIT_FAILURE; + } + } + + printf("%016" PRIx64 "\n", t1ha2_atonce(word, length, T1HA2_SEED)); + free(stdin_buffer); + return EXIT_SUCCESS; +} diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/upstream/LICENSE b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/LICENSE new file mode 100644 index 0000000..c198acc --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/LICENSE @@ -0,0 +1,23 @@ + zlib License, see https://en.wikipedia.org/wiki/Zlib_License + + Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com, + Fast Positive Hash. + + Portions Copyright (c) 2010-2013 Leonid Yuriev , + The 1Hippeus project (t1h). + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha2.c b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha2.c new file mode 100644 index 0000000..009f922 --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha2.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com, + * Fast Positive Hash. + * + * Portions Copyright (c) 2010-2020 Leonid Yuriev , + * The 1Hippeus project (t1h). + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * t1ha = { Fast Positive Hash, aka "Позитивный Хэш" } + * by [Positive Technologies](https://www.ptsecurity.ru) + * + * Briefly, it is a 64-bit Hash Function: + * 1. Created for 64-bit little-endian platforms, in predominantly for x86_64, + * but portable and without penalties it can run on any 64-bit CPU. + * 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash + * and all others portable hash-functions (which do not use specific + * hardware tricks). + * 3. Not suitable for cryptography. + * + * The Future will (be) Positive. Всё будет хорошо. + * + * ACKNOWLEDGEMENT: + * The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев) + * for The 1Hippeus project - zerocopy messaging in the spirit of Sparta! + */ + +#ifndef T1HA2_DISABLED +#include "t1ha_bits.h" +#include "t1ha_selfcheck.h" + +static __always_inline void init_ab(t1ha_state256_t *s, uint64_t x, + uint64_t y) { + s->n.a = x; + s->n.b = y; +} + +static __always_inline void init_cd(t1ha_state256_t *s, uint64_t x, + uint64_t y) { + s->n.c = rot64(y, 23) + ~x; + s->n.d = ~y + rot64(x, 19); +} + +/* TODO: C++ template in the next version */ +#define T1HA2_UPDATE(ENDIANNES, ALIGNESS, state, v) \ + do { \ + t1ha_state256_t *const s = state; \ + const uint64_t w0 = fetch64_##ENDIANNES##_##ALIGNESS(v + 0); \ + const uint64_t w1 = fetch64_##ENDIANNES##_##ALIGNESS(v + 1); \ + const uint64_t w2 = fetch64_##ENDIANNES##_##ALIGNESS(v + 2); \ + const uint64_t w3 = fetch64_##ENDIANNES##_##ALIGNESS(v + 3); \ + \ + const uint64_t d02 = w0 + rot64(w2 + s->n.d, 56); \ + const uint64_t c13 = w1 + rot64(w3 + s->n.c, 19); \ + s->n.d ^= s->n.b + rot64(w1, 38); \ + s->n.c ^= s->n.a + rot64(w0, 57); \ + s->n.b ^= prime_6 * (c13 + w2); \ + s->n.a ^= prime_5 * (d02 + w3); \ + } while (0) + +static __always_inline void squash(t1ha_state256_t *s) { + s->n.a ^= prime_6 * (s->n.c + rot64(s->n.d, 23)); + s->n.b ^= prime_5 * (rot64(s->n.c, 19) + s->n.d); +} + +/* TODO: C++ template in the next version */ +#define T1HA2_LOOP(ENDIANNES, ALIGNESS, state, data, len) \ + do { \ + const void *detent = (const uint8_t *)data + len - 31; \ + do { \ + const uint64_t *v = (const uint64_t *)data; \ + data = (const uint64_t *)data + 4; \ + prefetch(data); \ + T1HA2_UPDATE(le, ALIGNESS, state, v); \ + } while (likely(data < detent)); \ + } while (0) + +/* TODO: C++ template in the next version */ +#define T1HA2_TAIL_AB(ENDIANNES, ALIGNESS, state, data, len) \ + do { \ + t1ha_state256_t *const s = state; \ + const uint64_t *v = (const uint64_t *)data; \ + switch (len) { \ + default: \ + mixup64(&s->n.a, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_4); \ + /* fall through */ \ + case 24: \ + case 23: \ + case 22: \ + case 21: \ + case 20: \ + case 19: \ + case 18: \ + case 17: \ + mixup64(&s->n.b, &s->n.a, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_3); \ + /* fall through */ \ + case 16: \ + case 15: \ + case 14: \ + case 13: \ + case 12: \ + case 11: \ + case 10: \ + case 9: \ + mixup64(&s->n.a, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_2); \ + /* fall through */ \ + case 8: \ + case 7: \ + case 6: \ + case 5: \ + case 4: \ + case 3: \ + case 2: \ + case 1: \ + mixup64(&s->n.b, &s->n.a, tail64_##ENDIANNES##_##ALIGNESS(v, len), \ + prime_1); \ + /* fall through */ \ + case 0: \ + return final64(s->n.a, s->n.b); \ + } \ + } while (0) + +/* TODO: C++ template in the next version */ +#define T1HA2_TAIL_ABCD(ENDIANNES, ALIGNESS, state, data, len) \ + do { \ + t1ha_state256_t *const s = state; \ + const uint64_t *v = (const uint64_t *)data; \ + switch (len) { \ + default: \ + mixup64(&s->n.a, &s->n.d, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_4); \ + /* fall through */ \ + case 24: \ + case 23: \ + case 22: \ + case 21: \ + case 20: \ + case 19: \ + case 18: \ + case 17: \ + mixup64(&s->n.b, &s->n.a, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_3); \ + /* fall through */ \ + case 16: \ + case 15: \ + case 14: \ + case 13: \ + case 12: \ + case 11: \ + case 10: \ + case 9: \ + mixup64(&s->n.c, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \ + prime_2); \ + /* fall through */ \ + case 8: \ + case 7: \ + case 6: \ + case 5: \ + case 4: \ + case 3: \ + case 2: \ + case 1: \ + mixup64(&s->n.d, &s->n.c, tail64_##ENDIANNES##_##ALIGNESS(v, len), \ + prime_1); \ + /* fall through */ \ + case 0: \ + return final128(s->n.a, s->n.b, s->n.c, s->n.d, extra_result); \ + } \ + } while (0) + +static __always_inline uint64_t final128(uint64_t a, uint64_t b, uint64_t c, + uint64_t d, uint64_t *h) { + mixup64(&a, &b, rot64(c, 41) ^ d, prime_0); + mixup64(&b, &c, rot64(d, 23) ^ a, prime_6); + mixup64(&c, &d, rot64(a, 19) ^ b, prime_5); + mixup64(&d, &a, rot64(b, 31) ^ c, prime_4); + *h = c + d; + return a ^ b; +} + +//------------------------------------------------------------------------------ + +uint64_t t1ha2_atonce(const void *data, size_t length, uint64_t seed) { + t1ha_state256_t state; + init_ab(&state, seed, length); + +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT + if (unlikely(length > 32)) { + init_cd(&state, seed, length); +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &state, data, length); + squash(&state); + length &= 31; + } + T1HA2_TAIL_AB(le, unaligned, &state, data, length); +#else + const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0; + if (misaligned) { + if (unlikely(length > 32)) { + init_cd(&state, seed, length); +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &state, data, length); + squash(&state); + length &= 31; + } + T1HA2_TAIL_AB(le, unaligned, &state, data, length); + } else { + if (unlikely(length > 32)) { + init_cd(&state, seed, length); +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, aligned, &state, data, length); + squash(&state); + length &= 31; + } + T1HA2_TAIL_AB(le, aligned, &state, data, length); + } +#endif +} + +uint64_t t1ha2_atonce128(uint64_t *__restrict extra_result, + const void *__restrict data, size_t length, + uint64_t seed) { + t1ha_state256_t state; + init_ab(&state, seed, length); + init_cd(&state, seed, length); + +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT + if (unlikely(length > 32)) { +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &state, data, length); + length &= 31; + } + T1HA2_TAIL_ABCD(le, unaligned, &state, data, length); +#else + const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0; + if (misaligned) { + if (unlikely(length > 32)) { +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &state, data, length); + length &= 31; + } + T1HA2_TAIL_ABCD(le, unaligned, &state, data, length); + } else { + if (unlikely(length > 32)) { +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, aligned, &state, data, length); + length &= 31; + } + T1HA2_TAIL_ABCD(le, aligned, &state, data, length); + } +#endif +} + +//------------------------------------------------------------------------------ + +void t1ha2_init(t1ha_context_t *ctx, uint64_t seed_x, uint64_t seed_y) { + init_ab(&ctx->state, seed_x, seed_y); + init_cd(&ctx->state, seed_x, seed_y); + ctx->partial = 0; + ctx->total = 0; +} + +void t1ha2_update(t1ha_context_t *__restrict ctx, const void *__restrict data, + size_t length) { + ctx->total += length; + + if (ctx->partial) { + const size_t left = 32 - ctx->partial; + const size_t chunk = (length >= left) ? left : length; + memcpy(ctx->buffer.bytes + ctx->partial, data, chunk); + ctx->partial += chunk; + if (ctx->partial < 32) { + assert(left >= length); + return; + } + ctx->partial = 0; + data = (const uint8_t *)data + chunk; + length -= chunk; + T1HA2_UPDATE(le, aligned, &ctx->state, ctx->buffer.u64); + } + + if (length >= 32) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &ctx->state, data, length); +#else + const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0; + if (misaligned) { +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, unaligned, &ctx->state, data, length); + } else { +#if defined(__LCC__) && __LCC__ > 123 +/* Форсирует комбинирование пар арифметических операций в двухэтажные операции + * в ближайшем после объявления директивы цикле, даже если эвристики оптимизации + * говорят, что это нецелесообразно */ +#pragma comb_oper +#endif /* E2K LCC > 1.23 */ + T1HA2_LOOP(le, aligned, &ctx->state, data, length); + } +#endif + length &= 31; + } + + if (length) + memcpy(ctx->buffer.bytes, data, ctx->partial = length); +} + +uint64_t t1ha2_final(t1ha_context_t *__restrict ctx, + uint64_t *__restrict extra_result) { + uint64_t bits = (ctx->total << 3) ^ (UINT64_C(1) << 63); +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + bits = bswap64(bits); +#endif + t1ha2_update(ctx, &bits, 8); + + if (likely(!extra_result)) { + squash(&ctx->state); + T1HA2_TAIL_AB(le, aligned, &ctx->state, ctx->buffer.u64, ctx->partial); + } + + T1HA2_TAIL_ABCD(le, aligned, &ctx->state, ctx->buffer.u64, ctx->partial); +} + +#endif /* T1HA2_DISABLED */ diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_bits.h b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_bits.h new file mode 100644 index 0000000..9d0f337 --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_bits.h @@ -0,0 +1,1254 @@ +/* + * Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com, + * Fast Positive Hash. + * + * Portions Copyright (c) 2010-2020 Leonid Yuriev , + * The 1Hippeus project (t1h). + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * t1ha = { Fast Positive Hash, aka "Позитивный Хэш" } + * by [Positive Technologies](https://www.ptsecurity.ru) + * + * Briefly, it is a 64-bit Hash Function: + * 1. Created for 64-bit little-endian platforms, in predominantly for x86_64, + * but portable and without penalties it can run on any 64-bit CPU. + * 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash + * and all others portable hash-functions (which do not use specific + * hardware tricks). + * 3. Not suitable for cryptography. + * + * The Future will (be) Positive. Всё будет хорошо. + * + * ACKNOWLEDGEMENT: + * The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев) + * for The 1Hippeus project - zerocopy messaging in the spirit of Sparta! + */ + +#pragma once + +#if defined(_MSC_VER) +#pragma warning(disable : 4201) /* nameless struct/union */ +#if _MSC_VER > 1800 +#pragma warning(disable : 4464) /* relative include path contains '..' */ +#endif /* 1800 */ +#endif /* MSVC */ +#include "../t1ha.h" + +#ifndef T1HA_USE_FAST_ONESHOT_READ +/* Define it to 1 for little bit faster code. + * Unfortunately this may triggering a false-positive alarms from Valgrind, + * AddressSanitizer and other similar tool. + * So, define it to 0 for calmness if doubt. */ +#define T1HA_USE_FAST_ONESHOT_READ 1 +#endif /* T1HA_USE_FAST_ONESHOT_READ */ + +/*****************************************************************************/ + +#include /* for assert() */ +#include /* for bool */ +#include /* for memcpy() */ + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ && \ + __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ +#error Unsupported byte order. +#endif + +#define T1HA_UNALIGNED_ACCESS__UNABLE 0 +#define T1HA_UNALIGNED_ACCESS__SLOW 1 +#define T1HA_UNALIGNED_ACCESS__EFFICIENT 2 + +#ifndef T1HA_SYS_UNALIGNED_ACCESS +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +#define T1HA_SYS_UNALIGNED_ACCESS T1HA_UNALIGNED_ACCESS__EFFICIENT +#elif defined(__ia32__) +#define T1HA_SYS_UNALIGNED_ACCESS T1HA_UNALIGNED_ACCESS__EFFICIENT +#elif defined(__e2k__) +#define T1HA_SYS_UNALIGNED_ACCESS T1HA_UNALIGNED_ACCESS__SLOW +#else +#define T1HA_SYS_UNALIGNED_ACCESS T1HA_UNALIGNED_ACCESS__UNABLE +#endif +#endif /* T1HA_SYS_UNALIGNED_ACCESS */ + +#define ALIGNMENT_16 2 +#define ALIGNMENT_32 4 +#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define ALIGNMENT_64 8 +#else +#define ALIGNMENT_64 4 +#endif + +#ifndef PAGESIZE +#define PAGESIZE 4096 +#endif /* PAGESIZE */ + +/***************************************************************************/ + +#ifndef __has_builtin +#define __has_builtin(x) (0) +#endif + +#ifndef __has_warning +#define __has_warning(x) (0) +#endif + +#ifndef __has_feature +#define __has_feature(x) (0) +#endif + +#ifndef __has_extension +#define __has_extension(x) (0) +#endif + +#if __has_feature(address_sanitizer) +#define __SANITIZE_ADDRESS__ 1 +#endif + +#ifndef __optimize +#if defined(__clang__) && !__has_attribute(__optimize__) +#define __optimize(ops) +#elif defined(__GNUC__) || __has_attribute(__optimize__) +#define __optimize(ops) __attribute__((__optimize__(ops))) +#else +#define __optimize(ops) +#endif +#endif /* __optimize */ + +#ifndef __cold +#if defined(__OPTIMIZE__) +#if defined(__e2k__) +#define __cold __optimize(1) __attribute__((__cold__)) +#elif defined(__clang__) && !__has_attribute(__cold__) && \ + __has_attribute(__section__) +/* just put infrequently used functions in separate section */ +#define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os") +#elif defined(__GNUC__) || __has_attribute(__cold__) +#define __cold __attribute__((__cold__)) __optimize("Os") +#else +#define __cold __optimize("Os") +#endif +#else +#define __cold +#endif +#endif /* __cold */ + +#if __GNUC_PREREQ(4, 4) || defined(__clang__) + +#if defined(__ia32__) || defined(__e2k__) +#include +#endif + +#if defined(__ia32__) && !defined(__cpuid_count) +#include +#endif + +#if defined(__e2k__) +#include +#endif + +#ifndef likely +#define likely(cond) __builtin_expect(!!(cond), 1) +#endif + +#ifndef unlikely +#define unlikely(cond) __builtin_expect(!!(cond), 0) +#endif + +#if __GNUC_PREREQ(4, 5) || __has_builtin(__builtin_unreachable) +#define unreachable() __builtin_unreachable() +#endif + +#define bswap64(v) __builtin_bswap64(v) +#define bswap32(v) __builtin_bswap32(v) +#if __GNUC_PREREQ(4, 8) || __has_builtin(__builtin_bswap16) +#define bswap16(v) __builtin_bswap16(v) +#endif + +#if !defined(__maybe_unused) && \ + (__GNUC_PREREQ(4, 3) || __has_attribute(__unused__)) +#define __maybe_unused __attribute__((__unused__)) +#endif + +#if !defined(__always_inline) && \ + (__GNUC_PREREQ(3, 2) || __has_attribute(__always_inline__)) +#define __always_inline __inline __attribute__((__always_inline__)) +#endif + +#if defined(__e2k__) + +#if __iset__ >= 3 +#define mul_64x64_high(a, b) __builtin_e2k_umulhd(a, b) +#endif /* __iset__ >= 3 */ + +#if __iset__ >= 5 +static __maybe_unused __always_inline unsigned +e2k_add64carry_first(uint64_t base, uint64_t addend, uint64_t *sum) { + *sum = base + addend; + return (unsigned)__builtin_e2k_addcd_c(base, addend, 0); +} +#define add64carry_first(base, addend, sum) \ + e2k_add64carry_first(base, addend, sum) + +static __maybe_unused __always_inline unsigned +e2k_add64carry_next(unsigned carry, uint64_t base, uint64_t addend, + uint64_t *sum) { + *sum = __builtin_e2k_addcd(base, addend, carry); + return (unsigned)__builtin_e2k_addcd_c(base, addend, carry); +} +#define add64carry_next(carry, base, addend, sum) \ + e2k_add64carry_next(carry, base, addend, sum) + +static __maybe_unused __always_inline void e2k_add64carry_last(unsigned carry, + uint64_t base, + uint64_t addend, + uint64_t *sum) { + *sum = __builtin_e2k_addcd(base, addend, carry); +} +#define add64carry_last(carry, base, addend, sum) \ + e2k_add64carry_last(carry, base, addend, sum) +#endif /* __iset__ >= 5 */ + +#define fetch64_be_aligned(ptr) ((uint64_t)__builtin_e2k_ld_64s_be(ptr)) +#define fetch32_be_aligned(ptr) ((uint32_t)__builtin_e2k_ld_32u_be(ptr)) + +#endif /* __e2k__ Elbrus */ + +#elif defined(_MSC_VER) + +#if _MSC_FULL_VER < 190024234 && defined(_M_IX86) +#pragma message( \ + "For AES-NI at least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required.") +#endif +#if _MSC_FULL_VER < 191526730 +#pragma message( \ + "It is recommended to use \"Microsoft C/C++ Compiler\" version 19.15.26730 (Visual Studio 2017 15.8) or newer.") +#endif +#if _MSC_FULL_VER < 180040629 +#error At least "Microsoft C/C++ Compiler" version 18.00.40629 (Visual Studio 2013 Update 5) is required. +#endif + +#pragma warning(push, 1) + +#include +#include +#define likely(cond) (cond) +#define unlikely(cond) (cond) +#define unreachable() __assume(0) +#define bswap64(v) _byteswap_uint64(v) +#define bswap32(v) _byteswap_ulong(v) +#define bswap16(v) _byteswap_ushort(v) +#define rot64(v, s) _rotr64(v, s) +#define rot32(v, s) _rotr(v, s) +#define __always_inline __forceinline + +#if defined(_M_X64) || defined(_M_IA64) +#pragma intrinsic(_umul128) +#define mul_64x64_128(a, b, ph) _umul128(a, b, ph) +#pragma intrinsic(_addcarry_u64) +#define add64carry_first(base, addend, sum) _addcarry_u64(0, base, addend, sum) +#define add64carry_next(carry, base, addend, sum) \ + _addcarry_u64(carry, base, addend, sum) +#define add64carry_last(carry, base, addend, sum) \ + (void)_addcarry_u64(carry, base, addend, sum) +#endif + +#if defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64) +#pragma intrinsic(__umulh) +#define mul_64x64_high(a, b) __umulh(a, b) +#endif + +#if defined(_M_IX86) +#pragma intrinsic(__emulu) +#define mul_32x32_64(a, b) __emulu(a, b) + +#if _MSC_VER >= 1915 /* LY: workaround for SSA-optimizer bug */ +#pragma intrinsic(_addcarry_u32) +#define add32carry_first(base, addend, sum) _addcarry_u32(0, base, addend, sum) +#define add32carry_next(carry, base, addend, sum) \ + _addcarry_u32(carry, base, addend, sum) +#define add32carry_last(carry, base, addend, sum) \ + (void)_addcarry_u32(carry, base, addend, sum) + +static __forceinline char +msvc32_add64carry_first(uint64_t base, uint64_t addend, uint64_t *sum) { + uint32_t *const sum32 = (uint32_t *)sum; + const uint32_t base_32l = (uint32_t)base; + const uint32_t base_32h = (uint32_t)(base >> 32); + const uint32_t addend_32l = (uint32_t)addend; + const uint32_t addend_32h = (uint32_t)(addend >> 32); + return add32carry_next(add32carry_first(base_32l, addend_32l, sum32), + base_32h, addend_32h, sum32 + 1); +} +#define add64carry_first(base, addend, sum) \ + msvc32_add64carry_first(base, addend, sum) + +static __forceinline char msvc32_add64carry_next(char carry, uint64_t base, + uint64_t addend, + uint64_t *sum) { + uint32_t *const sum32 = (uint32_t *)sum; + const uint32_t base_32l = (uint32_t)base; + const uint32_t base_32h = (uint32_t)(base >> 32); + const uint32_t addend_32l = (uint32_t)addend; + const uint32_t addend_32h = (uint32_t)(addend >> 32); + return add32carry_next(add32carry_next(carry, base_32l, addend_32l, sum32), + base_32h, addend_32h, sum32 + 1); +} +#define add64carry_next(carry, base, addend, sum) \ + msvc32_add64carry_next(carry, base, addend, sum) + +static __forceinline void msvc32_add64carry_last(char carry, uint64_t base, + uint64_t addend, + uint64_t *sum) { + uint32_t *const sum32 = (uint32_t *)sum; + const uint32_t base_32l = (uint32_t)base; + const uint32_t base_32h = (uint32_t)(base >> 32); + const uint32_t addend_32l = (uint32_t)addend; + const uint32_t addend_32h = (uint32_t)(addend >> 32); + add32carry_last(add32carry_next(carry, base_32l, addend_32l, sum32), base_32h, + addend_32h, sum32 + 1); +} +#define add64carry_last(carry, base, addend, sum) \ + msvc32_add64carry_last(carry, base, addend, sum) +#endif /* _MSC_FULL_VER >= 190024231 */ + +#elif defined(_M_ARM) +#define mul_32x32_64(a, b) _arm_umull(a, b) +#endif + +#pragma warning(pop) +#pragma warning(disable : 4514) /* 'xyz': unreferenced inline function \ + has been removed */ +#pragma warning(disable : 4710) /* 'xyz': function not inlined */ +#pragma warning(disable : 4711) /* function 'xyz' selected for \ + automatic inline expansion */ +#pragma warning(disable : 4127) /* conditional expression is constant */ +#pragma warning(disable : 4702) /* unreachable code */ +#endif /* Compiler */ + +#ifndef likely +#define likely(cond) (cond) +#endif +#ifndef unlikely +#define unlikely(cond) (cond) +#endif +#ifndef __maybe_unused +#define __maybe_unused +#endif +#ifndef __always_inline +#define __always_inline __inline +#endif +#ifndef unreachable +#define unreachable() \ + do { \ + } while (1) +#endif + +#ifndef bswap64 +#if defined(bswap_64) +#define bswap64 bswap_64 +#elif defined(__bswap_64) +#define bswap64 __bswap_64 +#else +static __always_inline uint64_t bswap64(uint64_t v) { + return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) | + ((v << 24) & UINT64_C(0x0000ff0000000000)) | + ((v << 8) & UINT64_C(0x000000ff00000000)) | + ((v >> 8) & UINT64_C(0x00000000ff000000)) | + ((v >> 24) & UINT64_C(0x0000000000ff0000)) | + ((v >> 40) & UINT64_C(0x000000000000ff00)); +} +#endif +#endif /* bswap64 */ + +#ifndef bswap32 +#if defined(bswap_32) +#define bswap32 bswap_32 +#elif defined(__bswap_32) +#define bswap32 __bswap_32 +#else +static __always_inline uint32_t bswap32(uint32_t v) { + return v << 24 | v >> 24 | ((v << 8) & UINT32_C(0x00ff0000)) | + ((v >> 8) & UINT32_C(0x0000ff00)); +} +#endif +#endif /* bswap32 */ + +#ifndef bswap16 +#if defined(bswap_16) +#define bswap16 bswap_16 +#elif defined(__bswap_16) +#define bswap16 __bswap_16 +#else +static __always_inline uint16_t bswap16(uint16_t v) { return v << 8 | v >> 8; } +#endif +#endif /* bswap16 */ + +#if defined(__ia32__) || \ + T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT +/* The __builtin_assume_aligned() leads gcc/clang to load values into the + * registers, even when it is possible to directly use an operand from memory. + * This can lead to a shortage of registers and a significant slowdown. + * Therefore avoid unnecessary use of __builtin_assume_aligned() for x86. */ +#define read_unaligned(ptr, bits) (*(const uint##bits##_t *__restrict)(ptr)) +#define read_aligned(ptr, bits) (*(const uint##bits##_t *__restrict)(ptr)) +#endif /* __ia32__ */ + +#ifndef read_unaligned +#if defined(__GNUC__) || __has_attribute(__packed__) +typedef struct { + uint8_t unaligned_8; + uint16_t unaligned_16; + uint32_t unaligned_32; + uint64_t unaligned_64; +} __attribute__((__packed__)) t1ha_unaligned_proxy; +#define read_unaligned(ptr, bits) \ + (((const t1ha_unaligned_proxy *)((const uint8_t *)(ptr)-offsetof( \ + t1ha_unaligned_proxy, unaligned_##bits))) \ + ->unaligned_##bits) +#elif defined(_MSC_VER) +#pragma warning( \ + disable : 4235) /* nonstandard extension used: '__unaligned' \ + * keyword not supported on this architecture */ +#define read_unaligned(ptr, bits) (*(const __unaligned uint##bits##_t *)(ptr)) +#else +#pragma pack(push, 1) +typedef struct { + uint8_t unaligned_8; + uint16_t unaligned_16; + uint32_t unaligned_32; + uint64_t unaligned_64; +} t1ha_unaligned_proxy; +#pragma pack(pop) +#define read_unaligned(ptr, bits) \ + (((const t1ha_unaligned_proxy *)((const uint8_t *)(ptr)-offsetof( \ + t1ha_unaligned_proxy, unaligned_##bits))) \ + ->unaligned_##bits) +#endif +#endif /* read_unaligned */ + +#ifndef read_aligned +#if __GNUC_PREREQ(4, 8) || __has_builtin(__builtin_assume_aligned) +#define read_aligned(ptr, bits) \ + (*(const uint##bits##_t *)__builtin_assume_aligned(ptr, ALIGNMENT_##bits)) +#elif (__GNUC_PREREQ(3, 3) || __has_attribute(__aligned__)) && \ + !defined(__clang__) +#define read_aligned(ptr, bits) \ + (*(const uint##bits##_t \ + __attribute__((__aligned__(ALIGNMENT_##bits))) *)(ptr)) +#elif __has_attribute(__assume_aligned__) + +static __always_inline const + uint16_t *__attribute__((__assume_aligned__(ALIGNMENT_16))) + cast_aligned_16(const void *ptr) { + return (const uint16_t *)ptr; +} +static __always_inline const + uint32_t *__attribute__((__assume_aligned__(ALIGNMENT_32))) + cast_aligned_32(const void *ptr) { + return (const uint32_t *)ptr; +} +static __always_inline const + uint64_t *__attribute__((__assume_aligned__(ALIGNMENT_64))) + cast_aligned_64(const void *ptr) { + return (const uint64_t *)ptr; +} + +#define read_aligned(ptr, bits) (*cast_aligned_##bits(ptr)) + +#elif defined(_MSC_VER) +#define read_aligned(ptr, bits) \ + (*(const __declspec(align(ALIGNMENT_##bits)) uint##bits##_t *)(ptr)) +#else +#define read_aligned(ptr, bits) (*(const uint##bits##_t *)(ptr)) +#endif +#endif /* read_aligned */ + +#ifndef prefetch +#if (__GNUC_PREREQ(4, 0) || __has_builtin(__builtin_prefetch)) && \ + !defined(__ia32__) +#define prefetch(ptr) __builtin_prefetch(ptr) +#elif defined(_M_ARM64) || defined(_M_ARM) +#define prefetch(ptr) __prefetch(ptr) +#else +#define prefetch(ptr) \ + do { \ + (void)(ptr); \ + } while (0) +#endif +#endif /* prefetch */ + +#if __has_warning("-Wconstant-logical-operand") +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wconstant-logical-operand" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wconstant-logical-operand" +#else +#pragma warning disable "constant-logical-operand" +#endif +#endif /* -Wconstant-logical-operand */ + +#if __has_warning("-Wtautological-pointer-compare") +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wtautological-pointer-compare" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wtautological-pointer-compare" +#else +#pragma warning disable "tautological-pointer-compare" +#endif +#endif /* -Wtautological-pointer-compare */ + +/***************************************************************************/ + +#if __GNUC_PREREQ(4, 0) +#pragma GCC visibility push(hidden) +#endif /* __GNUC_PREREQ(4,0) */ + +/*---------------------------------------------------------- Little Endian */ + +#ifndef fetch16_le_aligned +static __maybe_unused __always_inline uint16_t +fetch16_le_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_16 == 0); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_aligned(v, 16); +#else + return bswap16(read_aligned(v, 16)); +#endif +} +#endif /* fetch16_le_aligned */ + +#ifndef fetch16_le_unaligned +static __maybe_unused __always_inline uint16_t +fetch16_le_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE && \ + !defined(__ARM_FEATURE_UNALIGNED) + const uint8_t *p = (const uint8_t *)v; + return p[0] | (uint16_t)p[1] << 8; +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_unaligned(v, 16); +#else + return bswap16(read_unaligned(v, 16)); +#endif +} +#endif /* fetch16_le_unaligned */ + +#ifndef fetch32_le_aligned +static __maybe_unused __always_inline uint32_t +fetch32_le_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_32 == 0); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_aligned(v, 32); +#else + return bswap32(read_aligned(v, 32)); +#endif +} +#endif /* fetch32_le_aligned */ + +#ifndef fetch32_le_unaligned +static __maybe_unused __always_inline uint32_t +fetch32_le_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE && \ + !defined(__ARM_FEATURE_UNALIGNED) + return fetch16_le_unaligned(v) | + (uint32_t)fetch16_le_unaligned((const uint8_t *)v + 2) << 16; +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_unaligned(v, 32); +#else + return bswap32(read_unaligned(v, 32)); +#endif +} +#endif /* fetch32_le_unaligned */ + +#ifndef fetch64_le_aligned +static __maybe_unused __always_inline uint64_t +fetch64_le_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_64 == 0); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_aligned(v, 64); +#else + return bswap64(read_aligned(v, 64)); +#endif +} +#endif /* fetch64_le_aligned */ + +#ifndef fetch64_le_unaligned +static __maybe_unused __always_inline uint64_t +fetch64_le_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE + return fetch32_le_unaligned(v) | + (uint64_t)fetch32_le_unaligned((const uint8_t *)v + 4) << 32; +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return read_unaligned(v, 64); +#else + return bswap64(read_unaligned(v, 64)); +#endif +} +#endif /* fetch64_le_unaligned */ + +static __maybe_unused __always_inline uint64_t tail64_le_aligned(const void *v, + size_t tail) { + const uint8_t *const p = (const uint8_t *)v; +#if T1HA_USE_FAST_ONESHOT_READ && !defined(__SANITIZE_ADDRESS__) + /* We can perform a 'oneshot' read, which is little bit faster. */ + const unsigned shift = ((8 - tail) & 7) << 3; + return fetch64_le_aligned(p) & ((~UINT64_C(0)) >> shift); +#else + uint64_t r = 0; + switch (tail & 7) { + default: + unreachable(); +/* fall through */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* For most CPUs this code is better when not needed byte reordering. */ + case 0: + return fetch64_le_aligned(p); + case 7: + r = (uint64_t)p[6] << 8; + /* fall through */ + case 6: + r += p[5]; + r <<= 8; + /* fall through */ + case 5: + r += p[4]; + r <<= 32; + /* fall through */ + case 4: + return r + fetch32_le_aligned(p); + case 3: + r = (uint64_t)p[2] << 16; + /* fall through */ + case 2: + return r + fetch16_le_aligned(p); + case 1: + return p[0]; +#else + case 0: + r = p[7] << 8; + /* fall through */ + case 7: + r += p[6]; + r <<= 8; + /* fall through */ + case 6: + r += p[5]; + r <<= 8; + /* fall through */ + case 5: + r += p[4]; + r <<= 8; + /* fall through */ + case 4: + r += p[3]; + r <<= 8; + /* fall through */ + case 3: + r += p[2]; + r <<= 8; + /* fall through */ + case 2: + r += p[1]; + r <<= 8; + /* fall through */ + case 1: + return r + p[0]; +#endif + } +#endif /* T1HA_USE_FAST_ONESHOT_READ */ +} + +#if T1HA_USE_FAST_ONESHOT_READ && \ + T1HA_SYS_UNALIGNED_ACCESS != T1HA_UNALIGNED_ACCESS__UNABLE && \ + defined(PAGESIZE) && PAGESIZE > 42 && !defined(__SANITIZE_ADDRESS__) +#define can_read_underside(ptr, size) \ + (((PAGESIZE - (size)) & (uintptr_t)(ptr)) != 0) +#endif /* T1HA_USE_FAST_ONESHOT_READ */ + +static __maybe_unused __always_inline uint64_t +tail64_le_unaligned(const void *v, size_t tail) { + const uint8_t *p = (const uint8_t *)v; +#if defined(can_read_underside) && \ + (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) + /* On some systems (e.g. x86_64) we can perform a 'oneshot' read, which + * is little bit faster. Thanks Marcin Żukowski + * for the reminder. */ + const unsigned offset = (8 - tail) & 7; + const unsigned shift = offset << 3; + if (likely(can_read_underside(p, 8))) { + p -= offset; + return fetch64_le_unaligned(p) >> shift; + } + return fetch64_le_unaligned(p) & ((~UINT64_C(0)) >> shift); +#else + uint64_t r = 0; + switch (tail & 7) { + default: + unreachable(); +/* fall through */ +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* For most CPUs this code is better when not needed + * copying for alignment or byte reordering. */ + case 0: + return fetch64_le_unaligned(p); + case 7: + r = (uint64_t)p[6] << 8; + /* fall through */ + case 6: + r += p[5]; + r <<= 8; + /* fall through */ + case 5: + r += p[4]; + r <<= 32; + /* fall through */ + case 4: + return r + fetch32_le_unaligned(p); + case 3: + r = (uint64_t)p[2] << 16; + /* fall through */ + case 2: + return r + fetch16_le_unaligned(p); + case 1: + return p[0]; +#else + /* For most CPUs this code is better than a + * copying for alignment and/or byte reordering. */ + case 0: + r = p[7] << 8; + /* fall through */ + case 7: + r += p[6]; + r <<= 8; + /* fall through */ + case 6: + r += p[5]; + r <<= 8; + /* fall through */ + case 5: + r += p[4]; + r <<= 8; + /* fall through */ + case 4: + r += p[3]; + r <<= 8; + /* fall through */ + case 3: + r += p[2]; + r <<= 8; + /* fall through */ + case 2: + r += p[1]; + r <<= 8; + /* fall through */ + case 1: + return r + p[0]; +#endif + } +#endif /* can_read_underside */ +} + +/*------------------------------------------------------------- Big Endian */ + +#ifndef fetch16_be_aligned +static __maybe_unused __always_inline uint16_t +fetch16_be_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_16 == 0); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_aligned(v, 16); +#else + return bswap16(read_aligned(v, 16)); +#endif +} +#endif /* fetch16_be_aligned */ + +#ifndef fetch16_be_unaligned +static __maybe_unused __always_inline uint16_t +fetch16_be_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE + const uint8_t *p = (const uint8_t *)v; + return (uint16_t)p[0] << 8 | p[1]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_unaligned(v, 16); +#else + return bswap16(read_unaligned(v, 16)); +#endif +} +#endif /* fetch16_be_unaligned */ + +#ifndef fetch32_be_aligned +static __maybe_unused __always_inline uint32_t +fetch32_be_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_32 == 0); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_aligned(v, 32); +#else + return bswap32(read_aligned(v, 32)); +#endif +} +#endif /* fetch32_be_aligned */ + +#ifndef fetch32_be_unaligned +static __maybe_unused __always_inline uint32_t +fetch32_be_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE + return (uint32_t)fetch16_be_unaligned(v) << 16 | + fetch16_be_unaligned((const uint8_t *)v + 2); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_unaligned(v, 32); +#else + return bswap32(read_unaligned(v, 32)); +#endif +} +#endif /* fetch32_be_unaligned */ + +#ifndef fetch64_be_aligned +static __maybe_unused __always_inline uint64_t +fetch64_be_aligned(const void *v) { + assert(((uintptr_t)v) % ALIGNMENT_64 == 0); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_aligned(v, 64); +#else + return bswap64(read_aligned(v, 64)); +#endif +} +#endif /* fetch64_be_aligned */ + +#ifndef fetch64_be_unaligned +static __maybe_unused __always_inline uint64_t +fetch64_be_unaligned(const void *v) { +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__UNABLE + return (uint64_t)fetch32_be_unaligned(v) << 32 | + fetch32_be_unaligned((const uint8_t *)v + 4); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return read_unaligned(v, 64); +#else + return bswap64(read_unaligned(v, 64)); +#endif +} +#endif /* fetch64_be_unaligned */ + +static __maybe_unused __always_inline uint64_t tail64_be_aligned(const void *v, + size_t tail) { + const uint8_t *const p = (const uint8_t *)v; +#if T1HA_USE_FAST_ONESHOT_READ && !defined(__SANITIZE_ADDRESS__) + /* We can perform a 'oneshot' read, which is little bit faster. */ + const unsigned shift = ((8 - tail) & 7) << 3; + return fetch64_be_aligned(p) >> shift; +#else + switch (tail & 7) { + default: + unreachable(); +/* fall through */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + /* For most CPUs this code is better when not byte reordering. */ + case 1: + return p[0]; + case 2: + return fetch16_be_aligned(p); + case 3: + return (uint32_t)fetch16_be_aligned(p) << 8 | p[2]; + case 4: + return fetch32_be_aligned(p); + case 5: + return (uint64_t)fetch32_be_aligned(p) << 8 | p[4]; + case 6: + return (uint64_t)fetch32_be_aligned(p) << 16 | fetch16_be_aligned(p + 4); + case 7: + return (uint64_t)fetch32_be_aligned(p) << 24 | + (uint32_t)fetch16_be_aligned(p + 4) << 8 | p[6]; + case 0: + return fetch64_be_aligned(p); +#else + case 1: + return p[0]; + case 2: + return p[1] | (uint32_t)p[0] << 8; + case 3: + return p[2] | (uint32_t)p[1] << 8 | (uint32_t)p[0] << 16; + case 4: + return p[3] | (uint32_t)p[2] << 8 | (uint32_t)p[1] << 16 | + (uint32_t)p[0] << 24; + case 5: + return p[4] | (uint32_t)p[3] << 8 | (uint32_t)p[2] << 16 | + (uint32_t)p[1] << 24 | (uint64_t)p[0] << 32; + case 6: + return p[5] | (uint32_t)p[4] << 8 | (uint32_t)p[3] << 16 | + (uint32_t)p[2] << 24 | (uint64_t)p[1] << 32 | (uint64_t)p[0] << 40; + case 7: + return p[6] | (uint32_t)p[5] << 8 | (uint32_t)p[4] << 16 | + (uint32_t)p[3] << 24 | (uint64_t)p[2] << 32 | (uint64_t)p[1] << 40 | + (uint64_t)p[0] << 48; + case 0: + return p[7] | (uint32_t)p[6] << 8 | (uint32_t)p[5] << 16 | + (uint32_t)p[4] << 24 | (uint64_t)p[3] << 32 | (uint64_t)p[2] << 40 | + (uint64_t)p[1] << 48 | (uint64_t)p[0] << 56; +#endif + } +#endif /* T1HA_USE_FAST_ONESHOT_READ */ +} + +static __maybe_unused __always_inline uint64_t +tail64_be_unaligned(const void *v, size_t tail) { + const uint8_t *p = (const uint8_t *)v; +#if defined(can_read_underside) && \ + (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) + /* On some systems (e.g. x86_64) we can perform a 'oneshot' read, which + * is little bit faster. Thanks Marcin Żukowski + * for the reminder. */ + const unsigned offset = (8 - tail) & 7; + const unsigned shift = offset << 3; + if (likely(can_read_underside(p, 8))) { + p -= offset; + return fetch64_be_unaligned(p) & ((~UINT64_C(0)) >> shift); + } + return fetch64_be_unaligned(p) >> shift; +#else + switch (tail & 7) { + default: + unreachable(); +/* fall through */ +#if T1HA_SYS_UNALIGNED_ACCESS == T1HA_UNALIGNED_ACCESS__EFFICIENT && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + /* For most CPUs this code is better when not needed + * copying for alignment or byte reordering. */ + case 1: + return p[0]; + case 2: + return fetch16_be_unaligned(p); + case 3: + return (uint32_t)fetch16_be_unaligned(p) << 8 | p[2]; + case 4: + return fetch32_be(p); + case 5: + return (uint64_t)fetch32_be_unaligned(p) << 8 | p[4]; + case 6: + return (uint64_t)fetch32_be_unaligned(p) << 16 | + fetch16_be_unaligned(p + 4); + case 7: + return (uint64_t)fetch32_be_unaligned(p) << 24 | + (uint32_t)fetch16_be_unaligned(p + 4) << 8 | p[6]; + case 0: + return fetch64_be_unaligned(p); +#else + /* For most CPUs this code is better than a + * copying for alignment and/or byte reordering. */ + case 1: + return p[0]; + case 2: + return p[1] | (uint32_t)p[0] << 8; + case 3: + return p[2] | (uint32_t)p[1] << 8 | (uint32_t)p[0] << 16; + case 4: + return p[3] | (uint32_t)p[2] << 8 | (uint32_t)p[1] << 16 | + (uint32_t)p[0] << 24; + case 5: + return p[4] | (uint32_t)p[3] << 8 | (uint32_t)p[2] << 16 | + (uint32_t)p[1] << 24 | (uint64_t)p[0] << 32; + case 6: + return p[5] | (uint32_t)p[4] << 8 | (uint32_t)p[3] << 16 | + (uint32_t)p[2] << 24 | (uint64_t)p[1] << 32 | (uint64_t)p[0] << 40; + case 7: + return p[6] | (uint32_t)p[5] << 8 | (uint32_t)p[4] << 16 | + (uint32_t)p[3] << 24 | (uint64_t)p[2] << 32 | (uint64_t)p[1] << 40 | + (uint64_t)p[0] << 48; + case 0: + return p[7] | (uint32_t)p[6] << 8 | (uint32_t)p[5] << 16 | + (uint32_t)p[4] << 24 | (uint64_t)p[3] << 32 | (uint64_t)p[2] << 40 | + (uint64_t)p[1] << 48 | (uint64_t)p[0] << 56; +#endif + } +#endif /* can_read_underside */ +} + +/***************************************************************************/ + +#ifndef rot64 +static __maybe_unused __always_inline uint64_t rot64(uint64_t v, unsigned s) { + return (v >> s) | (v << (64 - s)); +} +#endif /* rot64 */ + +#ifndef mul_32x32_64 +static __maybe_unused __always_inline uint64_t mul_32x32_64(uint32_t a, + uint32_t b) { + return a * (uint64_t)b; +} +#endif /* mul_32x32_64 */ + +#ifndef add64carry_first +static __maybe_unused __always_inline unsigned +add64carry_first(uint64_t base, uint64_t addend, uint64_t *sum) { +#if __has_builtin(__builtin_addcll) + unsigned long long carryout; + *sum = __builtin_addcll(base, addend, 0, &carryout); + return (unsigned)carryout; +#else + *sum = base + addend; + return *sum < addend; +#endif /* __has_builtin(__builtin_addcll) */ +} +#endif /* add64carry_fist */ + +#ifndef add64carry_next +static __maybe_unused __always_inline unsigned +add64carry_next(unsigned carry, uint64_t base, uint64_t addend, uint64_t *sum) { +#if __has_builtin(__builtin_addcll) + unsigned long long carryout; + *sum = __builtin_addcll(base, addend, carry, &carryout); + return (unsigned)carryout; +#else + *sum = base + addend + carry; + return *sum < addend || (carry && *sum == addend); +#endif /* __has_builtin(__builtin_addcll) */ +} +#endif /* add64carry_next */ + +#ifndef add64carry_last +static __maybe_unused __always_inline void +add64carry_last(unsigned carry, uint64_t base, uint64_t addend, uint64_t *sum) { +#if __has_builtin(__builtin_addcll) + unsigned long long carryout; + *sum = __builtin_addcll(base, addend, carry, &carryout); + (void)carryout; +#else + *sum = base + addend + carry; +#endif /* __has_builtin(__builtin_addcll) */ +} +#endif /* add64carry_last */ + +#ifndef mul_64x64_128 +static __maybe_unused __always_inline uint64_t mul_64x64_128(uint64_t a, + uint64_t b, + uint64_t *h) { +#if (defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)) && \ + (!defined(__LCC__) || __LCC__ != 124) + __uint128_t r = (__uint128_t)a * (__uint128_t)b; + /* modern GCC could nicely optimize this */ + *h = (uint64_t)(r >> 64); + return (uint64_t)r; +#elif defined(mul_64x64_high) + *h = mul_64x64_high(a, b); + return a * b; +#else + /* performs 64x64 to 128 bit multiplication */ + const uint64_t ll = mul_32x32_64((uint32_t)a, (uint32_t)b); + const uint64_t lh = mul_32x32_64(a >> 32, (uint32_t)b); + const uint64_t hl = mul_32x32_64((uint32_t)a, b >> 32); + const uint64_t hh = mul_32x32_64(a >> 32, b >> 32); + + /* Few simplification are possible here for 32-bit architectures, + * but thus we would lost compatibility with the original 64-bit + * version. Think is very bad idea, because then 32-bit t1ha will + * still (relatively) very slowly and well yet not compatible. */ + uint64_t l; + add64carry_last(add64carry_first(ll, lh << 32, &l), hh, lh >> 32, h); + add64carry_last(add64carry_first(l, hl << 32, &l), *h, hl >> 32, h); + return l; +#endif +} +#endif /* mul_64x64_128() */ + +#ifndef mul_64x64_high +static __maybe_unused __always_inline uint64_t mul_64x64_high(uint64_t a, + uint64_t b) { + uint64_t h; + mul_64x64_128(a, b, &h); + return h; +} +#endif /* mul_64x64_high */ + +/***************************************************************************/ + +/* 'magic' primes */ +static const uint64_t prime_0 = UINT64_C(0xEC99BF0D8372CAAB); +static const uint64_t prime_1 = UINT64_C(0x82434FE90EDCEF39); +static const uint64_t prime_2 = UINT64_C(0xD4F06DB99D67BE4B); +static const uint64_t prime_3 = UINT64_C(0xBD9CACC22C6E9571); +static const uint64_t prime_4 = UINT64_C(0x9C06FAF4D023E3AB); +static const uint64_t prime_5 = UINT64_C(0xC060724A8424F345); +static const uint64_t prime_6 = UINT64_C(0xCB5AF53AE3AAAC31); + +/* xor high and low parts of full 128-bit product */ +static __maybe_unused __always_inline uint64_t mux64(uint64_t v, + uint64_t prime) { + uint64_t l, h; + l = mul_64x64_128(v, prime, &h); + return l ^ h; +} + +static __maybe_unused __always_inline uint64_t final64(uint64_t a, uint64_t b) { + uint64_t x = (a + rot64(b, 41)) * prime_0; + uint64_t y = (rot64(a, 23) + b) * prime_6; + return mux64(x ^ y, prime_5); +} + +static __maybe_unused __always_inline void mixup64(uint64_t *__restrict a, + uint64_t *__restrict b, + uint64_t v, uint64_t prime) { + uint64_t h; + *a ^= mul_64x64_128(*b + v, prime, &h); + *b += h; +} + +/***************************************************************************/ + +typedef union t1ha_uint128 { +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + __uint128_t v; +#endif + struct { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint64_t l, h; +#else + uint64_t h, l; +#endif + }; +} t1ha_uint128_t; + +static __maybe_unused __always_inline t1ha_uint128_t +not128(const t1ha_uint128_t v) { + t1ha_uint128_t r; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = ~v.v; +#else + r.l = ~v.l; + r.h = ~v.h; +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t +left128(const t1ha_uint128_t v, unsigned s) { + t1ha_uint128_t r; + assert(s < 128); +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = v.v << s; +#else + r.l = (s < 64) ? v.l << s : 0; + r.h = (s < 64) ? (v.h << s) | (s ? v.l >> (64 - s) : 0) : v.l << (s - 64); +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t +right128(const t1ha_uint128_t v, unsigned s) { + t1ha_uint128_t r; + assert(s < 128); +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = v.v >> s; +#else + r.l = (s < 64) ? (s ? v.h << (64 - s) : 0) | (v.l >> s) : v.h >> (s - 64); + r.h = (s < 64) ? v.h >> s : 0; +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t or128(t1ha_uint128_t x, + t1ha_uint128_t y) { + t1ha_uint128_t r; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = x.v | y.v; +#else + r.l = x.l | y.l; + r.h = x.h | y.h; +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t xor128(t1ha_uint128_t x, + t1ha_uint128_t y) { + t1ha_uint128_t r; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = x.v ^ y.v; +#else + r.l = x.l ^ y.l; + r.h = x.h ^ y.h; +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t rot128(t1ha_uint128_t v, + unsigned s) { + s &= 127; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + v.v = (v.v << (128 - s)) | (v.v >> s); + return v; +#else + return s ? or128(left128(v, 128 - s), right128(v, s)) : v; +#endif +} + +static __maybe_unused __always_inline t1ha_uint128_t add128(t1ha_uint128_t x, + t1ha_uint128_t y) { + t1ha_uint128_t r; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = x.v + y.v; +#else + add64carry_last(add64carry_first(x.l, y.l, &r.l), x.h, y.h, &r.h); +#endif + return r; +} + +static __maybe_unused __always_inline t1ha_uint128_t mul128(t1ha_uint128_t x, + t1ha_uint128_t y) { + t1ha_uint128_t r; +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + r.v = x.v * y.v; +#else + r.l = mul_64x64_128(x.l, y.l, &r.h); + r.h += x.l * y.h + y.l * x.h; +#endif + return r; +} + +/***************************************************************************/ + +#if T1HA0_AESNI_AVAILABLE && defined(__ia32__) +uint64_t t1ha_ia32cpu_features(void); + +static __maybe_unused __always_inline bool +t1ha_ia32_AESNI_avail(uint64_t ia32cpu_features) { + /* check for AES-NI */ + return (ia32cpu_features & UINT32_C(0x02000000)) != 0; +} + +static __maybe_unused __always_inline bool +t1ha_ia32_AVX_avail(uint64_t ia32cpu_features) { + /* check for any AVX */ + return (ia32cpu_features & UINT32_C(0x1A000000)) == UINT32_C(0x1A000000); +} + +static __maybe_unused __always_inline bool +t1ha_ia32_AVX2_avail(uint64_t ia32cpu_features) { + /* check for 'Advanced Vector Extensions 2' */ + return ((ia32cpu_features >> 32) & 32) != 0; +} + +#endif /* T1HA0_AESNI_AVAILABLE && __ia32__ */ diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_selfcheck.h b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_selfcheck.h new file mode 100644 index 0000000..e83cd24 --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/src/t1ha_selfcheck.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com, + * Fast Positive Hash. + * + * Portions Copyright (c) 2010-2020 Leonid Yuriev , + * The 1Hippeus project (t1h). + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * t1ha = { Fast Positive Hash, aka "Позитивный Хэш" } + * by [Positive Technologies](https://www.ptsecurity.ru) + * + * Briefly, it is a 64-bit Hash Function: + * 1. Created for 64-bit little-endian platforms, in predominantly for x86_64, + * but portable and without penalties it can run on any 64-bit CPU. + * 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash + * and all others portable hash-functions (which do not use specific + * hardware tricks). + * 3. Not suitable for cryptography. + * + * The Future will (be) Positive. Всё будет хорошо. + * + * ACKNOWLEDGEMENT: + * The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев) + * for The 1Hippeus project - zerocopy messaging in the spirit of Sparta! + */ + +#pragma once +#if defined(_MSC_VER) && _MSC_VER > 1800 +#pragma warning(disable : 4464) /* relative include path contains '..' */ +#endif /* MSVC */ +#include "../t1ha.h" + +/***************************************************************************/ +/* Self-checking */ + +extern const uint8_t t1ha_test_pattern[64]; +int t1ha_selfcheck(uint64_t (*hash)(const void *, size_t, uint64_t), + const uint64_t *reference_values); + +#ifndef T1HA2_DISABLED +extern const uint64_t t1ha_refval_2atonce[81]; +extern const uint64_t t1ha_refval_2atonce128[81]; +extern const uint64_t t1ha_refval_2stream[81]; +extern const uint64_t t1ha_refval_2stream128[81]; +#endif /* T1HA2_DISABLED */ + +#ifndef T1HA1_DISABLED +extern const uint64_t t1ha_refval_64le[81]; +extern const uint64_t t1ha_refval_64be[81]; +#endif /* T1HA1_DISABLED */ + +#ifndef T1HA0_DISABLED +extern const uint64_t t1ha_refval_32le[81]; +extern const uint64_t t1ha_refval_32be[81]; +#if T1HA0_AESNI_AVAILABLE +extern const uint64_t t1ha_refval_ia32aes_a[81]; +extern const uint64_t t1ha_refval_ia32aes_b[81]; +#endif /* T1HA0_AESNI_AVAILABLE */ +#endif /* T1HA0_DISABLED */ diff --git a/hash_testing/new_testing/hash_funcs/t1ha2/upstream/t1ha.h b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/t1ha.h new file mode 100644 index 0000000..498f0dd --- /dev/null +++ b/hash_testing/new_testing/hash_funcs/t1ha2/upstream/t1ha.h @@ -0,0 +1,719 @@ +/* + * Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com, + * Fast Positive Hash. + * + * Portions Copyright (c) 2010-2020 Leonid Yuriev , + * The 1Hippeus project (t1h). + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * t1ha = { Fast Positive Hash, aka "Позитивный Хэш" } + * by [Positive Technologies](https://www.ptsecurity.ru) + * + * Briefly, it is a 64-bit Hash Function: + * 1. Created for 64-bit little-endian platforms, in predominantly for x86_64, + * but portable and without penalties it can run on any 64-bit CPU. + * 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash + * and all others portable hash-functions (which do not use specific + * hardware tricks). + * 3. Not suitable for cryptography. + * + * The Future will (be) Positive. Всё будет хорошо. + * + * ACKNOWLEDGEMENT: + * The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев) + * for The 1Hippeus project - zerocopy messaging in the spirit of Sparta! + */ + +#pragma once + +/***************************************************************************** + * + * PLEASE PAY ATTENTION TO THE FOLLOWING NOTES + * about macros definitions which controls t1ha behaviour and/or performance. + * + * + * 1) T1HA_SYS_UNALIGNED_ACCESS = Defines the system/platform/CPU/architecture + * abilities for unaligned data access. + * + * By default, when the T1HA_SYS_UNALIGNED_ACCESS not defined, + * it will defined on the basis hardcoded knowledge about of capabilities + * of most common CPU architectures. But you could override this + * default behavior when build t1ha library itself: + * + * // To disable unaligned access at all. + * #define T1HA_SYS_UNALIGNED_ACCESS 0 + * + * // To enable unaligned access, but indicate that it significantly slow. + * #define T1HA_SYS_UNALIGNED_ACCESS 1 + * + * // To enable unaligned access, and indicate that it effecient. + * #define T1HA_SYS_UNALIGNED_ACCESS 2 + * + * + * 2) T1HA_USE_FAST_ONESHOT_READ = Controls the data reads at the end of buffer. + * + * When defined to non-zero, t1ha will use 'one shot' method for reading + * up to 8 bytes at the end of data. In this case just the one 64-bit read + * will be performed even when the available less than 8 bytes. + * + * This is little bit faster that switching by length of data tail. + * Unfortunately this will triggering a false-positive alarms from Valgrind, + * AddressSanitizer and other similar tool. + * + * By default, t1ha defines it to 1, but you could override this + * default behavior when build t1ha library itself: + * + * // For little bit faster and small code. + * #define T1HA_USE_FAST_ONESHOT_READ 1 + * + * // For calmness if doubt. + * #define T1HA_USE_FAST_ONESHOT_READ 0 + * + * + * 3) T1HA0_RUNTIME_SELECT = Controls choice fastest function in runtime. + * + * t1ha library offers the t1ha0() function as the fastest for current CPU. + * But actual CPU's features/capabilities and may be significantly different, + * especially on x86 platform. Therefore, internally, t1ha0() may require + * dynamic dispatching for choice best implementation. + * + * By default, t1ha enables such runtime choice and (may be) corresponding + * indirect calls if it reasonable, but you could override this default + * behavior when build t1ha library itself: + * + * // To enable runtime choice of fastest implementation. + * #define T1HA0_RUNTIME_SELECT 1 + * + * // To disable runtime choice of fastest implementation. + * #define T1HA0_RUNTIME_SELECT 0 + * + * When T1HA0_RUNTIME_SELECT is nonzero the t1ha0_resolve() function could + * be used to get actual t1ha0() implementation address at runtime. This is + * useful for two cases: + * - calling by local pointer-to-function usually is little + * bit faster (less overhead) than via a PLT thru the DSO boundary. + * - GNU Indirect functions (see below) don't supported by environment + * and calling by t1ha0_funcptr is not available and/or expensive. + * + * 4) T1HA_USE_INDIRECT_FUNCTIONS = Controls usage of GNU Indirect functions. + * + * In continue of T1HA0_RUNTIME_SELECT the T1HA_USE_INDIRECT_FUNCTIONS + * controls usage of ELF indirect functions feature. In general, when + * available, this reduces overhead of indirect function's calls though + * a DSO-bundary (https://sourceware.org/glibc/wiki/GNU_IFUNC). + * + * By default, t1ha engage GNU Indirect functions when it available + * and useful, but you could override this default behavior when build + * t1ha library itself: + * + * // To enable use of GNU ELF Indirect functions. + * #define T1HA_USE_INDIRECT_FUNCTIONS 1 + * + * // To disable use of GNU ELF Indirect functions. This may be useful + * // if the actual toolchain or the system's loader don't support ones. + * #define T1HA_USE_INDIRECT_FUNCTIONS 0 + * + * 5) T1HA0_AESNI_AVAILABLE = Controls AES-NI detection and dispatching on x86. + * + * In continue of T1HA0_RUNTIME_SELECT the T1HA0_AESNI_AVAILABLE controls + * detection and usage of AES-NI CPU's feature. On the other hand, this + * requires compiling parts of t1ha library with certain properly options, + * and could be difficult or inconvenient in some cases. + * + * By default, t1ha engade AES-NI for t1ha0() on the x86 platform, but + * you could override this default behavior when build t1ha library itself: + * + * // To disable detection and usage of AES-NI instructions for t1ha0(). + * // This may be useful when you unable to build t1ha library properly + * // or known that AES-NI will be unavailable at the deploy. + * #define T1HA0_AESNI_AVAILABLE 0 + * + * // To force detection and usage of AES-NI instructions for t1ha0(), + * // but I don't known reasons to anybody would need this. + * #define T1HA0_AESNI_AVAILABLE 1 + * + * 6) T1HA0_DISABLED, T1HA1_DISABLED, T1HA2_DISABLED = Controls availability of + * t1ha functions. + * + * In some cases could be useful to import/use only few of t1ha functions + * or just the one. So, this definitions allows disable corresponding parts + * of t1ha library. + * + * // To disable t1ha0(), t1ha0_32le(), t1ha0_32be() and all AES-NI. + * #define T1HA0_DISABLED + * + * // To disable t1ha1_le() and t1ha1_be(). + * #define T1HA1_DISABLED + * + * // To disable t1ha2_atonce(), t1ha2_atonce128() and so on. + * #define T1HA2_DISABLED + * + *****************************************************************************/ + +#define T1HA_VERSION_MAJOR 2 +#define T1HA_VERSION_MINOR 1 +#define T1HA_VERSION_RELEASE 1 + +#ifndef __has_attribute +#define __has_attribute(x) (0) +#endif + +#ifndef __has_include +#define __has_include(x) (0) +#endif + +#ifndef __GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GNUC_PREREQ(maj, min) 0 +#endif +#endif /* __GNUC_PREREQ */ + +#ifndef __CLANG_PREREQ +#ifdef __clang__ +#define __CLANG_PREREQ(maj, min) \ + ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min)) +#else +#define __CLANG_PREREQ(maj, min) (0) +#endif +#endif /* __CLANG_PREREQ */ + +#ifndef __LCC_PREREQ +#ifdef __LCC__ +#define __LCC_PREREQ(maj, min) \ + ((__LCC__ << 16) + __LCC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __LCC_PREREQ(maj, min) (0) +#endif +#endif /* __LCC_PREREQ */ + +/*****************************************************************************/ + +#ifdef _MSC_VER +/* Avoid '16' bytes padding added after data member 't1ha_context::total' + * and other warnings from std-headers if warning-level > 3. */ +#pragma warning(push, 3) +#endif + +#if defined(__cplusplus) && __cplusplus >= 201103L +#include +#include +#include +#else +#include +#include +#include +#endif + +/*****************************************************************************/ + +#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \ + defined(i486) || defined(__i486) || defined(__i486__) || \ + defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) || \ + defined(__i686) || defined(__i686__) || defined(_M_IX86) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \ + defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64__) || defined(__amd64) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__) +#ifndef __ia32__ +/* LY: define neutral __ia32__ for x86 and x86-64 archs */ +#define __ia32__ 1 +#endif /* __ia32__ */ +#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64) || defined(_M_X64)) +/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */ +#define __amd64__ 1 +#endif /* __amd64__ */ +#endif /* all x86 */ + +#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \ + !defined(__ORDER_BIG_ENDIAN__) + +/* *INDENT-OFF* */ +/* clang-format off */ + +#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID__) || \ + defined(HAVE_ENDIAN_H) || __has_include() +#include +#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) || \ + defined(HAVE_MACHINE_ENDIAN_H) || __has_include() +#include +#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include() +#include +#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) || \ + (__has_include() && __has_include()) +#include +#include +#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ + defined(__NETBSD__) || defined(__NetBSD__) || \ + defined(HAVE_SYS_PARAM_H) || __has_include() +#include +#endif /* OS */ + +/* *INDENT-ON* */ +/* clang-format on */ + +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) +#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN +#define __BYTE_ORDER__ __BYTE_ORDER +#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) +#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN +#define __BYTE_ORDER__ _BYTE_ORDER +#else +#define __ORDER_LITTLE_ENDIAN__ 1234 +#define __ORDER_BIG_ENDIAN__ 4321 + +#if defined(__LITTLE_ENDIAN__) || \ + (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \ + defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ + defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) || \ + defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) || \ + defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) || \ + defined(__BFIN__) || defined(__ia64__) || defined(_IA64) || \ + defined(__IA64__) || defined(__ia64) || defined(_M_IA64) || \ + defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) || \ + defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) || \ + defined(__WINDOWS__) +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ + +#elif defined(__BIG_ENDIAN__) || \ + (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || \ + defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ + defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) || \ + defined(__m68k__) || defined(M68000) || defined(__hppa__) || \ + defined(__hppa) || defined(__HPPA__) || defined(__sparc__) || \ + defined(__sparc) || defined(__370__) || defined(__THW_370__) || \ + defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__) +#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__ + +#else +#error __BYTE_ORDER__ should be defined. +#endif /* Arch */ + +#endif +#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */ + +/*****************************************************************************/ + +#ifndef __dll_export +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#if defined(__GNUC__) || __has_attribute(dllexport) +#define __dll_export __attribute__((dllexport)) +#else +#define __dll_export __declspec(dllexport) +#endif +#elif defined(__GNUC__) || __has_attribute(__visibility__) +#define __dll_export __attribute__((__visibility__("default"))) +#else +#define __dll_export +#endif +#endif /* __dll_export */ + +#ifndef __dll_import +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#if defined(__GNUC__) || __has_attribute(dllimport) +#define __dll_import __attribute__((dllimport)) +#else +#define __dll_import __declspec(dllimport) +#endif +#elif defined(__GNUC__) || __has_attribute(__visibility__) +#define __dll_import __attribute__((__visibility__("default"))) +#else +#define __dll_import +#endif +#endif /* __dll_import */ + +#ifndef __force_inline +#ifdef _MSC_VER +#define __force_inline __forceinline +#elif __GNUC_PREREQ(3, 2) || __has_attribute(__always_inline__) +#define __force_inline __inline __attribute__((__always_inline__)) +#else +#define __force_inline __inline +#endif +#endif /* __force_inline */ + +#ifndef T1HA_API +#if defined(t1ha_EXPORTS) +#define T1HA_API __dll_export +#elif defined(t1ha_IMPORTS) +#define T1HA_API __dll_import +#else +#define T1HA_API +#endif +#endif /* T1HA_API */ + +#if defined(_MSC_VER) && defined(__ia32__) +#define T1HA_ALIGN_PREFIX __declspec(align(32)) /* required only for SIMD */ +#else +#define T1HA_ALIGN_PREFIX +#endif /* _MSC_VER */ + +#if defined(__GNUC__) && defined(__ia32__) +#define T1HA_ALIGN_SUFFIX \ + __attribute__((__aligned__(32))) /* required only for SIMD */ +#else +#define T1HA_ALIGN_SUFFIX +#endif /* GCC x86 */ + +#ifndef T1HA_USE_INDIRECT_FUNCTIONS +/* GNU ELF indirect functions usage control. For more info please see + * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format + * and https://sourceware.org/glibc/wiki/GNU_IFUNC */ +#if defined(__ELF__) && defined(__amd64__) && \ + (__has_attribute(__ifunc__) || \ + (!defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && \ + !defined(__SANITIZE_ADDRESS__) && !defined(__SSP_ALL__))) +/* Enable gnu_indirect_function by default if : + * - ELF AND x86_64 + * - attribute(__ifunc__) is available OR + * GCC >= 4 WITHOUT -fsanitize=address NOR -fstack-protector-all */ +#define T1HA_USE_INDIRECT_FUNCTIONS 1 +#else +#define T1HA_USE_INDIRECT_FUNCTIONS 0 +#endif +#endif /* T1HA_USE_INDIRECT_FUNCTIONS */ + +#if __GNUC_PREREQ(4, 0) +#pragma GCC visibility push(hidden) +#endif /* __GNUC_PREREQ(4,0) */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union T1HA_ALIGN_PREFIX t1ha_state256 { + uint8_t bytes[32]; + uint32_t u32[8]; + uint64_t u64[4]; + struct { + uint64_t a, b, c, d; + } n; +} t1ha_state256_t T1HA_ALIGN_SUFFIX; + +typedef struct t1ha_context { + t1ha_state256_t state; + t1ha_state256_t buffer; + size_t partial; + uint64_t total; +} t1ha_context_t; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +/****************************************************************************** + * + * Self-testing API. + * + * Unfortunately, some compilers (exactly only Microsoft Visual C/C++) has + * a bugs which leads t1ha-functions to produce wrong results. This API allows + * check the correctness of the actual code in runtime. + * + * All check-functions returns 0 on success, or -1 in case the corresponding + * hash-function failed verification. PLEASE, always perform such checking at + * initialization of your code, if you using MSVC or other troubleful compilers. + */ + +T1HA_API int t1ha_selfcheck__all_enabled(void); + +#ifndef T1HA2_DISABLED +T1HA_API int t1ha_selfcheck__t1ha2_atonce(void); +T1HA_API int t1ha_selfcheck__t1ha2_atonce128(void); +T1HA_API int t1ha_selfcheck__t1ha2_stream(void); +T1HA_API int t1ha_selfcheck__t1ha2(void); +#endif /* T1HA2_DISABLED */ + +#ifndef T1HA1_DISABLED +T1HA_API int t1ha_selfcheck__t1ha1_le(void); +T1HA_API int t1ha_selfcheck__t1ha1_be(void); +T1HA_API int t1ha_selfcheck__t1ha1(void); +#endif /* T1HA1_DISABLED */ + +#ifndef T1HA0_DISABLED +T1HA_API int t1ha_selfcheck__t1ha0_32le(void); +T1HA_API int t1ha_selfcheck__t1ha0_32be(void); +T1HA_API int t1ha_selfcheck__t1ha0(void); + +/* Define T1HA0_AESNI_AVAILABLE to 0 for disable AES-NI support. */ +#ifndef T1HA0_AESNI_AVAILABLE +#if defined(__e2k__) || \ + (defined(__ia32__) && (!defined(_M_IX86) || _MSC_VER > 1800)) +#define T1HA0_AESNI_AVAILABLE 1 +#else +#define T1HA0_AESNI_AVAILABLE 0 +#endif +#endif /* ifndef T1HA0_AESNI_AVAILABLE */ + +#if T1HA0_AESNI_AVAILABLE +T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_noavx(void); +T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_avx(void); +#ifndef __e2k__ +T1HA_API int t1ha_selfcheck__t1ha0_ia32aes_avx2(void); +#endif +#endif /* if T1HA0_AESNI_AVAILABLE */ +#endif /* T1HA0_DISABLED */ + +/****************************************************************************** + * + * t1ha2 = 64 and 128-bit, SLIGHTLY MORE ATTENTION FOR QUALITY AND STRENGTH. + * + * - The recommended version of "Fast Positive Hash" with good quality + * for checksum, hash tables and fingerprinting. + * - Portable and extremely efficiency on modern 64-bit CPUs. + * Designed for 64-bit little-endian platforms, + * in other cases will runs slowly. + * - Great quality of hashing and still faster than other non-t1ha hashes. + * Provides streaming mode and 128-bit result. + * + * Note: Due performance reason 64- and 128-bit results are completely + * different each other, i.e. 64-bit result is NOT any part of 128-bit. + */ +#ifndef T1HA2_DISABLED + +/* The at-once variant with 64-bit result */ +T1HA_API uint64_t t1ha2_atonce(const void *data, size_t length, uint64_t seed); + +/* The at-once variant with 128-bit result. + * Argument `extra_result` is NOT optional and MUST be valid. + * The high 64-bit part of 128-bit hash will be always unconditionally + * stored to the address given by `extra_result` argument. */ +T1HA_API uint64_t t1ha2_atonce128(uint64_t *__restrict extra_result, + const void *__restrict data, size_t length, + uint64_t seed); + +/* The init/update/final trinity for streaming. + * Return 64 or 128-bit result depentently from `extra_result` argument. */ +T1HA_API void t1ha2_init(t1ha_context_t *ctx, uint64_t seed_x, uint64_t seed_y); +T1HA_API void t1ha2_update(t1ha_context_t *__restrict ctx, + const void *__restrict data, size_t length); + +/* Argument `extra_result` is optional and MAY be NULL. + * - If `extra_result` is NOT NULL then the 128-bit hash will be calculated, + * and high 64-bit part of it will be stored to the address given + * by `extra_result` argument. + * - Otherwise the 64-bit hash will be calculated + * and returned from function directly. + * + * Note: Due performance reason 64- and 128-bit results are completely + * different each other, i.e. 64-bit result is NOT any part of 128-bit. */ +T1HA_API uint64_t t1ha2_final(t1ha_context_t *__restrict ctx, + uint64_t *__restrict extra_result /* optional */); + +#endif /* T1HA2_DISABLED */ + +/****************************************************************************** + * + * t1ha1 = 64-bit, BASELINE FAST PORTABLE HASH: + * + * - Runs faster on 64-bit platforms in other cases may runs slowly. + * - Portable and stable, returns same 64-bit result + * on all architectures and CPUs. + * - Unfortunately it fails the "strict avalanche criteria", + * see test results at https://github.com/demerphq/smhasher. + * + * This flaw is insignificant for the t1ha1() purposes and imperceptible + * from a practical point of view. + * However, nowadays this issue has resolved in the next t1ha2(), + * that was initially planned to providing a bit more quality. + */ +#ifndef T1HA1_DISABLED + +/* The little-endian variant. */ +T1HA_API uint64_t t1ha1_le(const void *data, size_t length, uint64_t seed); + +/* The big-endian variant. */ +T1HA_API uint64_t t1ha1_be(const void *data, size_t length, uint64_t seed); + +#endif /* T1HA1_DISABLED */ + +/****************************************************************************** + * + * t1ha0 = 64-bit, JUST ONLY FASTER: + * + * - Provides fast-as-possible hashing for current CPU, including + * 32-bit systems and engaging the available hardware acceleration. + * - It is a facade that selects most quick-and-dirty hash + * for the current processor. For instance, on IA32 (x86) actual function + * will be selected in runtime, depending on current CPU capabilities + * + * BE CAREFUL!!! THIS IS MEANS: + * + * 1. The quality of hash is a subject for tradeoffs with performance. + * So, the quality and strength of t1ha0() may be lower than t1ha1(), + * especially on 32-bit targets, but then much faster. + * However, guaranteed that it passes all SMHasher tests. + * + * 2. No warranty that the hash result will be same for particular + * key on another machine or another version of libt1ha. + * + * Briefly, such hash-results and their derivatives, should be + * used only in runtime, but should not be persist or transferred + * over a network. + * + * + * When T1HA0_RUNTIME_SELECT is nonzero the t1ha0_resolve() function could + * be used to get actual t1ha0() implementation address at runtime. This is + * useful for two cases: + * - calling by local pointer-to-function usually is little + * bit faster (less overhead) than via a PLT thru the DSO boundary. + * - GNU Indirect functions (see below) don't supported by environment + * and calling by t1ha0_funcptr is not available and/or expensive. + */ + +#ifndef T1HA0_DISABLED + +/* The little-endian variant for 32-bit CPU. */ +uint64_t t1ha0_32le(const void *data, size_t length, uint64_t seed); +/* The big-endian variant for 32-bit CPU. */ +uint64_t t1ha0_32be(const void *data, size_t length, uint64_t seed); + +/* Define T1HA0_AESNI_AVAILABLE to 0 for disable AES-NI support. */ +#ifndef T1HA0_AESNI_AVAILABLE +#if defined(__e2k__) || \ + (defined(__ia32__) && (!defined(_M_IX86) || _MSC_VER > 1800)) +#define T1HA0_AESNI_AVAILABLE 1 +#else +#define T1HA0_AESNI_AVAILABLE 0 +#endif +#endif /* T1HA0_AESNI_AVAILABLE */ + +/* Define T1HA0_RUNTIME_SELECT to 0 for disable dispatching t1ha0 at runtime. */ +#ifndef T1HA0_RUNTIME_SELECT +#if T1HA0_AESNI_AVAILABLE && !defined(__e2k__) +#define T1HA0_RUNTIME_SELECT 1 +#else +#define T1HA0_RUNTIME_SELECT 0 +#endif +#endif /* T1HA0_RUNTIME_SELECT */ + +#if !T1HA0_RUNTIME_SELECT && !defined(T1HA0_USE_DEFINE) +#if defined(__LCC__) +#define T1HA0_USE_DEFINE 1 +#else +#define T1HA0_USE_DEFINE 0 +#endif +#endif /* T1HA0_USE_DEFINE */ + +#if T1HA0_AESNI_AVAILABLE +uint64_t t1ha0_ia32aes_noavx(const void *data, size_t length, uint64_t seed); +uint64_t t1ha0_ia32aes_avx(const void *data, size_t length, uint64_t seed); +#ifndef __e2k__ +uint64_t t1ha0_ia32aes_avx2(const void *data, size_t length, uint64_t seed); +#endif +#endif /* T1HA0_AESNI_AVAILABLE */ + +#if T1HA0_RUNTIME_SELECT +typedef uint64_t (*t1ha0_function_t)(const void *, size_t, uint64_t); +T1HA_API t1ha0_function_t t1ha0_resolve(void); +#if T1HA_USE_INDIRECT_FUNCTIONS +T1HA_API uint64_t t1ha0(const void *data, size_t length, uint64_t seed); +#else +/* Otherwise function pointer will be used. + * Unfortunately this may cause some overhead calling. */ +T1HA_API extern uint64_t (*t1ha0_funcptr)(const void *data, size_t length, + uint64_t seed); +static __force_inline uint64_t t1ha0(const void *data, size_t length, + uint64_t seed) { + return t1ha0_funcptr(data, length, seed); +} +#endif /* T1HA_USE_INDIRECT_FUNCTIONS */ + +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#if T1HA0_USE_DEFINE + +#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \ + (!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED)) +#if defined(T1HA1_DISABLED) +#define t1ha0 t1ha2_atonce +#else +#define t1ha0 t1ha1_be +#endif /* T1HA1_DISABLED */ +#else /* 32/64 */ +#define t1ha0 t1ha0_32be +#endif /* 32/64 */ + +#else /* T1HA0_USE_DEFINE */ + +static __force_inline uint64_t t1ha0(const void *data, size_t length, + uint64_t seed) { +#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \ + (!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED)) +#if defined(T1HA1_DISABLED) + return t1ha2_atonce(data, length, seed); +#else + return t1ha1_be(data, length, seed); +#endif /* T1HA1_DISABLED */ +#else /* 32/64 */ + return t1ha0_32be(data, length, seed); +#endif /* 32/64 */ +} + +#endif /* !T1HA0_USE_DEFINE */ + +#else /* !T1HA0_RUNTIME_SELECT && __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ + +#if T1HA0_USE_DEFINE + +#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \ + (!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED)) +#if defined(T1HA1_DISABLED) +#define t1ha0 t1ha2_atonce +#else +#define t1ha0 t1ha1_le +#endif /* T1HA1_DISABLED */ +#else /* 32/64 */ +#define t1ha0 t1ha0_32le +#endif /* 32/64 */ + +#else + +static __force_inline uint64_t t1ha0(const void *data, size_t length, + uint64_t seed) { +#if (UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul) && \ + (!defined(T1HA1_DISABLED) || !defined(T1HA2_DISABLED)) +#if defined(T1HA1_DISABLED) + return t1ha2_atonce(data, length, seed); +#else + return t1ha1_le(data, length, seed); +#endif /* T1HA1_DISABLED */ +#else /* 32/64 */ + return t1ha0_32le(data, length, seed); +#endif /* 32/64 */ +} + +#endif /* !T1HA0_USE_DEFINE */ + +#endif /* !T1HA0_RUNTIME_SELECT */ + +#endif /* T1HA0_DISABLED */ + +#ifdef __cplusplus +} +#endif + +#if __GNUC_PREREQ(4, 0) +#pragma GCC visibility pop +#endif /* __GNUC_PREREQ(4,0) */ diff --git a/hash_testing/new_testing/probability_map.py b/hash_testing/new_testing/probability_map.py index 3feac96..deb8a19 100755 --- a/hash_testing/new_testing/probability_map.py +++ b/hash_testing/new_testing/probability_map.py @@ -34,6 +34,7 @@ DEFAULT_OUTPUT_DIR = ROOT / "probability_maps" HASHES = [ "jenkinsOAAT", "xxh64", + "t1ha2", ] HEX_HASH = re.compile(r"(?:0[xX])?([0-9a-fA-F]+)") diff --git a/hash_testing/new_testing/probability_maps/jenkinsOAAT.csv b/hash_testing/new_testing/probability_maps/jenkinsOAAT.csv new file mode 100644 index 0000000..a47a3d9 --- /dev/null +++ b/hash_testing/new_testing/probability_maps/jenkinsOAAT.csv @@ -0,0 +1,8 @@ +operation,pairs,bit_0,bit_1,bit_2,bit_3,bit_4,bit_5,bit_6,bit_7,bit_8,bit_9,bit_10,bit_11,bit_12,bit_13,bit_14,bit_15,bit_16,bit_17,bit_18,bit_19,bit_20,bit_21,bit_22,bit_23,bit_24,bit_25,bit_26,bit_27,bit_28,bit_29,bit_30,bit_31 +replace,1984,0.484375,0.499496,0.494960,0.497984,0.506048,0.490423,0.501512,0.511593,0.496472,0.499496,0.515121,0.504536,0.485383,0.500504,0.496976,0.477319,0.510081,0.490423,0.492440,0.501512,0.502016,0.484879,0.490927,0.490927,0.511593,0.494960,0.512097,0.523185,0.498992,0.505544,0.496472,0.500504 +delete,31,0.612903,0.451613,0.612903,0.516129,0.419355,0.548387,0.451613,0.612903,0.419355,0.548387,0.677419,0.419355,0.580645,0.516129,0.451613,0.516129,0.516129,0.645161,0.548387,0.516129,0.548387,0.419355,0.516129,0.419355,0.645161,0.612903,0.516129,0.580645,0.516129,0.419355,0.580645,0.354839 +add,2173,0.501611,0.492867,0.500690,0.505292,0.515877,0.505292,0.505292,0.505752,0.497929,0.502991,0.485044,0.503451,0.496088,0.524160,0.517257,0.507593,0.489646,0.476760,0.496549,0.521859,0.514956,0.514036,0.513116,0.508053,0.492867,0.503451,0.518638,0.506673,0.495628,0.506213,0.518178,0.489185 +swap,28,0.607143,0.500000,0.428571,0.535714,0.392857,0.535714,0.500000,0.357143,0.571429,0.428571,0.678571,0.750000,0.428571,0.464286,0.392857,0.464286,0.500000,0.428571,0.428571,0.428571,0.464286,0.428571,0.500000,0.678571,0.571429,0.464286,0.607143,0.571429,0.571429,0.535714,0.428571,0.607143 +case,29,0.344828,0.551724,0.517241,0.448276,0.448276,0.310345,0.482759,0.344828,0.379310,0.413793,0.413793,0.448276,0.620690,0.620690,0.448276,0.586207,0.517241,0.551724,0.482759,0.448276,0.413793,0.517241,0.275862,0.655172,0.551724,0.586207,0.551724,0.482759,0.448276,0.551724,0.517241,0.655172 +first,186,0.500000,0.500000,0.494624,0.467742,0.521505,0.451613,0.489247,0.478495,0.521505,0.543011,0.516129,0.510753,0.478495,0.510753,0.510753,0.510753,0.456989,0.473118,0.456989,0.543011,0.489247,0.478495,0.456989,0.467742,0.500000,0.483871,0.483871,0.489247,0.559140,0.559140,0.462366,0.483871 +last,186,0.510753,0.516129,0.510753,0.467742,0.510753,0.505376,0.473118,0.516129,0.500000,0.516129,0.516129,0.521505,0.483871,0.526882,0.510753,0.451613,0.548387,0.489247,0.505376,0.430108,0.526882,0.456989,0.478495,0.505376,0.516129,0.537634,0.526882,0.478495,0.467742,0.494624,0.446237,0.548387 diff --git a/hash_testing/new_testing/probability_maps/jenkinsOAAT_bits.png b/hash_testing/new_testing/probability_maps/jenkinsOAAT_bits.png new file mode 100644 index 0000000000000000000000000000000000000000..3290b4eb7dac6718e41a3e19a434fc37accce2a6 GIT binary patch literal 38786 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 literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/probability_maps/jenkinsOAAT_deviation.png b/hash_testing/new_testing/probability_maps/jenkinsOAAT_deviation.png new file mode 100644 index 0000000000000000000000000000000000000000..fbe5af2dda9d81a2929fdca50644c7648dc9ad89 GIT binary patch literal 24640 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μND66<50QWneF{xg7*ybdurM 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�AI4m#~V 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 DQ-(PC literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/probability_maps/t1ha2.csv b/hash_testing/new_testing/probability_maps/t1ha2.csv new file mode 100644 index 0000000..55ba47c --- /dev/null +++ b/hash_testing/new_testing/probability_maps/t1ha2.csv @@ -0,0 +1,8 @@ +operation,pairs,bit_0,bit_1,bit_2,bit_3,bit_4,bit_5,bit_6,bit_7,bit_8,bit_9,bit_10,bit_11,bit_12,bit_13,bit_14,bit_15,bit_16,bit_17,bit_18,bit_19,bit_20,bit_21,bit_22,bit_23,bit_24,bit_25,bit_26,bit_27,bit_28,bit_29,bit_30,bit_31,bit_32,bit_33,bit_34,bit_35,bit_36,bit_37,bit_38,bit_39,bit_40,bit_41,bit_42,bit_43,bit_44,bit_45,bit_46,bit_47,bit_48,bit_49,bit_50,bit_51,bit_52,bit_53,bit_54,bit_55,bit_56,bit_57,bit_58,bit_59,bit_60,bit_61,bit_62,bit_63 +replace,1984,0.511593,0.515121,0.510081,0.525706,0.499496,0.504032,0.495464,0.494960,0.522681,0.521169,0.507056,0.484879,0.502016,0.482359,0.513609,0.513105,0.500504,0.503024,0.496472,0.509073,0.491431,0.488911,0.495464,0.491431,0.494960,0.491431,0.496976,0.496976,0.502016,0.511593,0.502016,0.496976,0.504536,0.499496,0.494456,0.496976,0.496976,0.490927,0.523690,0.489919,0.495968,0.478327,0.492944,0.529234,0.495968,0.496472,0.500000,0.493448,0.519657,0.510585,0.493448,0.496976,0.495464,0.501512,0.512097,0.500504,0.494960,0.494456,0.512097,0.494456,0.494960,0.495464,0.494456,0.515121 +delete,31,0.741935,0.387097,0.548387,0.354839,0.483871,0.451613,0.483871,0.612903,0.451613,0.645161,0.516129,0.419355,0.419355,0.483871,0.516129,0.483871,0.548387,0.741935,0.354839,0.483871,0.645161,0.516129,0.516129,0.548387,0.516129,0.354839,0.387097,0.387097,0.354839,0.548387,0.419355,0.516129,0.548387,0.516129,0.322581,0.419355,0.387097,0.483871,0.483871,0.419355,0.451613,0.612903,0.451613,0.419355,0.516129,0.580645,0.548387,0.483871,0.387097,0.612903,0.419355,0.516129,0.483871,0.548387,0.516129,0.516129,0.677419,0.451613,0.483871,0.451613,0.516129,0.612903,0.516129,0.483871 +add,2173,0.496088,0.508514,0.489646,0.488725,0.500230,0.514496,0.491486,0.479521,0.499770,0.484123,0.488725,0.495168,0.499310,0.484584,0.498850,0.530143,0.488265,0.484123,0.519098,0.494248,0.497469,0.505752,0.501611,0.520018,0.497929,0.512195,0.498389,0.474919,0.498389,0.504372,0.491026,0.514496,0.496549,0.479521,0.492867,0.499310,0.499770,0.498389,0.480902,0.493787,0.492407,0.505292,0.492867,0.499310,0.494708,0.511735,0.524620,0.506213,0.518638,0.518178,0.492867,0.498850,0.498389,0.502531,0.509434,0.498850,0.492867,0.499310,0.501611,0.506213,0.482743,0.503451,0.511275,0.493787 +swap,28,0.571429,0.571429,0.607143,0.535714,0.428571,0.392857,0.428571,0.535714,0.571429,0.535714,0.571429,0.464286,0.285714,0.714286,0.607143,0.500000,0.500000,0.357143,0.392857,0.571429,0.678571,0.464286,0.428571,0.392857,0.357143,0.392857,0.607143,0.571429,0.392857,0.642857,0.464286,0.678571,0.750000,0.428571,0.607143,0.428571,0.535714,0.500000,0.571429,0.642857,0.428571,0.357143,0.535714,0.571429,0.535714,0.571429,0.535714,0.464286,0.607143,0.642857,0.642857,0.678571,0.285714,0.500000,0.642857,0.571429,0.500000,0.357143,0.464286,0.428571,0.571429,0.571429,0.678571,0.535714 +case,29,0.413793,0.413793,0.620690,0.586207,0.379310,0.586207,0.482759,0.448276,0.551724,0.448276,0.655172,0.586207,0.655172,0.586207,0.379310,0.551724,0.517241,0.310345,0.517241,0.517241,0.310345,0.620690,0.482759,0.655172,0.551724,0.379310,0.413793,0.482759,0.517241,0.517241,0.482759,0.448276,0.586207,0.448276,0.620690,0.448276,0.448276,0.448276,0.551724,0.586207,0.551724,0.413793,0.413793,0.586207,0.517241,0.482759,0.551724,0.482759,0.586207,0.586207,0.379310,0.482759,0.586207,0.379310,0.482759,0.344828,0.620690,0.482759,0.448276,0.551724,0.482759,0.551724,0.344828,0.482759 +first,186,0.500000,0.500000,0.526882,0.526882,0.489247,0.483871,0.456989,0.532258,0.510753,0.483871,0.537634,0.456989,0.500000,0.424731,0.500000,0.435484,0.532258,0.456989,0.478495,0.532258,0.430108,0.489247,0.521505,0.478495,0.478495,0.532258,0.478495,0.532258,0.500000,0.473118,0.473118,0.537634,0.575269,0.526882,0.505376,0.526882,0.424731,0.462366,0.548387,0.478495,0.462366,0.532258,0.500000,0.473118,0.473118,0.559140,0.510753,0.526882,0.564516,0.521505,0.532258,0.521505,0.564516,0.537634,0.467742,0.473118,0.500000,0.424731,0.424731,0.462366,0.494624,0.489247,0.537634,0.559140 +last,186,0.510753,0.543011,0.580645,0.516129,0.516129,0.564516,0.500000,0.478495,0.489247,0.494624,0.494624,0.478495,0.521505,0.462366,0.526882,0.521505,0.564516,0.451613,0.489247,0.543011,0.537634,0.467742,0.467742,0.526882,0.500000,0.526882,0.478495,0.532258,0.462366,0.473118,0.569892,0.505376,0.516129,0.494624,0.456989,0.478495,0.537634,0.473118,0.516129,0.494624,0.440860,0.505376,0.537634,0.548387,0.408602,0.569892,0.537634,0.559140,0.494624,0.559140,0.526882,0.559140,0.489247,0.569892,0.537634,0.543011,0.543011,0.494624,0.537634,0.505376,0.473118,0.494624,0.532258,0.483871 diff --git a/hash_testing/new_testing/probability_maps/t1ha2_bits.png b/hash_testing/new_testing/probability_maps/t1ha2_bits.png new file mode 100644 index 0000000000000000000000000000000000000000..23ff27511959973364a57febd40e07dacc0203bb GIT binary patch literal 34872 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

O@lML9S)IIlB$3+|?~yooamwG)Ri*QHF#&A)gJ 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%0DN}n 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 S_rj8VanjK2SSI1zPk#fyc`s}L literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/tests/test_t1ha2_bin_hash.py b/hash_testing/new_testing/tests/test_t1ha2_bin_hash.py new file mode 100644 index 0000000..7785ae8 --- /dev/null +++ b/hash_testing/new_testing/tests/test_t1ha2_bin_hash.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Behavior tests for the standalone t1ha2_atonce hash CLI.""" + +from __future__ import annotations + +import subprocess +import tempfile +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +SOURCE = ROOT / "hash_funcs" / "t1ha2" / "bin_hash.c" + + +class T1ha2BinHashTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.temporary_directory = tempfile.TemporaryDirectory() + cls.binary = Path(cls.temporary_directory.name) / "bin_hash" + subprocess.run( + [ + "cc", + "-std=c11", + "-O2", + "-Wall", + "-Wextra", + "-Wpedantic", + "-Werror", + str(SOURCE), + "-o", + str(cls.binary), + ], + check=True, + text=True, + capture_output=True, + ) + + @classmethod + def tearDownClass(cls) -> None: + cls.temporary_directory.cleanup() + + def run_hash( + self, word: str | None = None, stdin: bytes | None = None + ) -> subprocess.CompletedProcess[bytes]: + command = [str(self.binary)] + if word is not None: + command.append(word) + return subprocess.run(command, input=stdin, capture_output=True, check=False) + + def test_matches_upstream_t1ha2_atonce_seed_zero_vectors(self) -> None: + vectors = { + "": b"0000000000000000\n", + "hello": b"2a5f2abd74df73b4\n", + "HashWord": b"3885d16135ce64f0\n", + "abc": b"16bae0f716c45f2e\n", + "12345678901234567890123456789012": b"75ed8a8aa66a4602\n", + } + + for word, expected in vectors.items(): + with self.subTest(word=word): + result = self.run_hash(word) + self.assertEqual(result.returncode, 0) + self.assertEqual(result.stdout, expected) + self.assertRegex(result.stdout.decode(), r"^[0-9a-f]{16}\n$") + + def test_argv_and_stdin_are_equivalent_and_strip_trailing_ascii_space(self) -> None: + argv = self.run_hash("hello") + stdin = self.run_hash(stdin=b"hello \t\r\n") + + self.assertEqual(stdin.returncode, 0) + self.assertEqual(stdin.stdout, argv.stdout) + + def test_handles_long_ascii_input(self) -> None: + payload = b"a" * 100_000 + result = self.run_hash(stdin=payload) + + self.assertEqual(result.returncode, 0) + self.assertEqual(result.stdout, b"bdf3f8539f0504ea\n") + + def test_rejects_non_ascii_input(self) -> None: + result = self.run_hash(stdin="ёж".encode()) + + self.assertNotEqual(result.returncode, 0) + self.assertIn(b"ASCII", result.stderr) + self.assertEqual(result.stdout, b"") + + def test_unaligned_argv_is_clean_under_undefined_behavior_sanitizer(self) -> None: + sanitized = Path(self.temporary_directory.name) / "bin_hash_ubsan" + subprocess.run( + [ + "cc", + "-std=c11", + "-O1", + "-g", + "-fsanitize=undefined", + "-fno-sanitize-recover=undefined", + str(SOURCE), + "-o", + str(sanitized), + ], + check=True, + capture_output=True, + ) + + for word in ("hello", "12345678", "a" * 33): + with self.subTest(word=word): + result = subprocess.run( + [str(sanitized), word], capture_output=True, check=False + ) + self.assertEqual(result.returncode, 0, result.stderr.decode()) + + +if __name__ == "__main__": + unittest.main()

$Ieu5IIl)4X6eQI z6`qfOrkPjsBwB$Z6;D@a(xe@9Npo*h*U6)mX{>uZIRmIUUGBM@-OT*B@cya?#jjfg zs3V->v@8`~bCx~|n9`fpw6S)?iIVIb2}3$qT>c2S+`eRH-jkx=W*juVemcT$xA%kZ z1GkvG*9p5Cwp(>HVtmMp-;EPIPS2M#*k5x(on&j z@$)+wT?83u;Kc(2j3O;+{)ZoLVPv`8d1ktSDXIIfp^<0jE7Hw!+Cw6*V{I9#=)XTU zKPSY-g$3-wLU-RAZmr9TNG%Rl>(*Nr(t{xXT+9!`x*H0ApBn0> zTdfX_h*=OKYT~*lg6O9+$i#}=aW}iYXm}SKdKHdeLbZiayYY&q8OGgv4b#RjvBZ&v zZQDEg-c`SPZ*cd#x_m)_oU)yF4{SxUdGFxhyXq~YZw(BXsAxmmk}Pf7!+F|BN5)%~(v$g7am|n`&Ha``e&l08Gqh@Gm$TZj&DbMxI3NL%o z>xIuN-xpqX^J46dq9KoP8b(oq{x*)v)|~n4cd_1OR5n*WRYi}2`#}BaN|l#!`gUiQ z`)Xr}GbHORSu%#?)Q-Nwch}P%p~ZwO5~4FE%Refjl}H55sA_lVF9mU)4y}Y?ua3Vc z>6ZF!Sl!_B;T60eb*HOK_54^Gn5Kvo?Xa&Vt-bM=Bx8*`H%&@{XCEEd!Vb3%Zn(2f zzzZJKXw7hKje{|FMt2~_LkK_qIfX4x{M>%aW^{Ygd!;A~IZQP?zsVl>4Ka2gCQYpH2xa}im>mhh5A2isXpM^t;$WkcTg|EBPLq! zj-jr~aRI4l`8zc+5@tF9abXIL6#+u5d>mi~uJn3WS1fOq(pIM3gx=9iF!t@aUBltQ4%x!YnDIh?4fXc-eYKl;ccI^6jAv&38W=uH zk;lmIeI{B$c>)Bd(;hSyf7)DnXoS~>T;!1ZE@kkZXMH|nsRQh;JM&O`=#UOaD`))t z6Is!~9Xp0an?8T}V*aqAA|Y!|Zxy-CL0Y&~t@KdLZfz9m`9ga>4U1dnC&}Yq3g7ze zknZK&Ue{H$?$TzO5>j$fPRHbp(w*lpnJ3+faXZP~-7lY#@7EtOh=|WV8-G=#OhiqM zt!gUveE4wx&@m;-2x%*pi|d5a$vWI1PNk00K9!s*N4`~^3C&*3j?&mn!uwq8Qs4<5 zyqQSvwPwQ;s;yfk3fg1{7)6E26P53-Pw5T*d}5E@?&Oe+7aucr%dF&)*>PQ#*ucQR z5#0GOHbwKSW@$CP@S0J9I&uQXvlJSe+%8D!M4gY{>O~}aV3l^v>NkJX=4|ch?A=Nl z+`(p=_;wi05-e!mJ@Ixk@8e=B-)X=E~8*`WqRF_{twmfema#6 zMRHpvH|weOIicVMRi`(F9>^yVtAC^^(E) z+ftcs?kik>r$62*Hd9e2fGxMSv9hkNx1x0*427o8xF(115mYX-68Rbs7)uCxd2Opq z#4g?sa$NiJ#69fo(>_M%H+5g3kB&=tdF)^S*ruTtV$o_Oz66X;68A=?irE~{{66=R zJ-w7yJ>&g+YWw5I{!z^geTh6T8Lq2dwT$lQoon=ZG?}VQ!uU?jWr>iIzee?8;mt|O z$+O)$6r?xZ1(bauLcm_mJu0@9D&Q%@bJ$Gq~NsTT^kCTnrkVn$HO1qp|k!uIrF`lm!?Ml2$ zSIIg7!}uG=>^SScLD=Lo<7JQ3-tBmIV9%R<`L>yMTdyU19Ec3Y@lI4?;ysii6dH-~ zFUOUJgWU!KvfKdTnzbb_-wIf@@0`I|cNslNq16i^eV3GwZQ09|?C?_V zQ}POOjK>QftXXsOd0OE}TbcHx zYoB|p*S@?!ji6AU#>qJ+%31o4~q{|}*3M!x_6 literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/probability_maps/t1ha2_deviation.png b/hash_testing/new_testing/probability_maps/t1ha2_deviation.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb84380a45d6ff13f83838235b89616300a5b5a GIT binary patch literal 24040 zcmce;cU)83x;4z!tzZQUvQ>)6Mg#;@q?aflC$|5-}PT3K_=`8?wpV?6WCLmiD1M=u;@ zVPQFO|DKvY3(L=?EG!4UvmF4husiVXvanc|+*i9}=r_5Jb_n7$YG(ZrbNil($_WmY z1o3-%KmBy-?5VY*ub(3?k!F0|8c0=zE|z6n9B(gQx}5v`9_O8hXU}HdCn%kGPgV_j za-8Gz&oW&^>aGW&r_P`+F(#1FlbHB=A+{1+?aL=2eNON%Tgdk98Ha>)Ml&1jy<)dS#8Zrdche=ko6JA{GBK>Ns$o;`XPAIzfG3){C==j}4a zO|-$N)J`}#t$4v7ZJ?+5mV(GF)I$-*#by;x=d)vnhac;;X~svE7*I;>HKbMoNWw-1 zhJ&r#zm_x(5C(*-IyyQYa=!XrgXz6UpB0M9*0HV%SdSN*>WURN%F}<`AT8FfoMF)0 zl21z$^i`x$`M9q2=yuM&w1Nh;&Q2cSV0*!Mabd@NF=&dh&Sh3D>x>X2z?buWdZ|ub z@!2R7vi75`|J0zXI}`Ul<$ZZTZ~dE?90++3$CZv*FP|YnH`LN|pw1WV<2G>l?l9*ijsw)V z^~t!+{i%cJ#P;^864G8rK68_19sI~I;I$N$nb|sK74+E(ZFV?T+@bDM_~P zrMp89`QRsaRxc97Ov~5W7>eASi>UDDKeBJKz@N@5r&DLX*sQ)dh@Ap zjlDa}z~Tcp@)QSutJeJn+oZxVhL*QILOCu;U&+2de^}#IuCLn50F7IPGS1tzT$Dzd z!^CdwTv<-4=iHHXGa0wxOZ=bKCcSY&4^l|O@clw_6u(26FNIwRrQzU~y0~8;fuyf$ zxqTy4+I5enK)VxkJsfHM!E(W)-)H%-DTDOgCk!8o_ej1m-G;79rV~3;OgCR8VDJH? zJm!l^E{a+6M=$Azercr5{78X{n&j`!NwT-M zs)cb}kSb(MM(9>5<++f0fAhsp@6AwJ2#t%*JBQgqzF4=Xk`>F_671POu3!8%EX|Cl-sk;Luj*G(4>NKtn~xrZg{encI4~VucO|) zK_CjOiacNLd&~Pc`nnd_HA`rahhxC&e2Ww0LZ^|Tl4 z>XCi0K+^ftH2=95rPd}QC%F~pUY^Q;r=UDEJU#Uvzw&9XYTTZ~OXVANVoz5S?(s@L z-p&*rLQ&}LI~QdHg>t~eFAu2dax;@5Jnc)ofB%i#F?PPa&J#5=2}B`6Yk#Pkn%aWd zl14_mmDfC`0%QE(8pLUh)%4&6B5bAwCZl-=fecdidE6cErm7L7=)Y=$=}$#H9a@Tw z9eyu3Cu(@r*ES|ps0xA)@hS4fkQL9R^$SR{Lw9(dF<$DfE7Rz#>0N17;-A(`V$|_& zlKKWi`zL>q4_Xk?ioZ5h>*Upb(v70X*dK%ibH3qjwhrd}wD3CsMORPM7w3E-e(y!y}Jo!Nv(l57IIHX{o_4V43BX*PN z-|bsFbYbh-e9@=aetN<2U{u-WJNmaP){tq-`%pDDBxw%&ky!qQx7O^!qv$SYSy3PZi?Yd*-exWpgRj(C@ zk;hW_%5$z+)w@2$+##@^-`iF7)zHu&cpV9*um`W@an-n^2l)>kj@rc{YeLU0_1QNHvYyvJY^)`2nO%y z0AY%->DNGmvhz%2&Jya%#igW*#-wWcQ=}Xa-6%>^dpH-OH%^YoutlYWw||2%cE;Cg zFpRf>2oV#_E~za2tX4GisK>L-*~nvC6Mqi|g|8BTdsxMIpUIp{Y4UFt~%BP%Md1nsJ2U+TTU*j0s#npHaX zrSC$K6greX$oa-~GIKU+%xaX-i&fq$#YEoc6Wev4Yc!pQ@JTLzrMQdgT~=O@MZWd* z=yDqV@D$UNnC#V+#g!U(okZ@0qf$gq%y{(L4PA-cwIN}HF@D9)ahhP>_s-9kpp-6+ z>FhMEQ9I|AcQ=!d&}M>|?@kOssLMmjCFE|{R0U;1uKh&x1tn?hp&0%Uc4clP6Fk%i zRl21z__8VJtE{B)z`d%by1@Y{q(st9{7XJm;&s;_E?{9^4&3icRVYEOq=99_^96({ zu5`H0X!LNAr6hJ6J{{;nQnrucIuRIPxDO!2l+r%$28~8)@P~*$+Fgba_T9fZ#Iy&0 zukO7ehouwWIV|-hV{&b1?^I`!6kMi7B@}rto{5oEBwyUPvm2}%k}l`cw_{?RG{Uuy zqNx-mjd-2gr5t2*DYpf)xJ}o}E$|9Iyh$iK$R84QQHCcHa?&8XcX@g~JWkYvVtfE3 zyzhfW-79buaUbOU4cPfLOd*R=lG8M?JVI+9MR>bsgq%Xzs3ri zW!`)6;MtCIoP=Ttjx&MOV+tmt@ZQAp#EPY9AF`@kPRg^#QwH*B9$(1MhL*(Y=BDkq zyitpxqNhb;BcjE9KxTrXNDrPpD=Q_RitJZpIQI#2ZLe+BC=?gO#y%>1WQdFJwep|c zOvxima9Lw2{k2AM7e?|c-Tj~SX>mY!C6(8L8y#QZO9QT75InnkIBm*P>GY2+t$^vL z-6J3YwT0i6a+>~;I+k|7@S*sEEFWdNqJ;a40P&+Ux_sh`uQhWl6Racs=qs!)BZV+9 zZ$>Yctoh?jpFV996%?HD@0PNu@p36aQEgiedp~*dSVz8WeI>_7wzTT$L>n54Eb}$C zcAS{Y^|hkt_DOb5RlC6(Fh4vv(r$ln(JXshr|{dhyFv9DDes`&$ZC}gdXwGy=vnW!$*;icT6`YjvvW3CKR;iX|>S-;!@F7Ni_0B_;|vAn8xPHm8i;GS<{| z^|k2!9gqIWHI{ar9w7{Fie1j#X^2uz^g8z%flxqcU{gLV&+C4J(7&VQ`YANJ0P#23 zYNLu8tKe+McbEA?#y@-*(p~r1&*KS2P#3=7q3gkHV90pvOiNWM_U%=!^5y{03ij?&a>=fR}$-d)>l$7%J0O&VrhTZ{ujcT$&t}u`yOUwG&kb z*_jgHhg{&%BYa|Y@An^YdbPDE5-Y*PhzO;*qKy)d?}u(YHha^VI!kFo8K&yw-faRM_XAuZSz>a;;NXG}$W?1~d@2u$2MVn-%z zu3bx5Y#_i3^-xALE*AU5trW7hQVniJg5$#<^5#uXWvvV_anSv8 z8MhJNWuHftV?2#?>Oz#J`KyEW${R47JI}cjS#?!Z5|z|z4>qCfx)z$;>+Btt>KBI#VhX-&Efz#OK9nHb=?fbx2xjp``nkHQs7$1g-^=-p zT|Mws+m3}kd__Bv7Z%t#4Nvp?_;uF19P0N$lo5iQPFftCsaeu|DPuW?d!s>zl@9&Z z3{AJJZXc3zfd?)LQJ1c1s@xf?6>WDM=THIBBwC^RE@^7-*tuXy2mD7&G?x;peF7eo z5pvKYTzIy|yCKZkqGqbqGZ4aOe($X4Iq$1$gvlx#xsG->TrGZb{oF^?(CiLwA%E5s z6O>TUGgi?=S@#ka;T^At1vqJpQ9YI*Vsw*9JlL?Sio?AwA_OiBcYEheRZ5^vQtIDW z*BmRRKi*2) z8w}sfjw*^=dT(hv+yKIt=E9HlW%RDAV(j>k8K$BYxFk3S_hNnhDk6R%AbhM9lUCHV*na4k0=f1wwxw!*etu?+_-w2~ zm-eI@)mtX!X|z=UZA`#9&_GpznQBKsr$n$y*O!7AEg^4)NXCAnYlHyHUCb|A zYkm=1pa)PWlgTu%yRCXpzAdHZHHhlCWUNwGyRKSy~86%v>Et(H!#J^{*JHPM7R;Wfv|b5JrzcPq*HCzxWIU7>*`uJxYHK$ ztSti;i|X)K`O&2Kg#p8vR@@&jR#<*DE2kc|TLj`|6lkkNx_+T3TXRlq!mJDmc) zi;WYVU{*!$|5!g*{z@!Kis#ld+rBewy2`{YK`x(&s3;y<=PrdWK%Rh0vVv7Xi^G(m zQ`NNJyWPjl_k6A4)!Miv*3wX|1d)k~DN|^pn1qj;8PJk@z=4F%ay z<6s>WtjqO=6U4pqaF2|$+v8Ko?*->e8dl%8rv=T9mC}|12L{^2 zmnQ^2xvmhfV!K!YhE<)jcE{7%Q85{dP3(FR97ziX84lobIgoh=vowR10{bw0yC!|V zp5x<75Uu06+I|aC4w5*wF?9vN1QMyT$0fkp5NWnpibC)Q=U{&Ll6G#j4e7Y2yIlPV z#5wAnXy(L0Y~43#a`u`lL465j4?u373S&TPHbAASOqs)V$Cvb^Z2_XD2d3x?Fq*ri z4jkSQ_NwkZ6t$RtBqrMqbN9NWBoQF9{%8lV;L|V}UKqM6i2R`by}`)2OT#eiE;(vy zu4)C(!18pzZu#`PJ2Y)UyRy+|I(5jq2yO1A#mxJn@6d-7HC|vNL0_+hP9d}zzhdy{2yTtf052!rP)pJ3S3b?jS;g1QXjiJS_+Fs}zOUGI zR`|64z#ga_ux)6*C^n81{-2xqc3LamsbT_XMRZU-o7V1P*Qb1KA?Y7Ca;%H{!AZeS<{_Y4hb>qTEpMo2nNYs^@FKTiUWowN60IA_VPAOsk3)!6MJI>9| z53Q~-3<5HJMt{^_Ngggum#OKJEesejZs(?35Fo{NZP7Y(|p>OIQOIW+7 z)3?fn6kqpe5-ox20I)M?B@_uTex>Z~50bV(z3Wo#K4q0}_(mj7gx7cNhGn08){@Og zGr@0iRh5i^k=@3k>D$En2HDI47K9~qwOb$81AM@_$jdoVd#dPN%V$LoW7O=FonRk6 zKw;-mvZq!W_g-Y!G?cowC83n4)B)|22!trT9ZI@0iP1~f4j>{=@kL&!5s<68gG_=y z&|WH&U`%O>yW-@3AeZ1(O8!CD9S$w!_duEujGt~wN~ZhK*I#$M&W{rf<*0T=!*DbP zJ(ZQpE4Jsqh@*wFbCWu;F%ItNdZc@i^SgI}vS+S)f2%<#QI<5)b-L(WCXIek`S(q| zyxeA3`J&PlX~_Z?M~JD%;OFle{X~sZ;}Wg5nUBA#mB43QR7_H5>sUPlhZ$| zeEcqKd~J2(LYQ{)rlrrN6zTZ}fs13w^c`Q3oQ>syx*PNYv8#}+!;q_0?c{T@_Bw?sO zr|1z%q_lqXj7qoiHv? zk1Mh7M>qPL>$iDg)BN>!7<>k?2E50P@UKnR;a=*^JM`|^5SQGHM1|4b# zf9zNZ`!&j)|hj-yWn!lh@s0SA19-@TElW!>lOBDmd!p7^EAi8$JIpR*~s#$#xyDDHh1d2QNhBx#2aky`HF@-5_MmVEjs z{q=rTvsI|+(sY8Nh(A;;j{Gh@3>kc#VBC#eh3N_=?0VvM{zUB>u+!^ASE?^M{>q?XayA0N?(770SA6_prn?{sun_ff`53-Ls-o3;0S$f!J1W2M1P0DR8iY}n6l5*1ALr3&1BFVtD%E5T6#(VfkHt4i{ie1#{vqQ6W2 zOlElY5emg3`oEIlo>=7Dy<-XA+Bs3+1FCE0(I3ypxHb&Y>mj*RSKG|A<*>76L4 z{iyYt4MMN9?b?Rw5d19IW{I7W>XB(4U*&S73$1b3#e$h2sG6te>K-=b^j7eejfuK? z@jH9}F;$%>LNGZ}M2R>a7LaN-a_-vxUJ+fuvkyJxnZ&CHDtFzcls!wzd=f){t6*aB zOxGIhJa#7E1(BROq+B2fS@)jscaWBE991A7f=KTaJYl646E}S=;7>;rLpEc!%m%2h zASOkIo1-q`({)~0QNr|88qAmpYM@%|!E+S7H zTJHd0sFjOP!GC`(W~!zyX{&9xL{unFSMypr`STY1JDxn7prOjx9U26B*y3qTY~3r0 zwcf-ibo`lZM*Rd7#2g9zUp>*G+JV;^UB-$Vc!Q+H+#L2ivk-0rmAyAK?1ehfJRs=W z+b|YxU1@3l*&cV<%U}K?kfjAR!P*yrVMOy< zDzNsda5ABa?Irl8w;z@tW7EAf^WJY}X?{zG_jQ81eL(m0VdEDR^rl2Fgzh+VO7I#e zN@uT}+9@CWjm>7*A!f2#es%duSi2fmfkDOOd7+wA`T69iH8x!6Od|ghqo=#zOKmJjfO5O6~HXUc*2hL`bgNp^E zx^GA$Pi6D`k47~$>`N6RTXppZyg&E!^Z=mY3gR)zEh*tOLe#QcE$57xUDj7*aQ^K- z9yH{F65;Nm-dzgyw--$Owsu4Nigt49yLabR?&;{H-U!4$6+;vnWpoh{=(_fymxtsX z;r-xo6U-}oR7c0d6sh#^uAbv73clxP>-WNQKi?f1^uarM4}cM$Exsroyo`5=hEz{{ zM||7ilb1)l;z9uR?~N7G2Pt8}*2i(+l|gp~Vt0%Pl`yLh8W^Qa%bd4Ob(|W}r?LM3Y%QJaGZq6l{rR>-6%XA zih0*anIu}>(|=qC9_}my`XVOw5ex)L{*bx0CuY3pwtOG0|z~k=*x*=Z%Z4OtK9-X$9%QqpH<~RR9*~lVVfIdL4msMM+X=vTmdA z?L-Sq?kCaER3HF8iB|snaimISFE2i*dJKQMTgW#3-ZVB`!$%0CAi09WF8oMqF%c*Ii^>?`y!VYh)1I z^gz6Btg(S`2R;}Yn9mN9A>^o^aMn%UbF;NotH`GCvM2VxB$2sc{@YDF!ooLhv~A5a zQw@jNkDY^%SDzP-MO_?T3D!$U@e;VK0$3>pU-}h#7Gc`7aGV#myQnxYmTx+*om>;V zy~5@2OukqxXnID#<(a2vKGd8Uv-35xTEjU{&-g)iZAL^Abg!QAoW?1JY~Vj4W_Y&s z`nJFm>kSyduJeObWbNft<7ubGC3;TEc452@BHp!mOu(A_u_ut&)+W zt>Hvf#-|JgUd&AwHDfmZ1q(0x4r~;fm=>p@wBTjwFOd^4lBxM-G3NoJIv_4n*gAOV zqkFH?Ot%fHz$Ja;bQy|#ytm$63?&-g;Z?9TVn{J&&)x`q6>(~^=cp;6{rY$3vV zd1Yk-KY;;z_!=rE`D~#!y1izS8lJc;qm>3P@k&?z*m#lD<#fu8Z z&aK~zebbMb)&*DslsJm09D+#Lbsm1imi`hwtW z?cx@VjZa_7o7$Zdx8yx_>iy~NMKf;;SJ%E6y#mkU4kD*be|33i3R|6(fyiiq)Q7MH zz-rc;onp5x=i`vx?KDw1kXsg`<2n^ILv2Hf%Qk!*iF2v&qMht>sG`#Ordb2;GE<0D zBPI-|45@AZV@v}J%1PVI?C$gd6H&ee{{@?at{MKm=z8Jq>Aif z>l2{|iE_kbf8ji*W9Mj!bMr^U5bli>zX9;;ds9)%VTZH^2Zy*o{%^TqZQC!B@X)!p z{sizcbn7ZD3~uhmKS6zuZK?B6oA ztdmwq2r}*_kXZ{Ip>Zi1CkW)(`hIqN88g7sX7a&^4Jq)-Je@4ujInnGvdK_WvMD`JI*8H)k^;B^^M}ov{cTx#SrOU1AYB4*ez)(F}J-gDZc2v&)&o< zSz7TONlaLP!v`qhkrlGJSAs`P&599gY5+)eVZ})#1X` zf^)x1hI~oa0p-#B++zrh+FipMdCjcy-eTrap-QKC+L=#dhf*x)?XCm6q zrtnSijRldX%J3ESKA5!>z86{ao!9ebyd&`CW$@3Q2L0y z>oLe~iI_edhz7{Gy;M$4I^#HY2N`gjzEPpT*mHG#@Qf&MF>N9b&8w9*jQ@aW*IAL- zoljNp1)2|fXPZ=%EYta<6NKOvfbVCp=$9`b5x{MCtBQpMZo{ll+yb|%5>hD%(+!|n z-w)b~48u41u$!oy(;TwzIlnWJNpWwujGNdtuXbllwe({GT}le?e0Wt<=IJ&Q%_B@! zCJjm@co!IDgr^<)`c{wSIpY&RT`*;Tb&9kY{hHJDkneN30zklju*YCcq1Hw21v$6u zOJ&_*3ynO$LWL^rr^}2MqQB?fSwAx+%{b%cqo!6nzaPQK^oEgy+Z8r|e#Sz70O0mF zYfluuX;VMy5Ql{-;5lxCK=D`8-hWXV%>Vs88svZDHNdB{uy|Y*Hv2{TvVefsc>8=# z?=BMr)9R%HeDH>smBkr$qs16m&z@F)CPlkCnm@C+O#&;7jena@K47lWbV6%6VE+wR zAlaQiv9Oe@{hE_W>zA3EFN+b|r7RRAN)veY@3qFXbl;no{H(wzek(=jJX*IA)l=I1rT< zxZM}VfVmZ2FiL~1pewhxt;yGKmYXexTj~<7JK%qh9loV~l7;2rqXRY|1`i5qU9+sd ziCfQ?!VL`$iGtyAOnm+NApj5UXUyEjYwgzSwUf@Vu>8>VFi4aZONQ<5C3Kq;5DDwl__QY1 zwpD%sh|8lA;|I@fFn1pdi=z!`?dU-_-*Tvap1x>~J?X3*f{v zBCy(ez*EcA`oZwO;Q0Ujz+A5^|Hi`)7Loj;EYF*t0Kv@4Z?D%MLO;vN>HVN0+jlxZ z8!0bE&e#BcOlyA{Qnx*LlUN=Hu-Oi7q-iNUf+;S9yaoQ-wU!&uonQu~4zL37hWYxL zgw%9o4-mVWhM*fc^H++^kkuA-R+m#f|jhDx7o> zNsqym?(awCGN>o5A^ld$X;-N_D1LCU00x?&!vk3xkMBjLC>M;4)bv}IUJbbpJb#i+ z^d;aC!puMBgYUO}i#o|SOjzuk4;_^+oCFNcfa z6`G5g)o#&p`A!*bQ`Hb!x-vy?H~wPrvgfEUAfiv7?n)V2tmJ40MgiCd)b$V#_pu?y z&IShI_z;Rn-rVv+cq1iuSB zeCJ{4NMr9x#~8O22Q^5xI^`g0IGQYr*E>Xe`D zw(m`UXdnb`4?R7@JQ>ge`W4rIEmHM3iu{rM0uc0Xt-W!>UGk@D{5mDL1jJ11uZ1w} zRs10o-k^MSnz7haYGQhG9UQMl-FlgG&-NYFwR2tux%=yCa2FsMH zzx=q&dkdB|mKRlix$f86-)$U32h@#2|CXxwGWVbb3QtdiX4J_Og zKA3z6$C)$eDq_CC zvb#}*4Awfr*PI!=Lhj?odwJ>X{S6zVMN`G7ohGpGfxmknlpE|y^tIRT(py{A;MX^* z3K_RL-zO!-?=Y_XH9qwB-o6C;@oBmSE`T_`PL;qqti@($zC*k!OR;-N|0YRR+SSX zZ(n7Cg`dZm$3Jkx-#cuuUS-BU8gaDlpkXtt!S6TUIF_Fsz>i{KvMMZJtkrum+Q2(n zbqd;o|M3QM$^+x*|MT#(3K++~z4S(cVdZtGg}V9@D7SQzH{Hx8`}VzEw%4Zf)PgMN z-G!E@rwbq65YJsZ$`AMpWcSLtR>HMUOsJwV3sIG|r^Y5$U@b8P?KI!*nL4jAAlY!` z_HY@Xl*^wYDbR+kKAgmTZEg4yT|QRk&pej##=ybbaqP3F{wq-LHl&Qg=*?LLW9}XB zMDd&|=wPY4tLrmBdz#lcHa?pWSwF$dmW;OppwU9cZNjWbQ-5>{Fc#r=?}}O1T`3Ei zI1qP)-*u+kZ8Z`K_`#TdBMHm0nRh?2a2vv)+(%dQ4+Ljk$~V&FV1viKe}7H|*wp*d zPG7v3`aa3*<4psHAPSzs_liSAC=LaxidS`lEG#H0OR(A{>fHwq$~aU!yGmBX<>aKU z$k*StW3o(un0A|}cH18B)J1LMm1?#{&T(dqFbBk@DfD`=pX0sivxO=Qc9muaIDSp(-^BAC17FyS+_xGi0wze;#dVo@ZI1jNKc+WX7 zpa+;gIb5vIje!CF5Fl9Trbvqh9mK=a&{6|BceA7*o3!DK3WNSMYLBVkt zEKkgMg9E)gNYMw_Afof0!Un%-n_ClP)@U~AR(^OV(+VaF{;$;$bxkJZeQ)PhH4P!b zcwpIzITQgOEe5mX(?&Y~^gpR1fRLzB@T;IbisreL(mCXi@H)a}_#vR0wGNSUqA4<-Wgjqm)6_*2YeW1<&(U%G^d3=!tKzg|~ ztT4aDyOzh?v{+bRdq3^p`yXXQ1^%eP$D8T8X*X6YI%T$3^~67ILrH(Get4L8V?H~Y zS7!0sj8cK2=5Q_;0(eq#SEbX$HV|+vnml^}sT~%{ZJuL4QW$ZNa*}svx`0L$Kcn)? zjeusZp{6FFU&R2X&%!m`HQW@^Nly`@OEJ&CN3A zjHyz+$PB4(#V*UW*?FV#|JmZ#YZ)S0ccDEsWeu6N``_k{e|25`d)CIEI?JDlQvW=L z{i%2VCK&zsKfmzhI@-+C0_D<%50NfCKUGV74`{LcY>PPcBa-@ARgnjtc}nJ2>JZvw-T^LDn;c-z)O+ z!e!HCVoBE?Q7cG?0T_7&?^q`BbS78378wf)?p`pR$>t z@Qw5WtNO=CfrBivxzriiv%^M*_V3*>EQr0tK^I{X0vs2KI3qZy-vGmYNbHQtF5si~ zBI0MBuDAVXCjRx8n@NIKvLCVW%Po#QO91R0uK4<%FmZ3;e1>vzkZK7p5GP%rfCYlw zxfChNYhG{rCac@n9%)%+A8Zy70O-dvyRdpeq)R9k?5x_a38TXoL!U3j+VygxlNEdkgV7fW5)e!E@RNA>z ziQG4ZiW=X$dXBRyXfX-sj>in`5r2<|+ndPD5*<~z2^ftoLX_$qOQVm7vuahEN5URo z0*xET_!lCb|GMrf8vYse_9KDsBO*lAt;6we@$g4GQhnIFcOxPuYXJdaa$a13igfY> z3$gh$8xXSM#Z4ctl*gGuO^QrGuCfC0InB&d%3R`xD2LZ&Bl>IeP8ldsmOT5Nkp>+U93E%|zBK7GgjwxS+Y>Xpi zTHD*I-Dhlnl->X|UK9f1HvO?Lk7v@688ci@bqb3YP>lW{E&qc%E7gUjD%=)atBGLs zF*ySFzk#@rR?X1I#~U<%y7~WsRr^y@{NMB8e{~i7yFd4*;?~hT(18B~aSL?YOEglK z8u{Si;oHtsHNSygWKNu!vRew!c9N&5-8acmIaOQNEZLejm zgprFfq!6ZO`d>pS5oqs39Y=~cj^(7jK2vxax_2_9|1Y{m< zg|RK{INOLVwy0X7@e8Q3F?&v)<-Jd^7#9oK7-|+IocJZaY9k>%un@R%g^aJ7G+8uz zn^>M!8LxFBj&H_Po?`h~Rs9&^AA*DPvTHF%4D3TWK;f4byl^t=1Qkk?W#q&ajD~PH z8cslz&H_w&bB#5D6F=S9#Xew_a}H+6PN%p4Oy zrWLN}-Hlkf5Ep>%B?p0aUt8M+6fZpxcxorvSbpcvc-8t((92rbAEER4LGg0O9tpT@ zd{O7VLPY@j8;45gX~9vq=~L494)|=a_-e6&yLj?OU+aB?WS&4X{kGPSkaFA@H1~ty z4J@XnJ$<(yaLwxKYSUh1F>QomSGw}<%avzgzt`vA<`aJH9C!NX=C@BS8JMy0OJ9)> z)CA0jrnB>%ZmOx-f!*$clt}JE zzEHi2b~S}O&1?hMN=)DjSexiIuO7}frSXwx0&M!lC$#WHGfW|uE`-uG)Zg@eXMa^x zypcHS0#*#S{^j=ugGblD1%rAw)2X7QKGOvtX<(a;O-q9T=dTJIFeXlxJ_W>Sz=GbD zsT9zv=I`L4%%`CDSER;$p5=e0gmVT*C}NBFTX7sGH?bT(e}{pox@~twHysV#Xg4h> z0a83i^Aqw62On3#A6yYXM0K~_E0lu;h~_|e_~Y2j+{xlEyP*K0P-W&@ko+vzDk6nE zudAo0*M7?-puK2pxWK@Rag^YO2MlK#j1&jD=0G!$C1_D7Fe(}b&9n(te(s|=U^yp0SJ5N?jhiG#*qbgF3yNJ~_T zH5tgOng`4H`gpvnHOHX`b@y%y0vS8>t*RO@Mb22At@N1jBJ5HGR70bj2W!8A?IU2a z3%$!9mQiTNE}+pJxR%F1t$(hI5kgRYRK`q|Sfe&UHxU)|YhPevmIo)}yY9a+m8b^p zxShvSBp&_{(5AB_uT@N8xARG~%j3xH@|1ZY!}33%i; zYFsAtSa#Iu=JDsfVuZw z56VA$05msb-{e+wNFNZEuOA0Qz1-$7FIXUMQYSox01z;@PtmB6RAm#?Y_*0xC4-)O3K-6088=~*;B*% z%lX4P@wN!4H2fiL#O&OomukBmL4yTp_8$?YAV>c{srWzOR>!AY5!qHAM#rPLQp`6- z5mFOeP?l+Q`18EMKmW$RO4R(jKli67o3r}=oco-y2Ts%fX_z>wcZpjP*3~mXEGCQy zC^z{5?-u|iRKUa$t*;be5}YR%wi>p$R%!x z^iidEFJR|E@C|A93H1Q}VBj<}E_ffi15C&vz;px(hx^y8r6G1(^xXtW?1MDr1~m%{ z;4c(0X9xcgKPk%c zpZsJ@dm*S;_x$%(fvdt!)EI2!V%ic=wWX{CrYT73w3mNRdjOe_Bwg^2tO~Xf_jK+X z90Oy`v=9A@9LLp<%!nw5wanwa1O>bEScBx8eolM>QMZBJnbv|<%Hkt|L`?%5R)D1W z39Q#C-(L&PZ777(9vT8W#H{WPXd!VH=FiP^41jjTswNs_ywbmWcE{Nl=V{i*zNExOKTzDTIKvLvzZLQj3{%Pw zDp^jt*l&#&^~Psyd~-ZT0wzOl2Ux4fjN5z6ZOk|?WxIyL$9LUPjpSJj8bqhuZ#G4% z;uRKg6JFaVL6RvI9^MIL6Pci~0h2>%cBS7}$EEH%{6DjteGJ=idnN zA%zMyh9w-X#EL0xpc$bYyg_RaAiK9tD~YothWP~L24gjufZVrd zz!^CDXgjx(+y0o$4E^?BZaxjZ|Md(4LaJ`yqpmdEH#J~R2(q^?em&U{H0ay6r%mn^ z##qDXWx!_%+5j(HcWf<^A;A{-eDRZ2-5+I7E)rrb8*Yj>Y)K;z%EZmGh+2!!exgA8 zHD7{3XEytG3h}_T2@%X4*K$ZU2s$&vJK!L0DDLkcbn!Mr+7SI;};N^&vT%pjAalP6Sl7=Jgf#_-v!u*!M&2}tad9p zynDhptb+E|trE5s^Jq^&@|@y>uNfi5J4}@cbslW6Gj5=Ba6Y>iluVYupa6DbNEzG= zF^8@dg>R&O_64n)3zzbYDgp*Rqqt4FO$tHnOM4^4ovc)IKjSd7RR=7jD$Oho74)Rk z{9HKW^vQ_!(ER*CCmFZ44&BWXi>l?BBp%COEl!f9q3YzGn} zV*K##uFil0(6l|@+FGI#1c7rR#Djw2Ee3kTD9Y>vXiM0N>1+({TU{tz$~u>hBv zgRaa5 zW^K*DL!DgE6TPs&+~{sqOLw@$T-2p2G7+<6K?g15-tu{tFGi2OGUaU#0<9``nh8mA zE;>`v?bMq%9JB)RfovfgD<#{g^RfkJ;lH;>*uF^p(xPh}xY!233fN?!cb^?NVo(O# zCz)V;yG8WoR-bvXKQKjTM4hkk?;b5OuK^p$853}L3$Txe@e9!RI=x8_Gbyra0H%%x zd@yJVyR6iZ%K3kqIrFHb(>0Dy&FzehrB=6XN*Obo8b`h6m??=#me*TqS!!BJi(2M3 z?vo}sVOg4Ki%VV$6${0M6iq>aa?2g5ToTs|m&6r8K-Bw?o!gmnnsaXd-G4d!^V{C{ zd7tO=`37&9aG}{&L&!%b#EVFUTM&|V0UX)xF=Sky^1_J-!8ke65oA zdJ{&k9WA9yb#V0%=u-OZH40PG1E*D=Ugmke*ix4z@@ZznYNBK&z{*Byxa0DqAGjAm zqlQNadS(8PGXafIK^Kz~K!K)*HW?RJrAt1&bjmIBsrnFsBAoUN_oWRGAPz^>h1Ja4 z7(z)tiSqPm*kECoXFJlRnD0^?+O%f%2gZD-zUJYY31<8vYIZn$@d~+h<%Mc3j-;#ulR0lV0lej^2F)XNpo-(E)q0 z2NZ?tOaIV=Lp_*(Q9e|mp5-%EX}vGKsWQ$K8Pan#xnmge6|q$IYe#BmFmkkE1Vac6 zWkbbDD?ml{g+%w5C4Mab_KOiFMZZC&;!h*wxq(k3|z=C(E z^l=D87&V&?-3MM>`1*1BT|Cfg^CcyJ2VZ1gE`I0>hkgQr{nsS zD^pDTp~s|&@`4bXpaw#B07YqUcDJ4ZS<}0#NGQZslI`+;@28P?e$Qt?Mp~j^>x)yb z9Zm$(H3Fy-Q?lQ@D$=&bI+Yo=S)79|KA>fyBPDNgT$nyZf3$u>`LpV}pVQw(ZNPvyLq2P8n=~8RC zA4pgh=8-BD_jJo&(+>{7?A0|~1hUfx9mi*ZZ$Aj=kIKPT0FBqT`x)^PuPUH<_-HX~ zduJQP+4o3nY@bL=K-GiJ*r`%iiL>Ep+d^|N6>nL;G?{-@20v@r?M6kmK+Wn{eeOIF z02$d}m_}g_l(eIn1970bs^>Hwuwls=UziLS=zK@P^Yh}iK3DP&r;I!5-d#%sGtadv zlOmdkKER!lNT>&l){&a&?<$%>@5Sl~M>k>+GtX5SVD4gq>WtJQp+mVorw#7$NlayZ6cRx>eAMRN01ocy}{Q?;oyL z2pFu%)@ORZNwZcs`?(}H$oX$czDB_)OLco>JOSmOW?U=xC@ufhHMDGz*JuRyQ)kV_ zcA(7VCUNY|9%#*i69E9WXp)6F#X1`Rq&?NfB;C4+oRYx$4Of>9BB1*f{Sug}f@Z}8 zd&pf_51AY-x|2k$IHk4d77O{MdpqsP164txKQmaH)Re40R|cC4=T}dA5Vl~nIOc?y zZ< zyT4qA1j#7az3%7C&Hq`arxFTKQ*ZbpQ3cJ*oOZx;YDZ!QfsnY6bTc;A+R~~uSGG*m zl@R_uA~2r)6FZr8aYVJyP$8m7;}K}~i0 z-++vI-*PT|%!DO5o{tiwjfv2qn!0kl5nPC+BcIb5a* z&DK`3?zVTLL1tc>4y%uER%seOne7n0LHpH6q&=9q+fh1u!h9NtTT}y15Vg6_V%3n6 zk)$5RP@)Swjlun5i1>aCedciE`vIb<#50)Xi~y_yjU-3?WA$Ivpw=FN_I z{?+-Ukl#fKSTJ!o)fwBip+^T}bL{drp@-ivTfsEPfn=y>p_=X{85JgVo6OcnfYoLy zoAo@O5o0Cw7aiASgt40#;4lnt6myD8lx)ea!S0sy4xIu};Ga?_$Ngn2EYWOMVcmrcJmLn}!5 z8Z0XQ)@H*X*?Wo)zgvG-!Rfa9;K8mi?jvSI+wV+L@xS$=xpCDUBSXc7pXc2|xX*sl zUATO(UB5Hw=QRlQ#oi~9C?e}*QQ+m*8XrdBG7~Jmo9bS(FDm{(6YwaH05rJ&rU;@0 zXrR@CEAZs;1T>Cr-Mp#elv(?ZkQDcDZ#Y5mfgx^cl0%>XB?zT8eD^aCN1#S_Y&SHW ztZI<-CKq6iEKZR$vpqcE8NZ+JCj=U&+llf-Uqt5VK4hzgCj{&Q4}=3)c2Hm$LQViZ zA|Brf7rkOkV~%46*7js|5yh7|E#v>XX#rQtQBxLw>5vMC;cN0W%>PvqHAx4PkdnB^ zy-U6U(Tlr{Q&~>9w?uJi2PpYFjy#|RaYaQ%GoV}X>pS2}*eP9s4dijmX6`_YMpVik z?UdV_OwP*J|Aqvn^sW!+K?4I7Z%L_>HDQ$@+es&KQaiv~j!Dd|4O0hz&lx6`F%%Zd zqoEC8Y!__LTTXQ}?-&+r2^dqQ3Z?WiHD&dE!4s>e{0gk%vf3B%9B4#nJCmz!zAU~7 zD=_~L;a^(-15j~=+N(r=B?8) zUF1XB+Ki%XxV{W_{1*WVE2BD8()99ivk^725H7R-Kx`sbLEB_rX>xg=lB>qP9& ug7}lK<0HOmDEXIv{(qw^`q*QO-!wk&(ulUTqQNcs#`2)Gc|Q8g)&Bq*4JUm7 literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/probability_maps/xxh64.csv b/hash_testing/new_testing/probability_maps/xxh64.csv new file mode 100644 index 0000000..2f24aaf --- /dev/null +++ b/hash_testing/new_testing/probability_maps/xxh64.csv @@ -0,0 +1,8 @@ +operation,pairs,bit_0,bit_1,bit_2,bit_3,bit_4,bit_5,bit_6,bit_7,bit_8,bit_9,bit_10,bit_11,bit_12,bit_13,bit_14,bit_15,bit_16,bit_17,bit_18,bit_19,bit_20,bit_21,bit_22,bit_23,bit_24,bit_25,bit_26,bit_27,bit_28,bit_29,bit_30,bit_31,bit_32,bit_33,bit_34,bit_35,bit_36,bit_37,bit_38,bit_39,bit_40,bit_41,bit_42,bit_43,bit_44,bit_45,bit_46,bit_47,bit_48,bit_49,bit_50,bit_51,bit_52,bit_53,bit_54,bit_55,bit_56,bit_57,bit_58,bit_59,bit_60,bit_61,bit_62,bit_63 +replace,1984,0.491431,0.497984,0.532258,0.504536,0.494456,0.519657,0.516129,0.493448,0.501008,0.519657,0.490423,0.495968,0.516129,0.498488,0.491935,0.509073,0.520665,0.487903,0.497984,0.487903,0.502016,0.504536,0.502520,0.510081,0.512097,0.492440,0.505544,0.492944,0.491431,0.500000,0.509577,0.511593,0.491431,0.485383,0.481351,0.493448,0.498992,0.498992,0.499496,0.504032,0.495968,0.483367,0.495464,0.498488,0.512097,0.489415,0.502520,0.496472,0.501008,0.495464,0.503528,0.507056,0.510081,0.504032,0.487399,0.523690,0.511089,0.472278,0.496976,0.501008,0.503528,0.504032,0.494456,0.491935 +delete,31,0.548387,0.516129,0.451613,0.580645,0.548387,0.483871,0.548387,0.387097,0.451613,0.451613,0.451613,0.387097,0.677419,0.419355,0.354839,0.612903,0.387097,0.419355,0.548387,0.645161,0.451613,0.548387,0.451613,0.322581,0.516129,0.483871,0.516129,0.387097,0.483871,0.483871,0.483871,0.451613,0.483871,0.516129,0.645161,0.483871,0.580645,0.612903,0.677419,0.516129,0.516129,0.516129,0.516129,0.516129,0.677419,0.419355,0.516129,0.612903,0.612903,0.451613,0.483871,0.419355,0.516129,0.419355,0.580645,0.483871,0.645161,0.419355,0.419355,0.677419,0.451613,0.483871,0.419355,0.516129 +add,2173,0.506213,0.502531,0.484584,0.506213,0.505292,0.469397,0.497929,0.499310,0.487345,0.516797,0.502071,0.504832,0.515416,0.498389,0.486884,0.492867,0.505752,0.484123,0.513116,0.503451,0.508974,0.494248,0.501150,0.509894,0.485964,0.482743,0.490106,0.501150,0.487345,0.491486,0.515416,0.502071,0.497009,0.480902,0.499310,0.510815,0.509894,0.499310,0.511735,0.510354,0.498389,0.485504,0.497009,0.511275,0.504832,0.490566,0.495628,0.495628,0.498850,0.497009,0.485504,0.498850,0.506673,0.488265,0.492407,0.509434,0.495168,0.489185,0.500230,0.489646,0.498850,0.493327,0.493327,0.504832 +swap,28,0.535714,0.607143,0.428571,0.321429,0.535714,0.464286,0.500000,0.357143,0.464286,0.500000,0.464286,0.607143,0.535714,0.357143,0.607143,0.321429,0.428571,0.571429,0.464286,0.357143,0.357143,0.464286,0.464286,0.607143,0.500000,0.642857,0.642857,0.535714,0.428571,0.464286,0.535714,0.535714,0.285714,0.607143,0.500000,0.571429,0.428571,0.642857,0.500000,0.607143,0.571429,0.392857,0.500000,0.535714,0.535714,0.392857,0.571429,0.285714,0.642857,0.500000,0.535714,0.321429,0.428571,0.428571,0.464286,0.678571,0.642857,0.571429,0.607143,0.535714,0.535714,0.571429,0.285714,0.357143 +case,29,0.448276,0.551724,0.586207,0.620690,0.482759,0.655172,0.655172,0.586207,0.517241,0.379310,0.551724,0.448276,0.482759,0.482759,0.586207,0.448276,0.517241,0.448276,0.448276,0.517241,0.551724,0.620690,0.655172,0.655172,0.551724,0.586207,0.655172,0.586207,0.482759,0.379310,0.586207,0.517241,0.517241,0.551724,0.517241,0.655172,0.413793,0.551724,0.551724,0.448276,0.517241,0.379310,0.517241,0.517241,0.586207,0.310345,0.620690,0.379310,0.413793,0.448276,0.586207,0.689655,0.482759,0.310345,0.551724,0.413793,0.448276,0.517241,0.586207,0.551724,0.517241,0.448276,0.448276,0.448276 +first,186,0.521505,0.456989,0.543011,0.516129,0.505376,0.494624,0.569892,0.516129,0.564516,0.500000,0.500000,0.500000,0.516129,0.446237,0.580645,0.532258,0.521505,0.521505,0.473118,0.462366,0.462366,0.473118,0.526882,0.500000,0.500000,0.516129,0.532258,0.532258,0.489247,0.559140,0.462366,0.564516,0.521505,0.467742,0.456989,0.516129,0.537634,0.483871,0.548387,0.500000,0.532258,0.516129,0.478495,0.478495,0.462366,0.483871,0.494624,0.526882,0.537634,0.478495,0.446237,0.473118,0.478495,0.564516,0.435484,0.467742,0.526882,0.494624,0.494624,0.494624,0.543011,0.478495,0.430108,0.494624 +last,186,0.526882,0.446237,0.526882,0.521505,0.494624,0.521505,0.521505,0.483871,0.516129,0.500000,0.478495,0.500000,0.564516,0.500000,0.381720,0.500000,0.537634,0.473118,0.532258,0.543011,0.505376,0.510753,0.483871,0.456989,0.564516,0.489247,0.596774,0.526882,0.510753,0.462366,0.494624,0.494624,0.408602,0.548387,0.505376,0.543011,0.494624,0.467742,0.462366,0.440860,0.548387,0.505376,0.516129,0.510753,0.543011,0.462366,0.478495,0.505376,0.478495,0.532258,0.510753,0.586022,0.526882,0.478495,0.467742,0.516129,0.543011,0.478495,0.510753,0.478495,0.494624,0.505376,0.548387,0.478495 diff --git a/hash_testing/new_testing/probability_maps/xxh64_bits.png b/hash_testing/new_testing/probability_maps/xxh64_bits.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d10f6e119532fefc0d6ee9b053b3a395031306 GIT binary patch literal 35711 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 Qk>8P(Ryvy^b@l%L0jYx(^#A|> literal 0 HcmV?d00001 diff --git a/hash_testing/new_testing/probability_maps/xxh64_deviation.png b/hash_testing/new_testing/probability_maps/xxh64_deviation.png new file mode 100644 index 0000000000000000000000000000000000000000..f3c969abfc669a38df020a53105eccdf3050fef8 GIT binary patch literal 24576 zcmc$`cUY6_wk?jjT%ahRsHiki5d{Gi0g;j=3Me252uN2HkluTV3W$h+NE2yFl^Uc4 z2oMF4PNbKRL~3Xuv?PSI`)2LE@A*CF?tRXBp5M9q{_`mq^R;)*Ip!E+zR~yev<~h+ zxu1iB*AxDN=IDaMb8QwlW za5Girw!xuYhmIU7KYHj!MX<(7Q))12BAD3p{Mqi)r!?~KXdO9nbeH2mu>P)hl-8Xe z@_%q~?cY&>sIBy6q+ygCc$8T^X=(4Pw|c;-zC!d%CBdJ3T)Y0=hu_q}dH*~x4^7|S z-9KD@t=Segi>Z`qFb38 zz3}dovaxC6l9>lm)nYi<2m0cWD4wolE<1rZo6)Vod36C;}W=?U9yaEW&acj zojFjTv6*XYYwK7464uPD9js4vu(Q+9521fT^tnJQm+WA{gfbCcRkC_HBbM>qABWn0 z^2_0|gsydiOWO`fkXO>A+OqzNbh@GvW2n}cw|q-$WO6>q+rBR=G5cM1$d*0hCU5_- zXMb>2aHpkNWCc#eDqLg