/* * 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 2018 Danny Robson */ #include "siphash.hpp" #include "../bitwise.hpp" #include "../debug/assert.hpp" #include "../endian.hpp" using cruft::hash::siphash; /////////////////////////////////////////////////////////////////////////////// static constexpr uint64_t INITIALISERS[4] = { 0x736f6d6570736575, 0x646f72616e646f6d, 0x6c7967656e657261, 0x7465646279746573, }; /////////////////////////////////////////////////////////////////////////////// static void round (uint64_t v[4]) { using cruft::rotatel; v[0] += v[1]; v[2] += v[3]; v[1] = rotatel (v[1], 13); v[3] = rotatel (v[3], 16); v[1] ^= v[0]; v[3] ^= v[2]; v[0] = rotatel (v[0], 32); v[2] += v[1]; v[0] += v[3]; v[1] = rotatel (v[1], 17); v[3] = rotatel (v[3], 21); v[1] ^= v[2]; v[3] ^= v[0]; v[2] = rotatel (v[2], 32); } /////////////////////////////////////////////////////////////////////////////// static std::array bytes_to_u64 (std::span val) { u64 r0 = u64 (val[0 + 0]) << u64 (0 * 8) | u64 (val[0 + 1]) << u64 (1 * 8) | u64 (val[0 + 2]) << u64 (2 * 8) | u64 (val[0 + 3]) << u64 (3 * 8) | u64 (val[0 + 4]) << u64 (4 * 8) | u64 (val[0 + 5]) << u64 (5 * 8) | u64 (val[0 + 6]) << u64 (6 * 8) | u64 (val[0 + 7]) << u64 (7 * 8); u64 r1 = u64 (val[8 + 0]) << u64 (0 * 8) | u64 (val[8 + 1]) << u64 (1 * 8) | u64 (val[8 + 2]) << u64 (2 * 8) | u64 (val[8 + 3]) << u64 (3 * 8) | u64 (val[8 + 4]) << u64 (4 * 8) | u64 (val[8 + 5]) << u64 (5 * 8) | u64 (val[8 + 6]) << u64 (6 * 8) | u64 (val[8 + 7]) << u64 (7 * 8); return { r0, r1 }; } /////////////////////////////////////////////////////////////////////////////// template siphash::siphash (std::array _key) noexcept: m_key (_key) { ; } //----------------------------------------------------------------------------- template siphash::siphash (std::span _key) noexcept : siphash (bytes_to_u64 (_key)) { ; } /////////////////////////////////////////////////////////////////////////////// template typename siphash::digest_t siphash::operator() (cruft::view data) const noexcept { // init uint64_t state[4] = { m_key[0] ^ INITIALISERS[0], m_key[1] ^ INITIALISERS[1], m_key[0] ^ INITIALISERS[2], m_key[1] ^ INITIALISERS[3], }; // update auto cursor = data.begin (); for ( ; data.end () - cursor >= 8; cursor += sizeof (uint64_t)) { auto word = readle (cursor); state[3] ^= word; for (int c = 0; c < C; ++c) round (state); state[0] ^= word; } // drain union { uint64_t d64 = 0; uint8_t d08[8]; } accum; if (cursor != data.cend ()) { std::copy (cursor, data.cend (), std::begin (accum.d08)); cursor = data.cend (); } CHECK_EQ (cursor, data.cend ()); // append the length accum.d08[7] = data.size (); state[3] ^= accum.d64; for (int c = 0; c < C; ++c) round (state); state[0] ^= accum.d64; // finalisation state[2] ^= 0xff; for (int d = 0; d < D; ++d) round (state); return state[0] ^ state[1] ^ state[2] ^ state[3]; } /////////////////////////////////////////////////////////////////////////////// template class cruft::hash::siphash<2,4>;