1 // Copyright 2015-2017 the openage authors. See copying.md for legal info.
2
3 #include <array>
4 #include <limits.h>
5
6 #include "hash.h"
7 #include "misc.h"
8
9 namespace openage {
10 namespace util {
11
hash_combine(size_t hash1,size_t hash2)12 size_t hash_combine(size_t hash1, size_t hash2) {
13 // Taken from http://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
14 return hash1 ^ (hash2 + 0x9e3779b9 + ((hash1 << 6) + (hash1 >> 2)));
15 }
16
17
Siphash(std::array<uint8_t,16> key)18 Siphash::Siphash(std::array<uint8_t, 16> key) {
19 set_key(key);
20 }
21
22
set_key(std::array<uint8_t,16> key)23 Siphash& Siphash::set_key(std::array<uint8_t, 16> key) {
24 this->key[0] = array8_to_uint64(key.data(), 8, false);
25 this->key[1] = array8_to_uint64(key.data() + 8, 8, false);
26
27 return *this;
28 }
29
30
31 /**
32 * Siphash implementation
33 *
34 * https://131002.net/siphash/
35 */
hash(const uint64_t key[2],const uint8_t * data,size_t len_data)36 uint64_t hash(const uint64_t key[2], const uint8_t *data, size_t len_data) {
37
38 static auto sipround = [](uint64_t *v) {
39 v[0] += v[1];
40 v[1] = rol<uint64_t, 13>(v[1]);
41 v[1] ^= v[0];
42 v[0] = rol<uint64_t, 32>(v[0]);
43 v[2] += v[3];
44 v[3] = rol<uint64_t, 16>(v[3]);
45 v[3] ^= v[2];
46 v[0] += v[3];
47 v[3] = rol<uint64_t, 21>(v[3]);
48 v[3] ^= v[0];
49 v[2] += v[1];
50 v[1] = rol<uint64_t, 17>(v[1]);
51 v[1] ^= v[2];
52 v[2] = rol<uint64_t, 32>(v[2]);
53 };
54
55 // (len_data mod 256) ending to append later at the end of the data
56 uint64_t ending = static_cast<uint64_t>(len_data & 0xff) << 56;
57
58 // Initialization
59
60 uint64_t v[4];
61 // These values were taken from the paper: https://131002.net/siphash/siphash.pdf
62 v[0] = key[0] ^ 0x736f6d6570736575ull;
63 v[1] = key[1] ^ 0x646f72616e646f6dull;
64 v[2] = key[0] ^ 0x6c7967656e657261ull;
65 v[3] = key[1] ^ 0x7465646279746573ull;
66
67 // Compression
68
69 {
70 size_t rem_bytes{len_data};
71 const uint8_t *idx{data}; // Points to the start of the current block being copied
72 uint64_t block;
73 bool finished{false};
74
75 do {
76 if (rem_bytes < 8) {
77 block = array8_to_uint64(idx, rem_bytes, false);
78 block |= ending;
79 finished = true;
80 }
81 else {
82 block = array8_to_uint64(idx, 8, false);
83 }
84
85 v[3] ^= block;
86 sipround(v);
87 sipround(v);
88 v[0] ^= block;
89
90 rem_bytes -= 8;
91 idx += 8;
92 } while (!finished);
93 }
94
95 // Finalization
96
97 v[2] ^= 0xff;
98 sipround(v);
99 sipround(v);
100 sipround(v);
101 sipround(v);
102
103 return v[0] ^ v[1] ^ v[2] ^ v[3];
104 }
105
106
digest(const uint8_t * data,size_t count)107 uint64_t Siphash::digest(const uint8_t *data, size_t count) {
108 return hash(key, data, count);
109 }
110
111
digest(uint64_t value)112 uint64_t Siphash::digest(uint64_t value) {
113 std::vector<uint8_t> data = uint64_to_array8(value, true);
114 return hash(key, data.data(), 8);
115 }
116
117
118 }} // openage::util
119