Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tpruvot
GitHub Repository: tpruvot/cpuminer-multi
Path: blob/linux/sha3/sph_hefty1.c
1201 views
1
/*
2
* HEFTY1 cryptographic hash function
3
*
4
* Copyright (c) 2014, dbcc14 <BM-NBx4AKznJuyem3dArgVY8MGyABpihRy5>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright notice, this
11
* list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright notice,
13
* this list of conditions and the following disclaimer in the documentation
14
* and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*
27
* The views and conclusions contained in the software and documentation are those
28
* of the authors and should not be interpreted as representing official policies,
29
* either expressed or implied, of the FreeBSD Project.
30
*/
31
32
#include <assert.h>
33
#include <string.h>
34
35
#ifdef _MSC_VER
36
#define inline __inline
37
#endif
38
39
#include "sph_hefty1.h"
40
41
#define Min(A, B) (A <= B ? A : B)
42
#define RoundFunc(ctx, A, B, C, D, E, F, G, H, W, K) \
43
{ \
44
/* To thwart parallelism, Br modifies itself each time it's \
45
* called. This also means that calling it in different \
46
* orders yeilds different results. In C the order of \
47
* evaluation of function arguments and + operands are \
48
* unspecified (and depends on the compiler), so we must make \
49
* the order of Br calls explicit. \
50
*/ \
51
uint32_t brG = Br(ctx, G); \
52
uint32_t tmp1 = Ch(E, Br(ctx, F), brG) + H + W + K; \
53
uint32_t tmp2 = tmp1 + Sigma1(Br(ctx, E)); \
54
uint32_t brC = Br(ctx, C); \
55
uint32_t brB = Br(ctx, B); \
56
uint32_t tmp3 = Ma(Br(ctx, A), brB, brC); \
57
uint32_t tmp4 = tmp3 + Sigma0(Br(ctx, A)); \
58
H = G; \
59
G = F; \
60
F = E; \
61
E = D + Br(ctx, tmp2); \
62
D = C; \
63
C = B; \
64
B = A; \
65
A = tmp2 + tmp4; \
66
} \
67
68
/* Nothing up my sleeve constants */
69
const static uint32_t K[64] = {
70
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
71
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
72
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
73
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
74
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
75
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
76
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
77
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
78
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
79
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
80
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
81
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
82
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
83
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
84
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
85
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
86
};
87
88
/* Initial hash values */
89
const static uint32_t H[HEFTY1_STATE_WORDS] = {
90
0x6a09e667UL,
91
0xbb67ae85UL,
92
0x3c6ef372UL,
93
0xa54ff53aUL,
94
0x510e527fUL,
95
0x9b05688cUL,
96
0x1f83d9abUL,
97
0x5be0cd19UL
98
};
99
100
static inline uint32_t Rr(uint32_t X, uint8_t n)
101
{
102
return (X >> n) | (X << (32 - n));
103
}
104
105
static inline uint32_t Ch(uint32_t E, uint32_t F, uint32_t G)
106
{
107
return (E & F) ^ (~E & G);
108
}
109
110
static inline uint32_t Sigma1(uint32_t E)
111
{
112
return Rr(E, 6) ^ Rr(E, 11) ^ Rr(E, 25);
113
}
114
115
static inline uint32_t sigma1(uint32_t X)
116
{
117
return Rr(X, 17) ^ Rr(X, 19) ^ (X >> 10);
118
}
119
120
static inline uint32_t Ma(uint32_t A, uint32_t B, uint32_t C)
121
{
122
return (A & B) ^ (A & C) ^ (B & C);
123
}
124
125
static inline uint32_t Sigma0(uint32_t A)
126
{
127
return Rr(A, 2) ^ Rr(A, 13) ^ Rr(A, 22);
128
}
129
130
static inline uint32_t sigma0(uint32_t X)
131
{
132
return Rr(X, 7) ^ Rr(X, 18) ^ (X >> 3);
133
}
134
135
static inline uint32_t Reverse32(uint32_t n)
136
{
137
#if BYTE_ORDER == LITTLE_ENDIAN
138
return n << 24 | (n & 0x0000ff00) << 8 | (n & 0x00ff0000) >> 8 | n >> 24;
139
#else
140
return n;
141
#endif
142
}
143
144
static inline uint64_t Reverse64(uint64_t n)
145
{
146
#if BYTE_ORDER == LITTLE_ENDIAN
147
uint32_t a = n >> 32;
148
uint32_t b = (n << 32) >> 32;
149
150
return (uint64_t)Reverse32(b) << 32 | Reverse32(a);
151
#else
152
return n;
153
#endif
154
}
155
156
/* Smoosh byte into nibble */
157
static inline uint8_t Smoosh4(uint8_t X)
158
{
159
return (X >> 4) ^ (X & 0xf);
160
}
161
162
/* Smoosh 32-bit word into 2-bits */
163
static inline uint8_t Smoosh2(uint32_t X)
164
{
165
uint16_t w = (X >> 16) ^ (X & 0xffff);
166
uint8_t n = Smoosh4((w >> 8) ^ (w & 0xff));
167
return (n >> 2) ^ (n & 0x3);
168
}
169
170
static void Mangle(uint32_t *S)
171
{
172
uint32_t *R = S;
173
uint32_t *C = &S[1];
174
175
uint8_t r0 = Smoosh4(R[0] >> 24);
176
uint8_t r1 = Smoosh4(R[0] >> 16);
177
uint8_t r2 = Smoosh4(R[0] >> 8);
178
uint8_t r3 = Smoosh4(R[0] & 0xff);
179
180
int i;
181
182
/* Diffuse */
183
uint32_t tmp = 0;
184
for (i = 0; i < HEFTY1_SPONGE_WORDS - 1; i++) {
185
uint8_t r = Smoosh2(tmp);
186
switch (r) {
187
case 0:
188
C[i] ^= Rr(R[0], i + r0);
189
break;
190
case 1:
191
C[i] += Rr(~R[0], i + r1);
192
break;
193
case 2:
194
C[i] &= Rr(~R[0], i + r2);
195
break;
196
case 3:
197
C[i] ^= Rr(R[0], i + r3);
198
break;
199
}
200
tmp ^= C[i];
201
}
202
203
/* Compress */
204
tmp = 0;
205
for (i = 0; i < HEFTY1_SPONGE_WORDS - 1; i++)
206
if (i % 2)
207
tmp ^= C[i];
208
else
209
tmp += C[i];
210
R[0] ^= tmp;
211
}
212
213
static void Absorb(uint32_t *S, uint32_t X)
214
{
215
uint32_t *R = S;
216
R[0] ^= X;
217
Mangle(S);
218
}
219
220
static uint32_t Squeeze(uint32_t *S)
221
{
222
uint32_t Y = S[0];
223
Mangle(S);
224
return Y;
225
}
226
227
/* Branch, compress and serialize function */
228
static inline uint32_t Br(HEFTY1_CTX *ctx, uint32_t X)
229
{
230
uint32_t R = Squeeze(ctx->sponge);
231
232
uint8_t r0 = R >> 8;
233
uint8_t r1 = R & 0xff;
234
235
uint32_t Y = 1 << (r0 % 32);
236
237
switch (r1 % 4)
238
{
239
case 0:
240
/* Do nothing */
241
break;
242
case 1:
243
return X & ~Y;
244
case 2:
245
return X | Y;
246
case 3:
247
return X ^ Y;
248
}
249
250
return X;
251
}
252
253
static void HashBlock(HEFTY1_CTX *ctx)
254
{
255
uint32_t A, B, C, D, E, F, G, H;
256
uint32_t W[HEFTY1_BLOCK_BYTES];
257
258
assert(ctx);
259
260
A = ctx->h[0];
261
B = ctx->h[1];
262
C = ctx->h[2];
263
D = ctx->h[3];
264
E = ctx->h[4];
265
F = ctx->h[5];
266
G = ctx->h[6];
267
H = ctx->h[7];
268
269
int t = 0;
270
for (; t < 16; t++) {
271
W[t] = Reverse32(((uint32_t *)&ctx->block[0])[t]); /* To host byte order */
272
Absorb(ctx->sponge, W[t] ^ K[t]);
273
}
274
275
for (t = 0; t < 16; t++) {
276
Absorb(ctx->sponge, D ^ H);
277
RoundFunc(ctx, A, B, C, D, E, F, G, H, W[t], K[t]);
278
}
279
for (t = 16; t < 64; t++) {
280
Absorb(ctx->sponge, H + D);
281
W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + W[t - 16];
282
RoundFunc(ctx, A, B, C, D, E, F, G, H, W[t], K[t]);
283
}
284
285
ctx->h[0] += A;
286
ctx->h[1] += B;
287
ctx->h[2] += C;
288
ctx->h[3] += D;
289
ctx->h[4] += E;
290
ctx->h[5] += F;
291
ctx->h[6] += G;
292
ctx->h[7] += H;
293
294
A = 0;
295
B = 0;
296
C = 0;
297
D = 0;
298
E = 0;
299
F = 0;
300
G = 0;
301
H = 0;
302
303
memset(W, 0, sizeof(W));
304
}
305
306
/* Public interface */
307
308
void HEFTY1_Init(HEFTY1_CTX *ctx)
309
{
310
assert(ctx);
311
312
memcpy(ctx->h, H, sizeof(ctx->h));
313
memset(ctx->block, 0, sizeof(ctx->block));
314
ctx->written = 0;
315
memset(ctx->sponge, 0, sizeof(ctx->sponge));
316
}
317
318
void HEFTY1_Update(HEFTY1_CTX *ctx, const void *buf, size_t len)
319
{
320
assert(ctx);
321
322
uint64_t read = 0;
323
while (len) {
324
size_t end = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES);
325
size_t count = Min(len, HEFTY1_BLOCK_BYTES - end);
326
memcpy(&ctx->block[end], &((unsigned char *)buf)[read], count);
327
len -= count;
328
read += count;
329
ctx->written += count;
330
if (!(ctx->written % HEFTY1_BLOCK_BYTES))
331
HashBlock(ctx);
332
}
333
}
334
335
void HEFTY1_Final(unsigned char *digest, HEFTY1_CTX *ctx)
336
{
337
assert(digest);
338
assert(ctx);
339
340
/* Pad message (FIPS 180 Section 5.1.1) */
341
size_t used = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES);
342
ctx->block[used++] = 0x80; /* Append 1 to end of message */
343
if (used > HEFTY1_BLOCK_BYTES - 8) {
344
/* We have already written into the last 64bits, so
345
* we must continue into the next block. */
346
memset(&ctx->block[used], 0, HEFTY1_BLOCK_BYTES - used);
347
HashBlock(ctx);
348
used = 0; /* Create a new block (below) */
349
}
350
351
/* All remaining bits to zero */
352
memset(&ctx->block[used], 0, HEFTY1_BLOCK_BYTES - 8 - used);
353
354
/* The last 64bits encode the length (in network byte order) */
355
uint64_t *len = (uint64_t *)&ctx->block[HEFTY1_BLOCK_BYTES - 8];
356
*len = Reverse64(ctx->written*8);
357
358
HashBlock(ctx);
359
360
/* Convert back to network byte order */
361
int i = 0;
362
for (; i < HEFTY1_STATE_WORDS; i++)
363
ctx->h[i] = Reverse32(ctx->h[i]);
364
365
memcpy(digest, ctx->h, sizeof(ctx->h));
366
memset(ctx, 0, sizeof(HEFTY1_CTX));
367
}
368
369
unsigned char* HEFTY1(const unsigned char *buf, size_t len, unsigned char *digest)
370
{
371
HEFTY1_CTX ctx;
372
static unsigned char m[HEFTY1_DIGEST_BYTES];
373
374
if (!digest)
375
digest = m;
376
377
HEFTY1_Init(&ctx);
378
HEFTY1_Update(&ctx, buf, len);
379
HEFTY1_Final(digest, &ctx);
380
381
return digest;
382
}
383