igneum/docs/analysis/cryptanalysis/report-mixer-3.md
2026-10-07 18:58:14 +00:00

16 KiB

Report: the statistical distinguisher and the round margin of M_r

Internal adversarial pass, not an independent review. Every sentence here that could be quoted in public carries that label. Lane adv-mixer-3, branch adv-mixer-3. First results 7 October 2026, 19:0x UTC; rows are appended as they land.

Header

Field Value
Target commit 017e703764 (class v4 sub-version 3, object byte 7)
Target the mixer M_r (spec 01 section 1.8.4), class v4 (V4_CLASS = MX8): 72 applications per item, 8 between dependent cache reads
Base commit build/master 7a7caa34, merged 04c4d9bc; git diff --quiet 017e7037 HEAD -- igneum-pow && echo IDENTICAL prints IDENTICAL
Harness tools/attack/adv-mixer-3 (igneum-pow by path); binary sha256 bdd8432f6181bcc9e77885cf840c83e2a6ffe5ae027182a1d9181710bbb06e70 (commands index, sac, diff, lin, lin0, rx, cnf), identical on both boxes; v2 8153dbafa4540c796ae5a76e31258dbb1323724465aa4709d9cecd050dea5c40 adds sac0
SAT solver CaDiCaL 3.0.1, built from the GitHub source into ~/adv-mixer-3-tools on each box (user directory, nothing system-wide)
Boxes igneum-build-1 (queue 01, 03, 05, 09) and igneum-build-2 (queue 02, 04, 06, 08), nice 10, cores 8 to 95, 64 threads per sweep; the boxes ran at load 160 to 460 on 96 cores throughout, so every wall time here is a loaded-box time
Logs /srv/builds/_adv-mixer-3/logs/ on each box (outside the worktree mirror); copies under docs/analysis/cryptanalysis/logs/adv-mixer-3/ on this branch
Days 20729 (genesis, 3 October 2026), 20733 (Devnet 3 epoch 0), plus 8 fixed day indices in queue 07
Band 6 sigma at the sample count of each row; a cell beyond it is a distinguisher, a cell inside it is invisible to that row

Plant rule: a tool is trusted once it has fired on a known-failed shape. Which shape fired is in each row.

Status board

Q Method Known-failed shape Gate Result (numbers) Status
Q1 exhaustive round-0 line-index census, all 2^32 t, k = 0..8 k = 0 (the init: one bin holds 2^32, fired on both days) chi-square z within 6, no empty bin day 20729: uniform at k = 1 (z -1.13), 2 (-0.68), 3 (-0.39), 4 (-0.47); day 20733 uniform at k = 1 (z -0.71); k = 5..8 running PASS to k = 4 (BOUND: the index histogram is uniform from k = 1), RUNNING
Q2 single-bit avalanche, random states, 2^24 (and 2^27) states one at k = 8 (fired: 1959 holes); weak fires at k = 1 only, not at k = 8 (see Q2) no cell beyond 6 sigma k = 1: 354 holes, 129,726 cells beyond 6 sigma, worst p = 1.000; k = 2 at 2^24: 0 holes, 0 cells beyond 6 sigma, worst z -4.74 (band 0.0015); k = 3..8 and the 2^27 rows running FINDING at k = 1, PASS at k = 2 (margin: 1 of 8 on random states)
Q2b t-bit avalanche on the round-0 input (32 bits in), 2^24 (and 2^28) states k = 0 (the init alone, fired: 12,439 holes) no cell beyond 6 sigma k = 1: 0 holes, 218 cells beyond 6 sigma, worst p = 0.7427 (t bit 31 to state bit 53), 18 line-index cells beyond 6 sigma. k = 2..8 at 2^24: 0 cells beyond 6 sigma, worst z 3.7 to 4.7 (the maximum of 16,384 normals is about 4.1). 2^28 rows at k = 2, 3, 4 running FINDING at k = 1, PASS from k = 2 (margin: 1 of 8)
Q3 differential multiplicity, 576 low-weight input differences, 2^20 pairs each nomul at k = 1 (fired: 17,289 deterministic output bits at 4,096 pairs) no multiplicity 4 or more, no deterministic bit k = 1: 695 deterministic output bits over the 576 differences (max 35 in one difference) on day 20729, 537 (max 40) on 20733; k = 2..7: 0 deterministic bits, max multiplicity 1, no pair with 2 zero words, both days; k = 8 running FINDING at k = 1 (deterministic bits), PASS from k = 2
Q4 single-bit linear correlations, random states, 2^26 samples k = 0 (the identity, fired: c = 1.0 on the diagonal) no cell beyond 6 sigma (band 0.00073) k = 1..7: worst c between 0.00055 and 0.00058 (z 4.5 to 4.7, the expected maximum of 262,144 normals is 4.8), 0 cells beyond 6 sigma; k = 8 running PASS from k = 1 (BOUND)
Q4b t-bit linear correlations on the round-0 input, 2^26 samples k = 0 (fired: c = 1.0, t bit 0 to s[8] bit 0) no cell beyond 6 sigma k = 1..8: worst c 0.00048 to 0.00059 (z 3.9 to 4.9 over 16,384 cells), 0 cells beyond 6 sigma PASS from k = 1 (BOUND)
Q5 rotational-XOR, rotations 1, 8, 16, 2^22 samples weak0 at k = 1 (fired: 740 zero-difference words of 2^20 at r = 1, 245 at r = 16) no zero-difference word above 2 of N, no repeated difference above 3 k = 1..4 running RUNNING
Q6 SAT (CaDiCaL) on the round-0 input: find t with a given 22-bit index after k applications k = 1 solved and verified solve inside one hour per k, time against the honest 2^10 x k x 130 ops k = 1: SATISFIABLE in 137 s wall (loaded box); model t = 0x49880000 verifies to the target 0x20eb79. Honest: 2^10 trials of one application is under a millisecond. The solver is already slower than brute force at k = 1 PASS at k = 1 (BOUND); k = 2..4 RUNNING
Q7 days: 20733 on every row, 8 fixed day indices on Q1 and Q2 as above as above day 20733 rows land below RUNNING
GPU any GPU row n/a n/a no GPU on either box BLOCKED

The round margin so far (internal adversarial pass, not an independent review): every single-bit statistic that reaches beyond k = 1 is listed with its k in the rows below. Where the table says "pending" the row is not yet in.

Q1: the round-0 line-index census (exhaustive)

The input to round 0 is 8 fixed words K and 8 words affine in one 32-bit t, so the first line index is a map of 32 bits to 22 bits and can be censused over its whole domain. For k applications with keys round_key(0..k-1):

Command (build-1), per k: adv-mixer-3 index --day 20729 --apps k --threads 64. Logs: index-20729-k.log.

Day k chi-square z (df 2^22 - 1) empty bins min max segment z line z s[0] bit balance worst z verdict
20729 0 6.2e12 4194303 0 2^32 7.8e11 2.4e10 n/a NON-UNIFORM (the plant: one bin)
20729 1 -1.13 0 871 1191 -2.00 -0.26 pending uniform within the band
20729 2 -0.68 0 874 1191 0.56 -0.14 pending uniform
20729 3 -0.39 0 853 1187 -0.03 -1.15 pending uniform
20729 4 -0.47 0 857 1190 1.07 -0.25 pending uniform
20733 0 6.2e12 4194303 0 2^32 7.8e11 2.4e10 n/a NON-UNIFORM (plant)
20733 1 -0.71 0 863 1202 0.11 -0.60 pending uniform

Reading: after one application the 2^32 round-0 inputs already spread over the 2^22 lines as a uniform draw would (Poisson 1024 per bin: min 871, max 1191 are the expected extremes over 4 million bins). The multiply layer on the 8 affine words and one double round are enough for the line index as a histogram. This is a histogram test, not an independence test: Q2b measures whether individual t bits still leak into individual index bits.

Q2: single-bit avalanche on random states (the regime of rounds 1 to 8)

Command (build-1), per k: adv-mixer-3 sac --day 20729 --apps k --start 8 --states 2^24 --threads 64. Keys round_key(8..8+k-1) (round 1's keys). Logs: sac-20729-k.log.

Plants: --plant one --apps 8 (one application in place of eight) fired with 1,959 holes and 89,129 cells beyond 6 sigma at 65,536 states. --plant weak --apps 8 (MUL 1, RC 0, ROT 16) did NOT fire at k = 8: 0 holes, worst z 4.88. Eight double rounds of a constant-free ARX permutation on random 512-bit inputs diffuse fully, so "weak" is a known-failed shape at k = 1 only (a sibling's census fired it there; this lane's 4,096-state smoke run at k = 1 fired it too: 14,364 holes). The one plant is the firing check of this row.

Day k states holes cells beyond 6 sigma worst cell worst p line-index cells beyond 6 sigma (of 11,264) verdict
20729 1 2^24 354 129,726 in 279 (word 8) to out 64 (word 2) 1.0000 7,930 DISTINGUISHED
20729 2 2^24 0 0 in 322 (word 10) to out 373 (word 11) 0.49942 (z -4.74) 0 inside the band

Reading: one application on a random 512-bit state leaves 354 deterministic cells (an input bit that always or never flips a given output bit) and 129,726 of 262,144 cells beyond 6 sigma; 7,930 of the 11,264 cells that feed the line index are among them. Two applications leave no cell beyond 6 sigma at 2^24 states (band 0.0015). The worst z of -4.74 is the expected extreme of 262,144 standard normals. The margin on this statistic is 1 of the 8 applications between reads, the same as on the round-0 input (Q2b).

Q2b: t-bit avalanche on the round-0 input

Command (build-1), per k: adv-mixer-3 sac0 --day 20729 --apps k --states 2^24 --threads 64 (v2 binary). Logs: sac0-20729-k.log. Plant k = 0 (the init alone) fired: 12,439 holes of 16,384 cells.

Day k states holes cells beyond 6 sigma (of 16,384) worst cell worst p line-index cells beyond 6 sigma (of 704) verdict
20729 1 2^24 0 218 t bit 31 to state bit 53 (word 1) 0.7427 18 DISTINGUISHED
20729 2 2^24 0 0 t bit 23 to bit 147 0.49949 (z -4.19) 0 inside the band
20729 3 2^24 0 0 t bit 26 to bit 219 0.49955 (z -3.73) 0 inside
20729 4 2^24 0 0 t bit 30 to bit 329 0.50051 (z 4.15) 0 inside
20729 5 2^24 0 0 t bit 31 to bit 162 0.49947 (z -4.32) 0 inside
20729 6 2^24 0 0 t bit 26 to bit 194 0.50050 (z 4.08) 0 inside
20729 7 2^24 0 0 t bit 6 to bit 390 0.49943 (z -4.69) 0 inside
20729 8 2^24 0 0 t bit 13 to bit 9 0.49947 (z -4.33) 0 inside

Reading: on the real input of round 0 (one 32-bit t), one application leaves a 24 percent bias on 218 of the 16,384 (t bit, state bit) cells and on 18 of the 704 cells that feed the first line index. Two applications leave nothing at 2^24 states (band 0.0015). The margin on this statistic is 1 of the 8 applications before the first read: the first read's address is not predictable from t after 2 of its 8 applications, at this band.

Q3: differential multiplicity

Command (build-1), per k: adv-mixer-3 diff --day 20729 --apps k --start 8 --samples 2^20 --threads 64. 576 input differences (512 single bits, 64 random two-bit), 2^20 random pairs each, the 512-bit output difference hashed to 64 bits; the band for one output difference is 2^-19 (multiplicity 2 or more). Plant nomul at k = 1 fired: 7,992 deterministic output bits (day 20729), 7,189 (day 20733). Logs: diff--k.log.

Day k max multiplicity of one output difference deterministic output bits (all 576 differences) max in one difference pairs with 2 or more zero output words verdict
20729 1 1 695 35 of 512 0 DISTINGUISHED (deterministic bits)
20729 2 1 0 0 0 inside the band
20729 3 to 7 1 0 0 0 inside
20733 1 1 537 40 of 512 0 DISTINGUISHED (deterministic bits)
20733 2 to 7 1 0 0 0 inside

Reading: at k = 1 a single-bit input difference fixes 35 to 40 output bits (the quarter-round structure: the first add and XOR of a column pass a flipped bit on deterministically before the rotations spread it), but no full output difference repeats even once in 2^20 pairs, because the other 470 bits of the difference are spread. At k = 2 no output bit is fixed by any of the 576 input differences. Differentials of probability above 2^-19 do not exist for these input differences past k = 1. The truncated form (whole output words unchanged) never beats the random rate at any k.

Q4: single-bit linear correlations

Command (build-1), per k: adv-mixer-3 lin --day 20729 --apps k --start 8 --samples 2^26 --threads 64. Band: 6 sigma = 0.00073. Plant k = 0 fired (c = 1.0 on the 512 diagonal cells).

Day k samples worst c worst z cells beyond 6 sigma (of 262,144) line-index worst z output balance worst z verdict
20729 1 2^26 -0.00056 -4.61 0 -3.72 3.82 inside the band
20729 2 2^26 0.00058 4.73 0 4.09 3.47 inside
20729 3 2^26 0.00056 4.61 0 -3.95 3.17 inside
20729 4 2^26 -0.00056 -4.61 0 4.18 3.08 inside
20729 5 2^26 0.00057 4.64 0 4.14 3.27 inside
20729 6 2^26 -0.00055 -4.54 0 pending pending inside
20729 7 2^26 -0.00055 -4.51 0 pending pending inside

Reading: a single input bit and a single output bit have no measurable linear correlation after one application on random states. The worst z of 4.6 to 4.7 over 262,144 cells is what 262,144 draws of a standard normal give (expected maximum about 4.8). This is the single-bit mask family only; multi-bit masks are owed work.

Q4b: t-bit linear correlations on the round-0 input

Command (build-1), per k: adv-mixer-3 lin0 --day 20729 --apps k --samples 2^26 --threads 64 (x = the 32 bits of t, y = the state after the init and k applications). Plant k = 0 fired: c = 1.0 between t bit 0 and s[8] bit 0 (the init's t * MUL[0] + RC[0] has bit 0 = t bit 0 XOR RC bit 0), 65 cells beyond 6 sigma.

Day k worst c worst z cells beyond 6 sigma (of 16,384)
20729 1 0.00048 3.93 0
20729 2 0.00059 4.85 0
20729 3 0.00051 4.14 0
20729 4 0.00049 4.04 0
20729 5 -0.00057 -4.67 0
20729 6 -0.00048 -3.97 0
20729 7 0.00058 4.76 0
20729 8 -0.00051 -4.15 0

Reading: no t bit has a linear correlation with any state bit after one application, at a band of 0.00073. The 24 percent avalanche bias of Q2b at k = 1 is a differential effect (a flipped t bit flips a state bit with probability 0.74), not a linear one.

Q5: rotational-XOR

Command (build-1): adv-mixer-3 rx --day 20729 --apps k --start 8 --samples 2^22. Plant weak0 (MUL 1, RC 0, ROT 16, round key 0: a constant-free ARX round) at k = 1 fired: at r = 1, 740 of 2^20 samples had a zero rotational-XOR difference in one word and the difference 0x00000001 repeated 784 times; at r = 16, 245 zero differences. Rows for the real day land here.

Q6: SAT on the round-0 input

Command (build-1, smoke run): adv-mixer-3 cnf --day 20729 --apps 1 --t0 0x12345678 --out k1.cnf then cadical -q k1.cnf. CNF: 33,873 variables, 112,328 clauses (Tseitin: t is 32 variables; each constant multiply is a shift-add chain of 32-bit ripple adders over the set bits of MUL; each quarter round four adders; rotations are wires; constants are folded). Result: s SATISFIABLE, 137.06 s wall on the loaded box; the model gives t = 0x49880000; adv-mixer-3 verify --day 20729 --apps 1 --t 0x49880000 prints index 0x20eb79, the target.

Honest cost of the same task: about 2^10 random t each through one application, under 2^18 integer operations, under a millisecond on one core. The solver at k = 1 is five orders slower than the honest search. The queue 08 rows (k = 1..4, both days, one-hour cap) land below.

Box-hours

Rule changes during the pass (so the hours stay honest): 18:4x UTC the build-server lane dropped the SIGSTOP yield-to-builds rule and set every sweep to nice 10 on cores 8 to 95; the same lane moved every log, pid file and CNF out of the worktree mirror into /srv/builds/_adv-mixer-3/. Both applied before the first sweep started. 18:56 UTC the same lane set one bounded sweep per box across all lanes (flock /srv/builds/_adv/locks/sweep.lock, 88 threads): queue 01 (index 20729, k = 5..8 left) and 02 (index 20733, k = 2..8 left) were killed by pid file at 18:57 and 18:58 UTC as the lowest-value runs and re-queued as queue 10 under the lock; the six other sweeps that had started were left to finish; nothing new starts outside the lock.

Step Box Start (UTC) Wall Note
Build harness (two builds, one fix) build-1 18:36 29 s
Build harness build-2 18:44 14 s
CaDiCaL from source build-1, build-2 18:42, 18:44 about 1 min each
Smoke plants and k = 1 SAT build-1 18:38 3 min
Queue 01, 03, 05 build-1 18:42 running
Queue 02, 04, 06, 08 build-2 18:47 running
Queue 09 (sac0) build-1 18:50 running

What a longer pass would add

Multi-bit linear masks and a MILP trail bound; the SAT model on the full 512-bit state with a cache-line XOR between applications; 2^30 states on the k that sits at the band. None of these is a reason to wait on the numbers above.