add t1ha2 hash and test results
This commit is contained in:
BIN
Binary file not shown.
@@ -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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <leo@yuriev.ru>,
|
||||
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.
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
|
||||
* Fast Positive Hash.
|
||||
*
|
||||
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
|
||||
* 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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
|
||||
* Fast Positive Hash.
|
||||
*
|
||||
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
|
||||
* 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 */
|
||||
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Positive Technologies, https://www.ptsecurity.com,
|
||||
* Fast Positive Hash.
|
||||
*
|
||||
* Portions Copyright (c) 2010-2020 Leonid Yuriev <leo@yuriev.ru>,
|
||||
* 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 <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#else
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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(<endian.h>)
|
||||
#include <endian.h>
|
||||
#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) || \
|
||||
defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
|
||||
#include <machine/endian.h>
|
||||
#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
|
||||
#include <sys/isa_defs.h>
|
||||
#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) || \
|
||||
(__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
|
||||
#include <sys/endian.h>
|
||||
#include <sys/types.h>
|
||||
#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
|
||||
defined(__NETBSD__) || defined(__NetBSD__) || \
|
||||
defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
|
||||
#include <sys/param.h>
|
||||
#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) */
|
||||
@@ -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]+)")
|
||||
|
||||
@@ -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
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -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
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -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
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -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()
|
||||
Reference in New Issue
Block a user