xref: /PHP-7.4/ext/hash/hash_sha3.c (revision 588db7ce)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Sara Golemon <pollita@php.net>                               |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php_hash.h"
20 #include "php_hash_sha3.h"
21 
22 #ifdef HAVE_SLOW_HASH3
23 // ================= slow algo ==============================================
24 
25 #if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
26     (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
27 # if defined(__LITTLE_ENDIAN__)
28 #  undef WORDS_BIGENDIAN
29 # else
30 #  if defined(__BIG_ENDIAN__)
31 #   define WORDS_BIGENDIAN
32 #  endif
33 # endif
34 #endif
35 
rol64(uint64_t v,unsigned char b)36 static inline uint64_t rol64(uint64_t v, unsigned char b) {
37 	return (v << b) | (v >> (64 - b));
38 }
idx(unsigned char x,unsigned char y)39 static inline unsigned char idx(unsigned char x, unsigned char y) {
40 	return x + (5 * y);
41 }
42 
43 #ifdef WORDS_BIGENDIAN
load64(const unsigned char * x)44 static inline uint64_t load64(const unsigned char* x) {
45 	signed char i;
46 	uint64_t ret = 0;
47 	for (i = 7; i >= 0; --i) {
48 		ret <<= 8;
49 		ret |= x[i];
50 	}
51 	return ret;
52 }
store64(unsigned char * x,uint64_t val)53 static inline void store64(unsigned char* x, uint64_t val) {
54 	char i;
55 	for (i = 0; i < 8; ++i) {
56 		x[i] = val & 0xFF;
57 		val >>= 8;
58 	}
59 }
xor64(unsigned char * x,uint64_t val)60 static inline void xor64(unsigned char* x, uint64_t val) {
61 	char i;
62 	for (i = 0; i < 8; ++i) {
63 		x[i] ^= val & 0xFF;
64 		val >>= 8;
65 	}
66 }
67 # define readLane(x, y)     load64(ctx->state+sizeof(uint64_t)*idx(x, y))
68 # define writeLane(x, y, v) store64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
69 # define XORLane(x, y, v)   xor64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
70 #else
71 # define readLane(x, y)     (((uint64_t*)ctx->state)[idx(x,y)])
72 # define writeLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] = v)
73 # define XORLane(x, y, v)   (((uint64_t*)ctx->state)[idx(x,y)] ^= v)
74 #endif
75 
LFSR86540(unsigned char * pLFSR)76 static inline char LFSR86540(unsigned char* pLFSR)
77 {
78 	unsigned char LFSR = *pLFSR;
79 	char result = LFSR & 0x01;
80 	if (LFSR & 0x80) {
81 		// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
82 		LFSR = (LFSR << 1) ^ 0x71;
83 	} else {
84 		LFSR <<= 1;
85 	}
86 	*pLFSR = LFSR;
87 	return result;
88 }
89 
permute(PHP_SHA3_CTX * ctx)90 static void permute(PHP_SHA3_CTX* ctx) {
91 	unsigned char LFSRstate = 0x01;
92 	unsigned char round;
93 
94 	for (round = 0; round < 24; ++round) {
95 		{ // Theta step (see [Keccak Reference, Section 2.3.2])
96 			uint64_t C[5], D;
97 			unsigned char x, y;
98 			for (x = 0; x < 5; ++x) {
99 				C[x] = readLane(x, 0) ^ readLane(x, 1) ^
100 				readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
101 			}
102 			for (x = 0; x < 5; ++x) {
103 				D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
104 				for (y = 0; y < 5; ++y) {
105 					XORLane(x, y, D);
106 				}
107 			}
108 		}
109 
110 		{ // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
111 			unsigned char x = 1, y = 0, t;
112 			uint64_t current = readLane(x, y);
113 			for (t = 0; t < 24; ++t) {
114 				unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
115 				unsigned char Y = (2*x + 3*y) % 5;
116 				uint64_t temp;
117 				x = y;
118 				y = Y;
119 				temp = readLane(x, y);
120 				writeLane(x, y, rol64(current, r));
121 				current = temp;
122 			}
123 		}
124 
125 		{ // X step (see [Keccak Reference, Section 2.3.1])
126 			unsigned char x, y;
127 			for (y = 0; y < 5; ++y) {
128 				uint64_t temp[5];
129 				for (x = 0; x < 5; ++x) {
130 					temp[x] = readLane(x, y);
131 				}
132 				for (x = 0; x < 5; ++x) {
133 					writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
134 				}
135 			}
136 		}
137 
138 		{ // i step (see [Keccak Reference, Section 2.3.5])
139 			unsigned char j;
140 			for (j = 0; j < 7; ++j) {
141 				if (LFSR86540(&LFSRstate)) {
142 					uint64_t bitPos = (1<<j) - 1;
143 					XORLane(0, 0, (uint64_t)1 << bitPos);
144 				}
145 			}
146 		}
147 	}
148 }
149 
150 // ==========================================================================
151 
PHP_SHA3_Init(PHP_SHA3_CTX * ctx,int bits)152 static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
153                           int bits) {
154 	memset(ctx, 0, sizeof(PHP_SHA3_CTX));
155 }
156 
PHP_SHA3_Update(PHP_SHA3_CTX * ctx,const unsigned char * buf,size_t count,size_t block_size)157 static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
158                             const unsigned char* buf,
159                             size_t count,
160                             size_t block_size) {
161 	while (count > 0) {
162 		size_t len = block_size - ctx->pos;
163 
164 		if (len > count) {
165 			len = count;
166 		}
167 
168 		count -= len;
169 
170 		while (len-- > 0) {
171 			ctx->state[ctx->pos++] ^= *(buf++);
172 		}
173 
174 		if (ctx->pos >= block_size) {
175 			permute(ctx);
176 			ctx->pos = 0;
177 		}
178 	}
179 }
180 
PHP_SHA3_Final(unsigned char * digest,PHP_SHA3_CTX * ctx,size_t block_size,size_t digest_size)181 static void PHP_SHA3_Final(unsigned char* digest,
182                            PHP_SHA3_CTX* ctx,
183                            size_t block_size,
184                            size_t digest_size) {
185 	size_t len = digest_size;
186 
187 	// Pad state to finalize
188 	ctx->state[ctx->pos++] ^= 0x06;
189 	ctx->state[block_size-1] ^= 0x80;
190 	permute(ctx);
191 
192 	// Square output for digest
193 	for(;;) {
194 		int bs = (len < block_size) ? len : block_size;
195 		memcpy(digest, ctx->state, bs);
196 		digest += bs;
197 		len -= bs;
198 		if (!len) break;
199 		permute(ctx);
200 	}
201 
202 	// Zero out context
203 	ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
204 }
205 
206 // ==========================================================================
207 
208 #define DECLARE_SHA3_OPS(bits) \
209 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
210 	PHP_SHA3_Init(ctx, bits); \
211 } \
212 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
213                             const unsigned char* input, \
214                             size_t inputLen) { \
215 	PHP_SHA3_Update(ctx, input, inputLen, \
216                     (1600 - (2 * bits)) >> 3); \
217 } \
218 void PHP_SHA3##bits##Final(unsigned char* digest, \
219                            PHP_SHA3_##bits##_CTX* ctx) { \
220 	PHP_SHA3_Final(digest, ctx, \
221                    (1600 - (2 * bits)) >> 3, \
222                    bits >> 3); \
223 } \
224 const php_hash_ops php_hash_sha3_##bits##_ops = { \
225 	(php_hash_init_func_t) PHP_SHA3##bits##Init, \
226 	(php_hash_update_func_t) PHP_SHA3##bits##Update, \
227 	(php_hash_final_func_t) PHP_SHA3##bits##Final, \
228 	php_hash_copy, \
229 	bits >> 3, \
230 	(1600 - (2 * bits)) >> 3, \
231 	sizeof(PHP_SHA3_##bits##_CTX), \
232 	1 \
233 }
234 
235 #else
236 
237 // ================= fast algo ==============================================
238 
239 #define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
240 #include "KeccakHash.h"
241 
242 
243 // ==========================================================================
244 
hash_sha3_copy(const void * ops,void * orig_context,void * dest_context)245 static int hash_sha3_copy(const void *ops, void *orig_context, void *dest_context)
246 {
247 	PHP_SHA3_CTX* orig = (PHP_SHA3_CTX*)orig_context;
248 	PHP_SHA3_CTX* dest = (PHP_SHA3_CTX*)dest_context;
249 	memcpy(dest->hashinstance, orig->hashinstance, sizeof(Keccak_HashInstance));
250 	return SUCCESS;
251 }
252 
253 #define DECLARE_SHA3_OPS(bits) \
254 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
255 	ctx->hashinstance = emalloc(sizeof(Keccak_HashInstance)); \
256 	Keccak_HashInitialize_SHA3_##bits((Keccak_HashInstance *)ctx->hashinstance); \
257 } \
258 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
259                             const unsigned char* input, \
260                             size_t inputLen) { \
261 	Keccak_HashUpdate((Keccak_HashInstance *)ctx->hashinstance, input, inputLen * 8); \
262 } \
263 void PHP_SHA3##bits##Final(unsigned char* digest, \
264                            PHP_SHA3_##bits##_CTX* ctx) { \
265 	Keccak_HashFinal((Keccak_HashInstance *)ctx->hashinstance, digest); \
266 	efree(ctx->hashinstance); \
267 	ctx->hashinstance = NULL; \
268 } \
269 const php_hash_ops php_hash_sha3_##bits##_ops = { \
270 	(php_hash_init_func_t) PHP_SHA3##bits##Init, \
271 	(php_hash_update_func_t) PHP_SHA3##bits##Update, \
272 	(php_hash_final_func_t) PHP_SHA3##bits##Final, \
273 	hash_sha3_copy, \
274 	bits >> 3, \
275 	(1600 - (2 * bits)) >> 3, \
276 	sizeof(PHP_SHA3_##bits##_CTX), \
277 	1 \
278 }
279 
280 #endif
281 // ================= both algo ==============================================
282 
283 DECLARE_SHA3_OPS(224);
284 DECLARE_SHA3_OPS(256);
285 DECLARE_SHA3_OPS(384);
286 DECLARE_SHA3_OPS(512);
287 
288 #undef DECLARE_SHA3_OPS
289