#include "obfuscate.h" #include static uint16_t rotl16(uint16_t x, unsigned int n) { n &= 15u; return (uint16_t)((x << n) | (x >> (16u - n))); } static uint64_t rotl40(uint64_t x, unsigned int n) { n %= OBF_PAYLOAD_BITS; x &= OBF_PAYLOAD_MASK; if (n == 0u) return x; return ((x << n) | (x >> (OBF_PAYLOAD_BITS - n))) & OBF_PAYLOAD_MASK; } static uint64_t rotr40(uint64_t x, unsigned int n) { n %= OBF_PAYLOAD_BITS; x &= OBF_PAYLOAD_MASK; if (n == 0u) return x; return ((x >> n) | (x << (OBF_PAYLOAD_BITS - n))) & OBF_PAYLOAD_MASK; } /* Lightweight seed mixer — same output for same seed on any platform. */ static uint64_t derive_key(uint64_t seed) { uint64_t x = seed ^ 0xA5A5A5A5A5A5A5A5ULL; x ^= x >> 33; x *= 0xFF51AFD7ED558CCDULL; x ^= x >> 33; x *= 0xC4CEB9FE1A85EC53ULL; x ^= x >> 33; return x & OBF_PAYLOAD_MASK; } static unsigned int derive_rotation(uint64_t seed) { uint64_t mix = seed * 0x9E3779B97F4A7C15ULL; return (unsigned int)((mix >> 59) + 1u); /* 1..8 */ } /* * 24-bit FEC-style tag: four 16-bit shards XOR-mixed with key and seed. * Detects single-bit flips and wrong seed with high probability. */ static uint32_t compute_tag(uint64_t val, uint64_t seed) { uint64_t k = derive_key(seed); uint64_t a = (val & 0xFFFFULL) ^ (k & 0xFFFFULL); uint64_t b = ((val >> 16) & 0xFFFFULL) ^ ((k >> 16) & 0xFFFFULL); uint64_t c = ((val >> 32) & 0xFFFFULL) ^ ((k >> 32) & 0xFFFFULL); uint64_t d = ((val >> 48) & 0xFFFFULL) ^ ((k >> 48) & 0xFFFFULL); uint64_t p1 = a ^ rotl16((uint16_t)b, 3) ^ c; uint64_t p2 = b ^ rotl16((uint16_t)c, 7) ^ d; uint64_t p3 = c ^ rotl16((uint16_t)d, 11) ^ a; uint64_t mix = (p1 * 0x01000193ULL) ^ (p2 << 16) ^ (p3 << 8); mix ^= seed; mix *= 0x85EBCA77C2B2AE63ULL; mix ^= mix >> 33; return (uint32_t)(mix & 0xFFFFFFULL); } static uint64_t obfuscate(uint64_t val, uint64_t seed) { uint64_t key = derive_key(seed); unsigned int rot = derive_rotation(seed); return rotl40(val & OBF_PAYLOAD_MASK, rot) ^ key; } static uint64_t deobfuscate(uint64_t obscured, uint64_t seed) { uint64_t key = derive_key(seed); unsigned int rot = derive_rotation(seed); return rotr40(obscured ^ key, rot); } int32_t encode(uint64_t val, uint64_t seed, uint64_t *out) { uint64_t packed; uint32_t tag; if (out == NULL) return OBF_ERR_NULL; if (val > OBF_PAYLOAD_MASK) return OBF_ERR_RANGE; tag = compute_tag(val, seed); packed = ((uint64_t)tag << OBF_PAYLOAD_BITS) | obfuscate(val, seed); *out = packed; return OBF_OK; } int32_t decode(uint64_t encoded_val, uint64_t seed, uint64_t *out) { uint32_t stored_tag; uint32_t expected_tag; uint64_t obscured; uint64_t val; if (out == NULL) return OBF_ERR_NULL; stored_tag = (uint32_t)(encoded_val >> OBF_PAYLOAD_BITS); obscured = encoded_val & OBF_PAYLOAD_MASK; val = deobfuscate(obscured, seed); expected_tag = compute_tag(val, seed); if (stored_tag != expected_tag) return OBF_ERR_VERIFY; *out = val; return OBF_OK; }