 {
 ****************************************************************************
 CRW32 project
 Copyright (C) by Kuryakin Alexey, Sarov, Russia, 2017, <kouriakine@mail.ru>
 Hash functions for fast string indexing.
 Modifications:
 20170216 - Creation, first release
 20171201 - Redisign, sanity test, performance benchmark, collision analysis.
 20171218 - FindIndexOfHasher,GetHasherByIndex.
 20180219 - Crc8x,Crc16x,Crc32x,ModbusLrc/Crc,Dcon,Hart etc
 ****************************************************************************
 }

unit _hash;

{$I _sysdef}

interface

uses windows,sysutils,classes,_alloc,_rtc,_sort,_str;

 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Non-cryptographic hash functions library to use for fast indexing by string keys.
 // Hash functions library reference:
 // [1]  http://www.partow.net/programming/hashfunctions/                   - General Purpose Hash Function Algorithms
 //      http://www.partow.net/downloads/GeneralHashFunctions.zip           - General Hash Function Source Code (All Languages)
 // [2]  https://sohabr.net/post/219139/                                    - Несколько простых хеш-функций и их свойства
 //      http://www.pvsm.ru/programmirovanie/58836
 // [3]  https://www.strchr.com/hash_functions                              - Hash functions: An empirical comparison
 // [4]  http://www.cse.yorku.ca/~oz/hash.html                              - Hash Functions
 // [5]  http://www.lua.org/ftp/lua-5.3.3.tar.gz                            - LUA language, src/lstring.c
 // [6]  http://artamonov.ru/2008/05/08/best-hashing-algorithm/             - Выбор лучшего алгоритма хэширования строк
 // [7]  http://www.delphiplus.org/fundamentalnie-algoritmy-i-struktury-dannih/prostaya-funkciya-heshirovaniya-dlya-strok.html
 // [8]  http://www.delphiplus.org/fundamentalnie-algoritmy-i-struktury-dannih/funkcii-heshirovaniya-pjw.html
 // [9]  https://ru.wikipedia.org/wiki/PJW-32                               -
 // [10] http://www.drdobbs.com/database/hashing-rehashed/184409859
 // [11] https://en.wikipedia.org/wiki/PJW_hash_function#cite_note-3
 // [12] https://en.wikipedia.org/wiki/Jenkins_hash_function                - Jenkins hash function
 // [13] http://vak.ru/doku.php/proj/hash/efficiency                        - Эффективность хэш-функций
 // [14] http://vak.ru/doku.php/proj/hash/conflicts                         - General purpose hash function algorithms library
 // [15] http://vak.ru/doku.php/proj/hash/sources                           - Collisions of hash functions
 // [16] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/142054 - String Hashing Algorithms
 // [17] https://habrahabr.ru/post/142589/                                  - Полиномиальные хеши и их применение
 // [18] http://godoc.org/github.com/Cergoo/gol/hash                        - Package hash it's a non-cryptographic hash 32 functions library.
 // [19] https://habrahabr.ru/post/99876/                                   - Обзор генераторов псевдослучайных чисел для CUDA
 // [20] https://en.wikipedia.org/wiki/Linear_congruential_generator        - Linear congruential generator
 // [21] http://numerical.recipes/                                          - "Numerical Recipes" book
 // [22] http://www.guildalfa.ru/alsha/node/32                              - Aleksandr Sharahov
 // [23] https://github.com/liushoukai/node-hashes                          - node-hashes
 // [24] https://github.com/rurban/smhasher                                 - smhasher project
 // [25] https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
 // [26] http://www.isthe.com/chongo/tech/comp/fnv/index.html               - FNV home site
 // [27] http://www.amsoftware.narod.ru/algo.html                           - Простые хэш-функции высокой производительности
 //      http://www.amsoftware.narod.ru/algo2.html                          - benchmarks
 // [28] http://www.amsoftware.narod.ru/algo/hashtest.zip                   - big hash library
 // [29] https://sourceforge.net/projects/jcl/                              - The JEDI Code Library (JCL)
 // [30] http://crccalc.com/, https://github.com/meetanthony/crcjava        - Online CRC Calculator
 // [31] http://www.modbus.org/specs.php                                    - Modbus specification
 // [32] https://en.wikipedia.org/wiki/Highway_Addressable_Remote_Transducer_Protocol - HART protocol
 // [33] http://reveng.sourceforge.net/                                     - CRC RevEng: arbitrary-precision CRC calculator
 //      http://reveng.sourceforge.net/crc-catalogue/all.htm                - Catalogue of parametrised CRC algorithms
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Notes:
 // 1) Some algorighms (like SDBM,DJB) have 2 equivalent forms based on multiplication and based on shift and addition.
 //    For example, (65599*hash) is equivalent to ((hash shl 6)+(hash shl 16)-hash), because 65599=(1 shl 6)+(1 shl 16)-1.
 //    In old processors multiplication operation has high cost and takes more CPU clocks compare to shift & addition one.
 //    But in new processors (Pentium+) multiplication is faster (1 CPU clock) vs  shift+addition (2++ clocks) equivalent.
 //    Library keeps this historical shift+add versions, but multiplication variant is more preferable for new processors.
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const //                    Hash ID   Reference      Author(s)                         Comment
 hid_Hash32_RS              = 0;   // [1,2,15]       Robert Sedgwicks                  "Algorithms in C" book
 hid_Hash32_RS_W2           = 1;   //                                                  2-byte word
 hid_Hash32_RS_W4           = 2;   //                                                  4-byte word
 hid_Hash32_SDBM            = 3;   // [1,4,6]        open source SDBM project          multiplication version
 hid_Hash32_SDBM_W2         = 4;   //                                                  2-byte word version
 hid_Hash32_SDBM_W4         = 5;   //                                                  4-byte word version
 hid_Hash32_SDBM_ASM        = 6;   //                                                  assembler version
 hid_Hash32_SDBM_SHF        = 7;   //                                                  shift+addition version
 hid_Hash32_ROT13           = 8;   // [2,15]         Sergey Vakulenko                  based on cyclic rotation
 hid_Hash32_ROT13_ASM       = 9;   //                                                  assembler version
 hid_Hash32_LY              = 10;  // [2,15]         Leonid Yuryev                     based on linear congruential random generator [19,20,21]
 hid_Hash32_FNV             = 11;  // [23]           Glenn Fowler and Phong Vo
 hid_Hash32_FNV0            = 12;  // [25,26]        Glenn Fowler and Phong Vo
 hid_Hash32_FNV1            = 13;  // [25,26]        Glenn Fowler and Phong Vo
 hid_Hash32_FNV1A           = 14;  // [25,26]        Glenn Fowler and Phong Vo
 hid_Hash32_JENKINS         = 15;  // [2,12]         Bob Jenkins
 hid_Hash32_AP              = 16;  // [1]            Arash Partow
 hid_Hash32_ALSHA1          = 17;  // [22]           Aleksandr Sharahov
 hid_Hash32_ALSHA2          = 18;  // [22]
 hid_Hash32_MURMUR3         = 19;  // [22]           Austin Appleby
 hid_Hash32_MURMUR3_ASM     = 20;  // [22]
 hid_Hash32_BKDR131         = 21;  // [1,3,15]       Brian Kernighan + Dennis Ritchie  "The C Programming Language" book
 hid_Hash32_BKDR31          = 22;  // [1,3,15]       Brian Kernighan + Dennis Ritchie  "The C Programming Language" book
 hid_Hash32_BKDR1313        = 23;  // [1,3,15]       Brian Kernighan + Dennis Ritchie  "The C Programming Language" book
 hid_Hash32_BKDR13131       = 24;  // [1,3,15]       Brian Kernighan + Dennis Ritchie  "The C Programming Language" book
 hid_Hash32_BKDR131313      = 25;  // [1,3,15]       Brian Kernighan + Dennis Ritchie  "The C Programming Language" book
 hid_Hash32_DJB             = 26;  // [1,3,4,6,16]   Professor Daniel J. Bernstein     usenet newsgroup comp.lang.c  (multiplication)
 hid_Hash32_DJB_SHF         = 27;  // [1,3,4,6,16]   Professor Daniel J. Bernstein     usenet newsgroup comp.lang.c  (shift+addition)
 hid_Hash32_JS              = 28;  // [1]            Justin Sobel
 hid_Hash32_LUA             = 29;  // [5]
 hid_Hash32_H37             = 30;  // [2]
 hid_Hash32_TDH17           = 31;  // [7]
 hid_Hash32_TDPJW           = 32;  // [8]
 hid_Hash32_PJW             = 33;  // [10]
 hid_Hash32_PJW32           = 34;  // [9]
 hid_Hash32_ELF             = 35;  // [11]
 hid_Hash32_DEK             = 36;  // [23]           Donald E. Knuth "The Art Of Computer Programming" Volume 3
 hid_Hash32_BP              = 37;  // [23]
 hid_Hash32_LOSER           = 38;  // [4]            Brian Kernighan + Dennis Ritchie  Worst and simplest hash, just for testing; K&R (1st ed)
 hid_Hash32_JCL             = 39;  // [29]
 hid_Hash32_Goulburn        = 40;  // [27]
 hid_Hash32_OneAtTime       = 41;  // [27]
 hid_Hash32_SBOX            = 42;  // [27]
 hid_Hash32_CRAP8           = 43;  // [27]
 hid_Hash32_CRAPWOW         = 44;  // [27]
 hid_Hash32_SUPERFAST       = 45;  // [27]
 hid_Hash32_Murmur2         = 46;  // [27]
 hid_Hash32_Crc8            = 47;  // [30,33]
 hid_Hash32_Crc8Cdma2000    = 48;  // [30,33]
 hid_Hash32_Crc8Darc        = 49;  // [30,33]
 hid_Hash32_Crc8Dvbs2       = 50;  // [30,33]
 hid_Hash32_Crc8Ebu         = 51;  // [30,33]
 hid_Hash32_Crc8Icode       = 52;  // [30,33]
 hid_Hash32_Crc8Itu         = 53;  // [30,33]
 hid_Hash32_Crc8Maxim       = 54;  // [30,33]
 hid_Hash32_Crc8Rohc        = 55;  // [30,33]
 hid_Hash32_Crc8Wcdma       = 56;  // [30,33]
 hid_Hash32_Crc16CcittFalse = 57;  // [30,33]
 hid_Hash32_Crc16Arc        = 58;  // [30,33]
 hid_Hash32_Crc16AugCcitt   = 59;  // [30,33]
 hid_Hash32_Crc16Buypass    = 60;  // [30,33]
 hid_Hash32_Crc16Cdma2000   = 61;  // [30,33]
 hid_Hash32_Crc16Dds110     = 62;  // [30,33]
 hid_Hash32_Crc16DectR      = 63;  // [30,33]
 hid_Hash32_Crc16DectX      = 64;  // [30,33]
 hid_Hash32_Crc16Dnp        = 65;  // [30,33]
 hid_Hash32_Crc16En13757    = 66;  // [30,33]
 hid_Hash32_Crc16Genibus    = 67;  // [30,33]
 hid_Hash32_Crc16Maxim      = 68;  // [30,33]
 hid_Hash32_Crc16Mcrf4xx    = 69;  // [30,33]
 hid_Hash32_Crc16Riello     = 70;  // [30,33]
 hid_Hash32_Crc16T10dif     = 71;  // [30,33]
 hid_Hash32_Crc16Teledisk   = 72;  // [30,33]
 hid_Hash32_Crc16Tms37157   = 73;  // [30,33]
 hid_Hash32_Crc16Usb        = 74;  // [30,33]
 hid_Hash32_Crc16A          = 75;  // [30,33]
 hid_Hash32_Crc16Kermit     = 76;  // [30,33]
 hid_Hash32_Crc16Modbus     = 77;  // [30,33]
 hid_Hash32_Crc16X25        = 78;  // [30,33]
 hid_Hash32_Crc16Xmodem     = 79;  // [30,33]
 hid_Hash32_Crc32           = 80;  // [30,33]
 hid_Hash32_Crc32Bzip2      = 81;  // [30,33]
 hid_Hash32_Crc32C          = 82;  // [30,33]
 hid_Hash32_Crc32D          = 83;  // [30,33]
 hid_Hash32_Crc32Jamcrc     = 84;  // [30,33]
 hid_Hash32_Crc32Mpeg2      = 85;  // [30,33]
 hid_Hash32_Crc32Posix      = 86;  // [30,33]
 hid_Hash32_Crc32Q          = 87;  // [30,33]
 hid_Hash32_Crc32Xfer       = 88;  // [30,33]
 hid_Hash32_ModbusLrc       = 89;  // [31]           Modbus ASCII
 hid_Hash32_ModbusCrc       = 90;  // [31]           Modbus RTU
 hid_Hash32_Dcon            = 91;  //                DCON protocol checksum
 hid_Hash32_Hart            = 92;  // [32]           HART protocol checksum
 hid_Hash32_ZERO            = 93;  //                Zero hash just for software stress testing

type
 THash32MethodId = hid_Hash32_RS..hid_Hash32_ZERO;

function GetHashByBufferKey(aKey:PChar; aLength:Integer; aTableSize:Cardinal=0; aMethod:THash32MethodId=0):Cardinal;
function GetHashByStringKey(const aKey:AnsiString; aTableSize:Cardinal=0; aMethod:THash32MethodId=0):Cardinal;

function sar32(value,shift:Cardinal):Cardinal;
function ror32(value,shift:Cardinal):Cardinal;
function rol32(value,shift:Cardinal):Cardinal;

 ////////////////////////////////////////////////////////////////////////////////
 // Non-cryptographic hash functions to be used for fast indexing by string keys.
 // The key is uses like raw array of char (not zero-terminated) with length len.
 // So len MUST be actual length taken from strlen() or Length() functions, like:
 // hash:=Hash32_Ly(key,strlen(key)); or hash:=Hash32_Rs(PChar(key),Length(key));
 ////////////////////////////////////////////////////////////////////////////////
type
 THash32EchoProc = procedure(const Msg:LongString);
 THash32Function = function(key:PChar; len:Integer):Cardinal;

function Hash32_RS(key:PChar; len:Integer):Cardinal;
function Hash32_RS_W2(key:PChar; len:Integer):Cardinal;
function Hash32_RS_W4(key:PChar; len:Integer):Cardinal;
function Hash32_SDBM(key:PChar; len:Integer):Cardinal;
function Hash32_SDBM_W2(key:PChar; len:Integer):Cardinal;
function Hash32_SDBM_W4(key:PChar; len:Integer):Cardinal;
function Hash32_SDBM_ASM(key:PChar; len:Integer):Cardinal;
function Hash32_SDBM_SHF(key:PChar; len:Integer):Cardinal;
function Hash32_ROT13(key:PChar; len:Integer):Cardinal;
function Hash32_ROT13_ASM(key:PChar; len:Integer):Cardinal;
function Hash32_LY(key:PChar; len:Integer):Cardinal;
function Hash32_FNV(key:PChar; len:Integer):Cardinal;
function Hash32_FNV0(key:PChar; len:Integer):Cardinal;
function Hash32_FNV1(key:PChar; len:Integer):Cardinal;
function Hash32_FNV1A(key:PChar; len:Integer):Cardinal;
function Hash32_JENKINS(key:PChar; len:Integer):Cardinal;
function Hash32_AP(key:PChar; len:Integer):Cardinal;
function Hash32_ALSHA1(key:PChar; len:Integer):Cardinal;
function Hash32_ALSHA2(key:PChar; len:Integer):Cardinal;
function Hash32_MURMUR3(key:PChar; len:Integer):Cardinal;
function Hash32_MURMUR3_ASM(key:PChar; len:Integer):Cardinal;
function Hash32_BKDR131(key:PChar; len:Integer):Cardinal;
function Hash32_BKDR31(key:PChar; len:Integer):Cardinal;
function Hash32_BKDR1313(key:PChar; len:Integer):Cardinal;
function Hash32_BKDR13131(key:PChar; len:Integer):Cardinal;
function Hash32_BKDR131313(key:PChar; len:Integer):Cardinal;
function Hash32_DJB(key:PChar; len:Integer):Cardinal;
function Hash32_DJB_SHF(key:PChar; len:Integer):Cardinal;
function Hash32_JS(key:PChar; len:Integer):Cardinal;
function Hash32_LUA(key:PChar; len:Integer):Cardinal;
function Hash32_H37(key:PChar; len:Integer):Cardinal;
function Hash32_TDH17(key:PChar; len:Integer):Cardinal;
function Hash32_TDPJW(key:PChar; len:Integer):Cardinal;
function Hash32_PJW(key:PChar; len:Integer):Cardinal;
function Hash32_PJW32(key:PChar; len:Integer):Cardinal;
function Hash32_ELF(key:PChar; len:Integer):Cardinal;
function Hash32_DEK(key:PChar; len:Integer):Cardinal;
function Hash32_BP(key:PChar; len:Integer):Cardinal;
function Hash32_LOSER(key:PChar; len:Integer):Cardinal;
function Hash32_JCL(key:PChar; len:Integer):Cardinal;
function Hash32_Goulburn(key:PChar; len:Integer):Cardinal;
function Hash32_OneAtTime(key:PChar; len:Integer):Cardinal;
function Hash32_SBOX(key:PChar; len:Integer):Cardinal;
function Hash32_Crap8(key:PChar; len:Integer):Cardinal;
function Hash32_CrapWow(key:PChar; len:Integer):Cardinal;
function Hash32_SuperFast(key:PChar; len:Integer):Cardinal;
function Hash32_Murmur2(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Cdma2000(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Darc(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Dvbs2(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Ebu(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Icode(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Itu(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Maxim(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Rohc(key:PChar; len:Integer):Cardinal;
function Hash32_Crc8Wcdma(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16CcittFalse(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Arc(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16AugCcitt(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Buypass(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Cdma2000(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Dds110(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16DectR(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16DectX(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Dnp(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16En13757(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Genibus(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Maxim(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Mcrf4xx(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Riello(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16T10dif(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Teledisk(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Tms37157(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Usb(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16A(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Kermit(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Modbus(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16X25(key:PChar; len:Integer):Cardinal;
function Hash32_Crc16Xmodem(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Bzip2(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32C(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32D(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Jamcrc(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Mpeg2(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Posix(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Q(key:PChar; len:Integer):Cardinal;
function Hash32_Crc32Xfer(key:PChar; len:Integer):Cardinal;
function Hash32_ModbusLrc(key:PChar; len:Integer):Cardinal;
function Hash32_ModbusCrc(key:PChar; len:Integer):Cardinal;
function Hash32_Dcon(key:PChar; len:Integer):Cardinal;
function Hash32_Hart(key:PChar; len:Integer):Cardinal;
function Hash32_ZERO(key:PChar; len:Integer):Cardinal;

const
 Hash32FuncTable : array[THash32MethodId] of record
   Func:THash32Function;    Name:PChar;
 end = (
  (Func:Hash32_RS;              Name:'RS'              ),
  (Func:Hash32_RS_W2;           Name:'RS_W2'           ),
  (Func:Hash32_RS_W4;           Name:'RS_W4'           ),
  (Func:Hash32_SDBM;            Name:'SDBM'            ),
  (Func:Hash32_SDBM_W2;         Name:'SDBM_W2'         ),
  (Func:Hash32_SDBM_W4;         Name:'SDBM_W4'         ),
  (Func:Hash32_SDBM_ASM;        Name:'SDBM_ASM'        ),
  (Func:Hash32_SDBM_SHF;        Name:'SDBM_SHF'        ),
  (Func:Hash32_ROT13;           Name:'ROT13'           ),
  (Func:Hash32_ROT13_ASM;       Name:'ROT13_ASM'       ),
  (Func:Hash32_LY;              Name:'LY'              ),
  (Func:Hash32_FNV;             Name:'FNV'             ),
  (Func:Hash32_FNV0;            Name:'FNV0'            ),
  (Func:Hash32_FNV1;            Name:'FNV1'            ),
  (Func:Hash32_FNV1A;           Name:'FNV1A'           ),
  (Func:Hash32_JENKINS;         Name:'JENKINS'         ),
  (Func:Hash32_AP;              Name:'AP'              ),
  (Func:Hash32_ALSHA1;          Name:'ALSHA1'          ),
  (Func:Hash32_ALSHA2;          Name:'ALSHA2'          ),
  (Func:Hash32_MURMUR3;         Name:'MURMUR3'         ),
  (Func:Hash32_MURMUR3_ASM;     Name:'MURMUR3_ASM'     ),
  (Func:Hash32_BKDR131;         Name:'BKDR131'         ),
  (Func:Hash32_BKDR31;          Name:'BKDR31'          ),
  (Func:Hash32_BKDR1313;        Name:'BKDR1313'        ),
  (Func:Hash32_BKDR13131;       Name:'BKDR13131'       ),
  (Func:Hash32_BKDR131313;      Name:'BKDR131313'      ),
  (Func:Hash32_DJB;             Name:'DJB'             ),
  (Func:Hash32_DJB_SHF;         Name:'DJB_SHF'         ),
  (Func:Hash32_JS;              Name:'JS'              ),
  (Func:Hash32_LUA;             Name:'LUA'             ),
  (Func:Hash32_H37;             Name:'H37'             ),
  (Func:Hash32_TDH17;           Name:'TDH17'           ),
  (Func:Hash32_TDPJW;           Name:'TDPJW'           ),
  (Func:Hash32_PJW;             Name:'PJW'             ),
  (Func:Hash32_PJW32;           Name:'PJW32'           ),
  (Func:Hash32_ELF;             Name:'ELF'             ),
  (Func:Hash32_DEK;             Name:'DEK'             ),
  (Func:Hash32_BP;              Name:'BP'              ),
  (Func:Hash32_LOSER;           Name:'LOSER'           ),
  (Func:Hash32_JCL;             Name:'JCL'             ),
  (Func:Hash32_Goulburn;        Name:'GOULBURN'        ),
  (Func:Hash32_OneAtTime;       Name:'ONEATTIME'       ),
  (Func:Hash32_SBOX;            Name:'SBOX'            ),
  (Func:Hash32_Crap8;           Name:'CRAP8'           ),
  (Func:Hash32_CrapWow;         Name:'CRAPWOW'         ),
  (Func:Hash32_SUPERFAST;       Name:'SUPERFAST'       ),
  (Func:Hash32_Murmur2;         Name:'Murmur2'         ),
  (Func:Hash32_Crc8;            Name:'Crc8'            ),
  (Func:Hash32_Crc8Cdma2000;    Name:'Crc8Cdma2000'    ),
  (Func:Hash32_Crc8Darc;        Name:'Crc8Darc'        ),
  (Func:Hash32_Crc8Dvbs2;       Name:'Crc8Dvbs2'       ),
  (Func:Hash32_Crc8Ebu;         Name:'Crc8Ebu'         ),
  (Func:Hash32_Crc8Icode;       Name:'Crc8Icode'       ),
  (Func:Hash32_Crc8Itu;         Name:'Crc8Itu'         ),
  (Func:Hash32_Crc8Maxim;       Name:'Crc8Maxim'       ),
  (Func:Hash32_Crc8Rohc;        Name:'Crc8Rohc'        ),
  (Func:Hash32_Crc8Wcdma;       Name:'Crc8Wcdma'       ),
  (Func:Hash32_Crc16CcittFalse; Name:'Crc16CcittFalse' ),
  (Func:Hash32_Crc16Arc;        Name:'Crc16Arc'        ),
  (Func:Hash32_Crc16AugCcitt;   Name:'Crc16AugCcitt'   ),
  (Func:Hash32_Crc16Buypass;    Name:'Crc16Buypass'    ),
  (Func:Hash32_Crc16Cdma2000;   Name:'Crc16Cdma2000'   ),
  (Func:Hash32_Crc16Dds110;     Name:'Crc16Dds110'     ),
  (Func:Hash32_Crc16DectR;      Name:'Crc16DectR'      ),
  (Func:Hash32_Crc16DectX;      Name:'Crc16DectX'      ),
  (Func:Hash32_Crc16Dnp;        Name:'Crc16Dnp'        ),
  (Func:Hash32_Crc16En13757;    Name:'Crc16En13757'    ),
  (Func:Hash32_Crc16Genibus;    Name:'Crc16Genibus'    ),
  (Func:Hash32_Crc16Maxim;      Name:'Crc16Maxim'      ),
  (Func:Hash32_Crc16Mcrf4xx;    Name:'Crc16Mcrf4xx'    ),
  (Func:Hash32_Crc16Riello;     Name:'Crc16Riello'     ),
  (Func:Hash32_Crc16T10dif;     Name:'Crc16T10dif'     ),
  (Func:Hash32_Crc16Teledisk;   Name:'Crc16Teledisk'   ),
  (Func:Hash32_Crc16Tms37157;   Name:'Crc16Tms37157'   ),
  (Func:Hash32_Crc16Usb;        Name:'Crc16Usb'        ),
  (Func:Hash32_Crc16A;          Name:'Crc16A'          ),
  (Func:Hash32_Crc16Kermit;     Name:'Crc16Kermit'     ),
  (Func:Hash32_Crc16Modbus;     Name:'Crc16Modbus'     ),
  (Func:Hash32_Crc16X25;        Name:'Crc16X25'        ),
  (Func:Hash32_Crc16Xmodem;     Name:'Crc16Xmodem'     ),
  (Func:Hash32_Crc32;           Name:'Crc32'           ),
  (Func:Hash32_Crc32Bzip2;      Name:'Crc32Bzip2'      ),
  (Func:Hash32_Crc32C;          Name:'Crc32C'          ),
  (Func:Hash32_Crc32D;          Name:'Crc32D'          ),
  (Func:Hash32_Crc32Jamcrc;     Name:'Crc32Jamcrc'     ),
  (Func:Hash32_Crc32Mpeg2;      Name:'Crc32Mpeg2'      ),
  (Func:Hash32_Crc32Posix;      Name:'Crc32Posix'      ),
  (Func:Hash32_Crc32Q;          Name:'Crc32Q'          ),
  (Func:Hash32_Crc32Xfer;       Name:'Crc32Xfer'       ),
  (Func:Hash32_ModbusLrc;       Name:'ModbusLrc'       ),
  (Func:Hash32_ModbusCrc;       Name:'ModbusCrc'       ),
  (Func:Hash32_Dcon;            Name:'DCON'            ),
  (Func:Hash32_Hart;            Name:'HART'            ),
  (Func:Hash32_ZERO;            Name:'ZERO'            )
 );

function FindIndexOfHasher(aHasherFunc:THash32Function):Integer; overload;
function FindIndexOfHasher(aHasherName:LongString):Integer; overload;
function GetHasherByIndex(aIndex:Integer):THash32Function;
function GetHasherNameByIndex(aIndex:Integer):AnsiString;

 ////////////////////////////////////////////////////////////////////////////////
 // Hash function sanity test and benchmark to check correctness and performance.
 ////////////////////////////////////////////////////////////////////////////////
function MakeHash32SanityTest(Echo:THash32EchoProc=nil):Integer;
function MakeHash32BenchByList(List:TStringList; Func:THash32Function; Name:LongString; nIter:Integer=100):LongString;
function DoHashBench(dictFileName:LongString; nIter:Integer=100; Echo:THash32EchoProc=nil):LongString;

implementation

function GetHashByBufferKey(aKey:PChar; aLength:Integer; aTableSize:Cardinal=0; aMethod:THash32MethodId=0):Cardinal;
begin
 Result:=0;
 if aLength>0 then
 if aKey<>nil then
 try
  case aMethod of
   hid_Hash32_RS              : Result:=Hash32_RS(aKey,aLength);
   hid_Hash32_RS_W2           : Result:=Hash32_RS_W2(aKey,aLength);
   hid_Hash32_RS_W4           : Result:=Hash32_RS_W4(aKey,aLength);
   hid_Hash32_SDBM            : Result:=Hash32_SDBM(aKey,aLength);
   hid_Hash32_SDBM_W2         : Result:=Hash32_SDBM_W2(aKey,aLength);
   hid_Hash32_SDBM_W4         : Result:=Hash32_SDBM_W4(aKey,aLength);
   hid_Hash32_SDBM_ASM        : Result:=Hash32_SDBM_ASM(aKey,aLength);
   hid_Hash32_SDBM_SHF        : Result:=Hash32_SDBM_SHF(aKey,aLength);
   hid_Hash32_ROT13           : Result:=Hash32_ROT13(aKey,aLength);
   hid_Hash32_ROT13_ASM       : Result:=Hash32_ROT13_ASM(aKey,aLength);
   hid_Hash32_LY              : Result:=Hash32_LY(aKey,aLength);
   hid_Hash32_FNV             : Result:=Hash32_FNV(aKey,aLength);
   hid_Hash32_FNV0            : Result:=Hash32_FNV0(aKey,aLength);
   hid_Hash32_FNV1            : Result:=Hash32_FNV1(aKey,aLength);
   hid_Hash32_FNV1A           : Result:=Hash32_FNV1A(aKey,aLength);
   hid_Hash32_JENKINS         : Result:=Hash32_JENKINS(aKey,aLength);
   hid_Hash32_AP              : Result:=Hash32_AP(aKey,aLength);
   hid_Hash32_ALSHA1          : Result:=Hash32_ALSHA1(aKey,aLength);
   hid_Hash32_ALSHA2          : Result:=Hash32_ALSHA2(aKey,aLength);
   hid_Hash32_MURMUR3         : Result:=Hash32_MURMUR3(aKey,aLength);
   hid_Hash32_MURMUR3_ASM     : Result:=Hash32_MURMUR3_ASM(aKey,aLength);
   hid_Hash32_BKDR131         : Result:=Hash32_BKDR131(aKey,aLength);
   hid_Hash32_BKDR31          : Result:=Hash32_BKDR31(aKey,aLength);
   hid_Hash32_BKDR1313        : Result:=Hash32_BKDR1313(aKey,aLength);
   hid_Hash32_BKDR13131       : Result:=Hash32_BKDR13131(aKey,aLength);
   hid_Hash32_BKDR131313      : Result:=Hash32_BKDR131313(aKey,aLength);
   hid_Hash32_DJB             : Result:=Hash32_DJB(aKey,aLength);
   hid_Hash32_DJB_SHF         : Result:=Hash32_DJB_SHF(aKey,aLength);
   hid_Hash32_JS              : Result:=Hash32_JS(aKey,aLength);
   hid_Hash32_LUA             : Result:=Hash32_LUA(aKey,aLength);
   hid_Hash32_H37             : Result:=Hash32_H37(aKey,aLength);
   hid_Hash32_TDH17           : Result:=Hash32_TDH17(aKey,aLength);
   hid_Hash32_TDPJW           : Result:=Hash32_TDPJW(aKey,aLength);
   hid_Hash32_PJW             : Result:=Hash32_PJW(aKey,aLength);
   hid_Hash32_PJW32           : Result:=Hash32_PJW32(aKey,aLength);
   hid_Hash32_ELF             : Result:=Hash32_ELF(aKey,aLength);
   hid_Hash32_DEK             : Result:=Hash32_DEK(aKey,aLength);
   hid_Hash32_BP              : Result:=Hash32_BP(aKey,aLength);
   hid_Hash32_LOSER           : Result:=Hash32_LOSER(aKey,aLength);
   hid_Hash32_JCL             : Result:=Hash32_JCL(aKey,aLength);
   hid_Hash32_Goulburn        : Result:=Hash32_Goulburn(aKey,aLength);
   hid_Hash32_OneAtTime       : Result:=Hash32_OneAtTime(aKey,aLength);
   hid_Hash32_SBOX            : Result:=Hash32_SBOX(aKey,aLength);
   hid_Hash32_Crap8           : Result:=Hash32_Crap8(aKey,aLength);
   hid_Hash32_CrapWow         : Result:=Hash32_CrapWow(aKey,aLength);
   hid_Hash32_SuperFast       : Result:=Hash32_SuperFast(aKey,aLength);
   hid_Hash32_Murmur2         : Result:=Hash32_Murmur2(aKey,aLength);
   hid_Hash32_Crc8            : Result:=Hash32_Crc8(aKey,aLength);
   hid_Hash32_Crc8Cdma2000    : Result:=Hash32_Crc8Cdma2000(aKey,aLength);
   hid_Hash32_Crc8Darc        : Result:=Hash32_Crc8Darc(aKey,aLength);
   hid_Hash32_Crc8Dvbs2       : Result:=Hash32_Crc8Dvbs2(aKey,aLength);
   hid_Hash32_Crc8Ebu         : Result:=Hash32_Crc8Ebu(aKey,aLength);
   hid_Hash32_Crc8Icode       : Result:=Hash32_Crc8Icode(aKey,aLength);
   hid_Hash32_Crc8Itu         : Result:=Hash32_Crc8Itu(aKey,aLength);
   hid_Hash32_Crc8Maxim       : Result:=Hash32_Crc8Maxim(aKey,aLength);
   hid_Hash32_Crc8Rohc        : Result:=Hash32_Crc8Rohc(aKey,aLength);
   hid_Hash32_Crc8Wcdma       : Result:=Hash32_Crc8Wcdma(aKey,aLength);
   hid_Hash32_Crc16CcittFalse : Result:=Hash32_Crc16CcittFalse(aKey,aLength);
   hid_Hash32_Crc16Arc        : Result:=Hash32_Crc16Arc(aKey,aLength);
   hid_Hash32_Crc16AugCcitt   : Result:=Hash32_Crc16AugCcitt(aKey,aLength);
   hid_Hash32_Crc16Buypass    : Result:=Hash32_Crc16Buypass(aKey,aLength);
   hid_Hash32_Crc16Cdma2000   : Result:=Hash32_Crc16Cdma2000(aKey,aLength);
   hid_Hash32_Crc16Dds110     : Result:=Hash32_Crc16Dds110(aKey,aLength);
   hid_Hash32_Crc16DectR      : Result:=Hash32_Crc16DectR(aKey,aLength);
   hid_Hash32_Crc16DectX      : Result:=Hash32_Crc16DectX(aKey,aLength);
   hid_Hash32_Crc16Dnp        : Result:=Hash32_Crc16Dnp(aKey,aLength);
   hid_Hash32_Crc16En13757    : Result:=Hash32_Crc16En13757(aKey,aLength);
   hid_Hash32_Crc16Genibus    : Result:=Hash32_Crc16Genibus(aKey,aLength);
   hid_Hash32_Crc16Maxim      : Result:=Hash32_Crc16Maxim(aKey,aLength);
   hid_Hash32_Crc16Mcrf4xx    : Result:=Hash32_Crc16Mcrf4xx(aKey,aLength);
   hid_Hash32_Crc16Riello     : Result:=Hash32_Crc16Riello(aKey,aLength);
   hid_Hash32_Crc16T10dif     : Result:=Hash32_Crc16T10dif(aKey,aLength);
   hid_Hash32_Crc16Teledisk   : Result:=Hash32_Crc16Teledisk(aKey,aLength);
   hid_Hash32_Crc16Tms37157   : Result:=Hash32_Crc16Tms37157(aKey,aLength);
   hid_Hash32_Crc16Usb        : Result:=Hash32_Crc16Usb(aKey,aLength);
   hid_Hash32_Crc16A          : Result:=Hash32_Crc16A(aKey,aLength);
   hid_Hash32_Crc16Kermit     : Result:=Hash32_Crc16Kermit(aKey,aLength);
   hid_Hash32_Crc16Modbus     : Result:=Hash32_Crc16Modbus(aKey,aLength);
   hid_Hash32_Crc16X25        : Result:=Hash32_Crc16X25(aKey,aLength);
   hid_Hash32_Crc16Xmodem     : Result:=Hash32_Crc16Xmodem(aKey,aLength);
   hid_Hash32_Crc32           : Result:=Hash32_Crc32(aKey,aLength);
   hid_Hash32_Crc32Bzip2      : Result:=Hash32_Crc32Bzip2(aKey,aLength);
   hid_Hash32_Crc32C          : Result:=Hash32_Crc32C(aKey,aLength);
   hid_Hash32_Crc32D          : Result:=Hash32_Crc32D(aKey,aLength);
   hid_Hash32_Crc32Jamcrc     : Result:=Hash32_Crc32Jamcrc(aKey,aLength);
   hid_Hash32_Crc32Mpeg2      : Result:=Hash32_Crc32Mpeg2(aKey,aLength);
   hid_Hash32_Crc32Posix      : Result:=Hash32_Crc32Posix(aKey,aLength);
   hid_Hash32_Crc32Q          : Result:=Hash32_Crc32Q(aKey,aLength);
   hid_Hash32_Crc32Xfer       : Result:=Hash32_Crc32Xfer(aKey,aLength);
   hid_Hash32_ModbusLrc       : Result:=Hash32_ModbusLrc(aKey,aLength);
   hid_Hash32_ModbusCrc       : Result:=Hash32_ModbusCrc(aKey,aLength);
   hid_Hash32_Dcon            : Result:=Hash32_Dcon(aKey,aLength);
   hid_Hash32_Hart            : Result:=Hash32_Hart(aKey,aLength);
   hid_Hash32_ZERO            : Result:=Hash32_ZERO(aKey,aLength);
   else                         Result:=Hash32_RS(aKey,aLength);
  end;
  if aTableSize>0 then Result:=Result mod aTableSize;
 except
  on E:Exception do BugReport(E);
 end;
end;

function GetHashByStringKey(const aKey:AnsiString; aTableSize:Cardinal=0; aMethod:THash32MethodId=0):Cardinal;
begin
 Result:=GetHashByBufferKey(PChar(aKey),Length(aKey),aTableSize,aMethod);
end;

 // http://www.guildalfa.ru/alsha/node/9
function sar32(value,shift:Cardinal):Cardinal;
asm
 mov ecx, edx
 sar eax, cl
end;

function ror32(value,shift:Cardinal):Cardinal;
asm
 mov ecx, edx
 ror eax, cl
end;

function rol32(value,shift:Cardinal):Cardinal;
asm
 mov ecx, edx
 rol eax, cl
end;

 ////////////////////////////////////////////////
 // Hash functions for non-cryptographic hashing.
 ////////////////////////////////////////////////

 // Robert Sedgewick
 // http://www.partow.net/programming/hashfunctions
function Hash32_RS(key:PChar; len:Integer):Cardinal;
var a:Cardinal; const b=378551;
begin
 Result:=0;
 if Assigned(key) then begin
  a:=63689;
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]); a:=a*b;
   inc(key); dec(len);
  end;
 end;
end;

 // Version of Hash32_RS but with 2-byte words
function Hash32_RS_W2(key:PChar; len:Integer):Cardinal;
var a:Cardinal; const b=378551;
begin
 Result:=0;
 if Assigned(key) then begin
  a:=63689;
  while (len>1) do begin
   Result:=Result*a+PWord(key)^; a:=a*b;
   inc(key,2); dec(len,2);
  end;
  if len>0 then Result:=Result*a+Byte(key[0]);
 end;
end;

 // Version of Hash32_RS but with 4-byte words
function Hash32_RS_W4(key:PChar; len:Integer):Cardinal;
var a:Cardinal; const b=378551;
begin
 Result:=0;
 if Assigned(key) then begin
  a:=63689;
  while (len>3) do begin
   Result:=Result*a+PCardinal(key)^; a:=a*b;
   inc(key,4); dec(len,4);
  end;
  case len of
   1: Result:=Result*a+Byte(key[0]);
   2: Result:=Result*a+PWord(key)^;
   3: Result:=Result*a+PWord(key)^+(Cardinal(key[2]) shl 16);
  end;
 end;
end;

 // Used in the open source SDBM project
 // http://www.partow.net/programming/hashfunctions
function Hash32_SDBM(key:PChar; len:Integer):Cardinal;
const a=65599;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Version of Hash32_SDBM but with 2-byte words
function Hash32_SDBM_W2(key:PChar; len:Integer):Cardinal;
const a=65599;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>1) do begin
   Result:=Result*a+PWord(key)^;
   inc(key,2); dec(len,2);
  end;
  if len>0 then Result:=Result*a+Byte(key[0]);
 end;
end;

 // Version of Hash32_SDBM but with 4-byte words
function Hash32_SDBM_W4(key:PChar; len:Integer):Cardinal;
const a=65599;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>3) do begin
   Result:=Result*a+PCardinal(key)^;
   inc(key,4); dec(len,4);
  end;
  case len of
   1: Result:=Result*a+Byte(key[0]);
   2: Result:=Result*a+PWord(key)^;
   3: Result:=Result*a+PWord(key)^+(Cardinal(key[2]) shl 16);
  end;
 end;
end;

 // Version of Hash32_SDBM with assembler
function Hash32_SDBM_ASM(key:PChar; len:Integer):Cardinal;
const a=65599;
asm
 test  eax,eax              // if key=nil
 jz    @zero                // then @zero
 push  ebx                  // save EBX
 xor   ecx,ecx              // hash:=0
 test  edx,edx              // if len<=0
 jle   @done                // then @done
@loop:                      // repeat
 imul  ecx,ecx,a            // hash:=hash*a
 movzx ebx,byte ptr [eax]   // data:=byte(key[0])
 add   ecx,ebx              // hash:=hash+data
 inc   eax                  // inc(key)
 sub   edx,1                // dec(len)
 jnle  @loop                // until len<=0
@done:                      // finally
 mov   eax,ecx              // Result:=hash
 pop   ebx                  // restore EBX
@zero:
end;

 // Version of Hash32_SDBM with shifts
function Hash32_SDBM_SHF(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 6)+(Result shl 16)-Result+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Sergey Vakulenko
 // http://vak.ru/doku.php/proj/hash/sources
function Hash32_ROT13(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result+Byte(key[0]); Result:=Result-((Result shl 13) or (Result shr (32-13)));
   inc(key); dec(len);
  end;
 end;
end;

 // Assembler version of Hash32_ROT13
function Hash32_ROT13_ASM(key:PChar; len:Integer):Cardinal;
asm
 test  eax,eax              // if key=nil
 jz    @zero                // then exit
 push  ebx                  // save EBX
 xor   ecx,ecx              // hash:=0
 test  edx,edx              // if len<=0
 jle   @done                // then exit
@loop:                      // repeat
 movzx ebx,byte ptr [eax]   // data:=Byte(key[0])
 add   ecx,ebx              // hash:=hash+data
 mov   ebx,ecx              // temp:=hash
 rol   ebx,$0d              // temp:=temp rol 13
 sub   ecx,ebx              // hash:=hash-temp
 inc   eax                  // inc(key);
 sub   edx,1
 jnle  @loop                // until len<=0
@done:
 mov   eax,ecx              // Result:=hash
 pop   ebx                  // restore EBX
@zero:
end;

 // Leonid Yuriev
 // http://vak.ru/doku.php/proj/hash/sources
function Hash32_LY(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result*1664525)+Byte(key[0])+1013904223;
   inc(key); dec(len);
  end;
 end;
end;

 // Glenn Fowler and Phong Vo
 // https://github.com/liushoukai/node-hashes
 // http://www.amsoftware.narod.ru/algo/hashtest.zip
function Hash32_FNV(key:PChar; len:Integer):Cardinal;
const fnv_prime = $811C9DC5;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result * fnv_prime;
   Result:=Result xor Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Glenn Fowler and Phong Vo
 // http://www.isthe.com/chongo/tech/comp/fnv/index.html
 // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
function Hash32_FNV0(key:PChar; len:Integer):Cardinal;
const fnv_prime=16777619; fnv_basis=0;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=fnv_basis;
  while (len>0) do begin
   Result:=Result * fnv_prime;
   Result:=Result xor Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_FNV1(key:PChar; len:Integer):Cardinal;
const fnv_prime=16777619; fnv_basis=2166136261;//$01000193,$811C9DC5
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=fnv_basis;
  while (len>0) do begin
   Result:=Result * fnv_prime;
   Result:=Result xor Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_FNV1A(key:PChar; len:Integer):Cardinal;
const fnv_prime=16777619; fnv_basis=2166136261;//$01000193,$811C9DC5
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=fnv_basis;
  while (len>0) do begin
   Result:=Result xor Byte(key[0]);
   Result:=Result * fnv_prime;
   inc(key); dec(len);
  end;
 end;
end;

 // Bob Jenkins
 // Also known as "OneAtTime"
 // http://vak.ru/doku.php/proj/hash/sources
function Hash32_Jenkins(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result+Byte(key[0]);
   Result:=Result+(Result shl 10);
   Result:=Result xor (Result shr 6);
   inc(key); dec(len);
  end;
  Result:=Result+(Result shl 3);
  Result:=Result xor (Result shr 11);
  Result:=Result+(Result shl 15);
 end;
end;

 // Arash Partow
 // http://www.partow.net/programming/hashfunctions
function Hash32_AP(key:PChar; len:Integer):Cardinal;
var i:Integer;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=$AAAAAAAA;
  for i:=0 to len-1 do begin
   if ((i and 1)=0)
   then Result:=Result xor ((Result shl 7) xor Byte(key[i]) * (Result shr 3))
   else Result:=Result xor (not((Result shl 11) + (Byte(key[i]) xor (Result shr 5))));
  end;
 end;
end;

 // Aleksandr Sharahov
 // http://www.guildalfa.ru/alsha/node/32
function Hash32_ALSHA1(key:PChar; len:Integer):Cardinal;
var a:Cardinal; const b=378551;
begin
 Result:=0;
 if Assigned(key) then begin
  a:=$b612afe9;
  while (len>0) do begin
   Result:=(Result+Byte(key[0]))*a; a:=a*b;
   inc(key); dec(len);
  end;
  //Result:=Result*$560ced27;
 end;
end;

 // Aleksandr Sharahov
 // http://www.guildalfa.ru/alsha/node/32
function Hash32_ALSHA2(key:PChar; len:Integer):Cardinal;
const PerfCA=$59D65D2F; PerfCM=$3E0F83E1;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Byte(key[0])+(Result+PerfCA))*PerfCM;
   inc(key); dec(len);
  end;
  //Result:=Result*$a8c6c567;
 end;
end;

 // Austin Appleby
 // http://www.guildalfa.ru/alsha/node/32
function Hash32_MURMUR3(key:PChar; len:Integer):Cardinal;
const MurC1=$CC9E2D51; MurC2=$1B873593; MurC3=$E6546B64; MurC4=$85EBCA6B;
      MurC5=$C2B2AE35; MurCM:array[0..3] of Cardinal= (0, $FF, $FFFF, $FFFFFF);
var i:Integer; v:Cardinal;
begin
 Result:=0;
 if Assigned(key) and (len>0) then begin
  i:=len;
  while i>=4 do begin
   v:=PCardinal(key)^ * MurC1;
   Result:=(v shl 15 or v shr (32-15)) * MurC2 xor Result;
   inc(key,4); dec(i,4);
   Result:=(Result shl 13 or Result shr (32-13)) * 5 + MurC3;
  end;
  Result:=Result xor Cardinal(len);
  if i>0 then begin;
   v:=(MurCM[i] and PCardinal(key)^) * MurC1;
   Result:=(v shl 15 or v shr (32-15)) * MurC2 xor Result;
  end;
  Result:=((Result shr 16) xor Result) * MurC4;
  Result:=((Result shr 13) xor Result) * MurC5;
  Result:=(Result shr 16) xor Result;
 end;
end;

 // Austin Appleby
 // http://www.guildalfa.ru/alsha/node/32
function Hash32_MURMUR3_ASM(key:PChar; len:Integer):Cardinal;
const C1=integer($CC9E2D51); C2=integer($1B873593); C3=integer($E6546B64); C4=integer($85EBCA6B);
      C5=integer($C2B2AE35); CM:array[0..3] of integer=(0, $FF, $FFFF, $FFFFFF);
asm
  test  eax, eax               // if key=nil
  jz    @zero                  // then exit
  mov   ecx, eax               // key = current (first) position
  xor   eax, eax               // Result=0
  test  edx, edx
  jle   @zero
  push  ebx
  push  edx                    // save len
  and   edx, -4
  jz    @loopdone
  add   edx, ecx               // tail position
@loop:                         // while i>=4 do begin;
  imul  ebx, [ecx], C1         // v:=p^ * C1
  add   ecx, 4
  rol   ebx, 15                // Result:=(v shl 15 or v shr (32-15)) * C2 xor Result;
  imul  ebx, ebx, C2
  xor   eax, ebx
  rol   eax, 13                //Result:=(Result shl 13 or Result shr (32-13)) * 5 + C3;
  lea   eax, [eax+4*eax+C3]
  cmp   ecx, edx
  jne   @loop
@loopdone:
  pop   edx                    //get len
  xor   eax, edx               //Result:=Result xor len;
  and   edx, 3                 //if i>0 then begin;
  jz    @taildone
  mov   ecx, dword ptr [ecx]   //v:=p^; load tail
  and   ecx, dword ptr [4*edx+CM]
  imul  ecx, ecx, C1           //v:=v * C1;
  rol   ecx, 15                //Result:=(v shl 15 or v shr (32-15)) * C2 xor Result;
  imul  ecx, ecx, C2
  xor   eax, ecx
@taildone:
  mov   ecx, eax               //Result:=((Result shr 16) xor Result) * C4;
  shr   ecx, 16
  xor   ecx, eax
  imul  ecx, ecx, C4
  mov   eax, ecx               //Result:=((Result shr 13) xor Result) * C5;
  shr   eax, 13
  xor   eax, ecx
  imul  eax, eax, C5
  mov   ecx, eax               //Result:=(Result shr 16) xor Result;
  shr   ecx, 16
  xor   eax, ecx
@done:
  pop   ebx
@zero:
end;

 // Brian Kernighan and Dennis Ritchie
 // http://www.partow.net/programming/hashfunctions
function Hash32_BKDR131(key:PChar; len:Integer):Cardinal;
const a=131;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_BKDR31(key:PChar; len:Integer):Cardinal;
const a=31;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_BKDR1313(key:PChar; len:Integer):Cardinal;
const a=1313;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_BKDR13131(key:PChar; len:Integer):Cardinal;
const a=13131;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;
function Hash32_BKDR131313(key:PChar; len:Integer):Cardinal;
const a=131313;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Daniel J. Bernstein
 // http://www.partow.net/programming/hashfunctions
function Hash32_DJB(key:PChar; len:Integer):Cardinal;
const a=33;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=5381;
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Version of Hash32_DJB with shifts
function Hash32_DJB_SHF(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=5381;
  while (len>0) do begin
   Result:=((Result shl 5)+Result)+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Justin Sobel
 // http://www.partow.net/programming/hashfunctions
function Hash32_JS(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=1315423911;
  while (len>0) do begin
   Result:=Result xor ((Result shl 5)+Byte(key[0])+(Result shr 2));
   inc(key); dec(len);
  end;
 end;
end;

 // http://www.lua.org/ftp/lua-5.3.3.tar.gz
function Hash32_LUA(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result xor ((Result shl 5)+(Result shr 2)+Byte(key[0]));
   inc(key); dec(len);
  end;
 end;
end;

 // https://sohabr.net/post/219139/
function Hash32_H37(key:PChar; len:Integer):Cardinal;
const a=37;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=2139062143;
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // http://www.delphiplus.org/fundamentalnie-algoritmy-i-struktury-dannih/prostaya-funkciya-heshirovaniya-dlya-strok.html
function Hash32_TDH17(key:PChar; len:Integer):Cardinal;
const a=17;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result*a+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // http://www.delphiplus.org/fundamentalnie-algoritmy-i-struktury-dannih/funkcii-heshirovaniya-pjw.html
function Hash32_TDPJW(key:PChar; len:Integer):Cardinal;
var test:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 4)+Byte(key[0]); test:=Result and $F0000000;
   if (test<>0) then Result:=(Result xor (test shr 24)) xor test;
   inc(key); dec(len);
  end;
 end;
end;

 // Peter J. Weinberger of AT&T Bell Labs
 // http://www.partow.net/programming/hashfunctions
function Hash32_PJW(key:PChar; len:Integer):Cardinal;
var test:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 4)+Byte(key[0]); test:=Result and $f0000000;
   if test<>0 then Result:=(Result xor (test shr 24)) and not test;
   inc(key); dec(len);
  end;
 end;
end;

 // https://ru.wikipedia.org/wiki/PJW-32
function Hash32_PJW32(key:PChar; len:Integer):Cardinal;
var test:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 4)+Byte(key[0]); test:=Result and $f0000000;
   if test<>0 then Result:=(Result xor (test shr 24)) and $fffffff;
   inc(key); dec(len);
  end;
 end;
end;

 // Used in UNIX ELF format
 // http://www.partow.net/programming/hashfunctions
function Hash32_ELF(key:PChar; len:Integer):Cardinal;
var test:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 4)+Byte(key[0]); test:=Result and $f0000000;
   if test<>0 then Result:=(Result xor (test shr 24));
   Result:=Result and not test;
   inc(key); dec(len);
  end;
 end;
end;

 // Donald E. Knuth
 // http://www.partow.net/programming/hashfunctions
function Hash32_DEK(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=Cardinal(len);
  while (len>0) do begin
   Result:=((Result shl 5) xor (Result shr 27)) xor Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Unknown
 // https://github.com/liushoukai/node-hashes
function Hash32_BP(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=(Result shl 7) xor Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // Worst hash, just for comparioson and calibration
 // http://www.cse.yorku.ca/~oz/hash.html
function Hash32_LOSER(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result+Byte(key[0]);
   inc(key); dec(len);
  end;
 end;
end;

 // From JEDI Code Library JCL 2.7, see https://github.com/project-jedi/jedi
 // from "Fast Hashing of Variable-Length Text Strings", Peter K. Pearson, 1990
 // http://portal.acm.org/citation.cfm?id=78978
function Hash32_JCL(key:PChar; len:Integer):Cardinal;
const // table of byte permutations without inner loop
 BytePermTable: array [Byte] of Byte = (
  22,  133, 0,   244, 194, 193, 4,   164, 69,  211, 166, 235, 75,  110, 9,   140,
  125, 84,  64,  209, 57,  47,  197, 76,  237, 48,  189, 87,  221, 254, 20,  132,
  25,  162, 203, 225, 186, 165, 72,  228, 61,  208, 158, 185, 114, 173, 1,   66,
  202, 46,  198, 214, 27,  161, 178, 238, 8,   68,  97,  17,  199, 210, 96,  196,
  85,  240, 233, 71,  232, 142, 148, 70,  184, 152, 90,  206, 139, 182, 34,  101,
  104, 12,  143, 227, 24,  247, 175, 150, 39,  31,  36,  123, 62,  119, 236, 28,
  117, 100, 230, 223, 30,  154, 18,  153, 127, 192, 176, 19,  174, 134, 2,   216,
  218, 91,  45,  7,   128, 138, 126, 40,  16,  54,  207, 181, 11,  137, 60,  191,
  51,  231, 121, 213, 86,  111, 141, 172, 98,  226, 179, 249, 136, 58,  88,  93,
  201, 195, 118, 144, 146, 113, 212, 32,  21,  131, 177, 33,  151, 130, 205, 171,
  92,  251, 168, 29,  156, 124, 224, 200, 3,   187, 105, 52,  239, 147, 82,  94,
  26,  102, 243, 242, 145, 163, 49,  135, 43,  78,  112, 83,  63,  35,  170, 167,
  250, 159, 73,  37,  6,   79,  106, 215, 129, 74,  109, 42,  41,  120, 23,  160,
  107, 180, 103, 77,  53,  169, 89,  149, 44,  38,  81,  246, 188, 67,  15,  80,
  155, 99,  95,  5,   229, 108, 13,  255, 59,  241, 252, 245, 222, 248, 115, 55,
  217, 56,  65,  219, 204, 190, 10,  50,  253, 183, 234, 116, 122, 220, 14,  157);
type TIntegerHash = packed record case Byte of 0:(H1,H2,H3,H4:Byte); 1:(H:Integer); end;
var C:Byte;
begin
 Result:=0;
 if Assigned(key) then with TIntegerHash(Result) do begin
  H1:=0; H2:=1; H3:=2; H4:=3;
  while (len>0)  do begin
   C:=Byte(key[0]);
   H1 := BytePermTable[H1 xor C];
   H2 := BytePermTable[H2 xor C];
   H3 := BytePermTable[H3 xor C];
   H4 := BytePermTable[H4 xor C];
   inc(key); dec(len);
  end;
  Result := H and MaxInt;
 end;
end;

 // Alexander Myasnikov
 // http://burtleburtle.net/bob/hash/doobs.html
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_Goulburn(key:PChar; len:Integer):Cardinal;
const g_table0 : array [0..255] of Cardinal = (
  4143812366, 2806512183, 4212398656,  393834663, 3943187971,  847901099, 3746904015, 2990585247,
  4243977488, 4075301976, 2737181671, 2429701352, 4196558752, 3152011060, 1432515895,  204108242,
  1180540305,  922583281, 1734842702, 1453807349,  507756934, 1553886700, 2005976083, 3346025117,
    97642817, 2510760451, 4103916440, 3222467334, 1312447049,  522841194, 3955607179, 3028936967,
  2763655970, 3033075496, 1935362065,  512912210, 2660383701, 1652921526,  260485165,  141882627,
  2895806269,  804034013, 1356707616, 3942447612, 2875374199,   81028672, 1055595160, 2755907176,
  2880512448, 1232977841, 3719796487, 2940441976, 3739585976,  168332576, 1318372270, 3173546601,
  3992298512, 3785690335, 3667530757, 3101895251, 2789438017, 3213463724, 3067100319, 2554433152,
   794184286, 2599814956, 1251486151, 4214997752,  690900134,  323888098, 1537487787, 1155362310,
  1826165850, 2358083425, 2957662097, 2514517438, 1828367703, 3847031274, 2308450901,  955547506,
  1037823031, 2922505570, 2544914051, 2572931499,  442837508, 1873354958, 2004376537,   25413657,
  3560636876, 1768043132, 2870782748, 1031556958,  715180405,  201079975, 4116730284, 2748714587,
  1091411202,   33354499, 1931487277, 1039106939, 3327011403,  396608379, 3447523131,  301432924,
  3180185526, 1780290520, 3909968679, 2398211959, 3704875308,   66082280,  601805180, 3226323057,
  3284786200, 2282257088,  700775591, 3528928994, 1601645543,  120115228,  568698020,  178214456,
    41846783,  897656032, 3309570546, 2624714322, 2542948622, 1168171675, 2460933760,   93808223,
  2384991231, 4268721795, 4001720080, 1516739672, 4111847489,  810915309, 1238071781,  935043360,
  2020231594,   37717498, 3603218947, 1534593867, 2819275526, 1965883441,  674162751,  128087286,
  4138356188,  543626850, 1355906380, 3565721429, 1142978716, 1614752605, 1624389156, 3363454971,
  2029311310, 2249603714, 3448236784, 1764058505, 2198836711, 3481576182, 3168665556, 3834682664,
  1979945243, 3456525349, 2721891322, 1099639387, 1528675965, 3069012165, 1807951214, 1901014398,
  2805656341, 3321210152, 2317543573, 1015607418,  178584554, 4020226276,  492648819,   97778844,
  4134244261, 1389599433,  331211243, 3769684011, 2036127367, 3174548433, 3241354897, 2570869934,
  3071842004, 1972073698,   48467379, 1015444026, 3126762609, 1104264591, 3096375666, 1380392409,
   684368280, 1493310388, 2109527660, 3034364089, 3168522906, 3042350939, 3696929834, 3410250713,
  3726870750, 3357455860, 1816295563, 2678332086,   26178399,  614899533, 2248041911, 1431155883,
  1184971826, 3711847923, 2744489682, 168580352,   694400736, 2659092308,  811197288, 1093111228,
   824677015, 2041709752, 1650020171, 2344240270, 3773698958, 3393428365, 3498636527,  556541408,
  1883820721, 3249806350, 3635420446, 1661145756, 3087642385, 1620143845, 3852949019, 1054565053,
  3574021829, 2466085457, 2078148836, 460565767,  4097474724, 1381665351, 1652238922, 2200252397,
  3726797486, 4001080204,  259576503, 567653141,   325219513, 1227314237, 3191441965, 1433728871,
  4198425173, 2908977223, 3757065246, 294312130,  4136006097, 3409363054, 2112383431, 1177366649);
const g_table1 : array[0..127] of Cardinal = (
   826524031,  360568984, 3001046685, 1511935255, 1287825396, 3167385669, 1488463483, 4077470910,
  1360843071,  986771770, 2307292828, 3845679814, 1429883439, 1990257475, 4087625806, 1700033651,
  1388994450,  935547107, 3237786789,  644530675, 2274037095,  888755779, 3020158166, 2136355264,
  2558959443, 1751931693, 2325730565, 3029134627,  668542860, 2140243729, 2384660990,  666440934,
   842610975, 1563602260, 1429103271,  899918690, 3441536151, 4078621296, 1527765522, 4191433361,
   222526771,  309447417, 2035245353, 3730203536, 3330019758,  876252573, 2545027471,  453932528,
   282738293, 1826993794, 1569532013,  543681326, 3097574376, 2336551794, 1563241416, 1127019882,
  3088670038, 2766122176, 3706267663, 1110947226, 2608363541, 3166834418, 1310161541,  755904436,
  2922000163, 3815555181, 1578365408, 3137960721, 3254556244, 4287631844,  750375141, 1481489491,
  1903967768, 3684774106,  765971482, 3225162750, 2946561128, 1920278401, 1803486497, 4166913456,
  1855615192, 1934651772, 1736560291, 2101779280, 3560837687, 3004438879,  804667617, 2969326308,
  3118017313, 3090405800,  566615197, 2451279063, 4029572038, 2612593078, 3831703462,  914594646,
  2873305199, 2860901605, 3296630085, 1273702937, 2852911938, 1003268745, 1387783190,  159227777,
  2211994285,   28095103, 3659848176, 3976935977, 3301276082, 2641346573,  651238838, 2264520966,
  1484747269, 3016251036, 3857206301,   91952846, 1662449304, 2028491746, 1613452911, 2409055848,
  1453868667, 4146146473, 1646176015, 3769580099, 3171524988, 2980516679,  828895558, 3384493282);
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result:=Result+g_table0[Byte(key[0])];
   Result:=Result xor ( (Result shl  3) xor (Result shr 29) );
   Result:=Result+g_table1[Result shr 25 ];
   Result:=Result xor ( (Result shl 14) xor (Result shr 18) );
   Result:=Result+1783936964;
   inc(key); dec(len);
  end;
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_OneAtTime(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  while (len>0) do begin
   Result := Result + Byte(key[0]);
   Result := Result + (Result shl 10);
   Result := Result xor (Result shr 6);
   inc(key); dec(len);
  end;
  Result := Result + (Result shl 3);
  Result := Result xor (Result shr 11);
  Result := Result + (Result shl 15);
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_SBOX(key:PChar; len:Integer):Cardinal;
const SBOX_table : array [0..255] of Cardinal = (
  $4660c395, $3baba6c5, $27ec605b, $dfc1d81a, $aaac4406, $3783e9b8, $a4e87c68, $62dc1b2a,
  $a8830d34, $10a56307, $4ba469e3, $54836450, $1b0223d4, $23312e32, $c04e13fe, $3b3d61fa,
  $dab2d0ea, $297286b1, $73dbf93f, $6bb1158b, $46867fe2, $b7fb5313, $3146f063, $4fd4c7cb,
  $a59780fa, $9fa38c24, $38c63986, $a0bac49f, $d47d3386, $49f44707, $a28dea30, $d0f30e6d,
  $d5ca7704, $934698e3, $1a1ddd6d, $fa026c39, $d72f0fe6, $4d52eb70, $e99126df, $dfdaed86,
  $4f649da8, $427212bb, $c728b983, $7ca5d563, $5e6164e5, $e41d3a24, $10018a23, $5a12e111,
  $999ebc05, $f1383400, $50b92a7c, $a37f7577, $2c126291, $9daf79b2, $dea086b1, $85b1f03d,
  $598ce687, $f3f5f6b9, $e55c5c74, $791733af, $39954ea8, $afcff761, $5fea64f1, $216d43b4,
  $d039f8c1, $a6cf1125, $c14b7939, $b6ac7001, $138a2eff, $2f7875d6, $fe298e40, $4a3fad3b,
  $066207fd, $8d4dd630, $96998973, $e656ac56, $bb2df109, $0ee1ec32, $03673d6c, $d20fb97d,
  $2c09423c, $093eb555, $ab77c1e2, $64607bf2, $945204bd, $e8819613, $b59de0e3, $5df7fc9a,
  $82542258, $fb0ee357, $da2a4356, $5c97ab61, $8076e10d, $48e4b3cc, $7c28ec12, $b17986e1,
  $01735836, $1b826322, $6602a990, $7c1cef68, $e102458e, $a5564a67, $1136b393, $98dc0ea1,
  $3b6f59e5, $9efe981d, $35fafbe0, $c9949ec2, $62c765f9, $510cab26, $be071300, $7ee1d449,
  $cc71beef, $fbb4284e, $bfc02ce7, $df734c93, $2f8cebcd, $feedc6ab, $5476ee54, $bd2b5ff9,
  $f4fd0352, $67f9d6ea, $7b70db05, $5a5f5310, $482dd7aa, $a0a66735, $321ae71f, $8e8ad56c,
  $27a509c3, $1690b261, $4494b132, $c43a42a7, $3f60a7a6, $d63779ff, $e69c1659, $d15972c8,
  $5f6cdb0c, $b9415af2, $1261ad8d, $b70a6135, $52ceda5e, $d4591dc3, $442b793c, $e50e2dee,
  $6f90fc79, $d9ecc8f9, $063dd233, $6cf2e985, $e62cfbe9, $3466e821, $2c8377a2, $00b9f14e,
  $237c4751, $40d4a33b, $919df7e8, $a16991a4, $c5295033, $5c507944, $89510e2b, $b5f7d902,
  $d2d439a6, $c23e5216, $d52d9de3, $534a5e05, $762e73d4, $3c147760, $2d189706, $20aa0564,
  $b07bbc3b, $8183e2de, $ebc28889, $f839ed29, $532278f7, $41f8b31b, $762e89c1, $a1e71830,
  $ac049bfc, $9b7f839c, $8fd9208d, $2d2402ed, $f1f06670, $2711d695, $5b9e8fe4, $dc935762,
  $a56b794f, $d8666b88, $6872c274, $bc603be2, $2196689b, $5b2b5f7a, $00c77076, $16bfa292,
  $c2f86524, $dd92e83e, $ab60a3d4, $92daf8bd, $1fe14c62, $f0ff82cc, $c0ed8d0a, $64356e4d,
  $7e996b28, $81aad3e8, $05a22d56, $c4b25d4f, $5e3683e5, $811c2881, $124b1041, $db1b4f02,
  $5a72b5cc, $07f8d94e, $e5740463, $498632ad, $7357ffb1, $0dddd380, $3d095486, $2569b0a9,
  $d6e054ae, $14a47e22, $73ec8dcc, $004968cf, $e0c3a853, $c9b50a03, $e1b0eb17, $57c6f281,
  $c9f9377d, $43e03612, $9a0c4554, $bb2d83ff, $a818ffee, $f407db87, $175e3847, $5597168f,
  $d3d547a7, $78f3157c, $fc750f20, $9880a1c6, $1af41571, $95d01dfc, $a3968d62, $eae03cf8,
  $02ee4662, $5f1943ff, $252d9d1c, $6b718887, $e052f724, $4cefa30b, $dcc31a00, $e4d0024d,
  $dbb4534a, $ce01f5c8, $0c072b61, $5d59736a, $60291da4, $1fbe2c71, $2f11d09c, $9dce266a);
begin
 Result:=0;
 if Assigned(key) then begin
  Result:=Cardinal(len);
  while (len>1) do begin
   Result := ( ( ( Result xor SBOX_table[Byte(key[0])] ) * 3 ) xor SBOX_table[Byte(key[1])] ) * 3;
   inc(key,2); dec(len,2);
  end;
  if (len>0) then Result := ( Result xor SBOX_table[Byte(key[0])] ) * 3;
  Result := Result + (( Result shr 22 ) xor ( Result shl 4 ));
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_Crap8(key:PChar; len:Integer):Cardinal;
const m=$83d2e73b; n=$97e1cc59; cf:array[0..3] of Cardinal=(0,$FF,$FFFF,$FFFFFF);
var h,k,x:Cardinal; key4:PCardinal; p:Int64;
type Int64Rec=record lo,hi:Cardinal; end;
begin
 Result:=0;
 if Assigned(key) then begin
  Pointer(key4):=Pointer(key);
  h:=Cardinal(len); k:=n+Cardinal(len);
  while ( len >= 8 ) do begin
   h:=h*m; x:=key4^; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi; inc(key4);
   h:=h*m; x:=key4^; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi; inc(key4);
   dec(len,8);
  end;
  if ( len >= 4 ) then begin
   h:=h*m; x:=key4^; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi; inc(key4);
   dec(len,4);
  end;
  if ( len>0 ) then begin
   h:=h*m; x:=key4^ and cf[len]; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi;
  end;
  x:=h xor k; p:=x*Int64(n); k:=k xor Int64Rec(p).Lo; k:=k xor Int64Rec(p).Hi;
  Result:=k;
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_CrapWow(key:PChar; len:Integer):Cardinal;
const m=$57559429; n=$5052acdb; cf:array[0..3] of Cardinal=(0,$FF,$FFFF,$FFFFFF);
var h,k,x:Cardinal; key4:PCardinal; p:Int64;
type Int64Rec=record lo,hi:Cardinal; end;
begin
 Result:=0;
 if Assigned(key) then begin
  Pointer(key4):=Pointer(key);
  h:=Cardinal(len); k:=len+n;
  while ( len >= 8 ) do begin
   x:=key4^; p:=x*Int64(n); h:=h xor Int64Rec(p).Lo; k:=k xor Int64Rec(p).Hi; inc(key4);
   x:=key4^; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi; inc(key4);
   dec(len,8);
  end;
  if ( len >= 4 ) then begin
   x:=key4^; p:=x*Int64(n); h:=h xor Int64Rec(p).Lo; k:=k xor Int64Rec(p).Hi; inc(key4);
   dec(len,4);
  end;
  if ( len>0 ) then begin
   x:=key4^ and cf[len]; p:=x*Int64(m); k:=k xor Int64Rec(p).Lo; h:=h xor Int64Rec(p).Hi;
  end;
  x:=h xor (k+n); p:=x*Int64(n); h:=h xor Int64Rec(p).Lo; k:=k xor Int64Rec(p).Hi;
  Result:=k xor h;
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_SuperFast(key:PChar; len:Integer):Cardinal;
var hash,tmp:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  hash:=len;
  if (len <= 0 ) or (key = nil) then begin Result:=0; Exit; end;
  // Main loop
  while ( len >= 4 ) do begin
   hash := hash + PWord(key)^;            inc(key,2);
   tmp  := (PWord(key)^ shl 11) xor hash; inc(key,2);
   hash := (hash shl 16) xor tmp;
   hash := hash + (hash shr 11);
   dec(len,4);
  end;
  // Handle end cases
  case (len) of
   3: begin
       hash := hash + PWord(key)^; inc(key,2);
       hash := hash xor (hash shl 16);
       hash := hash xor (PWord(key)^ shl 18);
       hash := hash + (hash shr 11);
      end;
   2: begin
       hash := hash + PWord(key)^;
       hash := hash xor (hash shl 11);
       hash := hash + (hash shr 17);
      end;
   1: begin
       hash := hash + Byte(key[0]);
       hash := hash xor (hash shl 10);
       hash := hash + (hash shr 1);
      end;
  end;
  // Force "avalanching" of final 127 bits
  hash := hash xor (hash shl 3);
  hash := hash +   (hash shr 5);
  hash := hash xor (hash shl 4);
  hash := hash +   (hash shr 17);
  hash := hash xor (hash shl 25);
  hash := hash +   (hash shr 6);
  Result:=hash;
 end;
end;

 // Alexander Myasnikov
 // http://amsoftware.narod.ru/algo/hashtest.zip
function Hash32_Murmur2(key:PChar; len:Integer):Cardinal;
const m=$5bd1e995; seed=0; r=24; var h,k:Cardinal;
begin
 Result:=0;
 if Assigned(key) then begin
  h:=seed xor len;
  while (len>=4) do begin
   k:=PCardinal(key)^;
   k:=k*m;
   k:=k xor (k shr r);
   k:=k*m;
   h:=h*m;
   h:=h xor k;
   inc(key,4);
   dec(len,4);
  end;
  case (len) of
   3: begin
       k:=PWord(key)^;
       k:=k or (Cardinal(key[2]) shl 16);
       h:=h xor k;
      end;
   2: begin
       k:=PWord(key)^;
       h:=h xor k;
       h:=h*m;
      end;
   1: begin
       k:=Byte(key[0]);
       h:=h xor k;
       h:=h*m;
      end;
  end;
  h:=h xor (h shr 13);
  h:=h*m;
  h:=h xor (h shr 15);
  Result:=h;
 end;
end;

 //////////////////////////////////////////////////////////////////////////////////////////
 // CRC32 checksum derived from http://crccalc.com/, https://github.com/meetanthony/crcjava
 //////////////////////////////////////////////////////////////////////////////////////////
type
 PCrcParams = ^TCrcParams;
 TCrcParams = record
  Name     : PChar;    // This is a name given to the algorithm. A string value.
  Check    : Cardinal; // The checksum obtained when the ASCII string "123456789" is fed through the specified algorithm.
  HashSize : Integer;  // This is hash size, bits.
  Init     : Cardinal; // This parameter specifies the initial value of the register when the algorithm starts.
  RefInit  : Cardinal; // Reflected Init.
  Poly     : Cardinal; // This parameter is the polynom.
  RefIn    : LongBool; // Reflected input.
  RefOut   : LongBool; // Reflected output.
  XorOut   : Cardinal; // XOR output
  Mask     : Cardinal; // AND output
  Table    : array[Byte] of Cardinal;
 end;

function ReverseBits(Source:Cardinal; SourceLength:Integer):Cardinal;
begin
 Result:=0;
 while (SourceLength>0) do begin
  Result := (Result shl 1) or (Source and 1);
  Source := (Source shr 1);
  dec(SourceLength);
 end;
end;

function CreateCrcTableEntry(const CrcParams:TCrcParams; index:Integer):Cardinal;
var r,LastBit:Cardinal; i:Integer;
begin
 r:=index;
 if CrcParams.RefIn then r := ReverseBits(r, CrcParams.HashSize) else
 if (CrcParams.HashSize > 8) then r := r shl (CrcParams.HashSize - 8);
 lastBit := (1 shl (CrcParams.HashSize - 1));
 for i := 0 to 7 do begin
  if ((r and lastBit) <> 0)
  then r := (r shl 1) xor CrcParams.Poly
  else r := (r shl 1);
 end;
 if CrcParams.RefOut then r := ReverseBits(r, CrcParams.HashSize);
 Result:= r and CrcParams.Mask;
end;

procedure InitCrcParams(var CrcParams:TCrcParams; Name:PChar; HashSize:Integer; Poly,Init:Cardinal; RefIn,RefOut:Boolean; XorOut,Check:Cardinal);
var i:Integer;
begin
 CrcParams.Name     := Name;
 CrcParams.Check    := Check;
 CrcParams.HashSize := HashSize;
 CrcParams.Init     := Init;
 CrcParams.RefInit  := ReverseBits(Init, HashSize);
 CrcParams.Poly     := Poly;
 CrcParams.RefIn    := RefIn;
 CrcParams.RefOut   := RefOut;
 CrcParams.XorOut   := XorOut;
 CrcParams.Mask     := High(CrcParams.Mask);
 if CrcParams.HashSize<SizeOf(CrcParams.Mask)*8 then CrcParams.Mask:=(1 shl CrcParams.HashSize)-1;
 for i:=Low(CrcParams.Table) to High(CrcParams.Table) do CrcParams.Table[i]:=CreateCrcTableEntry(CrcParams,i);
end;

function ComputeCrc(const CrcParams:TCrcParams; key:PChar; len:Integer):Cardinal;
var crc:Cardinal; toRight:Integer;
begin
 if CrcParams.RefOut then begin
  crc:=CrcParams.RefInit;
  while (len>0) do begin
   crc := CrcParams.Table[(crc xor Byte(key[0])) and $FF] xor (crc shr 8);
   crc := crc and CrcParams.Mask;
   inc(key); dec(len);
  end;
 end else begin
  crc := CrcParams.Init;
  if (CrcParams.HashSize > 8) then toRight := CrcParams.HashSize - 8 else toRight := 0;
  while (len>0) do begin
   crc := CrcParams.Table[((crc shr toRight) xor Byte(key[0])) and $FF] xor (crc shl 8);
   crc := crc and CrcParams.Mask;
   inc(key); dec(len);
  end;
 end;
 Result:= (crc xor CrcParams.XorOut) and CrcParams.Mask;
end;

const
 Crc8Params  : array of TCrcParams = nil;

procedure InitCrc8Params;
begin
 if Length(Crc8Params)=0 then begin
  SetLength(Crc8Params,10);
  //////////////////////////// Name              size poly init refin  refout xor  check
  InitCrcParams(Crc8Params[0], 'CRC-8',          8,   $07, $00, false, false, $00, $F4);
  InitCrcParams(Crc8Params[1], 'CRC-8/CDMA2000', 8,   $9B, $FF, false, false, $00, $DA);
  InitCrcParams(Crc8Params[2], 'CRC-8/DARC',     8,   $39, $00, true,  true,  $00, $15);
  InitCrcParams(Crc8Params[3], 'CRC-8/DVB-S2',   8,   $D5, $00, false, false, $00, $BC);
  InitCrcParams(Crc8Params[4], 'CRC-8/EBU',      8,   $1D, $FF, true,  true,  $00, $97);
  InitCrcParams(Crc8Params[5], 'CRC-8/I-CODE',   8,   $1D, $FD, false, false, $00, $7E);
  InitCrcParams(Crc8Params[6], 'CRC-8/ITU',      8,   $07, $00, false, false, $55, $A1);
  InitCrcParams(Crc8Params[7], 'CRC-8/MAXIM',    8,   $31, $00, true,  true,  $00, $A1);
  InitCrcParams(Crc8Params[8], 'CRC-8/ROHC',     8,   $07, $FF, true,  true,  $00, $D0);
  InitCrcParams(Crc8Params[9], 'CRC-8/WCDMA',    8,   $9B, $00, true,  true,  $00, $25);
 end;
end;

procedure FreeCrc8Params;
begin
 SetLength(Crc8Params,0);
end;

function Hash32_Crc8(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[0],key,len);
end;

function Hash32_Crc8Cdma2000(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[1],key,len);
end;

function Hash32_Crc8Darc(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[2],key,len);
end;

function Hash32_Crc8Dvbs2(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[3],key,len);
end;

function Hash32_Crc8Ebu(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[4],key,len);
end;

function Hash32_Crc8Icode(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[5],key,len);
end;

function Hash32_Crc8Itu(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[6],key,len);
end;

function Hash32_Crc8Maxim(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[7],key,len);
end;

function Hash32_Crc8Rohc(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[8],key,len);
end;

function Hash32_Crc8Wcdma(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc8Params)=0 then InitCrc8Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc8Params[9],key,len);
end;

const
 Crc16Params : array of TCrcParams = nil;

procedure InitCrc16Params;
begin
 if Length(Crc16Params)=0 then begin
  SetLength(Crc16Params,23);
  ////////////////////////////// Name                  size poly   init   refin  refout xor    check
  InitCrcParams(Crc16Params[0],  'CRC-16/CCITT-FALSE', 16,  $1021, $FFFF, false, false, $0000, $29B1);
  InitCrcParams(Crc16Params[1],  'CRC-16/ARC',         16,  $8005, $0000, true,  true,  $0000, $BB3D);
  InitCrcParams(Crc16Params[2],  'CRC-16/AUG-CCITT',   16,  $1021, $1D0F, false, false, $0000, $E5CC);
  InitCrcParams(Crc16Params[3],  'CRC-16/BUYPASS',     16,  $8005, $0000, false, false, $0000, $FEE8);
  InitCrcParams(Crc16Params[4],  'CRC-16/CDMA2000',    16,  $C867, $FFFF, false, false, $0000, $4C06);
  InitCrcParams(Crc16Params[5],  'CRC-16/DDS-110',     16,  $8005, $800D, false, false, $0000, $9ECF);
  InitCrcParams(Crc16Params[6],  'CRC-16/DECT-R',      16,  $0589, $0000, false, false, $0001, $007E);
  InitCrcParams(Crc16Params[7],  'CRC-16/DECT-X',      16,  $0589, $0000, false, false, $0000, $007F);
  InitCrcParams(Crc16Params[8],  'CRC-16/DNP',         16,  $3D65, $0000, true,  true,  $FFFF, $EA82);
  InitCrcParams(Crc16Params[9],  'CRC-16/EN-13757',    16,  $3D65, $0000, false, false, $FFFF, $C2B7);
  InitCrcParams(Crc16Params[10], 'CRC-16/GENIBUS',     16,  $1021, $FFFF, false, false, $FFFF, $D64E);
  InitCrcParams(Crc16Params[11], 'CRC-16/MAXIM',       16,  $8005, $0000, true,  true,  $FFFF, $44C2);
  InitCrcParams(Crc16Params[12], 'CRC-16/MCRF4XX',     16,  $1021, $FFFF, true,  true,  $0000, $6F91);
  InitCrcParams(Crc16Params[13], 'CRC-16/RIELLO',      16,  $1021, $B2AA, true,  true,  $0000, $63D0);
  InitCrcParams(Crc16Params[14], 'CRC-16/T10-DIF',     16,  $8BB7, $0000, false, false, $0000, $D0DB);
  InitCrcParams(Crc16Params[15], 'CRC-16/TELEDISK',    16,  $A097, $0000, false, false, $0000, $0FB3);
  InitCrcParams(Crc16Params[16], 'CRC-16/TMS37157',    16,  $1021, $89EC, true,  true,  $0000, $26B1);
  InitCrcParams(Crc16Params[17], 'CRC-16/USB',         16,  $8005, $FFFF, true,  true,  $FFFF, $B4C8);
  InitCrcParams(Crc16Params[18], 'CRC-A',              16,  $1021, $c6c6, true,  true,  $0000, $BF05);
  InitCrcParams(Crc16Params[19], 'CRC-16/KERMIT',      16,  $1021, $0000, true,  true,  $0000, $2189);
  InitCrcParams(Crc16Params[20], 'CRC-16/MODBUS',      16,  $8005, $FFFF, true,  true,  $0000, $4B37);
  InitCrcParams(Crc16Params[21], 'CRC-16/X-25',        16,  $1021, $FFFF, true,  true,  $FFFF, $906E);
  InitCrcParams(Crc16Params[22], 'CRC-16/XMODEM',      16,  $1021, $0000, false, false, $0000, $31C3);
 end;
end;

procedure FreeCrc16Params;
begin
 SetLength(Crc16Params,0);
end;

function Hash32_Crc16CcittFalse(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[0],key,len);
end;

function Hash32_Crc16Arc(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[1],key,len);
end;

function Hash32_Crc16AugCcitt(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[2],key,len);
end;

function Hash32_Crc16Buypass(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[3],key,len);
end;

function Hash32_Crc16Cdma2000(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[4],key,len);
end;

function Hash32_Crc16Dds110(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[5],key,len);
end;

function Hash32_Crc16DectR(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[6],key,len);
end;

function Hash32_Crc16DectX(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[7],key,len);
end;

function Hash32_Crc16Dnp(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[8],key,len);
end;

function Hash32_Crc16En13757(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[9],key,len);
end;

function Hash32_Crc16Genibus(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[10],key,len);
end;

function Hash32_Crc16Maxim(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[11],key,len);
end;

function Hash32_Crc16Mcrf4xx(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[12],key,len);
end;

function Hash32_Crc16Riello(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[13],key,len);
end;

function Hash32_Crc16T10dif(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[14],key,len);
end;

function Hash32_Crc16Teledisk(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[15],key,len);
end;

function Hash32_Crc16Tms37157(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[16],key,len);
end;

function Hash32_Crc16Usb(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[17],key,len);
end;

function Hash32_Crc16A(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[18],key,len);
end;

function Hash32_Crc16Kermit(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[19],key,len);
end;

function Hash32_Crc16Modbus(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[20],key,len);
end;

function Hash32_Crc16X25(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[21],key,len);
end;

function Hash32_Crc16Xmodem(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc16Params)=0 then InitCrc16Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc16Params[22],key,len);
end;

const
 Crc32Params : array of TCrcParams = nil;

procedure InitCrc32Params;
begin
 if Length(Crc32Params)=0 then begin
  SetLength(Crc32Params,9);
  ///////////////////////////// Name             size poly       init       refin  refout xor        check
  InitCrcParams(Crc32Params[0], 'CRC-32',        32,  $04C11DB7, $FFFFFFFF, true,  true,  $FFFFFFFF, $CBF43926);
  InitCrcParams(Crc32Params[1], 'CRC-32/BZIP2',  32,  $04C11DB7, $FFFFFFFF, false, false, $FFFFFFFF, $FC891918);
  InitCrcParams(Crc32Params[2], 'CRC-32C',       32,  $1EDC6F41, $FFFFFFFF, true,  true,  $FFFFFFFF, $E3069283);
  InitCrcParams(Crc32Params[3], 'CRC-32D',       32,  $A833982B, $FFFFFFFF, true,  true,  $FFFFFFFF, $87315576);
  InitCrcParams(Crc32Params[4], 'CRC-32/JAMCRC', 32,  $04C11DB7, $FFFFFFFF, true,  true,  $00000000, $340BC6D9);
  InitCrcParams(Crc32Params[5], 'CRC-32/MPEG-2', 32,  $04C11DB7, $FFFFFFFF, false, false, $00000000, $0376E6E7);
  InitCrcParams(Crc32Params[6], 'CRC-32/POSIX',  32,  $04C11DB7, $00000000, false, false, $FFFFFFFF, $765E7680);
  InitCrcParams(Crc32Params[7], 'CRC-32Q',       32,  $814141AB, $00000000, false, false, $00000000, $3010BF7F);
  InitCrcParams(Crc32Params[8], 'CRC-32/XFER',   32,  $000000AF, $00000000, false, false, $00000000, $BD0BE338);
 end;
end;

procedure FreeCrc32Params;
begin
 SetLength(Crc32Params,0);
end;

function Hash32_Crc32(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[0],key,len);
end;

function Hash32_Crc32Bzip2(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[1],key,len);
end;

function Hash32_Crc32C(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[2],key,len);
end;

function Hash32_Crc32D(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[3],key,len);
end;

function Hash32_Crc32Jamcrc(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[4],key,len);
end;

function Hash32_Crc32Mpeg2(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[5],key,len);
end;

function Hash32_Crc32Posix(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[6],key,len);
end;

function Hash32_Crc32Q(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[7],key,len);
end;

function Hash32_Crc32Xfer(key:PChar; len:Integer):Cardinal;
begin
 Result:=0; if Length(Crc32Params)=0 then InitCrc32Params;
 if Assigned(key) and (len>0) then Result:=ComputeCrc(Crc32Params[8],key,len);
end;

procedure InitCrcAllParams;
begin
 InitCrc8Params;
 InitCrc16Params;
 InitCrc32Params;
end;

procedure FreeCrcAllParams;
begin
 FreeCrc8Params;
 FreeCrc16Params;
 FreeCrc32Params;
end;

 // Calculate MODBUS/ASCII LRC checksum.
 // https://en.wikipedia.org/wiki/Longitudinal_redundancy_check
function Hash32_ModbusLrc(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) and (len>0) then begin
  while (len>0) do begin
   Result:=(Result+Byte(key[0])) and $FF;
   inc(key); dec(len);
  end;
  Result:=((Result xor $FF)+1) and $FF;
 end;
end;

 // Calculate MODBUS/RTU CRC checksum.
function Hash32_ModbusCrc(key:PChar; len:Integer):Cardinal;
var j:Integer;
begin
 Result:=0;
 if Assigned(key) and (len>0) then begin
  Result:=$FFFF;
  while (len>0) do begin
   Result:=Result xor Byte(key[0]);
   for j:=1 to 8 do if (Result and 1)<>0
   then Result:=(Result shr 1) xor $A001
   else Result:=(Result shr 1);
   inc(key); dec(len);
  end;
  Result:=Result and $FFFF;
 end;
end;

 // Calculate DCON checksum.
function Hash32_Dcon(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) and (len>0) then begin
  while (len>0) do begin
   Result:=Result+Byte(key[0]);
   inc(key); dec(len);
  end;
  Result:=Result and $FF;
 end;
end;

 // Calculate HART checksum.
function Hash32_Hart(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
 if Assigned(key) and (len>0) then begin
  while (len>0) do begin
   Result:=Result xor Byte(key[0]);
   inc(key); dec(len);
  end;
  Result:=Result and $FF;
 end;
end;

 // Zero hash just for software stress test
function Hash32_ZERO(key:PChar; len:Integer):Cardinal;
begin
 Result:=0;
end;

 //////////////////////////////////////////////////////////////////////////////////////////
 // Utility functions
 //////////////////////////////////////////////////////////////////////////////////////////
function FindIndexOfHasher(aHasherFunc:THash32Function):Integer;
var i:Integer;
begin
 Result:=-1;
 for i:=Low(Hash32FuncTable) to High(Hash32FuncTable) do
 if (@aHasherFunc=@Hash32FuncTable[i].Func) then
 begin Result:=i; break; end;
end;

function FindIndexOfHasher(aHasherName:LongString):Integer;
var i:Integer;
begin
 Result:=-1;
 for i:=Low(Hash32FuncTable) to High(Hash32FuncTable) do
 if SameText(aHasherName,Hash32FuncTable[i].Name) or SameText(aHasherName,'Hash32_'+Hash32FuncTable[i].Name)
 then begin Result:=i; break; end;
end;

function GetHasherByIndex(aIndex:Integer):THash32Function;
begin
 if (Low(Hash32FuncTable)<=aIndex) and (aIndex<=High(Hash32FuncTable))
 then Result:=Hash32FuncTable[aIndex].Func
 else Result:=nil;
end;

function GetHasherNameByIndex(aIndex:Integer):AnsiString;
begin
 if (Low(Hash32FuncTable)<=aIndex) and (aIndex<=High(Hash32FuncTable))
 then Result:=Hash32FuncTable[aIndex].Name
 else Result:='';
end;

 //////////////////////////////////////////////////////////////////////////////////////////
 // Hash function sanity test and benchmark to check correctness and performance.
 // [1] https://github.com/liushoukai/node-hashes/blob/master/test/hash.test.js
 // [2] https://github.com/liushoukai/node-hashes/blob/master/src/GeneralHashFunctions.cpp
 // [3] http://vak.ru/doku.php/proj/hash/conflicts
 // [4] http://vak.ru/doku.php/proj/hash/sources
 // [5] http://murmurhash.shorelabs.com/
 // [6] http://www.isthe.com/chongo/src/fnv/test_fnv.c
 /////////////////////////////////////////////////////////////////////////////////////////
function MakeHash32SanityTest(Echo:THash32EchoProc=nil):Integer;
const abcnum:PChar='abcdefghijklmnopqrstuvwxyz1234567890';
var Passed,Failed:Integer;
 procedure PrintLine(Line:LongString);
 begin
  if Assigned(Echo) then Echo(Line);
 end;
 procedure Test(name:PChar; func:THash32Function; key:PChar; expected:Cardinal);
 var hash:Cardinal;
 begin
  if Assigned(func) then
  if Assigned(name) then if StrLen(name)>0 then
  if Assigned(key)  then if StrLen(key)>0  then begin
   hash:=func(key,StrLen(key));
   if hash = expected then begin
    PrintLine(Format('Passed - %s'+CRLF,[name]));
    inc(Passed);
   end else begin
    PrintLine(Format('Failed - %s - %d<>%d'+CRLF,[name,hash,expected]));
    inc(Failed);
   end;
  end;
 end;
begin
 passed:=0; failed:=0;
 try
  PrintLine('MakeHash32SanityTest...'+CRLF);
  Test('Hash32_RS',              Hash32_RS,              abcnum,             4097835502); // [1]
  Test('Hash32_JS',              Hash32_JS,              abcnum,             1651003062); // [1]
  Test('Hash32_PJW',             Hash32_PJW,             abcnum,             126631744);  // [1]
  Test('Hash32_PJW32',           Hash32_PJW32,           abcnum,             126631744);  // [1]
  Test('Hash32_ELF',             Hash32_ELF,             abcnum,             126631744);  // [1]
  Test('Hash32_BKDR131',         Hash32_BKDR131,         abcnum,             3153586616); // [1]
  Test('Hash32_BKDR31',          Hash32_BKDR31,          abcnum,             2134697992); // [1]
  Test('Hash32_BKDR1313',        Hash32_BKDR1313,        abcnum,             1529523244); // [1]
  Test('Hash32_BKDR13131',       Hash32_BKDR13131,       abcnum,             2933456568); // [1]
  Test('Hash32_BKDR131313',      Hash32_BKDR131313,      abcnum,             2550573228); // [1]
  Test('Hash32_SDBM',            Hash32_SDBM,            abcnum,             3449571336); // [1]
  Test('Hash32_SDBM_SHF',        Hash32_SDBM_SHF,        abcnum,             3449571336); // [1]
  Test('Hash32_DJB',             Hash32_DJB,             abcnum,             729241521);  // [1]
  Test('Hash32_DJB_SHF',         Hash32_DJB_SHF,         abcnum,             729241521);  // [1]
  Test('Hash32_DEK',             Hash32_DEK,             abcnum,             2923964919); // [1]
  Test('Hash32_BP',              Hash32_BP,              abcnum,             1726880944); // [1]
  Test('Hash32_FNV',             Hash32_FNV,             abcnum,             3243095106); // [1]
  Test('Hash32_AP',              Hash32_AP,              abcnum,             882643939);  // [1]
  Test('Hash32_RS',              Hash32_RS,              'silicon',          $8c36aef3);  // [3]
  Test('Hash32_BKDR131313',      Hash32_BKDR131313,      'Mussorgsky',       $59dadc77);  // [3]
  Test('Hash32_SDBM',            Hash32_SDBM,            'set_enginetime',   $e105f84c);  // [3]
  Test('Hash32_SDBM_SHF',        Hash32_SDBM_SHF,        'set_enginetime',   $e105f84c);  // [3]
  Test('Hash32_LY',              Hash32_LY,              'eapol_sm_step',    $0947d7e6);  // [3]
  Test('Hash32_ROT13',           Hash32_ROT13,           'swinishness',      $df86d7c1);  // [3]
  Test('Hash32_ROT13_ASM',       Hash32_ROT13_ASM,       'swinishness',      $df86d7c1);  // [3]
  Test('Hash32_ROT13',           Hash32_ROT13,           'shopkeeper',       $3e6df6d9);  // [3]
  Test('Hash32_ROT13_ASM',       Hash32_ROT13_ASM,       'shopkeeper',       $3e6df6d9);  // [3]
  Test('Hash32_JENKINS',         Hash32_JENKINS,         'hci_ptypetostr',   $73aba9cf);  // [3]
  Test('Hash32_MURMUR3',         Hash32_MURMUR3,         abcnum,             $64528504);  // [5]
  Test('Hash32_MURMUR3_ASM',     Hash32_MURMUR3_ASM,     abcnum,             $64528504);  // [5]
  Test('Hash32_FNV0',            Hash32_FNV0,            'chongo was here!', $007c6c4c);  // [6]
  Test('Hash32_FNV1',            Hash32_FNV1,            'chongo was here!', $b10d5725);  // [6]
  Test('Hash32_FNV1A',           Hash32_FNV1A,           'chongo was here!', $448524fd);  // [6]
  Test('Hash32_Crc8',            Hash32_Crc8,            '123456789',        $F4);  // [30]
  Test('Hash32_Crc8Cdma2000',    Hash32_Crc8Cdma2000,    '123456789',        $DA);  // [30]
  Test('Hash32_Crc8Darc',        Hash32_Crc8Darc,        '123456789',        $15);  // [30]
  Test('Hash32_Crc8Dvbs2',       Hash32_Crc8Dvbs2,       '123456789',        $BC);  // [30]
  Test('Hash32_Crc8Ebu',         Hash32_Crc8Ebu,         '123456789',        $97);  // [30]
  Test('Hash32_Crc8Icode',       Hash32_Crc8Icode,       '123456789',        $7E);  // [30]
  Test('Hash32_Crc8Itu',         Hash32_Crc8Itu,         '123456789',        $A1);  // [30]
  Test('Hash32_Crc8Maxim',       Hash32_Crc8Maxim,       '123456789',        $A1);  // [30]
  Test('Hash32_Crc8Rohc',        Hash32_Crc8Rohc,        '123456789',        $D0);  // [30]
  Test('Hash32_Crc8Wcdma',       Hash32_Crc8Wcdma,       '123456789',        $25);  // [30]
  Test('Hash32_Crc16Ccittfalse', Hash32_Crc16Ccittfalse, '123456789',        $29B1);  // [30]
  Test('Hash32_Crc16Arc',        Hash32_Crc16Arc,        '123456789',        $BB3D);  // [30]
  Test('Hash32_Crc16AugCcitt',   Hash32_Crc16AugCcitt,   '123456789',        $E5CC);  // [30]
  Test('Hash32_Crc16Buypass',    Hash32_Crc16Buypass,    '123456789',        $FEE8);  // [30]
  Test('Hash32_Crc16Cdma2000',   Hash32_Crc16Cdma2000,   '123456789',        $4C06);  // [30]
  Test('Hash32_Crc16Dds110',     Hash32_Crc16Dds110,     '123456789',        $9ECF);  // [30]
  Test('Hash32_Crc16DectR',      Hash32_Crc16DectR,      '123456789',        $007E);  // [30]
  Test('Hash32_Crc16DectX',      Hash32_Crc16DectX,      '123456789',        $007F);  // [30]
  Test('Hash32_Crc16Dnp',        Hash32_Crc16Dnp,        '123456789',        $EA82);  // [30]
  Test('Hash32_Crc16En13757',    Hash32_Crc16En13757,    '123456789',        $C2B7);  // [30]
  Test('Hash32_Crc16Genibus',    Hash32_Crc16Genibus,    '123456789',        $D64E);  // [30]
  Test('Hash32_Crc16Maxim',      Hash32_Crc16Maxim,      '123456789',        $44C2);  // [30]
  Test('Hash32_Crc16Mcrf4xx',    Hash32_Crc16Mcrf4xx,    '123456789',        $6F91);  // [30]
  Test('Hash32_Crc16Riello',     Hash32_Crc16Riello,     '123456789',        $63D0);  // [30]
  Test('Hash32_Crc16T10dif',     Hash32_Crc16T10dif,     '123456789',        $D0DB);  // [30]
  Test('Hash32_Crc16Teledisk',   Hash32_Crc16Teledisk,   '123456789',        $0FB3);  // [30]
  Test('Hash32_Crc16Tms37157',   Hash32_Crc16Tms37157,   '123456789',        $26B1);  // [30]
  Test('Hash32_Crc16Usb',        Hash32_Crc16Usb,        '123456789',        $B4C8);  // [30]
  Test('Hash32_Crc16A',          Hash32_Crc16A,          '123456789',        $BF05);  // [30]
  Test('Hash32_Crc16Kermit',     Hash32_Crc16Kermit,     '123456789',        $2189);  // [30]
  Test('Hash32_Crc16Modbus',     Hash32_Crc16Modbus,     '123456789',        $4B37);  // [30]
  Test('Hash32_Crc16X25',        Hash32_Crc16X25,        '123456789',        $906E);  // [30]
  Test('Hash32_Crc16Xmodem',     Hash32_Crc16Xmodem,     '123456789',        $31C3);  // [30]
  Test('Hash32_Crc32',           Hash32_Crc32,           '123456789',        $CBF43926);  // [30]
  Test('Hash32_Crc32Bzip2',      Hash32_Crc32Bzip2,      '123456789',        $FC891918);  // [30]
  Test('Hash32_Crc32C',          Hash32_Crc32C,          '123456789',        $E3069283);  // [30]
  Test('Hash32_Crc32D',          Hash32_Crc32D,          '123456789',        $87315576);  // [30]
  Test('Hash32_Crc32Jamcrc',     Hash32_Crc32Jamcrc,     '123456789',        $340BC6D9);  // [30]
  Test('Hash32_Crc32Mpeg2',      Hash32_Crc32Mpeg2,      '123456789',        $0376E6E7);  // [30]
  Test('Hash32_Crc32Posix',      Hash32_Crc32Posix,      '123456789',        $765E7680);  // [30]
  Test('Hash32_Crc32Q',          Hash32_Crc32Q,          '123456789',        $3010BF7F);  // [30]
  Test('Hash32_Crc32Xfer',       Hash32_Crc32Xfer,       '123456789',        $BD0BE338);  // [30]
  Test('Hash32_ModbusLrc',       Hash32_ModbusLrc,       '123456789',        $23);    // [31]
  Test('Hash32_ModbusCrc',       Hash32_ModbusCrc,       '123456789',        $4B37);  // [31]
  Test('Hash32_Dcon',            Hash32_Dcon,            '123456789',        $DD);    // []
  Test('Hash32_Hart',            Hash32_Hart,            '123456789',        $31);    // []
  PrintLine(Format('%d passed, %d failed'+CRLF,[passed,failed]));
 except
  on E:Exception do BugReport(E);
 end;
 Result:=Failed;
end;

function MakeHash32BenchByList(List:TStringList; Func:THash32Function; Name:LongString; nIter:Integer=100):LongString;
var key:LongString; i,j,len,nChar,nColl:Integer; ms,ns,nsPerHash,nsPerChar:Double;
    hashs:array of Cardinal; index:array of Integer;
begin
 Result:='';
 if nIter>0 then
 if Length(Name)>0 then
 if Assigned(Func) then
 if Assigned(List) then
 try
  SetLength(hashs,0);
  SetLength(index,0);
  try
   SetLength(hashs,List.Count);
   SetLength(index,List.Count);
   ms:=msecnow;
   for i:=0 to List.Count-1 do begin
    key:=List[i];
    len:=Length(key);
    for j:=1 to nIter do
    hashs[i]:=Func(PChar(key),len);
   end;
   ms:=msecnow-ms; ns:=ms*1e6; nChar:=0;
   for i:=0 to List.Count-1 do inc(nChar,Length(List[i]));
   nsPerHash:=ns/nIter/List.Count; nsPerChar:=ns/nIter/nChar;
   nColl:=0; SortIndex(Length(hashs),hashs,@index[0],smShellSort);
   for i:=1 to Length(hashs)-1 do if hashs[index[i]]=hashs[index[i-1]] then inc(nColl);
   Result:=Result+Format('%-22s : ',[Name]);
   Result:=Result+Format('%5.0f ms, ',[ms]);
   Result:=Result+Format('%5.1f ns/hash, ',[nsPerHash]);
   Result:=Result+Format('%6.3f ns/char, ',[nsPerChar]);
   Result:=Result+Format('%6.3f GB/sec, ',[1/nsPerChar]);
   Result:=Result+Format('%7d collisions',[nColl]);
  finally
   SetLength(hashs,0);
   SetLength(index,0);
  end;
 except
  on E:Exception do BugReport(E);
 end;
end;

function DoHashBench(dictFileName:LongString; nIter:Integer=100; Echo:THash32EchoProc=nil):LongString;
var i,nChar:Integer; List:TStringList;
 procedure PrintLine(Line:LongString);
 begin
  if Assigned(Echo) then Echo(Line);
  Result:=Result+Line;
 end;
begin
 Result:='';
 try
  List:=TStringList.Create;
  try
   dictFileName:=Trim(dictFileName);
   if SameText(dictFileName,'') then exit;
   if SameText(dictFileName,'--test') then begin
    MakeHash32SanityTest(Echo);
    exit;
   end;
   if MakeHash32SanityTest=0
   then PrintLine('Sanity test: Success'+CRLF+CRLF)
   else PrintLine('Sanity test: Failure'+CRLF+CRLF);
   List.LoadFromFile(dictFileName); nChar:=0; for i:=0 to List.Count-1 do inc(nChar,Length(List[i]));
   PrintLine(Format('HashBench("%s",%d) with %d key(s), %d char(s), %5.1f char(s)/key :',
              [dictFileName,nIter,List.Count,nChar,nChar/List.Count])+CRLF);
   for i:=Low(Hash32FuncTable) to High(Hash32FuncTable) do if Assigned(Hash32FuncTable[i].Func) then
   with Hash32FuncTable[i] do PrintLine(MakeHash32BenchByList(List, Func, 'Hash32_'+Name,nIter)+CRLF);
  finally
   List.Free;
  end;
 except
  on E:Exception do BugReport(E);
 end;
end;

initialization

 //InitCrcAllParams;

finalization

 FreeCrcAllParams;

end.
