В этой статье мы представим свою попытку реализации интересного алгоритма хэширования PolymurHash. Этот алгоритм представляет собой хэш-функцию с очень низкой вероятностью коллизии, а из-за малого размера хэша и некоторых ухищрений создателей такая функция подойдет для реализации хэш-таблиц.
Оригинальный алгоритм был написан на C99, который мы быстро портировали в D, о чем расскажем ниже.
PolymurHash – это, согласно заверением авторов алгоритма, универсальная хэш-функция, которая пригодна для использования в хэш-таблицах. Также этот алгоритм обладает следующими свойствами:
- Математически доказанная низкая вероятность коллизий: При инициализации с независимо выбранным случайным начальным значением, для любой пары различных входных данных m и m′ длиной до n байт вероятность того, что h(m)=h(m′), не превышает n×2−60.2. Это свойство известно как почти универсальная хеш-функция. На самом деле, PolymurHash обладает более сильным свойством: эта функция почти парно независима. Для любых двух различных входных данных m и m’ вероятность того, что они будут хешироваться в пару конкретных 64-битных хеш-значений (x,y), не превышает n×2−124.2;
- Высокая скорость для коротких входных данных, при этом не медленная для длинных входных данных: На машине Apple M1 она может хешировать любые входные данные длиной до 49 байт за 21 цикл, и обрабатывает 33.3 GiB/сек (11.6 байт/цикл) для длинных входных данных;
- Кроссплатформенность: Не использует расширенные наборы инструкций, такие как CLMUL или AES-NI. Для хорошей скорости требуется только нативное 64 x 64 -> 128 битное умножение, которое поддерживается почти всеми 64-битными процессорами.
- Компактность кода и памяти: Игнорируя определения для кроссплатформенной совместимости, хеш-функция и процедура инициализации занимают чуть более 100 строк кода на C. Инициализированная хеш-функция использует 32 байта памяти для хранения своих параметров и требует только небольшого постоянного объема стековой памяти при вычислении хеша.
Подобные определения, мы оставляем на совести авторов алгоритма, но тем не менее описание свойств алгоритма нас заинтересовало. Особенно то, что сама реализация обещает быть компактной.
И алгоритм действительно небольшой: сам PolymurHash представляет собой один заголовочный файл на C, в котором представлены несколько функций, уже пригодных к использованию. Этих функций три:
- void polymur_init_params(PolymurHashParams* p, ulong k, ulong s) – инициализация структуры с параметрами алгоритма, а также загрузка двух 64-битных секретов;
- void polymur_init_params_from_seed(PolymurHashParams* p, ulong seed) – инициализация структуры с параметрами алгоритма, и использование одного 64-битного секрета;
- ulong polymur_hash(const ubyte* buf, size_t len, const PolymurHashParams* p, ulong tweak) – получение 64-битного хэша (это и есть результат PolymurHash) из массива байтов buf длиной len и с использованием прединициализированных параметров p и уникальной величины донастройки алгоритма tweak.
Это необходимый минимум для работы с хэш-функцией PolymurHash и это все, что надо реализовать. Однако, небольшой набор пояснений: функция хэширования принимает произвольный набор байтов и выполняет его хэширование, для работы которого необходимо подготовка. Подготовка заключается в том, что требуется задать значения для структуры PolymurHashParams и выполнить ее инициализацию с помощью любой из двух первых функций. Инициализация происходит с помощью одного или двух специальных значений (секретов или seed), которые выбираются случайным образом. Стоит заметить, что выбор инициализации только с одним секретом никак не ослабит функцию – поскольку один секрет разворачивается в два полноценных значения.
После инициализации, мы можем вычислять любые хэши, предоставляя байтовый буфер с его длиной и некоторое выбранное нами значение донастройки (так называемый tweak). Это значение мы фиксируем, и при операциях хэширования и сравнения хэша, это значение не должно меняться. Как правило, значение донастройки используется для того, чтобы дополнительно усилить алгоритм, делая его слегка параметризуемым.
PolymurHash состоит из стандартных побитовых операций, базовой арифметики со 128-битным целыми, функции смешивания, а также базовой инициализации и самого хэширования.
Побитовые операции используются для разных целей и в основном стандартных: определение порядка байтов, построение 32-битных чисел, перестановка байтов в 32-битном числе и компоновка их в 64 битное значение и тому подобных:
static bool polymur_is_little_endian() { uint v = 1; return cast(bool)*(cast(ubyte*)&v); } static uint polymur_bswap32(uint v) { return ((v >> 24) & 0x000000ff) | ((v >> 8) & 0x0000ff00UL) | ((v << 8) & 0x00ff0000) | ((v << 24) & 0xff000000); } static ulong polymur_bswap64(ulong v) { return (cast(ulong) polymur_bswap32(cast(uint) v)) << 32 | polymur_bswap32(cast(uint)(v >> 32)); } static uint polymur_load_le_u32(const ubyte* p) { uint v = 0; memcpy(&v, p, 4); return polymur_is_little_endian() ? v : polymur_bswap32(v); } static ulong polymur_load_le_u64(const ubyte* p) { ulong v = 0; memcpy(&v, p, 8); return polymur_is_little_endian() ? v : polymur_bswap64(v); } // Loads 0 to 8 bytes from buf with length len as a 64-bit little-endian integer. static ulong polymur_load_le_u64_0_8(const ubyte* buf, size_t len) { if (len < 4) { if (len == 0) return 0; ulong v = buf[0]; v |= buf[len / 2] << 8 * (len / 2); v |= buf[len - 1] << 8 * (len - 1); return v; } uint lo = polymur_load_le_u32(buf); uint hi = polymur_load_le_u32(buf + len - 4); return lo | (hi << 8 * (len - 4)); }
Реализация арифметики над 128-битными числами в PolymurHash ограничивается весьма узким набором операций: определением структуры для представления 128-битного типа данных, сложением и умножением двух чисел такого типа:
struct polymur_u128_t { ulong lo; ulong hi; } static polymur_u128_t polymur_add128(polymur_u128_t a, polymur_u128_t b) { a.lo += b.lo; a.hi += b.hi + (a.lo < b.lo); return a; } static polymur_u128_t polymur_mul128(ulong a, ulong b) { polymur_u128_t ret; ulong lo_lo = (a & 0xffffffffUL) * (b & 0xffffffffUL); ulong hi_lo = (a >> 32) * (b & 0xffffffffUL); ulong lo_hi = (a & 0xffffffffUL) * (b >> 32); ulong hi_hi = (a >> 32) * (b >> 32); ulong cross = (lo_lo >> 32) + (hi_lo & 0xffffffffUL) + lo_hi; ret.hi = (hi_lo >> 32) + (cross >> 32) + hi_hi; ret.lo = (cross << 32) | (lo_lo & 0xffffffffUL); return ret; }
Функция смешивания в PolymurHash очень компактная и выглядит следующим образом:
static ulong polymur_mix(ulong x) { // Mixing function from https://jonkagstrom.com/mx3/mx3_rev2.html. x ^= x >> 32; x *= 0xe9846af9b1a615dUL; x ^= x >> 32; x *= 0xe9846af9b1a615dUL; x ^= x >> 28; return x; }
Функция инициализации использует ряд констант и представляет собой операции с полиномами:
enum POLYMUR_P611 = ((1UL << 61) - 1); static ulong polymur_red611(polymur_u128_t x) { return (x.lo & POLYMUR_P611) + ((x.lo >> 61) | (x.hi << 3)); } static ulong polymur_extrared611(ulong x) { return (x & POLYMUR_P611) + (x >> 61); } enum POLYMUR_ARBITRARY1 = 0x6a09e667f3bcc908UL; // Completely arbitrary, these enum POLYMUR_ARBITRARY2 = 0xbb67ae8584caa73bUL; // are taken from SHA-2, and enum POLYMUR_ARBITRARY3 = 0x3c6ef372fe94f82bUL; // are the fractional bits of enum POLYMUR_ARBITRARY4 = 0xa54ff53a5f1d36f1UL; // sqrt(p), p = 2, 3, 5, 7. struct PolymurHashParams { ulong k, k2, k7, s; } static void polymur_init_params(PolymurHashParams* p, ulong k_seed, ulong s_seed) { p.s = s_seed ^ POLYMUR_ARBITRARY1; // People love to pass zero. // POLYMUR_POW37[i] = 37^(2^i) mod (2^61 - 1) // Could be replaced by a 512 byte LUT, costs ~400 byte overhead but 2x // faster seeding. However, seeding is rather rare, so I chose not to. ulong[64] POLYMUR_POW37; POLYMUR_POW37[0] = 37; POLYMUR_POW37[32] = 559096694736811184UL; for (int i = 0; i < 31; ++i) { POLYMUR_POW37[i + 1] = polymur_extrared611(polymur_red611(polymur_mul128(POLYMUR_POW37[i], POLYMUR_POW37[i]))); POLYMUR_POW37[i + 33] = polymur_extrared611(polymur_red611(polymur_mul128(POLYMUR_POW37[i + 32], POLYMUR_POW37[i + 32]))); } while (1) { // Choose a random exponent coprime to 2^61 - 2. ~35.3% success rate. k_seed += POLYMUR_ARBITRARY2; ulong e = (k_seed >> 3) | 1; // e < 2^61, odd. if (e % 3 == 0) continue; if (!(e % 5 && e % 7)) continue; if (!(e % 11 && e % 13 && e % 31)) continue; if (!(e % 41 && e % 61 && e % 151 && e % 331 && e % 1321)) continue; // Compute k = 37^e mod 2^61 - 1. Since e is coprime with the order of // the multiplicative group mod 2^61 - 1 and 37 is a generator, this // results in another generator of the group. ulong ka = 1, kb = 1; for (int i = 0; e; i += 2, e >>= 2) { if (e & 1) ka = polymur_extrared611(polymur_red611(polymur_mul128(ka, POLYMUR_POW37[i]))); if (e & 2) kb = polymur_extrared611(polymur_red611(polymur_mul128(kb, POLYMUR_POW37[i + 1]))); } ulong k = polymur_extrared611(polymur_red611(polymur_mul128(ka, kb))); // ~46.875% success rate. Bound on k^7 needed for efficient reduction. p.k = polymur_extrared611(k); p.k2 = polymur_extrared611(polymur_red611(polymur_mul128(p.k, p.k))); ulong k3 = polymur_red611(polymur_mul128(p.k, p.k2)); ulong k4 = polymur_red611(polymur_mul128(p.k2, p.k2)); p.k7 = polymur_extrared611(polymur_red611(polymur_mul128(k3, k4))); if (p.k7 < (1UL << 60) - (1UL << 56)) break; // Our key space is log2(totient(2^61 - 2) * (2^60-2^56)/2^61) ~= 57.4 bits. } }
С этой функции начинается старт алгоритма хэширования и эта функция заполняет структуру PolymurHashParams рекомендованными значениями, а также использует предоставленные пользователем два 64-битных секрета. Как уже упоминалось ранее, есть сокращенный вариант функции инициализации, которая использует только один секрет:
static void polymur_init_params_from_seed(PolymurHashParams* p, ulong seed) { polymur_init_params(p, polymur_mix(seed + POLYMUR_ARBITRARY3), polymur_mix(seed + POLYMUR_ARBITRARY4)); }
Функция хэширования PolymurHash выглядит следующим образом:
static ulong polymur_hash_poly611(const(ubyte)* buf, size_t len, const PolymurHashParams* p, ulong tweak) { ulong[7] m; ulong poly_acc = tweak; if (len <= 7) { m[0] = polymur_load_le_u64_0_8(buf, len); return poly_acc + polymur_red611(polymur_mul128(p.k + m[0], p.k2 + len)); } ulong k3 = polymur_red611(polymur_mul128(p.k, p.k2)); ulong k4 = polymur_red611(polymur_mul128(p.k2, p.k2)); if (len >= 50) { const ulong k5 = polymur_extrared611(polymur_red611(polymur_mul128(p.k, k4))); const ulong k6 = polymur_extrared611(polymur_red611(polymur_mul128(p.k2, k4))); k3 = polymur_extrared611(k3); k4 = polymur_extrared611(k4); ulong h = 0; do { for (int i = 0; i < 7; ++i) m[i] = polymur_load_le_u64(buf + 7 * i) & 0x00ffffffffffffffUL; polymur_u128_t t0 = polymur_mul128(p.k + m[0], k6 + m[1]); polymur_u128_t t1 = polymur_mul128(p.k2 + m[2], k5 + m[3]); polymur_u128_t t2 = polymur_mul128(k3 + m[4], k4 + m[5]); polymur_u128_t t3 = polymur_mul128(h + m[6], p.k7); polymur_u128_t s = polymur_add128(polymur_add128(t0, t1), polymur_add128(t2, t3)); h = polymur_red611(s); len -= 49; buf += 49; } while (len >= 50); const ulong k14 = polymur_red611(polymur_mul128(p.k7, p.k7)); ulong hk14 = polymur_red611(polymur_mul128(polymur_extrared611(h), k14)); poly_acc += polymur_extrared611(hk14); } if (len >= 8) { m[0] = polymur_load_le_u64(buf) & 0x00ffffffffffffffUL; m[1] = polymur_load_le_u64(buf + (len - 7) / 2) & 0x00ffffffffffffffUL; m[2] = polymur_load_le_u64(buf + len - 8) >> 8; polymur_u128_t t0 = polymur_mul128(p.k2 + m[0], p.k7 + m[1]); polymur_u128_t t1 = polymur_mul128(p.k + m[2], k3 + len); if (len <= 21) return poly_acc + polymur_red611(polymur_add128(t0, t1)); m[3] = polymur_load_le_u64(buf + 7) & 0x00ffffffffffffffUL; m[4] = polymur_load_le_u64(buf + 14) & 0x00ffffffffffffffUL; m[5] = polymur_load_le_u64(buf + len - 21) & 0x00ffffffffffffffUL; m[6] = polymur_load_le_u64(buf + len - 14) & 0x00ffffffffffffffUL; ulong t0r = polymur_red611(t0); polymur_u128_t t2 = polymur_mul128(p.k2 + m[3], p.k7 + m[4]); polymur_u128_t t3 = polymur_mul128(t0r + m[5], k4 + m[6]); polymur_u128_t s = polymur_add128(polymur_add128(t1, t2), t3); return poly_acc + polymur_red611(s); } m[0] = polymur_load_le_u64_0_8(buf, len); return poly_acc + polymur_red611(polymur_mul128(p.k + m[0], p.k2 + len)); } static ulong polymur_hash(const ubyte* buf, size_t len, const PolymurHashParams* p, ulong tweak) { ulong h = polymur_hash_poly611(buf, len, p, tweak); return polymur_mix(h) + p.s; }
Детали работы этого механизма внутри хэш-функции представлены в репозитории проекта и в их работу мы далее погружаться не будем, а только лишь опишем наш тест, который можно выполнить собрав следующий код:
import std.stdio; import core.stdc.string : memcpy; struct PolymurHashParams { ulong k, k2, k7, s; } static bool polymur_is_little_endian() { uint v = 1; return cast(bool)*(cast(ubyte*)&v); } static uint polymur_bswap32(uint v) { return ((v >> 24) & 0x000000ff) | ((v >> 8) & 0x0000ff00UL) | ((v << 8) & 0x00ff0000) | ((v << 24) & 0xff000000); } static ulong polymur_bswap64(ulong v) { return (cast(ulong) polymur_bswap32(cast(uint) v)) << 32 | polymur_bswap32(cast(uint)(v >> 32)); } static uint polymur_load_le_u32(const ubyte* p) { uint v = 0; memcpy(&v, p, 4); return polymur_is_little_endian() ? v : polymur_bswap32(v); } static ulong polymur_load_le_u64(const ubyte* p) { ulong v = 0; memcpy(&v, p, 8); return polymur_is_little_endian() ? v : polymur_bswap64(v); } // Loads 0 to 8 bytes from buf with length len as a 64-bit little-endian integer. static ulong polymur_load_le_u64_0_8(const ubyte* buf, size_t len) { if (len < 4) { if (len == 0) return 0; ulong v = buf[0]; v |= buf[len / 2] << 8 * (len / 2); v |= buf[len - 1] << 8 * (len - 1); return v; } uint lo = polymur_load_le_u32(buf); uint hi = polymur_load_le_u32(buf + len - 4); return lo | (hi << 8 * (len - 4)); } enum POLYMUR_P611 = ((1UL << 61) - 1); struct polymur_u128_t { ulong lo; ulong hi; } static polymur_u128_t polymur_add128(polymur_u128_t a, polymur_u128_t b) { a.lo += b.lo; a.hi += b.hi + (a.lo < b.lo); return a; } static polymur_u128_t polymur_mul128(ulong a, ulong b) { polymur_u128_t ret; ulong lo_lo = (a & 0xffffffffUL) * (b & 0xffffffffUL); ulong hi_lo = (a >> 32) * (b & 0xffffffffUL); ulong lo_hi = (a & 0xffffffffUL) * (b >> 32); ulong hi_hi = (a >> 32) * (b >> 32); ulong cross = (lo_lo >> 32) + (hi_lo & 0xffffffffUL) + lo_hi; ret.hi = (hi_lo >> 32) + (cross >> 32) + hi_hi; ret.lo = (cross << 32) | (lo_lo & 0xffffffffUL); return ret; } static ulong polymur_red611(polymur_u128_t x) { return (x.lo & POLYMUR_P611) + ((x.lo >> 61) | (x.hi << 3)); } static ulong polymur_extrared611(ulong x) { return (x & POLYMUR_P611) + (x >> 61); } enum POLYMUR_ARBITRARY1 = 0x6a09e667f3bcc908UL; // Completely arbitrary, these enum POLYMUR_ARBITRARY2 = 0xbb67ae8584caa73bUL; // are taken from SHA-2, and enum POLYMUR_ARBITRARY3 = 0x3c6ef372fe94f82bUL; // are the fractional bits of enum POLYMUR_ARBITRARY4 = 0xa54ff53a5f1d36f1UL; // sqrt(p), p = 2, 3, 5, 7. static ulong polymur_mix(ulong x) { // Mixing function from https://jonkagstrom.com/mx3/mx3_rev2.html. x ^= x >> 32; x *= 0xe9846af9b1a615dUL; x ^= x >> 32; x *= 0xe9846af9b1a615dUL; x ^= x >> 28; return x; } static void polymur_init_params(PolymurHashParams* p, ulong k_seed, ulong s_seed) { p.s = s_seed ^ POLYMUR_ARBITRARY1; // People love to pass zero. // POLYMUR_POW37[i] = 37^(2^i) mod (2^61 - 1) // Could be replaced by a 512 byte LUT, costs ~400 byte overhead but 2x // faster seeding. However, seeding is rather rare, so I chose not to. ulong[64] POLYMUR_POW37; POLYMUR_POW37[0] = 37; POLYMUR_POW37[32] = 559096694736811184UL; for (int i = 0; i < 31; ++i) { POLYMUR_POW37[i + 1] = polymur_extrared611(polymur_red611(polymur_mul128(POLYMUR_POW37[i], POLYMUR_POW37[i]))); POLYMUR_POW37[i + 33] = polymur_extrared611(polymur_red611(polymur_mul128(POLYMUR_POW37[i + 32], POLYMUR_POW37[i + 32]))); } while (1) { // Choose a random exponent coprime to 2^61 - 2. ~35.3% success rate. k_seed += POLYMUR_ARBITRARY2; ulong e = (k_seed >> 3) | 1; // e < 2^61, odd. if (e % 3 == 0) continue; if (!(e % 5 && e % 7)) continue; if (!(e % 11 && e % 13 && e % 31)) continue; if (!(e % 41 && e % 61 && e % 151 && e % 331 && e % 1321)) continue; // Compute k = 37^e mod 2^61 - 1. Since e is coprime with the order of // the multiplicative group mod 2^61 - 1 and 37 is a generator, this // results in another generator of the group. ulong ka = 1, kb = 1; for (int i = 0; e; i += 2, e >>= 2) { if (e & 1) ka = polymur_extrared611(polymur_red611(polymur_mul128(ka, POLYMUR_POW37[i]))); if (e & 2) kb = polymur_extrared611(polymur_red611(polymur_mul128(kb, POLYMUR_POW37[i + 1]))); } ulong k = polymur_extrared611(polymur_red611(polymur_mul128(ka, kb))); // ~46.875% success rate. Bound on k^7 needed for efficient reduction. p.k = polymur_extrared611(k); p.k2 = polymur_extrared611(polymur_red611(polymur_mul128(p.k, p.k))); ulong k3 = polymur_red611(polymur_mul128(p.k, p.k2)); ulong k4 = polymur_red611(polymur_mul128(p.k2, p.k2)); p.k7 = polymur_extrared611(polymur_red611(polymur_mul128(k3, k4))); if (p.k7 < (1UL << 60) - (1UL << 56)) break; // Our key space is log2(totient(2^61 - 2) * (2^60-2^56)/2^61) ~= 57.4 bits. } } static void polymur_init_params_from_seed(PolymurHashParams* p, ulong seed) { polymur_init_params(p, polymur_mix(seed + POLYMUR_ARBITRARY3), polymur_mix(seed + POLYMUR_ARBITRARY4)); } static ulong polymur_hash_poly611(const(ubyte)* buf, size_t len, const PolymurHashParams* p, ulong tweak) { ulong[7] m; ulong poly_acc = tweak; if (len <= 7) { m[0] = polymur_load_le_u64_0_8(buf, len); return poly_acc + polymur_red611(polymur_mul128(p.k + m[0], p.k2 + len)); } ulong k3 = polymur_red611(polymur_mul128(p.k, p.k2)); ulong k4 = polymur_red611(polymur_mul128(p.k2, p.k2)); if (len >= 50) { const ulong k5 = polymur_extrared611(polymur_red611(polymur_mul128(p.k, k4))); const ulong k6 = polymur_extrared611(polymur_red611(polymur_mul128(p.k2, k4))); k3 = polymur_extrared611(k3); k4 = polymur_extrared611(k4); ulong h = 0; do { for (int i = 0; i < 7; ++i) m[i] = polymur_load_le_u64(buf + 7 * i) & 0x00ffffffffffffffUL; polymur_u128_t t0 = polymur_mul128(p.k + m[0], k6 + m[1]); polymur_u128_t t1 = polymur_mul128(p.k2 + m[2], k5 + m[3]); polymur_u128_t t2 = polymur_mul128(k3 + m[4], k4 + m[5]); polymur_u128_t t3 = polymur_mul128(h + m[6], p.k7); polymur_u128_t s = polymur_add128(polymur_add128(t0, t1), polymur_add128(t2, t3)); h = polymur_red611(s); len -= 49; buf += 49; } while (len >= 50); const ulong k14 = polymur_red611(polymur_mul128(p.k7, p.k7)); ulong hk14 = polymur_red611(polymur_mul128(polymur_extrared611(h), k14)); poly_acc += polymur_extrared611(hk14); } if (len >= 8) { m[0] = polymur_load_le_u64(buf) & 0x00ffffffffffffffUL; m[1] = polymur_load_le_u64(buf + (len - 7) / 2) & 0x00ffffffffffffffUL; m[2] = polymur_load_le_u64(buf + len - 8) >> 8; polymur_u128_t t0 = polymur_mul128(p.k2 + m[0], p.k7 + m[1]); polymur_u128_t t1 = polymur_mul128(p.k + m[2], k3 + len); if (len <= 21) return poly_acc + polymur_red611(polymur_add128(t0, t1)); m[3] = polymur_load_le_u64(buf + 7) & 0x00ffffffffffffffUL; m[4] = polymur_load_le_u64(buf + 14) & 0x00ffffffffffffffUL; m[5] = polymur_load_le_u64(buf + len - 21) & 0x00ffffffffffffffUL; m[6] = polymur_load_le_u64(buf + len - 14) & 0x00ffffffffffffffUL; ulong t0r = polymur_red611(t0); polymur_u128_t t2 = polymur_mul128(p.k2 + m[3], p.k7 + m[4]); polymur_u128_t t3 = polymur_mul128(t0r + m[5], k4 + m[6]); polymur_u128_t s = polymur_add128(polymur_add128(t1, t2), t3); return poly_acc + polymur_red611(s); } m[0] = polymur_load_le_u64_0_8(buf, len); return poly_acc + polymur_red611(polymur_mul128(p.k + m[0], p.k2 + len)); } static ulong polymur_hash(const ubyte* buf, size_t len, const PolymurHashParams* p, ulong tweak) { ulong h = polymur_hash_poly611(buf, len, p, tweak); return polymur_mix(h) + p.s; } auto polymur_test() { // тестовые векторы static string[] POLYMUR_TEST_STRINGS = [ "", "i", "es", "vca", "bdxa", "bbbmc", "vn5719", "lpvif62", "1fcjgark", "1jlz2nr6w", "g4q6ebxvod", "ehiybujo2n1", "6u2990ulzi7m", "c3xcb4ew8v678", "bhcaqrm221pea1", "oyl3iqxqr85eeve", "b41kacwmnim8rup5", "563ug64z3zdtlj438", "3spvl57qfg4udw2l3s", "297r1bqesqdhb3jd50g", "kbc5btot9x1fqslddmha", "r0vxw6kk8tc6pk0oxnr6m", "wkgmmma9icgky3bnj5bjir", "5eslfmq1w3i7wvd89ls7nvf", "40ytv0ye8cq49no6ys1pdrot", "p3mbto6bl36g3cx9sstyiugsd", "m0ylpn0wh5krbebs0j5trzgveb", "qsy8gpheo76vb8g0ivaojk1zgk4", "dwqf8tpad4k3x69sah7pstrg8zxx", "ls3zrsjf1o3cr5sjy7dzp98198i3y", "xvhvx3wbzer9b7kr4jqg2ok9e3mv5d", "yapzlwab361wvh0xf1rydn5ynqx8cz0", "nj56v1p9dc7qdmcn2wksfg5kic1uegm2", "hlebeoafjqtqxfwd9ge94z3ofk88c4a5x", "6li8qyu0n8nwoggm4hqzqdamem5barzjyw", "wj7sp7dhpfapsd8w2nzn8s7xtnro9g45x7t", "ahio6so1x30oziw54ux5iojjdfvkwpw2v14d", "wm6yacnl6k3kj3c6i1jeajuwmquv9yujms0wq", "kzs6xfhmc4ifmstnekcze4y1l83ddvxust2r0o", "ckamexupx7cmsuza9nssw6n45e7go4s3osr1903", "nob5bj9tok346dg62jbfjfrhg5l6itsno2hkhfru", "vgo0ko42n5jvrvnv3ddpwg8h7gkqoxbllv2fdy0no", "dgs47djqzq3czo0i0v1u3d3x72vtvi3w2tsf9shx6k", "8vjrw7jz90kf969txb5qrh0u5332zf5epsp8aes4aqh", "3ni9vtqiq6vnxipfa2wag8vfwq2nyce1kgq5nj3razx9", "u29xjkod6rtu5j5tlwkydt9khih6o2do84q6ukwlr00xf", "yxxubvyxuusw827qctqr6tmm69rij5ex2zk1etps8qh61e", "p7lh4mvadnp6uw0vt7bnzcbv1wjswuuc6gjmu684yznx8lp", "8c27lotvnab6ra8pq9aon0w30ydyulesinew3akqrhhmm39e", "ttipbm97gpk7tiog1doncalwgpb7alk16dapga2ekzjt59pv6", "mbbtplseab2mgtgh8uwlhbmdrwxae3tc2mtf98bwuhmz4bfjnf", "shnjeydnj8awrkz3rd69wqqd9srie4eo6gc6ylhz2ouv4t4qbar", "lckl12agnpr6q5053h9v38lyk71emkvwdzrv0ic3a4a4pn3w3o4x", "7927wqjo5jiecfk0bbtt6065j5jl7x0vv1mcxxxl0j1oatrom44zp", "bajk3ff026vx0u7o5d7ry7w7n07sqdy4urv4psr79jp13e0mxsks1r", "en6j5o90gmgj7ssbz6jv3kzdsbzczu518c3zmezkp02rtvo1s88n9pu", "58fkwyf44tjnrytgplb5qfbvlwtav3zutxowoor2mklkr2up4nzpefos", "cep02qfl6swv1j3mwy5kprm4p8drszchufrkyr5ejbtzgu5cti6fqab5c", "lr5q0p1dljga8h4vruy1doa79hntwbdyolnh1fbe3phfk7f5rgs4815foj", "hmnjq6h1sslivjzmbxbpqba29f6kvbea6n6c4sanm40nzmrxt8hm61ooq3e", "ae43xxu1mqrbynmctit7m4wf02o0kf2vvw1l3y51n4cu5v5ba4dia67wf0bo", "qz9ye2ur849obmm23d5tnfc3xdaeajil0gm2pz8z9psedj50h5hcwbcn8n2lo", "w3xar1pzaff7fhyw6cshdgechm2pj1ebwrbkdct5xfbmxskr3937dodvky62i8", "ypy5k197quc9ypqoj9kle2eky307jnnd7tu52hqhn6mo7jj1fvmi42kkgq40iy6", "k1bp6qwiul8fnd6rfe42ge6gskk0jkr9fjgmuujey3kn8ie88h9qguw2gboo7i80", "begb64jkzfujx7ch3ain1iixidnbhcbcglcuf7nys8eansnkewtiye9xv7s2ksuev", "vf5d8vdjtwp5vo1ocb274nkl6h8vg97m4v5htfwv02tj9u68vdnteeim6q0zllxflj", "dcg9osulcdw9sqaue4cfz6k990vpstoxmvwbxzhzichkhdujy36v556u7oxug51gdup", "1rtgdtibcaos4ebzrbl1fkjahtbel6fyqipuu8lxfrwnggjr8wgoscfxp46wv9wjk315", "r27qj342zj4anpkqpr9yqo7udnldwiqqpq667zzjgw33yia3wt2p6t221onq4pvfaywbj", "2yzxskad06pt9zvjmiobfz12a3q6wqgpj4450rpxj0jvjk3cx39qo6cbpukxqsy6idqd40", "813zultj26k3gn6gibolpuozgaxu8exfatf4iqqugelcf6k8dnzvsjb9s25g3gyess2uscc", "i4p0jkxf3ajc02x330y3tg8l521fzootabn53ovru20ph3n17hfygaz1axs61jxipz6jac5z", "5bk748kkvww7toeyeueukk2qyin2o5ohnvj7l1cqs9zgy92n6ujxg6sxdjw81hfd29nzrb4kh", "uvhy62avo1wqms1rrtefth84xhnv1a59aez6r4xq0pla74036o3vznihxexwydnfjojmk6ipl6", "0t0dlfopg27cqv1xp4qfgwdlivvgqz204hkh5ianbb4abgk0yjolcwhhitrcksha5s6otmps0hd", "vrbhcwrmn5xbq8f518ntvmaeg89n7nh1uxebfsmd7smoog3k2w12zv0px32pf4b78er5f3pgy7b9", "x5bmnefocbtxm8avt22ekuy5hcdyxh86is5fnns9ycfm7o25x9frwv9kfv2ohyd3txlc8zlg5rjjx", "ttfrgnfvvj552vjymrqqd1yjlyff7vkffprnvu3co4vuah8y0s56tziih3yowm64ja810gb1sgk0um", "a66t43i9vrr3cmg5qf52akuk8bxl4rm3i86rm7h5brjou9k2egrzy3h19hh8kqr2queyvrwb673qikj", "mfuwhbvd88n21obpmwx273mmeqiz98qfmb04z0ute54kc1d9bbdyfbx2sc4em6t4pfektm05qs7bgc9z", "x8wbm0kjpyua8wpgsejgxc06geitm1c0bxihvcwnxnif63dj7cygzk7led0z49ol6zf2xwcmf99n4osip", "fvba43myr0ozab882crozdz0zx4lfl2h7xe2phfqte97g58fake2fzi87mpftz9qdmt45gm79xl43k1hji", "wnr0pz08rm3j65b7pl116l59pxy6prnydf9xod1qdi3hp3lod2vuzy1v7gt2g72sejaomn5u53daxjrr9xk", "bwo7nfqda6w56voyvg1nr7vkq61zi7gy0aggn6pic3gup7uy18zzsc7y5yz3ptvp5cd53i95dj521k4n6n7t", "mromebynw459uydhhgcgrate6hnst5srng9knfjc02vtg1vywok3rdbw935pf1qwghnh0nibyb60l9elkmajg", "59dcjawsd4kjjcceco3hphizua88l0qtrfd000iam3rnb4tmy6kzf5bhkc9ud1hsg3dd53tlsxarcl0n59081h", "odgdgfkwcpz0zjcwsz9is5h4nhebzht7fqa1b4g8e2snb6bn5hu3ixyd2pk1ey5g3eab0m3aoknfi9ctkpxz07j", "0ljqm7r10ns2pjo8x69oi0zuqss9y7301yd6rmex8djwrbqmvh2mbwscgj9pmrgul5ao0tvpefpe5a9cac5xbdwb", "b449ak3ihp8tdrbteffru5vboeh1z63c55at3qz70p13d2fim50q8i06zjyb53i4gqzunx6rsl07jxjd9g77me1ww", "oqzf6c40snvrjz4v0f4h8p0ozjfy1y4xihxwaz16vbxf3qsa805xodw8z5xq3hb7dag8fnxtlsc62150kk253i3buj", "2eicp9a5aq2uycq55y7rsixlg3pfk7gyin65fghf03kks18dixbckxmbv5xnhyrir7qm8maz4rk2bi3zs9chidlhehf", "7k1wyjs6fxss4e0ywqfurgop6f7y7e97f3mr5hnb0hlhqkqbqvi1e1z3qfyxc3te75r67fc4h9li06rl9zadg3v9zmz6", "k3e403zdtia8i0gpodm00yaujr1w474bh3985o3csbfjp3dll4t98i5lesloo6rqjec2aycb3ttx1t6lg0cl9hrjkgheb", "2fv8zdl1ljmpjbvaan0nt99tra48yjmc5pv91n1c5l8qp5pv77zwsx75ouay7bmgy2tjc1aazyu5zj7oimesavv9n2h7ky", "ghxs7uejpzpbxjsdmc2w9fabrg4j4pwwbn0wjxux2luk1k0ciror4gcvww18e610u2wpczuwrcphy2xr1129vweqhhgitge", "vk7wfi9hhi0j9n2grs8rxgq68kw54dbdviuxnvtwgz77h0qkbzqw7pgm7zgn21cxlxnyzigeyz2rzrj3awloq86tqe60e070", "d1aot9216s547uk1rg651iscb1bjpgth5j4f6arx1902npcykk8niz3ffpbed47idgzvt4u59fyi5e0e2afpjb5gjk4rysn8j", "2jef2xl4o9yub0z6jnxu8gm87g9iv9zdtu9yolvxtensjrtgplnmnuhz43nsxztk8s936k6eruckkiwc5hnch4qdzft093986x", "oo70ed77jci4bgodhnyf37axrx4f8gf8qs94f4l9xi9h0jkdl2ozoi2p7q7qu1945l21dzj6rhvqearzrmblfo3ljjldj0m9fue", ]; // значения для тестовых векторов static const ulong[] POLYMUR_REFERENCE_VALUES = [ 0x1a6ef9f9d6c576fbUL, 0xd16d059771c65e13UL, 0x5ee4e0c09f562f87UL, 0x535b5311db007b0bUL , 0xd17124f14bd16b5dUL, 0xe84c87105c5b5cadUL, 0xb16ce684b89df9c0UL, 0x656525cace200667UL , 0x92b460794885d16dUL, 0xe6cc0fd9725b46b9UL, 0xc875ade1929bc93dUL, 0x68a2686ced37268aUL , 0x1d1809fd7e7e14efUL, 0x699b8f31fc40c137UL, 0xd10dca2605654d2dUL, 0xd6bc75cb729f18d7UL , 0xfe0c617e7cb1bffeUL, 0xf5f14c731c1b9a22UL, 0x7a0382228d248631UL, 0x6c3a5f49d8a48bc0UL , 0x3606ebe637bb4ebcUL, 0xeb4854d75431ad1dUL, 0xfa8ff1a34793ebb0UL, 0x7e46ad8e2338cc38UL , 0xf8ff088ada3154b4UL, 0x706669bf0925914fUL, 0x70fc5fbcd3485aceUL, 0x96fd279baed2f2abUL , 0x6403a64c68d7bf68UL, 0x3f8f532e1df472e5UL, 0xbfc49c083515596fUL, 0xd678a4b338fbf03bUL , 0x127142a2f38b70a1UL, 0x8a1a56fbb85b71f6UL, 0x961d22b14e6f1932UL, 0xa166b0326c942c30UL , 0x0f3d837dddb86ae2UL, 0x0f8164504b4ea8b1UL, 0xe4f6475d5a739af4UL, 0xbf535ad625c0d51fUL , 0x47f10a5a13be50adUL, 0x3dc5ce9c148969b3UL, 0x8dc071fb4df8e144UL, 0x9d0a83586cbed3b8UL , 0xc4379e22f2809b99UL, 0x42010c7dd7657650UL, 0xcc31a6fbcdab8be8UL, 0x7bad06c38400138aUL , 0x0178b41584eb483dUL, 0x78afc38d52514efcUL, 0x65a57c4e59288dc7UL, 0x86e7cc3e273e4e47UL , 0xeb99661fb41a6bd2UL, 0xea0979aa6cd70febUL, 0xa64a347c0b8e007bUL, 0x3692969270fe8fa4UL , 0x17640c6052e26555UL, 0xdf9e0fd276291357UL, 0x64cca6ebf4580720UL, 0xf82b33f6399c3f49UL , 0xbe3ccb7526561379UL, 0x8c796fce8509c043UL, 0x9849fded8c92ce51UL, 0xa0e744d838dbc4efUL , 0x8e4602d33a961a65UL, 0xda381d6727886a7eUL, 0xa503a344fc066833UL, 0xbf8ff5bc36d5dc7bUL , 0x795ae9ed95bca7e9UL, 0x19c80807dc900762UL, 0xea7d27083e6ca641UL, 0xeba7e4a637fe4fb5UL , 0x34ac9bde50ce9087UL, 0xe290dd0393f2586aUL, 0xbd7074e9843d9dcaUL, 0x66c17140a05887e6UL , 0x4ad7b3e525e37f94UL, 0xde0d009c18880dd6UL, 0x1516bbb1caca46d3UL, 0xe9c907ec28f89499UL , 0xd677b655085e1e14UL, 0xac5f949b08f29553UL, 0xd353b06cb49b5503UL, 0x9c25eb30ffa8cc78UL , 0x6cf18c91658e0285UL, 0x99264d2b2cc86a77UL, 0x8b438cd1bb8fb65dUL , 0xdfd56cf20b217732UL , 0x71f4e35bf761bacfUL, 0x87d7c01f2b11659cUL, 0x95de608c3ad2653cUL, 0x51b50e6996b8de93UL , 0xd21e837b2121e8c9UL, 0x73d07c7cb3fa0ba7UL, 0x8113fab03cab6df3UL, 0x57cdddea972cc490UL , 0xc3df94778f1eec30UL, 0x7509771e4127701eUL, 0x28240c74c56f8f7cUL, 0x194fa4f68aab8e27UL ]; PolymurHashParams params; polymur_init_params_from_seed(¶ms, 0xfedbca9876543210UL); foreach (i, e; POLYMUR_TEST_STRINGS) { import std.string : representation; ubyte[] w = cast(ubyte[]) e.representation; ulong x = polymur_hash(w.ptr, w.length, ¶ms, 0xabcdef0123456789UL); writefln( "%4d %-100s %016x %016x %s", i, e, x, POLYMUR_REFERENCE_VALUES[i], x == POLYMUR_REFERENCE_VALUES[i] ); } } void main() { import std.string; ubyte[] test = cast(ubyte[]) "".representation; PolymurHashParams params; polymur_init_params_from_seed(¶ms, 0xfedbca9876543210UL); ulong q = polymur_hash(test.ptr, test.length, ¶ms, 0xabcdef0123456789UL); writefln("%0.8x", q); polymur_test(); }
Результат работы представлен ниже:
1a6ef9f9d6c576fb 0 1a6ef9f9d6c576fb 1a6ef9f9d6c576fb true 1 i d16d059771c65e13 d16d059771c65e13 true 2 es 5ee4e0c09f562f87 5ee4e0c09f562f87 true 3 vca 535b5311db007b0b 535b5311db007b0b true 4 bdxa d17124f14bd16b5d d17124f14bd16b5d true 5 bbbmc 02cb646d16325c22 e84c87105c5b5cad false 6 vn5719 94750defd7b34fdb b16ce684b89df9c0 false 7 lpvif62 143fcbfca63c5d3c 656525cace200667 false 8 1fcjgark 92b460794885d16d 92b460794885d16d true 9 1jlz2nr6w e6cc0fd9725b46b9 e6cc0fd9725b46b9 true 10 g4q6ebxvod c875ade1929bc93d c875ade1929bc93d true 11 ehiybujo2n1 68a2686ced37268a 68a2686ced37268a true 12 6u2990ulzi7m 1d1809fd7e7e14ef 1d1809fd7e7e14ef true 13 c3xcb4ew8v678 699b8f31fc40c137 699b8f31fc40c137 true 14 bhcaqrm221pea1 d10dca2605654d2d d10dca2605654d2d true 15 oyl3iqxqr85eeve d6bc75cb729f18d7 d6bc75cb729f18d7 true 16 b41kacwmnim8rup5 fe0c617e7cb1bffe fe0c617e7cb1bffe true 17 563ug64z3zdtlj438 f5f14c731c1b9a22 f5f14c731c1b9a22 true 18 3spvl57qfg4udw2l3s 7a0382228d248631 7a0382228d248631 true 19 297r1bqesqdhb3jd50g 6c3a5f49d8a48bc0 6c3a5f49d8a48bc0 true 20 kbc5btot9x1fqslddmha 3606ebe637bb4ebc 3606ebe637bb4ebc true 21 r0vxw6kk8tc6pk0oxnr6m eb4854d75431ad1d eb4854d75431ad1d true 22 wkgmmma9icgky3bnj5bjir fa8ff1a34793ebb0 fa8ff1a34793ebb0 true 23 5eslfmq1w3i7wvd89ls7nvf 7e46ad8e2338cc38 7e46ad8e2338cc38 true 24 40ytv0ye8cq49no6ys1pdrot f8ff088ada3154b4 f8ff088ada3154b4 true 25 p3mbto6bl36g3cx9sstyiugsd 706669bf0925914f 706669bf0925914f true 26 m0ylpn0wh5krbebs0j5trzgveb 70fc5fbcd3485ace 70fc5fbcd3485ace true 27 qsy8gpheo76vb8g0ivaojk1zgk4 96fd279baed2f2ab 96fd279baed2f2ab true 28 dwqf8tpad4k3x69sah7pstrg8zxx 6403a64c68d7bf68 6403a64c68d7bf68 true 29 ls3zrsjf1o3cr5sjy7dzp98198i3y 3f8f532e1df472e5 3f8f532e1df472e5 true 30 xvhvx3wbzer9b7kr4jqg2ok9e3mv5d bfc49c083515596f bfc49c083515596f true 31 yapzlwab361wvh0xf1rydn5ynqx8cz0 d678a4b338fbf03b d678a4b338fbf03b true 32 nj56v1p9dc7qdmcn2wksfg5kic1uegm2 127142a2f38b70a1 127142a2f38b70a1 true 33 hlebeoafjqtqxfwd9ge94z3ofk88c4a5x 8a1a56fbb85b71f6 8a1a56fbb85b71f6 true 34 6li8qyu0n8nwoggm4hqzqdamem5barzjyw 961d22b14e6f1932 961d22b14e6f1932 true 35 wj7sp7dhpfapsd8w2nzn8s7xtnro9g45x7t a166b0326c942c30 a166b0326c942c30 true 36 ahio6so1x30oziw54ux5iojjdfvkwpw2v14d 0f3d837dddb86ae2 0f3d837dddb86ae2 true 37 wm6yacnl6k3kj3c6i1jeajuwmquv9yujms0wq 0f8164504b4ea8b1 0f8164504b4ea8b1 true 38 kzs6xfhmc4ifmstnekcze4y1l83ddvxust2r0o e4f6475d5a739af4 e4f6475d5a739af4 true 39 ckamexupx7cmsuza9nssw6n45e7go4s3osr1903 bf535ad625c0d51f bf535ad625c0d51f true 40 nob5bj9tok346dg62jbfjfrhg5l6itsno2hkhfru 47f10a5a13be50ad 47f10a5a13be50ad true 41 vgo0ko42n5jvrvnv3ddpwg8h7gkqoxbllv2fdy0no 3dc5ce9c148969b3 3dc5ce9c148969b3 true 42 dgs47djqzq3czo0i0v1u3d3x72vtvi3w2tsf9shx6k 8dc071fb4df8e144 8dc071fb4df8e144 true 43 8vjrw7jz90kf969txb5qrh0u5332zf5epsp8aes4aqh 9d0a83586cbed3b8 9d0a83586cbed3b8 true 44 3ni9vtqiq6vnxipfa2wag8vfwq2nyce1kgq5nj3razx9 c4379e22f2809b99 c4379e22f2809b99 true 45 u29xjkod6rtu5j5tlwkydt9khih6o2do84q6ukwlr00xf 42010c7dd7657650 42010c7dd7657650 true 46 yxxubvyxuusw827qctqr6tmm69rij5ex2zk1etps8qh61e cc31a6fbcdab8be8 cc31a6fbcdab8be8 true 47 p7lh4mvadnp6uw0vt7bnzcbv1wjswuuc6gjmu684yznx8lp 7bad06c38400138a 7bad06c38400138a true 48 8c27lotvnab6ra8pq9aon0w30ydyulesinew3akqrhhmm39e 0178b41584eb483d 0178b41584eb483d true 49 ttipbm97gpk7tiog1doncalwgpb7alk16dapga2ekzjt59pv6 78afc38d52514efc 78afc38d52514efc true 50 mbbtplseab2mgtgh8uwlhbmdrwxae3tc2mtf98bwuhmz4bfjnf 65a57c4e59288dc7 65a57c4e59288dc7 true 51 shnjeydnj8awrkz3rd69wqqd9srie4eo6gc6ylhz2ouv4t4qbar 86e7cc3e273e4e47 86e7cc3e273e4e47 true 52 lckl12agnpr6q5053h9v38lyk71emkvwdzrv0ic3a4a4pn3w3o4x eb99661fb41a6bd2 eb99661fb41a6bd2 true 53 7927wqjo5jiecfk0bbtt6065j5jl7x0vv1mcxxxl0j1oatrom44zp ea0979aa6cd70feb ea0979aa6cd70feb true 54 bajk3ff026vx0u7o5d7ry7w7n07sqdy4urv4psr79jp13e0mxsks1r d18f9c6098441c26 a64a347c0b8e007b false 55 en6j5o90gmgj7ssbz6jv3kzdsbzczu518c3zmezkp02rtvo1s88n9pu 39ec128ea95fa3ba 3692969270fe8fa4 false 56 58fkwyf44tjnrytgplb5qfbvlwtav3zutxowoor2mklkr2up4nzpefos 8538d38cbeeb2396 17640c6052e26555 false 57 cep02qfl6swv1j3mwy5kprm4p8drszchufrkyr5ejbtzgu5cti6fqab5c df9e0fd276291357 df9e0fd276291357 true 58 lr5q0p1dljga8h4vruy1doa79hntwbdyolnh1fbe3phfk7f5rgs4815foj 64cca6ebf4580720 64cca6ebf4580720 true 59 hmnjq6h1sslivjzmbxbpqba29f6kvbea6n6c4sanm40nzmrxt8hm61ooq3e f82b33f6399c3f49 f82b33f6399c3f49 true 60 ae43xxu1mqrbynmctit7m4wf02o0kf2vvw1l3y51n4cu5v5ba4dia67wf0bo be3ccb7526561379 be3ccb7526561379 true 61 qz9ye2ur849obmm23d5tnfc3xdaeajil0gm2pz8z9psedj50h5hcwbcn8n2lo 8c796fce8509c043 8c796fce8509c043 true 62 w3xar1pzaff7fhyw6cshdgechm2pj1ebwrbkdct5xfbmxskr3937dodvky62i8 9849fded8c92ce51 9849fded8c92ce51 true 63 ypy5k197quc9ypqoj9kle2eky307jnnd7tu52hqhn6mo7jj1fvmi42kkgq40iy6 a0e744d838dbc4ef a0e744d838dbc4ef true 64 k1bp6qwiul8fnd6rfe42ge6gskk0jkr9fjgmuujey3kn8ie88h9qguw2gboo7i80 8e4602d33a961a65 8e4602d33a961a65 true 65 begb64jkzfujx7ch3ain1iixidnbhcbcglcuf7nys8eansnkewtiye9xv7s2ksuev da381d6727886a7e da381d6727886a7e true 66 vf5d8vdjtwp5vo1ocb274nkl6h8vg97m4v5htfwv02tj9u68vdnteeim6q0zllxflj a503a344fc066833 a503a344fc066833 true 67 dcg9osulcdw9sqaue4cfz6k990vpstoxmvwbxzhzichkhdujy36v556u7oxug51gdup bf8ff5bc36d5dc7b bf8ff5bc36d5dc7b true 68 1rtgdtibcaos4ebzrbl1fkjahtbel6fyqipuu8lxfrwnggjr8wgoscfxp46wv9wjk315 795ae9ed95bca7e9 795ae9ed95bca7e9 true 69 r27qj342zj4anpkqpr9yqo7udnldwiqqpq667zzjgw33yia3wt2p6t221onq4pvfaywbj 19c80807dc900762 19c80807dc900762 true 70 2yzxskad06pt9zvjmiobfz12a3q6wqgpj4450rpxj0jvjk3cx39qo6cbpukxqsy6idqd40 ea7d27083e6ca641 ea7d27083e6ca641 true 71 813zultj26k3gn6gibolpuozgaxu8exfatf4iqqugelcf6k8dnzvsjb9s25g3gyess2uscc eba7e4a637fe4fb5 eba7e4a637fe4fb5 true 72 i4p0jkxf3ajc02x330y3tg8l521fzootabn53ovru20ph3n17hfygaz1axs61jxipz6jac5z 34ac9bde50ce9087 34ac9bde50ce9087 true 73 5bk748kkvww7toeyeueukk2qyin2o5ohnvj7l1cqs9zgy92n6ujxg6sxdjw81hfd29nzrb4kh e290dd0393f2586a e290dd0393f2586a true 74 uvhy62avo1wqms1rrtefth84xhnv1a59aez6r4xq0pla74036o3vznihxexwydnfjojmk6ipl6 bd7074e9843d9dca bd7074e9843d9dca true 75 0t0dlfopg27cqv1xp4qfgwdlivvgqz204hkh5ianbb4abgk0yjolcwhhitrcksha5s6otmps0hd 66c17140a05887e6 66c17140a05887e6 true 76 vrbhcwrmn5xbq8f518ntvmaeg89n7nh1uxebfsmd7smoog3k2w12zv0px32pf4b78er5f3pgy7b9 4ad7b3e525e37f94 4ad7b3e525e37f94 true 77 x5bmnefocbtxm8avt22ekuy5hcdyxh86is5fnns9ycfm7o25x9frwv9kfv2ohyd3txlc8zlg5rjjx de0d009c18880dd6 de0d009c18880dd6 true 78 ttfrgnfvvj552vjymrqqd1yjlyff7vkffprnvu3co4vuah8y0s56tziih3yowm64ja810gb1sgk0um 1516bbb1caca46d3 1516bbb1caca46d3 true 79 a66t43i9vrr3cmg5qf52akuk8bxl4rm3i86rm7h5brjou9k2egrzy3h19hh8kqr2queyvrwb673qikj e9c907ec28f89499 e9c907ec28f89499 true 80 mfuwhbvd88n21obpmwx273mmeqiz98qfmb04z0ute54kc1d9bbdyfbx2sc4em6t4pfektm05qs7bgc9z d677b655085e1e14 d677b655085e1e14 true 81 x8wbm0kjpyua8wpgsejgxc06geitm1c0bxihvcwnxnif63dj7cygzk7led0z49ol6zf2xwcmf99n4osip ac5f949b08f29553 ac5f949b08f29553 true 82 fvba43myr0ozab882crozdz0zx4lfl2h7xe2phfqte97g58fake2fzi87mpftz9qdmt45gm79xl43k1hji d353b06cb49b5503 d353b06cb49b5503 true 83 wnr0pz08rm3j65b7pl116l59pxy6prnydf9xod1qdi3hp3lod2vuzy1v7gt2g72sejaomn5u53daxjrr9xk 9c25eb30ffa8cc78 9c25eb30ffa8cc78 true 84 bwo7nfqda6w56voyvg1nr7vkq61zi7gy0aggn6pic3gup7uy18zzsc7y5yz3ptvp5cd53i95dj521k4n6n7t 6cf18c91658e0285 6cf18c91658e0285 true 85 mromebynw459uydhhgcgrate6hnst5srng9knfjc02vtg1vywok3rdbw935pf1qwghnh0nibyb60l9elkmajg 99264d2b2cc86a77 99264d2b2cc86a77 true 86 59dcjawsd4kjjcceco3hphizua88l0qtrfd000iam3rnb4tmy6kzf5bhkc9ud1hsg3dd53tlsxarcl0n59081h 8b438cd1bb8fb65d 8b438cd1bb8fb65d true 87 odgdgfkwcpz0zjcwsz9is5h4nhebzht7fqa1b4g8e2snb6bn5hu3ixyd2pk1ey5g3eab0m3aoknfi9ctkpxz07j dfd56cf20b217732 dfd56cf20b217732 true 88 0ljqm7r10ns2pjo8x69oi0zuqss9y7301yd6rmex8djwrbqmvh2mbwscgj9pmrgul5ao0tvpefpe5a9cac5xbdwb 71f4e35bf761bacf 71f4e35bf761bacf true 89 b449ak3ihp8tdrbteffru5vboeh1z63c55at3qz70p13d2fim50q8i06zjyb53i4gqzunx6rsl07jxjd9g77me1ww 87d7c01f2b11659c 87d7c01f2b11659c true 90 oqzf6c40snvrjz4v0f4h8p0ozjfy1y4xihxwaz16vbxf3qsa805xodw8z5xq3hb7dag8fnxtlsc62150kk253i3buj 95de608c3ad2653c 95de608c3ad2653c true 91 2eicp9a5aq2uycq55y7rsixlg3pfk7gyin65fghf03kks18dixbckxmbv5xnhyrir7qm8maz4rk2bi3zs9chidlhehf 51b50e6996b8de93 51b50e6996b8de93 true 92 7k1wyjs6fxss4e0ywqfurgop6f7y7e97f3mr5hnb0hlhqkqbqvi1e1z3qfyxc3te75r67fc4h9li06rl9zadg3v9zmz6 d21e837b2121e8c9 d21e837b2121e8c9 true 93 k3e403zdtia8i0gpodm00yaujr1w474bh3985o3csbfjp3dll4t98i5lesloo6rqjec2aycb3ttx1t6lg0cl9hrjkgheb 73d07c7cb3fa0ba7 73d07c7cb3fa0ba7 true 94 2fv8zdl1ljmpjbvaan0nt99tra48yjmc5pv91n1c5l8qp5pv77zwsx75ouay7bmgy2tjc1aazyu5zj7oimesavv9n2h7ky 8113fab03cab6df3 8113fab03cab6df3 true 95 ghxs7uejpzpbxjsdmc2w9fabrg4j4pwwbn0wjxux2luk1k0ciror4gcvww18e610u2wpczuwrcphy2xr1129vweqhhgitge 57cdddea972cc490 57cdddea972cc490 true 96 vk7wfi9hhi0j9n2grs8rxgq68kw54dbdviuxnvtwgz77h0qkbzqw7pgm7zgn21cxlxnyzigeyz2rzrj3awloq86tqe60e070 c3df94778f1eec30 c3df94778f1eec30 true 97 d1aot9216s547uk1rg651iscb1bjpgth5j4f6arx1902npcykk8niz3ffpbed47idgzvt4u59fyi5e0e2afpjb5gjk4rysn8j 7509771e4127701e 7509771e4127701e true 98 2jef2xl4o9yub0z6jnxu8gm87g9iv9zdtu9yolvxtensjrtgplnmnuhz43nsxztk8s936k6eruckkiwc5hnch4qdzft093986x 28240c74c56f8f7c 28240c74c56f8f7c true 99 oo70ed77jci4bgodhnyf37axrx4f8gf8qs94f4l9xi9h0jkdl2ozoi2p7q7qu1945l21dzj6rhvqearzrmblfo3ljjldj0m9fue 194fa4f68aab8e27 194fa4f68aab8e27 true
Тест проходит так: мы берем те строковые значения, которые представлены авторами алгоритма, и пробуем получить для них хэш PolymurHash. После получения хэша мы выводим четыре колонки: номер значения, строковое значение, его вычисленный хэш , эталонное значение хэша, а также колонку true/false. показывающую совпал ли хэш с эталонным.
Реализацию теста мы написали сами (взяв строки и эталонные значения из репозитория PolymurHash) и она показывает как можно применить нашу реализацию хэш-функции – в функцию нужно передать указатель на байтовый буфер (используя свойство .ptr для массива в D), длину массива байтов, инициализированные параметры PolymurHashParams и значение донастройки.
Стоит заметить, что тест почти успешен – так как мы получили шесть значений, которые помечены словом false. Судя по всему, расхождение связано с тем, что в условиях оригинального алгоритма, был использован ряд специфических макросов, срабатывающих на основе вероятного предсказания срабатывания условий (это почти все условия больше/меньше в функции хэширования), однако, это лишь наша догадка. И догадка остается догадкой, так как оригинальную реализацию алгоритма на предмет прохождения собственных тестов нам запустить не удалось: оригинальный код просто не запускается и падает на части системных вызовов…
Но…Несмотря на это, алгоритм полностью рабочий и стоящий, несмотря на то, что эталонная реализация на C подводит и хэш является 64-битным. Мы считаем алгоритм весьма перспективным, и крайне рекомендуем к изучению, и если он вас заинтересовал рекомендуем обратится к первоисточнику.