php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
hash_sha3.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Sara Golemon <pollita@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#include "php_hash.h"
18#include "php_hash_sha3.h"
19
20#ifdef HAVE_SLOW_HASH3
21// ================= slow algo ==============================================
22
23#if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
24 (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
25# if defined(__LITTLE_ENDIAN__)
26# undef WORDS_BIGENDIAN
27# else
28# if defined(__BIG_ENDIAN__)
29# define WORDS_BIGENDIAN
30# endif
31# endif
32#endif
33
34static inline uint64_t rol64(uint64_t v, unsigned char b) {
35 return (v << b) | (v >> (64 - b));
36}
37static inline unsigned char idx(unsigned char x, unsigned char y) {
38 return x + (5 * y);
39}
40
41#ifdef WORDS_BIGENDIAN
42static inline uint64_t load64(const unsigned char* x) {
43 signed char i;
44 uint64_t ret = 0;
45 for (i = 7; i >= 0; --i) {
46 ret <<= 8;
47 ret |= x[i];
48 }
49 return ret;
50}
51static inline void store64(unsigned char* x, uint64_t val) {
52 size_t i;
53 for (i = 0; i < 8; ++i) {
54 x[i] = val & 0xFF;
55 val >>= 8;
56 }
57}
58static inline void xor64(unsigned char* x, uint64_t val) {
59 size_t i;
60 for (i = 0; i < 8; ++i) {
61 x[i] ^= val & 0xFF;
62 val >>= 8;
63 }
64}
65# define readLane(x, y) load64(ctx->state+sizeof(uint64_t)*idx(x, y))
66# define writeLane(x, y, v) store64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
67# define XORLane(x, y, v) xor64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
68#else
69# define readLane(x, y) (((uint64_t*)ctx->state)[idx(x,y)])
70# define writeLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] = v)
71# define XORLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] ^= v)
72#endif
73
74static inline char LFSR86540(unsigned char* pLFSR)
75{
76 unsigned char LFSR = *pLFSR;
77 char result = LFSR & 0x01;
78 if (LFSR & 0x80) {
79 // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
80 LFSR = (LFSR << 1) ^ 0x71;
81 } else {
82 LFSR <<= 1;
83 }
84 *pLFSR = LFSR;
85 return result;
86}
87
88static void permute(PHP_SHA3_CTX* ctx) {
89 unsigned char LFSRstate = 0x01;
90 unsigned char round;
91
92 for (round = 0; round < 24; ++round) {
93 { // Theta step (see [Keccak Reference, Section 2.3.2])
94 uint64_t C[5], D;
95 unsigned char x, y;
96 for (x = 0; x < 5; ++x) {
97 C[x] = readLane(x, 0) ^ readLane(x, 1) ^
98 readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
99 }
100 for (x = 0; x < 5; ++x) {
101 D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
102 for (y = 0; y < 5; ++y) {
103 XORLane(x, y, D);
104 }
105 }
106 }
107
108 { // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
109 unsigned char x = 1, y = 0, t;
110 uint64_t current = readLane(x, y);
111 for (t = 0; t < 24; ++t) {
112 unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
113 unsigned char Y = (2*x + 3*y) % 5;
114 uint64_t temp;
115 x = y;
116 y = Y;
117 temp = readLane(x, y);
118 writeLane(x, y, rol64(current, r));
119 current = temp;
120 }
121 }
122
123 { // X step (see [Keccak Reference, Section 2.3.1])
124 unsigned char x, y;
125 for (y = 0; y < 5; ++y) {
126 uint64_t temp[5];
127 for (x = 0; x < 5; ++x) {
128 temp[x] = readLane(x, y);
129 }
130 for (x = 0; x < 5; ++x) {
131 writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
132 }
133 }
134 }
135
136 { // i step (see [Keccak Reference, Section 2.3.5])
137 unsigned char j;
138 for (j = 0; j < 7; ++j) {
139 if (LFSR86540(&LFSRstate)) {
140 uint64_t bitPos = (1<<j) - 1;
141 XORLane(0, 0, (uint64_t)1 << bitPos);
142 }
143 }
144 }
145 }
146}
147
148// ==========================================================================
149
150static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
151 int bits) {
152 memset(ctx, 0, sizeof(PHP_SHA3_CTX));
153}
154
155static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
156 const unsigned char* buf,
157 size_t count,
158 size_t block_size) {
159 while (count > 0) {
160 size_t len = block_size - ctx->pos;
161
162 if (len > count) {
163 len = count;
164 }
165
166 count -= len;
167
168 while (len-- > 0) {
169 ctx->state[ctx->pos++] ^= *(buf++);
170 }
171
172 if (ctx->pos >= block_size) {
173 permute(ctx);
174 ctx->pos = 0;
175 }
176 }
177}
178
179static void PHP_SHA3_Final(unsigned char* digest,
180 PHP_SHA3_CTX* ctx,
181 size_t block_size,
182 size_t digest_size) {
183 size_t len = digest_size;
184
185 // Pad state to finalize
186 ctx->state[ctx->pos++] ^= 0x06;
187 ctx->state[block_size-1] ^= 0x80;
188 permute(ctx);
189
190 // Square output for digest
191 for(;;) {
192 int bs = (len < block_size) ? len : block_size;
193 digest = zend_mempcpy(digest, ctx->state, bs);
194 len -= bs;
195 if (!len) break;
196 permute(ctx);
197 }
198
199 // Zero out context
200 ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
201}
202
203static int php_sha3_unserialize(php_hashcontext_object *hash,
205 const zval *zv,
206 size_t block_size)
207{
208 PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context;
209 int r = FAILURE;
211 && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == SUCCESS
212 && ctx->pos < block_size) {
213 return SUCCESS;
214 } else {
215 return r != SUCCESS ? r : -2000;
216 }
217}
218
219// ==========================================================================
220
221#define DECLARE_SHA3_OPS(bits) \
222void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
223 PHP_SHA3_Init(ctx, bits); \
224} \
225void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
226 const unsigned char* input, \
227 size_t inputLen) { \
228 PHP_SHA3_Update(ctx, input, inputLen, \
229 (1600 - (2 * bits)) >> 3); \
230} \
231void PHP_SHA3##bits##Final(unsigned char* digest, \
232 PHP_SHA3_##bits##_CTX* ctx) { \
233 PHP_SHA3_Final(digest, ctx, \
234 (1600 - (2 * bits)) >> 3, \
235 bits >> 3); \
236} \
237static int php_sha3##bits##_unserialize(php_hashcontext_object *hash, \
238 zend_long magic, \
239 const zval *zv) { \
240 return php_sha3_unserialize(hash, magic, zv, (1600 - (2 * bits)) >> 3); \
241} \
242const php_hash_ops php_hash_sha3_##bits##_ops = { \
243 "sha3-" #bits, \
244 (php_hash_init_func_t) PHP_SHA3##bits##Init, \
245 (php_hash_update_func_t) PHP_SHA3##bits##Update, \
246 (php_hash_final_func_t) PHP_SHA3##bits##Final, \
247 php_hash_copy, \
248 php_hash_serialize, \
249 php_sha3##bits##_unserialize, \
250 PHP_SHA3_SPEC, \
251 bits >> 3, \
252 (1600 - (2 * bits)) >> 3, \
253 sizeof(PHP_SHA3_##bits##_CTX), \
254 1 \
255}
256
257#else
258
259// ================= fast algo ==============================================
260
261#define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
262#include "KeccakHash.h"
263
264/* KECCAK SERIALIZATION
265
266 Keccak_HashInstance consists of:
267 KeccakWidth1600_SpongeInstance {
268 unsigned char state[200];
269 unsigned int rate; -- fixed for digest size
270 unsigned int byteIOIndex; -- in range [0, rate/8)
271 int squeezing; -- 0 normally, 1 only during finalize
272 } sponge;
273 unsigned int fixedOutputLength; -- fixed for digest size
274 unsigned char delimitedSuffix; -- fixed for digest size
275
276 NB If the external sha3/ library is updated, the serialization code
277 may need to be updated.
278
279 The simpler SHA3 code's serialization states are not interchangeable with
280 Keccak. Furthermore, the Keccak sponge state is sensitive to architecture
281 -- 32-bit and 64-bit implementations produce different states. It does not
282 appear that the state is sensitive to endianness. */
283
284#if Keccak_HashInstance_ImplType == 64
285/* corresponds to sha3/generic64lc */
286# define PHP_HASH_SERIALIZE_MAGIC_KECCAK 100
287#elif Keccak_HashInstance_ImplType == 32
288/* corresponds to sha3/generic32lc */
289# define PHP_HASH_SERIALIZE_MAGIC_KECCAK 101
290#else
291# error "Unknown Keccak_HashInstance_ImplType"
292#endif
293#define PHP_KECCAK_SPEC "b200IiIIB"
294
295static zend_result php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv)
296{
297 *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
299}
300
301static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
302{
303 Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
304 int r = FAILURE;
305 if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK
307 && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
308 return SUCCESS;
309 } else {
310 return r != SUCCESS ? r : -2000;
311 }
312}
313
314// ==========================================================================
315
316#define DECLARE_SHA3_OPS(bits) \
317void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args) { \
318 ZEND_ASSERT(sizeof(Keccak_HashInstance) <= sizeof(PHP_SHA3_##bits##_CTX)); \
319 Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx); \
320} \
321void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
322 const unsigned char* input, \
323 size_t inputLen) { \
324 Keccak_HashUpdate((Keccak_HashInstance *)ctx, input, inputLen * 8); \
325} \
326void PHP_SHA3##bits##Final(unsigned char* digest, \
327 PHP_SHA3_##bits##_CTX* ctx) { \
328 Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \
329} \
330const php_hash_ops php_hash_sha3_##bits##_ops = { \
331 "sha3-" #bits, \
332 (php_hash_init_func_t) PHP_SHA3##bits##Init, \
333 (php_hash_update_func_t) PHP_SHA3##bits##Update, \
334 (php_hash_final_func_t) PHP_SHA3##bits##Final, \
335 php_hash_copy, \
336 php_keccak_serialize, \
337 php_keccak_unserialize, \
338 PHP_KECCAK_SPEC, \
339 bits >> 3, \
340 (1600 - (2 * bits)) >> 3, \
341 sizeof(PHP_SHA3_CTX), \
342 1 \
343}
344
345#endif
346// ================= both algo ==============================================
347
352
353#undef DECLARE_SHA3_OPS
size_t len
Definition apprentice.c:174
count(Countable|array $value, int $mode=COUNT_NORMAL)
uint32_t v
Definition cdf.c:1237
zval * zv
Definition ffi.c:3975
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
PHP_HASH_API zend_result php_hash_serialize_spec(const php_hashcontext_object *hash, zval *zv, const char *spec)
Definition hash.c:232
PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec)
Definition hash.c:280
hash(string $algo, string $data, bool $binary=false, array $options=[])
Definition hash.stub.php:12
#define round(tables, k1, k2)
Definition hash_gost.c:26
#define C(x)
Definition hash_gost.c:111
#define PHP_KECCAK_SPEC
Definition hash_sha3.c:293
#define SUCCESS
Definition hash_sha3.c:261
#define DECLARE_SHA3_OPS(bits)
Definition hash_sha3.c:316
again j
struct _php_hashcontext_object php_hashcontext_object
Definition php_hash.h:32
#define PHP_HASH_SERIALIZE_MAGIC_SPEC
Definition php_hash.h:28
zval * current
Definition session.c:1024
#define D(d)
unsigned char state[224]
Definition file.h:202
struct _zval_struct zval
int32_t zend_long
Definition zend_long.h:42
#define ZEND_SECURE_ZERO(var, size)
@ FAILURE
Definition zend_types.h:61
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
bool result
zval * ret