| /* Sha3.c -- SHA-3 Hash |
| : Igor Pavlov : Public domain |
| This code is based on public domain code from Wei Dai's Crypto++ library. */ |
| |
| #include "Precomp.h" |
| |
| #include <string.h> |
| |
| #include "Sha3.h" |
| #include "RotateDefs.h" |
| #include "CpuArch.h" |
| |
| #define U64C(x) UINT64_CONST(x) |
| |
| static |
| MY_ALIGN(64) |
| const UInt64 SHA3_K_ARRAY[24] = |
| { |
| U64C(0x0000000000000001), U64C(0x0000000000008082), |
| U64C(0x800000000000808a), U64C(0x8000000080008000), |
| U64C(0x000000000000808b), U64C(0x0000000080000001), |
| U64C(0x8000000080008081), U64C(0x8000000000008009), |
| U64C(0x000000000000008a), U64C(0x0000000000000088), |
| U64C(0x0000000080008009), U64C(0x000000008000000a), |
| U64C(0x000000008000808b), U64C(0x800000000000008b), |
| U64C(0x8000000000008089), U64C(0x8000000000008003), |
| U64C(0x8000000000008002), U64C(0x8000000000000080), |
| U64C(0x000000000000800a), U64C(0x800000008000000a), |
| U64C(0x8000000080008081), U64C(0x8000000000008080), |
| U64C(0x0000000080000001), U64C(0x8000000080008008) |
| }; |
| |
| void Sha3_Init(CSha3 *p) |
| { |
| p->count = 0; |
| memset(p->state, 0, sizeof(p->state)); |
| } |
| |
| #define GET_state(i, a) UInt64 a = state[i]; |
| #define SET_state(i, a) state[i] = a; |
| |
| #define LS_5(M, i, a0,a1,a2,a3,a4) \ |
| M ((i) * 5 , a0) \ |
| M ((i) * 5 + 1, a1) \ |
| M ((i) * 5 + 2, a2) \ |
| M ((i) * 5 + 3, a3) \ |
| M ((i) * 5 + 4, a4) \ |
| |
| #define LS_25(M) \ |
| LS_5 (M, 0, a50, a51, a52, a53, a54) \ |
| LS_5 (M, 1, a60, a61, a62, a63, a64) \ |
| LS_5 (M, 2, a70, a71, a72, a73, a74) \ |
| LS_5 (M, 3, a80, a81, a82, a83, a84) \ |
| LS_5 (M, 4, a90, a91, a92, a93, a94) \ |
| |
| |
| #define XOR_1(i, a0) \ |
| a0 ^= GetUi64(data + (i) * 8); \ |
| |
| #define XOR_4(i, a0,a1,a2,a3) \ |
| XOR_1 ((i) , a0); \ |
| XOR_1 ((i) + 1, a1); \ |
| XOR_1 ((i) + 2, a2); \ |
| XOR_1 ((i) + 3, a3); \ |
| |
| #define D(d,b1,b2) \ |
| d = b1 ^ Z7_ROTL64(b2, 1); |
| |
| #define D5 \ |
| D (d0, c4, c1) \ |
| D (d1, c0, c2) \ |
| D (d2, c1, c3) \ |
| D (d3, c2, c4) \ |
| D (d4, c3, c0) \ |
| |
| #define C0(c,a,d) \ |
| c = a ^ d; \ |
| |
| #define C(c,a,d,k) \ |
| c = a ^ d; \ |
| c = Z7_ROTL64(c, k); \ |
| |
| #define E4(e1,e2,e3,e4) \ |
| e1 = c1 ^ (~c2 & c3); \ |
| e2 = c2 ^ (~c3 & c4); \ |
| e3 = c3 ^ (~c4 & c0); \ |
| e4 = c4 ^ (~c0 & c1); \ |
| |
| #define CK( v0,w0, \ |
| v1,w1,k1, \ |
| v2,w2,k2, \ |
| v3,w3,k3, \ |
| v4,w4,k4, e0,e1,e2,e3,e4, keccak_c) \ |
| C0(c0,v0,w0) \ |
| C (c1,v1,w1,k1) \ |
| C (c2,v2,w2,k2) \ |
| C (c3,v3,w3,k3) \ |
| C (c4,v4,w4,k4) \ |
| e0 = c0 ^ (~c1 & c2) ^ keccak_c; \ |
| E4(e1,e2,e3,e4) \ |
| |
| #define CE( v0,w0,k0, \ |
| v1,w1,k1, \ |
| v2,w2,k2, \ |
| v3,w3,k3, \ |
| v4,w4,k4, e0,e1,e2,e3,e4) \ |
| C (c0,v0,w0,k0) \ |
| C (c1,v1,w1,k1) \ |
| C (c2,v2,w2,k2) \ |
| C (c3,v3,w3,k3) \ |
| C (c4,v4,w4,k4) \ |
| e0 = c0 ^ (~c1 & c2); \ |
| E4(e1,e2,e3,e4) \ |
| |
| // numBlocks != 0 |
| static |
| Z7_NO_INLINE |
| void Z7_FASTCALL Sha3_UpdateBlocks(UInt64 state[SHA3_NUM_STATE_WORDS], |
| const Byte *data, size_t numBlocks, size_t blockSize) |
| { |
| LS_25 (GET_state) |
| |
| do |
| { |
| unsigned round; |
| XOR_4 ( 0, a50, a51, a52, a53) |
| XOR_4 ( 4, a54, a60, a61, a62) |
| XOR_1 ( 8, a63) |
| if (blockSize > 8 * 9) { XOR_4 ( 9, a64, a70, a71, a72) // sha3-384 |
| if (blockSize > 8 * 13) { XOR_4 (13, a73, a74, a80, a81) // sha3-256 |
| if (blockSize > 8 * 17) { XOR_1 (17, a82) // sha3-224 |
| if (blockSize > 8 * 18) { XOR_1 (18, a83) // shake128 |
| XOR_1 (19, a84) |
| XOR_1 (20, a90) }}}} |
| data += blockSize; |
| |
| for (round = 0; round < 24; round += 2) |
| { |
| UInt64 c0, c1, c2, c3, c4; |
| UInt64 d0, d1, d2, d3, d4; |
| UInt64 e50, e51, e52, e53, e54; |
| UInt64 e60, e61, e62, e63, e64; |
| UInt64 e70, e71, e72, e73, e74; |
| UInt64 e80, e81, e82, e83, e84; |
| UInt64 e90, e91, e92, e93, e94; |
| |
| c0 = a50^a60^a70^a80^a90; |
| c1 = a51^a61^a71^a81^a91; |
| c2 = a52^a62^a72^a82^a92; |
| c3 = a53^a63^a73^a83^a93; |
| c4 = a54^a64^a74^a84^a94; |
| D5 |
| CK( a50, d0, |
| a61, d1, 44, |
| a72, d2, 43, |
| a83, d3, 21, |
| a94, d4, 14, e50, e51, e52, e53, e54, SHA3_K_ARRAY[round]) |
| CE( a53, d3, 28, |
| a64, d4, 20, |
| a70, d0, 3, |
| a81, d1, 45, |
| a92, d2, 61, e60, e61, e62, e63, e64) |
| CE( a51, d1, 1, |
| a62, d2, 6, |
| a73, d3, 25, |
| a84, d4, 8, |
| a90, d0, 18, e70, e71, e72, e73, e74) |
| CE( a54, d4, 27, |
| a60, d0, 36, |
| a71, d1, 10, |
| a82, d2, 15, |
| a93, d3, 56, e80, e81, e82, e83, e84) |
| CE( a52, d2, 62, |
| a63, d3, 55, |
| a74, d4, 39, |
| a80, d0, 41, |
| a91, d1, 2, e90, e91, e92, e93, e94) |
| |
| // ---------- ROUND + 1 ---------- |
| |
| c0 = e50^e60^e70^e80^e90; |
| c1 = e51^e61^e71^e81^e91; |
| c2 = e52^e62^e72^e82^e92; |
| c3 = e53^e63^e73^e83^e93; |
| c4 = e54^e64^e74^e84^e94; |
| D5 |
| CK( e50, d0, |
| e61, d1, 44, |
| e72, d2, 43, |
| e83, d3, 21, |
| e94, d4, 14, a50, a51, a52, a53, a54, SHA3_K_ARRAY[(size_t)round + 1]) |
| CE( e53, d3, 28, |
| e64, d4, 20, |
| e70, d0, 3, |
| e81, d1, 45, |
| e92, d2, 61, a60, a61, a62, a63, a64) |
| CE( e51, d1, 1, |
| e62, d2, 6, |
| e73, d3, 25, |
| e84, d4, 8, |
| e90, d0, 18, a70, a71, a72, a73, a74) |
| CE (e54, d4, 27, |
| e60, d0, 36, |
| e71, d1, 10, |
| e82, d2, 15, |
| e93, d3, 56, a80, a81, a82, a83, a84) |
| CE (e52, d2, 62, |
| e63, d3, 55, |
| e74, d4, 39, |
| e80, d0, 41, |
| e91, d1, 2, a90, a91, a92, a93, a94) |
| } |
| } |
| while (--numBlocks); |
| |
| LS_25 (SET_state) |
| } |
| |
| |
| #define Sha3_UpdateBlock(p) \ |
| Sha3_UpdateBlocks(p->state, p->buffer, 1, p->blockSize) |
| |
| void Sha3_Update(CSha3 *p, const Byte *data, size_t size) |
| { |
| /* |
| for (;;) |
| { |
| if (size == 0) |
| return; |
| unsigned cur = p->blockSize - p->count; |
| if (cur > size) |
| cur = (unsigned)size; |
| size -= cur; |
| unsigned pos = p->count; |
| p->count = pos + cur; |
| while (pos & 7) |
| { |
| if (cur == 0) |
| return; |
| Byte *pb = &(((Byte *)p->state)[pos]); |
| *pb = (Byte)(*pb ^ *data++); |
| cur--; |
| pos++; |
| } |
| if (cur >= 8) |
| { |
| do |
| { |
| *(UInt64 *)(void *)&(((Byte *)p->state)[pos]) ^= GetUi64(data); |
| data += 8; |
| pos += 8; |
| cur -= 8; |
| } |
| while (cur >= 8); |
| } |
| if (pos != p->blockSize) |
| { |
| if (cur) |
| { |
| Byte *pb = &(((Byte *)p->state)[pos]); |
| do |
| { |
| *pb = (Byte)(*pb ^ *data++); |
| pb++; |
| } |
| while (--cur); |
| } |
| return; |
| } |
| Sha3_UpdateBlock(p->state); |
| p->count = 0; |
| } |
| */ |
| if (size == 0) |
| return; |
| { |
| const unsigned pos = p->count; |
| const unsigned num = p->blockSize - pos; |
| if (num > size) |
| { |
| p->count = pos + (unsigned)size; |
| memcpy(p->buffer + pos, data, size); |
| return; |
| } |
| if (pos != 0) |
| { |
| size -= num; |
| memcpy(p->buffer + pos, data, num); |
| data += num; |
| Sha3_UpdateBlock(p); |
| } |
| } |
| if (size >= p->blockSize) |
| { |
| const size_t numBlocks = size / p->blockSize; |
| const Byte *dataOld = data; |
| data += numBlocks * p->blockSize; |
| size = (size_t)(dataOld + size - data); |
| Sha3_UpdateBlocks(p->state, dataOld, numBlocks, p->blockSize); |
| } |
| p->count = (unsigned)size; |
| if (size) |
| memcpy(p->buffer, data, size); |
| } |
| |
| |
| // we support only (digestSize % 4 == 0) cases |
| void Sha3_Final(CSha3 *p, Byte *digest, unsigned digestSize, unsigned shake) |
| { |
| memset(p->buffer + p->count, 0, p->blockSize - p->count); |
| // we write bits markers from low to higher in current byte: |
| // - if sha-3 : 2 bits : 0,1 |
| // - if shake : 4 bits : 1111 |
| // then we write bit 1 to same byte. |
| // And we write bit 1 to highest bit of last byte of block. |
| p->buffer[p->count] = (Byte)(shake ? 0x1f : 0x06); |
| // we need xor operation (^= 0x80) here because we must write 0x80 bit |
| // to same byte as (0x1f : 0x06), if (p->count == p->blockSize - 1) !!! |
| p->buffer[p->blockSize - 1] ^= 0x80; |
| /* |
| ((Byte *)p->state)[p->count] ^= (Byte)(shake ? 0x1f : 0x06); |
| ((Byte *)p->state)[p->blockSize - 1] ^= 0x80; |
| */ |
| Sha3_UpdateBlock(p); |
| #if 1 && defined(MY_CPU_LE) |
| memcpy(digest, p->state, digestSize); |
| #else |
| { |
| const unsigned numWords = digestSize >> 3; |
| unsigned i; |
| for (i = 0; i < numWords; i++) |
| { |
| const UInt64 v = p->state[i]; |
| SetUi64(digest, v) |
| digest += 8; |
| } |
| if (digestSize & 4) // for SHA3-224 |
| { |
| const UInt32 v = (UInt32)p->state[numWords]; |
| SetUi32(digest, v) |
| } |
| } |
| #endif |
| Sha3_Init(p); |
| } |
| |
| #undef GET_state |
| #undef SET_state |
| #undef LS_5 |
| #undef LS_25 |
| #undef XOR_1 |
| #undef XOR_4 |
| #undef D |
| #undef D5 |
| #undef C0 |
| #undef C |
| #undef E4 |
| #undef CK |
| #undef CE |