/src/solidity/libsolutil/Keccak256.cpp
Line | Count | Source |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** @file SHA3.cpp |
19 | | * @author Gav Wood <i@gavwood.com> |
20 | | * @date 2014 |
21 | | */ |
22 | | |
23 | | #include <libsolutil/Keccak256.h> |
24 | | |
25 | | #include <cstdint> |
26 | | #include <cstring> |
27 | | |
28 | | namespace solidity::util |
29 | | { |
30 | | |
31 | | namespace |
32 | | { |
33 | | |
34 | | /** libkeccak-tiny |
35 | | * |
36 | | * A single-file implementation of SHA-3 and SHAKE. |
37 | | * |
38 | | * implementer: David Leon Gil |
39 | | * License: CC0, attribution kindly requested. Blame taken too, |
40 | | * but not liability. |
41 | | */ |
42 | | |
43 | | /******** The Keccak-f[1600] permutation ********/ |
44 | | |
45 | | /*** Constants. ***/ |
46 | | static uint8_t const rho[24] = \ |
47 | | { 1, 3, 6, 10, 15, 21, |
48 | | 28, 36, 45, 55, 2, 14, |
49 | | 27, 41, 56, 8, 25, 43, |
50 | | 62, 18, 39, 61, 20, 44}; |
51 | | static uint8_t const pi[24] = \ |
52 | | {10, 7, 11, 17, 18, 3, |
53 | | 5, 16, 8, 21, 24, 4, |
54 | | 15, 23, 19, 13, 12, 2, |
55 | | 20, 14, 22, 9, 6, 1}; |
56 | | static uint64_t const RC[24] = \ |
57 | | {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, |
58 | | 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, |
59 | | 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, |
60 | | 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, |
61 | | 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, |
62 | | 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; |
63 | | |
64 | | /*** Helper macros to unroll the permutation. ***/ |
65 | | #define rol(x, s) (((x) << s) | ((x) >> (64 - s))) |
66 | 680M | #define REPEAT6(e) e e e e e e |
67 | 680M | #define REPEAT24(e) REPEAT6(e e e e) |
68 | 2.04G | #define REPEAT5(e) e e e e e |
69 | | #define FOR5(type, v, s, e) \ |
70 | 2.04G | v = 0; \ |
71 | 2.04G | REPEAT5(e; v = static_cast<type>(v + s);) |
72 | | |
73 | | /*** Keccak-f[1600] ***/ |
74 | 28.3M | static inline void keccakf(void* state) { |
75 | 28.3M | auto* a = static_cast<uint64_t*>(state); |
76 | 28.3M | uint64_t b[5] = {0}; |
77 | | |
78 | 709M | for (int i = 0; i < 24; i++) |
79 | 680M | { |
80 | 680M | uint8_t x, y; |
81 | | // Theta |
82 | 680M | FOR5(uint8_t, x, 1, |
83 | 680M | b[x] = 0; |
84 | 680M | FOR5(uint8_t, y, 5, |
85 | 680M | b[x] ^= a[x + y]; )) |
86 | 680M | FOR5(uint8_t, x, 1, |
87 | 680M | FOR5(uint8_t, y, 5, |
88 | 680M | a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) |
89 | | // Rho and pi |
90 | 680M | uint64_t t = a[1]; |
91 | 680M | x = 0; |
92 | 680M | REPEAT24(b[0] = a[pi[x]]; |
93 | 680M | a[pi[x]] = rol(t, rho[x]); |
94 | 680M | t = b[0]; |
95 | 680M | x++; ) |
96 | | // Chi |
97 | 680M | FOR5(uint8_t, |
98 | 680M | y, |
99 | 680M | 5, |
100 | 680M | FOR5(uint8_t, x, 1, |
101 | 680M | b[x] = a[y + x];) |
102 | 680M | FOR5(uint8_t, x, 1, |
103 | 680M | a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) |
104 | | // Iota |
105 | 680M | a[0] ^= RC[i]; |
106 | 680M | } |
107 | 28.3M | } |
108 | | |
109 | | /******** The FIPS202-defined functions. ********/ |
110 | | |
111 | | /*** Some helper macros. ***/ |
112 | | |
113 | 11.2G | #define _(S) do { S } while (0) |
114 | | #define FOR(i, ST, L, S) \ |
115 | 31.1M | _(for (size_t i = 0; i < L; i += ST) { S; }) |
116 | | #define mkapply_ds(NAME, S) \ |
117 | | static inline void NAME(uint8_t* dst, \ |
118 | | uint8_t const* src, \ |
119 | 28.3M | size_t len) { \ |
120 | 28.3M | FOR(i, 1, len, S); \ |
121 | 28.3M | } |
122 | | #define mkapply_sd(NAME, S) \ |
123 | | static inline void NAME(uint8_t const* src, \ |
124 | | uint8_t* dst, \ |
125 | 2.78M | size_t len) { \ |
126 | 2.78M | FOR(i, 1, len, S); \ |
127 | 2.78M | } |
128 | | |
129 | | mkapply_ds(xorin, dst[i] ^= src[i]) // xorin |
130 | | mkapply_sd(setout, dst[i] = src[i]) // setout |
131 | | |
132 | 28.3M | #define P keccakf |
133 | | #define Plen 200 |
134 | | |
135 | | // Fold P*F over the full blocks of an input. |
136 | | #define foldP(I, L, F) \ |
137 | 31.1M | while (L >= rate) { \ |
138 | 25.5M | F(a, I, rate); \ |
139 | 25.5M | P(a); \ |
140 | 25.5M | I += rate; \ |
141 | 25.5M | L -= rate; \ |
142 | 25.5M | } |
143 | | |
144 | | /** The sponge-based hash construction. **/ |
145 | | inline void hash( |
146 | | uint8_t* out, |
147 | | size_t outlen, |
148 | | uint8_t const* in, |
149 | | size_t inlen, |
150 | | size_t rate, |
151 | | uint8_t delim |
152 | | ) |
153 | 2.78M | { |
154 | 2.78M | uint8_t a[Plen] = {0}; |
155 | | // Absorb input. |
156 | 2.78M | foldP(in, inlen, xorin); |
157 | | // Xor in the DS and pad frame. |
158 | 2.78M | a[inlen] ^= delim; |
159 | 2.78M | a[rate - 1] ^= 0x80; |
160 | | // Xor in the last block. |
161 | 2.78M | xorin(a, in, inlen); |
162 | | // Apply P |
163 | 2.78M | P(a); |
164 | | // Squeeze output. |
165 | 2.78M | foldP(out, outlen, setout); |
166 | 2.78M | setout(a, out, outlen); |
167 | 2.78M | memset(a, 0, 200); |
168 | 2.78M | } |
169 | | |
170 | | } |
171 | | |
172 | | h256 keccak256(bytesConstRef _input) |
173 | 2.78M | { |
174 | 2.78M | h256 output; |
175 | | // Parameters used: |
176 | | // The 0x01 is the specific padding for keccak (sha3 uses 0x06) and |
177 | | // the way the round size (or window or whatever it was) is calculated. |
178 | | // 200 - (256 / 4) is the "rate" |
179 | 2.78M | hash(output.data(), output.size, _input.data(), _input.size(), 200 - (256 / 4), 0x01); |
180 | 2.78M | return output; |
181 | 2.78M | } |
182 | | |
183 | | } |