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