148 lines
3.3 KiB
C++
148 lines
3.3 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2020, Danny Robson <danny@nerdcruft.net>
|
|
*
|
|
* Derived from the CC0 reference implementation by:
|
|
* Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../std.hpp"
|
|
|
|
#include <type_traits>
|
|
#include <span>
|
|
|
|
|
|
namespace cruft::hash {
|
|
template <
|
|
typename ResultT,
|
|
int CRoundsV,
|
|
int DRoundsV,
|
|
typename = std::enable_if_t<std::is_same_v<ResultT, u32> || std::is_same_v<ResultT, u64>>
|
|
>
|
|
struct halfsiphash {
|
|
u32 rotl (u32 x, u32 b)
|
|
{
|
|
return ((x) << (b)) | ((x) >> (32 - (b)));
|
|
}
|
|
|
|
u32 v0, v1, v2, v3;
|
|
|
|
constexpr halfsiphash (u32 k0, u32 k1)
|
|
{
|
|
v0 = 0 ^ k0;
|
|
v1 = 0 ^ k1;
|
|
v2 = 0x6c796765 ^ k0;
|
|
v3 = 0x74656462 ^ k1;
|
|
|
|
if constexpr (std::is_same_v<ResultT, u64>)
|
|
v1 ^= 0xee;
|
|
}
|
|
|
|
constexpr void round (void)
|
|
{
|
|
v0 += v1;
|
|
v1 = rotl (v1, 5);
|
|
v1 ^= v0;
|
|
v0 = rotl (v0, 16);
|
|
v2 += v3;
|
|
v3 = rotl (v3, 8);
|
|
v3 ^= v2;
|
|
v0 += v3;
|
|
v3 = rotl (v3, 7);
|
|
v3 ^= v0;
|
|
v2 += v1;
|
|
v1 = rotl (v1, 13);
|
|
v1 ^= v2;
|
|
v2 = rotl (v2, 16);
|
|
}
|
|
|
|
constexpr void put (u32 word)
|
|
{
|
|
v3 ^= word;
|
|
for (int i = 0; i < CRoundsV; ++i)
|
|
round ();
|
|
v0 ^= word;
|
|
}
|
|
|
|
constexpr ResultT
|
|
operator() (
|
|
std::span<u32 const> in
|
|
) {
|
|
for (auto const &m: in)
|
|
put (m);
|
|
|
|
return finish (u32 (in.size ()));
|
|
}
|
|
|
|
template <typename ...ArgsT>
|
|
requires (std::is_same_v<std::remove_cvref_t<ArgsT>, u32> && ...)
|
|
constexpr ResultT
|
|
operator() (ArgsT &&...vals)
|
|
{
|
|
(put (vals), ...);
|
|
return finish (sizeof ...(vals));
|
|
}
|
|
|
|
constexpr ResultT
|
|
finish (u32 count)
|
|
{
|
|
u32 const b = u32(count * sizeof (u32)) << 24;
|
|
|
|
v3 ^= b;
|
|
|
|
for (int i = 0; i < CRoundsV; ++i)
|
|
round ();
|
|
|
|
v0 ^= b;
|
|
|
|
if (std::is_same_v<ResultT,u64>)
|
|
v2 ^= 0xee;
|
|
else
|
|
v2 ^= 0xff;
|
|
|
|
for (int i = 0; i < DRoundsV; ++i)
|
|
round ();
|
|
|
|
ResultT res = v1 ^ v3;
|
|
|
|
if constexpr (std::is_same_v<ResultT, u32>)
|
|
return res;
|
|
|
|
v1 ^= 0xdd;
|
|
|
|
for (int i = 0; i < DRoundsV; ++i)
|
|
round ();
|
|
|
|
res |= u64(v1 ^ v3) << 32;
|
|
|
|
return res;
|
|
}
|
|
};
|
|
|
|
|
|
template <
|
|
int CRoundsV,
|
|
int DRoundsV,
|
|
typename ...ValuesT
|
|
>
|
|
requires (std::is_same_v<std::remove_cvref_t<ValuesT>, u32> && ...)
|
|
inline constexpr
|
|
u32 halfsipmix (u32 key0, u32 key1, ValuesT &&...vals)
|
|
{
|
|
return halfsiphash<u32, 2,4> (key0, key1) (vals...);
|
|
}
|
|
|
|
|
|
template <typename ...ValueT>
|
|
decltype(auto)
|
|
halfsipmix24 (ValueT &&...vals)
|
|
{
|
|
return halfsipmix<2, 4> (vals...);
|
|
}
|
|
};
|