From 1ed53412f7e342eae7c181591cc416f6b56e3523 Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Wed, 7 Jan 2026 05:47:00 +0100 Subject: [PATCH 1/6] random: Implement Time Jitter Entropy Collector (TJEC) --- src/oboskrnl/contrib/csprng.c | 47 ++ src/oboskrnl/contrib/random.h | 168 +++++ src/oboskrnl/contrib/tjec.c | 1084 ++++++++++++++++++++++++++++ src/oboskrnl/net/tcp.c | 10 +- src/oboskrnl/net/udp.c | 6 +- src/oboskrnl/scheduler/cpu_local.h | 5 + src/oboskrnl/vfs/dummy_devices.c | 313 ++++++-- 7 files changed, 1559 insertions(+), 74 deletions(-) create mode 100644 src/oboskrnl/contrib/csprng.c create mode 100644 src/oboskrnl/contrib/random.h create mode 100644 src/oboskrnl/contrib/tjec.c diff --git a/src/oboskrnl/contrib/csprng.c b/src/oboskrnl/contrib/csprng.c new file mode 100644 index 00000000..293dada0 --- /dev/null +++ b/src/oboskrnl/contrib/csprng.c @@ -0,0 +1,47 @@ +/* + * oboskrnl/contrib/csprng.c + * + * Copyright (c) 2026 MarcasRealAccount + */ + +#include + +#include + +// TODO: Make thread-safe + +size_t csprng_tjec_read_entropy(void* userdata, void* data, size_t size) +{ + int64_t res = tjec_read_entropy_safe((tjec*) userdata, data, size); + return res > 0 ? (size_t) res : 0; +} + +uint32_t csprng_init(csprng* ctx, const csprng_callbacks* callbacks, uint64_t flags) +{ + if (!ctx || !callbacks) + return CSPRNG_EINVAL; + + memset(ctx, 0, sizeof(csprng)); + + memcpy(&ctx->callbacks, callbacks, sizeof(csprng_callbacks)); + ctx->flags = flags; + + return CSPRNG_ENOERR; +} + +void csprng_destroy(csprng* ctx) +{ + if (!ctx) + return; + + memset(ctx, 0, sizeof(csprng)); +} + +int64_t csprng_read_random(csprng* ctx, void* data, size_t size) +{ + if (!ctx || !data) + return 0; + + size_t read = ctx->callbacks.read_entropy(ctx->callbacks.userdata, data, size); + return (int64_t) read; +} \ No newline at end of file diff --git a/src/oboskrnl/contrib/random.h b/src/oboskrnl/contrib/random.h new file mode 100644 index 00000000..59217f06 --- /dev/null +++ b/src/oboskrnl/contrib/random.h @@ -0,0 +1,168 @@ +/* + * oboskrnl/contrib/random.h + * + * Copyright (c) 2026 MarcasRealAccount + */ + +#pragma once + +#include +#include + +#include + +typedef struct tjec_sha3 +{ + uint16_t r; + uint16_t rword; + uint16_t digest_size; + uint8_t partial[136]; + uint64_t state[25]; + uint64_t msg_len; +} tjec_sha3; + +typedef struct tjec_memory +{ + atomic_uchar* memory; + size_t cell_size; + size_t size; + uint64_t flags; +} tjec_memory; + +typedef struct tjec +{ + mutex mtx; + + uint32_t health_failure; + uint16_t base_acc_count; + uint8_t osr; + uint8_t apt_base_set : 1; + uint8_t fips_enabled : 1; + uint8_t random_access : 1; + uint8_t lag_predictor : 1; + uint64_t flags; + + uint64_t prev_time; + uint64_t prev_delta; + uint64_t prev_delta2; + + uint64_t common_time_gcd; + + const tjec_memory* memory; + size_t location; + + uint64_t apt_base; + uint32_t apt_count; + uint32_t apt_cutoff; + uint32_t apt_cutoff_permanent; + uint32_t apt_observations; + + uint32_t rct_count; + + uint32_t lag_global_cutoff; + uint32_t lag_local_cutoff; + uint32_t lag_prediction_success_count; + uint32_t lag_prediction_success_run; + uint32_t lag_best_predictor; + uint32_t lag_observations; + uint64_t lag_scoreboard[8]; + uint64_t lag_delta_history[8]; + + tjec_sha3 sha3; +} tjec; + +typedef struct csprng_callbacks +{ + void* userdata; + size_t(* read_entropy)(void* userdata, void* data, size_t size); +} csprng_callbacks; + +typedef struct csprng +{ + csprng_callbacks callbacks; + + uint64_t flags; +} csprng; + +static const uint64_t TJEC_MEM_32KIB = 1; +static const uint64_t TJEC_MEM_64KIB = 2; +static const uint64_t TJEC_MEM_128KIB = 3; +static const uint64_t TJEC_MEM_256KIB = 4; +static const uint64_t TJEC_MEM_512KIB = 5; +static const uint64_t TJEC_MEM_1MIB = 6; +static const uint64_t TJEC_MEM_2MIB = 7; +static const uint64_t TJEC_MEM_4MIB = 8; +static const uint64_t TJEC_MEM_8MIB = 9; +static const uint64_t TJEC_MEM_16MIB = 10; +static const uint64_t TJEC_MEM_32MIB = 11; +static const uint64_t TJEC_MEM_64MIB = 12; +static const uint64_t TJEC_MEM_128MIB = 13; +static const uint64_t TJEC_MEM_256MIB = 14; +static const uint64_t TJEC_MEM_512MIB = 15; +static const uint64_t TJEC_MEM_RANDOM_ACCESS = 16; + +static const uint64_t TJEC_USE_FIPS = 1; +static const uint64_t TJEC_USE_LAG_PREDICTOR = 2; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_1 = UINT64_C(0) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_2 = UINT64_C(1) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_3 = UINT64_C(2) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_4 = UINT64_C(3) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_5 = UINT64_C(4) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_6 = UINT64_C(5) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_7 = UINT64_C(6) << 8; +static const uint64_t TJEC_MAX_ACC_LOOP_BITS_8 = UINT64_C(7) << 8; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_1 = UINT64_C(0) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_2 = UINT64_C(1) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_3 = UINT64_C(2) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_4 = UINT64_C(3) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_5 = UINT64_C(4) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_6 = UINT64_C(5) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_7 = UINT64_C(6) << 11; +static const uint64_t TJEC_MAX_HASH_LOOP_BITS_8 = UINT64_C(7) << 11; + +static const uint32_t TJEC_ENOERR = 0; +static const uint32_t TJEC_EINVAL = 1; +static const uint32_t TJEC_ENOMEM = 2; +static const uint32_t TJEC_ENOTIME = 3; +static const uint32_t TJEC_ECOARSETIME = 4; +static const uint32_t TJEC_ENOMONOTONIC = 5; +static const uint32_t TJEC_ERCT = 6; +static const uint32_t TJEC_EHEALTH = 7; +static const uint32_t TJEC_ESTUCK = 8; +static const uint32_t TJEC_EMINVARVAR = 9; + +static const int64_t TJEC_OSR_FAILURE = -1; +static const int64_t TJEC_RCT_FAILURE = -2; +static const int64_t TJEC_APT_FAILURE = -3; +static const int64_t TJEC_LAG_FAILURE = -4; +static const int64_t TJEC_UNKNOWN_FAILURE = -5; +static const int64_t TJEC_RCT_FAILURE_PERMANENT = -6; +static const int64_t TJEC_APT_FAILURE_PERMANENT = -7; +static const int64_t TJEC_LAG_FAILURE_PERMANENT = -8; + +uint32_t tjec_memory_init(tjec_memory* mem, uint64_t flags); +void tjec_memory_destroy(tjec_memory* mem); +size_t tjec_memory_get_size(const tjec_memory* mem); + +uint32_t tjec_pre_init(tjec* ec, const tjec_memory* mem, uint64_t flags); +uint32_t tjec_pre_init_ex(tjec* ec, const tjec_memory* mem, uint64_t flags, uint8_t osr); +uint32_t tjec_init(tjec* ec, const tjec_memory* mem, uint64_t flags); +uint32_t tjec_init_ex(tjec* ec, const tjec_memory* mem, uint64_t flags, uint8_t osr); +void tjec_destroy(tjec* ec); +int64_t tjec_read_entropy(tjec* ec, void* data, size_t size); +int64_t tjec_read_entropy_safe(tjec* ec, void* data, size_t size); + +static const uint32_t CSPRNG_ENOERR = 0; +static const uint32_t CSPRNG_EINVAL = 1; + +size_t csprng_tjec_read_entropy(void* userdata, void* data, size_t size); + +uint32_t csprng_init(csprng* ctx, const csprng_callbacks* callbacks, uint64_t flags); +void csprng_destroy(csprng* ctx); +int64_t csprng_read_random(csprng* ctx, void* data, size_t size); + +uint8_t random8(void); +uint16_t random16(void); +uint32_t random32(void); +uint64_t random64(void); +bool random_buffer(void* buffer, size_t size); \ No newline at end of file diff --git a/src/oboskrnl/contrib/tjec.c b/src/oboskrnl/contrib/tjec.c new file mode 100644 index 00000000..b895e667 --- /dev/null +++ b/src/oboskrnl/contrib/tjec.c @@ -0,0 +1,1084 @@ +/* + * oboskrnl/contrib/tjec.c + * + * Copyright (c) 2026 MarcasRealAccount + */ + +#include + +#include + +#include + +#include +#include + +#define ENTROPY_SAFETY_FACTOR 64 +#define APT_MASK (UINT64_C(0xFFFFFFFFFFFFFFFF)) +#define APT_WINDOW_SIZE 512 +#define LAG_HISTORY_SIZE (sizeof(((tjec*) 0)->lag_delta_history) / sizeof(*((tjec*) 0)->lag_delta_history)) +#define LAG_MASK (LAG_HISTORY_SIZE - 1) +#define LAG_WINDOW_SIZE (1 << 10) +#define SHA3_UNROLLED 0 + +#define CELL_SIZE 128 +#define CELL_COUNT 512 + +#define APT_FAILURE_PERMANENT 1 +#define RCT_FAILURE_PERMANENT 2 +#define LAG_FAILURE_PERMANENT 4 +#define APT_FAILURE 8 +#define RCT_FAILURE 16 +#define LAG_FAILURE 32 + +/* Helper functions: */ + +#if __x86_64__ +# include +#endif + +static uint64_t temp_time() +{ +#if __x86_64__ + return rdtsc(); +#else + return CoreS_GetNativeTimerTick(); +#endif +} + +static uint64_t temp_l1_cache_size() +{ +#if __x86_64__ + uint32_t ecx; + uint32_t edx; + __cpuid__(0x80000005, 0, NULL, NULL, &ecx, &edx); + uint64_t cachesize = ((uint64_t)((ecx >> 24) & 7) + ((edx >>24 ) & 7)) << 10; + return cachesize; +#else + return 0; +#endif +} + +static inline uint64_t rotl64(uint64_t v, uint8_t s) +{ + return (v << s) | (v >> (64 - s)); +} + +static inline uint32_t rotl32(uint32_t v, uint8_t s) +{ + return (v << s) | (v >> (32 - s)); +} + +static inline uint64_t gcd64(uint64_t a, uint64_t b) +{ + if (a < b) + { + uint64_t tmp = a; + a = b; + b = tmp; + } + + while (b != 0) + { + uint64_t r = a % b; + a = b; + b = r; + } + return a; +} + +static void sha3_init(tjec_sha3* ctx); +static void sha3_256_init(tjec_sha3* ctx); +static void sha3_update(tjec_sha3* ctx, const void* data, size_t size); +static void sha3_final(tjec_sha3* ctx, void* digest); + +static void apt_init(tjec* ec, uint8_t osr); +static void apt_reinit(tjec* ec, uint64_t delta, uint32_t apt_count, uint32_t apt_observations); +static void apt_reset(tjec* ec); +static void apt_insert(tjec* ec, uint64_t delta); + +static void lag_init(tjec* ec, uint8_t osr); +static void lag_reset(tjec* ec); +static void lag_insert(tjec* ec, uint64_t delta); +static uint64_t lag_delta2(tjec* ec, uint64_t delta); +static uint64_t lag_delta3(tjec* ec, uint64_t delta2); + +static uint32_t rct_permanent_cutoff(uint8_t osr); +static uint32_t rct_intermittent_cutoff(uint8_t osr); +static void rct_insert(tjec* ec, int stuck); + +static int tjec_is_stuck(tjec* ec, uint64_t delta); +static uint32_t tjec_health_failure(tjec* ec); +static uint64_t tjec_loop_shuffle(tjec* ec, uint32_t bits, uint32_t min); +static void tjec_hash_time(tjec* ec, uint64_t delta, int stuck); +static void tjec_random_memory_access(tjec* ec); +static void tjec_memory_access(tjec* ec); +static int tjec_measure_jitter(tjec* ec, uint64_t* current_delta); +static void tjec_random_data(tjec* ec); +static void tjec_read_random_block(tjec* ec, void* dst, size_t size); +static uint32_t tjec_find_common_time_gcd(tjec* ec); +static uint64_t tjec_memory_size(uint64_t flags); + +static uint64_t tjec_common_time_gcd = 1; + +uint32_t tjec_memory_init(tjec_memory* mem, uint64_t flags) +{ + if (!mem) + return TJEC_EINVAL; + + memset(mem, 0, sizeof(tjec_memory)); + + uint64_t memory_size = tjec_memory_size(flags); + + mem->memory = (atomic_uchar*) Mm_QuickVMAllocate(memory_size, true); + mem->cell_size = CELL_SIZE; + mem->size = memory_size; + mem->flags = flags; + if (!mem->memory) + return TJEC_ENOMEM; + memset(mem->memory, 0, memory_size); + + return TJEC_ENOERR; +} + +void tjec_memory_destroy(tjec_memory* mem) +{ + if (!mem) + return; + + Mm_VirtualMemoryFree(&Mm_KernelContext, mem->memory, mem->size); + memset(mem, 0, sizeof(tjec_memory)); +} + +size_t tjec_memory_get_size(const tjec_memory* mem) +{ + return mem ? mem->size : 0; +} + +uint32_t tjec_pre_init(tjec* ec, const tjec_memory* mem, uint64_t flags) +{ + return tjec_pre_init_ex(ec, mem, flags, 1); +} + +uint32_t tjec_pre_init_ex(tjec* ec, const tjec_memory* mem, uint64_t flags, uint8_t osr) +{ + uint32_t err = tjec_init_ex(ec, mem, flags, osr); + if (err) + return err; + + err = tjec_find_common_time_gcd(ec); + if (err) + return err; + + tjec_common_time_gcd = ec->common_time_gcd; + return TJEC_ENOERR; +} + +uint32_t tjec_init(tjec* ec, const tjec_memory* mem, uint64_t flags) +{ + return tjec_init_ex(ec, mem, flags, 1); +} + +uint32_t tjec_init_ex(tjec* ec, const tjec_memory* mem, uint64_t flags, uint8_t osr) +{ + if (!ec || !mem || !osr) + return TJEC_EINVAL; + + memset(ec, 0, sizeof(tjec)); + + ec->mtx = MUTEX_INITIALIZE(); + ec->base_acc_count = 64; + ec->osr = osr; + ec->fips_enabled = !!(flags & TJEC_USE_FIPS); + ec->random_access = !!(mem->flags & TJEC_MEM_RANDOM_ACCESS); + ec->lag_predictor = !!(flags & TJEC_USE_LAG_PREDICTOR); + ec->flags = flags; + ec->common_time_gcd = tjec_common_time_gcd; + ec->memory = mem; + + sha3_256_init(&ec->sha3); + apt_init(ec, osr); + if (ec->lag_predictor) + lag_init(ec, osr); + + tjec_measure_jitter(ec, NULL); + + return TJEC_ENOERR; +} + +void tjec_destroy(tjec* ec) +{ + if (!ec) + return; + + memset(ec, 0, sizeof(tjec)); +} + +int64_t tjec_read_entropy(tjec* ec, void* data, size_t size) +{ + if (!ec || !data) + return 0; + + size_t orig_size = size; + int32_t ret = 0; + + uint8_t* ptr = (uint8_t*) data; + + uint8_t reacquire_counter = 0; + Core_MutexAcquire(&ec->mtx); + + while (size > 0) + { + tjec_random_data(ec); + + uint32_t health_test = tjec_health_failure(ec); + if (health_test) + { + if (health_test & RCT_FAILURE_PERMANENT) + ret = TJEC_RCT_FAILURE_PERMANENT; + else if (health_test & APT_FAILURE_PERMANENT) + ret = TJEC_APT_FAILURE_PERMANENT; + else if (health_test & LAG_FAILURE_PERMANENT) + ret = TJEC_LAG_FAILURE_PERMANENT; + else if (health_test & RCT_FAILURE) + ret = TJEC_RCT_FAILURE; + else if (health_test & APT_FAILURE) + ret = TJEC_APT_FAILURE; + else if (health_test & LAG_FAILURE) + ret = TJEC_LAG_FAILURE; + else + ret = TJEC_UNKNOWN_FAILURE; + break; + } + + size_t to_copy = size >= 32 ? 32 : size; + tjec_read_random_block(ec, ptr, to_copy); + size -= to_copy; + ptr += to_copy; + + if (++reacquire_counter >= 128) + { + reacquire_counter = 0; + Core_MutexRelease(&ec->mtx); + Core_MutexAcquire(&ec->mtx); + } + } + + tjec_read_random_block(ec, NULL, 0); + + Core_MutexRelease(&ec->mtx); + + return ret ? ret : (int64_t) orig_size; +} + +int64_t tjec_read_entropy_safe(tjec* ec, void* data, size_t size) +{ + if (!ec) + return 0; + + size_t orig_size = size; + uint8_t* ptr = (uint8_t*) data; + + while (size > 0) + { + int64_t ret = tjec_read_entropy(ec, ptr, size); + + switch (ret) + { + case TJEC_OSR_FAILURE: + case TJEC_RCT_FAILURE_PERMANENT: + case TJEC_APT_FAILURE_PERMANENT: + case TJEC_LAG_FAILURE_PERMANENT: + return ret; + + case TJEC_UNKNOWN_FAILURE: + case TJEC_RCT_FAILURE: + case TJEC_APT_FAILURE: + case TJEC_LAG_FAILURE: + { + Core_MutexAcquire(&ec->mtx); + uint32_t apt_observations = ec->apt_observations; + uint64_t current_delta = ec->apt_base; + uint32_t lag_prediction_success_run = ec->lag_prediction_success_run; + uint32_t lag_prediction_success_count = ec->lag_prediction_success_count; + + const tjec_memory* mem = ec->memory; + + uint16_t osr = (uint16_t) ec->osr + 1; + uint64_t flags = ec->flags; + + if (osr > 20) + return ret; + + while (tjec_init_ex(ec, mem, flags, (uint8_t) osr)) + { + ++osr; + if (osr > 20) + { + Core_MutexRelease(&ec->mtx); + return TJEC_OSR_FAILURE; + } + } + + if (apt_observations) + { + apt_reinit(ec, current_delta, 0, apt_observations); + ec->rct_count = rct_intermittent_cutoff(osr); + ec->lag_prediction_success_run = lag_prediction_success_run; + ec->lag_prediction_success_count = lag_prediction_success_count; + } + Core_MutexRelease(&ec->mtx); + break; + } + default: + size -= (size_t) ret; + ptr += (size_t) ret; + break; + } + } + + return (int64_t) orig_size; +} + +// APT + +void apt_init(tjec* ec, uint8_t osr) +{ + const uint32_t cutoff_lut[] = { 325, 422, 459, 477, 488, 494, 499, 502, 505, 507, 508, 509, 510, 511, 512 }; + const uint32_t cutoff_permanent_lut[] = { 355, 447, 479, 494, 502, 507, 510, 512, 512, 512, 512, 512, 512, 512, 512 }; + + osr = osr < sizeof(cutoff_lut) / sizeof(*cutoff_lut) ? osr : sizeof(cutoff_lut) / sizeof(*cutoff_lut); + + ec->apt_cutoff = cutoff_lut[osr]; + ec->apt_cutoff_permanent = cutoff_permanent_lut[osr]; +} + +void apt_reinit(tjec* ec, uint64_t delta, uint32_t apt_count, uint32_t apt_observations) +{ + ec->apt_base = delta; + ec->apt_base_set = 1; + if (apt_count) + ec->apt_count = apt_count; + else + ec->apt_count = ec->apt_cutoff; + ec->apt_observations = apt_observations; +} + +void apt_reset(tjec* ec) +{ + ec->apt_base_set = 0; +} + +void apt_insert(tjec* ec, uint64_t delta) +{ + delta &= APT_MASK; + + if (!ec->apt_base_set) + { + apt_reinit(ec, delta, 1, 1); + return; + } + + if (delta == ec->apt_base) + { + ++ec->apt_count; + + if (ec->apt_count >= ec->apt_cutoff_permanent) + ec->health_failure |= APT_FAILURE_PERMANENT; + else if (ec->apt_count == ec->apt_cutoff) + ec->health_failure |= APT_FAILURE; + } + + ++ec->apt_observations; + + if (ec->apt_observations >= APT_WINDOW_SIZE) + apt_reset(ec); +} + +// LAG + +void lag_init(tjec* ec, uint8_t osr) +{ + const uint32_t global_cutoff_lut[] = { 66443, 93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823, 122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457, 126704, 126926 }; + const uint32_t local_cutoff_lut[] = { 38, 75, 111, 146, 181, 215, 250, 284, 318, 351, 385, 419, 452, 485, 518, 551, 584, 617, 650, 683 }; + + osr = osr < sizeof(global_cutoff_lut) / sizeof(*global_cutoff_lut) ? osr : sizeof(global_cutoff_lut) / sizeof(*global_cutoff_lut); + + ec->lag_global_cutoff = global_cutoff_lut[osr - 1]; + ec->lag_local_cutoff = local_cutoff_lut[osr - 1]; +} + +void lag_reset(tjec* ec) +{ + ec->lag_prediction_success_count = 0; + ec->lag_prediction_success_run = 0; + ec->lag_best_predictor = 0; + ec->lag_observations = 0; + + for (uint32_t i = 0; i < LAG_HISTORY_SIZE; ++i) + { + ec->lag_scoreboard[i] = 0; + ec->lag_delta_history[i] = 0; + } +} + +#define LAG_HISTORY(ec, loc) (ec->lag_delta_history[(ec->lag_observations - loc - 1) & LAG_MASK]) + +void lag_insert(tjec* ec, uint64_t delta) +{ + if (ec->lag_observations < LAG_HISTORY_SIZE) + { + ec->lag_delta_history[ec->lag_observations++] = delta; + return; + } + + uint64_t prediction = LAG_HISTORY(ec, ec->lag_best_predictor); + if (prediction == delta) + { + ++ec->lag_prediction_success_count; + ++ec->lag_prediction_success_run; + + if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) || + (ec->lag_prediction_success_count >= ec->lag_global_cutoff)) + ec->health_failure |= LAG_FAILURE; + } + else + { + ec->lag_prediction_success_run = 0; + } + + for (uint32_t i = 0; i < LAG_HISTORY_SIZE; ++i) + { + if (LAG_HISTORY(ec, i) == delta) + { + ++ec->lag_scoreboard[i]; + + if (ec->lag_scoreboard[i] > ec->lag_scoreboard[ec->lag_best_predictor]) + ec->lag_best_predictor = i; + } + } + + ec->lag_delta_history[(ec->lag_observations++) & LAG_MASK] = delta; + if (ec->lag_observations >= LAG_WINDOW_SIZE) + lag_reset(ec); +} + +uint64_t lag_delta2(tjec* ec, uint64_t delta) +{ + return delta - LAG_HISTORY(ec, 0); +} + +uint64_t lag_delta3(tjec* ec, uint64_t delta2) +{ + return delta2 - (LAG_HISTORY(ec, 0) - LAG_HISTORY(ec, 1)); +} + +// RCT + +uint32_t rct_permanent_cutoff(uint8_t osr) +{ + return osr * 60; +} + +uint32_t rct_intermittent_cutoff(uint8_t osr) +{ + return osr * 30; +} + +void rct_insert(tjec* ec, int stuck) +{ + if (stuck) + { + ++ec->rct_count; + + if (ec->rct_count >= rct_permanent_cutoff(ec->osr)) + ec->health_failure |= RCT_FAILURE_PERMANENT; + else if (ec->rct_count >= rct_intermittent_cutoff(ec->osr)) + ec->health_failure |= RCT_FAILURE; + } + else + { + ec->rct_count = 0; + } +} + +// TJEC + +int tjec_is_stuck(tjec* ec, uint64_t delta) +{ + uint64_t delta2; + uint64_t delta3; + if (ec->lag_predictor) + { + delta2 = lag_delta2(ec, delta); + delta3 = lag_delta3(ec, delta2); + } + else + { + delta2 = delta - ec->prev_delta; + ec->prev_delta = delta; + delta3 = delta2 - ec->prev_delta2; + ec->prev_delta2 = delta2; + } + + apt_insert(ec, delta); + if (ec->lag_predictor) + lag_insert(ec, delta); + + if (!delta || !delta2 || !delta3) + { + rct_insert(ec, 1); + return 1; + } + + rct_insert(ec, 0); + return 0; +} + +uint32_t tjec_health_failure(tjec* ec) +{ + if (!ec->fips_enabled) + return 0; + return ec->health_failure; +} + +uint64_t tjec_loop_shuffle(tjec* ec, uint32_t bits, uint32_t min) +{ + uint64_t time_now = (uint64_t) temp_time(); + + uint64_t mask = (UINT64_C(1) << bits) - 1; + uint64_t shuffle = 0; + for (uint32_t i = 0; i < (((sizeof(time_now) << 3) + bits - 1) / bits); ++i) + { + shuffle ^= time_now & mask; + time_now = time_now >> bits; + } + return shuffle + (UINT64_C(1) << min); +} + +void tjec_hash_time(tjec* ec, uint64_t delta, int stuck) +{ + tjec_sha3 sha3; + + uint8_t temp[sizeof(((tjec_sha3*) 0)->partial)]; + memset(temp, 0, sizeof(temp)); + + uint64_t loop_count = tjec_loop_shuffle(ec, 1 + ((ec->flags >> 11) & 7), 0); + + sha3_256_init(&sha3); + for (uint64_t j = 0; j < loop_count; ++j) + { + sha3_update(&sha3, temp, 32); + sha3_update(&sha3, &ec->rct_count, sizeof(ec->rct_count)); + sha3_update(&sha3, &ec->apt_cutoff, sizeof(ec->apt_cutoff)); + sha3_update(&sha3, &ec->apt_observations, sizeof(ec->apt_observations)); + sha3_update(&sha3, &ec->apt_count, sizeof(ec->apt_count)); + sha3_update(&sha3, &ec->apt_base, sizeof(ec->apt_base)); + sha3_update(&sha3, &j, sizeof(j)); + sha3_final(&sha3, temp); + } + + if (stuck) + delta = 0; + + memcpy(temp + 32, &delta, sizeof(delta)); + sha3_update(&ec->sha3, temp, sizeof(temp)); + + memset(&sha3, 0, sizeof(sha3)); + memset(temp, 0, sizeof(temp)); +} + +static uint32_t xoshiro128starstar(uint32_t* s) +{ + const uint32_t result = rotl32(s[1] * 5, 7) * 9; + const uint32_t t = s[1] << 9; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + s[2] ^= t; + s[3] = rotl32(s[3], 11); + return result; +} + +void tjec_random_memory_access(tjec* ec) +{ + uint32_t prng_state[4] = { 0x8E93EEC0, 0xCE65608A, 0xA8D46B46, 0xE83CEF69 }; + + uint64_t loop_count = ec->base_acc_count + tjec_loop_shuffle(ec, 1 + ((ec->flags >> 8) & 7), 0); + + for (size_t i = 0; i < sizeof(prng_state) / sizeof(*prng_state); ++i) + { + prng_state[i] = (temp_time() & 0xFF) | ((temp_time() & 0xFF) << 8) | ((temp_time() & 0xFF) << 16) | ((temp_time() & 0xFF) << 24); + } + + for (uint64_t i = 0; i < loop_count; ++i) + { + atomic_uchar* pMem = ec->memory->memory + (xoshiro128starstar(prng_state) % ec->memory->size); + *pMem = *pMem + 1; + } +} + +void tjec_memory_access(tjec* ec) +{ + uint64_t loop_count = ec->base_acc_count + tjec_loop_shuffle(ec, 1 + ((ec->flags >> 8) & 7), 0); + + for (uint64_t i = 0; i < loop_count; ++i) + { + atomic_uchar* pMem = ec->memory->memory + ec->location; + *pMem = *pMem + 1; + + ec->location = ec->location + ec->memory->cell_size - 1; + ec->location = ec->location % ec->memory->size; + } +} + +int tjec_measure_jitter(tjec* ec, uint64_t* current_delta) +{ + if (ec->random_access) + tjec_random_memory_access(ec); + else + tjec_memory_access(ec); + + uint64_t time_now = temp_time(); + uint64_t delta = (time_now - ec->prev_time) / ec->common_time_gcd; + ec->prev_time = time_now; + + int stuck = tjec_is_stuck(ec, delta); + tjec_hash_time(ec, delta, stuck); + + if (current_delta) + *current_delta = delta; + return stuck; +} + +void tjec_random_data(tjec* ec) +{ + uint32_t bits_to_read = (256 + (ec->fips_enabled ? ENTROPY_SAFETY_FACTOR : 0)) * ec->osr; + + tjec_measure_jitter(ec, NULL); + + uint32_t k = 0; + while (!tjec_health_failure(ec)) + { + if (tjec_measure_jitter(ec, NULL)) + continue; + + if (++k >= bits_to_read) + break; + } +} + +void tjec_read_random_block(tjec* ec, void* dst, size_t size) +{ + uint8_t block[32]; + sha3_final(&ec->sha3, block); + if (size) + memcpy(dst, block, size); + sha3_update(&ec->sha3, block, sizeof(block)); + memset(block, 0, sizeof(block)); +} + +uint32_t tjec_find_common_time_gcd(tjec* ec) +{ + uint64_t gcd_history[1024]; + uint32_t time_backwards = 0; + uint32_t count_stuck = 0; + + const int CLEARCACHE = 100; + for (int i = -CLEARCACHE; i < 1024; ++i) + { + uint64_t delta = 0; + int stuck = tjec_measure_jitter(ec, &delta); + uint64_t end_time = ec->prev_time; + uint64_t start_time = end_time - delta; + if (!start_time || !end_time) + return TJEC_ENOTIME; + + if (!delta || (end_time == start_time)) + return TJEC_ECOARSETIME; + + if (i < 0) + continue; + + if (stuck) + ++count_stuck; + + if (end_time < start_time) + ++time_backwards; + + gcd_history[i] = delta; + } + + if (time_backwards > 3) + return TJEC_ENOMONOTONIC; + + uint32_t health_test = tjec_health_failure(ec); + if (health_test) + return (health_test & RCT_FAILURE) ? TJEC_ERCT : TJEC_EHEALTH; + + if (count_stuck > (1024 * 9) / 10) + return TJEC_ESTUCK; + + { + uint64_t running_gcd = gcd_history[0]; + uint64_t delta_sum = 0; + + for (size_t i = 1; i < 1024; ++i) + { + if (gcd_history[i] >= gcd_history[i - 1]) + delta_sum += gcd_history[i] - gcd_history[i - 1]; + else + delta_sum += gcd_history[i - 1] - gcd_history[i]; + running_gcd = gcd64(gcd_history[i], running_gcd); + } + + if ((delta_sum * ec->osr) < 1024) + return TJEC_EMINVARVAR; + if (running_gcd >= UINT32_MAX / 2) + return TJEC_ECOARSETIME; + + ec->common_time_gcd = running_gcd; + } + + return TJEC_ENOERR; +} + +uint64_t tjec_memory_size(uint64_t flags) +{ + uint64_t max_memory_size; + if ((flags & 0xF) == 0) + { + if (flags & TJEC_MEM_RANDOM_ACCESS) + max_memory_size = UINT64_C(1) << 17; + else + max_memory_size = CELL_SIZE * CELL_COUNT; + } + else + { + max_memory_size = UINT64_C(32) << (9 + (flags & 0xF)); + } + + uint64_t cache_memory_size = temp_l1_cache_size(); + uint64_t memory_size = (!cache_memory_size || max_memory_size < cache_memory_size) ? max_memory_size : cache_memory_size; + return memory_size; +} + +// SHA-3 + +#if SHA3_UNROLLED + +static void keccakp_1600(uint64_t* s) +{ + const uint8_t rols[24] = { 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 }; + const uint64_t iota_values[] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL }; + + uint64_t C[5], D[5]; + for (uint8_t round = 0; round < 24; ++round) + { + C[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20]; + C[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21]; + C[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22]; + C[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23]; + C[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24]; + D[0] = C[4] ^ rotl64(C[1], 1); + D[1] = C[0] ^ rotl64(C[2], 1); + D[2] = C[1] ^ rotl64(C[3], 1); + D[3] = C[2] ^ rotl64(C[4], 1); + D[4] = C[3] ^ rotl64(C[0], 1); + + uint64_t tmp = s[7]; + + s[0] = s[0] ^ D[0]; + s[7] = rotl64(s[10] ^ D[0], rols[9]); + s[10] = rotl64(s[1] ^ D[1], rols[0]); + s[1] = rotl64(s[6] ^ D[1], rols[5]); + s[6] = rotl64(s[9] ^ D[4], rols[8]); + s[9] = rotl64(s[22] ^ D[2], rols[21]); + s[22] = rotl64(s[14] ^ D[4], rols[13]); + s[14] = rotl64(s[20] ^ D[0], rols[19]); + s[20] = rotl64(s[2] ^ D[2], rols[1]); + s[2] = rotl64(s[12] ^ D[2], rols[11]); + s[12] = rotl64(s[13] ^ D[3], rols[12]); + s[13] = rotl64(s[19] ^ D[4], rols[18]); + s[19] = rotl64(s[23] ^ D[3], rols[22]); + s[23] = rotl64(s[15] ^ D[0], rols[14]); + s[15] = rotl64(s[4] ^ D[4], rols[3]); + s[4] = rotl64(s[24] ^ D[4], rols[23]); + s[24] = rotl64(s[21] ^ D[1], rols[20]); + s[21] = rotl64(s[8] ^ D[3], rols[7]); + s[8] = rotl64(s[16] ^ D[1], rols[15]); + s[16] = rotl64(s[5] ^ D[0], rols[4]); + s[5] = rotl64(s[3] ^ D[3], rols[2]); + s[3] = rotl64(s[18] ^ D[3], rols[17]); + s[18] = rotl64(s[17] ^ D[2], rols[16]); + s[17] = rotl64(s[11] ^ D[1], rols[10]); + s[11] = rotl64(tmp ^ D[2], rols[6]); + + C[0] = s[0]; + C[1] = s[5]; + C[2] = s[10]; + C[3] = s[15]; + C[4] = s[20]; + D[0] = s[1]; + D[1] = s[6]; + D[2] = s[11]; + D[3] = s[16]; + D[4] = s[21]; + s[0] ^= ~s[1] & s[2]; + s[1] ^= ~s[2] & s[3]; + s[2] ^= ~s[3] & s[4]; + s[3] ^= ~s[4] & C[0]; + s[4] ^= ~C[0] & D[0]; + s[5] ^= ~s[6] & s[7]; + s[6] ^= ~s[7] & s[8]; + s[7] ^= ~s[8] & s[9]; + s[8] ^= ~s[9] & C[1]; + s[9] ^= ~C[1] & D[1]; + s[10] ^= ~s[11] & s[12]; + s[11] ^= ~s[12] & s[13]; + s[12] ^= ~s[13] & s[14]; + s[13] ^= ~s[14] & C[2]; + s[14] ^= ~C[2] & D[2]; + s[15] ^= ~s[16] & s[17]; + s[16] ^= ~s[17] & s[18]; + s[17] ^= ~s[18] & s[19]; + s[18] ^= ~s[19] & C[3]; + s[19] ^= ~C[3] & D[3]; + s[20] ^= ~s[21] & s[22]; + s[21] ^= ~s[22] & s[23]; + s[22] ^= ~s[23] & s[24]; + s[23] ^= ~s[24] & C[4]; + s[24] ^= ~C[4] & D[4]; + + s[0] ^= iota_values[round]; + } +} + +#else + +static inline void keccakp_theta(uint64_t* s) +{ + uint64_t C[5], D[5]; + C[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20]; + C[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21]; + C[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22]; + C[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23]; + C[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24]; + D[0] = C[4] ^ rotl64(C[1], 1); + D[1] = C[0] ^ rotl64(C[2], 1); + D[2] = C[1] ^ rotl64(C[3], 1); + D[3] = C[2] ^ rotl64(C[4], 1); + D[4] = C[3] ^ rotl64(C[0], 1); + s[0] ^= D[0]; + s[1] ^= D[1]; + s[2] ^= D[2]; + s[3] ^= D[3]; + s[4] ^= D[4]; + s[5] ^= D[0]; + s[6] ^= D[1]; + s[7] ^= D[2]; + s[8] ^= D[3]; + s[9] ^= D[4]; + s[10] ^= D[0]; + s[11] ^= D[1]; + s[12] ^= D[2]; + s[13] ^= D[3]; + s[14] ^= D[4]; + s[15] ^= D[0]; + s[16] ^= D[1]; + s[17] ^= D[2]; + s[18] ^= D[3]; + s[19] ^= D[4]; + s[20] ^= D[0]; + s[21] ^= D[1]; + s[22] ^= D[2]; + s[23] ^= D[3]; + s[24] ^= D[4]; +} + +static inline void keccakp_rho(uint64_t* s) +{ + const uint8_t rols[24] = { 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 }; + s[1] = rotl64(s[1], rols[0]); + s[2] = rotl64(s[2], rols[1]); + s[3] = rotl64(s[3], rols[2]); + s[4] = rotl64(s[4], rols[3]); + s[5] = rotl64(s[5], rols[4]); + s[6] = rotl64(s[6], rols[5]); + s[7] = rotl64(s[7], rols[6]); + s[8] = rotl64(s[8], rols[7]); + s[9] = rotl64(s[9], rols[8]); + s[10] = rotl64(s[10], rols[9]); + s[11] = rotl64(s[11], rols[10]); + s[12] = rotl64(s[12], rols[11]); + s[13] = rotl64(s[13], rols[12]); + s[14] = rotl64(s[14], rols[13]); + s[15] = rotl64(s[15], rols[14]); + s[16] = rotl64(s[16], rols[15]); + s[17] = rotl64(s[17], rols[16]); + s[18] = rotl64(s[18], rols[17]); + s[19] = rotl64(s[19], rols[18]); + s[20] = rotl64(s[20], rols[19]); + s[21] = rotl64(s[21], rols[20]); + s[22] = rotl64(s[22], rols[21]); + s[23] = rotl64(s[23], rols[22]); + s[24] = rotl64(s[24], rols[23]); +} + +static inline void keccakp_pi(uint64_t* s) +{ + uint64_t tmp = s[21]; + s[0] = s[0]; + s[1] = s[6]; + s[2] = s[12]; + s[3] = s[18]; + s[4] = s[24]; + s[5] = s[3]; + s[6] = s[9]; + s[7] = s[10]; + s[8] = s[16]; + s[9] = s[22]; + s[10] = s[1]; + s[11] = s[7]; + s[12] = s[13]; + s[13] = s[19]; + s[14] = s[20]; + s[15] = s[4]; + s[16] = s[5]; + s[17] = s[11]; + s[18] = s[17]; + s[19] = s[23]; + s[20] = s[2]; + s[21] = s[8]; + s[22] = s[14]; + s[23] = s[15]; + s[24] = tmp; +} + +static inline void keccakp_chi(uint64_t* s) +{ + uint64_t t0[5], t1[5]; + t0[0] = s[0]; + t0[1] = s[5]; + t0[2] = s[10]; + t0[3] = s[15]; + t0[4] = s[20]; + t1[0] = s[1]; + t1[1] = s[6]; + t1[2] = s[11]; + t1[3] = s[16]; + t1[4] = s[21]; + s[0] ^= ~s[1] & s[2]; + s[5] ^= ~s[6] & s[7]; + s[10] ^= ~s[11] & s[12]; + s[15] ^= ~s[16] & s[17]; + s[20] ^= ~s[21] & s[22]; + s[1] ^= ~s[2] & s[3]; + s[6] ^= ~s[7] & s[8]; + s[11] ^= ~s[12] & s[13]; + s[16] ^= ~s[17] & s[18]; + s[21] ^= ~s[22] & s[23]; + s[2] ^= ~s[3] & s[4]; + s[7] ^= ~s[8] & s[9]; + s[12] ^= ~s[13] & s[14]; + s[17] ^= ~s[18] & s[19]; + s[22] ^= ~s[23] & s[24]; + s[3] ^= ~s[4] & t0[0]; + s[8] ^= ~s[9] & t0[1]; + s[13] ^= ~s[14] & t0[2]; + s[18] ^= ~s[19] & t0[3]; + s[23] ^= ~s[24] & t0[4]; + s[4] ^= ~t0[0] & t1[0]; + s[9] ^= ~t0[1] & t1[1]; + s[14] ^= ~t0[2] & t1[2]; + s[19] ^= ~t0[3] & t1[3]; + s[24] ^= ~t0[4] & t1[4]; +} + +static inline void keccakp_iota(uint64_t* s, uint8_t round) +{ + const uint64_t iota_values[] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL }; + s[0] ^= iota_values[round]; +} + +static void keccakp_1600(uint64_t* s) +{ + for (uint8_t round = 0; round < 24; ++round) + { + keccakp_theta(s); + keccakp_rho(s); + keccakp_pi(s); + keccakp_chi(s); + keccakp_iota(s, round); + } +} + +#endif + +void sha3_init(tjec_sha3* ctx) +{ + memset(ctx->state, 0, sizeof(ctx->state)); + ctx->msg_len = 0; +} + +void sha3_256_init(tjec_sha3* ctx) +{ + sha3_init(ctx); + ctx->r = 136; + ctx->rword = 136 / sizeof(uint64_t); + ctx->digest_size = 32; +} + +void sha3_update(tjec_sha3* ctx, const void* data, size_t size) +{ + const uint8_t* ptr = (const uint8_t*) data; + + size_t partial = ctx->msg_len % ctx->r; + ctx->msg_len += size; + if (partial) + { + size_t to_copy = ctx->r - partial; + if (size < to_copy) + { + memcpy(ctx->partial + partial, ptr, size); + return; + } + + memcpy(ctx->partial + partial, ptr, to_copy); + size -= to_copy; + ptr += to_copy; + + for (size_t i = 0; i < ctx->rword; ++i) + ctx->state[i] ^= ((uint64_t*) ctx->partial)[i]; + keccakp_1600(ctx->state); + } + + for (; size >= ctx->r; size -= ctx->r, ptr += ctx->r) + { + for (size_t i = 0; i < ctx->rword; ++i) + ctx->state[i] ^= ((uint64_t*) ptr)[i]; + keccakp_1600(ctx->state); + } + + if (size) + memcpy(ctx->partial, ptr, size); +} + +void sha3_final(tjec_sha3* ctx, void* digest) +{ + size_t partial = ctx->msg_len % ctx->r; + memset(ctx->partial + partial, 0, ctx->r - partial); + + ctx->partial[partial] = 0x06; + ctx->partial[ctx->r - 1] |= 0x80; + + for (size_t i = 0; i < ctx->rword; ++i) + ctx->state[i] ^= ((uint64_t*) ctx->partial)[i]; + keccakp_1600(ctx->state); + + memcpy(digest, ctx->state, ctx->digest_size); + memset(ctx->partial, 0, ctx->r); + sha3_init(ctx); +} \ No newline at end of file diff --git a/src/oboskrnl/net/tcp.c b/src/oboskrnl/net/tcp.c index 4d53863f..b5a2339d 100644 --- a/src/oboskrnl/net/tcp.c +++ b/src/oboskrnl/net/tcp.c @@ -37,6 +37,8 @@ #include +#include + DefineNetFreeSharedPtr static uint16_t tcp_chksum(const void *seg1, size_t sz_seg1, const void* seg2, size_t sz_seg2) @@ -201,8 +203,6 @@ obos_status NetH_SendTCPSegment(vnode* nic, tcp_connection* con, void* ent_ /* i return OBOS_STATUS_SUCCESS; } -uintptr_t mt_random(void); - void tx_tm_hnd(void* udata) { event* evnt = udata; @@ -352,7 +352,7 @@ PacketProcessSignature(TCP, ip_header*) con = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(tcp_connection), nullptr); con->state.rcv.nxt = be32_to_host(hdr->seq)+1; con->state.rcv.irs = be32_to_host(hdr->seq); - con->state.snd.iss = mt_random(); + con->state.snd.iss = random32(); con->state.snd.nxt = con->state.snd.iss + 1; con->state.snd.una = con->state.snd.iss; con->state.state_change_event = EVENT_INITIALIZE(EVENT_NOTIFICATION); @@ -1351,7 +1351,7 @@ static obos_status get_src_port(vnode* nic, ip_table_entry* ent, ip_addr dest, u // bru for (int i = 0; i < 0x10000; i++) { - *src_port = mt_random() % 0x10000 + 1; + *src_port = random16() + 1; key.src.port = *src_port; if (!RB_FIND(tcp_connection_tree, &nic->net_tables->tcp_outgoing_connections, &key)) { @@ -1405,7 +1405,7 @@ obos_status tcp_connect(socket_desc* socket, struct sockaddr* saddr, size_t addr s->connection->state.state = TCP_STATE_SYN_SENT; s->connection->state.rcv.wnd = s->connection->recv_buffer.size; s->connection->state.rcv.up = 0; - s->connection->state.snd.iss = (uint32_t)mt_random(); + s->connection->state.snd.iss = random32(); s->connection->state.snd.nxt = s->connection->state.snd.iss+1; s->connection->state.snd.una = s->connection->state.snd.iss; s->connection->state.snd.up = 0; diff --git a/src/oboskrnl/net/udp.c b/src/oboskrnl/net/udp.c index ba6c3c33..eb1ac3ba 100644 --- a/src/oboskrnl/net/udp.c +++ b/src/oboskrnl/net/udp.c @@ -42,6 +42,8 @@ DefineNetFreeSharedPtr #include +#include + static void pckt_onDeref(struct shared_ptr* ptr) { udp_recv_packet* pckt = ptr->obj; @@ -345,8 +347,6 @@ obos_status udp_bind(socket_desc* socket, struct sockaddr* saddr, size_t addrlen return OBOS_STATUS_SUCCESS; } -uintptr_t mt_random(); - obos_status udp_connect(socket_desc* socket, struct sockaddr* saddr, size_t addrlen) { struct sockaddr_in* addr = (void*)saddr; @@ -377,7 +377,7 @@ obos_status udp_connect(socket_desc* socket, struct sockaddr* saddr, size_t addr udp_port* found = nullptr; uint32_t i = 0; do { - ports->ports[0]->port = mt_random() % 0x10000 + 1; + ports->ports[0]->port = random16() + 1; found = RB_FIND(udp_port_tree, &source_interface->udp_ports,ports->ports[0]); } while(found && i++ < 0x10000); ports->read_event = &ports->ports[0]->recv_event; diff --git a/src/oboskrnl/scheduler/cpu_local.h b/src/oboskrnl/scheduler/cpu_local.h index b1e6f8de..45d87a34 100644 --- a/src/oboskrnl/scheduler/cpu_local.h +++ b/src/oboskrnl/scheduler/cpu_local.h @@ -8,6 +8,8 @@ #include +#include + #include #include @@ -44,6 +46,9 @@ typedef struct cpu_local struct cpu_local* curr; bool ever_yielded; + + tjec* tjec_state; + csprng* csprng_state; } cpu_local; extern DRV_EXPORT cpu_local* Core_CpuInfo; extern DRV_EXPORT size_t Core_CpuCount; diff --git a/src/oboskrnl/vfs/dummy_devices.c b/src/oboskrnl/vfs/dummy_devices.c index a21eb6a2..4d98896c 100644 --- a/src/oboskrnl/vfs/dummy_devices.c +++ b/src/oboskrnl/vfs/dummy_devices.c @@ -10,11 +10,16 @@ #include #include +#include #include #include +#include + #include +#include + #include #include #include @@ -22,83 +27,62 @@ #include -// shamelessly stolen from https://osdev.wiki/wiki/Random_Number_Generator#Mersenne_Twister - -#if OBOS_ARCHITECTURE_BITS == 32 -#define STATE_SIZE 624 -#define MIDDLE 397 -#define INIT_SHIFT 30 -#define INIT_FACT 1812433253 -#define TWIST_MASK 0x9908b0df -#define SHIFT1 11 -#define MASK1 0xffffffff -#define SHIFT2 7 -#define MASK2 0x9d2c5680 -#define SHIFT3 15 -#define MASK3 0xefc60000 -#define SHIFT4 18 -#else -#define STATE_SIZE 312 -#define MIDDLE 156 -#define INIT_SHIFT 62 -#define TWIST_MASK 0xb5026f5aa96619e9 -#define INIT_FACT 6364136223846793005 -#define SHIFT1 29 -#define MASK1 0x5555555555555555 -#define SHIFT2 17 -#define MASK2 0x71d67fffeda60000 -#define SHIFT3 37 -#define MASK3 0xfff7eee000000000 -#define SHIFT4 43 -#endif +//+ Random -#define LOWER_MASK 0x7fffffff -#define UPPER_MASK (~(uintptr_t)LOWER_MASK) -static uintptr_t state[STATE_SIZE]; -static size_t index = STATE_SIZE + 1; +static tjec_memory tjec_memory_state; -static void mt_seed(uintptr_t s) +uint8_t random8(void) { - index = STATE_SIZE; - state[0] = s; - for (size_t i = 1; i < STATE_SIZE; i++) - state[i] = (INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i; + struct cpu_local* local = CoreS_GetCPULocalPtr(); + + uint8_t value = 0; + int64_t res = local && local->csprng_state ? csprng_read_random(local->csprng_state, &value, sizeof(value)) : -1; + (void) res; + return value; } -static void twist(void) +uint16_t random16(void) { - for (size_t i = 0; i < STATE_SIZE; i++) - { - uintptr_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK); - x = (x >> 1) ^ (x & 1? TWIST_MASK : 0); - state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x; - } - index = 0; + struct cpu_local* local = CoreS_GetCPULocalPtr(); + + uint16_t value = 0; + int64_t res = local && local->csprng_state ? csprng_read_random(local->csprng_state, &value, sizeof(value)) : -1; + (void) res; + return value; } -uintptr_t mt_random(void) +uint32_t random32(void) { - if (index >= STATE_SIZE) - { - OBOS_ASSERT(index == STATE_SIZE || !"Generator never seeded"); - twist(); - } + struct cpu_local* local = CoreS_GetCPULocalPtr(); - uintptr_t y = state[index]; - y ^= (y >> SHIFT1) & MASK1; - y ^= (y << SHIFT2) & MASK2; - y ^= (y << SHIFT3) & MASK3; - y ^= y >> SHIFT4; + uint32_t value = 0; + int64_t res = local && local->csprng_state ? csprng_read_random(local->csprng_state, &value, sizeof(value)) : -1; + (void) res; + return value; +} + +uint64_t random64(void) +{ + struct cpu_local* local = CoreS_GetCPULocalPtr(); - index++; - return y; + uint64_t value = 0; + int64_t res = local && local->csprng_state ? csprng_read_random(local->csprng_state, &value, sizeof(value)) : -1; + (void) res; + return value; } -static uintptr_t random_seed() +bool random_buffer(void* buffer, size_t size) { - return CoreS_GetNativeTimerTick(); + struct cpu_local* local = CoreS_GetCPULocalPtr(); + + int64_t res = local && local->csprng_state ? csprng_read_random(local->csprng_state, buffer, size) : -1; + if (res < 0) + memset(buffer, 0, size); + return res >= 0; } +//- Random + enum { // /dev/null DUMMY_NULL = 1, @@ -160,10 +144,15 @@ static obos_status read_sync(dev_desc desc, void* buf, size_t blkCount, size_t b *nBlkRead = blkCount; break; case DUMMY_RANDOM: - for (size_t i = 0; i < blkCount / sizeof(mt_random()); i++) - ((uintptr_t*)buf)[i] = mt_random(); - if (nBlkRead) - *nBlkRead = blkCount; + if (random_buffer(buf, blkCount)) + { + if (nBlkRead) + *nBlkRead = blkCount; + } + else if (nBlkRead) + { + *nBlkRead = 0; + } break; case DUMMY_FB0: return OBOS_STATUS_INVALID_OPERATION; @@ -484,13 +473,205 @@ static void init_desc(dev_desc desc) VfsH_DirentAppendChild(parent, ent); } +static void init_random() +{ + uint64_t memory_flags = 0; + uint64_t tjec_flags = 0; + uint8_t tjec_osr = 1; + if (OBOS_GetOPTF("tjec-random-access")) + memory_flags |= TJEC_MEM_RANDOM_ACCESS; + { + uint64_t max_memory_size = OBOS_GetOPTD_Ex("tjec-max-memory-size", 0); + if (max_memory_size == 0) + memory_flags |= 0; // no-op hopefully + else if (max_memory_size <= 32 << 10) + memory_flags |= TJEC_MEM_32KIB; + else if (max_memory_size <= 64 << 10) + memory_flags |= TJEC_MEM_64KIB; + else if (max_memory_size <= 128 << 10) + memory_flags |= TJEC_MEM_128KIB; + else if (max_memory_size <= 256 << 10) + memory_flags |= TJEC_MEM_256KIB; + else if (max_memory_size <= 512 << 10) + memory_flags |= TJEC_MEM_512KIB; + else if (max_memory_size <= 1 << 20) + memory_flags |= TJEC_MEM_1MIB; + else if (max_memory_size <= 2 << 20) + memory_flags |= TJEC_MEM_2MIB; + else if (max_memory_size <= 4 << 20) + memory_flags |= TJEC_MEM_4MIB; + else if (max_memory_size <= 8 << 20) + memory_flags |= TJEC_MEM_8MIB; + else if (max_memory_size <= 16 << 20) + memory_flags |= TJEC_MEM_16MIB; + else if (max_memory_size <= 32 << 20) + memory_flags |= TJEC_MEM_32MIB; + else if (max_memory_size <= 64 << 20) + memory_flags |= TJEC_MEM_64MIB; + else if (max_memory_size <= 128 << 20) + memory_flags |= TJEC_MEM_128MIB; + else if (max_memory_size <= 256 << 20) + memory_flags |= TJEC_MEM_256MIB; + else + memory_flags |= TJEC_MEM_512MIB; + } + if (!OBOS_GetOPTF("tjec-no-fips")) + tjec_flags |= TJEC_USE_FIPS; + if (!OBOS_GetOPTF("tjec-no-lag-predictor")) + tjec_flags |= TJEC_USE_LAG_PREDICTOR; + { + uint64_t max_acc_loop_bits = OBOS_GetOPTD_Ex("tjec-max-acc-loop-bits", 7); + if (max_acc_loop_bits < 0) + max_acc_loop_bits = 1; + else if (max_acc_loop_bits > 8) + max_acc_loop_bits = 8; + switch (max_acc_loop_bits) + { + case 1: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_1; break; + case 2: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_2; break; + case 3: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_3; break; + case 4: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_4; break; + case 5: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_5; break; + case 6: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_6; break; + case 7: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_7; break; + case 8: tjec_flags |= TJEC_MAX_ACC_LOOP_BITS_8; break; + } + } + { + uint64_t max_hash_loop_bits = OBOS_GetOPTD_Ex("tjec-max-hash-loop-bits", 3); + if (max_hash_loop_bits < 1) + max_hash_loop_bits = 1; + else if (max_hash_loop_bits > 8) + max_hash_loop_bits = 8; + switch (max_hash_loop_bits) + { + case 1: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_1; break; + case 2: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_2; break; + case 3: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_3; break; + case 4: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_4; break; + case 5: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_5; break; + case 6: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_6; break; + case 7: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_7; break; + case 8: tjec_flags |= TJEC_MAX_HASH_LOOP_BITS_8; break; + } + } + { + uint64_t osr = OBOS_GetOPTD_Ex("tjec-osr", 1); + if (osr < 1) + osr = 1; + else if (osr > 255) + osr = 255; + tjec_osr = (uint8_t) osr; + } + uint32_t err = tjec_memory_init(&tjec_memory_state, memory_flags); + if (err) + { + switch (err) + { + case TJEC_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Invalid argument!"); break; + case TJEC_ENOMEM: OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC Memory: Not enough memory available!"); break; + case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_NOTIME???"); break; + case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_ECOARSETIME???"); break; + case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_ENOMONOTONIC???"); break; + case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_ERCT???"); break; + case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_EHEALTH???"); break; + case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_ESTUCK???"); break; + case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? TJEC_EMINVARVAR???"); break; + default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC Memory: Huh? Unknown error %u", err); break; + } + return; // Unreachable + } + OBOS_Log("TJEC Memory: Allocated %llu bytes of access memory\n", tjec_memory_get_size(&tjec_memory_state)); + + tjec* tjec_states = (tjec*) Mm_QuickVMAllocate(Core_CpuCount * sizeof(tjec), false); + if (!tjec_states) + { + OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC: Not enough memory available for %u cores", Core_CpuCount); + return; + } + csprng* csprng_states = (csprng*) Mm_QuickVMAllocate(Core_CpuCount * sizeof(csprng), false); + if (!csprng_states) + { + OBOS_Panic(OBOS_PANIC_NO_MEMORY, "CSPRNG: Not enough memory available for %u cores", Core_CpuCount); + return; + } + + err = tjec_pre_init_ex(tjec_states, &tjec_memory_state, tjec_flags, tjec_osr); + if (err) + { + switch (err) + { + case TJEC_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Invalid argument!"); break; + case TJEC_ENOMEM: OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC: Not enough memory available!"); break; + case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Non functional timer!"); break; + case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Timer too coarse!"); break; + case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Timer is not monotonic!"); break; + case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: RCT failure during pre-test!"); break; + case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Health Failure during pre-test 0x%08X", tjec_states->health_failure); break; + case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Bit generator got stuck during pre-test!"); break; + case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: OSR is unreasonable or something \\_(-_-)_/"); break; + default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Huh? Unknown error %u", err); break; + } + return; // Unreachable + } + OBOS_Log("TJEC: Pre initialized with Common Time GCD %llu\n", tjec_states->common_time_gcd); + + for (size_t i = 0; i < Core_CpuCount; ++i) + { + err = tjec_init_ex(&tjec_states[i], &tjec_memory_state, tjec_flags, tjec_osr); + if (err) + { + switch (err) + { + case TJEC_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Invalid argument!", i); break; + case TJEC_ENOMEM: OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC %llu: Not enough memory available!", i); break; + case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Non functional timer!", i); break; + case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Timer too coarse!", i); break; + case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Timer is not monotonic!", i); break; + case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: RCT failure during pre-test!", i); break; + case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Health Failure during pre-test 0x%08X", i, tjec_states[i].health_failure); break; + case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Bit generator got stuck during pre-test!", i); break; + case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: OSR is unreasonable or something \\_(-_-)_/", i); break; + default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Huh? Unknown error %u", i, err); break; + } + return; // Unreachable + } + + csprng_callbacks callbacks = (csprng_callbacks) { + .userdata = &tjec_states[i], + .read_entropy = &csprng_tjec_read_entropy, + }; + + err = csprng_init(&csprng_states[i], &callbacks, 0); + if (err) + { + switch (err) + { + case CSPRNG_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "CSPRNG %llu: Invalid argument!", i); break; + default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "CSPRNG %llu: Huh? Unknown error %u", i, err); break; + } + return; // Unreachable + } + } + + for (size_t i = 0; i < Core_CpuCount; ++i) + { + struct cpu_local* local = &Core_CpuInfo[i]; + + local->tjec_state = &tjec_states[i]; + local->csprng_state = &csprng_states[i]; + } + OBOS_Log("TJEC: Initialized\n"); + OBOS_Log("CSPRNG: Initialized\n"); +} + void Vfs_InitDummyDevices() { init_desc(DUMMY_NULL); init_desc(DUMMY_FULL); init_desc(DUMMY_ZERO); init_desc(DUMMY_FB0); - mt_seed(random_seed()); + init_random(); init_desc(DUMMY_RANDOM); } From dbfd65e7a877395ad45e784e0a6cf37b99d3e6e6 Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Thu, 8 Jan 2026 06:36:00 +0100 Subject: [PATCH 2/6] random: Implement AES128-CTR-DRBG --- src/oboskrnl/contrib/csprng.c | 242 +++++++++++++++++++++++++++++++++- src/oboskrnl/contrib/random.h | 26 ++-- 2 files changed, 253 insertions(+), 15 deletions(-) diff --git a/src/oboskrnl/contrib/csprng.c b/src/oboskrnl/contrib/csprng.c index 293dada0..906a6556 100644 --- a/src/oboskrnl/contrib/csprng.c +++ b/src/oboskrnl/contrib/csprng.c @@ -8,7 +8,20 @@ #include -// TODO: Make thread-safe +/* Helper functions: */ + +static inline uint32_t rotr32(uint32_t v, uint8_t s) +{ + return (v >> s) | (v << (32 - s)); +} + +static void ctr_drbg_instantiate(csprng* ctx); +static void ctr_drbg_reseed(csprng* ctx); +static void ctr_drbg_generate(csprng* ctx, void* output, size_t size); +static void ctr_drbg_update(const void* provided_data, void* key, void* v); + +static void aes128_key_expand(const void* key, void* keys); +static void aes_cipher(const void* keys, const void* in, void* out); size_t csprng_tjec_read_entropy(void* userdata, void* data, size_t size) { @@ -18,14 +31,17 @@ size_t csprng_tjec_read_entropy(void* userdata, void* data, size_t size) uint32_t csprng_init(csprng* ctx, const csprng_callbacks* callbacks, uint64_t flags) { - if (!ctx || !callbacks) + if (!ctx || !callbacks || !callbacks->read_entropy) return CSPRNG_EINVAL; memset(ctx, 0, sizeof(csprng)); - + + ctx->mtx = MUTEX_INITIALIZE(); memcpy(&ctx->callbacks, callbacks, sizeof(csprng_callbacks)); ctx->flags = flags; + ctr_drbg_instantiate(ctx); + return CSPRNG_ENOERR; } @@ -42,6 +58,222 @@ int64_t csprng_read_random(csprng* ctx, void* data, size_t size) if (!ctx || !data) return 0; - size_t read = ctx->callbacks.read_entropy(ctx->callbacks.userdata, data, size); - return (int64_t) read; + size_t orig_size = size; + uint8_t* ptr = (uint8_t*) data; + + while (size > 0) + { + size_t to_generate = size < 4096 ? size : 4096; + Core_MutexAcquire(&ctx->mtx); + ctr_drbg_generate(ctx, ptr, to_generate); + Core_MutexRelease(&ctx->mtx); + ptr += to_generate; + size -= to_generate; + } + return (int64_t) orig_size; +} + +// CTR DRBG + +void ctr_drbg_instantiate(csprng* ctx) +{ + memset(ctx->v, 0, sizeof(ctx->v)); + memset(ctx->key, 0, sizeof(ctx->key)); + ctr_drbg_reseed(ctx); +} + +void ctr_drbg_reseed(csprng* ctx) +{ + uint8_t seed_material[32]; + size_t read = ctx->callbacks.read_entropy(ctx->callbacks.userdata, seed_material, sizeof(seed_material)); + + ctr_drbg_update(seed_material, ctx->key, ctx->v); + ctx->reseed_counter = 1; + + memset(seed_material, 0, sizeof(seed_material)); +} + +void ctr_drbg_generate(csprng* ctx, void* output, size_t size) +{ + const uint64_t reseed_interval = 16; + + uint8_t temp[32]; + + if (ctx->reseed_counter > reseed_interval) + ctr_drbg_reseed(ctx); + + uint8_t keys[16*11]; + aes128_key_expand(ctx->key, keys); + uint8_t* p_out = (uint8_t*) output; + + while (size > 0) + { + if (*(uint64_t*) ctx->v == ~((uint64_t)0)) + { + ((uint64_t*) ctx->v)[0] = 0; + ++((uint64_t*) ctx->v)[1]; + } + else + { + ++((uint64_t*) ctx->v)[0]; + } + aes_cipher(keys, ctx->v, temp); + size_t to_copy = size < 16 ? size : 16; + memcpy(p_out, temp, to_copy); + p_out += to_copy; + size -= to_copy; + } + memset(keys, 0, sizeof(keys)); + memset(temp, 0, sizeof(temp)); + ctr_drbg_update(temp, ctx->key, ctx->v); + ++ctx->reseed_counter; +} + +void ctr_drbg_update(const void* provided_data, void* key, void* v) +{ + uint8_t keys[16*11]; + aes128_key_expand(key, keys); + aes_cipher(keys, v, key); + if (*(uint64_t*) v == ~((uint64_t)0)) + { + ((uint64_t*) v)[0] = 0; + ++((uint64_t*) v)[1]; + } + else + { + ++((uint64_t*) v)[0]; + } + aes_cipher(keys, v, v); + ((uint64_t*) key)[0] ^= ((uint64_t*) provided_data)[0]; + ((uint64_t*) key)[1] ^= ((uint64_t*) provided_data)[1]; + ((uint64_t*) v)[0] ^= ((uint64_t*) provided_data)[2]; + ((uint64_t*) v)[1] ^= ((uint64_t*) provided_data)[3]; + memset(keys, 0, sizeof(keys)); +} + +// AES-128 + +static const _Alignas(64) uint8_t SBOX_MAT[16][16] = { + { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76 }, + { 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0 }, + { 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15 }, + { 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75 }, + { 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84 }, + { 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF }, + { 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8 }, + { 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2 }, + { 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73 }, + { 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB }, + { 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79 }, + { 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08 }, + { 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A }, + { 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E }, + { 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF }, + { 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 } +}; +static const uint8_t* SBOX = (const uint8_t*) SBOX_MAT; + +typedef union aes_block { + uint8_t bytes[16]; + uint32_t words[4]; + uint64_t quads[2]; +} aes_block; + +void aes128_key_expand(const void* key, void* keys) +{ + const uint8_t Rcon[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }; + uint8_t* p_bytes = (uint8_t*) keys; + memcpy(p_bytes, key, 16); + for (uint8_t i = 0; i < 10; ++i) + { + p_bytes[16 + i * 16] = p_bytes[0 + i * 16] ^ SBOX[p_bytes[13 + i * 16]] ^ Rcon[i]; + p_bytes[17 + i * 16] = p_bytes[1 + i * 16] ^ SBOX[p_bytes[14 + i * 16]]; + p_bytes[18 + i * 16] = p_bytes[2 + i * 16] ^ SBOX[p_bytes[15 + i * 16]]; + p_bytes[19 + i * 16] = p_bytes[3 + i * 16] ^ SBOX[p_bytes[12 + i * 16]]; + + p_bytes[20 + i * 16] = p_bytes[4 + i * 16] ^ p_bytes[16 + i * 16]; + p_bytes[21 + i * 16] = p_bytes[5 + i * 16] ^ p_bytes[17 + i * 16]; + p_bytes[22 + i * 16] = p_bytes[6 + i * 16] ^ p_bytes[18 + i * 16]; + p_bytes[23 + i * 16] = p_bytes[7 + i * 16] ^ p_bytes[19 + i * 16]; + + p_bytes[24 + i * 16] = p_bytes[8 + i * 16] ^ p_bytes[20 + i * 16]; + p_bytes[25 + i * 16] = p_bytes[9 + i * 16] ^ p_bytes[21 + i * 16]; + p_bytes[26 + i * 16] = p_bytes[10 + i * 16] ^ p_bytes[22 + i * 16]; + p_bytes[27 + i * 16] = p_bytes[11 + i * 16] ^ p_bytes[23 + i * 16]; + + p_bytes[28 + i * 16] = p_bytes[12 + i * 16] ^ p_bytes[24 + i * 16]; + p_bytes[29 + i * 16] = p_bytes[13 + i * 16] ^ p_bytes[25 + i * 16]; + p_bytes[30 + i * 16] = p_bytes[14 + i * 16] ^ p_bytes[26 + i * 16]; + p_bytes[31 + i * 16] = p_bytes[15 + i * 16] ^ p_bytes[27 + i * 16]; + } +} + +void aes_cipher(const void* keys, const void* in, void* out) +{ + const aes_block* key_blocks = (const aes_block*) keys; + aes_block* block_out = (aes_block*) out; + memcpy(block_out, in, 16); + + block_out->quads[0] ^= key_blocks[0].quads[0]; + block_out->quads[1] ^= key_blocks[0].quads[1]; + for (size_t i = 1; i < 10; ++i) + { + for (size_t j = 0; j < 16; ++j) + block_out->bytes[j] = SBOX[block_out->bytes[j]]; + + uint8_t tmp = block_out->bytes[1]; + block_out->bytes[1] = block_out->bytes[5]; + block_out->bytes[5] = block_out->bytes[9]; + block_out->bytes[9] = block_out->bytes[13]; + block_out->bytes[13] = tmp; + tmp = block_out->bytes[2]; + block_out->bytes[2] = block_out->bytes[10]; + block_out->bytes[10] = tmp; + tmp = block_out->bytes[6]; + block_out->bytes[6] = block_out->bytes[14]; + block_out->bytes[14] = tmp; + tmp = block_out->bytes[15]; + block_out->bytes[15] = block_out->bytes[11]; + block_out->bytes[11] = block_out->bytes[7]; + block_out->bytes[7] = block_out->bytes[3]; + block_out->bytes[3] = tmp; + + for (uint8_t c = 0; c < 4; ++c) + { + uint32_t column = block_out->words[c]; + uint32_t column2 = ((column & 0x7F7F7F7F) << 1) ^ (((column >> 7) & 0x01010101) * 0x1B); + uint32_t column3 = rotr32(column, 8); + uint32_t column4 = rotr32(column2, 8); + uint32_t column5 = rotr32(column, 16); + uint32_t column6 = rotr32(column, 24); + + block_out->words[c] = column2 ^ column3 ^ column4 ^ column5 ^ column6; + } + + block_out->quads[0] ^= key_blocks[i].quads[0]; + block_out->quads[1] ^= key_blocks[i].quads[1]; + } + + for (size_t j = 0; j < 16; ++j) + block_out->bytes[j] = SBOX[block_out->bytes[j]]; + + uint8_t tmp = block_out->bytes[1]; + block_out->bytes[1] = block_out->bytes[5]; + block_out->bytes[5] = block_out->bytes[9]; + block_out->bytes[9] = block_out->bytes[13]; + block_out->bytes[13] = tmp; + tmp = block_out->bytes[2]; + block_out->bytes[2] = block_out->bytes[10]; + block_out->bytes[10] = tmp; + tmp = block_out->bytes[6]; + block_out->bytes[6] = block_out->bytes[14]; + block_out->bytes[14] = tmp; + tmp = block_out->bytes[15]; + block_out->bytes[15] = block_out->bytes[11]; + block_out->bytes[11] = block_out->bytes[7]; + block_out->bytes[7] = block_out->bytes[3]; + block_out->bytes[3] = tmp; + + block_out->quads[0] ^= key_blocks[10].quads[0]; + block_out->quads[1] ^= key_blocks[10].quads[1]; } \ No newline at end of file diff --git a/src/oboskrnl/contrib/random.h b/src/oboskrnl/contrib/random.h index 59217f06..6690416d 100644 --- a/src/oboskrnl/contrib/random.h +++ b/src/oboskrnl/contrib/random.h @@ -16,7 +16,7 @@ typedef struct tjec_sha3 uint16_t r; uint16_t rword; uint16_t digest_size; - uint8_t partial[136]; + uint8_t partial[136]; uint64_t state[25]; uint64_t msg_len; } tjec_sha3; @@ -24,9 +24,9 @@ typedef struct tjec_sha3 typedef struct tjec_memory { atomic_uchar* memory; - size_t cell_size; - size_t size; - uint64_t flags; + size_t cell_size; + size_t size; + uint64_t flags; } tjec_memory; typedef struct tjec @@ -35,11 +35,11 @@ typedef struct tjec uint32_t health_failure; uint16_t base_acc_count; - uint8_t osr; - uint8_t apt_base_set : 1; - uint8_t fips_enabled : 1; - uint8_t random_access : 1; - uint8_t lag_predictor : 1; + uint8_t osr; + uint8_t apt_base_set : 1; + uint8_t fips_enabled : 1; + uint8_t random_access : 1; + uint8_t lag_predictor : 1; uint64_t flags; uint64_t prev_time; @@ -49,7 +49,7 @@ typedef struct tjec uint64_t common_time_gcd; const tjec_memory* memory; - size_t location; + size_t location; uint64_t apt_base; uint32_t apt_count; @@ -79,9 +79,15 @@ typedef struct csprng_callbacks typedef struct csprng { + mutex mtx; + csprng_callbacks callbacks; uint64_t flags; + + uint64_t reseed_counter; + uint8_t v[16]; + uint8_t key[16]; } csprng; static const uint64_t TJEC_MEM_32KIB = 1; From 7dc240383349372593eecc1d9b472cff87f025c9 Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Thu, 8 Jan 2026 06:46:11 +0100 Subject: [PATCH 3/6] misc: Add contrib/tjec.c and contrib/csprng.c to oboskrnl/CMakeLists.txt --- src/oboskrnl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oboskrnl/CMakeLists.txt b/src/oboskrnl/CMakeLists.txt index 191027ca..04294c44 100644 --- a/src/oboskrnl/CMakeLists.txt +++ b/src/oboskrnl/CMakeLists.txt @@ -22,7 +22,7 @@ list (APPEND oboskrnl_sources "init_proc.c" "vfs/create.c" "net/route.c" "net/eth.c" "net/ip.c" "net/arp.c" "power/event.c" "net/udp.c" "net/icmp.c" "net/tcp.c" "vfs/socket.c" "net/lo.c" - "kinit.c" "vfs/local_socket.c" "perm.c" + "kinit.c" "vfs/local_socket.c" "perm.c" "contrib/tjec.c" "contrib/csprng.c" ) add_executable(oboskrnl) From aa4b588b91fc062db71674af146ea41f411a4dfe Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Fri, 9 Jan 2026 02:39:40 +0100 Subject: [PATCH 4/6] misc: Add help messages for tjec command options --- src/oboskrnl/cmdline.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/oboskrnl/cmdline.c b/src/oboskrnl/cmdline.c index 0146378f..3a510704 100644 --- a/src/oboskrnl/cmdline.c +++ b/src/oboskrnl/cmdline.c @@ -47,6 +47,13 @@ static const char* const help_message = "--pnp-module-path=pathspec: Where to find kernel modules for PnP during kernel init.\n" "--disable-libc-log: Disables the logs from the C library (see Sys_LibcLog) .\n" "--disable-syscall-error-log: Makes all syscall logs happen at DEBUG level.\n" +"--tjec-random-access: Makes the underlying TJEC memory accessing randomized.\n" +"--tjec-max-memory-size=bytes: Specifies the maximum amount of memory TJEC is allowed to allocate.\n" +"--tjec-no-fips: Tells TJEC to not over sample per block of bits generated.\n" +"--tjec-no-lag-predictor: Disables TJEC LAG Predictor health checks.\n" +"--tjec-max-acc-loop-bits=<1-8>: Specifies a maximum number of random additional memory accesses TJEC makes per block in 2^k, default k=7 or 128.\n" +"--tjec-max-hash-loop-bits=<1-8>: Specifies a maximum number of random additional hash iterations TJEC makes per block in 2^k, default k=3 or 8.\n" +"--tjec-osr=<1-255>: Specifies the over sampling ratio for TJEC, in other words, how many blocks to collect per block generated.\n" "--help: Displays this help message.\n"; struct cmd_allocation_header From 6fe13445dacc1d6e8b732459922a597618866db7 Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Fri, 9 Jan 2026 02:40:08 +0100 Subject: [PATCH 5/6] misc: Fix mistakes with TJEC --- src/oboskrnl/contrib/tjec.c | 7 +++++-- src/oboskrnl/vfs/dummy_devices.c | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/oboskrnl/contrib/tjec.c b/src/oboskrnl/contrib/tjec.c index b895e667..4e92b9b7 100644 --- a/src/oboskrnl/contrib/tjec.c +++ b/src/oboskrnl/contrib/tjec.c @@ -42,7 +42,7 @@ static uint64_t temp_time() #if __x86_64__ return rdtsc(); #else - return CoreS_GetNativeTimerTick(); + return CoreS_GetTimerTick(); #endif } @@ -130,7 +130,7 @@ uint32_t tjec_memory_init(tjec_memory* mem, uint64_t flags) uint64_t memory_size = tjec_memory_size(flags); - mem->memory = (atomic_uchar*) Mm_QuickVMAllocate(memory_size, true); + mem->memory = (atomic_uchar*) Mm_QuickVMAllocate(memory_size, false); mem->cell_size = CELL_SIZE; mem->size = memory_size; mem->flags = flags; @@ -308,7 +308,10 @@ int64_t tjec_read_entropy_safe(tjec* ec, void* data, size_t size) uint64_t flags = ec->flags; if (osr > 20) + { + Core_MutexRelease(&ec->mtx); return ret; + } while (tjec_init_ex(ec, mem, flags, (uint8_t) osr)) { diff --git a/src/oboskrnl/vfs/dummy_devices.c b/src/oboskrnl/vfs/dummy_devices.c index 4d98896c..741731a1 100644 --- a/src/oboskrnl/vfs/dummy_devices.c +++ b/src/oboskrnl/vfs/dummy_devices.c @@ -603,13 +603,13 @@ static void init_random() { case TJEC_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Invalid argument!"); break; case TJEC_ENOMEM: OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC: Not enough memory available!"); break; - case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Non functional timer!"); break; - case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Timer too coarse!"); break; - case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Timer is not monotonic!"); break; - case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: RCT failure during pre-test!"); break; - case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Health Failure during pre-test 0x%08X", tjec_states->health_failure); break; - case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: Bit generator got stuck during pre-test!"); break; - case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC: OSR is unreasonable or something \\_(-_-)_/"); break; + case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Non functional timer!"); break; + case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Timer too coarse!"); break; + case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Timer is not monotonic!"); break; + case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: RCT failure during pre-test!"); break; + case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Health Failure during pre-test 0x%08X", tjec_states->health_failure); break; + case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Bit generator got stuck during pre-test!"); break; + case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: OSR is unreasonable or something \\_(-_-)_/"); break; default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC: Huh? Unknown error %u", err); break; } return; // Unreachable @@ -625,13 +625,13 @@ static void init_random() { case TJEC_EINVAL: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Invalid argument!", i); break; case TJEC_ENOMEM: OBOS_Panic(OBOS_PANIC_NO_MEMORY, "TJEC %llu: Not enough memory available!", i); break; - case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Non functional timer!", i); break; - case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Timer too coarse!", i); break; - case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Timer is not monotonic!", i); break; - case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: RCT failure during pre-test!", i); break; - case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Health Failure during pre-test 0x%08X", i, tjec_states[i].health_failure); break; - case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: Bit generator got stuck during pre-test!", i); break; - case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_EXCEPTION, "TJEC %llu: OSR is unreasonable or something \\_(-_-)_/", i); break; + case TJEC_ENOTIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Non functional timer!", i); break; + case TJEC_ECOARSETIME: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Timer too coarse!", i); break; + case TJEC_ENOMONOTONIC: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Timer is not monotonic!", i); break; + case TJEC_ERCT: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: RCT failure during pre-test!", i); break; + case TJEC_EHEALTH: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Health Failure during pre-test 0x%08X", i, tjec_states[i].health_failure); break; + case TJEC_ESTUCK: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Bit generator got stuck during pre-test!", i); break; + case TJEC_EMINVARVAR: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: OSR is unreasonable or something \\_(-_-)_/", i); break; default: OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "TJEC %llu: Huh? Unknown error %u", i, err); break; } return; // Unreachable From 5fe6ad8aca7eddf1dd47439aa6bcf011b8e822cc Mon Sep 17 00:00:00 2001 From: MarcasRealAccount Date: Fri, 9 Jan 2026 03:10:31 +0100 Subject: [PATCH 6/6] misc: Use CoreS_GetNativeTimerTick() instead of temp_time() in TJEC --- src/oboskrnl/contrib/csprng.c | 1 + src/oboskrnl/contrib/tjec.c | 19 +++++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/oboskrnl/contrib/csprng.c b/src/oboskrnl/contrib/csprng.c index 906a6556..08db1749 100644 --- a/src/oboskrnl/contrib/csprng.c +++ b/src/oboskrnl/contrib/csprng.c @@ -86,6 +86,7 @@ void ctr_drbg_reseed(csprng* ctx) { uint8_t seed_material[32]; size_t read = ctx->callbacks.read_entropy(ctx->callbacks.userdata, seed_material, sizeof(seed_material)); + (void) read; ctr_drbg_update(seed_material, ctx->key, ctx->v); ctx->reseed_counter = 1; diff --git a/src/oboskrnl/contrib/tjec.c b/src/oboskrnl/contrib/tjec.c index 4e92b9b7..64c9be97 100644 --- a/src/oboskrnl/contrib/tjec.c +++ b/src/oboskrnl/contrib/tjec.c @@ -37,15 +37,6 @@ # include #endif -static uint64_t temp_time() -{ -#if __x86_64__ - return rdtsc(); -#else - return CoreS_GetTimerTick(); -#endif -} - static uint64_t temp_l1_cache_size() { #if __x86_64__ @@ -547,7 +538,8 @@ uint32_t tjec_health_failure(tjec* ec) uint64_t tjec_loop_shuffle(tjec* ec, uint32_t bits, uint32_t min) { - uint64_t time_now = (uint64_t) temp_time(); + (void) ec; + uint64_t time_now = (uint64_t) CoreS_GetNativeTimerTick(); uint64_t mask = (UINT64_C(1) << bits) - 1; uint64_t shuffle = 0; @@ -613,7 +605,10 @@ void tjec_random_memory_access(tjec* ec) for (size_t i = 0; i < sizeof(prng_state) / sizeof(*prng_state); ++i) { - prng_state[i] = (temp_time() & 0xFF) | ((temp_time() & 0xFF) << 8) | ((temp_time() & 0xFF) << 16) | ((temp_time() & 0xFF) << 24); + // It is very likely prng_state[i] = v & 0xFF | ((v & 0xFF) << 8) | ((v & 0xFF) << 16) | ((v & 0xFF) << 24), i.e. same byte repeated, because taking the time and doing bitwise and + shift left shouldn't generally cost enough to cause timer increments. + // for that reason, the following code is commented out, and replaced with a broadcast instead. + // prng_state[i] = (CoreS_GetNativeTimerTick() & 0xFF) | ((CoreS_GetTimerTick() & 0xFF) << 8) | ((CoreS_GetTimerTick() & 0xFF) << 16) | ((CoreS_GetTimerTick() & 0xFF) << 24); + prng_state[i] = (CoreS_GetNativeTimerTick() & 0xFF) * 0x01010101; } for (uint64_t i = 0; i < loop_count; ++i) @@ -644,7 +639,7 @@ int tjec_measure_jitter(tjec* ec, uint64_t* current_delta) else tjec_memory_access(ec); - uint64_t time_now = temp_time(); + uint64_t time_now = (uint64_t) CoreS_GetNativeTimerTick(); uint64_t delta = (time_now - ec->prev_time) / ec->common_time_gcd; ec->prev_time = time_now;