From 0c3e4cb59cc3868b6c316383c1612a14220a477c Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:51:42 +0000 Subject: [PATCH] adv-mixer-3 report: header, status board, first rows (Q1 k=1..3 uniform, Q2 k=1, Q2b k=1, Q4 k=1..4 inside the band, SAT k=1 bound) Co-Authored-By: Claude Fable 5.1 --- docs/analysis/cryptanalysis/report-mixer-3.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/analysis/cryptanalysis/report-mixer-3.md diff --git a/docs/analysis/cryptanalysis/report-mixer-3.md b/docs/analysis/cryptanalysis/report-mixer-3.md new file mode 100644 index 000000000..e0b7def0c --- /dev/null +++ b/docs/analysis/cryptanalysis/report-mixer-3.md @@ -0,0 +1,138 @@ +# 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, 20:0x BST; rows are appended as +they land. + +## Header + +| Field | Value | +|---|---| +| Target commit | 017e70376489251e18564c0abce7e466e606c8b3 (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 (z -0.68), 3 (z -0.39); later k below | 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 | RUNNING | +| 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 | pending the k = 1..4 rows | RUNNING | +| 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: worst c = -0.00056 (z -4.61); k = 2: 0.00058; k = 3: 0.00056; k = 4: -0.00056: all inside the band | PASS to k = 4 (BOUND), RUNNING to k = 8 | +| 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 | + +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 | + +## Q3: differential multiplicity + +Command (build-1), per k: `adv-mixer-3 diff --day 20729 --apps k --start 8 --samples 2^20 --threads 64`. + +Rows land here. + +## 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 | + +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): 19:4x BST 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.