CCF
Loading...
Searching...
No Matches
siphash.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include <cstddef>
6#include <cstdint>
7#include <stdexcept>
8#include <vector>
9
10// C++ port of reference implementation
11// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
12namespace ccf::siphash
13{
14 using SipState = uint64_t[4];
15 using SipKey = uint64_t[2];
16
17 constexpr uint64_t rotl(uint64_t x, size_t b)
18 {
19 return (x << b) | (x >> (64 - b));
20 }
21
22 inline void u32_to_bytes_le(uint32_t v, uint8_t* out)
23 {
24 out[0] = (uint8_t)(v);
25 out[1] = (uint8_t)(v >> 8);
26 out[2] = (uint8_t)(v >> 16);
27 out[3] = (uint8_t)(v >> 24);
28 }
29
30 inline void u64_to_bytes_le(uint64_t v, uint8_t* out)
31 {
32 u32_to_bytes_le((uint32_t)v, out);
33 u32_to_bytes_le((uint32_t)(v >> 32), out + 4);
34 }
35
36 template <typename ConstRandomIterator>
37 constexpr uint64_t bytes_to_64_le(const ConstRandomIterator in)
38 {
39 return ((uint64_t)in[0]) | ((uint64_t)in[1] << 8) |
40 ((uint64_t)in[2] << 16) | ((uint64_t)in[3] << 24) |
41 ((uint64_t)in[4] << 32) | ((uint64_t)in[5] << 40) |
42 ((uint64_t)in[6] << 48) | ((uint64_t)in[7] << 56);
43 }
44
45 inline void sip_rounds(SipState& s, size_t rounds)
46 {
47 for (size_t i = 0; i < rounds; ++i)
48 {
49 s[0] += s[1];
50 s[1] = rotl(s[1], 13);
51 s[1] ^= s[0];
52 s[0] = rotl(s[0], 32);
53 s[2] += s[3];
54 s[3] = rotl(s[3], 16);
55 s[3] ^= s[2];
56 s[0] += s[3];
57 s[3] = rotl(s[3], 21);
58 s[3] ^= s[0];
59 s[2] += s[1];
60 s[1] = rotl(s[1], 17);
61 s[1] ^= s[2];
62 s[2] = rotl(s[2], 32);
63 }
64 }
65
66 enum class OutputLength : uint8_t
67 {
68 EightBytes = 8,
69 SixteenBytes = 16,
70 };
71
72 template <
73 size_t CompressionRounds,
74 size_t FinalizationRounds,
75 OutputLength out_size>
77 const uint8_t* in, size_t in_len, const SipKey& key, uint8_t* out)
78 {
79 SipState s{
80 0x736f6d6570736575ULL,
81 0x646f72616e646f6dULL,
82 0x6c7967656e657261ULL,
83 0x7465646279746573ULL};
84
85 SipKey k{key[0], key[1]};
86
87 s[0] ^= k[0];
88 s[1] ^= k[1];
89 s[2] ^= k[0];
90 s[3] ^= k[1];
91
92 const uint8_t* end = in + in_len - (in_len % 8);
93 const size_t left = in_len & 7;
94
95 if constexpr (out_size == OutputLength::SixteenBytes)
96 {
97 s[1] ^= 0xee;
98 }
99
100 uint64_t m = 0;
101 for (; in != end; in += 8)
102 {
103 m = bytes_to_64_le(in);
104 s[3] ^= m;
105
106 sip_rounds(s, CompressionRounds);
107
108 s[0] ^= m;
109 }
110
111 uint64_t b = (uint64_t)in_len << 56;
112
113 // Deliberate fall through
114 switch (left)
115 {
116 case 7:
117 b |= (uint64_t)in[6] << 48;
118 case 6:
119 b |= (uint64_t)in[5] << 40;
120 case 5:
121 b |= (uint64_t)in[4] << 32;
122 case 4:
123 b |= (uint64_t)in[3] << 24;
124 case 3:
125 b |= (uint64_t)in[2] << 16;
126 case 2:
127 b |= (uint64_t)in[1] << 8;
128 case 1:
129 b |= (uint64_t)in[0];
130 case 0:
131 break;
132 default:
133 throw std::logic_error("unreachable");
134 }
135
136 s[3] ^= b;
137
138 sip_rounds(s, CompressionRounds);
139
140 s[0] ^= b;
141
142 if constexpr (out_size == OutputLength::SixteenBytes)
143 {
144 s[2] ^= 0xee;
145 }
146 else
147 {
148 s[2] ^= 0xff;
149 }
150
151 sip_rounds(s, FinalizationRounds);
152
153 b = s[0] ^ s[1] ^ s[2] ^ s[3];
154 u64_to_bytes_le(b, out);
155
156 if constexpr (out_size == OutputLength::EightBytes)
157 {
158 return;
159 }
160
161 s[1] ^= 0xdd;
162
163 sip_rounds(s, FinalizationRounds);
164
165 b = s[0] ^ s[1] ^ s[2] ^ s[3];
166 u64_to_bytes_le(b, out + 8);
167 }
168
169 template <size_t CompressionRounds, size_t FinalizationRounds>
170 uint64_t siphash(const uint8_t* data, size_t size, const SipKey& key)
171 {
172 uint64_t out = 0;
173
175 CompressionRounds,
176 FinalizationRounds,
178 data, size, key, reinterpret_cast<uint8_t*>(&out));
179
180 return out;
181 }
182
183 template <size_t CompressionRounds, size_t FinalizationRounds>
184 uint64_t siphash(const std::vector<uint8_t>& in, const SipKey& key)
185 {
186 return siphash<CompressionRounds, FinalizationRounds>(
187 in.data(), in.size(), key);
188 }
189}
190// NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
Definition siphash.h:13
void siphash_raw(const uint8_t *in, size_t in_len, const SipKey &key, uint8_t *out)
Definition siphash.h:76
void sip_rounds(SipState &s, size_t rounds)
Definition siphash.h:45
void u32_to_bytes_le(uint32_t v, uint8_t *out)
Definition siphash.h:22
uint64_t[4] SipState
Definition siphash.h:14
constexpr uint64_t rotl(uint64_t x, size_t b)
Definition siphash.h:17
uint64_t[2] SipKey
Definition siphash.h:15
void u64_to_bytes_le(uint64_t v, uint8_t *out)
Definition siphash.h:30
constexpr uint64_t bytes_to_64_le(const ConstRandomIterator in)
Definition siphash.h:37
uint64_t siphash(const uint8_t *data, size_t size, const SipKey &key)
Definition siphash.h:170
OutputLength
Definition siphash.h:67