Dqn/dqn_keccak.h
2021-09-24 22:29:34 +10:00

896 lines
38 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#if !defined(DQN_KECCAK_H)
#define DQN_KECCAK_H
// -----------------------------------------------------------------------------
// NOTE: Overview
// -----------------------------------------------------------------------------
// Implementation of the Keccak hashing algorithms from the Keccak and SHA3
// families (including the FIPS202 published algorithms and the non-finalized
// ones, i.e. the ones used in Ethereum and Monero which adopted SHA3 before it
// was finalized. The only difference between the 2 is a different delimited
// suffix).
//
// -----------------------------------------------------------------------------
// NOTE: MIT License
// -----------------------------------------------------------------------------
// Copyright (c) 2021 github.com/doy-lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------------
// NOTE: Macros
// -----------------------------------------------------------------------------
// #define DQN_KECCAK_IMPLEMENTATION
// Define this in one and only one C++ file to enable the implementation
// code of the header file.
#if !defined(DQN_KECCAK_MEMCOPY)
#include <string.h>
#define DQN_KECCAK_MEMCOPY(dest, src, count) memcpy(dest, src, count)
#endif
#if !defined(DQN_KECCAK_MEMCMP)
#include <string.h>
#define DQN_KECCAK_MEMCMP(dest, src, count) memcmp(dest, src, count)
#endif
#if !defined(DQN_KECCAK_ASSERT)
#if defined(NDEBUG)
#define DQN_KECCAK_ASSERT(expr)
#else
#define DQN_KECCAK_ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
(*(volatile int *)0) = 0; \
} \
} while (0)
#endif
#endif
// Use this macro in a printf-like function,
/*
Dqn_KeccakString64 string = {};
printf("%.*s\n", DQN_KECCAK_STRING64_FMT(string));
*/
#define DQN_KECCAK_STRING56_FMT(string) 56, string
#define DQN_KECCAK_STRING64_FMT(string) 64, string
#define DQN_KECCAK_STRING96_FMT(string) 96, string
#define DQN_KECCAK_STRING128_FMT(string) 128, string
// -----------------------------------------------------------------------------
// NOTE: Data structures
// -----------------------------------------------------------------------------
struct Dqn_KeccakBytes28 { char data[28]; }; // 224 bit
struct Dqn_KeccakBytes32 { char data[32]; }; // 256 bit
struct Dqn_KeccakBytes48 { char data[48]; }; // 384 bit
struct Dqn_KeccakBytes64 { char data[64]; }; // 512 bit
struct Dqn_KeccakString56 { char str[(sizeof(Dqn_KeccakBytes28) * 2) + 1]; };
struct Dqn_KeccakString64 { char str[(sizeof(Dqn_KeccakBytes32) * 2) + 1]; };
struct Dqn_KeccakString96 { char str[(sizeof(Dqn_KeccakBytes48) * 2) + 1]; };
struct Dqn_KeccakString128 { char str[(sizeof(Dqn_KeccakBytes64) * 2) + 1]; };
// -----------------------------------------------------------------------------
// NOTE: API
// -----------------------------------------------------------------------------
// TODO(dqn): Write a streaming API
typedef unsigned char Dqn_Keccak_u8;
typedef unsigned short Dqn_Keccak_u16;
typedef unsigned int Dqn_Keccak_u32;
typedef unsigned int Dqn_Keccak_uint;
#ifdef _MSC_VER
typedef unsigned __int64 Dqn_Keccak_u64;
#else
typedef unsigned long long Dqn_Keccak_u64;
#endif
// -----------------------------------------------------------------------------
// NOTE: SHA3
// -----------------------------------------------------------------------------
// Applies the FIPS 202 SHA3 algorithm on the supplied buffer. The size of
// the returned hash is (bit-rate/8) bytes, i.e. the dest_size must be atleast
// 32 bytes for SHA-256 and so forth.
void Dqn_Keccak_SHA3_224(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_ToBytes28(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_SHA3_256(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_ToBytes32(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_SHA3_384(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_ToBytes48(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_SHA3_512(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_ToBytes64(void *bytes, Dqn_Keccak_u64 bytes_size);
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: SHA3 - Helpers for Dqn data structures
// -----------------------------------------------------------------------------
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_StringToBytes28(Dqn_String string);
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_StringToBytes32(Dqn_String string);
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_StringToBytes48(Dqn_String string);
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_StringToBytes64(Dqn_String string);
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_U8ArrayToBytes28(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_U8ArrayToBytes32(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_U8ArrayToBytes48(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_U8ArrayToBytes64(Dqn_Array<Dqn_Keccak_u8> array);
#endif // DQN_H
// -----------------------------------------------------------------------------
// NOTE: Keccak
// -----------------------------------------------------------------------------
// Applies the non-finalized SHA3 algorithm (i.e. a delimited suffix of 0x1
// instead of 0x6 in SHA3). This is the version of the algorithm used by
// Ethereum and Monero as they adopted SHA3 before it was finalized.
void Dqn_Keccak_224(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes28 Dqn_Keccak_224_ToBytes28(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_256(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes32 Dqn_Keccak_256_ToBytes32(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_384(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes48 Dqn_Keccak_384_ToBytes48(void *bytes, Dqn_Keccak_u64 bytes_size);
void Dqn_Keccak_512(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size);
Dqn_KeccakBytes64 Dqn_Keccak_512_ToBytes64(void *bytes, Dqn_Keccak_u64 bytes_size);
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: Keccak - Helpers for Dqn data structures
// -----------------------------------------------------------------------------
Dqn_KeccakBytes28 Dqn_Keccak_224_StringToBytes28(Dqn_String string);
Dqn_KeccakBytes32 Dqn_Keccak_256_StringToBytes32(Dqn_String string);
Dqn_KeccakBytes48 Dqn_Keccak_384_StringToBytes48(Dqn_String string);
Dqn_KeccakBytes64 Dqn_Keccak_512_StringToBytes64(Dqn_String string);
Dqn_KeccakBytes28 Dqn_Keccak_224_U8ArrayToBytes28(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes32 Dqn_Keccak_256_U8ArrayToBytes32(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes48 Dqn_Keccak_384_U8ArrayToBytes48(Dqn_Array<Dqn_Keccak_u8> array);
Dqn_KeccakBytes64 Dqn_Keccak_512_U8ArrayToBytes64(Dqn_Array<Dqn_Keccak_u8> array);
#endif // DQN_H
// -----------------------------------------------------------------------------
// NOTE: Helper functions
// -----------------------------------------------------------------------------
// Convert a binary buffer into its hex representation into dest. The dest
// buffer must be large enough to contain the hex representation, i.e.
// atleast src_size * 2). This function does *not* null-terminate the buffer.
void Dqn_Keccak_BytesToHex(void const *src, Dqn_Keccak_u64 src_size, char *dest, Dqn_Keccak_u64 dest_size);
// Converts a fixed amount of bytes into a hexadecimal string. Helper functions
// that call into Dqn_Keccak_BytesToHex.
// return: The hexadecimal string of the bytes, null-terminated.
Dqn_KeccakString56 Dqn_Keccak_Bytes28ToHex(Dqn_KeccakBytes28 const *bytes);
Dqn_KeccakString64 Dqn_Keccak_Bytes32ToHex(Dqn_KeccakBytes32 const *bytes);
Dqn_KeccakString96 Dqn_Keccak_Bytes48ToHex(Dqn_KeccakBytes48 const *bytes);
Dqn_KeccakString128 Dqn_Keccak_Bytes64ToHex(Dqn_KeccakBytes64 const *bytes);
// Compares byte data structures for byte equality (via memcmp).
// return: 1 if the contents are equal otherwise 0.
int Dqn_Keccak_Bytes28Equals(Dqn_KeccakBytes28 const *a, Dqn_KeccakBytes28 const *b);
int Dqn_Keccak_Bytes32Equals(Dqn_KeccakBytes32 const *a, Dqn_KeccakBytes32 const *b);
int Dqn_Keccak_Bytes48Equals(Dqn_KeccakBytes48 const *a, Dqn_KeccakBytes48 const *b);
int Dqn_Keccak_Bytes64Equals(Dqn_KeccakBytes64 const *a, Dqn_KeccakBytes64 const *b);
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: Other helper functions for Dqn data structures
// -----------------------------------------------------------------------------
// Converts a 64 character hex string into the 32 byte binary representation.
// Invalid hex characters in the string will be represented as 0.
// hex: Must be exactly a 64 character hex string.
Dqn_KeccakBytes32 Dqn_Keccak_Hex64StringToBytes(Dqn_String hex);
#endif // DQN_H
#endif // DQN_KECCAK_H
#if defined(DQN_KECCAK_IMPLEMENTATION)
Dqn_Keccak_u64 const DQN_KECCAK_ROUNDS[] = {
0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000, 0x000000000000808B,
0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 0x0000000000000088,
0x0000000080008009, 0x000000008000000A, 0x000000008000808B, 0x800000000000008B, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
};
Dqn_Keccak_u64 const DQN_KECCAK_ROTATIONS[][5] =
{
{0, 36, 3, 41, 18},
{1, 44, 10, 45, 2},
{62, 6, 43, 15, 61},
{28, 55, 25, 21, 56},
{27, 20, 39, 8, 14},
};
#define DQN_KECCAK_LANE_SIZE_U64 5
#define DQN_KECCAK_ROL64(val, rotate) (((val) << (rotate)) | (((val) >> (64 - (rotate)))))
static void Dqn_Keccak__ReferencePermute(Dqn_Keccak_u64 *A)
{
// TODO(dqn): Do some more tests and remove.
// NOTE: Reference permutation taken for cross-reference and back verifying
// against from digestpp by kerukuro
// https://github.com/kerukuro/digestpp/blob/master/algorithm/detail/sha3_provider.hpp
for (int round = 0; round < 24; round++)
{
Dqn_Keccak_u64 C[5], D[5];
C[0] = A[0 * 5 + 0] ^ A[1 * 5 + 0] ^ A[2 * 5 + 0] ^ A[3 * 5 + 0] ^ A[4 * 5 + 0];
C[1] = A[0 * 5 + 1] ^ A[1 * 5 + 1] ^ A[2 * 5 + 1] ^ A[3 * 5 + 1] ^ A[4 * 5 + 1];
C[2] = A[0 * 5 + 2] ^ A[1 * 5 + 2] ^ A[2 * 5 + 2] ^ A[3 * 5 + 2] ^ A[4 * 5 + 2];
C[3] = A[0 * 5 + 3] ^ A[1 * 5 + 3] ^ A[2 * 5 + 3] ^ A[3 * 5 + 3] ^ A[4 * 5 + 3];
C[4] = A[0 * 5 + 4] ^ A[1 * 5 + 4] ^ A[2 * 5 + 4] ^ A[3 * 5 + 4] ^ A[4 * 5 + 4];
D[0] = C[4] ^ DQN_KECCAK_ROL64(C[1], 1);
D[1] = C[0] ^ DQN_KECCAK_ROL64(C[2], 1);
D[2] = C[1] ^ DQN_KECCAK_ROL64(C[3], 1);
D[3] = C[2] ^ DQN_KECCAK_ROL64(C[4], 1);
D[4] = C[3] ^ DQN_KECCAK_ROL64(C[0], 1);
Dqn_Keccak_u64 B00 = A[0 * 5 + 0] ^ D[0];
Dqn_Keccak_u64 B10 = DQN_KECCAK_ROL64(A[0 * 5 + 1] ^ D[1], 1);
Dqn_Keccak_u64 B20 = DQN_KECCAK_ROL64(A[0 * 5 + 2] ^ D[2], 62);
Dqn_Keccak_u64 B5 = DQN_KECCAK_ROL64(A[0 * 5 + 3] ^ D[3], 28);
Dqn_Keccak_u64 B15 = DQN_KECCAK_ROL64(A[0 * 5 + 4] ^ D[4], 27);
Dqn_Keccak_u64 B16 = DQN_KECCAK_ROL64(A[1 * 5 + 0] ^ D[0], 36);
Dqn_Keccak_u64 B1 = DQN_KECCAK_ROL64(A[1 * 5 + 1] ^ D[1], 44);
Dqn_Keccak_u64 B11 = DQN_KECCAK_ROL64(A[1 * 5 + 2] ^ D[2], 6);
Dqn_Keccak_u64 B21 = DQN_KECCAK_ROL64(A[1 * 5 + 3] ^ D[3], 55);
Dqn_Keccak_u64 B6 = DQN_KECCAK_ROL64(A[1 * 5 + 4] ^ D[4], 20);
Dqn_Keccak_u64 B7 = DQN_KECCAK_ROL64(A[2 * 5 + 0] ^ D[0], 3);
Dqn_Keccak_u64 B17 = DQN_KECCAK_ROL64(A[2 * 5 + 1] ^ D[1], 10);
Dqn_Keccak_u64 B2 = DQN_KECCAK_ROL64(A[2 * 5 + 2] ^ D[2], 43);
Dqn_Keccak_u64 B12 = DQN_KECCAK_ROL64(A[2 * 5 + 3] ^ D[3], 25);
Dqn_Keccak_u64 B22 = DQN_KECCAK_ROL64(A[2 * 5 + 4] ^ D[4], 39);
Dqn_Keccak_u64 B23 = DQN_KECCAK_ROL64(A[3 * 5 + 0] ^ D[0], 41);
Dqn_Keccak_u64 B8 = DQN_KECCAK_ROL64(A[3 * 5 + 1] ^ D[1], 45);
Dqn_Keccak_u64 B18 = DQN_KECCAK_ROL64(A[3 * 5 + 2] ^ D[2], 15);
Dqn_Keccak_u64 B3 = DQN_KECCAK_ROL64(A[3 * 5 + 3] ^ D[3], 21);
Dqn_Keccak_u64 B13 = DQN_KECCAK_ROL64(A[3 * 5 + 4] ^ D[4], 8);
Dqn_Keccak_u64 B14 = DQN_KECCAK_ROL64(A[4 * 5 + 0] ^ D[0], 18);
Dqn_Keccak_u64 B24 = DQN_KECCAK_ROL64(A[4 * 5 + 1] ^ D[1], 2);
Dqn_Keccak_u64 B9 = DQN_KECCAK_ROL64(A[4 * 5 + 2] ^ D[2], 61);
Dqn_Keccak_u64 B19 = DQN_KECCAK_ROL64(A[4 * 5 + 3] ^ D[3], 56);
Dqn_Keccak_u64 B4 = DQN_KECCAK_ROL64(A[4 * 5 + 4] ^ D[4], 14);
#if 0
printf("B00: %024llu\n", A[0 * 5 + 0] ^ D[0]);
printf("B10: %024llu\n", DQN_KECCAK_ROL64(A[0 * 5 + 1] ^ D[1], 1));
printf("B20: %024llu\n", DQN_KECCAK_ROL64(A[0 * 5 + 2] ^ D[2], 62));
printf("B05: %024llu\n", DQN_KECCAK_ROL64(A[0 * 5 + 3] ^ D[3], 28));
printf("B15: %024llu\n\n", DQN_KECCAK_ROL64(A[0 * 5 + 4] ^ D[4], 27));
printf("B16: %024llu\n", DQN_KECCAK_ROL64(A[1 * 5 + 0] ^ D[0], 36));
printf("B01: %024llu\n", DQN_KECCAK_ROL64(A[1 * 5 + 1] ^ D[1], 44));
printf("B11: %024llu\n", DQN_KECCAK_ROL64(A[1 * 5 + 2] ^ D[2], 6));
printf("B21: %024llu\n", DQN_KECCAK_ROL64(A[1 * 5 + 3] ^ D[3], 55));
printf("B06: %024llu\n\n", DQN_KECCAK_ROL64(A[1 * 5 + 4] ^ D[4], 20));
printf("B07: %024llu\n", DQN_KECCAK_ROL64(A[2 * 5 + 0] ^ D[0], 3));
printf("B17: %024llu\n", DQN_KECCAK_ROL64(A[2 * 5 + 1] ^ D[1], 10));
printf("B02: %024llu\n", DQN_KECCAK_ROL64(A[2 * 5 + 2] ^ D[2], 43));
printf("B12: %024llu\n", DQN_KECCAK_ROL64(A[2 * 5 + 3] ^ D[3], 25));
printf("B22: %024llu\n\n", DQN_KECCAK_ROL64(A[2 * 5 + 4] ^ D[4], 39));
printf("B23: %024llu\n", DQN_KECCAK_ROL64(A[3 * 5 + 0] ^ D[0], 41));
printf("B08: %024llu\n", DQN_KECCAK_ROL64(A[3 * 5 + 1] ^ D[1], 45));
printf("B18: %024llu\n", DQN_KECCAK_ROL64(A[3 * 5 + 2] ^ D[2], 15));
printf("B03: %024llu\n", DQN_KECCAK_ROL64(A[3 * 5 + 3] ^ D[3], 21));
printf("B13: %024llu\n\n", DQN_KECCAK_ROL64(A[3 * 5 + 4] ^ D[4], 8));
printf("B14: %024llu\n", DQN_KECCAK_ROL64(A[4 * 5 + 0] ^ D[0], 18));
printf("B24: %024llu\n", DQN_KECCAK_ROL64(A[4 * 5 + 1] ^ D[1], 2));
printf("B09: %024llu\n", DQN_KECCAK_ROL64(A[4 * 5 + 2] ^ D[2], 61));
printf("B19: %024llu\n", DQN_KECCAK_ROL64(A[4 * 5 + 3] ^ D[3], 56));
printf("B04: %024llu\n\n", DQN_KECCAK_ROL64(A[4 * 5 + 4] ^ D[4], 14));
#endif
A[0 * 5 + 0] = B00 ^ ((~B1) & B2);
A[0 * 5 + 1] = B1 ^ ((~B2) & B3);
A[0 * 5 + 2] = B2 ^ ((~B3) & B4);
A[0 * 5 + 3] = B3 ^ ((~B4) & B00);
A[0 * 5 + 4] = B4 ^ ((~B00) & B1);
A[1 * 5 + 0] = B5 ^ ((~B6) & B7);
A[1 * 5 + 1] = B6 ^ ((~B7) & B8);
A[1 * 5 + 2] = B7 ^ ((~B8) & B9);
A[1 * 5 + 3] = B8 ^ ((~B9) & B5);
A[1 * 5 + 4] = B9 ^ ((~B5) & B6);
A[2 * 5 + 0] = B10 ^ ((~B11) & B12);
A[2 * 5 + 1] = B11 ^ ((~B12) & B13);
A[2 * 5 + 2] = B12 ^ ((~B13) & B14);
A[2 * 5 + 3] = B13 ^ ((~B14) & B10);
A[2 * 5 + 4] = B14 ^ ((~B10) & B11);
A[3 * 5 + 0] = B15 ^ ((~B16) & B17);
A[3 * 5 + 1] = B16 ^ ((~B17) & B18);
A[3 * 5 + 2] = B17 ^ ((~B18) & B19);
A[3 * 5 + 3] = B18 ^ ((~B19) & B15);
A[3 * 5 + 4] = B19 ^ ((~B15) & B16);
A[4 * 5 + 0] = B20 ^ ((~B21) & B22);
A[4 * 5 + 1] = B21 ^ ((~B22) & B23);
A[4 * 5 + 2] = B22 ^ ((~B23) & B24);
A[4 * 5 + 3] = B23 ^ ((~B24) & B20);
A[4 * 5 + 4] = B24 ^ ((~B20) & B21);
A[0] ^= DQN_KECCAK_ROUNDS[round];
#if 0
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
Dqn_Keccak_u64 lane = A[x + (y * 5)];
printf("[%d,%d] %024llu ", x, y, lane);
}
printf("\n");
}
#endif
}
}
void Dqn_Keccak__Permute(void *state)
{
// TODO(dqn): Do some profiling on unrolling and can we SIMD some part of
// this? Unroll loop, look at data dependencies and investigate.
#if 1
Dqn_Keccak_u64 *lanes_u64 = (Dqn_Keccak_u64 *)state;
for (int round_index = 0; round_index < 24; round_index++)
{
#define LANE_INDEX(x, y) ((x) + ((y) * DQN_KECCAK_LANE_SIZE_U64))
// ---------------------------------------------------------------------
// θ step
// ---------------------------------------------------------------------
#if 1
Dqn_Keccak_u64 c[DQN_KECCAK_LANE_SIZE_U64];
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
{
c[x] = lanes_u64[LANE_INDEX(x, 0)] ^
lanes_u64[LANE_INDEX(x, 1)] ^
lanes_u64[LANE_INDEX(x, 2)] ^
lanes_u64[LANE_INDEX(x, 3)] ^
lanes_u64[LANE_INDEX(x, 4)];
}
Dqn_Keccak_u64 d[DQN_KECCAK_LANE_SIZE_U64];
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
d[x] = c[(x + 4) % DQN_KECCAK_LANE_SIZE_U64] ^ DQN_KECCAK_ROL64(c[(x + 1) % DQN_KECCAK_LANE_SIZE_U64], 1);
for (int y = 0; y < DQN_KECCAK_LANE_SIZE_U64; y++)
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
lanes_u64[LANE_INDEX(x, y)] ^= d[x];
#else
Dqn_Keccak_u64 c[5], d[5];
c[0] = lanes_u64[0 * 5 + 0] ^ lanes_u64[1 * 5 + 0] ^ lanes_u64[2 * 5 + 0] ^ lanes_u64[3 * 5 + 0] ^ lanes_u64[4 * 5 + 0];
c[1] = lanes_u64[0 * 5 + 1] ^ lanes_u64[1 * 5 + 1] ^ lanes_u64[2 * 5 + 1] ^ lanes_u64[3 * 5 + 1] ^ lanes_u64[4 * 5 + 1];
c[2] = lanes_u64[0 * 5 + 2] ^ lanes_u64[1 * 5 + 2] ^ lanes_u64[2 * 5 + 2] ^ lanes_u64[3 * 5 + 2] ^ lanes_u64[4 * 5 + 2];
c[3] = lanes_u64[0 * 5 + 3] ^ lanes_u64[1 * 5 + 3] ^ lanes_u64[2 * 5 + 3] ^ lanes_u64[3 * 5 + 3] ^ lanes_u64[4 * 5 + 3];
c[4] = lanes_u64[0 * 5 + 4] ^ lanes_u64[1 * 5 + 4] ^ lanes_u64[2 * 5 + 4] ^ lanes_u64[3 * 5 + 4] ^ lanes_u64[4 * 5 + 4];
d[0] = c[4] ^ DQN_KECCAK_ROL64(c[1], 1);
d[1] = c[0] ^ DQN_KECCAK_ROL64(c[2], 1);
d[2] = c[1] ^ DQN_KECCAK_ROL64(c[3], 1);
d[3] = c[2] ^ DQN_KECCAK_ROL64(c[4], 1);
d[4] = c[3] ^ DQN_KECCAK_ROL64(c[0], 1);
#endif
// ---------------------------------------------------------------------
// ρ and π steps
// ---------------------------------------------------------------------
Dqn_Keccak_u64 b[DQN_KECCAK_LANE_SIZE_U64 * DQN_KECCAK_LANE_SIZE_U64];
for (int y = 0; y < DQN_KECCAK_LANE_SIZE_U64; y++)
{
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
{
Dqn_Keccak_u64 lane = lanes_u64[LANE_INDEX(x, y)];
Dqn_Keccak_u64 rotate_count = DQN_KECCAK_ROTATIONS[x][y];
b[LANE_INDEX(y, (2 * x + 3 * y) % 5)] = DQN_KECCAK_ROL64(lane, rotate_count);
#if 0
int index = LANE_INDEX(y, (2 * x + 3 * y) % 5);
printf("B%02d: %024llu\n", index, b[index]);
#endif
}
#if 0
printf("\n");
#endif
}
// ---------------------------------------------------------------------
// χ step
// ---------------------------------------------------------------------
for (int y = 0; y < DQN_KECCAK_LANE_SIZE_U64; y++)
{
for (int x = 0; x < DQN_KECCAK_LANE_SIZE_U64; x++)
{
Dqn_Keccak_u64 rhs = ~b[LANE_INDEX((x + 1) % 5, y)] &
b[LANE_INDEX((x + 2) % 5, y)];
lanes_u64[LANE_INDEX(x, y)] = b[LANE_INDEX(x, y)] ^ rhs;
}
}
// ---------------------------------------------------------------------
// ι step
// ---------------------------------------------------------------------
lanes_u64[LANE_INDEX(0, 0)] ^= DQN_KECCAK_ROUNDS[round_index];
#if 0
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
Dqn_Keccak_u64 lane = lanes_u64[x + (y * 5)];
printf("[%d,%d] %024llu ", x, y, lane);
}
printf("\n");
}
#endif
#undef LANE_INDEX
#undef DQN_KECCAK_ROL64
}
#else
Dqn_Keccak__ReferencePermute((Dqn_Keccak_u64 *)state);
#endif
}
static void Dqn_Keccak__Construction(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size, int bitrate, char delimited_suffix)
{
int const ABSORB_SIZE = bitrate / 8;
int const ABSORB_SIZE_U64 = ABSORB_SIZE / 8;
Dqn_Keccak_u64 state_u64[DQN_KECCAK_LANE_SIZE_U64 * DQN_KECCAK_LANE_SIZE_U64] = {};
// ---------------------------------------------------------------------
// Sponge Step: Absorb all the bytes into the state
// ---------------------------------------------------------------------
Dqn_Keccak_u64 const *block = (Dqn_Keccak_u64 const *)src;
int const absorb_count = src_size / ABSORB_SIZE;
for (int absorb_index = 0; absorb_index < absorb_count; absorb_index++, block += ABSORB_SIZE_U64)
{
for (int index = 0; index < ABSORB_SIZE_U64; index++)
state_u64[index] ^= block[index];
Dqn_Keccak__Permute(state_u64);
}
// ---------------------------------------------------------------------
// Sponge Finalization Step: Remaining source bytes + padding
// ---------------------------------------------------------------------
// NOTE: Do the remainder bytes not divisible in the block, then, also,
// complete the sponge by adding the padding bits and delimited suffix.
{
Dqn_Keccak_u8 * state_u8 = (Dqn_Keccak_u8 *) state_u64;
Dqn_Keccak_u8 const *block_u8 = (Dqn_Keccak_u8 const *) block;
int const remainder = src_size % ABSORB_SIZE;
for (int index = 0; index < remainder; index++)
state_u8[index] ^= block_u8[index];
// NOTE: (remainder + 1) can never point out of array bounds, the
// remainder is guaranteed to be less than the ABSORB_SIZE, since we
// processed all the full blocks above.
int const delimited_suffix_index = remainder;
int const INDEX_OF_0X80_BYTE = ABSORB_SIZE - 1;
state_u8[delimited_suffix_index] ^= delimited_suffix;
// NOTE: In the reference implementation, it checks that if the
// delimited suffix is set to the padding bit (0x80), then we need to
// permute twice. Once for the delimited suffix, and a second time for
// the "padding" permute.
//
// However all standard algorithms either specify a 0x01, or 0x06, 0x04
// delimited suffix and so forth- so this case is never hit. We can omit
// this from the implementation here.
state_u8[INDEX_OF_0X80_BYTE] ^= 0x80;
Dqn_Keccak__Permute(state_u64);
}
// ---------------------------------------------------------------------
// Squeeze Step: Squeeze bytes from the state into our hash
// ---------------------------------------------------------------------
Dqn_Keccak_u8 * dest_u8 = (Dqn_Keccak_u8 *) dest;
int const squeeze_count = dest_size / ABSORB_SIZE;
int squeeze_index = 0;
for (; squeeze_index < squeeze_count; squeeze_index++)
{
if (squeeze_index) Dqn_Keccak__Permute(state_u64);
DQN_KECCAK_MEMCOPY(dest_u8, state_u64, ABSORB_SIZE);
dest_u8 += ABSORB_SIZE;
}
// ---------------------------------------------------------------------
// Squeeze Finalisation Step: Remainder bytes in hash
// ---------------------------------------------------------------------
{
int const remainder = dest_size % ABSORB_SIZE;
if (remainder)
{
if (squeeze_index) Dqn_Keccak__Permute(state_u64);
DQN_KECCAK_MEMCOPY(dest_u8, state_u64, remainder);
}
}
}
#define DQN_KECCAK_SHA3_DELIMITED_SUFFIX 0x06
#define DQN_KECCAK_DELIMITED_SUFFIX 0x01
// -----------------------------------------------------------------------------
// NOTE: SHA3-224
// -----------------------------------------------------------------------------
void Dqn_Keccak_SHA3_224(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 1152;
DQN_KECCAK_ASSERT(dest_size >= 224 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_SHA3_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_ToBytes28(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_SHA3_224(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: SHA3-256
// -----------------------------------------------------------------------------
void Dqn_Keccak_SHA3_256(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 1088;
DQN_KECCAK_ASSERT(dest_size >= 256 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_SHA3_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_ToBytes32(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_SHA3_256(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: SHA3-384
// -----------------------------------------------------------------------------
void Dqn_Keccak_SHA3_384(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 832;
DQN_KECCAK_ASSERT(dest_size >= 384 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_SHA3_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_ToBytes48(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_SHA3_384(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: SHA3-512
// -----------------------------------------------------------------------------
void Dqn_Keccak_SHA3_512(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 576;
DQN_KECCAK_ASSERT(dest_size >= 512 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_SHA3_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_ToBytes64(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_SHA3_512(bytes, bytes_size, result.data, sizeof(result));
return result;
}
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: SHA3 - Helpers for Dqn data structures
// -----------------------------------------------------------------------------
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_StringToBytes28(Dqn_String string)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_SHA3_224(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes28 Dqn_Keccak_SHA3_224_U8ArrayToBytes28(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_SHA3_224(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_StringToBytes32(Dqn_String string)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_SHA3_256(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes32 Dqn_Keccak_SHA3_256_U8ArrayToBytes32(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_SHA3_256(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_StringToBytes48(Dqn_String string)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_SHA3_384(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes48 Dqn_Keccak_SHA3_384_U8ArrayToBytes48(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_SHA3_384(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_StringToBytes64(Dqn_String string)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_SHA3_512(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes64 Dqn_Keccak_SHA3_512_U8ArrayToBytes64(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_SHA3_512(array.data, array.size, result.data, sizeof(result));
return result;
}
#endif // DQN_H
// -----------------------------------------------------------------------------
// NOTE: Keccak-224
// -----------------------------------------------------------------------------
void Dqn_Keccak_224(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 1152;
DQN_KECCAK_ASSERT(dest_size >= 224 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes28 Dqn_Keccak_224_ToBytes28(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_224(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: Keccak-256
// -----------------------------------------------------------------------------
void Dqn_Keccak_256(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 1088;
DQN_KECCAK_ASSERT(dest_size >= 256 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes32 Dqn_Keccak_256_ToBytes32(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_256(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: Keccak-384
// -----------------------------------------------------------------------------
void Dqn_Keccak_384(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 832;
DQN_KECCAK_ASSERT(dest_size >= 384 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes48 Dqn_Keccak_384_ToBytes48(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_384(bytes, bytes_size, result.data, sizeof(result));
return result;
}
// -----------------------------------------------------------------------------
// NOTE: Keccak-512
// -----------------------------------------------------------------------------
void Dqn_Keccak_512(void const *src, Dqn_Keccak_u64 src_size, void *dest, int dest_size)
{
int const BITRATE = 576;
DQN_KECCAK_ASSERT(dest_size >= 512 / 8);
Dqn_Keccak__Construction(src, src_size, dest, dest_size, BITRATE, DQN_KECCAK_DELIMITED_SUFFIX);
}
Dqn_KeccakBytes64 Dqn_Keccak_512_ToBytes64(void *bytes, Dqn_Keccak_u64 bytes_size)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_512(bytes, bytes_size, result.data, sizeof(result));
return result;
}
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: Keccak - Helpers for Dqn data structures
// -----------------------------------------------------------------------------
Dqn_KeccakBytes28 Dqn_Keccak_224_StringToBytes28(Dqn_String string)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_224(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes28 Dqn_Keccak_224_U8ArrayToBytes28(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes28 result;
Dqn_Keccak_224(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes32 Dqn_Keccak_256_StringToBytes32(Dqn_String string)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_256(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes32 Dqn_Keccak_256_U8ArrayToBytes32(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes32 result;
Dqn_Keccak_256(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes48 Dqn_Keccak_384_StringToBytes48(Dqn_String string)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_384(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes48 Dqn_Keccak_384_U8ArrayToBytes48(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes48 result;
Dqn_Keccak_384(array.data, array.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes64 Dqn_Keccak_512_StringToBytes64(Dqn_String string)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_512(string.str, string.size, result.data, sizeof(result));
return result;
}
Dqn_KeccakBytes64 Dqn_Keccak_512_U8ArrayToBytes64(Dqn_Array<Dqn_Keccak_u8> array)
{
Dqn_KeccakBytes64 result;
Dqn_Keccak_512(array.data, array.size, result.data, sizeof(result));
return result;
}
#endif // DQN_H
// -----------------------------------------------------------------------------
// NOTE: Helper functions
// -----------------------------------------------------------------------------
void Dqn_Keccak_BytesToHex(void const *src, Dqn_Keccak_u64 src_size, char *dest, Dqn_Keccak_u64 dest_size)
{
(void)src_size; (void)dest_size;
DQN_KECCAK_ASSERT(dest_size >= src_size * 2);
unsigned char *src_u8 = (unsigned char *)src;
for (Dqn_Keccak_u64 src_index = 0, dest_index = 0;
src_index < src_size;
src_index += 1, dest_index += 2)
{
char byte = src_u8[src_index];
char hex01 = (byte >> 4) & 0b1111;
char hex02 = (byte >> 0) & 0b1111;
dest[dest_index + 0] = hex01 < 10 ? (hex01 + '0') : (hex01 - 10) + 'a';
dest[dest_index + 1] = hex02 < 10 ? (hex02 + '0') : (hex02 - 10) + 'a';
}
}
Dqn_KeccakString56 Dqn_Keccak_Bytes28ToHex(Dqn_KeccakBytes28 const *bytes)
{
Dqn_KeccakString56 result;
Dqn_Keccak_BytesToHex(bytes->data, sizeof(bytes->data), result.str, sizeof(result.str));
result.str[sizeof(result.str) - 1] = 0;
return result;
}
Dqn_KeccakString64 Dqn_Keccak_Bytes32ToHex(Dqn_KeccakBytes32 const *bytes)
{
Dqn_KeccakString64 result;
Dqn_Keccak_BytesToHex(bytes->data, sizeof(bytes->data), result.str, sizeof(result.str));
result.str[sizeof(result.str) - 1] = 0;
return result;
}
Dqn_KeccakString96 Dqn_Keccak_Bytes48ToHex(Dqn_KeccakBytes48 const *bytes)
{
Dqn_KeccakString96 result;
Dqn_Keccak_BytesToHex(bytes->data, sizeof(bytes->data), result.str, sizeof(result.str));
result.str[sizeof(result.str) - 1] = 0;
return result;
}
Dqn_KeccakString128 Dqn_Keccak_Bytes64ToHex(Dqn_KeccakBytes64 const *bytes)
{
Dqn_KeccakString128 result;
Dqn_Keccak_BytesToHex(bytes->data, sizeof(bytes->data), result.str, sizeof(result.str));
result.str[sizeof(result.str) - 1] = 0;
return result;
}
int Dqn_Keccak_Bytes28Equals(Dqn_KeccakBytes28 const *a, Dqn_KeccakBytes28 const *b)
{
int result = DQN_KECCAK_MEMCMP(a->data, b->data, sizeof(*a)) == 0;
return result;
}
int Dqn_Keccak_Bytes32Equals(Dqn_KeccakBytes32 const *a, Dqn_KeccakBytes32 const *b)
{
int result = DQN_KECCAK_MEMCMP(a->data, b->data, sizeof(*a)) == 0;
return result;
}
int Dqn_Keccak_Bytes48Equals(Dqn_KeccakBytes48 const *a, Dqn_KeccakBytes48 const *b)
{
int result = DQN_KECCAK_MEMCMP(a->data, b->data, sizeof(*a)) == 0;
return result;
}
int Dqn_Keccak_Bytes64Equals(Dqn_KeccakBytes64 const *a, Dqn_KeccakBytes64 const *b)
{
int result = DQN_KECCAK_MEMCMP(a->data, b->data, sizeof(*a)) == 0;
return result;
}
#if defined(DQN_H)
// -----------------------------------------------------------------------------
// NOTE: Other helper functions for Dqn data structures
// -----------------------------------------------------------------------------
Dqn_KeccakBytes32 Dqn_Keccak_Hex64StringToBytes(Dqn_String hex)
{
DQN_KECCAK_ASSERT(hex.size == 64);
Dqn_KeccakBytes32 result;
Dqn_HexToBytes(hex.str, hex.size, result.data, sizeof(result));
return result;
}
#endif // DQN_H
#endif // DQN_KECCAK_IMPLEMENTATION