Overhaul of DN

This commit is contained in:
2026-07-05 12:47:51 +10:00
parent d4834f45c0
commit ed1f4fc0cc
15 changed files with 7823 additions and 8670 deletions
+446 -123
View File
@@ -2,18 +2,22 @@
#define DN_SHA3_H
// NOTE: DN_Sha3 -- FIPS202 SHA3 + non-finalized SHA3 (aka. Keccak) hashing algorithms
//
// Overview
// Single header file 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).
//
// Configuration
// Define this in one and only one C++ file to enable the implementation code of the header file.
//
// #define DN_SHA3_IMPLEMENTATION
//
// Define this to enable unit tests in the implementation, it requires dn.h to be visible in the
//
// #define DN_SHA3_WITH_TESTS
// License
// MIT License
//
@@ -35,26 +39,26 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <stdint.h>
#if !defined(DN_SHA3Memcpy)
#if !defined(DN_SHA3_Memcpy)
#include <string.h>
#define DN_SHA3Memcpy(dest, src, count) memcpy(dest, src, count)
#define DN_SHA3_Memcpy(dest, src, count) memcpy(dest, src, count)
#endif
#if !defined(DN_SHA3Memcmp)
#if !defined(DN_SHA3_Memcmp)
#include <string.h>
#define DN_SHA3Memcmp(dest, src, count) memcmp(dest, src, count)
#define DN_SHA3_Memcmp(dest, src, count) memcmp(dest, src, count)
#endif
#if !defined(DN_SHA3Memset)
#if !defined(DN_SHA3_Memset)
#include <string.h>
#define DN_SHA3Memset(dest, byte, count) memset(dest, byte, count)
#define DN_SHA3_Memset(dest, byte, count) memset(dest, byte, count)
#endif
#if !defined(DN_SHA3Assert)
#if !defined(DN_SHA3_Assert)
#if defined(NDEBUG)
#define DN_SHA3Assert(expr)
#define DN_SHA3_Assert(expr)
#else
#define DN_SHA3Assert(expr) \
#define DN_SHA3_Assert(expr) \
do { \
if (!(expr)) { \
(*(volatile int *)0) = 0; \
@@ -81,47 +85,52 @@ typedef struct DN_SHA3State {
char delimited_suffix; // The delimited suffix of the current hash
} DN_SHA3State;
enum DN_SHA3Family
enum DN_SHA3Type
{
DN_SHA3Family_SHA3, // FIPS 202 SHA3 (delimited suffix is 0x6)
DN_SHA3Family_Keccak, // Non-finalized SHA3 (only difference is delimited suffix of 0x1 instead of 0x6)
DN_SHA3Type_SHA3, // FIPS 202 SHA3 (delimited suffix is 0x6)
DN_SHA3Type_Keccak, // Non-finalized SHA3 (only difference is delimited suffix of 0x1 instead of 0x6)
};
// hash_size_bits: Number of bits to hash to. Available sizes are 224, 256, 384 and 512.
DN_SHA3State DN_SHA3FamilyInit (DN_SHA3Family type, size_t hash_size_bits);
DN_SHA3State DN_SHA3FamilyInitSHA3 (size_t hash_size_bits);
DN_SHA3State DN_SHA3FamilyInitKeccak(size_t hash_size_bits);
void DN_SHA3FamilyUpdate (DN_SHA3State *sha3, void const *data, size_t data_size);
void DN_SHA3FamilyFinish (DN_SHA3State *sha3, void *dest, size_t dest_size);
void DN_SHA3FamilyHash (DN_SHA3Family type, size_t hash_size_bits, void const *src, size_t src_size, void *dest, int dest_size);
DN_SHA3State DN_SHA3_Init (DN_SHA3Type type, size_t hash_size_bits);
DN_SHA3State DN_SHA3_InitSHA3 (size_t hash_size_bits);
DN_SHA3State DN_SHA3_InitKeccak (size_t hash_size_bits);
void DN_SHA3_Update (DN_SHA3State *sha3, void const *data, size_t data_size);
void DN_SHA3_Finish (DN_SHA3State *sha3, void *dest, size_t dest_size);
void DN_SHA3_Hash (DN_SHA3Type type, size_t hash_size_bits, void const *src, size_t src_size, void *dest, int dest_size);
void DN_SHA3Hash224bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x28 DN_SHA3Hash224b (void const *src, size_t src_size);
void DN_SHA3Hash256bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x32 DN_SHA3Hash256b (void const *src, size_t src_size);
void DN_SHA3Hash384bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x48 DN_SHA3Hash384b (void const *src, size_t src_size);
void DN_SHA3Hash512bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x64 DN_SHA3Hash512b (void const *src, size_t src_size);
void DN_SHA3_Hash224bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x28 DN_SHA3_Hash224b (void const *src, size_t src_size);
void DN_SHA3_Hash256bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x32 DN_SHA3_Hash256b (void const *src, size_t src_size);
void DN_SHA3_Hash384bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x48 DN_SHA3_Hash384b (void const *src, size_t src_size);
void DN_SHA3_Hash512bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x64 DN_SHA3_Hash512b (void const *src, size_t src_size);
void DN_KeccakHash224bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x28 DN_KeccakHash224b (void const *src, size_t src_size);
void DN_KeccakHash256bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x32 DN_KeccakHash256b (void const *src, size_t src_size);
void DN_KeccakHash384bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x48 DN_KeccakHash384b (void const *src, size_t src_size);
void DN_KeccakHash512bPtr (void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x64 DN_KeccakHash512b (void const *src, size_t src_size);
void DN_SHA3_HashKeccak224bPtr(void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x28 DN_SHA3_HashKeccak224b (void const *src, size_t src_size);
void DN_SHA3_HashKeccak256bPtr(void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x32 DN_SHA3_HashKeccak256b (void const *src, size_t src_size);
void DN_SHA3_HashKeccak384bPtr(void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x48 DN_SHA3_HashKeccak384b (void const *src, size_t src_size);
void DN_SHA3_HashKeccak512bPtr(void const *src, size_t src_size, void *dest, size_t dest_size);
DN_SHA3U8x64 DN_SHA3_HashKeccak512b (void const *src, size_t src_size);
void DN_SHA3HexFromBytes (void const *src, uint64_t src_size, char *dest, uint64_t dest_size);
DN_SHA3Str8x56 DN_SHA3HexFromU8x28 (DN_SHA3U8x28 const *bytes);
DN_SHA3Str8x64 DN_SHA3HexFromU8x32 (DN_SHA3U8x32 const *bytes);
DN_SHA3Str8x96 DN_SHA3HexFromU8x48 (DN_SHA3U8x48 const *bytes);
DN_SHA3Str8x128 DN_SHA3HexFromU8x64 (DN_SHA3U8x64 const *bytes);
bool DN_SHA3U8x28Eq (DN_SHA3U8x28 const *a, DN_SHA3U8x28 const *b);
bool DN_SHA3U8x32Eq (DN_SHA3U8x32 const *a, DN_SHA3U8x32 const *b);
bool DN_SHA3U8x48Eq (DN_SHA3U8x48 const *a, DN_SHA3U8x48 const *b);
bool DN_SHA3U8x64Eq (DN_SHA3U8x64 const *a, DN_SHA3U8x64 const *b);
void DN_SHA3_HexFromBytes (void const *src, uint64_t src_size, char *dest, uint64_t dest_size);
DN_SHA3Str8x56 DN_SHA3_HexFromU8x28 (DN_SHA3U8x28 const *bytes);
DN_SHA3Str8x64 DN_SHA3_HexFromU8x32 (DN_SHA3U8x32 const *bytes);
DN_SHA3Str8x96 DN_SHA3_HexFromU8x48 (DN_SHA3U8x48 const *bytes);
DN_SHA3Str8x128 DN_SHA3_HexFromU8x64 (DN_SHA3U8x64 const *bytes);
bool DN_SHA3_U8x28Eq (DN_SHA3U8x28 const *a, DN_SHA3U8x28 const *b);
bool DN_SHA3_U8x32Eq (DN_SHA3U8x32 const *a, DN_SHA3U8x32 const *b);
bool DN_SHA3_U8x48Eq (DN_SHA3U8x48 const *a, DN_SHA3U8x48 const *b);
bool DN_SHA3_U8x64Eq (DN_SHA3U8x64 const *a, DN_SHA3U8x64 const *b);
#if defined(DN_SHA3_WITH_TESTS)
DN_TestCore DN_SHA3_TestSuite(DN_Arena *arena);
void DN_SHA3_TestSuiteThenOutput(DN_Str8FromTestCoreFlags flags);
#endif
#endif // DN_SHA3_H
#if defined(DN_SHA3_IMPLEMENTATION)
@@ -143,7 +152,7 @@ uint64_t const DN_SHA3_ROTATIONS[][5] =
};
#define DN_SHA3_ROL64(val, rotate) (((val) << (rotate)) | (((val) >> (64 - (rotate)))))
static void DN_SHA3FamilyPermute_(void *state)
static void DN_SHA3_Permute_(void *state)
{
uint64_t *lanes_u64 = (uint64_t *)state;
for (int round_index = 0; round_index < 24; round_index++) {
@@ -206,12 +215,12 @@ static void DN_SHA3FamilyPermute_(void *state)
}
}
DN_SHA3State DN_SHA3FamilyInit(DN_SHA3Family type, size_t hash_size_bits)
DN_SHA3State DN_SHA3_Init(DN_SHA3Type type, size_t hash_size_bits)
{
DN_SHA3Assert(hash_size_bits == 224 ||
hash_size_bits == 256 ||
hash_size_bits == 384 ||
hash_size_bits == 512);
DN_SHA3_Assert(hash_size_bits == 224 ||
hash_size_bits == 256 ||
hash_size_bits == 384 ||
hash_size_bits == 512);
char const SHA3_DELIMITED_SUFFIX = 0x06;
char const KECCAK_DELIMITED_SUFFIX = 0x01;
@@ -224,24 +233,24 @@ DN_SHA3State DN_SHA3FamilyInit(DN_SHA3Family type, size_t hash_size_bits)
#endif
result.hash_size_bits = hash_size_bits;
result.absorb_size = bitrate / 8;
result.delimited_suffix = type == DN_SHA3Family_SHA3 ? SHA3_DELIMITED_SUFFIX : KECCAK_DELIMITED_SUFFIX;
DN_SHA3Assert(bitrate + (hash_size_bits * 2) /*capacity*/ == 1600);
result.delimited_suffix = type == DN_SHA3Type_SHA3 ? SHA3_DELIMITED_SUFFIX : KECCAK_DELIMITED_SUFFIX;
DN_SHA3_Assert(bitrate + (hash_size_bits * 2) /*capacity*/ == 1600);
return result;
}
DN_SHA3State DN_SHA3FamilyInitSHA3(size_t hash_size_bits)
DN_SHA3State DN_SHA3_InitSHA3(size_t hash_size_bits)
{
DN_SHA3State result = DN_SHA3FamilyInit(DN_SHA3Family_SHA3, hash_size_bits);
DN_SHA3State result = DN_SHA3_Init(DN_SHA3Type_SHA3, hash_size_bits);
return result;
}
DN_SHA3State DN_SHA3FamilyInitKeccak(size_t hash_size_bits)
DN_SHA3State DN_SHA3_InitKeccak(size_t hash_size_bits)
{
DN_SHA3State result = DN_SHA3FamilyInit(DN_SHA3Family_Keccak, hash_size_bits);
DN_SHA3State result = DN_SHA3_Init(DN_SHA3Type_Keccak, hash_size_bits);
return result;
}
void DN_SHA3FamilyUpdate(DN_SHA3State *sha3, void const *data, size_t data_size)
void DN_SHA3_Update(DN_SHA3State *sha3, void const *data, size_t data_size)
{
uint8_t *state = sha3->state;
uint8_t const *ptr = (uint8_t *)data;
@@ -258,21 +267,21 @@ void DN_SHA3FamilyUpdate(DN_SHA3State *sha3, void const *data, size_t data_size)
ptr_size -= bytes_to_absorb;
if (sha3->state_size >= sha3->absorb_size) {
DN_SHA3Assert(sha3->state_size == sha3->absorb_size);
DN_SHA3FamilyPermute_(state);
DN_SHA3_Assert(sha3->state_size == sha3->absorb_size);
DN_SHA3_Permute_(state);
sha3->state_size = 0;
}
}
}
void DN_SHA3FamilyFinish(DN_SHA3State *sha3, void *dest, size_t dest_size)
void DN_SHA3_Finish(DN_SHA3State *sha3, void *dest, size_t dest_size)
{
DN_SHA3Assert(dest_size >= (size_t)(sha3->hash_size_bits / 8));
DN_SHA3_Assert(dest_size >= (size_t)(sha3->hash_size_bits / 8));
// Sponge Finalization Step: Final padding bit
size_t const INDEX_OF_0X80_BYTE = sha3->absorb_size - 1;
size_t const delimited_suffix_index = sha3->state_size;
DN_SHA3Assert(delimited_suffix_index < sha3->absorb_size);
DN_SHA3_Assert(delimited_suffix_index < sha3->absorb_size);
uint8_t *state = sha3->state;
state[delimited_suffix_index] ^= sha3->delimited_suffix;
@@ -287,7 +296,7 @@ void DN_SHA3FamilyFinish(DN_SHA3State *sha3, void *dest, size_t dest_size)
// this from the implementation here.
state[INDEX_OF_0X80_BYTE] ^= 0x80;
DN_SHA3FamilyPermute_(state);
DN_SHA3_Permute_(state);
// Squeeze Step: Squeeze bytes from the state into our hash
uint8_t *dest_u8 = (uint8_t *)dest;
@@ -295,8 +304,8 @@ void DN_SHA3FamilyFinish(DN_SHA3State *sha3, void *dest, size_t dest_size)
size_t squeeze_index = 0;
for (; squeeze_index < squeeze_count; squeeze_index++) {
if (squeeze_index)
DN_SHA3FamilyPermute_(state);
DN_SHA3Memcpy(dest_u8, state, sha3->absorb_size);
DN_SHA3_Permute_(state);
DN_SHA3_Memcpy(dest_u8, state, sha3->absorb_size);
dest_u8 += sha3->absorb_size;
}
@@ -304,119 +313,119 @@ void DN_SHA3FamilyFinish(DN_SHA3State *sha3, void *dest, size_t dest_size)
size_t const remainder = dest_size % sha3->absorb_size;
if (remainder) {
if (squeeze_index)
DN_SHA3FamilyPermute_(state);
DN_SHA3Memcpy(dest_u8, state, remainder);
DN_SHA3_Permute_(state);
DN_SHA3_Memcpy(dest_u8, state, remainder);
}
}
void DN_SHA3FamilyHash(DN_SHA3Family type, size_t hash_size_bits, void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_Hash(DN_SHA3Type type, size_t hash_size_bits, void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3State state = DN_SHA3FamilyInit(type, hash_size_bits);
DN_SHA3FamilyUpdate(&state, src, src_size);
DN_SHA3FamilyFinish(&state, dest, dest_size);
DN_SHA3State state = DN_SHA3_Init(type, hash_size_bits);
DN_SHA3_Update(&state, src, src_size);
DN_SHA3_Finish(&state, dest, dest_size);
}
void DN_SHA3Hash224bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_Hash224bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_SHA3, /*hash_size_bits=*/ 224, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_SHA3, /*hash_size_bits=*/ 224, src, src_size, dest, dest_size);
}
DN_SHA3U8x28 DN_SHA3Hash224b(void const *src, size_t src_size)
DN_SHA3U8x28 DN_SHA3_Hash224b(void const *src, size_t src_size)
{
DN_SHA3U8x28 result = {};
DN_SHA3Hash224bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_Hash224bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_SHA3Hash256bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_Hash256bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_SHA3, /*hash_size_bits=*/ 256, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_SHA3, /*hash_size_bits=*/ 256, src, src_size, dest, dest_size);
}
DN_SHA3U8x32 DN_SHA3Hash256b(void const *src, size_t src_size)
DN_SHA3U8x32 DN_SHA3_Hash256b(void const *src, size_t src_size)
{
DN_SHA3U8x32 result = {};
DN_SHA3Hash256bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_Hash256bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_SHA3Hash384bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_Hash384bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_SHA3, /*hash_size_bits=*/ 384, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_SHA3, /*hash_size_bits=*/ 384, src, src_size, dest, dest_size);
}
DN_SHA3U8x48 DN_SHA3Hash384b(void const *src, size_t src_size)
DN_SHA3U8x48 DN_SHA3_Hash384b(void const *src, size_t src_size)
{
DN_SHA3U8x48 result = {};
DN_SHA3Hash384bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_Hash384bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_SHA3Hash512bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_Hash512bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_SHA3, /*hash_size_bits=*/ 512, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_SHA3, /*hash_size_bits=*/ 512, src, src_size, dest, dest_size);
}
DN_SHA3U8x64 DN_SHA3Hash512b(void const *src, size_t src_size)
DN_SHA3U8x64 DN_SHA3_Hash512b(void const *src, size_t src_size)
{
DN_SHA3U8x64 result = {};
DN_SHA3Hash512bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_Hash512bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_KeccakHash224bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_HashKeccak224bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_Keccak, /*hash_size_bits=*/ 224, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_Keccak, /*hash_size_bits=*/ 224, src, src_size, dest, dest_size);
}
DN_SHA3U8x28 DN_KeccakHash224b(void const *src, size_t src_size)
DN_SHA3U8x28 DN_SHA3_HashKeccak224b(void const *src, size_t src_size)
{
DN_SHA3U8x28 result = {};
DN_KeccakHash224bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_HashKeccak224bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_KeccakHash256bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_HashKeccak256bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_Keccak, /*hash_size_bits=*/ 256, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_Keccak, /*hash_size_bits=*/ 256, src, src_size, dest, dest_size);
}
DN_SHA3U8x32 DN_KeccakHash256b(void const *src, size_t src_size)
DN_SHA3U8x32 DN_SHA3_HashKeccak256b(void const *src, size_t src_size)
{
DN_SHA3U8x32 result = {};
DN_KeccakHash256bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_HashKeccak256bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_KeccakHash384bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_HashKeccak384bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_Keccak, /*hash_size_bits=*/ 384, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_Keccak, /*hash_size_bits=*/ 384, src, src_size, dest, dest_size);
}
DN_SHA3U8x48 DN_KeccakHash384b(void const *src, size_t src_size)
DN_SHA3U8x48 DN_SHA3_HashKeccak384b(void const *src, size_t src_size)
{
DN_SHA3U8x48 result = {};
DN_KeccakHash384bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_HashKeccak384bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_KeccakHash512bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
void DN_SHA3_HashKeccak512bPtr(void const *src, size_t src_size, void *dest, size_t dest_size)
{
DN_SHA3FamilyHash(DN_SHA3Family_Keccak, /*hash_size_bits=*/ 512, src, src_size, dest, dest_size);
DN_SHA3_Hash(DN_SHA3Type_Keccak, /*hash_size_bits=*/ 512, src, src_size, dest, dest_size);
}
DN_SHA3U8x64 DN_KeccakHash512b(void const *src, size_t src_size)
DN_SHA3U8x64 DN_SHA3_HashKeccak512b(void const *src, size_t src_size)
{
DN_SHA3U8x64 result = {};
DN_KeccakHash512bPtr(src, src_size, result.data, sizeof(result.data));
DN_SHA3_HashKeccak512bPtr(src, src_size, result.data, sizeof(result.data));
return result;
}
void DN_SHA3HexFromBytes(void const *src, size_t src_size, char *dest, size_t dest_size)
void DN_SHA3_HexFromBytes(void const *src, size_t src_size, char *dest, size_t dest_size)
{
(void)src_size;
(void)dest_size;
DN_SHA3Assert(dest_size >= src_size * 2);
DN_SHA3_Assert(dest_size >= src_size * 2);
unsigned char *src_u8 = (unsigned char *)src;
for (size_t src_index = 0, dest_index = 0; src_index < src_size;
@@ -429,59 +438,373 @@ void DN_SHA3HexFromBytes(void const *src, size_t src_size, char *dest, size_t de
}
}
DN_SHA3Str8x56 DN_SHA3HexFromU8x28(DN_SHA3U8x28 const *bytes)
DN_SHA3Str8x56 DN_SHA3_HexFromU8x28(DN_SHA3U8x28 const *bytes)
{
DN_SHA3Str8x56 result;
DN_SHA3HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
DN_SHA3_HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
result.data[sizeof(result.data) - 1] = 0;
return result;
}
DN_SHA3Str8x64 DN_SHA3HexFromU8x32(DN_SHA3U8x32 const *bytes)
DN_SHA3Str8x64 DN_SHA3_HexFromU8x32(DN_SHA3U8x32 const *bytes)
{
DN_SHA3Str8x64 result;
DN_SHA3HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
DN_SHA3_HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
result.data[sizeof(result.data) - 1] = 0;
return result;
}
DN_SHA3Str8x96 DN_SHA3HexFromU8x48(DN_SHA3U8x48 const *bytes)
DN_SHA3Str8x96 DN_SHA3_HexFromU8x48(DN_SHA3U8x48 const *bytes)
{
DN_SHA3Str8x96 result;
DN_SHA3HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
DN_SHA3_HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
result.data[sizeof(result.data) - 1] = 0;
return result;
}
DN_SHA3Str8x128 DN_SHA3HexFromU8x64(DN_SHA3U8x64 const *bytes)
DN_SHA3Str8x128 DN_SHA3_HexFromU8x64(DN_SHA3U8x64 const *bytes)
{
DN_SHA3Str8x128 result;
DN_SHA3HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
DN_SHA3_HexFromBytes(bytes->data, sizeof(bytes->data), result.data, sizeof(result.data));
result.data[sizeof(result.data) - 1] = 0;
return result;
}
bool DN_SHA3U8x32Eq(DN_SHA3U8x28 const *a, DN_SHA3U8x28 const *b)
bool DN_SHA3_U8x32Eq(DN_SHA3U8x28 const *a, DN_SHA3U8x28 const *b)
{
int result = DN_SHA3Memcmp(a->data, b->data, sizeof(*a)) == 0;
int result = DN_SHA3_Memcmp(a->data, b->data, sizeof(*a)) == 0;
return result;
}
bool DN_SHA3U8x32Eq(DN_SHA3U8x32 const *a, DN_SHA3U8x32 const *b)
bool DN_SHA3_U8x32Eq(DN_SHA3U8x32 const *a, DN_SHA3U8x32 const *b)
{
int result = DN_SHA3Memcmp(a->data, b->data, sizeof(*a)) == 0;
int result = DN_SHA3_Memcmp(a->data, b->data, sizeof(*a)) == 0;
return result;
}
bool DN_SHA3U8x48Eq(DN_SHA3U8x48 const *a, DN_SHA3U8x48 const *b)
bool DN_SHA3_U8x48Eq(DN_SHA3U8x48 const *a, DN_SHA3U8x48 const *b)
{
int result = DN_SHA3Memcmp(a->data, b->data, sizeof(*a)) == 0;
int result = DN_SHA3_Memcmp(a->data, b->data, sizeof(*a)) == 0;
return result;
}
bool DN_SHA3U8x64Eq(DN_SHA3U8x64 const *a, DN_SHA3U8x64 const *b)
bool DN_SHA3_U8x64Eq(DN_SHA3U8x64 const *a, DN_SHA3U8x64 const *b)
{
int result = DN_SHA3Memcmp(a->data, b->data, sizeof(*a)) == 0;
int result = DN_SHA3_Memcmp(a->data, b->data, sizeof(*a)) == 0;
return result;
}
#endif // DN_SHA3_IMPLEMENTATION
#if defined(DN_SHA3_WITH_TESTS)
#if !defined(DN_H)
#error dn.h must be included to enable tests for dn_sha3.h
#endif
DN_GCC_WARNING_PUSH
DN_GCC_WARNING_DISABLE(-Wunused-parameter)
DN_GCC_WARNING_DISABLE(-Wsign-compare)
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(4244)
DN_MSVC_WARNING_DISABLE(4100)
DN_MSVC_WARNING_DISABLE(6385)
// NOTE: Keccak Reference Implementation
// A very compact Keccak implementation taken from the reference implementation
// repository
// https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/C/Keccak-more-compact.c
#define FOR(i, n) for (i = 0; i < n; ++i)
void DN_SHA3RefImplKeccak_(int r, int c, const uint8_t *in, uint64_t inLen, uint8_t sfx, uint8_t *out, uint64_t outLen);
void DN_SHA3RefImplFIPS202_SHAKE128_(const uint8_t *in, uint64_t inLen, uint8_t *out, uint64_t outLen)
{
DN_SHA3RefImplKeccak_(1344, 256, in, inLen, 0x1F, out, outLen);
}
void DN_SHA3RefImplFIPS202_SHAKE256_(const uint8_t *in, uint64_t inLen, uint8_t *out, uint64_t outLen)
{
DN_SHA3RefImplKeccak_(1088, 512, in, inLen, 0x1F, out, outLen);
}
void DN_SHA3RefImplFIPS202_SHA3_224_(const uint8_t *in, uint64_t inLen, uint8_t *out)
{
DN_SHA3RefImplKeccak_(1152, 448, in, inLen, 0x06, out, 28);
}
void DN_SHA3RefImplFIPS202_SHA3_256_(const uint8_t *in, uint64_t inLen, uint8_t *out)
{
DN_SHA3RefImplKeccak_(1088, 512, in, inLen, 0x06, out, 32);
}
void DN_SHA3RefImplFIPS202_SHA3_384_(const uint8_t *in, uint64_t inLen, uint8_t *out)
{
DN_SHA3RefImplKeccak_(832, 768, in, inLen, 0x06, out, 48);
}
void DN_SHA3RefImplFIPS202_SHA3_512_(const uint8_t *in, uint64_t inLen, uint8_t *out)
{
DN_SHA3RefImplKeccak_(576, 1024, in, inLen, 0x06, out, 64);
}
int DN_SHA3RefImplLFSR86540_(uint8_t *R)
{
(*R) = ((*R) << 1) ^ (((*R) & 0x80) ? 0x71 : 0);
return ((*R) & 2) >> 1;
}
#define ROL(a, o) ((((uint64_t)a) << o) ^ (((uint64_t)a) >> (64 - o)))
static uint64_t DN_SHA3RefImplload64_(const uint8_t *x)
{
int i;
uint64_t u = 0;
FOR(i, 8)
{
u <<= 8;
u |= x[7 - i];
}
return u;
}
static void DN_SHA3RefImplstore64_(uint8_t *x, uint64_t u)
{
int i;
FOR(i, 8)
{
x[i] = u;
u >>= 8;
}
}
static void DN_SHA3RefImplxor64_(uint8_t *x, uint64_t u)
{
int i;
FOR(i, 8)
{
x[i] ^= u;
u >>= 8;
}
}
#define rL(x, y) DN_SHA3RefImplload64_((uint8_t *)s + 8 * (x + 5 * y))
#define wL(x, y, l) DN_SHA3RefImplstore64_((uint8_t *)s + 8 * (x + 5 * y), l)
#define XL(x, y, l) DN_SHA3RefImplxor64_((uint8_t *)s + 8 * (x + 5 * y), l)
void DN_SHA3RefImplKeccak_F1600(void *s)
{
int r, x, y, i, j, Y;
uint8_t R = 0x01;
uint64_t C[5], D;
for (i = 0; i < 24; i++) {
/*??*/ FOR(x, 5) C[x] = rL(x, 0) ^ rL(x, 1) ^ rL(x, 2) ^ rL(x, 3) ^ rL(x, 4);
FOR(x, 5)
{
D = C[(x + 4) % 5] ^ ROL(C[(x + 1) % 5], 1);
FOR(y, 5)
XL(x, y, D);
}
/*????*/ x = 1;
y = r = 0;
D = rL(x, y);
FOR(j, 24)
{
r += j + 1;
Y = (2 * x + 3 * y) % 5;
x = y;
y = Y;
C[0] = rL(x, y);
wL(x, y, ROL(D, r % 64));
D = C[0];
}
/*??*/ FOR(y, 5)
{
FOR(x, 5)
C[x] = rL(x, y);
FOR(x, 5)
wL(x, y, C[x] ^ ((~C[(x + 1) % 5]) & C[(x + 2) % 5]));
}
/*??*/ FOR(j, 7) if (DN_SHA3RefImplLFSR86540_(&R)) XL(0, 0, (uint64_t)1 << ((1 << j) - 1));
}
}
void DN_SHA3RefImplKeccak_(int r, int c, const uint8_t *in, uint64_t inLen, uint8_t sfx, uint8_t *out, uint64_t outLen)
{
/*initialize*/ uint8_t s[200];
int R = r / 8;
int i, b = 0;
FOR(i, 200)
s[i] = 0;
/*absorb*/ while (inLen > 0) {
b = (inLen < R) ? inLen : R;
FOR(i, b)
s[i] ^= in[i];
in += b;
inLen -= b;
if (b == R) {
DN_SHA3RefImplKeccak_F1600(s);
b = 0;
}
}
/*pad*/ s[b] ^= sfx;
if ((sfx & 0x80) && (b == (R - 1)))
DN_SHA3RefImplKeccak_F1600(s);
s[R - 1] ^= 0x80;
DN_SHA3RefImplKeccak_F1600(s);
/*squeeze*/ while (outLen > 0) {
b = (outLen < R) ? outLen : R;
FOR(i, b)
out[i] = s[i];
out += b;
outLen -= b;
if (outLen > 0)
DN_SHA3RefImplKeccak_F1600(s);
}
}
#undef XL
#undef wL
#undef rL
#undef ROL
#undef FOR
DN_MSVC_WARNING_POP
DN_GCC_WARNING_POP
enum DN_SHA3TestHash
{
DN_SHA3TestHash_224,
DN_SHA3TestHash_256,
DN_SHA3TestHash_384,
DN_SHA3TestHash_512,
DN_SHA3TestHash_Keccak224,
DN_SHA3TestHash_Keccak256,
DN_SHA3TestHash_Keccak384,
DN_SHA3TestHash_Keccak512,
DN_SHA3TestHash_Count,
};
static void DN_SHA3TestHashDispatch_(DN_TestCore *test, DN_SHA3TestHash hash_type, DN_Str8 input)
{
DN_TCScratch scratch = DN_TCScratchBeginArena(&test->arena, 1);
DN_Str8 input_hex = DN_HexFromPtrBytesArena(input.data, input.count, &scratch.arena, DN_TrimLeadingZero_No);
switch (hash_type) {
case DN_SHA3TestHash_Count: DN_AssertInvalidCodePath; break;
case DN_SHA3TestHash_224: {
DN_SHA3U8x28 hash = DN_SHA3_Hash224b(input.data, input.count);
DN_SHA3U8x28 expect;
DN_SHA3RefImplFIPS202_SHA3_224_(DN_Cast(uint8_t *) input.data, input.count, (uint8_t *)expect.data);
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_256: {
DN_SHA3U8x32 hash = DN_SHA3_Hash256b(input.data, input.count);
DN_SHA3U8x32 expect;
DN_SHA3RefImplFIPS202_SHA3_256_(DN_Cast(uint8_t *) input.data, input.count, (uint8_t *)expect.data);
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_384: {
DN_SHA3U8x48 hash = DN_SHA3_Hash384b(input.data, input.count);
DN_SHA3U8x48 expect;
DN_SHA3RefImplFIPS202_SHA3_384_(DN_Cast(uint8_t *) input.data, input.count, (uint8_t *)expect.data);
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_512: {
DN_SHA3U8x64 hash = DN_SHA3_Hash512b(input.data, input.count);
DN_SHA3U8x64 expect;
DN_SHA3RefImplFIPS202_SHA3_512_(DN_Cast(uint8_t *) input.data, input.count, (uint8_t *)expect.data);
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_Keccak224: {
DN_SHA3U8x28 hash = DN_SHA3_HashKeccak224b(input.data, input.count);
DN_SHA3U8x28 expect;
DN_SHA3RefImplKeccak_(1152, 448, DN_Cast(uint8_t *) input.data, input.count, 0x01, (uint8_t *)expect.data, sizeof(expect));
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_Keccak256: {
DN_SHA3U8x32 hash = DN_SHA3_HashKeccak256b(input.data, input.count);
DN_SHA3U8x32 expect;
DN_SHA3RefImplKeccak_(1088, 512, DN_Cast(uint8_t *) input.data, input.count, 0x01, (uint8_t *)expect.data, sizeof(expect));
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_Keccak384: {
DN_SHA3U8x48 hash = DN_SHA3_HashKeccak384b(input.data, input.count);
DN_SHA3U8x48 expect;
DN_SHA3RefImplKeccak_(832, 768, DN_Cast(uint8_t *) input.data, input.count, 0x01, (uint8_t *)expect.data, sizeof(expect));
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
case DN_SHA3TestHash_Keccak512: {
DN_SHA3U8x64 hash = DN_SHA3_HashKeccak512b(input.data, input.count);
DN_SHA3U8x64 expect;
DN_SHA3RefImplKeccak_(576, 1024, DN_Cast(uint8_t *) input.data, input.count, 0x01, (uint8_t *)expect.data, sizeof(expect));
DN_TestVerifyBytesEqF(test, DN_Str8FromLitArray(hash.data), DN_Str8FromLitArray(expect.data), "Input: %.*s", DN_Str8PrintFmt(input_hex));
} break;
}
DN_TCScratchEnd(&scratch);
}
DN_TestCore DN_SHA3_TestSuite(DN_Arena *arena)
{
DN_TestCore result = DN_TestInit(arena);
for (DN_TestGroupScopeF(&result, "SHA3")) {
for (DN_ForIndexU(hash_type, DN_SHA3TestHash_Count)) {
// NOTE: Get a name for the hash type
DN_Str8 hash_name = {};
switch (hash_type) {
case DN_SHA3TestHash_224: hash_name = DN_Str8Lit("SHA3-224"); break;
case DN_SHA3TestHash_256: hash_name = DN_Str8Lit("SHA3-256"); break;
case DN_SHA3TestHash_384: hash_name = DN_Str8Lit("SHA3-384"); break;
case DN_SHA3TestHash_512: hash_name = DN_Str8Lit("SHA3-512"); break;
case DN_SHA3TestHash_Keccak224: hash_name = DN_Str8Lit("Keccak-224"); break;
case DN_SHA3TestHash_Keccak256: hash_name = DN_Str8Lit("Keccak-256"); break;
case DN_SHA3TestHash_Keccak384: hash_name = DN_Str8Lit("Keccak-384"); break;
case DN_SHA3TestHash_Keccak512: hash_name = DN_Str8Lit("Keccak-512"); break;
case DN_SHA3TestHash_Count: DN_AssertInvalidCodePath; break;
}
// NOTE: Test SHA3 against some fixed inputs
{
DN_Str8 const INPUTS[] = {
DN_Str8Lit("abc"),
DN_Str8Lit(""),
DN_Str8Lit("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
DN_Str8Lit("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
};
for (DN_ForItCArray(it, DN_Str8 const, INPUTS)) {
for (DN_TestScopeF(&result, "[%.*s] %.*s", DN_Str8PrintFmt(hash_name), DN_Str8PrintFmt(*it.data)))
DN_SHA3TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, *it.data);
}
}
// NOTE: Test SHA3 against some deterministic inputs generated from a PRNG
for (DN_TestScopeF(&result, "[%.*s] Deterministic random inputs", DN_Str8PrintFmt(hash_name))) {
DN_PCG32 rng = DN_PCG32Init(0xd48e'be21'2af8'733d);
for (DN_USize index = 0; index < 128; index++) {
// NOTE: Create a 4kb buffer with the deterministic contents
char src[4096] = {};
DN_U32 src_size = DN_PCG32Range(&rng, 0, sizeof(src));
for (DN_USize src_index = 0; src_index < src_size; src_index++)
src[src_index] = DN_Cast(char) DN_PCG32Range(&rng, 0, 255);
// NOTE: Do the hashing
DN_Str8 input = DN_Str8FromPtr(src, src_size);
DN_SHA3TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, input);
}
}
}
}
return result;
}
void DN_SHA3_TestSuiteThenOutput(DN_Str8FromTestCoreFlags flags)
{
DN_Arena arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_Kilobytes(64), DN_MemFlags_Nil, DN_OS_HeapInitDefault());
DN_TestCore test = DN_SHA3_TestSuite(&arena);
DN_Str8 output = DN_Str8FromTestCore(&test, &arena, flags);
printf("%.*s", DN_Str8PrintFmt(output));
DN_ArenaDeinit(&arena);
}
#endif // #if defined(DN_SHA3_WITH_TESTS)
#endif // #if defined(DN_SHA3_IMPLEMENTATION)