xref: /PHP-7.1/ext/hash/hash_sha3.c (revision 588db7ce)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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 #if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
23     (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
24 # if defined(__LITTLE_ENDIAN__)
25 #  undef WORDS_BIGENDIAN
26 # else
27 #  if defined(__BIG_ENDIAN__)
28 #   define WORDS_BIGENDIAN
29 #  endif
30 # endif
31 #endif
32 
rol64(uint64_t v,unsigned char b)33 static inline uint64_t rol64(uint64_t v, unsigned char b) {
34 	return (v << b) | (v >> (64 - b));
35 }
idx(unsigned char x,unsigned char y)36 static inline unsigned char idx(unsigned char x, unsigned char y) {
37 	return x + (5 * y);
38 }
39 
40 #ifdef WORDS_BIGENDIAN
load64(const unsigned char * x)41 static inline uint64_t load64(const unsigned char* x) {
42 	signed char i;
43 	uint64_t ret = 0;
44 	for (i = 7; i >= 0; --i) {
45 		ret <<= 8;
46 		ret |= x[i];
47 	}
48 	return ret;
49 }
store64(unsigned char * x,uint64_t val)50 static inline void store64(unsigned char* x, uint64_t val) {
51 	char i;
52 	for (i = 0; i < 8; ++i) {
53 		x[i] = val & 0xFF;
54 		val >>= 8;
55 	}
56 }
xor64(unsigned char * x,uint64_t val)57 static inline void xor64(unsigned char* x, uint64_t val) {
58 	char i;
59 	for (i = 0; i < 8; ++i) {
60 		x[i] ^= val & 0xFF;
61 		val >>= 8;
62 	}
63 }
64 # define readLane(x, y)     load64(ctx->state+sizeof(uint64_t)*idx(x, y))
65 # define writeLane(x, y, v) store64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
66 # define XORLane(x, y, v)   xor64(ctx->state+sizeof(uint64_t)*idx(x, y), v)
67 #else
68 # define readLane(x, y)     (((uint64_t*)ctx->state)[idx(x,y)])
69 # define writeLane(x, y, v) (((uint64_t*)ctx->state)[idx(x,y)] = v)
70 # define XORLane(x, y, v)   (((uint64_t*)ctx->state)[idx(x,y)] ^= v)
71 #endif
72 
LFSR86540(unsigned char * pLFSR)73 static inline char LFSR86540(unsigned char* pLFSR)
74 {
75 	unsigned char LFSR = *pLFSR;
76 	char result = LFSR & 0x01;
77 	if (LFSR & 0x80) {
78 		// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
79 		LFSR = (LFSR << 1) ^ 0x71;
80 	} else {
81 		LFSR <<= 1;
82 	}
83 	*pLFSR = LFSR;
84 	return result;
85 }
86 
permute(PHP_SHA3_CTX * ctx)87 static void permute(PHP_SHA3_CTX* ctx) {
88 	unsigned char LFSRstate = 0x01;
89 	unsigned char round;
90 
91 	for (round = 0; round < 24; ++round) {
92 		{ // Theta step (see [Keccak Reference, Section 2.3.2])
93 			uint64_t C[5], D;
94 			unsigned char x, y;
95 			for (x = 0; x < 5; ++x) {
96 				C[x] = readLane(x, 0) ^ readLane(x, 1) ^
97 				readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
98 			}
99 			for (x = 0; x < 5; ++x) {
100 				D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
101 				for (y = 0; y < 5; ++y) {
102 					XORLane(x, y, D);
103 				}
104 			}
105 		}
106 
107 		{ // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
108 			unsigned char x = 1, y = 0, t;
109 			uint64_t current = readLane(x, y);
110 			for (t = 0; t < 24; ++t) {
111 				unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
112 				unsigned char Y = (2*x + 3*y) % 5;
113 				uint64_t temp;
114 				x = y;
115 				y = Y;
116 				temp = readLane(x, y);
117 				writeLane(x, y, rol64(current, r));
118 				current = temp;
119 			}
120 		}
121 
122 		{ // X step (see [Keccak Reference, Section 2.3.1])
123 			unsigned char x, y;
124 			for (y = 0; y < 5; ++y) {
125 				uint64_t temp[5];
126 				for (x = 0; x < 5; ++x) {
127 					temp[x] = readLane(x, y);
128 				}
129 				for (x = 0; x < 5; ++x) {
130 					writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
131 				}
132 			}
133 		}
134 
135 		{ // i step (see [Keccak Reference, Section 2.3.5])
136 			unsigned char j;
137 			for (j = 0; j < 7; ++j) {
138 				if (LFSR86540(&LFSRstate)) {
139 					uint64_t bitPos = (1<<j) - 1;
140 					XORLane(0, 0, (uint64_t)1 << bitPos);
141 				}
142 			}
143 		}
144 	}
145 }
146 
147 // ==========================================================================
148 
PHP_SHA3_Init(PHP_SHA3_CTX * ctx,int bits)149 static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
150                           int bits) {
151 	memset(ctx, 0, sizeof(PHP_SHA3_CTX));
152 }
153 
PHP_SHA3_Update(PHP_SHA3_CTX * ctx,const unsigned char * buf,unsigned int count,size_t block_size)154 static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
155                             const unsigned char* buf,
156                             unsigned int count,
157                             size_t block_size) {
158 	while (count > 0) {
159 		unsigned int len = block_size - ctx->pos;
160 		if (len > count) len = count;
161 		count -= len;
162 		while (len-- > 0) {
163 			ctx->state[ctx->pos++] ^= *(buf++);
164 		}
165 		if (ctx->pos >= block_size) {
166 			permute(ctx);
167 			ctx->pos = 0;
168 		}
169 	}
170 }
171 
PHP_SHA3_Final(unsigned char * digest,PHP_SHA3_CTX * ctx,int block_size,int digest_size)172 static void PHP_SHA3_Final(unsigned char* digest,
173                            PHP_SHA3_CTX* ctx,
174                            int block_size,
175                            int digest_size) {
176 	int len = digest_size;
177 
178 	// Pad state to finalize
179 	ctx->state[ctx->pos++] ^= 0x06;
180 	ctx->state[block_size-1] ^= 0x80;
181 	permute(ctx);
182 
183 	// Square output for digest
184 	for(;;) {
185 		int bs = (len < block_size) ? len : block_size;
186 		memcpy(digest, ctx->state, bs);
187 		digest += bs;
188 		len -= bs;
189 		if (!len) break;
190 		permute(ctx);
191 	}
192 
193 	// Zero out context
194 	ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
195 }
196 
197 // ==========================================================================
198 
199 #define DECLARE_SHA3_OPS(bits) \
200 void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
201 	PHP_SHA3_Init(ctx, bits); \
202 } \
203 void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
204                             const unsigned char* input, \
205                             unsigned int inputLen) { \
206 	PHP_SHA3_Update(ctx, input, inputLen, \
207                     (1600 - (2 * bits)) >> 3); \
208 } \
209 void PHP_SHA3##bits##Final(unsigned char* digest, \
210                            PHP_SHA3_##bits##_CTX* ctx) { \
211 	PHP_SHA3_Final(digest, ctx, \
212                    (1600 - (2 * bits)) >> 3, \
213                    bits >> 3); \
214 } \
215 const php_hash_ops php_hash_sha3_##bits##_ops = { \
216 	(php_hash_init_func_t) PHP_SHA3##bits##Init, \
217 	(php_hash_update_func_t) PHP_SHA3##bits##Update, \
218 	(php_hash_final_func_t) PHP_SHA3##bits##Final, \
219 	php_hash_copy, \
220 	bits >> 3, \
221 	(1600 - (2 * bits)) >> 3, \
222 	sizeof(PHP_SHA3_##bits##_CTX) \
223 }
224 
225 DECLARE_SHA3_OPS(224);
226 DECLARE_SHA3_OPS(256);
227 DECLARE_SHA3_OPS(384);
228 DECLARE_SHA3_OPS(512);
229 
230 #undef DECLARE_SHA3_OPS
231 
232 /*
233  * Local variables:
234  * tab-width: 4
235  * c-basic-offset: 4
236  * End:
237  * vim600: sw=4 ts=4 fdm=marker
238  * vim<600: sw=4 ts=4
239  */
240