DF-0220 / chain_model.py
#!/usr/bin/env python3 """DF-0220 — verified model of the manufactured pre-reseed window output. Reproduces, byte-for-byte, what /dev/urandom returns from a per-CPU csprng_state forced into the pre-reseed condition (reseed_cnt=0, key=0^32, cipher_ctx=0^64, pool[0].bytes=0) in rand_mode=csprng, for consecutive 32-byte reads: read N: emit = block(cur_state, ctr)[0:32] ctr += 1 keygen = block(cur_state, ctr)[0:32] -> K ctr += 1 keysetup: cur_state = sigma || K || ctr (ctr preserved) Key detail: on the FIRST read the ctx is fully zero (chacha_keysetup was never called), so input[0..3] are ZERO (no sigma). The block at ctr=0 is the all-zero fixed point -> blk1 = 0x00*32. The keygen at ctr=1 then runs with sigma STILL absent (keysetup runs after keygen), so K1 comes from the sigma-less zero state at ctr=1 -- the chain never becomes plain "chacha20(key=0)". Verified against the live kernel (DragonFly 6.5-DEVELOPMENT #0, Jul 2 2026 build): 5/5 identical trials; per-read live ctx dumps (kmem) match the model's sigma/key/counter after every read. See kmem_window_decisive.log and kmem_window_chain.log. Run: python3 chain_model.py """ def rotl(v, c): return ((v << c) & 0xffffffff) | (v >> (32 - c)) def qr(x, a, b, c, d): x[a] = (x[a] + x[b]) & 0xffffffff; x[d] = rotl(x[d] ^ x[a], 16) x[c] = (x[c] + x[d]) & 0xffffffff; x[b] = rotl(x[b] ^ x[c], 12) x[a] = (x[a] + x[b]) & 0xffffffff; x[d] = rotl(x[d] ^ x[a], 8) x[c] = (x[c] + x[d]) & 0xffffffff; x[b] = rotl(x[b] ^ x[c], 7) def block(st): st = list(st); w = st[:] for _ in range(10): qr(w,0,4,8,12); qr(w,1,5,9,13); qr(w,2,6,10,14); qr(w,3,7,11,15) qr(w,0,5,10,15); qr(w,1,6,11,12); qr(w,2,7,8,13); qr(w,3,4,9,14) return b''.join(((w[i]+st[i]) & 0xffffffff).to_bytes(4,'little') for i in range(16)) def words(b): return [int.from_bytes(b[i*4:i*4+4], 'little') for i in range(len(b)//4)] SIG = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] st = [0]*16 # csprng_init() leaves cipher_ctx all-zero ctr = 0 for n in range(4): s = list(st); s[12] = ctr emit = block(s)[0:32] s = list(st); s[12] = ctr + 1 K = words(block(s)[0:32]) ctr += 2 st = SIG + K + [0]*4 # chacha_keysetup writes sigma+key, keeps counter print(f"blk{n+1}: {emit.hex()}") print(f" K{n+1} loaded: {b''.join(x.to_bytes(4,'little') for x in K)[:16].hex()} ctr={ctr}") # Observed on the live kernel (must match): EXPECT = [ "00"*32, "28958d01c7096dd755434108856438916ed176e0933b02e9268dba09c6bdfb66", "8f57ab7001763a0404a36d4ba6e5e1a1a6b1a9ae7680e47a05c5aa365cdcfac4", "75aa5968da092cf627267b697a27c651e3688fa22d366243b3a77833b37b27b4", ] |