/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2018 Danny Robson */ #include "siphash.hpp" #include "../bitwise.hpp" #include "../debug.hpp" #include "../endian.hpp" using util::hash::siphash; /////////////////////////////////////////////////////////////////////////////// static constexpr uint64_t INITIALISERS[4] = { 0x736f6d6570736575, 0x646f72616e646f6d, 0x6c7967656e657261, 0x7465646279746573, }; /////////////////////////////////////////////////////////////////////////////// static void round (uint64_t v[4]) { using util::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); } /////////////////////////////////////////////////////////////////////////////// template ValueT readle (const void *ptr) { return util::htol (*reinterpret_cast (ptr)); } /////////////////////////////////////////////////////////////////////////////// template siphash::siphash (std::array _key) noexcept: m_key (_key) { ; } //----------------------------------------------------------------------------- template typename siphash::digest_t siphash::operator() (util::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 util::hash::siphash<2,4>;