Update dqn and add some new libraries from internal projects
This commit is contained in:
parent
7f082c9395
commit
86391f6a73
88
Dqn_Curl.h
88
Dqn_Curl.h
@ -3,9 +3,8 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Curl
|
||||
// -----------------------------------------------------------------------------
|
||||
// A wrapper over CURL that is primarily used for hot-code reloading by
|
||||
// packaging the CURL api into a struct that can be passed across DLL
|
||||
// boundaries.
|
||||
// Define DQN_CURL_IMPLEMENTATION in one and only one file to enable the
|
||||
// implementation in translation unit.
|
||||
//
|
||||
// curl_global_init(CURL_GLOBAL_ALL) must return CURLE_OK before anything
|
||||
// in this file is used. You may cleanup curl on exit via curl_global_cleanup()
|
||||
@ -14,15 +13,56 @@
|
||||
// An easy way to generate the curl commands required to query a url is to use
|
||||
// CURL itself and the option to dump the command to a C-compatible file, i.e.
|
||||
//
|
||||
// curl --libcurl RequestToCCode.c -X POST -H "Content-Type: application/json" --data-binary "{\"jsonrpc\": \"2.0\", \"id\": \"0\", \"method\": \"get_service_nodes\", \"params\": []}" oxen.observer:22023/json_rpc
|
||||
// curl --libcurl RequestToCCode.c -X POST -H "Content-Type: application/json" --data-binary "{\"jsonrpc\": \"2.0\", \"id\": \"0\", \"method\": \"get_block_count\", \"params\": []}" oxen.observer:22023/json_rpc
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Configuration
|
||||
// NOTE: Example
|
||||
// -----------------------------------------------------------------------------
|
||||
// #define DQN_CURL_IMPLEMENTATION
|
||||
// Define this in one and only one C++ file to enable the implementation
|
||||
// code of the header file.
|
||||
#if 0
|
||||
struct CurlWriteFunctionUserData
|
||||
{
|
||||
Dqn_ArenaAllocator *arena;
|
||||
Dqn_StringList data;
|
||||
};
|
||||
|
||||
size_t CurlWriteFunction(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
auto *user_data = DQN_CAST(CurlWriteFunctionUserData *)userdata;
|
||||
Dqn_StringList_AppendStringCopy(&user_data->data, user_data->arena, Dqn_String_Init(ptr, nmemb));
|
||||
DQN_ASSERT(size == 1);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// NOTE: Setup Curl handle
|
||||
CURL *handle = curl_easy_init();
|
||||
|
||||
struct curl_slist *header_list = nullptr;
|
||||
header_list = curl_slist_append(header_list, "Content-Type: application/json");
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);
|
||||
|
||||
Dqn_String post_data = DQN_STRING("{\"jsonrpc\": \"2.0\", \"id\": \"0\", \"method\": \"get_block_count\", \"params\": []}");
|
||||
Dqn_Curl_SetHTTPPost(handle, "oxen.observer:22023/json_rpc", post_data.str, DQN_CAST(int)post_data.size);
|
||||
|
||||
// NOTE: Set write callback
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch();
|
||||
CurlWriteFunctionUserData user_data = {};
|
||||
user_data.arena = scratch.arena;
|
||||
Dqn_Curl_SetWriteCallback(handle, CurlWriteFunction, &user_data);
|
||||
|
||||
// NOTE: Execute CURL query
|
||||
curl_easy_perform(handle);
|
||||
Dqn_String output = Dqn_StringList_Build(&user_data.string_list, scoped_arena.arena);
|
||||
DQN_LOG_I("%.*s", DQN_STRING_FMT(output));
|
||||
|
||||
// NOTE: Cleanup
|
||||
curl_slist_free_all(header_list);
|
||||
curl_easy_cleanup(handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: Warning this causes Windows.h to be included.
|
||||
#define CURL_STATICLIB
|
||||
#define NOMINMAX
|
||||
#include <curl-7.72.0/include/curl/curl.h>
|
||||
@ -47,8 +87,9 @@ struct Dqn_CurlProcs
|
||||
};
|
||||
|
||||
Dqn_CurlProcs Dqn_CurlProcs_Init();
|
||||
void Dqn_Curl_SetPostData(CURL *curl, char const *post_data, int post_size);
|
||||
|
||||
void Dqn_Curl_SetURL(CURL *handle, char const *url);
|
||||
void Dqn_Curl_SetHTTPPost(CURL *handle, char const *url, char const *post_data, int post_data_size);
|
||||
void Dqn_Curl_SetWriteCallback(CURL *handle, size_t (*curl_write_callback)(char *ptr, size_t size, size_t nmemb, void *userdata), void *user_data);
|
||||
#endif // DQN_CURL_H
|
||||
|
||||
#if defined(DQN_CURL_IMPLEMENTATION)
|
||||
@ -80,10 +121,29 @@ Dqn_CurlProcs Dqn_CurlProcs_Init()
|
||||
return result;
|
||||
}
|
||||
|
||||
void Dqn_Curl_SetPostData(CURL *curl, char const *post_data, int post_size)
|
||||
void Dqn_Curl_SetURL(CURL *handle, char const *url)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, post_size);
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
}
|
||||
|
||||
void Dqn_Curl_SetHTTPPost(CURL *handle, char const *url, char const *post_data, int post_data_size)
|
||||
{
|
||||
curl_easy_setopt(handle, CURLOPT_BUFFERSIZE, 102400L);
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1L);
|
||||
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, post_data);
|
||||
curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)post_data_size);
|
||||
curl_easy_setopt(handle, CURLOPT_USERAGENT, "curl/7.55.1");
|
||||
curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 50L);
|
||||
curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_easy_setopt(handle, CURLOPT_TCP_KEEPALIVE, 1L);
|
||||
}
|
||||
|
||||
void Dqn_Curl_SetWriteCallback(CURL *handle,
|
||||
size_t (*curl_write_callback)(char *ptr, size_t size, size_t nmemb, void *userdata),
|
||||
void *user_data)
|
||||
{
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_write_callback);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, user_data);
|
||||
}
|
||||
#endif // DQN_CURL_IMPLEMENTATION
|
||||
|
704
Dqn_Jsmn.h
704
Dqn_Jsmn.h
@ -1,4 +1,4 @@
|
||||
#ifndef DQN_JSMN_H
|
||||
#if !defined(DQN_JSMN_H)
|
||||
#define DQN_JSMN_H
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Jsmn
|
||||
@ -16,7 +16,7 @@
|
||||
//
|
||||
|
||||
#if !defined(DQN_H)
|
||||
#error You must include "Dqn.h" before including "Dqn_Jsmn.h"
|
||||
#error You must include "dqn.h" before including "dqn_jsmn.h"
|
||||
#endif // DQN_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -135,13 +135,147 @@ JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
|
||||
#endif
|
||||
#endif // JSMN_H
|
||||
|
||||
// NOTE: Iterator copied from: https://github.com/zserge/jsmn/pull/69
|
||||
// TODO(dqn): Write our own iterator logic in a manner that is more stateful
|
||||
// than the current implementation, we should not have pass information back and
|
||||
// forth between iterators, i.e. see my iterator abstraction that sits on top of
|
||||
// this.
|
||||
#ifndef __JSMN_ITERATOR_H__
|
||||
#define __JSMN_ITERATOR_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Error return codes for jsmn iterator
|
||||
*/
|
||||
enum {
|
||||
/* Input parameter error */
|
||||
JSMNITER_ERR_PARAMETER = -1,
|
||||
/* JSMN index doesn't point at an Array/Object */
|
||||
JSMNITER_ERR_TYPE = -2,
|
||||
/* Group item misses string identifier */
|
||||
JSMNITER_ERR_NOIDENT = -3,
|
||||
/* Broken JSON */
|
||||
JSMNITER_ERR_BROKEN = -4,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Struct with state information for jsmn iterator
|
||||
* - When the no more items for iterator the parser_pos value will point to
|
||||
* JSMN index for next object after current Array/Object
|
||||
*/
|
||||
typedef struct {
|
||||
jsmntok_t *jsmn_tokens;
|
||||
unsigned int jsmn_len;
|
||||
unsigned int parent_pos;
|
||||
unsigned int parser_pos;
|
||||
unsigned int index;
|
||||
} jsmn_iterator_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Takes an JSMN Array/Object and locates index for last item in collection
|
||||
* @details Iterates over JSMN Array/Object until last item is found
|
||||
*
|
||||
* @param jsmn_tokens JSMN tokens
|
||||
* @param jsmn_len JSMN token count
|
||||
* @param parser_pos Current JSMN token
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* >=0 - JSMN index for last item in Array/Object
|
||||
*/
|
||||
int jsmn_iterator_find_last( jsmntok_t *jsmn_tokens, unsigned int jsmn_len, unsigned int parser_pos );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize iterator
|
||||
* @details Set initial value for iterator struct
|
||||
*
|
||||
* @param iterator Iterator struct
|
||||
* @param jsmn_tokens JSMN tokens
|
||||
* @param jsmn_len JSMN token count
|
||||
* @param parser_pos Current JSMN token
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* >=0 - Ok
|
||||
*/
|
||||
int jsmn_iterator_init( jsmn_iterator_t *iterator, jsmntok_t *jsmn_tokens, unsigned int jsmn_len,
|
||||
unsigned int parser_pos );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get next item in JSMN Array/Object
|
||||
* @details Gets JSMN position for next identifier and value in Array/Object
|
||||
*
|
||||
* @param iterator Iterator struct
|
||||
* @param jsmn_identifier Return pointer for identifier, NULL for Array
|
||||
* @param jsmn_value Return pointer for value
|
||||
* @param next_value_index Possible to indicate where next value begins, allows determine end of sub
|
||||
* Array/Object withouth manually searching for it
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* 0 - No more values
|
||||
* > 0 - Value (and identifier) has been returned
|
||||
*/
|
||||
int jsmn_iterator_next( jsmn_iterator_t *iterator, jsmntok_t **jsmn_identifier, jsmntok_t **jsmn_value,
|
||||
unsigned int next_value_index );
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return current parser position
|
||||
* @details For Array the parser point to current value index
|
||||
* For Object the parser points to the identifier
|
||||
*
|
||||
* @param iterator [description]
|
||||
* @return [description]
|
||||
*/
|
||||
#define jsmn_iterator_position(_iterator_) ((_iterator_)->parser_pos)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__JSMN_ITERATOR_H__*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Header File
|
||||
// -----------------------------------------------------------------------------
|
||||
#define DQN_JSMN_X_MACRO \
|
||||
DQN_JSMN_X_ENTRY(Object) \
|
||||
DQN_JSMN_X_ENTRY(Array) \
|
||||
DQN_JSMN_X_ENTRY(String) \
|
||||
DQN_JSMN_X_ENTRY(Number) \
|
||||
DQN_JSMN_X_ENTRY(Bool)
|
||||
|
||||
enum struct Dqn_JsmnTokenIs
|
||||
{
|
||||
#define DQN_JSMN_X_ENTRY(enum_val) enum_val,
|
||||
DQN_JSMN_X_MACRO
|
||||
#undef DQN_JSMN_X_ENTRY
|
||||
};
|
||||
|
||||
inline Dqn_String const Dqn_JsmnTokenIsEnumString(Dqn_JsmnTokenIs token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
#define DQN_JSMN_X_ENTRY(enum_val) case Dqn_JsmnTokenIs::enum_val: return DQN_STRING(#enum_val);
|
||||
DQN_JSMN_X_MACRO
|
||||
#undef DQN_JSMN_X_ENTRY
|
||||
}
|
||||
|
||||
return DQN_STRING("DQN_JSMN_UNHANDLED_ENUM");
|
||||
};
|
||||
|
||||
struct Dqn_JsmnError
|
||||
{
|
||||
jsmntok_t token;
|
||||
char const *cpp_func;
|
||||
Dqn_String json;
|
||||
Dqn_JsmnTokenIs expected;
|
||||
char const *cpp_file; // The file of the .cpp/h source code that triggered the error
|
||||
int cpp_line; // The line of the .cpp/h source code that triggered the error
|
||||
};
|
||||
@ -152,28 +286,94 @@ struct Dqn_JsmnErrorHandle
|
||||
Dqn_List<Dqn_JsmnError> list;
|
||||
};
|
||||
|
||||
void Dqn_JsmnErrorHandle_AddError (Dqn_JsmnErrorHandle *err_handle, char const *func, char const *file, int line);
|
||||
Dqn_String Dqn_JsmnToken_String (Dqn_String json, jsmntok_t token);
|
||||
Dqn_b32 Dqn_JsmnToken_Bool (Dqn_String json, jsmntok_t token);
|
||||
Dqn_u64 Dqn_JsmnToken_U64 (Dqn_String json, jsmntok_t token);
|
||||
jsmntok_t *Dqn_JsmnToken_AdvanceItPastObject(jsmntok_t *start_it, Dqn_JsmnErrorHandle *err_handle, Dqn_String json);
|
||||
jsmntok_t *Dqn_JsmnToken_AdvanceItPastArray (jsmntok_t *start_it, Dqn_JsmnErrorHandle *err_handle, Dqn_String json);
|
||||
struct Dqn_Jsmn
|
||||
{
|
||||
jsmn_parser parser;
|
||||
Dqn_String json;
|
||||
int tokens_size;
|
||||
jsmntok_t *tokens;
|
||||
};
|
||||
|
||||
#define Dqn_JsmnToken_ExpectBool(json, token, err_handle) Dqn_JsmnToken__ExpectBool(json, token, err_handle, __FILE__, __LINE__)
|
||||
#define Dqn_JsmnToken_ExpectNumber(json, token, err_handle) Dqn_JsmnToken__ExpectNumber(json, token, err_handle, __FILE__, __LINE__)
|
||||
#define Dqn_JsmnToken_ExpectString(token, err_handle) Dqn_JsmnToken__ExpectString(token, err_handle, __FILE__, __LINE__)
|
||||
#define Dqn_JsmnToken_ExpectArray(token, err_handle) Dqn_JsmnToken__ExpectArray(token, err_handle, __FILE__, __LINE__)
|
||||
#define Dqn_JsmnToken_ExpectObject(token, err_handle) Dqn_JsmnToken__ExpectObject(token, err_handle, __FILE__, __LINE__)
|
||||
struct Dqn_JsmnIterator
|
||||
{
|
||||
Dqn_b32 init;
|
||||
jsmn_iterator_t jsmn_it;
|
||||
Dqn_String json;
|
||||
jsmntok_t *key;
|
||||
jsmntok_t *value;
|
||||
|
||||
// When obj/array iteration is finished, we set the token_index_hint to the
|
||||
// parent iterator so that it knows where to continue off from and to skip
|
||||
// over the object/array we just iterated.
|
||||
int token_index_hint;
|
||||
};
|
||||
|
||||
Dqn_Jsmn Dqn_Jsmn_InitWithJSON (Dqn_String json, Dqn_ArenaAllocator *arena);
|
||||
Dqn_Jsmn Dqn_Jsmn_InitWithJSONFile (Dqn_String file, Dqn_ArenaAllocator *arena);
|
||||
|
||||
// return: If the token is an array, return the size of the array otherwise -1.
|
||||
int Dqn_Jsmn_TokenArraySize(jsmntok_t token);
|
||||
Dqn_String Dqn_Jsmn_TokenString(jsmntok_t token, Dqn_String json);
|
||||
Dqn_b32 Dqn_Jsmn_TokenBool(jsmntok_t token, Dqn_String json);
|
||||
Dqn_u64 Dqn_Jsmn_TokenU64(jsmntok_t token, Dqn_String json);
|
||||
|
||||
// Iterator abstraction over jsmn_iterator_t, example on how to use this is
|
||||
// shown below. The goal here is to minimise the amount of state the user has to
|
||||
// manage.
|
||||
#if 0
|
||||
Dqn_ArenaAllocator arena = {};
|
||||
Dqn_String json = DQN_STRING(R"({
|
||||
"test": {
|
||||
"test2": 0
|
||||
}
|
||||
})");
|
||||
|
||||
Dqn_Jsmn jsmn_state = Dqn_Jsmn_InitWithJSON(json, &arena);
|
||||
for (Dqn_JsmnIterator it = {}; Dqn_JsmnIterator_Next(&it, &jsmn_state, nullptr /*prev_it*/); )
|
||||
{
|
||||
Dqn_String key_str = Dqn_Jsmn_TokenString(*it.key, jsmn_state.json);
|
||||
if (Dqn_JsmnIterator_Key(&it) == DQN_STRING("test"))
|
||||
{
|
||||
if (!Dqn_JsmnIterator_ExpectValue(&it, Dqn_JsmnTokenIs::Object, nullptr))
|
||||
continue;
|
||||
|
||||
for (Dqn_JsmnIterator obj_it = {}; Dqn_JsmnIterator_Next(&obj_it, &jsmn_state, &it); )
|
||||
{
|
||||
if (Dqn_JsmnIterator_Key(&it) == DQN_STRING("test2"))
|
||||
{
|
||||
if (!Dqn_JsmnIterator_ExpectValue(&it, Dqn_JsmnTokenIs::Number, nullptr))
|
||||
continue;
|
||||
|
||||
Dqn_u64 test_2_value = Dqn_JsmnIterator_U64(&obj_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Dqn_b32 Dqn_JsmnIterator_Next(Dqn_JsmnIterator *it, Dqn_Jsmn *jsmn_state, Dqn_JsmnIterator *prev_it);
|
||||
Dqn_String Dqn_JsmnIterator_Key (Dqn_JsmnIterator *it);
|
||||
Dqn_JsmnIterator Dqn_JsmnIterator_FindKey(Dqn_Jsmn *jsmn_state, Dqn_String key, Dqn_JsmnIterator *parent_it);
|
||||
|
||||
#define Dqn_JsmnIterator_ExpectValue(it, expected, err_handle) Dqn_JsmnIterator__ExpectValue(it, expected, err_handle, __FILE__, __LINE__)
|
||||
#define Dqn_JsmnIterator_ExpectKey(it, expected, err_handle) Dqn_JsmnIterator__ExpectKey(it, expected, err_handle, __FILE__, __LINE__)
|
||||
|
||||
// Convert the value part of the key-value JSON pair the iterator is currently
|
||||
// pointing to, to a string/bool/u64. If the iterator's value does not point to
|
||||
// the type requested, a zero initialised value is returned.
|
||||
Dqn_String Dqn_JsmnIterator_String(Dqn_JsmnIterator const *it);
|
||||
Dqn_b32 Dqn_JsmnIterator_Bool (Dqn_JsmnIterator const *it);
|
||||
Dqn_u64 Dqn_JsmnIterator_U64 (Dqn_JsmnIterator const *it);
|
||||
|
||||
#define DQN_JSMN_ERROR_HANDLE_DUMP(handle) \
|
||||
for (Dqn_ListChunk<Dqn_JsmnError> *chunk = handle.list.head; chunk; chunk = chunk->next) \
|
||||
{ \
|
||||
for (auto *error = chunk->data; error != (chunk->data + chunk->count); error++) \
|
||||
{ \
|
||||
DQN_LOG_E("Json parsing error at %s from %s:%d", \
|
||||
error->cpp_func, \
|
||||
DQN_LOG_E("Json parsing error in %s:%d, expected token type: %.*s, token was: %.*s", \
|
||||
Dqn_Str_FileNameFromPath(error->cpp_file), \
|
||||
error->cpp_line); \
|
||||
error->cpp_line, \
|
||||
DQN_STRING_FMT(Dqn_JsmnTokenIsEnumString(error->expected)), \
|
||||
DQN_STRING_FMT(Dqn_Jsmn_TokenString(error->token, error->json))); \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -183,7 +383,58 @@ jsmntok_t *Dqn_JsmnToken_AdvanceItPastArray (jsmntok_t *start_it, Dqn_JsmnError
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
// -----------------------------------------------------------------------------
|
||||
void Dqn_JsmnErrorHandle_AddError(Dqn_JsmnErrorHandle *err_handle, char const *func, char const *file, int line)
|
||||
Dqn_Jsmn Dqn_Jsmn_InitWithJSON(Dqn_String json, Dqn_ArenaAllocator *arena)
|
||||
{
|
||||
Dqn_Jsmn result = {};
|
||||
result.json = json;
|
||||
|
||||
jsmn_init(&result.parser);
|
||||
result.tokens_size = jsmn_parse(&result.parser, result.json.str, result.json.size, nullptr, 0);
|
||||
result.tokens = Dqn_ArenaAllocator_NewArray(arena, jsmntok_t, result.tokens_size, Dqn_ZeroMem::No);
|
||||
|
||||
jsmn_init(&result.parser);
|
||||
result.tokens_size = jsmn_parse(&result.parser, result.json.str, result.json.size, result.tokens, result.tokens_size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_Jsmn Dqn_Jsmn_InitWithJSONFile(Dqn_String file, Dqn_ArenaAllocator *arena)
|
||||
{
|
||||
Dqn_String json = Dqn_File_ArenaReadFileToString(file.str, arena);
|
||||
Dqn_Jsmn result = Dqn_Jsmn_InitWithJSON(json, arena);
|
||||
return result;
|
||||
}
|
||||
|
||||
int Dqn_Jsmn_TokenArraySize(jsmntok_t token)
|
||||
{
|
||||
int result = token.type == JSMN_ARRAY ? token.size : -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_String Dqn_Jsmn_TokenString(jsmntok_t token, Dqn_String json)
|
||||
{
|
||||
Dqn_String result = Dqn_String_Init(json.str + token.start, token.end - token.start);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_Jsmn_TokenBool(jsmntok_t token, Dqn_String json)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
char ch = json.str[token.start];
|
||||
Dqn_b32 result = ch == 't';
|
||||
if (!result) { DQN_ASSERT(ch == 'f'); }
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_u64 Dqn_Jsmn_TokenU64(jsmntok_t token, Dqn_String json)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
Dqn_String string = Dqn_String_Init(json.str + token.start, token.end - token.start);
|
||||
Dqn_u64 result = Dqn_String_ToU64(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Dqn_JsmnErrorHandle__AddError(Dqn_JsmnErrorHandle *err_handle, jsmntok_t token, Dqn_String json, Dqn_JsmnTokenIs expected, char const *file, int line)
|
||||
{
|
||||
if (!err_handle)
|
||||
return;
|
||||
@ -194,120 +445,123 @@ void Dqn_JsmnErrorHandle_AddError(Dqn_JsmnErrorHandle *err_handle, char const *f
|
||||
Dqn_JsmnError *error = Dqn_List_Make(&err_handle->list, 1);
|
||||
if (error)
|
||||
{
|
||||
error->cpp_func = func;
|
||||
error->expected = expected;
|
||||
error->json = json;
|
||||
error->cpp_file = file;
|
||||
error->cpp_line = line;
|
||||
}
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken__ExpectBool(Dqn_String json, jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, int line)
|
||||
Dqn_b32 Dqn_JsmnIterator_Next(Dqn_JsmnIterator *it, Dqn_Jsmn *jsmn_state, Dqn_JsmnIterator *prev_it)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
char ch = json.str[token.start];
|
||||
Dqn_b32 result = token.type == JSMN_PRIMITIVE && (ch == 't' || ch == 'f');
|
||||
if (!result) Dqn_JsmnErrorHandle_AddError(err_handle, __func__, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken__ExpectNumber(Dqn_String json, jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, int line)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
char ch = json.str[token.start];
|
||||
Dqn_b32 result = token.type == JSMN_PRIMITIVE && (ch == '-' || Dqn_Char_IsDigit(ch));
|
||||
if (!result) Dqn_JsmnErrorHandle_AddError(err_handle, __func__, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken__ExpectString(jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, int line)
|
||||
{
|
||||
Dqn_b32 result = token.type == JSMN_STRING;
|
||||
if (!result) Dqn_JsmnErrorHandle_AddError(err_handle, __func__, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken__ExpectArray(jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, int line)
|
||||
{
|
||||
Dqn_b32 result = token.type == JSMN_ARRAY;
|
||||
if (!result) Dqn_JsmnErrorHandle_AddError(err_handle, __func__, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken__ExpectObject(jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, int line)
|
||||
{
|
||||
Dqn_b32 result = token.type == JSMN_OBJECT;
|
||||
if (!result) Dqn_JsmnErrorHandle_AddError(err_handle, __func__, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_String Dqn_JsmnToken_String(Dqn_String json, jsmntok_t token)
|
||||
{
|
||||
Dqn_String result = Dqn_String_Init(json.str + token.start, token.end - token.start);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnToken_Bool(Dqn_String json, jsmntok_t token)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
char ch = json.str[token.start];
|
||||
Dqn_b32 result = ch == 't';
|
||||
if (!result) { DQN_ASSERT(ch == 'f'); }
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_u64 Dqn_JsmnToken_U64(Dqn_String json, jsmntok_t token)
|
||||
{
|
||||
DQN_ASSERT_MSG(token.start < json.size, "%I64d < %I64u", token.start, json.size);
|
||||
Dqn_String string = Dqn_JsmnToken_String(json, token);
|
||||
Dqn_u64 result = Dqn_String_ToU64(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
jsmntok_t *Dqn_JsmnToken_AdvanceItPastObject(jsmntok_t *start_it, Dqn_JsmnErrorHandle *err_handle, Dqn_String json)
|
||||
{
|
||||
jsmntok_t *result = start_it;
|
||||
if (!Dqn_JsmnToken_ExpectObject(*result, err_handle)) return result;
|
||||
jsmntok_t *object = result++;
|
||||
|
||||
for (int index = 0; index < object->size; index++)
|
||||
if (!it->init)
|
||||
{
|
||||
jsmntok_t *key = result++;
|
||||
jsmntok_t *value = result++;
|
||||
Dqn_String key_str = Dqn_JsmnToken_String(json, *key);
|
||||
Dqn_String value_str = Dqn_JsmnToken_String(json, *value); (void)value_str;
|
||||
|
||||
if (value->type == JSMN_OBJECT)
|
||||
{
|
||||
result = Dqn_JsmnToken_AdvanceItPastObject(value, err_handle, json);
|
||||
it->init = true;
|
||||
it->json = jsmn_state->json;
|
||||
jsmn_iterator_init(&it->jsmn_it, jsmn_state->tokens, jsmn_state->tokens_size, prev_it ? jsmn_iterator_position(&prev_it->jsmn_it) : 0);
|
||||
}
|
||||
else if (value->type == JSMN_ARRAY)
|
||||
|
||||
Dqn_b32 result = false;
|
||||
if (!Dqn_String_IsValid(it->json) || it->json.size <= 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = jsmn_iterator_next(&it->jsmn_it, &it->key, &it->value, it->token_index_hint) > 0;
|
||||
if (!result)
|
||||
{
|
||||
result = Dqn_JsmnToken_AdvanceItPastArray(value, err_handle, json);
|
||||
// NOTE: Iterator has finished object/array, previous iterator will
|
||||
// continue off where this iterator left off.
|
||||
if (prev_it)
|
||||
prev_it->token_index_hint = jsmn_iterator_position(&it->jsmn_it);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_String Dqn_JsmnIterator_Key(Dqn_JsmnIterator *it)
|
||||
{
|
||||
Dqn_String result = {};
|
||||
if (it && it->key)
|
||||
result = Dqn_String_Init(it->json.str + it->key->start, it->key->end - it->key->start);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_JsmnIterator Dqn_JsmnIterator_FindKey(Dqn_Jsmn *jsmn_state, Dqn_String key, Dqn_JsmnIterator *parent_it)
|
||||
{
|
||||
Dqn_JsmnIterator result = {};
|
||||
for (Dqn_JsmnIterator it = {}; Dqn_JsmnIterator_Next(&it, jsmn_state, parent_it); )
|
||||
{
|
||||
Dqn_String it_key = Dqn_Jsmn_TokenString(*it.key, jsmn_state->json);
|
||||
if (it_key == key)
|
||||
{
|
||||
result = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
jsmntok_t *Dqn_JsmnToken_AdvanceItPastArray(jsmntok_t *start_it, Dqn_JsmnErrorHandle *err_handle, Dqn_String json)
|
||||
static Dqn_b32 Dqn_JsmnIterator__Expect(Dqn_JsmnIterator *it, Dqn_JsmnTokenIs expected, jsmntok_t token, Dqn_JsmnErrorHandle *err_handle, char const *file, unsigned int line)
|
||||
{
|
||||
jsmntok_t *result = start_it;
|
||||
if (!Dqn_JsmnToken_ExpectArray(*result, err_handle)) return result;
|
||||
jsmntok_t *array = result++;
|
||||
Dqn_b32 result = false;
|
||||
switch (expected)
|
||||
{
|
||||
case Dqn_JsmnTokenIs::Object: result = token.type == JSMN_OBJECT; break;
|
||||
case Dqn_JsmnTokenIs::Array: result = token.type == JSMN_ARRAY; break;
|
||||
case Dqn_JsmnTokenIs::String: result = token.type == JSMN_STRING; break;
|
||||
|
||||
for (int index = 0; index < array->size; index++)
|
||||
case Dqn_JsmnTokenIs::Number:
|
||||
{
|
||||
jsmntok_t *value = result++;
|
||||
Dqn_String value_str = Dqn_JsmnToken_String(json, *value); (void)value_str;
|
||||
if (value->type == JSMN_OBJECT)
|
||||
{
|
||||
Dqn_JsmnToken_AdvanceItPastObject(start_it, err_handle, json);
|
||||
DQN_ASSERT_MSG(token.start < it->json.size, "%I64d < %I64u", token.start, it->json.size);
|
||||
char ch = it->json.str[token.start];
|
||||
result = token.type == JSMN_PRIMITIVE && (ch == '-' || Dqn_Char_IsDigit(ch));
|
||||
}
|
||||
else if (value->type == JSMN_ARRAY)
|
||||
break;
|
||||
|
||||
case Dqn_JsmnTokenIs::Bool:
|
||||
{
|
||||
Dqn_JsmnToken_AdvanceItPastArray(start_it, err_handle, json);
|
||||
DQN_ASSERT_MSG(token.start < it->json.size, "%I64d < %I64u", token.start, it->json.size);
|
||||
char ch = it->json.str[token.start];
|
||||
result = token.type == JSMN_PRIMITIVE && (ch == 't' || ch == 'f');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
Dqn_JsmnErrorHandle__AddError(err_handle, token, it->json, expected, file, line);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnIterator__ExpectValue(Dqn_JsmnIterator *it, Dqn_JsmnTokenIs expected, Dqn_JsmnErrorHandle *err_handle, char const *file, unsigned int line)
|
||||
{
|
||||
Dqn_b32 result = it->value && Dqn_JsmnIterator__Expect(it, expected, *it->value, err_handle, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnIterator__ExpectKey(Dqn_JsmnIterator *it, Dqn_JsmnTokenIs expected, Dqn_JsmnErrorHandle *err_handle, char const *file, unsigned int line)
|
||||
{
|
||||
Dqn_b32 result = it->key && Dqn_JsmnIterator__Expect(it, expected, *it->key, err_handle, file, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_String Dqn_JsmnIterator_String(Dqn_JsmnIterator const *it)
|
||||
{
|
||||
Dqn_String result = {};
|
||||
if (it->value && it->json.str) result = Dqn_String_Init(it->json.str + it->value->start, it->value->end - it->value->start);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_b32 Dqn_JsmnIterator_Bool(Dqn_JsmnIterator const *it)
|
||||
{
|
||||
Dqn_b32 result = it->value && Dqn_Jsmn_TokenBool(*it->value, it->json);
|
||||
return result;
|
||||
}
|
||||
|
||||
Dqn_u64 Dqn_JsmnIterator_U64(Dqn_JsmnIterator const *it)
|
||||
{
|
||||
Dqn_u64 result = it->value && Dqn_Jsmn_TokenU64(*it->value, it->json);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -681,4 +935,236 @@ JSMN_API void jsmn_init(jsmn_parser *parser) {
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Takes an JSMN Array/Object and locates index for last item in collection
|
||||
* @details Iterates over JSMN Array/Object until last item is found
|
||||
*
|
||||
* @param jsmn_tokens JSMN tokens
|
||||
* @param jsmn_len JSMN token count
|
||||
* @param parser_pos Current JSMN token
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* >=0 - JSMN index for last item in Array/Object
|
||||
*/
|
||||
int jsmn_iterator_find_last( jsmntok_t *jsmn_tokens, unsigned int jsmn_len, unsigned int parser_pos ) {
|
||||
int child_count;
|
||||
unsigned int child_index;
|
||||
int parent_end;
|
||||
|
||||
/* No tokens */
|
||||
if (!jsmn_tokens)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* pos outside tokens */
|
||||
if (parser_pos >= jsmn_len)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* Not an Array/Object */
|
||||
if (jsmn_tokens[parser_pos].type != JSMN_ARRAY &&
|
||||
jsmn_tokens[parser_pos].type != JSMN_OBJECT)
|
||||
return JSMNITER_ERR_TYPE;
|
||||
|
||||
/* End position for Array/Object */
|
||||
parent_end = jsmn_tokens[parser_pos].end;
|
||||
|
||||
/* First child item */
|
||||
child_index = parser_pos + 1;
|
||||
|
||||
/* Count number of children we need to iterate */
|
||||
child_count = jsmn_tokens[parser_pos].size * (jsmn_tokens[parser_pos].type == JSMN_OBJECT ? 2 : 1);
|
||||
|
||||
/* Loop until end of current Array/Object */
|
||||
while(child_index < jsmn_len && jsmn_tokens[child_index].start <= parent_end && child_count >= 0) {
|
||||
/* Add item count in sub Arrays/Objects that we need to skip */
|
||||
if (jsmn_tokens[child_index].type == JSMN_ARRAY)
|
||||
child_count += jsmn_tokens[child_index].size;
|
||||
else if (jsmn_tokens[child_index].type == JSMN_OBJECT)
|
||||
child_count += jsmn_tokens[child_index].size * 2;
|
||||
|
||||
child_count--;
|
||||
child_index++;
|
||||
}
|
||||
|
||||
/* Validate that we have visited correct number of children */
|
||||
if (child_count != 0)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
|
||||
/* Points to last index inside Array/Object */
|
||||
return (int)child_index - 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize iterator
|
||||
* @details Set initial value for iterator struct
|
||||
*
|
||||
* @param iterator Iterator struct
|
||||
* @param jsmn_tokens JSMN tokens
|
||||
* @param jsmn_len JSMN token count
|
||||
* @param parser_pos Current JSMN token
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* >=0 - Ok
|
||||
*/
|
||||
int jsmn_iterator_init(jsmn_iterator_t *iterator, jsmntok_t *jsmn_tokens, unsigned int jsmn_len, unsigned int parser_pos) {
|
||||
/* No iterator */
|
||||
if (!iterator)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* No tokens */
|
||||
if (!jsmn_tokens)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* pos outside tokens */
|
||||
if (parser_pos >= jsmn_len)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* Not an Array/Object */
|
||||
if (jsmn_tokens[parser_pos].type != JSMN_ARRAY &&
|
||||
jsmn_tokens[parser_pos].type != JSMN_OBJECT)
|
||||
return JSMNITER_ERR_TYPE;
|
||||
|
||||
/* Save jsmn pointer */
|
||||
iterator->jsmn_tokens = jsmn_tokens;
|
||||
iterator->jsmn_len = jsmn_len;
|
||||
|
||||
iterator->parent_pos = parser_pos;
|
||||
iterator->parser_pos = parser_pos;
|
||||
|
||||
iterator->index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get next item in JSMN Array/Object
|
||||
* @details Gets JSMN position for next identifier and value in Array/Object
|
||||
*
|
||||
* @param iterator Iterator struct
|
||||
* @param jsmn_identifier Return pointer for identifier, NULL for Array
|
||||
* @param jsmn_value Return pointer for value
|
||||
* @param next_value_index Possible to indicate where next value begins, allows determine end of sub
|
||||
* Array/Object withouth manually searching for it
|
||||
*
|
||||
* @return < 0 - Error has occured, corresponds to one of JSMNITER_ERR_*
|
||||
* 0 - No more values
|
||||
* > 0 - Value (and identifier) has been returned
|
||||
*/
|
||||
int jsmn_iterator_next(jsmn_iterator_t *iterator, jsmntok_t **jsmn_identifier, jsmntok_t **jsmn_value,
|
||||
unsigned int next_value_index) {
|
||||
unsigned int is_object;
|
||||
jsmntok_t *parent_item;
|
||||
jsmntok_t *current_item;
|
||||
jsmntok_t *jsmn_tokens;
|
||||
unsigned int jsmn_len;
|
||||
|
||||
/* No iterator */
|
||||
if (!iterator)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* No value return pointer */
|
||||
if (!jsmn_value)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
/* Parser position is outside JSMN tokens array */
|
||||
if (iterator->parser_pos > iterator->jsmn_len)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
|
||||
jsmn_tokens = iterator->jsmn_tokens;
|
||||
jsmn_len = iterator->jsmn_len;
|
||||
parent_item = &jsmn_tokens[iterator->parent_pos];
|
||||
|
||||
/* parser_position is at the end of JSMN token array or points outside parent Array/Object */
|
||||
if (jsmn_iterator_position(iterator) == iterator->jsmn_len || jsmn_tokens[jsmn_iterator_position(iterator)].start > parent_item->end) {
|
||||
if (iterator->index != (unsigned int)parent_item->size)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
current_item = &jsmn_tokens[jsmn_iterator_position(iterator)];
|
||||
|
||||
/* Are we in an Object */
|
||||
is_object = (parent_item->type == JSMN_OBJECT ? 1 : 0);
|
||||
|
||||
/* Is it item we only need jump one to the next index */
|
||||
if (jsmn_iterator_position(iterator) == iterator->parent_pos) {
|
||||
next_value_index = jsmn_iterator_position(iterator) + 1;
|
||||
}
|
||||
/* For items that isn't Array/Object we only need to take the next value */
|
||||
else if (current_item->type != JSMN_ARRAY &&
|
||||
current_item->type != JSMN_OBJECT) {
|
||||
next_value_index = jsmn_iterator_position(iterator) + 1;
|
||||
}
|
||||
/* Check if next_value_index is correct, else we need to calculate it ourself */
|
||||
else if (next_value_index == 0 ||
|
||||
next_value_index > jsmn_len ||
|
||||
next_value_index <= jsmn_iterator_position(iterator) ||
|
||||
current_item->end < jsmn_tokens[next_value_index - 1].end ||
|
||||
(next_value_index < jsmn_len && current_item->end >= jsmn_tokens[next_value_index].start)) {
|
||||
/* Find index for last item in the Array/Object manually */
|
||||
int return_pos = jsmn_iterator_find_last(jsmn_tokens, jsmn_len, jsmn_iterator_position(iterator));
|
||||
|
||||
/* Error, bail out */
|
||||
if (return_pos < 0)
|
||||
return return_pos;
|
||||
|
||||
/* Update position to the next item token */
|
||||
next_value_index = (unsigned int)(return_pos) + 1;
|
||||
|
||||
/* Outside valid array */
|
||||
if (next_value_index > jsmn_len)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
/* Earlier than current value (not valid jsmn tree) */
|
||||
if (next_value_index <= jsmn_iterator_position(iterator))
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
/* Previus item is NOT inside current Array/Object */
|
||||
if (jsmn_tokens[next_value_index - 1].end > current_item->end)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
/* Not last item and next item is NOT outside Array/Object */
|
||||
if (next_value_index < jsmn_len && current_item->end > jsmn_tokens[next_value_index].start)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
}
|
||||
|
||||
/* Parser position is outside JSMN tokens array */
|
||||
if (next_value_index > iterator->jsmn_len)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
|
||||
/* parser_position is at the end of JSMN token array or points outside parent Array/Object */
|
||||
if (next_value_index == (unsigned int)iterator->jsmn_len || jsmn_tokens[next_value_index].start > parent_item->end) {
|
||||
if (iterator->index != (unsigned int)parent_item->size)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
/* Update parser position before exit */
|
||||
iterator->parser_pos = next_value_index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get current value/identifier */
|
||||
current_item = &jsmn_tokens[next_value_index];
|
||||
|
||||
/* We have identifier, read it */
|
||||
if (is_object) {
|
||||
/* Must be string */
|
||||
if (current_item->type != JSMN_STRING)
|
||||
return JSMNITER_ERR_NOIDENT;
|
||||
/* Ensure that we have next token */
|
||||
if (next_value_index + 1 >= jsmn_len)
|
||||
return JSMNITER_ERR_BROKEN;
|
||||
/* Missing identifier pointer */
|
||||
if (!jsmn_identifier)
|
||||
return JSMNITER_ERR_PARAMETER;
|
||||
|
||||
/* Set identifier and update current pointer to value item */
|
||||
*jsmn_identifier = current_item;
|
||||
next_value_index++;
|
||||
current_item = &jsmn_tokens[next_value_index];
|
||||
}
|
||||
/* Clear identifier if is set */
|
||||
else if (jsmn_identifier) {
|
||||
*jsmn_identifier = NULL;
|
||||
}
|
||||
|
||||
/* Set value */
|
||||
*jsmn_value = current_item;
|
||||
|
||||
/* Update parser position */
|
||||
iterator->parser_pos = next_value_index;
|
||||
|
||||
/* Increase the index and return it as the positive value */
|
||||
iterator->index++;
|
||||
return (int)iterator->index;
|
||||
}
|
||||
#endif // DQN_JSMN_IMPLEMENTATION
|
||||
|
353
Dqn_Tests.cpp
353
Dqn_Tests.cpp
@ -18,9 +18,14 @@
|
||||
#define DQN_WITH_MAP // Dqn_Map
|
||||
#define DQN_WITH_MATH // Dqn_V2/3/4/Mat4 and friends ...
|
||||
#define DQN_WITH_THREAD_CONTEXT // Dqn_ThreadContext and friends ...
|
||||
#include "Dqn.h"
|
||||
#include "dqn.h"
|
||||
|
||||
#define DQN_KECCAK_IMPLEMENTATION
|
||||
#include "dqn_keccak.h"
|
||||
#endif
|
||||
|
||||
#include "dqn_tests_helpers.cpp"
|
||||
|
||||
struct Dqn_TestState
|
||||
{
|
||||
int indent_level;
|
||||
@ -59,7 +64,7 @@ static int g_dqn_test_total_tests;
|
||||
#define DQN_TEST_ANSI_COLOR_RESET "\x1b[0m"
|
||||
#endif
|
||||
|
||||
#define DQN_TEST_START_SCOPE(testing_state, test_name) \
|
||||
#define DQN_TEST_START_SCOPE(testing_state, test_name, ...) \
|
||||
DQN_DEFER \
|
||||
{ \
|
||||
if (testing_state.test.fail_expr.size == 0) testing_state.num_tests_ok_in_group++; \
|
||||
@ -67,7 +72,7 @@ static int g_dqn_test_total_tests;
|
||||
Dqn_ArenaAllocator_ResetUsage(&testing_state.arena, Dqn_ZeroMem::No); \
|
||||
testing_state.test = {}; \
|
||||
}; \
|
||||
testing_state.test.name = DQN_STRING(test_name); \
|
||||
testing_state.test.name = Dqn_String_Fmt(&testing_state.arena, test_name, ##__VA_ARGS__); \
|
||||
testing_state.test.scope_started = true; \
|
||||
testing_state.num_tests_in_group++
|
||||
|
||||
@ -1394,131 +1399,6 @@ void Dqn_Test_String()
|
||||
}
|
||||
}
|
||||
|
||||
void Dqn_Test_StringBuilder()
|
||||
{
|
||||
Dqn_TestingState testing_state = {};
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_StringBuilder");
|
||||
Dqn_ArenaAllocator arena = {};
|
||||
// NOTE: Dqn_StringBuilder_Append
|
||||
{
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append variable size strings and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "Abc", 1);
|
||||
Dqn_StringBuilder_Append(&builder, "cd");
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "Acd";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append empty string and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append empty string onto string and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "Acd");
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "Acd";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append nullptr and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, nullptr, 5);
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append and require new linked buffer and build using heap arena");
|
||||
Dqn_StringBuilder<2> builder = {};
|
||||
Dqn_StringBuilder_InitWithArena(&builder, &arena);
|
||||
Dqn_StringBuilder_Append(&builder, "A");
|
||||
Dqn_StringBuilder_Append(&builder, "z"); // Should force a new memory block
|
||||
Dqn_StringBuilder_Append(&builder, "tec");
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "Aztec";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Dqn_StringBuilder_AppendChar
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append char and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_AppendChar(&builder, 'a');
|
||||
Dqn_StringBuilder_AppendChar(&builder, 'b');
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "ab";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
// NOTE: Dqn_StringBuilder_AppendFmt
|
||||
{
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append format string and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_AppendFmt(&builder, "Number: %d, String: %s, ", 4, "Hello Sailor");
|
||||
Dqn_StringBuilder_AppendFmt(&builder, "Extra Stuff");
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "Number: 4, String: Hello Sailor, Extra Stuff";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "Append nullptr format string and build using heap arena");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_AppendFmt(&builder, nullptr);
|
||||
Dqn_isize size = 0;
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &arena, &size);
|
||||
DQN_DEFER { Dqn_ArenaAllocator_Free(&arena); };
|
||||
|
||||
char const EXPECT_STR[] = "";
|
||||
DQN_TEST_EXPECT_MSG(testing_state, size == Dqn_CharCountI(EXPECT_STR), "size: %zd", size);
|
||||
DQN_TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, size) == 0, "result: %s", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dqn_Test_TicketMutex()
|
||||
{
|
||||
Dqn_TestingState testing_state = {};
|
||||
@ -1609,6 +1489,221 @@ void Dqn_Test_Win()
|
||||
#endif // DQN_OS_WIN32
|
||||
}
|
||||
|
||||
#define DQN_TESTS_HASH_X_MACRO \
|
||||
DQN_TESTS_HASH_X_ENTRY(SHA3_224, "SHA3-224") \
|
||||
DQN_TESTS_HASH_X_ENTRY(SHA3_256, "SHA3-256") \
|
||||
DQN_TESTS_HASH_X_ENTRY(SHA3_384, "SHA3-384") \
|
||||
DQN_TESTS_HASH_X_ENTRY(SHA3_512, "SHA3-512") \
|
||||
DQN_TESTS_HASH_X_ENTRY(Keccak_224, "Keccak-224") \
|
||||
DQN_TESTS_HASH_X_ENTRY(Keccak_256, "Keccak-256") \
|
||||
DQN_TESTS_HASH_X_ENTRY(Keccak_384, "Keccak-384") \
|
||||
DQN_TESTS_HASH_X_ENTRY(Keccak_512, "Keccak-512") \
|
||||
DQN_TESTS_HASH_X_ENTRY(Count, "Keccak-512")
|
||||
|
||||
enum Dqn_Tests__HashType
|
||||
{
|
||||
#define DQN_TESTS_HASH_X_ENTRY(enum_val, string) Hash_##enum_val,
|
||||
DQN_TESTS_HASH_X_MACRO
|
||||
#undef DQN_TESTS_HASH_X_ENTRY
|
||||
};
|
||||
|
||||
Dqn_String const DQN_TESTS__HASH_STRING[] =
|
||||
{
|
||||
#define DQN_TESTS_HASH_X_ENTRY(enum_val, string) DQN_STRING(string),
|
||||
DQN_TESTS_HASH_X_MACRO
|
||||
#undef DQN_TESTS_HASH_X_ENTRY
|
||||
};
|
||||
|
||||
|
||||
void Dqn_Test__KeccakDispatch(Dqn_TestingState *testing_state, int hash_type, Dqn_String input)
|
||||
{
|
||||
#if defined(DQN_KECCAK_H)
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch();
|
||||
Dqn_String input_hex = Dqn_Hex_BytesToHexStringArena(input.str, input.size, scratch.arena);
|
||||
|
||||
switch(hash_type)
|
||||
{
|
||||
case Hash_SHA3_224:
|
||||
{
|
||||
Dqn_KeccakBytes28 hash = Dqn_Keccak_SHA3_224_StringToBytes28(input);
|
||||
Dqn_KeccakBytes28 expect;
|
||||
FIPS202_SHA3_224(DQN_CAST(u8 *)input.str, input.size, (u8 *)expect.data);
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes28Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING56_FMT(Dqn_Keccak_Bytes28ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING56_FMT(Dqn_Keccak_Bytes28ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_SHA3_256:
|
||||
{
|
||||
Dqn_KeccakBytes32 hash = Dqn_Keccak_SHA3_256_StringToBytes32(input);
|
||||
Dqn_KeccakBytes32 expect;
|
||||
FIPS202_SHA3_256(DQN_CAST(u8 *)input.str, input.size, (u8 *)expect.data);
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes32Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING64_FMT(Dqn_Keccak_Bytes32ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING64_FMT(Dqn_Keccak_Bytes32ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_SHA3_384:
|
||||
{
|
||||
Dqn_KeccakBytes48 hash = Dqn_Keccak_SHA3_384_StringToBytes48(input);
|
||||
Dqn_KeccakBytes48 expect;
|
||||
FIPS202_SHA3_384(DQN_CAST(u8 *)input.str, input.size, (u8 *)expect.data);
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes48Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING96_FMT(Dqn_Keccak_Bytes48ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING96_FMT(Dqn_Keccak_Bytes48ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_SHA3_512:
|
||||
{
|
||||
Dqn_KeccakBytes64 hash = Dqn_Keccak_SHA3_512_StringToBytes64(input);
|
||||
Dqn_KeccakBytes64 expect;
|
||||
FIPS202_SHA3_512(DQN_CAST(u8 *)input.str, input.size, (u8 *)expect.data);
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes64Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING128_FMT(Dqn_Keccak_Bytes64ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING128_FMT(Dqn_Keccak_Bytes64ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_Keccak_224:
|
||||
{
|
||||
Dqn_KeccakBytes28 hash = Dqn_Keccak_224_StringToBytes28(input);
|
||||
Dqn_KeccakBytes28 expect;
|
||||
Keccak(1152, 448, DQN_CAST(u8 *)input.str, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes28Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING56_FMT(Dqn_Keccak_Bytes28ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING56_FMT(Dqn_Keccak_Bytes28ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_Keccak_256:
|
||||
{
|
||||
Dqn_KeccakBytes32 hash = Dqn_Keccak_256_StringToBytes32(input);
|
||||
Dqn_KeccakBytes32 expect;
|
||||
Keccak(1088, 512, DQN_CAST(u8 *)input.str, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes32Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING64_FMT(Dqn_Keccak_Bytes32ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING64_FMT(Dqn_Keccak_Bytes32ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_Keccak_384:
|
||||
{
|
||||
Dqn_KeccakBytes48 hash = Dqn_Keccak_384_StringToBytes48(input);
|
||||
Dqn_KeccakBytes48 expect;
|
||||
Keccak(832, 768, DQN_CAST(u8 *)input.str, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes48Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING96_FMT(Dqn_Keccak_Bytes48ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING96_FMT(Dqn_Keccak_Bytes48ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
case Hash_Keccak_512:
|
||||
{
|
||||
Dqn_KeccakBytes64 hash = Dqn_Keccak_512_StringToBytes64(input);
|
||||
Dqn_KeccakBytes64 expect;
|
||||
Keccak(576, 1024, DQN_CAST(u8 *)input.str, input.size, 0x01, (u8 *)expect.data, sizeof(expect));
|
||||
DQN_TEST_EXPECT_MSG((*testing_state),
|
||||
Dqn_Keccak_Bytes64Equals(&hash, &expect),
|
||||
"\ninput: %.*s"
|
||||
"\nhash: %.*s"
|
||||
"\nexpect: %.*s"
|
||||
,
|
||||
DQN_STRING_FMT(input_hex),
|
||||
DQN_KECCAK_STRING128_FMT(Dqn_Keccak_Bytes64ToHex(&hash).str),
|
||||
DQN_KECCAK_STRING128_FMT(Dqn_Keccak_Bytes64ToHex(&expect).str));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
#endif // DQN_KECCAK_H
|
||||
}
|
||||
|
||||
void Dqn_Test_Keccak()
|
||||
{
|
||||
#if defined(DQN_KECCAK_H)
|
||||
Dqn_TestingState testing_state = {};
|
||||
|
||||
Dqn_String const INPUTS[] = {
|
||||
DQN_STRING("abc"),
|
||||
DQN_STRING(""),
|
||||
DQN_STRING("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
|
||||
DQN_STRING("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmno"
|
||||
"pqrstnopqrstu"),
|
||||
};
|
||||
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Keccak");
|
||||
for (int hash_type = 0; hash_type < Hash_Count; hash_type++)
|
||||
{
|
||||
pcg32_random_t rng = {};
|
||||
pcg32_srandom_r(&rng, 0xd48e'be21'2af8'733d, 0x3f89'3bd2'd6b0'4eef);
|
||||
|
||||
for (Dqn_String input : INPUTS)
|
||||
{
|
||||
DQN_TEST_START_SCOPE(testing_state, "%.*s - Input: %.*s", DQN_STRING_FMT(DQN_TESTS__HASH_STRING[hash_type]), DQN_MIN(input.size, 54), input.str);
|
||||
Dqn_Test__KeccakDispatch(&testing_state, hash_type, input);
|
||||
}
|
||||
|
||||
DQN_TEST_START_SCOPE(testing_state, "%.*s - Deterministic random inputs", DQN_STRING_FMT(DQN_TESTS__HASH_STRING[hash_type]));
|
||||
for (int index = 0; index < 128; index++)
|
||||
{
|
||||
char src[4096] = {};
|
||||
Dqn_u32 src_size = pcg32_boundedrand_r(&rng, sizeof(src));
|
||||
|
||||
for (int src_index = 0; src_index < src_size; src_index++)
|
||||
src[src_index] = pcg32_boundedrand_r(&rng, 255);
|
||||
|
||||
Dqn_String input = Dqn_String_Init(src, src_size);
|
||||
Dqn_Test__KeccakDispatch(&testing_state, hash_type, input);
|
||||
}
|
||||
}
|
||||
#endif // DQN_KECCAK_H
|
||||
}
|
||||
|
||||
void Dqn_Test_RunSuite()
|
||||
{
|
||||
Dqn_Test_Array();
|
||||
@ -1623,9 +1718,9 @@ void Dqn_Test_RunSuite()
|
||||
Dqn_Test_Rect();
|
||||
Dqn_Test_PerfCounter();
|
||||
Dqn_Test_OS();
|
||||
Dqn_Test_Keccak();
|
||||
Dqn_Test_Str();
|
||||
Dqn_Test_String();
|
||||
Dqn_Test_StringBuilder();
|
||||
Dqn_Test_TicketMutex();
|
||||
Dqn_Test_Win();
|
||||
|
||||
|
1039
Dqn_U128.h
1039
Dqn_U128.h
File diff suppressed because it is too large
Load Diff
185
dqn_cpp_file.h
Normal file
185
dqn_cpp_file.h
Normal file
@ -0,0 +1,185 @@
|
||||
#if !defined(DQN_CPP_FILE_H)
|
||||
#define DQN_CPP_FILE_H
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Overview
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utility functions for creating C++ files at run-time.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Macros
|
||||
// -----------------------------------------------------------------------------
|
||||
// #define DQN_CPP_FILE_IMPLEMENTATION
|
||||
// Define this in one and only one C++ file to enable the implementation
|
||||
// code of the header file.
|
||||
//
|
||||
// #define DQN_CPPF_ASSERT(expr)
|
||||
// Define this macro to override the default assert used.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Dqn_CppFile: Helper functions to generate formatted CPP files
|
||||
// -----------------------------------------------------------------------------
|
||||
#if !defined(DQN_CPPF_ASSERT)
|
||||
#define DQN_CPPF_ASSERT(expr) do { if (!(expr)) { *((volatile int *)0) = 0; } } while (0)
|
||||
#endif
|
||||
|
||||
struct Dqn_CppFile
|
||||
{
|
||||
FILE *file; // The file to output to.
|
||||
int indent; // The current indent level
|
||||
int space_per_indent; // The number of spaces applied per indent. If zero- the functions give a default value.
|
||||
bool append_extra_new_line; // If true, when code blocks are terminated, an additional new line will be appended for whitespacing.
|
||||
};
|
||||
|
||||
// return: The number of spaces per indent at this point of invocation. If
|
||||
// spaces-per-indent in the CppFile is set to 0 the indent defaults to 4 spaces.
|
||||
int Dqn_CppFile_SpacePerIndent(Dqn_CppFile const *cpp);
|
||||
|
||||
// Create a line in the C++ file. This is a piece-meal API where you can
|
||||
// flexibly construct a line by calling {LineBegin, LineAdd, LineEnd}. Calling
|
||||
// LineEnd terminates the line with a trailing new-line. Calling LineAdd is
|
||||
// optional if the line can be constructed with just a LineAdd and LineEnd.
|
||||
void Dqn_CppFile_LineBeginV (Dqn_CppFile *cpp, char const *fmt, va_list args);
|
||||
void Dqn_CppFile_LineBegin (Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
void Dqn_CppFile_LineAdd (Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
void Dqn_CppFile_LineEnd (Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
|
||||
// Create a line in the C++ file and terminate it with a new-line.
|
||||
void Dqn_CppFile_LineV (Dqn_CppFile *cpp, char const *fmt, va_list args);
|
||||
void Dqn_CppFile_Line (Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
|
||||
void Dqn_CppFile_NewLine (Dqn_CppFile *cpp);
|
||||
void Dqn_CppFile_Indent (Dqn_CppFile *cpp);
|
||||
void Dqn_CppFile_Unindent (Dqn_CppFile *cpp);
|
||||
|
||||
// Begin a C++ code block which is any block that utilises a opening and
|
||||
// closing brace.
|
||||
// fmt: (Optional) The format string to print at the beginning of the block.
|
||||
// When the fmt string is given, it will place a new-line at the end of the fmt
|
||||
// string. When fmt is nullptr, no new line will be appended.
|
||||
/*
|
||||
Dqn_CppFile_Line(&cpp, "void MyFunction(int x, int y)");
|
||||
Dqn_CppFile_BeginBlock(&cpp, nullptr);
|
||||
Dqn_CppFile_Line(&cpp, "int result = x + y;");
|
||||
Dqn_CppFile_Line(&cpp, "return result;");
|
||||
Dqn_CppFile_EndFuncBlock(&cpp);
|
||||
|
||||
// Generates
|
||||
//
|
||||
// void MyFunction(int x, int y)
|
||||
// {
|
||||
// int result = x + y;
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
*/
|
||||
void Dqn_CppFile_BeginBlock (Dqn_CppFile *cpp, char const *fmt, ...);
|
||||
void Dqn_CppFile_EndBlock (Dqn_CppFile *cpp, bool trailing_semicolon, bool new_line_on_next_block);
|
||||
|
||||
#define Dqn_CppFile_EndEnumBlock(cpp) Dqn_CppFile_EndBlock(cpp, true /*trailing_semicolon*/, true /*new_line_on_next_block*/)
|
||||
#define Dqn_CppFile_EndForBlock(cpp) Dqn_CppFile_EndBlock(cpp, false /*trailing_semicolon*/, false /*new_line_on_next_block*/)
|
||||
#define Dqn_CppFile_EndIfBlock(cpp) Dqn_CppFile_EndBlock(cpp, false /*trailing_semicolon*/, false /*new_line_on_next_block*/)
|
||||
#define Dqn_CppFile_EndFuncBlock(cpp) Dqn_CppFile_EndBlock(cpp, false /*trailing_semicolon*/, true /*new_line_on_next_block*/)
|
||||
#define Dqn_CppFile_EndStructBlock(cpp) Dqn_CppFile_EndBlock(cpp, true /*trailing_semicolon*/, true /*new_line_on_next_block*/)
|
||||
#endif // DQN_CPP_FILE_H
|
||||
|
||||
#if defined(DQN_CPP_FILE_IMPLEMENTATION)
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: Dqn_CppFile Implementation
|
||||
// -----------------------------------------------------------------------------
|
||||
int Dqn_CppFile_SpacePerIndent(Dqn_CppFile const *cpp)
|
||||
{
|
||||
int result = cpp->space_per_indent == 0 ? 4 : cpp->space_per_indent;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Dqn_CppFile_LineBeginV(Dqn_CppFile *cpp, char const *fmt, va_list args)
|
||||
{
|
||||
int spaces = cpp->indent * Dqn_CppFile_SpacePerIndent(cpp);
|
||||
fprintf(cpp->file, "%*s", spaces, "");
|
||||
vfprintf(cpp->file, fmt, args);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_LineBegin(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_CppFile_LineBeginV(cpp, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_LineAdd(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(cpp->file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_LineEnd(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
{
|
||||
if (fmt)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(cpp->file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
fputc('\n', cpp->file);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_LineV(Dqn_CppFile *cpp, char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_CppFile_LineBeginV(cpp, fmt, args);
|
||||
Dqn_CppFile_LineEnd(cpp, nullptr);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_Line(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_CppFile_LineBeginV(cpp, fmt, args);
|
||||
Dqn_CppFile_LineEnd(cpp, nullptr);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_NewLine(Dqn_CppFile *cpp)
|
||||
{
|
||||
fputc('\n', cpp->file);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_Indent(Dqn_CppFile *cpp)
|
||||
{
|
||||
cpp->indent++;
|
||||
}
|
||||
|
||||
void Dqn_CppFile_Unindent(Dqn_CppFile *cpp)
|
||||
{
|
||||
cpp->indent--;
|
||||
DQN_CPPF_ASSERT(cpp->indent >= 0);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_BeginBlock(Dqn_CppFile *cpp, char const *fmt, ...)
|
||||
{
|
||||
if (fmt)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_CppFile_LineV(cpp, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
Dqn_CppFile_Line(cpp, "{");
|
||||
Dqn_CppFile_Indent(cpp);
|
||||
}
|
||||
|
||||
void Dqn_CppFile_EndBlock(Dqn_CppFile *cpp, bool trailing_semicolon, bool new_line_on_next_block)
|
||||
{
|
||||
Dqn_CppFile_Unindent(cpp);
|
||||
Dqn_CppFile_Line(cpp, trailing_semicolon ? "};" : "}");
|
||||
if (new_line_on_next_block) fputc('\n', cpp->file);
|
||||
}
|
||||
#endif // DQN_CPP_FILE_IMPLEMENTATION
|
965
dqn_keccak.h
Normal file
965
dqn_keccak.h
Normal file
@ -0,0 +1,965 @@
|
||||
#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.
|
||||
//
|
||||
// #define DQN_KECCAK_MEMCOPY
|
||||
// Define this macro to override the memcpy implementation and avoid pulling
|
||||
// in string.h.
|
||||
//
|
||||
// #define DQN_KECCAK_MEMCMP
|
||||
// Define this macro to override the memcmp implementation and avoid pulling
|
||||
// in string.h.
|
||||
//
|
||||
// #define DQN_NO_MALLOC_FUNCTIONS
|
||||
// Define this macro to disable the non-essential helper functions that use
|
||||
// malloc.
|
||||
//
|
||||
// #define DQN_KECCAK_MALLOC
|
||||
// Define this macro to override the malloc implementation. This library
|
||||
// provides helper functions that use malloc if DQN_NO_MALLOC_FUNCTIONS is
|
||||
// not defined.
|
||||
//
|
||||
// #define DQN_KECCAK_ASSERT
|
||||
// Define this macro to override the assert implementation.
|
||||
|
||||
#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_NO_MALLOC_FUNCTIONS)
|
||||
#if !defined(DQN_KECCAK_MALLOC)
|
||||
#include <stdlib.h>
|
||||
#define DQN_KECCAK_MALLOC(size) malloc(size)
|
||||
#endif
|
||||
#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 at least
|
||||
// 32 bytes for SHA-256 and so forth.
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 28 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 32 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 48 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 64 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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.
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 28 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 32 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 48 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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);
|
||||
|
||||
// dest_size: The passed in destination buffer must be >= 64 (bytes), otherwise
|
||||
// the function asserts or does no-op in release.
|
||||
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.
|
||||
// at least src_size * 2). This function does *not* null-terminate the buffer.
|
||||
// The returned result does *not* include a leading 0x prefix.
|
||||
void Dqn_Keccak_BytesToHex(void const *src, Dqn_Keccak_u64 src_size, char *dest, Dqn_Keccak_u64 dest_size);
|
||||
|
||||
#if defined(DQN_NO_MALLOC_FUNCTIONS)
|
||||
// Convert the src bytes into a null-terminated c-string using malloc. Calls
|
||||
// into Dqn_Keccak_BytesToHex under the hood.
|
||||
// src: If src is nullptr, the function returns an empty null-terminated
|
||||
// string, otherwise, the bytes will be converted and returned as hex.
|
||||
// return: A null-terminated c-string. This string must be freed by the user
|
||||
// using the CRT free(..). If malloc fails the returned string is nullptr.
|
||||
char *Dqn_Keccak_BytesToHexCString(void const *src, Dqn_Keccak_u64 src_size);
|
||||
#endif // DQN_NO_MALLOC_FUNCTIONS
|
||||
|
||||
// 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';
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DQN_NO_MALLOC_FUNCTIONS)
|
||||
char *Dqn_Keccak_BytesToHexCString(void const *src, Dqn_Keccak_u64 src_size)
|
||||
{
|
||||
int result_size = (src_size * 2);
|
||||
char *result = DQN_KECCAK_MALLOC(result_size + 1 /*null-terminator*/);
|
||||
if (result)
|
||||
{
|
||||
Dqn_Keccak_BytesToHex(src, src_size, result, result_size);
|
||||
result[result_size] = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // DQN_NO_MALLOC_FUNCTIONS
|
||||
|
||||
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_Hex_HexToBytes(hex.str, hex.size, result.data, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
#endif // DQN_H
|
||||
|
||||
#endif // DQN_KECCAK_IMPLEMENTATION
|
101
dqn_tests_helpers.cpp
Normal file
101
dqn_tests_helpers.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#if defined(DQN_KECCAK_H)
|
||||
// -----------------------------------------------------------------------------
|
||||
// Dqn_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)
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned long long int u64;
|
||||
typedef unsigned int ui;
|
||||
|
||||
void Keccak(ui r, ui c, const u8 *in, u64 inLen, u8 sfx, u8 *out, u64 outLen);
|
||||
void FIPS202_SHAKE128(const u8 *in, u64 inLen, u8 *out, u64 outLen) { Keccak(1344, 256, in, inLen, 0x1F, out, outLen); }
|
||||
void FIPS202_SHAKE256(const u8 *in, u64 inLen, u8 *out, u64 outLen) { Keccak(1088, 512, in, inLen, 0x1F, out, outLen); }
|
||||
void FIPS202_SHA3_224(const u8 *in, u64 inLen, u8 *out) { Keccak(1152, 448, in, inLen, 0x06, out, 28); }
|
||||
void FIPS202_SHA3_256(const u8 *in, u64 inLen, u8 *out) { Keccak(1088, 512, in, inLen, 0x06, out, 32); }
|
||||
void FIPS202_SHA3_384(const u8 *in, u64 inLen, u8 *out) { Keccak(832, 768, in, inLen, 0x06, out, 48); }
|
||||
void FIPS202_SHA3_512(const u8 *in, u64 inLen, u8 *out) { Keccak(576, 1024, in, inLen, 0x06, out, 64); }
|
||||
|
||||
int LFSR86540(u8 *R) { (*R)=((*R)<<1)^(((*R)&0x80)?0x71:0); return ((*R)&2)>>1; }
|
||||
#define ROL(a,o) ((((u64)a)<<o)^(((u64)a)>>(64-o)))
|
||||
static u64 load64(const u8 *x) { ui i; u64 u=0; FOR(i,8) { u<<=8; u|=x[7-i]; } return u; }
|
||||
static void store64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]=u; u>>=8; } }
|
||||
static void xor64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]^=u; u>>=8; } }
|
||||
#define rL(x,y) load64((u8*)s+8*(x+5*y))
|
||||
#define wL(x,y,l) store64((u8*)s+8*(x+5*y),l)
|
||||
#define XL(x,y,l) xor64((u8*)s+8*(x+5*y),l)
|
||||
void KeccakF1600(void *s)
|
||||
{
|
||||
ui r,x,y,i,j,Y; u8 R=0x01; u64 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 (LFSR86540(&R)) XL(0,0,(u64)1<<((1<<j)-1));
|
||||
}
|
||||
}
|
||||
void Keccak(ui r, ui c, const u8 *in, u64 inLen, u8 sfx, u8 *out, u64 outLen)
|
||||
{
|
||||
/*initialize*/ u8 s[200]; ui R=r/8; ui 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) { KeccakF1600(s); b=0; } }
|
||||
/*pad*/ s[b]^=sfx; if((sfx&0x80)&&(b==(R-1))) KeccakF1600(s); s[R-1]^=0x80; KeccakF1600(s);
|
||||
/*squeeze*/ while(outLen>0) { b=(outLen<R)?outLen:R; FOR(i,b) out[i]=s[i]; out+=b; outLen-=b; if(outLen>0) KeccakF1600(s); }
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PCG32 Random Number Generator
|
||||
// -----------------------------------------------------------------------------
|
||||
// NOTE: https://github.com/imneme/pcg-c-basic
|
||||
|
||||
struct pcg_state_setseq_64
|
||||
{ // Internals are *Private*.
|
||||
Dqn_u64 state; // RNG state. All values are possible.
|
||||
Dqn_u64 inc; // Controls which RNG sequence (stream) is
|
||||
// selected. Must *always* be odd.
|
||||
};
|
||||
typedef struct pcg_state_setseq_64 pcg32_random_t;
|
||||
|
||||
// pcg32_random_r(rng)
|
||||
// Generate a uniformly distributed 32-bit random number
|
||||
|
||||
Dqn_u32 pcg32_random_r(pcg32_random_t* rng)
|
||||
{
|
||||
Dqn_u64 oldstate = rng->state;
|
||||
rng->state = oldstate * 6364136223846793005ULL + rng->inc;
|
||||
Dqn_u32 xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
|
||||
Dqn_u32 rot = oldstate >> 59u;
|
||||
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
|
||||
}
|
||||
|
||||
// pcg32_srandom_r(rng, initstate, initseq):
|
||||
// Seed the rng. Specified in two parts, state initializer and a
|
||||
// sequence selection constant (a.k.a. stream id)
|
||||
|
||||
void pcg32_srandom_r(pcg32_random_t* rng, Dqn_u64 initstate, Dqn_u64 initseq)
|
||||
{
|
||||
rng->state = 0U;
|
||||
rng->inc = (initseq << 1u) | 1u;
|
||||
pcg32_random_r(rng);
|
||||
rng->state += initstate;
|
||||
pcg32_random_r(rng);
|
||||
}
|
||||
|
||||
// pcg32_boundedrand_r(rng, bound):
|
||||
// Generate a uniformly distributed number, r, where 0 <= r < bound
|
||||
|
||||
Dqn_u32 pcg32_boundedrand_r(pcg32_random_t* rng, Dqn_u32 bound)
|
||||
{
|
||||
Dqn_u32 threshold = -bound % bound;
|
||||
for (;;) {
|
||||
Dqn_u32 r = pcg32_random_r(rng);
|
||||
if (r >= threshold)
|
||||
return r % bound;
|
||||
}
|
||||
}
|
||||
#endif // DQN_KECCAK_H
|
Loading…
Reference in New Issue
Block a user