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