Skip to content

Instantly share code, notes, and snippets.

@bcrist
Last active January 25, 2021 10:11
Show Gist options
  • Save bcrist/bf58b31b66af04387ceb to your computer and use it in GitHub Desktop.
Save bcrist/bf58b31b66af04387ceb to your computer and use it in GitHub Desktop.
256-bit FNV-0, FNV-1, and FNV-1a implementations in C++
#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