/Users/mcomp/contrib/bitcoin/src/crypto/sha3.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2020-present The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | // Based on https://github.com/mjosaarinen/tiny_sha3/blob/master/sha3.c |
6 | | // by Markku-Juhani O. Saarinen <mjos@iki.fi> |
7 | | |
8 | | #include <crypto/sha3.h> |
9 | | #include <crypto/common.h> |
10 | | #include <span.h> |
11 | | |
12 | | #include <algorithm> |
13 | | #include <array> // For std::begin and std::end. |
14 | | #include <bit> |
15 | | |
16 | | #include <stdint.h> |
17 | | |
18 | | void KeccakF(uint64_t (&st)[25]) |
19 | 0 | { |
20 | 0 | static constexpr uint64_t RNDC[24] = { |
21 | 0 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, |
22 | 0 | 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, |
23 | 0 | 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, |
24 | 0 | 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, |
25 | 0 | 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, |
26 | 0 | 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 |
27 | 0 | }; |
28 | 0 | static constexpr int ROUNDS = 24; |
29 | |
|
30 | 0 | for (int round = 0; round < ROUNDS; ++round) { |
31 | 0 | uint64_t bc0, bc1, bc2, bc3, bc4, t; |
32 | | |
33 | | // Theta |
34 | 0 | bc0 = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; |
35 | 0 | bc1 = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; |
36 | 0 | bc2 = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; |
37 | 0 | bc3 = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; |
38 | 0 | bc4 = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; |
39 | 0 | t = bc4 ^ std::rotl(bc1, 1); st[0] ^= t; st[5] ^= t; st[10] ^= t; st[15] ^= t; st[20] ^= t; |
40 | 0 | t = bc0 ^ std::rotl(bc2, 1); st[1] ^= t; st[6] ^= t; st[11] ^= t; st[16] ^= t; st[21] ^= t; |
41 | 0 | t = bc1 ^ std::rotl(bc3, 1); st[2] ^= t; st[7] ^= t; st[12] ^= t; st[17] ^= t; st[22] ^= t; |
42 | 0 | t = bc2 ^ std::rotl(bc4, 1); st[3] ^= t; st[8] ^= t; st[13] ^= t; st[18] ^= t; st[23] ^= t; |
43 | 0 | t = bc3 ^ std::rotl(bc0, 1); st[4] ^= t; st[9] ^= t; st[14] ^= t; st[19] ^= t; st[24] ^= t; |
44 | | |
45 | | // Rho Pi |
46 | 0 | t = st[1]; |
47 | 0 | bc0 = st[10]; st[10] = std::rotl(t, 1); t = bc0; |
48 | 0 | bc0 = st[7]; st[7] = std::rotl(t, 3); t = bc0; |
49 | 0 | bc0 = st[11]; st[11] = std::rotl(t, 6); t = bc0; |
50 | 0 | bc0 = st[17]; st[17] = std::rotl(t, 10); t = bc0; |
51 | 0 | bc0 = st[18]; st[18] = std::rotl(t, 15); t = bc0; |
52 | 0 | bc0 = st[3]; st[3] = std::rotl(t, 21); t = bc0; |
53 | 0 | bc0 = st[5]; st[5] = std::rotl(t, 28); t = bc0; |
54 | 0 | bc0 = st[16]; st[16] = std::rotl(t, 36); t = bc0; |
55 | 0 | bc0 = st[8]; st[8] = std::rotl(t, 45); t = bc0; |
56 | 0 | bc0 = st[21]; st[21] = std::rotl(t, 55); t = bc0; |
57 | 0 | bc0 = st[24]; st[24] = std::rotl(t, 2); t = bc0; |
58 | 0 | bc0 = st[4]; st[4] = std::rotl(t, 14); t = bc0; |
59 | 0 | bc0 = st[15]; st[15] = std::rotl(t, 27); t = bc0; |
60 | 0 | bc0 = st[23]; st[23] = std::rotl(t, 41); t = bc0; |
61 | 0 | bc0 = st[19]; st[19] = std::rotl(t, 56); t = bc0; |
62 | 0 | bc0 = st[13]; st[13] = std::rotl(t, 8); t = bc0; |
63 | 0 | bc0 = st[12]; st[12] = std::rotl(t, 25); t = bc0; |
64 | 0 | bc0 = st[2]; st[2] = std::rotl(t, 43); t = bc0; |
65 | 0 | bc0 = st[20]; st[20] = std::rotl(t, 62); t = bc0; |
66 | 0 | bc0 = st[14]; st[14] = std::rotl(t, 18); t = bc0; |
67 | 0 | bc0 = st[22]; st[22] = std::rotl(t, 39); t = bc0; |
68 | 0 | bc0 = st[9]; st[9] = std::rotl(t, 61); t = bc0; |
69 | 0 | bc0 = st[6]; st[6] = std::rotl(t, 20); t = bc0; |
70 | 0 | st[1] = std::rotl(t, 44); |
71 | | |
72 | | // Chi Iota |
73 | 0 | bc0 = st[0]; bc1 = st[1]; bc2 = st[2]; bc3 = st[3]; bc4 = st[4]; |
74 | 0 | st[0] = bc0 ^ (~bc1 & bc2) ^ RNDC[round]; |
75 | 0 | st[1] = bc1 ^ (~bc2 & bc3); |
76 | 0 | st[2] = bc2 ^ (~bc3 & bc4); |
77 | 0 | st[3] = bc3 ^ (~bc4 & bc0); |
78 | 0 | st[4] = bc4 ^ (~bc0 & bc1); |
79 | 0 | bc0 = st[5]; bc1 = st[6]; bc2 = st[7]; bc3 = st[8]; bc4 = st[9]; |
80 | 0 | st[5] = bc0 ^ (~bc1 & bc2); |
81 | 0 | st[6] = bc1 ^ (~bc2 & bc3); |
82 | 0 | st[7] = bc2 ^ (~bc3 & bc4); |
83 | 0 | st[8] = bc3 ^ (~bc4 & bc0); |
84 | 0 | st[9] = bc4 ^ (~bc0 & bc1); |
85 | 0 | bc0 = st[10]; bc1 = st[11]; bc2 = st[12]; bc3 = st[13]; bc4 = st[14]; |
86 | 0 | st[10] = bc0 ^ (~bc1 & bc2); |
87 | 0 | st[11] = bc1 ^ (~bc2 & bc3); |
88 | 0 | st[12] = bc2 ^ (~bc3 & bc4); |
89 | 0 | st[13] = bc3 ^ (~bc4 & bc0); |
90 | 0 | st[14] = bc4 ^ (~bc0 & bc1); |
91 | 0 | bc0 = st[15]; bc1 = st[16]; bc2 = st[17]; bc3 = st[18]; bc4 = st[19]; |
92 | 0 | st[15] = bc0 ^ (~bc1 & bc2); |
93 | 0 | st[16] = bc1 ^ (~bc2 & bc3); |
94 | 0 | st[17] = bc2 ^ (~bc3 & bc4); |
95 | 0 | st[18] = bc3 ^ (~bc4 & bc0); |
96 | 0 | st[19] = bc4 ^ (~bc0 & bc1); |
97 | 0 | bc0 = st[20]; bc1 = st[21]; bc2 = st[22]; bc3 = st[23]; bc4 = st[24]; |
98 | 0 | st[20] = bc0 ^ (~bc1 & bc2); |
99 | 0 | st[21] = bc1 ^ (~bc2 & bc3); |
100 | 0 | st[22] = bc2 ^ (~bc3 & bc4); |
101 | 0 | st[23] = bc3 ^ (~bc4 & bc0); |
102 | 0 | st[24] = bc4 ^ (~bc0 & bc1); |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | SHA3_256& SHA3_256::Write(std::span<const unsigned char> data) |
107 | 0 | { |
108 | 0 | if (m_bufsize && data.size() >= sizeof(m_buffer) - m_bufsize) { |
109 | | // Fill the buffer and process it. |
110 | 0 | std::copy(data.begin(), data.begin() + (sizeof(m_buffer) - m_bufsize), m_buffer + m_bufsize); |
111 | 0 | data = data.subspan(sizeof(m_buffer) - m_bufsize); |
112 | 0 | m_state[m_pos++] ^= ReadLE64(m_buffer); |
113 | 0 | m_bufsize = 0; |
114 | 0 | if (m_pos == RATE_BUFFERS) { |
115 | 0 | KeccakF(m_state); |
116 | 0 | m_pos = 0; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | while (data.size() >= sizeof(m_buffer)) { |
120 | | // Process chunks directly from the buffer. |
121 | 0 | m_state[m_pos++] ^= ReadLE64(data.data()); |
122 | 0 | data = data.subspan(8); |
123 | 0 | if (m_pos == RATE_BUFFERS) { |
124 | 0 | KeccakF(m_state); |
125 | 0 | m_pos = 0; |
126 | 0 | } |
127 | 0 | } |
128 | 0 | if (data.size()) { |
129 | | // Keep the remainder in the buffer. |
130 | 0 | std::copy(data.begin(), data.end(), m_buffer + m_bufsize); |
131 | 0 | m_bufsize += data.size(); |
132 | 0 | } |
133 | 0 | return *this; |
134 | 0 | } |
135 | | |
136 | | SHA3_256& SHA3_256::Finalize(std::span<unsigned char> output) |
137 | 0 | { |
138 | 0 | assert(output.size() == OUTPUT_SIZE); |
139 | 0 | std::fill(m_buffer + m_bufsize, m_buffer + sizeof(m_buffer), 0); |
140 | 0 | m_buffer[m_bufsize] ^= 0x06; |
141 | 0 | m_state[m_pos] ^= ReadLE64(m_buffer); |
142 | 0 | m_state[RATE_BUFFERS - 1] ^= 0x8000000000000000; |
143 | 0 | KeccakF(m_state); |
144 | 0 | for (unsigned i = 0; i < 4; ++i) { |
145 | 0 | WriteLE64(output.data() + 8 * i, m_state[i]); |
146 | 0 | } |
147 | 0 | return *this; |
148 | 0 | } |
149 | | |
150 | | SHA3_256& SHA3_256::Reset() |
151 | 0 | { |
152 | 0 | m_bufsize = 0; |
153 | 0 | m_pos = 0; |
154 | 0 | std::fill(std::begin(m_state), std::end(m_state), 0); |
155 | 0 | return *this; |
156 | 0 | } |