14 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 | RUNNING |
| 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..6: 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 = 7, 8 running | PASS from k = 1 (BOUND) |
| Q4b | t-bit linear correlations on the round-0 input, 2^26 samples | k = 0 | no cell beyond 6 sigma | pending | RUNNING |
| Q5 | rotational-XOR, rotations 1, 8, 16, 2^22 samples | weak0 at k = 1 |
no zero-difference word above 2 of N, no repeated difference above 3 | pending | 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 |
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 |
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.
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.
| 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.