Last active
January 25, 2021 10:11
-
-
Save bcrist/bf58b31b66af04387ceb to your computer and use it in GitHub Desktop.
256-bit FNV-0, FNV-1, and FNV-1a implementations in C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#include <cassert> | |
#include <sstream> | |
#include <iomanip> | |
namespace { | |
typedef uint8_t U8; | |
typedef uint16_t U16; | |
typedef uint32_t U32; | |
typedef uint64_t U64; | |
struct U256 | |
{ | |
U32 d[8]; // Big-endian - d[0] is most significant | |
}; | |
void shift_left(U256& n, const int bits) | |
{ | |
assert(bits <= 32); | |
const int ibits = 32 - bits; | |
for (int i = 0; i < 7; ++i) | |
{ | |
n.d[i] <<= bits; | |
n.d[i] |= n.d[i + 1] >> ibits; | |
} | |
n.d[7] <<= bits; | |
} | |
void shift_left_160(U256& n) | |
{ | |
n.d[0] = n.d[5]; | |
n.d[1] = n.d[6]; | |
n.d[2] = n.d[7]; | |
n.d[3] = 0; | |
n.d[4] = 0; | |
n.d[5] = 0; | |
n.d[6] = 0; | |
n.d[7] = 0; | |
} | |
U32 accumulate(U256& a, const U256& b) | |
{ | |
U64 c = 0; | |
for (int i = 7; i >= 0; --i) | |
{ | |
U64 nd = c + a.d[i] + b.d[i]; | |
a.d[i] = (U32)nd; | |
c = nd >> 32; | |
} | |
return (U32)c; | |
} | |
std::string u256_tostring(const U256& n) | |
{ | |
std::ostringstream oss; | |
oss << std::hex << std::setfill('0'); | |
for (int i = 0; i < 8; ++i) | |
oss << std::setw(8) << n.d[i]; | |
return oss.str(); | |
} | |
} // namespace (anonymous) | |
std::string fnv256_0(const std::string& input) | |
{ | |
U256 hash = { }; | |
for (auto i(input.begin()), end(input.end()); i != end; ++i) | |
{ | |
U256 t = hash; | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 4); | |
accumulate(hash, t); | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 2); | |
accumulate(hash, t); | |
shift_left_160(t); | |
accumulate(hash, t); | |
hash.d[7] ^= (U8)*i; | |
} | |
return u256_tostring(hash); | |
} | |
std::string fnv256_1(const std::string& input) | |
{ | |
U256 hash = { | |
0xdd268dbcu, 0xaac55036u, 0x2d98c384u, 0xc4e576ccu, | |
0xc8b15368u, 0x47b6bbb3u, 0x1023b4c8u, 0xcaee0535u | |
}; | |
for (auto i(input.begin()), end(input.end()); i != end; ++i) | |
{ | |
U256 t = hash; | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 4); | |
accumulate(hash, t); | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 2); | |
accumulate(hash, t); | |
shift_left_160(t); | |
accumulate(hash, t); | |
hash.d[7] ^= (U8)*i; | |
} | |
return u256_tostring(hash); | |
} | |
std::string fnv256_1a(const std::string& input) | |
{ | |
U256 hash = { | |
0xdd268dbcu, 0xaac55036u, 0x2d98c384u, 0xc4e576ccu, | |
0xc8b15368u, 0x47b6bbb3u, 0x1023b4c8u, 0xcaee0535u | |
}; | |
for (auto i(input.begin()), end(input.end()); i != end; ++i) | |
{ | |
hash.d[7] ^= (U8)*i; | |
U256 t = hash; | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 4); | |
accumulate(hash, t); | |
shift_left(t, 1); | |
accumulate(hash, t); | |
shift_left(t, 2); | |
accumulate(hash, t); | |
shift_left_160(t); | |
accumulate(hash, t); | |
} | |
return u256_tostring(hash); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment