/* * 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 * * Derived from the CC0 reference implementation by: * Jean-Philippe Aumasson */ #pragma once #include "../std.hpp" #include #include namespace cruft::hash { template < typename ResultT, int CRoundsV, int DRoundsV, typename = std::enable_if_t || std::is_same_v> > 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) 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 in ) { for (auto const &m: in) put (m); return finish (u32 (in.size ())); } template requires (std::is_same_v, 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) v2 ^= 0xee; else v2 ^= 0xff; for (int i = 0; i < DRoundsV; ++i) round (); ResultT res = v1 ^ v3; if constexpr (std::is_same_v) 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, u32> && ...) inline constexpr u32 halfsipmix (u32 key0, u32 key1, ValuesT &&...vals) { return halfsiphash (key0, key1) (vals...); } template decltype(auto) halfsipmix24 (ValueT &&...vals) { return halfsipmix<2, 4> (vals...); } };