Last active
September 14, 2025 05:35
-
-
Save opsec-ee/623fb12bdb9a31cc011d5c13668e0a8d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * ISAAC CSPRNG High-Performance Implementation v2.0.0 | |
| * | |
| * Based on Bob Jenkins' ISAAC algorithm (1993) - Public Domain | |
| * | |
| * Version: 2.0.0 - H.Overman <opsec.ee@pm.me> | |
| * Date: 2025-01-13 | |
| * License: Public Domain (following original ISAAC license) | |
| */ | |
| #define _GNU_SOURCE | |
| #include <errno.h> | |
| #include <limits.h> | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <time.h> | |
| /* ============================================================================ | |
| * VERSION INFORMATION | |
| * ============================================================================ | |
| */ | |
| #define ISAAC_VERSION_MAJOR 2U | |
| #define ISAAC_VERSION_MINOR 0U | |
| #define ISAAC_VERSION_PATCH 0U | |
| #define ISAAC_VERSION_STRING "2.0.0" | |
| /* ============================================================================ | |
| * COMPILER OPTIMIZATION HINTS | |
| * ============================================================================ | |
| */ | |
| #ifdef __GNUC__ | |
| #define LIKELY(x) __builtin_expect(!!(x), 1) | |
| #define UNLIKELY(x) __builtin_expect(!!(x), 0) | |
| #define FORCE_INLINE __attribute__((always_inline)) inline | |
| #define RESTRICT __restrict__ | |
| #define CACHE_ALIGN __attribute__((aligned(CACHE_LINE_SIZE))) | |
| #define PREFETCH_READ(addr) __builtin_prefetch(addr, 0, 3) | |
| #define PREFETCH_WRITE(addr) __builtin_prefetch(addr, 1, 3) | |
| #define UNUSED __attribute__((unused)) | |
| #define PACKED __attribute__((packed)) | |
| #else | |
| #define LIKELY(x) (x) | |
| #define UNLIKELY(x) (x) | |
| #define FORCE_INLINE inline | |
| #define RESTRICT | |
| #define CACHE_ALIGN | |
| #define PREFETCH_READ(addr) ((void)0) | |
| #define PREFETCH_WRITE(addr) ((void)0) | |
| #define UNUSED | |
| #define PACKED | |
| #endif | |
| /* ============================================================================ | |
| * SYSTEM CONSTANTS - No Magic Numbers (OPT-000: TS-001) | |
| * ============================================================================ | |
| */ | |
| #define CACHE_LINE_SIZE 64U | |
| #define BITS_PER_BYTE 8U | |
| #define HEX_CHARS_PER_BYTE 2U | |
| #define UINT32_BYTES 4U | |
| /* ============================================================================ | |
| * ISAAC ALGORITHM CONSTANTS | |
| * ============================================================================ | |
| */ | |
| #define ISAAC_STATE_SIZE 256U | |
| #define ISAAC_RESULT_SIZE 256U | |
| #define ISAAC_GOLDEN_RATIO 0x9E3779B9U | |
| #define ISAAC_LOG_SIZE 8U | |
| #define ISAAC_MASK 0xFFU | |
| /* ASCII printable range */ | |
| #define ISAAC_ASCII_START 32U | |
| #define ISAAC_ASCII_RANGE 95U | |
| #define ISAAC_ASCII_END 126U | |
| /* Unrolling factors */ | |
| #define ISAAC_UNROLL_FACTOR 4U | |
| #define ISAAC_MIX_UNROLL 8U | |
| #define ISAAC_PREFETCH_DIST 32U | |
| /* Shift constants */ | |
| #define ISAAC_SHIFT1 13U | |
| #define ISAAC_SHIFT2 6U | |
| #define ISAAC_SHIFT3 2U | |
| #define ISAAC_SHIFT4 16U | |
| #define ISAAC_INDEX_SHIFT 2U | |
| #define ISAAC_RESULT_SHIFT 10U | |
| /* Buffer sizes */ | |
| #define MAX_MESSAGE_SIZE 8192U | |
| #define HEX_BUFFER_SIZE ((MAX_MESSAGE_SIZE * HEX_CHARS_PER_BYTE) + 1U) | |
| /* FUTURE USE: B-tree Integration Constants */ | |
| #define BTREE_PAGE_SIZE 4096U | |
| #define BTREE_KEY_SIZE 32U | |
| #define BTREE_MAC_SIZE 16U | |
| #define BTREE_NONCE_SIZE 16U | |
| /* ============================================================================ | |
| * TYPE DEFINITIONS (OPT-000: NC-002) | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Error codes for ISAAC operations | |
| */ | |
| typedef enum isaac_error { | |
| ISAAC_SUCCESS = 0, | |
| ISAAC_ERROR_NULL_PARAM = -1, | |
| ISAAC_ERROR_INVALID_SIZE = -2, | |
| ISAAC_ERROR_INVALID_HEX = -3, | |
| ISAAC_ERROR_OVERFLOW = -4, | |
| ISAAC_ERROR_NOMEM = -5 | |
| } isaac_error_e; | |
| /** | |
| * @brief ISAAC CSPRNG state structure | |
| * @note Cache-aligned for optimal performance (OPT-041) | |
| */ | |
| typedef struct isaac_state { | |
| uint32_t mem[ISAAC_STATE_SIZE] CACHE_ALIGN; /**< [in,out] Internal state */ | |
| uint32_t rnd[ISAAC_RESULT_SIZE] CACHE_ALIGN; /**< [out] Results array */ | |
| uint32_t cnt; /**< [in,out] Result counter */ | |
| uint32_t acc; /**< [in,out] Accumulator */ | |
| uint32_t bux; /**< [in,out] Secondary acc */ | |
| uint32_t ctr; /**< [in,out] Counter */ | |
| /* FUTURE USE: B-tree Integration Fields */ | |
| /* uint64_t total_bytes_generated; */ /**< Statistics tracking */ | |
| /* uint32_t reseed_counter; */ /**< Auto-reseed tracking */ | |
| /* uint8_t btree_node_id[BTREE_KEY_SIZE]; */ /**< Node-specific seed */ | |
| } isaac_state_t; | |
| /** | |
| * @brief Performance measurement structure | |
| */ | |
| #ifdef __x86_64__ | |
| typedef struct perf_counter { | |
| uint64_t start_cycles; | |
| uint64_t total_cycles; | |
| uint32_t call_count; | |
| uint32_t padding; | |
| } perf_counter_t; | |
| #else | |
| typedef struct perf_counter { | |
| uint64_t start_ns; | |
| uint64_t total_ns; | |
| uint32_t call_count; | |
| uint32_t padding; | |
| } perf_counter_t; | |
| #endif | |
| /* FUTURE USE: B-tree Cryptographic Context | |
| typedef struct btree_crypto { | |
| isaac_state_t key_gen; // Key generation | |
| isaac_state_t encrypt; // Data encryption | |
| isaac_state_t mac_gen; // MAC generation | |
| uint8_t master_key[32]; // Master key | |
| uint8_t current_nonce[16]; // Current nonce | |
| } btree_crypto_t; | |
| */ | |
| /* ============================================================================ | |
| * GLOBAL STATE (OPT-000: ID-003) | |
| * ============================================================================ | |
| */ | |
| /* OPT-033: Global State Management */ | |
| static isaac_state_t g_isaac CACHE_ALIGN = {0}; | |
| /* OPT-012: Pre-allocated buffers */ | |
| static char g_hex_buffer[HEX_BUFFER_SIZE] CACHE_ALIGN = {0}; | |
| static char g_message_buffer[MAX_MESSAGE_SIZE] CACHE_ALIGN = {0}; | |
| /* Performance counters */ | |
| static perf_counter_t g_gen_counter = {0}; | |
| static perf_counter_t g_encrypt_counter = {0}; | |
| static perf_counter_t g_decrypt_counter = {0}; | |
| /* OPT-003: Lookup table for hex conversion */ | |
| static const char HEX_CHARS[16] = "0123456789ABCDEF"; | |
| /* Hex decode table (-1 for invalid) */ | |
| static const int8_t HEX_DECODE[256] = { | |
| ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, ['5'] = 5, | |
| ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9, ['A'] = 10, ['B'] = 11, | |
| ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15, ['a'] = 10, ['b'] = 11, | |
| ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15}; | |
| /* ============================================================================ | |
| * PERFORMANCE TIMING (PERF-002) | |
| * ============================================================================ | |
| */ | |
| #ifdef __x86_64__ | |
| /** | |
| * @brief Read x86-64 timestamp counter | |
| * @return Current CPU cycle count | |
| */ | |
| static FORCE_INLINE uint64_t rdtsc(void) | |
| { | |
| uint32_t low = 0U; | |
| uint32_t high = 0U; | |
| __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); | |
| return ((uint64_t)high << 32U) | (uint64_t)low; | |
| } | |
| static FORCE_INLINE void perf_start(perf_counter_t *RESTRICT ctr) | |
| { | |
| ctr->start_cycles = rdtsc(); | |
| } | |
| static FORCE_INLINE uint64_t perf_end(perf_counter_t *RESTRICT ctr) | |
| { | |
| const uint64_t end_cycles = rdtsc(); | |
| const uint64_t elapsed = end_cycles - ctr->start_cycles; | |
| ctr->total_cycles += elapsed; | |
| ctr->call_count++; | |
| return elapsed; | |
| } | |
| #else | |
| static FORCE_INLINE void perf_start(perf_counter_t *RESTRICT ctr) | |
| { | |
| struct timespec tms = {0}; | |
| (void)clock_gettime(CLOCK_MONOTONIC, &tms); | |
| ctr->start_ns = | |
| (uint64_t)tms.tv_sec * 1000000000ULL + (uint64_t)tms.tv_nsec; | |
| } | |
| static FORCE_INLINE uint64_t perf_end(perf_counter_t *RESTRICT ctr) | |
| { | |
| struct timespec tms = {0}; | |
| (void)clock_gettime(CLOCK_MONOTONIC, &tms); | |
| const uint64_t end_ns = | |
| (uint64_t)tms.tv_sec * 1000000000ULL + (uint64_t)tms.tv_nsec; | |
| const uint64_t elapsed = end_ns - ctr->start_ns; | |
| ctr->total_ns += elapsed; | |
| ctr->call_count++; | |
| return elapsed; | |
| } | |
| #endif | |
| /* ============================================================================ | |
| * CORE ISAAC ALGORITHM (OPT-049) | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Generate next batch of random values | |
| * @param[in,out] ctx ISAAC state context | |
| * @note Preserves exact ISAAC algorithm behavior | |
| */ | |
| static FORCE_INLINE void isaac_generate(isaac_state_t *RESTRICT ctx) | |
| { | |
| perf_start(&g_gen_counter); | |
| register uint32_t *RESTRICT mem = ctx->mem; | |
| register uint32_t *RESTRICT rnd = ctx->rnd; | |
| register uint32_t acc = ctx->acc; | |
| register uint32_t bux = ctx->bux + (++ctx->ctr); | |
| register uint32_t tmp = 0U; | |
| register uint32_t out = 0U; | |
| /* Conservative prefetching (OPT-048) */ | |
| PREFETCH_READ(&mem[16]); | |
| PREFETCH_WRITE(&rnd[16]); | |
| /* First half: 4-way unrolled (0-127) */ | |
| for (uint32_t idx = 0U; idx < 128U; idx += ISAAC_UNROLL_FACTOR) { | |
| /* Pattern 0: idx % 4 == 0 */ | |
| tmp = mem[idx]; | |
| acc = (acc ^ (acc << ISAAC_SHIFT1)) + mem[idx + 128U]; | |
| mem[idx] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx] = bux = mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| /* Pattern 1: idx % 4 == 1 */ | |
| tmp = mem[idx + 1U]; | |
| acc = (acc ^ (acc >> ISAAC_SHIFT2)) + mem[idx + 129U]; | |
| mem[idx + 1U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 1U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| /* Pattern 2: idx % 4 == 2 */ | |
| tmp = mem[idx + 2U]; | |
| acc = (acc ^ (acc << ISAAC_SHIFT3)) + mem[idx + 130U]; | |
| mem[idx + 2U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 2U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| /* Pattern 3: idx % 4 == 3 */ | |
| tmp = mem[idx + 3U]; | |
| acc = (acc ^ (acc >> ISAAC_SHIFT4)) + mem[idx + 131U]; | |
| mem[idx + 3U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 3U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| /* Prefetch next cache lines */ | |
| if ((idx & (ISAAC_PREFETCH_DIST - 1U)) == 0U) { | |
| PREFETCH_READ(&mem[idx + ISAAC_PREFETCH_DIST]); | |
| PREFETCH_WRITE(&rnd[idx + ISAAC_PREFETCH_DIST]); | |
| } | |
| } | |
| /* Second half: 4-way unrolled (128-255) */ | |
| for (uint32_t idx = 128U; idx < 256U; idx += ISAAC_UNROLL_FACTOR) { | |
| tmp = mem[idx]; | |
| acc = (acc ^ (acc << ISAAC_SHIFT1)) + mem[idx - 128U]; | |
| mem[idx] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx] = bux = mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| tmp = mem[idx + 1U]; | |
| acc = (acc ^ (acc >> ISAAC_SHIFT2)) + mem[idx - 127U]; | |
| mem[idx + 1U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 1U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| tmp = mem[idx + 2U]; | |
| acc = (acc ^ (acc << ISAAC_SHIFT3)) + mem[idx - 126U]; | |
| mem[idx + 2U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 2U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| tmp = mem[idx + 3U]; | |
| acc = (acc ^ (acc >> ISAAC_SHIFT4)) + mem[idx - 125U]; | |
| mem[idx + 3U] = out = | |
| mem[(tmp >> ISAAC_INDEX_SHIFT) & ISAAC_MASK] + acc + bux; | |
| rnd[idx + 3U] = bux = | |
| mem[(out >> ISAAC_RESULT_SHIFT) & ISAAC_MASK] + tmp; | |
| } | |
| ctx->acc = acc; | |
| ctx->bux = bux; | |
| ctx->cnt = 0U; | |
| perf_end(&g_gen_counter); | |
| } | |
| /** | |
| * @brief Get next random 32-bit value | |
| * @param[in,out] ctx ISAAC state context | |
| * @return Random 32-bit value | |
| */ | |
| static FORCE_INLINE uint32_t isaac_random(isaac_state_t *RESTRICT ctx) | |
| { | |
| if (UNLIKELY(ctx->cnt >= ISAAC_RESULT_SIZE)) { | |
| isaac_generate(ctx); | |
| } | |
| return ctx->rnd[ctx->cnt++]; | |
| } | |
| /** | |
| * @brief Get random ASCII printable character | |
| * @param[in,out] ctx ISAAC state context | |
| * @return Random printable ASCII character | |
| */ | |
| static FORCE_INLINE char isaac_random_ascii(isaac_state_t *RESTRICT ctx) | |
| { | |
| return (char)((isaac_random(ctx) % ISAAC_ASCII_RANGE) + ISAAC_ASCII_START); | |
| } | |
| /* ============================================================================ | |
| * INITIALIZATION (OPT-000: FD-004 - Reduced Complexity) | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Mixing macro with proper parenthesization (OPT-000: SA-005) | |
| */ | |
| #define MIX(a, b, c, d, e, f, g, h) \ | |
| do { \ | |
| (a) ^= (b) << 11U; \ | |
| (d) += (a); \ | |
| (b) += (c); \ | |
| (b) ^= (c) >> 2U; \ | |
| (e) += (b); \ | |
| (c) += (d); \ | |
| (c) ^= (d) << 8U; \ | |
| (f) += (c); \ | |
| (d) += (e); \ | |
| (d) ^= (e) >> 16U; \ | |
| (g) += (d); \ | |
| (e) += (f); \ | |
| (e) ^= (f) << 10U; \ | |
| (h) += (e); \ | |
| (f) += (g); \ | |
| (f) ^= (g) >> 4U; \ | |
| (a) += (f); \ | |
| (g) += (h); \ | |
| (g) ^= (h) << 8U; \ | |
| (b) += (g); \ | |
| (h) += (a); \ | |
| (h) ^= (a) >> 9U; \ | |
| (c) += (h); \ | |
| (a) += (b); \ | |
| } while (0) | |
| /** | |
| * @brief Initialize mix array with golden ratio | |
| * @param[out] mix Array to initialize | |
| */ | |
| static void isaac_init_mix(uint32_t mix[ISAAC_MIX_UNROLL]) | |
| { | |
| for (uint32_t idx = 0U; idx < ISAAC_MIX_UNROLL; idx++) { | |
| mix[idx] = ISAAC_GOLDEN_RATIO; | |
| } | |
| /* Initial scramble */ | |
| for (uint32_t round = 0U; round < 4U; round++) { | |
| MIX(mix[0], mix[1], mix[2], mix[3], mix[4], mix[5], mix[6], mix[7]); | |
| } | |
| } | |
| /** | |
| * @brief Mix seed into state memory | |
| * @param[in,out] ctx ISAAC context | |
| * @param[in,out] mix Working mix array | |
| */ | |
| static void isaac_mix_seed(isaac_state_t *RESTRICT ctx, | |
| uint32_t mix[ISAAC_MIX_UNROLL]) | |
| { | |
| /* First pass: mix seed into state */ | |
| for (uint32_t idx = 0U; idx < ISAAC_STATE_SIZE; idx += ISAAC_MIX_UNROLL) { | |
| for (uint32_t jdx = 0U; jdx < ISAAC_MIX_UNROLL; jdx++) { | |
| mix[jdx] += ctx->rnd[idx + jdx]; | |
| } | |
| MIX(mix[0], mix[1], mix[2], mix[3], mix[4], mix[5], mix[6], mix[7]); | |
| for (uint32_t jdx = 0U; jdx < ISAAC_MIX_UNROLL; jdx++) { | |
| ctx->mem[idx + jdx] = mix[jdx]; | |
| } | |
| } | |
| /* Second pass: mix state into itself */ | |
| for (uint32_t idx = 0U; idx < ISAAC_STATE_SIZE; idx += ISAAC_MIX_UNROLL) { | |
| for (uint32_t jdx = 0U; jdx < ISAAC_MIX_UNROLL; jdx++) { | |
| mix[jdx] += ctx->mem[idx + jdx]; | |
| } | |
| MIX(mix[0], mix[1], mix[2], mix[3], mix[4], mix[5], mix[6], mix[7]); | |
| for (uint32_t jdx = 0U; jdx < ISAAC_MIX_UNROLL; jdx++) { | |
| ctx->mem[idx + jdx] = mix[jdx]; | |
| } | |
| } | |
| } | |
| /** | |
| * @brief Mix without seed (scramble only) | |
| * @param[in,out] ctx ISAAC context | |
| * @param[in,out] mix Working mix array | |
| */ | |
| static void isaac_mix_noseed(isaac_state_t *RESTRICT ctx, | |
| uint32_t mix[ISAAC_MIX_UNROLL]) | |
| { | |
| for (uint32_t idx = 0U; idx < ISAAC_STATE_SIZE; idx += ISAAC_MIX_UNROLL) { | |
| MIX(mix[0], mix[1], mix[2], mix[3], mix[4], mix[5], mix[6], mix[7]); | |
| for (uint32_t jdx = 0U; jdx < ISAAC_MIX_UNROLL; jdx++) { | |
| ctx->mem[idx + jdx] = mix[jdx]; | |
| } | |
| } | |
| } | |
| /** | |
| * @brief Initialize ISAAC with optional seed | |
| * @param[in,out] ctx ISAAC state to initialize | |
| * @param[in] use_seed Whether to use seed data from rnd array | |
| */ | |
| static void isaac_init(isaac_state_t *RESTRICT ctx, bool use_seed) | |
| { | |
| uint32_t mix[ISAAC_MIX_UNROLL] = {0}; | |
| isaac_init_mix(mix); | |
| if (use_seed) { | |
| isaac_mix_seed(ctx, mix); | |
| } else { | |
| isaac_mix_noseed(ctx, mix); | |
| } | |
| /* Initialize counters */ | |
| ctx->acc = 0U; | |
| ctx->bux = 0U; | |
| ctx->ctr = 0U; | |
| ctx->cnt = ISAAC_RESULT_SIZE; | |
| /* Generate first batch */ | |
| isaac_generate(ctx); | |
| } | |
| /** | |
| * @brief Seed ISAAC with string key | |
| * @param[out] ctx ISAAC state to seed | |
| * @param[in] key Seed string | |
| * @param[in] len Length of seed (0 for strlen) | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_seed(isaac_state_t *RESTRICT ctx, | |
| const char *RESTRICT key, size_t len) | |
| { | |
| if (!ctx || !key) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| const size_t key_len = (len > 0U) ? len : strlen(key); | |
| /* Clear state arrays */ | |
| memset(ctx->mem, 0, sizeof(ctx->mem)); | |
| memset(ctx->rnd, 0, sizeof(ctx->rnd)); | |
| /* Inject key into seed array */ | |
| for (size_t idx = 0U; idx < ISAAC_STATE_SIZE; idx++) { | |
| if (idx < key_len) { | |
| ctx->rnd[idx] = (uint32_t)(unsigned char)key[idx]; | |
| } else { | |
| ctx->rnd[idx] = 0U; | |
| } | |
| } | |
| isaac_init(ctx, true); | |
| return ISAAC_SUCCESS; | |
| } | |
| /* ============================================================================ | |
| * SECURE OPERATIONS | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Secure memory wipe (OPT-000: SC-001) | |
| * @param[out] ptr Memory to wipe | |
| * @param[in] len Number of bytes | |
| */ | |
| static void secure_wipe(void *ptr, size_t len) | |
| { | |
| volatile uint8_t *vptr = (volatile uint8_t *)ptr; | |
| for (size_t idx = 0U; idx < len; idx++) { | |
| vptr[idx] = 0U; | |
| } | |
| } | |
| /** | |
| * @brief Clone ISAAC state | |
| * @param[out] dst Destination state | |
| * @param[in] src Source state | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_clone(isaac_state_t *RESTRICT dst, | |
| const isaac_state_t *RESTRICT src) | |
| { | |
| if (!dst || !src) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| memcpy(dst, src, sizeof(isaac_state_t)); | |
| return ISAAC_SUCCESS; | |
| } | |
| /* ============================================================================ | |
| * HEX CONVERSION (OPT-003) | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Convert byte to hex characters | |
| * @param[in] byte Byte to convert | |
| * @param[out] hex Output buffer (min 2 chars) | |
| * @return true on success | |
| */ | |
| static FORCE_INLINE bool byte_to_hex(uint8_t byte, char *RESTRICT hex) | |
| { | |
| hex[0] = HEX_CHARS[byte >> 4U]; | |
| hex[1] = HEX_CHARS[byte & 0x0FU]; | |
| return true; | |
| } | |
| /** | |
| * @brief Convert hex characters to byte (optimized) | |
| * @param[in] hex Input hex chars (2 chars) | |
| * @param[out] byte Output byte | |
| * @return true on success | |
| */ | |
| static FORCE_INLINE bool hex_to_byte(const char *RESTRICT hex, | |
| uint8_t *RESTRICT byte) | |
| { | |
| const unsigned char h0 = (unsigned char)hex[0]; | |
| const unsigned char h1 = (unsigned char)hex[1]; | |
| const int8_t val0 = HEX_DECODE[h0]; | |
| const int8_t val1 = HEX_DECODE[h1]; | |
| if (val0 < 0 || val1 < 0) { | |
| return false; | |
| } | |
| *byte = (uint8_t)((val0 << 4U) | val1); | |
| return true; | |
| } | |
| /* ============================================================================ | |
| * CIPHER OPERATIONS | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Caesar cipher for MOD95 | |
| * @param[in] chr Character to shift | |
| * @param[in] shift Shift amount | |
| * @param[in] encrypt true=encrypt, false=decrypt | |
| * @return Shifted character | |
| */ | |
| static FORCE_INLINE char caesar_shift(char chr, char shift, bool encrypt) | |
| { | |
| uint32_t pos = (uint32_t)((unsigned char)chr - ISAAC_ASCII_START); | |
| uint32_t shift_amount = (uint32_t)(unsigned char)shift; | |
| if (!encrypt) { | |
| shift_amount = ISAAC_ASCII_RANGE - shift_amount; | |
| } | |
| pos = (pos + shift_amount) % ISAAC_ASCII_RANGE; | |
| return (char)(ISAAC_ASCII_START + pos); | |
| } | |
| /** | |
| * @brief XOR cipher encryption | |
| * @param[in,out] ctx ISAAC state | |
| * @param[out] output Hex output buffer | |
| * @param[in] input Input plaintext | |
| * @param[in] length Input length | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_xor_encrypt(isaac_state_t *RESTRICT ctx, | |
| char *RESTRICT output, | |
| const char *RESTRICT input, | |
| size_t length) | |
| { | |
| if (!ctx || !output || !input) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| perf_start(&g_encrypt_counter); | |
| for (size_t idx = 0U; idx < length; idx++) { | |
| const char key = isaac_random_ascii(ctx); | |
| const uint8_t res = (uint8_t)input[idx] ^ (uint8_t)key; | |
| (void)byte_to_hex(res, &output[idx * HEX_CHARS_PER_BYTE]); | |
| } | |
| output[length * HEX_CHARS_PER_BYTE] = '\0'; | |
| perf_end(&g_encrypt_counter); | |
| return ISAAC_SUCCESS; | |
| } | |
| /** | |
| * @brief XOR cipher decryption | |
| * @param[in,out] ctx ISAAC state | |
| * @param[out] output Plaintext output | |
| * @param[in] input Hex input | |
| * @param[in] length Output length | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_xor_decrypt(isaac_state_t *RESTRICT ctx, | |
| char *RESTRICT output, | |
| const char *RESTRICT input, | |
| size_t length) | |
| { | |
| if (!ctx || !output || !input) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| perf_start(&g_decrypt_counter); | |
| for (size_t idx = 0U; idx < length; idx++) { | |
| const char key = isaac_random_ascii(ctx); | |
| uint8_t enc = 0U; | |
| if (!hex_to_byte(&input[idx * HEX_CHARS_PER_BYTE], &enc)) { | |
| perf_end(&g_decrypt_counter); | |
| return ISAAC_ERROR_INVALID_HEX; | |
| } | |
| output[idx] = (char)(enc ^ (uint8_t)key); | |
| } | |
| output[length] = '\0'; | |
| perf_end(&g_decrypt_counter); | |
| return ISAAC_SUCCESS; | |
| } | |
| /** | |
| * @brief MOD95 cipher encryption | |
| * @param[in,out] ctx ISAAC state | |
| * @param[out] output Hex output buffer | |
| * @param[in] input Input plaintext | |
| * @param[in] length Input length | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_mod_encrypt(isaac_state_t *RESTRICT ctx, | |
| char *RESTRICT output, | |
| const char *RESTRICT input, | |
| size_t length) | |
| { | |
| if (!ctx || !output || !input) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| for (size_t idx = 0U; idx < length; idx++) { | |
| const char shift = isaac_random_ascii(ctx); | |
| const char enc = caesar_shift(input[idx], shift, true); | |
| (void)byte_to_hex((uint8_t)enc, &output[idx * HEX_CHARS_PER_BYTE]); | |
| } | |
| output[length * HEX_CHARS_PER_BYTE] = '\0'; | |
| return ISAAC_SUCCESS; | |
| } | |
| /** | |
| * @brief MOD95 cipher decryption | |
| * @param[in,out] ctx ISAAC state | |
| * @param[out] output Plaintext output | |
| * @param[in] input Hex input | |
| * @param[in] length Output length | |
| * @return ISAAC_SUCCESS or error code | |
| */ | |
| static isaac_error_e isaac_mod_decrypt(isaac_state_t *RESTRICT ctx, | |
| char *RESTRICT output, | |
| const char *RESTRICT input, | |
| size_t length) | |
| { | |
| if (!ctx || !output || !input) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| for (size_t idx = 0U; idx < length; idx++) { | |
| const char shift = isaac_random_ascii(ctx); | |
| uint8_t enc = 0U; | |
| if (!hex_to_byte(&input[idx * HEX_CHARS_PER_BYTE], &enc)) { | |
| return ISAAC_ERROR_INVALID_HEX; | |
| } | |
| output[idx] = caesar_shift((char)enc, shift, false); | |
| } | |
| output[length] = '\0'; | |
| return ISAAC_SUCCESS; | |
| } | |
| /* ============================================================================ | |
| * FUTURE USE: B-TREE DATABASE INTEGRATION | |
| * ============================================================================ | |
| */ | |
| /* FUTURE USE: Generate unique B-tree node ID | |
| static isaac_error_e isaac_btree_node_id(isaac_state_t* RESTRICT ctx, | |
| uint8_t* RESTRICT node_id, | |
| size_t id_size) { | |
| if (!ctx || !node_id || id_size == 0U) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| for (size_t idx = 0U; idx < id_size; idx += UINT32_BYTES) { | |
| const uint32_t rnd = isaac_random(ctx); | |
| const size_t chunk = (id_size - idx < UINT32_BYTES) ? | |
| (id_size - idx) : UINT32_BYTES; | |
| memcpy(&node_id[idx], &rnd, chunk); | |
| } | |
| return ISAAC_SUCCESS; | |
| } | |
| */ | |
| /* FUTURE USE: Stream cipher for B-tree pages | |
| static isaac_error_e isaac_btree_encrypt_page(isaac_state_t* RESTRICT ctx, | |
| uint8_t* RESTRICT page, | |
| size_t page_size) { | |
| if (!ctx || !page || page_size == 0U) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| for (size_t idx = 0U; idx < page_size; idx += UINT32_BYTES) { | |
| const uint32_t key = isaac_random(ctx); | |
| const size_t chunk = (page_size - idx < UINT32_BYTES) ? | |
| (page_size - idx) : UINT32_BYTES; | |
| for (size_t jdx = 0U; jdx < chunk; jdx++) { | |
| page[idx + jdx] ^= (uint8_t)(key >> (jdx * BITS_PER_BYTE)); | |
| } | |
| } | |
| return ISAAC_SUCCESS; | |
| } | |
| */ | |
| /* FUTURE USE: Generate MAC for B-tree node | |
| static isaac_error_e isaac_btree_mac(isaac_state_t* RESTRICT ctx, | |
| const uint8_t* RESTRICT data, | |
| size_t data_size, | |
| uint8_t* RESTRICT mac, | |
| size_t mac_size) { | |
| if (!ctx || !data || !mac || mac_size < 16U) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| uint32_t hash[4] = {0}; | |
| for (size_t idx = 0U; idx < data_size; idx++) { | |
| const uint32_t key = isaac_random(ctx); | |
| hash[0] ^= data[idx] * key; | |
| hash[1] += data[idx] + key; | |
| hash[2] = ((hash[2] << 1U) | (hash[2] >> 31U)) ^ key; | |
| hash[3] = ((hash[3] >> 1U) | (hash[3] << 31U)) + key; | |
| } | |
| // Mix final hash | |
| for (uint32_t round = 0U; round < 4U; round++) { | |
| hash[0] += isaac_random(ctx); | |
| hash[1] ^= hash[0]; | |
| hash[2] += hash[1]; | |
| hash[3] ^= hash[2]; | |
| } | |
| memcpy(mac, hash, (mac_size < 16U) ? mac_size : 16U); | |
| return ISAAC_SUCCESS; | |
| } | |
| */ | |
| /* FUTURE USE: Key derivation for B-tree levels | |
| static isaac_error_e isaac_btree_derive_key(isaac_state_t* RESTRICT ctx, | |
| const uint8_t* RESTRICT parent_key, | |
| size_t parent_size, | |
| uint32_t child_index, | |
| uint8_t* RESTRICT child_key, | |
| size_t child_size) { | |
| if (!ctx || !parent_key || !child_key) { | |
| return ISAAC_ERROR_NULL_PARAM; | |
| } | |
| // Reseed with parent key and child index | |
| isaac_state_t temp = {0}; | |
| memcpy(temp.rnd, parent_key, | |
| (parent_size < sizeof(temp.rnd)) ? parent_size : sizeof(temp.rnd)); | |
| temp.rnd[0] ^= child_index; | |
| isaac_init(&temp, true); | |
| // Generate child key | |
| for (size_t idx = 0U; idx < child_size; idx += UINT32_BYTES) { | |
| const uint32_t key = isaac_random(&temp); | |
| const size_t chunk = (child_size - idx < UINT32_BYTES) ? | |
| (child_size - idx) : UINT32_BYTES; | |
| memcpy(&child_key[idx], &key, chunk); | |
| } | |
| secure_wipe(&temp, sizeof(temp)); | |
| return ISAAC_SUCCESS; | |
| } | |
| */ | |
| /* ============================================================================ | |
| * BENCHMARKING | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Benchmark ISAAC performance | |
| */ | |
| static void benchmark_performance(void) | |
| { | |
| const uint32_t gen_iterations = 1000000U; | |
| const uint32_t enc_iterations = 1000U; | |
| const char *test_msg = | |
| "Performance test message for encryption benchmarking"; | |
| const size_t msg_len = strlen(test_msg); | |
| /* Reset counters */ | |
| g_gen_counter = (perf_counter_t){0}; | |
| g_encrypt_counter = (perf_counter_t){0}; | |
| g_decrypt_counter = (perf_counter_t){0}; | |
| /* Benchmark generation */ | |
| for (uint32_t idx = 0U; idx < gen_iterations; idx++) { | |
| (void)isaac_random(&g_isaac); | |
| } | |
| /* Benchmark encryption */ | |
| for (uint32_t idx = 0U; idx < enc_iterations; idx++) { | |
| (void)isaac_seed(&g_isaac, "benchmark_key", 0U); | |
| (void)isaac_xor_encrypt(&g_isaac, g_hex_buffer, test_msg, msg_len); | |
| } | |
| printf("=== ISAAC Performance Benchmarks ===\n"); | |
| #ifdef __x86_64__ | |
| if (g_gen_counter.call_count > 0U) { | |
| printf("Random generation: %lu cycles/call\n", | |
| g_gen_counter.total_cycles / g_gen_counter.call_count); | |
| } | |
| if (g_encrypt_counter.call_count > 0U) { | |
| printf("XOR encryption: %lu cycles/byte\n", | |
| g_encrypt_counter.total_cycles / (enc_iterations * msg_len)); | |
| } | |
| #else | |
| if (g_gen_counter.call_count > 0U) { | |
| printf("Random generation: %lu ns/call\n", | |
| g_gen_counter.total_ns / g_gen_counter.call_count); | |
| } | |
| if (g_encrypt_counter.call_count > 0U) { | |
| printf("XOR encryption: %lu ns/byte\n", | |
| g_encrypt_counter.total_ns / (enc_iterations * msg_len)); | |
| } | |
| #endif | |
| } | |
| /* ============================================================================ | |
| * UTILITY FUNCTIONS | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Print version information | |
| */ | |
| static void print_version(void) | |
| { | |
| printf("ISAAC CSPRNG Implementation v%s\n", ISAAC_VERSION_STRING); | |
| printf("================================================\n"); | |
| printf("Based on Bob Jenkins' ISAAC (1993) - Public Domain\n"); | |
| printf("Coding standards: OPT-000 v2.0 compliant\n\n"); | |
| } | |
| /** | |
| * @brief Get error string | |
| * @param[in] err Error code | |
| * @return Error description string | |
| */ | |
| static const char *isaac_error_string(isaac_error_e err) | |
| { | |
| switch (err) { | |
| case ISAAC_SUCCESS: | |
| return "Success"; | |
| case ISAAC_ERROR_NULL_PARAM: | |
| return "Null parameter"; | |
| case ISAAC_ERROR_INVALID_SIZE: | |
| return "Invalid size"; | |
| case ISAAC_ERROR_INVALID_HEX: | |
| return "Invalid hex string"; | |
| case ISAAC_ERROR_OVERFLOW: | |
| return "Integer overflow"; | |
| case ISAAC_ERROR_NOMEM: | |
| return "Out of memory"; | |
| default: | |
| return "Unknown error"; | |
| } | |
| } | |
| /* ============================================================================ | |
| * MAIN ENTRY POINT | |
| * ============================================================================ | |
| */ | |
| /** | |
| * @brief Program entry with test vectors | |
| * @return EXIT_SUCCESS or EXIT_FAILURE | |
| */ | |
| int main(void) | |
| { | |
| /* Stack variables (largest to smallest) */ | |
| char hex_buffer[HEX_BUFFER_SIZE] = {0}; | |
| char msg_buffer[MAX_MESSAGE_SIZE] = {0}; | |
| isaac_state_t test_state = {0}; | |
| isaac_error_e err = ISAAC_SUCCESS; | |
| /* Test configuration */ | |
| const char *const message = "a Top Secret secret"; | |
| const char *const key = "this is my secret key"; | |
| const size_t msg_len = strlen(message); | |
| /* Expected test vectors */ | |
| const char *const expected_xor = "1C0636190B1260233B35125F1E1D0E2F4C5422"; | |
| /* Validation */ | |
| if (msg_len >= MAX_MESSAGE_SIZE) { | |
| fprintf(stderr, "Error: Message too large (%zu >= %u)\n", msg_len, | |
| MAX_MESSAGE_SIZE); | |
| return EXIT_FAILURE; | |
| } | |
| print_version(); | |
| printf("Test Configuration:\n"); | |
| printf(" Message: %s\n", message); | |
| printf(" Key : %s\n\n", key); | |
| /* XOR Cipher Test */ | |
| printf("=== XOR (Vernam) Cipher ===\n"); | |
| err = isaac_seed(&test_state, key, 0U); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "Seed failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| err = isaac_xor_encrypt(&test_state, hex_buffer, message, msg_len); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "XOR encryption failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| printf("Encrypted: %s\n", hex_buffer); | |
| err = isaac_seed(&test_state, key, 0U); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "Reseed failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| err = isaac_xor_decrypt(&test_state, msg_buffer, hex_buffer, msg_len); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "XOR decryption failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| printf("Decrypted: %s\n\n", msg_buffer); | |
| /* MOD95 Cipher Test */ | |
| printf("=== MOD95 (Vigenère) Cipher ===\n"); | |
| err = isaac_seed(&test_state, key, 0U); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "Seed failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| err = isaac_mod_encrypt(&test_state, hex_buffer, message, msg_len); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "MOD encryption failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| printf("Encrypted: %s\n", hex_buffer); | |
| err = isaac_seed(&test_state, key, 0U); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "Reseed failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| err = isaac_mod_decrypt(&test_state, msg_buffer, hex_buffer, msg_len); | |
| if (err != ISAAC_SUCCESS) { | |
| fprintf(stderr, "MOD decryption failed: %s\n", isaac_error_string(err)); | |
| return EXIT_FAILURE; | |
| } | |
| printf("Decrypted: %s\n\n", msg_buffer); | |
| /* Verification */ | |
| printf("=== Test Vector Verification ===\n"); | |
| (void)isaac_seed(&test_state, key, 0U); | |
| (void)isaac_xor_encrypt(&test_state, hex_buffer, message, msg_len); | |
| const bool xor_match = (strcmp(hex_buffer, expected_xor) == 0); | |
| const bool mod_match = (strcmp(msg_buffer, message) == 0); | |
| printf("XOR cipher match: %s\n", xor_match ? "✓ PASS" : "✗ FAIL"); | |
| printf("MOD cipher match: %s\n", mod_match ? "✓ PASS" : "✗ FAIL"); | |
| printf("\n"); | |
| /* Performance benchmarks */ | |
| benchmark_performance(); | |
| /* Secure cleanup */ | |
| secure_wipe(&test_state, sizeof(test_state)); | |
| secure_wipe(hex_buffer, sizeof(hex_buffer)); | |
| secure_wipe(msg_buffer, sizeof(msg_buffer)); | |
| return (xor_match && mod_match) ? EXIT_SUCCESS : EXIT_FAILURE; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.