| /** @file | |
| @section license License | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you 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. | |
| */ | |
| #pragma once | |
| #include "tscore/Hash.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| /* | |
| SipHash is a Hash Message Authentication Code and can take a key. | |
| If you don't care about MAC use the void constructor and it will use | |
| a zero key for you. | |
| Template parameters: | |
| - c_rounds: number of compression rounds per message block | |
| - d_rounds: number of finalization rounds | |
| */ | |
| #define SIP_BLOCK_SIZE 8 | |
| #define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b))) | |
| static inline std::uint64_t | |
| U8TO64_LE(const std::uint8_t *p) | |
| { | |
| std::uint64_t result; | |
| std::memcpy(&result, p, sizeof(result)); | |
| return result; | |
| } | |
| #define SIPCOMPRESS(x0, x1, x2, x3) \ | |
| x0 += x1; \ | |
| x2 += x3; \ | |
| x1 = ROTL64(x1, 13); \ | |
| x3 = ROTL64(x3, 16); \ | |
| x1 ^= x0; \ | |
| x3 ^= x2; \ | |
| x0 = ROTL64(x0, 32); \ | |
| x2 += x1; \ | |
| x0 += x3; \ | |
| x1 = ROTL64(x1, 17); \ | |
| x3 = ROTL64(x3, 21); \ | |
| x1 ^= x2; \ | |
| x3 ^= x0; \ | |
| x2 = ROTL64(x2, 32); | |
| template <int c_rounds, int d_rounds> struct ATSHashSip : ATSHash64 { | |
| ATSHashSip() { this->clear(); } | |
| ATSHashSip(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0))) { this->clear(); } | |
| ATSHashSip(std::uint64_t key0, std::uint64_t key1) : k0(key0), k1(key1) { this->clear(); } | |
| void | |
| update(const void *data, std::size_t len) override | |
| { | |
| std::size_t i, blocks; | |
| unsigned char *m; | |
| std::uint64_t mi; | |
| std::uint8_t block_off = 0; | |
| if (!finalized) { | |
| m = (unsigned char *)data; | |
| total_len += len; | |
| if (len + block_buffer_len < SIP_BLOCK_SIZE) { | |
| std::memcpy(block_buffer + block_buffer_len, m, len); | |
| block_buffer_len += len; | |
| } else { | |
| if (block_buffer_len > 0) { | |
| block_off = SIP_BLOCK_SIZE - block_buffer_len; | |
| std::memcpy(block_buffer + block_buffer_len, m, block_off); | |
| mi = U8TO64_LE(block_buffer); | |
| v3 ^= mi; | |
| for (int r = 0; r < c_rounds; r++) { | |
| SIPCOMPRESS(v0, v1, v2, v3); | |
| } | |
| v0 ^= mi; | |
| } | |
| for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) { | |
| mi = U8TO64_LE(m + i); | |
| v3 ^= mi; | |
| for (int r = 0; r < c_rounds; r++) { | |
| SIPCOMPRESS(v0, v1, v2, v3); | |
| } | |
| v0 ^= mi; | |
| } | |
| block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1); | |
| std::memcpy(block_buffer, m + block_off + blocks, block_buffer_len); | |
| } | |
| } | |
| } | |
| void | |
| final() override | |
| { | |
| std::uint64_t last7; | |
| int i; | |
| if (!finalized) { | |
| last7 = static_cast<std::uint64_t>(total_len & 0xff) << 56; | |
| for (i = block_buffer_len - 1; i >= 0; i--) { | |
| last7 |= static_cast<std::uint64_t>(block_buffer[i]) << (i * 8); | |
| } | |
| v3 ^= last7; | |
| for (int r = 0; r < c_rounds; r++) { | |
| SIPCOMPRESS(v0, v1, v2, v3); | |
| } | |
| v0 ^= last7; | |
| v2 ^= 0xff; | |
| for (int r = 0; r < d_rounds; r++) { | |
| SIPCOMPRESS(v0, v1, v2, v3); | |
| } | |
| hfinal = v0 ^ v1 ^ v2 ^ v3; | |
| finalized = true; | |
| } | |
| } | |
| std::uint64_t | |
| get() const override | |
| { | |
| if (finalized) { | |
| return hfinal; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| void | |
| clear() override | |
| { | |
| v0 = k0 ^ 0x736f6d6570736575ull; | |
| v1 = k1 ^ 0x646f72616e646f6dull; | |
| v2 = k0 ^ 0x6c7967656e657261ull; | |
| v3 = k1 ^ 0x7465646279746573ull; | |
| finalized = false; | |
| total_len = 0; | |
| block_buffer_len = 0; | |
| } | |
| private: | |
| unsigned char block_buffer[8] = {0}; | |
| std::uint8_t block_buffer_len = 0; | |
| std::uint64_t k0 = 0; | |
| std::uint64_t k1 = 0; | |
| std::uint64_t v0 = 0; | |
| std::uint64_t v1 = 0; | |
| std::uint64_t v2 = 0; | |
| std::uint64_t v3 = 0; | |
| std::uint64_t hfinal = 0; | |
| std::size_t total_len = 0; | |
| bool finalized = false; | |
| }; | |
| // Standard SipHash variants | |
| using ATSHash64Sip24 = ATSHashSip<2, 4>; | |
| using ATSHash64Sip13 = ATSHashSip<1, 3>; |