diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-02-09 07:16:49 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-02-09 07:16:49 +0100 |
commit | b7b092a08dd3a61abcd7f9daabfc21fd3a392fa9 (patch) | |
tree | 6aac5e00d5c7c2bd60df11e2ea63a03a8c45c598 /reduced_system_layer.c | |
parent | 27b4343c2a7e2583881485a5ac667894fec729f0 (diff) | |
download | reduced_system_layer-b7b092a08dd3a61abcd7f9daabfc21fd3a392fa9.zip |
Naming; blake2b hash; allocator
Diffstat (limited to 'reduced_system_layer.c')
-rwxr-xr-x[-rw-r--r--] | reduced_system_layer.c | 919 |
1 files changed, 748 insertions, 171 deletions
diff --git a/reduced_system_layer.c b/reduced_system_layer.c index fff4f44..847edae 100644..100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -1,149 +1,176 @@ -// ================================================================ -// -// reduced_system_layer.c -// -// This is a reduced system layer. -// It allows you to create a window, draw graphics in it, handle -// input events, write samples to audio output, send and receive -// UDP packets, etc. All code is single-threaded. -// -// Primary target platforms: Linux (X11), Windows, Web. -// -// ---------------------------------------------------------------- -// -// DESIGN PRINCIPLES -// -// - Minimalistic feature set. For graphics, you have access to the -// pixel buffer, and that's it. -// -// - No implicit control flow. No callbacks. You write your own -// main and call everything explicitly. But the number of things -// you have to call to do something is as little as possible. -// -// - Optimized to use in a single source file. -// Installation process? Ctrl+C, Ctrl+V, done. -// -// STYLE CONVENTIONS -// -// - Capitalized_Snake_Case - Type name. -// - snake_case - Non-type name. -// - UPPER_SNAKE_CASE - Macro or constant. -// - g_ prefix - Global variable name. -// -// Most procedures have long and descriptive names. -// Some procedures have prefixes according to their domain. -// -// There may be exceptions if convenient. -// -// ---------------------------------------------------------------- -// -// To-Do list -// -// - Work in progress -// - Clipboard -// - Images -// - Sound -// - Seldom allocator -// - Logging -// - Graphics perf - request cache -// Requires: -// + [ ] Graphics tests -// + [x] Graphics requests -// + [ ] Seldom allocator -// + [ ] Blake2 hash -// + [ ] Requests cache -// + [ ] Incremental rendering -// - Examples -// - Conway's Game of Life -// - Julia Set -// - Labyrinth -// - Chat -// - Graphics -// - UI -// - Icons -// - Vector math -// - CMYK color -// - Textures -// - Test suite -// - Improve microbenchmarks library -// - System -// - Window -// - Wayland -// - Windows graphics -// - Sound -// - Windows audio -// - Recording -// - Device selection -// - Switching canvases - Web -// - Networking -// - Windows sockets -// - TCP -// - fetch - via libcurl on native platforms -// - Cross-platform networking - UDP + TCP + WebSocket -// Requires: -// - [ ] Sockets - UDP, TCP -// - [ ] HTTP client -// - [ ] HTTP server -// - [ ] Web sockets -// - [ ] Key exchange -// - [ ] Cipher suite (Lattice-based?) -// - [ ] TLS -// - [ ] Web sockets over TLS -// - Long term -// - dlopen - load libraries conditionally -// - X11 -// - Wayland -// - ALSA -// - Allocator -// - Parsing -// - Printing -// - File system -// - Secure random -// - Process -// - Shared memory -// - Shared mutex -// - Big integer -// - Mersenne Twister 64 -// - Arithmetic coding -// - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper -// - Cryptography - https://github.com/jedisct1/supercop -// - macOS support -// - Mobile devices support -// -// Done -// -// - Examples -// - Echo -// - UI -// - Particles -// - Graph -// - Sine Wave -// - Utility -// - UTF-8 -// - Testing -// - Stackless coroutines -// - Graphics -// - Font -// - Adaptive resolution -// - Oklab color -// - Relative coordinates -// - Alpha blending -// - Self-contained impl -// - Anti-aliasing -// - System -// - Window - X11, Web -// - Screenshot - X11, Wayland -// - Clipboard -// - Text - X11, Web -// - Sound - ALSA, Web -// - Networking -// - Unix UDP sockets -// - Drop files - X11, Web -// -// ---------------------------------------------------------------- -// -// (C) 2025 Mitya Selivanov <guattari.tech> -// +#if 0 /* +#/ ================================================================ +#/ +#/ reduced_system_layer.c +#/ +#/ This is a reduced system layer. +#/ It allows you to create a window, draw graphics in it, handle +#/ input events, write samples to audio output, send and receive +#/ UDP packets, etc. All code is single-threaded. +#/ +#/ Primary target platforms: Linux (X11), Windows, Web. +#/ +#/ ---------------------------------------------------------------- +#/ +#/ DESIGN PRINCIPLES +#/ +#/ - Minimalistic feature set. For graphics, you have access to the +#/ pixel buffer, and that's it. +#/ +#/ - No implicit control flow. No callbacks. You write your own +#/ main and call everything explicitly. But the number of things +#/ you have to call to do something is as little as possible. +#/ +#/ - Optimized to use in a single source file. +#/ Installation process? Ctrl+C, Ctrl+V, done. +#/ +#/ STYLE CONVENTIONS +#/ +#/ - Pascal_Snake_Case - Type name. +#/ - snake_case - Non-type name. +#/ - UPPER_SNAKE_CASE - Macro or constant. +#/ - g_ prefix - Global variable name. +#/ +#/ Most procedures have long and descriptive names. +#/ Some procedures have prefixes according to their domain. +#/ +#/ There may be exceptions if convenient. +#/ +#/ ---------------------------------------------------------------- +#/ +#/ To-Do list +#/ +#/ - Work in progress +#/ - Clipboard +#/ - Images +#/ - Sound +#/ - Logging +#/ - Graphics perf - request cache +#/ Requires: +#/ + [ ] Graphics tests +#/ + [x] Graphics requests +#/ + [x] Memory buffer allocator +#/ + [x] Blake2 hash +#/ + [ ] Requests cache +#/ + [ ] Incremental rendering +#/ - Examples +#/ - Conway's Game of Life +#/ - Julia Set +#/ - Labyrinth +#/ - Chat +#/ - Graphics +#/ - UI +#/ - Icons +#/ - Vector math +#/ - CMYK color +#/ - Textures +#/ - Test suite +#/ - Improve microbenchmarks library +#/ - System +#/ - Window +#/ - Wayland +#/ - Windows graphics +#/ - Sound +#/ - Windows audio +#/ - Recording +#/ - Device selection +#/ - Switching canvases - Web +#/ - Networking +#/ - Windows sockets +#/ - TCP +#/ - fetch - via libcurl on native platforms +#/ - Cross-platform networking - UDP + TCP + WebSocket +#/ Requires: +#/ - [ ] Sockets - UDP, TCP +#/ - [ ] HTTP client +#/ - [ ] HTTP server +#/ - [ ] Web sockets +#/ - [ ] Key exchange +#/ - [ ] Cipher suite +#/ - TLS_AES_128_GCM_SHA256 +#/ - Lattice-based ? +#/ - [ ] TLS +#/ - [ ] Web sockets over TLS +#/ - Long term +#/ - dlopen - load libraries conditionally +#/ - X11 +#/ - Wayland +#/ - ALSA +#/ - Allocator +#/ - Parsing +#/ - Printing +#/ - File system +#/ - Secure random +#/ - Process +#/ - Shared memory +#/ - Shared mutex +#/ - Big integer +#/ - Mersenne Twister 64 +#/ - Arithmetic coding +#/ - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper +#/ - Cryptography - https://github.com/jedisct1/supercop +#/ - macOS support +#/ - Mobile devices support +#/ +#/ Done +#/ +#/ - Examples +#/ - Echo +#/ - UI +#/ - Particles +#/ - Graph +#/ - Sine Wave +#/ - Utility +#/ - UTF-8 +#/ - Testing +#/ - Stackless coroutines +#/ - Graphics +#/ - Font +#/ - Adaptive resolution +#/ - Oklab color +#/ - Relative coordinates +#/ - Alpha blending +#/ - Self-contained impl +#/ - Anti-aliasing +#/ - System +#/ - Window - X11, Web +#/ - Screenshot - X11, Wayland +#/ - Clipboard +#/ - Text - X11, Web +#/ - Sound - ALSA, Web +#/ - Networking +#/ - Unix UDP sockets +#/ - Drop files - X11, Web +#/ +#/ ---------------------------------------------------------------- +#/ +#/ (C) 2025 Mitya Selivanov <guattari.tech> +#/ +#/ ================================================================ +#/ +#/ Self-testing shell script +#/ +#/ ================================================================ + +SRC=${0##*./} +BIN=${SRC%.*} +gcc \ + -Wall -Wextra -Werror -pedantic \ + -Wno-missing-braces \ + -Wno-old-style-declaration \ + -Wno-overlength-strings \ + -O3 -D NDEBUG \ + -fsanitize=undefined,address,leak \ + -D REDUCED_SYSTEM_LAYER_TEST_SUITE \ + -lm -lX11 -lasound \ + -lwayland-client \ + -o $BIN $SRC && \ + ./$BIN $@ +STATUS=$? +rm -f $BIN +exit $STATUS # */ +#endif + // ================================================================ // // Types @@ -187,6 +214,10 @@ typedef struct { f64 v[16]; } mat4; #ifndef REDUCED_SYSTEM_LAYER_HEADER_GUARD_ #define REDUCED_SYSTEM_LAYER_HEADER_GUARD_ +#ifdef EVERY_TEST_SUITE +#define GRAPHICS_TEST_SUITE +#endif + #ifdef __cplusplus extern "C" { #endif @@ -210,18 +241,22 @@ i32 main(i32 argc, c8 **argv); // // ================================================================ -#ifndef NO_WAYLAND -#define NO_WAYLAND 0 +#ifndef ENABLE_WAYLAND +#define ENABLE_WAYLAND 1 #endif -#ifndef NO_X11 -#define NO_X11 0 +#ifndef ENABLE_X11 +#define ENABLE_X11 1 #endif #ifndef STATIC_MEMORY_BUFFER_SIZE #define STATIC_MEMORY_BUFFER_SIZE (10 * 1024 * 1024) #endif +#ifndef MEMORY_CHUNK_SIZE +#define MEMORY_CHUNK_SIZE 1024 +#endif + // ---------------------------------------------------------------- // TEMP: Static buffers. @@ -672,7 +707,7 @@ i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_po void shutdown_all_systems(void); // Memory -void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data); +void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data); #ifdef REDUCED_SYSTEM_LAYER_HEADER extern Platform g_platform; @@ -736,14 +771,18 @@ void run_main_window_event_loop(void) { // ================================================================ // -// Seldom memory allocator +// Memory buffer allocator // // ================================================================ +enum { + OCCUPIED_SIZE_ = (STATIC_MEMORY_BUFFER_SIZE + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE), +}; + typedef struct { - i64 offset; - i64 size; -} Memory_Slot_; + i64 next_chunk; + u64 occupied[OCCUPIED_SIZE_]; +} Memory_Buffer_Header_; static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0}; @@ -751,20 +790,537 @@ static i64 num_memory_slots_(void) { return *(i64 *) &g_platform.memory_buffer[g_platform.memory_buffer_size - 8]; } -void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) { - if (g_platform.memory_buffer_size < 0) +static i64 align_(i64 x, i64 alignment) { + return ((x + (alignment - 1)) / alignment) * alignment; +} + +void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) { + if (g_platform.memory_buffer_size < 0) { LOG_ERROR("Invalid memory buffer size."); - if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) + return NULL; + } + + if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) { LOG_ERROR("Invalid memory buffer."); + return NULL; + } if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) { g_platform.memory_buffer_size = sizeof memory_buffer_; g_platform.memory_buffer = memory_buffer_; } - // TODO - LOG_ERROR("Not implemented."); - return NULL; + if (g_platform.memory_buffer_size <= (i64) sizeof(Memory_Buffer_Header_)) { + LOG_ERROR("Memory buffer too small."); + return NULL; + } + + Memory_Buffer_Header_ *h = (Memory_Buffer_Header_ *) g_platform.memory_buffer; + u8 * data = g_platform.memory_buffer + sizeof(Memory_Buffer_Header_); + + i64 prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; + i64 prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE; + + i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; + i64 chunk = 0; + + // Find free space + for (i64 i = h->next_chunk; i < OCCUPIED_SIZE_ * 64; ++i) { + b8 occupied = 0; + + for (i64 j = i; j < i + num_chunks; ++j) { + if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue; + if ((h->occupied[j / 64] & (1ull << (j % 64))) == 0) continue; + occupied = 1; + break; + } + + if (occupied) { + chunk = i; + break; + } + } + + u8 *src = data + prev_chunk * MEMORY_CHUNK_SIZE; + u8 *dst = data + chunk * MEMORY_CHUNK_SIZE; + i64 len = size < previous_size ? size : previous_size; + + // Check if out of memory + if (data + size > g_platform.memory_buffer + g_platform.memory_buffer_size) { + LOG_ERROR("Out of memory."); + return NULL; + } + + // Claim required space + for (i64 j = chunk; j < chunk + num_chunks; ++j) + h->occupied[j / 64] |= 1ull << (j % 64); + + // Copy data + if (dst > src) + for (i64 k = len - 1; k >= 0; --k) + dst[k] = src[k]; + else + for (i64 k = 0; k < len; ++k) + dst[k] = src[k]; + + // Free previous space + for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) { + if (j >= chunk && j < chunk + num_chunks) continue; + h->occupied[j / 64] &= ~(1ull << (j % 64)); + } + + if (num_chunks == 0) + return NULL; + + return dst; +} + +// ================================================================ +// +// BLAKE2B +// +// ================================================================ + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct { + u8 digest_length; + u8 key_length; + u8 fanout; + u8 depth; + u32 leaf_length; + u64 node_offset; + u8 node_depth; + u8 inner_length; + u8 reserved[14]; + u8 salt[BLAKE2B_SALTBYTES]; + u8 personal[BLAKE2B_PERSONALBYTES]; +} Blake2b_Param; + +typedef struct { + u64 h[8]; + u64 t[2]; + u64 f[2]; + u8 buf[2 * BLAKE2B_BLOCKBYTES]; + u64 buflen; + u8 last_node; +} Blake2b_State; + +static u64 blake2b_IV[8] = { + 0x6a09e667f3bcc908ull, 0xbb67ae8584caa73bull, + 0x3c6ef372fe94f82bull, 0xa54ff53a5f1d36f1ull, + 0x510e527fade682d1ull, 0x9b05688c2b3e6c1full, + 0x1f83d9abfb41bd6bull, 0x5be0cd19137e2179ull +}; + +static u8 blake2b_sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +static void mem_set_(void *dst, u8 x, u32 size) { + for (u32 i = 0; i < size; ++i) + ((u8 *) dst)[i] = x; +} + +static void mem_cpy_(void *dst, void *src, u32 size) { + for (u32 i = 0; i < size; ++i) + ((u8 *) dst)[i] = ((u8 *) src)[i]; +} + +static b8 native_little_endian_(void) { + return ((u8 *) &(u32) { 1 })[0] == 1; +} + +static u32 load32_(void *src) { + if (native_little_endian_()) + return *( u32 * )( src ); + else { + u8 *p = ( u8 * )src; + u32 w = *p++; + w |= ( u32 )( *p++ ) << 8; + w |= ( u32 )( *p++ ) << 16; + w |= ( u32 )( *p++ ) << 24; + return w; + } +} + +static u64 load64_(void *src) { + if (native_little_endian_()) + return *( u64 * )( src ); + else { + u8 *p = ( u8 * )src; + u64 w = *p++; + w |= ( u64 )( *p++ ) << 8; + w |= ( u64 )( *p++ ) << 16; + w |= ( u64 )( *p++ ) << 24; + w |= ( u64 )( *p++ ) << 32; + w |= ( u64 )( *p++ ) << 40; + w |= ( u64 )( *p++ ) << 48; + w |= ( u64 )( *p++ ) << 56; + return w; + } +} + +static void store32_(void *dst, u32 w) { + if (native_little_endian_()) + *( u32 * )( dst ) = w; + else { + u8 *p = ( u8 * )dst; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; + } +} + +static void store64_(void *dst, u64 w) { + if (native_little_endian_()) + *( u64 * )( dst ) = w; + else { + u8 *p = ( u8 * )dst; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; + } +} + +static u64 load48_(void *src) { + u8 *p = ( u8 * )src; + u64 w = *p++; + w |= ( u64 )( *p++ ) << 8; + w |= ( u64 )( *p++ ) << 16; + w |= ( u64 )( *p++ ) << 24; + w |= ( u64 )( *p++ ) << 32; + w |= ( u64 )( *p++ ) << 40; + return w; +} + +static void store48_(void *dst, u64 w) { + u8 *p = ( u8 * )dst; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; w >>= 8; + *p++ = ( u8 )w; +} + +static u32 rotl32_(u32 w, u32 c) { + return ( w << c ) | ( w >> ( 32 - c ) ); +} + +static u64 rotl64_(u64 w, u32 c) { + return ( w << c ) | ( w >> ( 64 - c ) ); +} + +static u32 rotr32_(u32 w, u32 c) { + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static u64 rotr64_(u64 w, u32 c) { + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +static void secure_zero_memory_(void *v, u64 n) { + volatile u8 *p = ( volatile u8 * )v; + while( n-- ) *p++ = 0; +} + +static i32 blake2b_set_lastnode_(Blake2b_State *S) { + S->f[1] = ~0ull; + return 0; +} + +static i32 blake2b_clear_lastnode_(Blake2b_State *S) { + S->f[1] = 0ull; + return 0; +} + +static i32 blake2b_set_lastblock_(Blake2b_State *S) { + if( S->last_node ) blake2b_set_lastnode_( S ); + + S->f[0] = ~0ull; + return 0; +} + +static i32 blake2b_clear_lastblock_(Blake2b_State *S) { + if( S->last_node ) blake2b_clear_lastnode_( S ); + + S->f[0] = 0ull; + return 0; +} + +static i32 blake2b_increment_counter_(Blake2b_State *S, u64 inc) { + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); + return 0; +} + +static i32 blake2b_param_set_digest_length_(Blake2b_Param *P, u8 digest_length) { + P->digest_length = digest_length; + return 0; +} + +static i32 blake2b_param_set_fanout_(Blake2b_Param *P, u8 fanout) { + P->fanout = fanout; + return 0; +} + +static i32 blake2b_param_set_max_depth_(Blake2b_Param *P, u8 depth) { + P->depth = depth; + return 0; +} + +static i32 blake2b_param_set_leaf_length_(Blake2b_Param *P, u32 leaf_length) { + store32_( &P->leaf_length, leaf_length ); + return 0; +} + +static i32 blake2b_param_set_node_offset_(Blake2b_Param *P, u64 node_offset) { + store64_( &P->node_offset, node_offset ); + return 0; +} + +static i32 blake2b_param_set_node_depth_(Blake2b_Param *P, u8 node_depth) { + P->node_depth = node_depth; + return 0; +} + +static i32 blake2b_param_set_inner_length_(Blake2b_Param *P, u8 inner_length) { + P->inner_length = inner_length; + return 0; +} + +static i32 blake2b_param_set_salt_(Blake2b_Param *P, u8 salt[BLAKE2B_SALTBYTES]) { + mem_cpy_( P->salt, salt, BLAKE2B_SALTBYTES ); + return 0; +} + +static i32 blake2b_param_set_personal_(Blake2b_Param *P, u8 personal[BLAKE2B_PERSONALBYTES]) { + mem_cpy_( P->personal, personal, BLAKE2B_PERSONALBYTES ); + return 0; +} + +static i32 blake2b_init0_(Blake2b_State *S) { + i32 i; + mem_set_( S, 0, sizeof( Blake2b_State ) ); + + for(i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; + + return 0; +} + +static i32 blake2b_init_param_(Blake2b_State *S, Blake2b_Param *P) { + blake2b_init0_( S ); + u8 *p = ( u8 * )( P ); + u64 i; + + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64_( p + sizeof( S->h[i] ) * i ); + + return 0; +} + +i32 blake2b_init(Blake2b_State *S, u8 outlen) { + Blake2b_Param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32_( &P->leaf_length, 0 ); + store64_( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + mem_set_( P->reserved, 0, sizeof( P->reserved ) ); + mem_set_( P->salt, 0, sizeof( P->salt ) ); + mem_set_( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param_( S, P ); +} + +static i32 blake2b_compress_(Blake2b_State *S, u8 block[BLAKE2B_BLOCKBYTES]) { + u64 m[16]; + u64 v[16]; + i32 i; + + for( i = 0; i < 16; ++i ) + m[i] = load64_( block + i * sizeof( m[i] ) ); + + for( i = 0; i < 8; ++i ) + v[i] = S->h[i]; + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = S->t[0] ^ blake2b_IV[4]; + v[13] = S->t[1] ^ blake2b_IV[5]; + v[14] = S->f[0] ^ blake2b_IV[6]; + v[15] = S->f[1] ^ blake2b_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64_(d ^ a, 32); \ + c = c + d; \ + b = rotr64_(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64_(d ^ a, 16); \ + c = c + d; \ + b = rotr64_(b ^ c, 63); \ + } while(0) +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + +#undef G +#undef ROUND + return 0; +} + +i32 blake2b_update(Blake2b_State *S, u8 *in, u64 inlen) { + while( inlen > 0 ) { + u64 left = S->buflen; + u64 fill = 2 * BLAKE2B_BLOCKBYTES - left; + + if( inlen > fill ) { + mem_cpy_( S->buf + left, in, fill ); + S->buflen += fill; + blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress_( S, S->buf ); + mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); + S->buflen -= BLAKE2B_BLOCKBYTES; + in += fill; + inlen -= fill; + } else { + mem_cpy_( S->buf + left, in, inlen ); + S->buflen += inlen; + in += inlen; + inlen -= inlen; + } + } + + return 0; +} + +i32 blake2b_init_key(Blake2b_State *S, u8 outlen, void *key, u8 keylen) { + Blake2b_Param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + store32_( &P->leaf_length, 0 ); + store64_( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + mem_set_( P->reserved, 0, sizeof( P->reserved ) ); + mem_set_( P->salt, 0, sizeof( P->salt ) ); + mem_set_( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param_( S, P ) < 0 ) return -1; + + { + u8 block[BLAKE2B_BLOCKBYTES]; + mem_set_( block, 0, BLAKE2B_BLOCKBYTES ); + mem_cpy_( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory_( block, BLAKE2B_BLOCKBYTES ); + } + return 0; +} + +i32 blake2b_final(Blake2b_State *S, u8 *out, u8 outlen) { + u8 buffer[BLAKE2B_OUTBYTES]; + i32 i; + + if( S->buflen > BLAKE2B_BLOCKBYTES ) { + blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress_( S, S->buf ); + S->buflen -= BLAKE2B_BLOCKBYTES; + mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen ); + } + + blake2b_increment_counter_( S, S->buflen ); + blake2b_set_lastblock_( S ); + mem_set_( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen ); + blake2b_compress_( S, S->buf ); + + for( i = 0; i < 8; ++i ) + store64_( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + mem_cpy_( out, buffer, outlen ); + return 0; +} + +i32 blake2b(u8 *out, void *in, void *key, u8 outlen, u64 inlen, u8 keylen) { + Blake2b_State S[1]; + + if ( NULL == in ) return -1; + if ( NULL == out ) return -1; + if ( NULL == key ) keylen = 0; + + if ( keylen > 0 ) { + if ( blake2b_init_key( S, outlen, key, keylen ) < 0 ) + return -1; + } else { + if ( blake2b_init( S, outlen ) < 0 ) + return -1; + } + + blake2b_update( S, ( u8 * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; } // ================================================================ @@ -1556,7 +2112,7 @@ void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { // // ================================================================ -#if defined(__linux__) && !NO_WAYLAND +#if defined(__linux__) && ENABLE_WAYLAND #include <sys/mman.h> #include <wayland-client.h> @@ -2088,7 +2644,7 @@ finalize: return ok; } -#endif // defined(__linux__) && !NO_WAYLAND +#endif // defined(__linux__) && ENABLE_WAYLAND // ================================================================ // @@ -2096,7 +2652,7 @@ finalize: // // ================================================================ -#if defined(__linux__) && !NO_X11 +#if defined(__linux__) && ENABLE_X11 #include <sys/stat.h> #include <X11/Xlib.h> @@ -2137,7 +2693,6 @@ static Window _dnd_source = 0; static b8 _mapped = 0; static b8 _requested_clipboard = 0; - static i16 _key_table [MAX_NUM_KEYS] = {0}; static b8 _key_repeat [MAX_NUM_KEYS] = {0}; static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0}; @@ -2151,7 +2706,7 @@ static b8 sub_str_eq_(c8 *a, c8 *b, i64 len) { return 1; } -i32 x11_error_handler_(Display *display, XErrorEvent *event) { +static i32 x11_error_handler_(Display *display, XErrorEvent *event) { XGetErrorText(display, event->error_code, _error_buffer, sizeof _error_buffer - 1); LOG_ERROR("%s", _error_buffer); return 0; @@ -3024,23 +3579,23 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels return 1; } -#endif // defined(__linux__) && !NO_X11 +#endif // defined(__linux__) && ENABLE_X11 // ================================================================ -#if defined(__linux__) && (!NO_X11 || !NO_WAYLAND) +#if defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND) void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { if (width == NULL || height == NULL) { LOG_ERROR("Invalid arguments."); return; } - #if !NO_X11 + #if ENABLE_X11 if (x11_screenshot_(max_num_pixels, width, height, pixels)) return; #endif - #if !NO_WAYLAND + #if ENABLE_WAYLAND if (wayland_screenshot_(max_num_pixels, width, height, pixels)) return; #endif @@ -3048,7 +3603,7 @@ void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixe *width = 0; *height = 0; } -#endif // defined(__linux__) && (!NO_X11 || !NO_WAYLAND) +#endif // defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND) // ================================================================ // @@ -3541,6 +4096,28 @@ __attribute__((export_name("js_drop"))) void js_drop(i32 name_len, i32 data_size #endif // defined(__wasm__) // ================================================================ +// +// Test suite +// +// ================================================================ + +#ifdef REDUCED_SYSTEM_LAYER_TEST_SUITE + +#define TEST_FILE reduced_system_layer +#include "test.c" + +#ifndef EVERY_TEST_SUITE +void update_and_render_frame(void) {} + +i32 main(i32 argc, c8 **argv) { + return run_tests(argc, argv); +} +#endif + +#undef TEST_FILE +#endif // REDUCED_SYSTEM_LAYER_TEST_SUITE + +// ================================================================ #undef LOG_ERROR |