diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2024-11-29 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2024-11-30 15:27:15 +0500 |
commit | e5431fa6f5505e385c6f9367260717e9c47dc2ee (patch) | |
tree | 4cd2c2c3b225b48c8e7053432c41d7b6b6a3d5f8 /C/Sha3.c | |
parent | e008ce3976c087bfd21344af8f00a23cf69d4174 (diff) | |
download | 7zip-main.tar.gz 7zip-main.tar.bz2 7zip-main.zip |
Diffstat (limited to '')
-rw-r--r-- | C/Sha3.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/C/Sha3.c b/C/Sha3.c new file mode 100644 index 0000000..be972d6 --- /dev/null +++ b/C/Sha3.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* Sha3.c -- SHA-3 Hash | ||
2 | : Igor Pavlov : Public domain | ||
3 | This code is based on public domain code from Wei Dai's Crypto++ library. */ | ||
4 | |||
5 | #include "Precomp.h" | ||
6 | |||
7 | #include <string.h> | ||
8 | |||
9 | #include "Sha3.h" | ||
10 | #include "RotateDefs.h" | ||
11 | #include "CpuArch.h" | ||
12 | |||
13 | #define U64C(x) UINT64_CONST(x) | ||
14 | |||
15 | static | ||
16 | MY_ALIGN(64) | ||
17 | const UInt64 SHA3_K_ARRAY[24] = | ||
18 | { | ||
19 | U64C(0x0000000000000001), U64C(0x0000000000008082), | ||
20 | U64C(0x800000000000808a), U64C(0x8000000080008000), | ||
21 | U64C(0x000000000000808b), U64C(0x0000000080000001), | ||
22 | U64C(0x8000000080008081), U64C(0x8000000000008009), | ||
23 | U64C(0x000000000000008a), U64C(0x0000000000000088), | ||
24 | U64C(0x0000000080008009), U64C(0x000000008000000a), | ||
25 | U64C(0x000000008000808b), U64C(0x800000000000008b), | ||
26 | U64C(0x8000000000008089), U64C(0x8000000000008003), | ||
27 | U64C(0x8000000000008002), U64C(0x8000000000000080), | ||
28 | U64C(0x000000000000800a), U64C(0x800000008000000a), | ||
29 | U64C(0x8000000080008081), U64C(0x8000000000008080), | ||
30 | U64C(0x0000000080000001), U64C(0x8000000080008008) | ||
31 | }; | ||
32 | |||
33 | void Sha3_Init(CSha3 *p) | ||
34 | { | ||
35 | p->count = 0; | ||
36 | memset(p->state, 0, sizeof(p->state)); | ||
37 | } | ||
38 | |||
39 | #define GET_state(i, a) UInt64 a = state[i]; | ||
40 | #define SET_state(i, a) state[i] = a; | ||
41 | |||
42 | #define LS_5(M, i, a0,a1,a2,a3,a4) \ | ||
43 | M ((i) * 5 , a0) \ | ||
44 | M ((i) * 5 + 1, a1) \ | ||
45 | M ((i) * 5 + 2, a2) \ | ||
46 | M ((i) * 5 + 3, a3) \ | ||
47 | M ((i) * 5 + 4, a4) \ | ||
48 | |||
49 | #define LS_25(M) \ | ||
50 | LS_5 (M, 0, a50, a51, a52, a53, a54) \ | ||
51 | LS_5 (M, 1, a60, a61, a62, a63, a64) \ | ||
52 | LS_5 (M, 2, a70, a71, a72, a73, a74) \ | ||
53 | LS_5 (M, 3, a80, a81, a82, a83, a84) \ | ||
54 | LS_5 (M, 4, a90, a91, a92, a93, a94) \ | ||
55 | |||
56 | |||
57 | #define XOR_1(i, a0) \ | ||
58 | a0 ^= GetUi64(data + (i) * 8); \ | ||
59 | |||
60 | #define XOR_4(i, a0,a1,a2,a3) \ | ||
61 | XOR_1 ((i) , a0); \ | ||
62 | XOR_1 ((i) + 1, a1); \ | ||
63 | XOR_1 ((i) + 2, a2); \ | ||
64 | XOR_1 ((i) + 3, a3); \ | ||
65 | |||
66 | #define D(d,b1,b2) \ | ||
67 | d = b1 ^ Z7_ROTL64(b2, 1); | ||
68 | |||
69 | #define D5 \ | ||
70 | D (d0, c4, c1) \ | ||
71 | D (d1, c0, c2) \ | ||
72 | D (d2, c1, c3) \ | ||
73 | D (d3, c2, c4) \ | ||
74 | D (d4, c3, c0) \ | ||
75 | |||
76 | #define C0(c,a,d) \ | ||
77 | c = a ^ d; \ | ||
78 | |||
79 | #define C(c,a,d,k) \ | ||
80 | c = a ^ d; \ | ||
81 | c = Z7_ROTL64(c, k); \ | ||
82 | |||
83 | #define E4(e1,e2,e3,e4) \ | ||
84 | e1 = c1 ^ (~c2 & c3); \ | ||
85 | e2 = c2 ^ (~c3 & c4); \ | ||
86 | e3 = c3 ^ (~c4 & c0); \ | ||
87 | e4 = c4 ^ (~c0 & c1); \ | ||
88 | |||
89 | #define CK( v0,w0, \ | ||
90 | v1,w1,k1, \ | ||
91 | v2,w2,k2, \ | ||
92 | v3,w3,k3, \ | ||
93 | v4,w4,k4, e0,e1,e2,e3,e4, keccak_c) \ | ||
94 | C0(c0,v0,w0) \ | ||
95 | C (c1,v1,w1,k1) \ | ||
96 | C (c2,v2,w2,k2) \ | ||
97 | C (c3,v3,w3,k3) \ | ||
98 | C (c4,v4,w4,k4) \ | ||
99 | e0 = c0 ^ (~c1 & c2) ^ keccak_c; \ | ||
100 | E4(e1,e2,e3,e4) \ | ||
101 | |||
102 | #define CE( v0,w0,k0, \ | ||
103 | v1,w1,k1, \ | ||
104 | v2,w2,k2, \ | ||
105 | v3,w3,k3, \ | ||
106 | v4,w4,k4, e0,e1,e2,e3,e4) \ | ||
107 | C (c0,v0,w0,k0) \ | ||
108 | C (c1,v1,w1,k1) \ | ||
109 | C (c2,v2,w2,k2) \ | ||
110 | C (c3,v3,w3,k3) \ | ||
111 | C (c4,v4,w4,k4) \ | ||
112 | e0 = c0 ^ (~c1 & c2); \ | ||
113 | E4(e1,e2,e3,e4) \ | ||
114 | |||
115 | // numBlocks != 0 | ||
116 | static | ||
117 | Z7_NO_INLINE | ||
118 | void Z7_FASTCALL Sha3_UpdateBlocks(UInt64 state[SHA3_NUM_STATE_WORDS], | ||
119 | const Byte *data, size_t numBlocks, size_t blockSize) | ||
120 | { | ||
121 | LS_25 (GET_state) | ||
122 | |||
123 | do | ||
124 | { | ||
125 | unsigned round; | ||
126 | XOR_4 ( 0, a50, a51, a52, a53) | ||
127 | XOR_4 ( 4, a54, a60, a61, a62) | ||
128 | XOR_1 ( 8, a63) | ||
129 | if (blockSize > 8 * 9) { XOR_4 ( 9, a64, a70, a71, a72) // sha3-384 | ||
130 | if (blockSize > 8 * 13) { XOR_4 (13, a73, a74, a80, a81) // sha3-256 | ||
131 | if (blockSize > 8 * 17) { XOR_1 (17, a82) // sha3-224 | ||
132 | if (blockSize > 8 * 18) { XOR_1 (18, a83) // shake128 | ||
133 | XOR_1 (19, a84) | ||
134 | XOR_1 (20, a90) }}}} | ||
135 | data += blockSize; | ||
136 | |||
137 | for (round = 0; round < 24; round += 2) | ||
138 | { | ||
139 | UInt64 c0, c1, c2, c3, c4; | ||
140 | UInt64 d0, d1, d2, d3, d4; | ||
141 | UInt64 e50, e51, e52, e53, e54; | ||
142 | UInt64 e60, e61, e62, e63, e64; | ||
143 | UInt64 e70, e71, e72, e73, e74; | ||
144 | UInt64 e80, e81, e82, e83, e84; | ||
145 | UInt64 e90, e91, e92, e93, e94; | ||
146 | |||
147 | c0 = a50^a60^a70^a80^a90; | ||
148 | c1 = a51^a61^a71^a81^a91; | ||
149 | c2 = a52^a62^a72^a82^a92; | ||
150 | c3 = a53^a63^a73^a83^a93; | ||
151 | c4 = a54^a64^a74^a84^a94; | ||
152 | D5 | ||
153 | CK( a50, d0, | ||
154 | a61, d1, 44, | ||
155 | a72, d2, 43, | ||
156 | a83, d3, 21, | ||
157 | a94, d4, 14, e50, e51, e52, e53, e54, SHA3_K_ARRAY[round]) | ||
158 | CE( a53, d3, 28, | ||
159 | a64, d4, 20, | ||
160 | a70, d0, 3, | ||
161 | a81, d1, 45, | ||
162 | a92, d2, 61, e60, e61, e62, e63, e64) | ||
163 | CE( a51, d1, 1, | ||
164 | a62, d2, 6, | ||
165 | a73, d3, 25, | ||
166 | a84, d4, 8, | ||
167 | a90, d0, 18, e70, e71, e72, e73, e74) | ||
168 | CE( a54, d4, 27, | ||
169 | a60, d0, 36, | ||
170 | a71, d1, 10, | ||
171 | a82, d2, 15, | ||
172 | a93, d3, 56, e80, e81, e82, e83, e84) | ||
173 | CE( a52, d2, 62, | ||
174 | a63, d3, 55, | ||
175 | a74, d4, 39, | ||
176 | a80, d0, 41, | ||
177 | a91, d1, 2, e90, e91, e92, e93, e94) | ||
178 | |||
179 | // ---------- ROUND + 1 ---------- | ||
180 | |||
181 | c0 = e50^e60^e70^e80^e90; | ||
182 | c1 = e51^e61^e71^e81^e91; | ||
183 | c2 = e52^e62^e72^e82^e92; | ||
184 | c3 = e53^e63^e73^e83^e93; | ||
185 | c4 = e54^e64^e74^e84^e94; | ||
186 | D5 | ||
187 | CK( e50, d0, | ||
188 | e61, d1, 44, | ||
189 | e72, d2, 43, | ||
190 | e83, d3, 21, | ||
191 | e94, d4, 14, a50, a51, a52, a53, a54, SHA3_K_ARRAY[(size_t)round + 1]) | ||
192 | CE( e53, d3, 28, | ||
193 | e64, d4, 20, | ||
194 | e70, d0, 3, | ||
195 | e81, d1, 45, | ||
196 | e92, d2, 61, a60, a61, a62, a63, a64) | ||
197 | CE( e51, d1, 1, | ||
198 | e62, d2, 6, | ||
199 | e73, d3, 25, | ||
200 | e84, d4, 8, | ||
201 | e90, d0, 18, a70, a71, a72, a73, a74) | ||
202 | CE (e54, d4, 27, | ||
203 | e60, d0, 36, | ||
204 | e71, d1, 10, | ||
205 | e82, d2, 15, | ||
206 | e93, d3, 56, a80, a81, a82, a83, a84) | ||
207 | CE (e52, d2, 62, | ||
208 | e63, d3, 55, | ||
209 | e74, d4, 39, | ||
210 | e80, d0, 41, | ||
211 | e91, d1, 2, a90, a91, a92, a93, a94) | ||
212 | } | ||
213 | } | ||
214 | while (--numBlocks); | ||
215 | |||
216 | LS_25 (SET_state) | ||
217 | } | ||
218 | |||
219 | |||
220 | #define Sha3_UpdateBlock(p) \ | ||
221 | Sha3_UpdateBlocks(p->state, p->buffer, 1, p->blockSize) | ||
222 | |||
223 | void Sha3_Update(CSha3 *p, const Byte *data, size_t size) | ||
224 | { | ||
225 | /* | ||
226 | for (;;) | ||
227 | { | ||
228 | if (size == 0) | ||
229 | return; | ||
230 | unsigned cur = p->blockSize - p->count; | ||
231 | if (cur > size) | ||
232 | cur = (unsigned)size; | ||
233 | size -= cur; | ||
234 | unsigned pos = p->count; | ||
235 | p->count = pos + cur; | ||
236 | while (pos & 7) | ||
237 | { | ||
238 | if (cur == 0) | ||
239 | return; | ||
240 | Byte *pb = &(((Byte *)p->state)[pos]); | ||
241 | *pb = (Byte)(*pb ^ *data++); | ||
242 | cur--; | ||
243 | pos++; | ||
244 | } | ||
245 | if (cur >= 8) | ||
246 | { | ||
247 | do | ||
248 | { | ||
249 | *(UInt64 *)(void *)&(((Byte *)p->state)[pos]) ^= GetUi64(data); | ||
250 | data += 8; | ||
251 | pos += 8; | ||
252 | cur -= 8; | ||
253 | } | ||
254 | while (cur >= 8); | ||
255 | } | ||
256 | if (pos != p->blockSize) | ||
257 | { | ||
258 | if (cur) | ||
259 | { | ||
260 | Byte *pb = &(((Byte *)p->state)[pos]); | ||
261 | do | ||
262 | { | ||
263 | *pb = (Byte)(*pb ^ *data++); | ||
264 | pb++; | ||
265 | } | ||
266 | while (--cur); | ||
267 | } | ||
268 | return; | ||
269 | } | ||
270 | Sha3_UpdateBlock(p->state); | ||
271 | p->count = 0; | ||
272 | } | ||
273 | */ | ||
274 | if (size == 0) | ||
275 | return; | ||
276 | { | ||
277 | const unsigned pos = p->count; | ||
278 | const unsigned num = p->blockSize - pos; | ||
279 | if (num > size) | ||
280 | { | ||
281 | p->count = pos + (unsigned)size; | ||
282 | memcpy(p->buffer + pos, data, size); | ||
283 | return; | ||
284 | } | ||
285 | if (pos != 0) | ||
286 | { | ||
287 | size -= num; | ||
288 | memcpy(p->buffer + pos, data, num); | ||
289 | data += num; | ||
290 | Sha3_UpdateBlock(p); | ||
291 | } | ||
292 | } | ||
293 | if (size >= p->blockSize) | ||
294 | { | ||
295 | const size_t numBlocks = size / p->blockSize; | ||
296 | const Byte *dataOld = data; | ||
297 | data += numBlocks * p->blockSize; | ||
298 | size = (size_t)(dataOld + size - data); | ||
299 | Sha3_UpdateBlocks(p->state, dataOld, numBlocks, p->blockSize); | ||
300 | } | ||
301 | p->count = (unsigned)size; | ||
302 | if (size) | ||
303 | memcpy(p->buffer, data, size); | ||
304 | } | ||
305 | |||
306 | |||
307 | // we support only (digestSize % 4 == 0) cases | ||
308 | void Sha3_Final(CSha3 *p, Byte *digest, unsigned digestSize, unsigned shake) | ||
309 | { | ||
310 | memset(p->buffer + p->count, 0, p->blockSize - p->count); | ||
311 | // we write bits markers from low to higher in current byte: | ||
312 | // - if sha-3 : 2 bits : 0,1 | ||
313 | // - if shake : 4 bits : 1111 | ||
314 | // then we write bit 1 to same byte. | ||
315 | // And we write bit 1 to highest bit of last byte of block. | ||
316 | p->buffer[p->count] = (Byte)(shake ? 0x1f : 0x06); | ||
317 | // we need xor operation (^= 0x80) here because we must write 0x80 bit | ||
318 | // to same byte as (0x1f : 0x06), if (p->count == p->blockSize - 1) !!! | ||
319 | p->buffer[p->blockSize - 1] ^= 0x80; | ||
320 | /* | ||
321 | ((Byte *)p->state)[p->count] ^= (Byte)(shake ? 0x1f : 0x06); | ||
322 | ((Byte *)p->state)[p->blockSize - 1] ^= 0x80; | ||
323 | */ | ||
324 | Sha3_UpdateBlock(p); | ||
325 | #if 1 && defined(MY_CPU_LE) | ||
326 | memcpy(digest, p->state, digestSize); | ||
327 | #else | ||
328 | { | ||
329 | const unsigned numWords = digestSize >> 3; | ||
330 | unsigned i; | ||
331 | for (i = 0; i < numWords; i++) | ||
332 | { | ||
333 | const UInt64 v = p->state[i]; | ||
334 | SetUi64(digest, v) | ||
335 | digest += 8; | ||
336 | } | ||
337 | if (digestSize & 4) // for SHA3-224 | ||
338 | { | ||
339 | const UInt32 v = (UInt32)p->state[numWords]; | ||
340 | SetUi32(digest, v) | ||
341 | } | ||
342 | } | ||
343 | #endif | ||
344 | Sha3_Init(p); | ||
345 | } | ||
346 | |||
347 | #undef GET_state | ||
348 | #undef SET_state | ||
349 | #undef LS_5 | ||
350 | #undef LS_25 | ||
351 | #undef XOR_1 | ||
352 | #undef XOR_4 | ||
353 | #undef D | ||
354 | #undef D5 | ||
355 | #undef C0 | ||
356 | #undef C | ||
357 | #undef E4 | ||
358 | #undef CK | ||
359 | #undef CE | ||