Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sha3.cpp
Go to the documentation of this file.
1#include <fc/crypto/hex.hpp>
2#include <fc/crypto/hmac.hpp>
3#include <fc/fwd_impl.hpp>
4#include <openssl/sha.h>
5#include <string.h>
6#include <cmath>
7#include <fc/crypto/sha3.hpp>
8#include <fc/variant.hpp>
10#include "_digest_common.hpp"
11
12namespace fc
13{
14
15template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
16template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
17
18#if defined(__BYTE_ORDER__)
19#if defined(__ORDER_LITTLE_ENDIAN__)
20inline constexpr bool is_little_endian = true;
21#else
22inline constexpr bool is_little_endian = false;
23#endif
24#else
25#error "sha3 implementation needs __BYTE_ORDER__ and __ORDER_LITTLE/BIG_ENDIAN__ defined"
26#endif
27
28#if defined(__builtin_rotateleft64)
29__attribute__ ((always_inline))
30inline uint64_t rotl64(uint64_t x, uint64_t y) { return __builtin_rotateleft64(x, y); }
31#else
32// gcc should recognize this better than clang
33__attribute__ ((always_inline))
34inline uint64_t rotl64(uint64_t x, uint64_t y) { return (x << y) | (x >> (64-y)); }
35#endif
36/* This implementation is an amalgam from tiny_sha3 (https://github.com/mjosaarinen/tiny_sha3) and
37 * SHA3UIF (https://github.com/brainhub/SHA3UIF) and documentation.
38 * This implementation is quite slow comparative to openssl 1.1.1. Once we require a version greater
39 * than or equal to 1.1.1, we should replace with their primitives.
40 */
41struct sha3_impl {
42 sha3_impl() { init(); }
43
44 static constexpr uint8_t number_of_rounds = 24;
45 static constexpr uint8_t number_of_words = 25;
46 static constexpr uint8_t digest_size = 32;
48 UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082), UINT64_C(0x800000000000808a), UINT64_C(0x8000000080008000),
49 UINT64_C(0x000000000000808b), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009),
50 UINT64_C(0x000000000000008a), UINT64_C(0x0000000000000088), UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000a),
51 UINT64_C(0x000000008000808b), UINT64_C(0x800000000000008b), UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003),
52 UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080), UINT64_C(0x000000000000800a), UINT64_C(0x800000008000000a),
53 UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008)};
54 static constexpr uint8_t rot_constants[number_of_rounds] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
55 static constexpr uint8_t pi_lanes[number_of_rounds] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
56
58 {
59 uint64_t bc[5];
60
61 if constexpr (!is_little_endian)
62 {
63 uint8_t *v;
64 // convert the buffer to little endian
65 for (std::size_t i; i < number_of_words; i++)
66 {
67 v = reinterpret_cast<uint8_t *>(words + i);
68 words[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) |
69 (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) |
70 (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) |
71 (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56);
72 }
73 }
74
75 #pragma clang loop vectorize(enable) interleave(enable)
76 for (std::size_t i = 0; i < number_of_rounds; i++)
77 {
78 // theta
79 #pragma clang loop vectorize(enable) interleave(enable)
80 for (std::size_t j = 0; j < 5; j++)
81 bc[j] = words[j] ^ words[j + 5] ^ words[j + 10] ^ words[j + 15] ^ words[j + 20];
82
83 uint64_t t;
84 #pragma clang loop vectorize(enable) interleave(enable)
85 for (std::size_t j = 0; j < 5; j++)
86 {
87 t = bc[(j + 4) % 5] ^ rotl64(bc[(j + 1) % 5], 1);
88 #pragma clang loop vectorize(enable) interleave(enable)
89 for (std::size_t k = 0; k < number_of_words; k += 5)
90 words[k + j] ^= t;
91 }
92
93 // rho pi
94 t = words[1];
95 #pragma clang loop vectorize(enable) interleave(enable)
96 for (std::size_t j = 0; j < number_of_rounds; j++)
97 {
99 bc[0] = words[p];
100 words[p] = rotl64(t, rot_constants[j]);
101 t = bc[0];
102 }
103
104 // chi
105 #pragma clang loop vectorize(enable) interleave(enable)
106 for (std::size_t j = 0; j < number_of_words; j += 5)
107 {
108 #pragma clang loop vectorize(enable) interleave(enable)
109 for (std::size_t k = 0; k < 5; k++)
110 bc[k] = words[k + j];
111 #pragma clang loop vectorize(enable) interleave(enable)
112 for (std::size_t k = 0; k < 5; k++)
113 words[k + j] ^= (~bc[(k + 1) % 5]) & bc[(k + 2) % 5];
114 }
115
116 // iota
117 words[0] ^= round_constants[i];
118 }
119
120 if constexpr (!is_little_endian)
121 {
122 uint8_t *v;
123 uint64_t tmp;
124 // convert back to big endian
125 for (std::size_t i = 0; i < sizeof(words); i++)
126 {
127 v = (uint8_t *)(words + i);
128 tmp = words[i];
129 v[0] = tmp & 0xFF;
130 v[1] = (tmp >> 8) & 0xFF;
131 v[2] = (tmp >> 16) & 0xFF;
132 v[3] = (tmp >> 24) & 0xFF;
133 v[4] = (tmp >> 32) & 0xFF;
134 v[5] = (tmp >> 40) & 0xFF;
135 v[6] = (tmp >> 48) & 0xFF;
136 v[7] = (tmp >> 56) & 0xFF;
137 }
138 }
139 }
140
141 void init() {
142 memset((char *)this, 0, sizeof(*this));
143 size = 136;
144 }
145
146 void update(const uint8_t* data, std::size_t len) {
147 int j = point;
148 for (std::size_t i = 0; i < len; i++)
149 {
150 bytes[j++] ^= data[i];
151 if (j >= size)
152 {
153 update_step();
154 j = 0;
155 }
156 }
157 point = j;
158 }
159
160 void finalize(char* buffer) {
161 bytes[point] ^= keccak ? 0x01 : 0x06;
162 bytes[size-1] ^= 0x80;
163 update_step();
164 memcpy(buffer, (const char*)bytes, digest_size);
165 }
166
167 union {
169 uint64_t words[number_of_words*5]; // this is greater than 25, because in the theta portion we need a wide berth
170 };
171 bool keccak = false;
172 int point;
173 int size;
174};
175
177{
178 memset(_hash, 0, sizeof(_hash));
179}
180sha3::sha3(const char *data, size_t size)
181{
182 if (size != sizeof(_hash))
183 FC_THROW_EXCEPTION(exception, "sha3: size mismatch");
184 memcpy(_hash, data, size);
185}
186sha3::sha3(const string &hex_str)
187{
188 auto bytes_written = fc::from_hex(hex_str, (char *)_hash, sizeof(_hash));
189 if (bytes_written < sizeof(_hash))
190 memset((char *)_hash + bytes_written, 0, (sizeof(_hash) - bytes_written));
191}
192
193string sha3::str() const
194{
195 return fc::to_hex((char *)_hash, sizeof(_hash));
196}
197sha3::operator string() const { return str(); }
198
199const char *sha3::data() const { return (const char *)&_hash[0]; }
200char *sha3::data() { return (char *)&_hash[0]; }
201
206
209{
210 reset();
211}
212
213void sha3::encoder::write(const char *d, uint32_t dlen)
214{
215 my->ctx.update((const uint8_t*)d, dlen);
216}
218{
219 sha3 h;
220 my->ctx.keccak = !is_nist;
221 my->ctx.finalize((char*)h.data());
222 return h;
223}
225{
226 my->ctx.init();
227}
228
230{
231 sha3 result;
232 fc::detail::shift_l(h1.data(), result.data(), result.data_size(), i);
233 return result;
234}
236{
237 sha3 result;
238 fc::detail::shift_r(h1.data(), result.data(), result.data_size(), i);
239 return result;
240}
241sha3 operator^(const sha3 &h1, const sha3 &h2)
242{
243 sha3 result;
244 result._hash[0] = h1._hash[0] ^ h2._hash[0];
245 result._hash[1] = h1._hash[1] ^ h2._hash[1];
246 result._hash[2] = h1._hash[2] ^ h2._hash[2];
247 result._hash[3] = h1._hash[3] ^ h2._hash[3];
248 return result;
249}
250bool operator>=(const sha3 &h1, const sha3 &h2)
251{
252 return memcmp(h1._hash, h2._hash, sizeof(h1._hash)) >= 0;
253}
254bool operator>(const sha3 &h1, const sha3 &h2)
255{
256 return memcmp(h1._hash, h2._hash, sizeof(h1._hash)) > 0;
257}
258bool operator<(const sha3 &h1, const sha3 &h2)
259{
260 return memcmp(h1._hash, h2._hash, sizeof(h1._hash)) < 0;
261}
262bool operator!=(const sha3 &h1, const sha3 &h2)
263{
264 return !(h1 == h2);
265}
266bool operator==(const sha3 &h1, const sha3 &h2)
267{
268 // idea to not use memcmp, from:
269 // https://lemire.me/blog/2018/08/22/avoid-lexicographical-comparisons-when-testing-for-string-equality/
270 return h1._hash[0] == h2._hash[0] &&
271 h1._hash[1] == h2._hash[1] &&
272 h1._hash[2] == h2._hash[2] &&
273 h1._hash[3] == h2._hash[3];
274}
275
276void to_variant(const sha3 &bi, variant &v)
277{
278 v = std::vector<char>((const char *)&bi, ((const char *)&bi) + sizeof(bi));
279}
280void from_variant(const variant &v, sha3 &bi)
281{
282 const auto &ve = v.as<std::vector<char>>();
283 if (ve.size())
284 memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(), sizeof(bi)));
285 else
286 memset(&bi, char(0), sizeof(bi));
287}
288} // namespace fc
const mie::Vuint & p
Definition bn.cpp:27
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
sha3 result(bool is_nist=true)
Definition sha3.cpp:217
void write(const char *d, uint32_t dlen)
Definition sha3.cpp:213
friend bool operator!=(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:262
friend T & operator<<(T &ds, const sha3 &ep)
Definition sha3.hpp:59
const char * data() const
Definition sha3.cpp:199
friend bool operator>=(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:250
friend T & operator>>(T &ds, sha3 &ep)
Definition sha3.hpp:66
string str() const
Definition sha3.cpp:193
friend bool operator>(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:254
friend bool operator<(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:258
friend bool operator==(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:266
uint64_t _hash[4]
Definition sha3.hpp:80
friend sha3 operator^(const sha3 &h1, const sha3 &h2)
Definition sha3.cpp:241
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
T as() const
Definition variant.hpp:327
Defines exception's used by fc.
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
namespace sysio::chain
Definition authority.cpp:3
std::string string
Definition string.hpp:10
__attribute__((always_inline)) inline uint64_t rotl64(uint64_t x
std::vector< char > bytes
Definition alt_bn128.hpp:10
uint8_t from_hex(char c)
Definition hex.cpp:6
const T & min(const T &a, const T &b)
Definition utility.hpp:140
fc::string to_hex(const char *d, uint32_t s)
Definition hex.cpp:17
overloaded(Ts...) -> overloaded< Ts... >
uint64_t y
Definition sha3.cpp:34
void from_variant(const fc::variant &v, sysio::chain::chain_id_type &cid)
void to_variant(const sysio::chain::shared_public_key &var, fc::variant &vo)
Definition authority.cpp:4
unsigned int uint32_t
Definition stdint.h:126
#define UINT64_C(val)
Definition stdint.h:284
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
void finalize(char *buffer)
Definition sha3.cpp:160
void init()
Definition sha3.cpp:141
bool keccak
Definition sha3.cpp:171
static constexpr uint8_t number_of_rounds
Definition sha3.cpp:44
static constexpr uint64_t round_constants[number_of_rounds]
Definition sha3.cpp:47
void update_step()
Definition sha3.cpp:57
static constexpr uint8_t pi_lanes[number_of_rounds]
Definition sha3.cpp:55
static constexpr uint8_t digest_size
Definition sha3.cpp:46
uint64_t words[number_of_words *5]
Definition sha3.cpp:169
static constexpr uint8_t number_of_words
Definition sha3.cpp:45
void update(const uint8_t *data, std::size_t len)
Definition sha3.cpp:146
static constexpr uint8_t rot_constants[number_of_rounds]
Definition sha3.cpp:54
CK_ULONG d
uint16_t j
size_t len
memset(pInfo->slotDescription, ' ', 64)
memcpy((char *) pInfo->slotDescription, s, l)