From 5bddb289c30e246d517d0c59f679f6ec4633a40b Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:24:11 +0000 Subject: [PATCH] adv-mixer: report with Q3 census (BOUND+tail), Q1 fold (BOUND), Q2 running Internal adversarial pass, not an independent review. Q3 census over 2^24 day keys: largest per-day M1 FPGA-datapath gain 1.1726x on one day, 3.26e-4 of days over 1.1x, zero days with any DSP or wall-time gain, ROT-all-equal never seen. Q1 fold probe: 1e6/1e6 affinity violations, 0 dead word pairs, 0 key-order agreements, so no cheap composition of the 8 keyed applications. Q2 diffusion sweep and the f4 analytic tail are running; numbers land as they finish. Co-Authored-By: Claude Fable 5.1 --- docs/analysis/cryptanalysis/report-mixer.md | 158 ++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/analysis/cryptanalysis/report-mixer.md diff --git a/docs/analysis/cryptanalysis/report-mixer.md b/docs/analysis/cryptanalysis/report-mixer.md new file mode 100644 index 000000000..37c134cb8 --- /dev/null +++ b/docs/analysis/cryptanalysis/report-mixer.md @@ -0,0 +1,158 @@ +# Report: adversarial cryptanalysis of the mixer M_r + +Internal adversarial pass, not an independent review. + +The label "internal adversarial pass, not an independent review" applies to every sentence here that could be +quoted in public. This is such a pass. It is not an outside review. + +## 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), 8 keyed applications between reads, 72 per item, class v4 (m = 8) | +| Branch | adv-mixer, from build/master | +| Byte-identity | memhard.rs, seed.rs, bind.rs, derive.rs, Cargo.toml, Cargo.lock are byte-identical to the frozen commit; accept.rs, emit.rs, generator.rs, packcheck.rs and the two mixer/recheck test files differ and are NOT M_r (plan section 0) | +| Harness attack-adv-mixer | sha256 a01bf61016a8bda530468f081442131f1bff4a7b6401dd84cbcde83c78bb48f3 (box 2 release) | +| Harness attack-f4 census | sha256 d51df6caab338b0165485c3ce6d6379c0af7180bf2b72fc0a1531beabeaf2d22 (box 2 release) | +| Box | igneum-build-2 (box 2), nice 10; the f4 expect tail on igneum-build-1 (box 1), nice 10 | +| Toolchain | rustc 1.99.0 both sides | +| Day under test | chain day index 20729 (genesis, 3 October 2026), bind::day_bytes(20729) | + +## Status board + +| Q | Method | Known-failed shape | Gate | Result (numbers) | Status | +|---|---|---|---|---|---| +| Q3 weak draws | f4 census over 2^24 days, M1/M2 datapath cost | plant alleq/mul1/mul1all/rc0/rcrk0 (all fired) | any class >= 1.1x on a non-negligible fraction | largest per-day M1 gain 1.1726x on 1 day in 2^24; 5476 days (3.26e-4) over 1.1x on the generous M1 metric; 0 days with any M2 DSP gain; 0 ops from ROT or RC on any day; ROT-all-equal never occurred | FINDING (tail), BOUNDED | +| Q2 round margin | adv-mixer diffusion census, K = 1..8, 2e6 states | diffusion --plant weak (fired: 7894 holes, 236269 strong cells at K=1) | full diffusion (no hole, no strong bias at 8 sigma) at K | running | RUNNING | +| Q1 shortcut | adv-mixer fold probe, 1e6 trials | the probes are their own control | affinity violations > 0, dead pairs = 0, key agreements = 0 | 1e6/1e6 affinity violations, 0 of 256 dead word pairs, 0 of 1e6 key-order agreements | PASS (BOUND: no fold) | +| Q4 other | watched while the above ran | n/a | n/a | fixed round keys and MUL/RC reuse in item init are covered by Q3 classes; nothing further yet | RUNNING | + +## Q3: weak parameter draws (BOUND with a measured tail) + +Command (box 2): +``` +nice -n 10 taskset -c 64-95 attack-f4 census --from 20729 --count 16777216 --threads 32 +``` +Seed: MixParams::with_shape(seed_words_from_bytes(bind::day_bytes(d)), Shape::for_class(&V4_CLASS)) for +consecutive chain day indices d from 20729. No external seed. 16,777,216 days (2^24), 4.4 s wall. +Log: /srv/builds/igneum-wt-adv-mixer/adv/census-20261007T181830Z.log on box 2. + +The gain metric M1 is the per-day LUT datapath: an FPGA bitstream synthesised for one day, the only per-day +attacker that exists. A constant XOR folds into the next LUT, a constant rotation is routing, a 32-bit add or XOR +is one adder-equivalent, a multiply by a constant is NAF(MUL) - 1 adders. M1 cost per application is +64 + sum(NAF(MUL_i) - 1). The 64 is the 8 quarter rounds' adds and xors. Gain is the census median over the +day's cost. This is the generous bound: real single-constant multipliers beat NAF and a DSP multiply is +value-independent. + +Headline numbers: + +| Quantity | Value | +|---|---| +| M1 cost mean | 231.11 adders per application (sd 6.19) | +| M1 cost median | 231 | +| M1 cost min (best attacker day) | 197, day 4819563 | +| M1 cost max | 263, day 15262713 | +| Largest M1 gain | 1.1726x (231 / 197), 1 day in 2^24 | +| Days with M1 gain over 1.1x (cost < 210) | 5476 of 16,777,216 = 3.26e-4 (about 1 in 3064 days) | +| Days with any M2 DSP-bound gain, k >= 2 | 0 | +| Days with a ROT or RC wall-time gain | 0 (a bit-exact verifier never skips an application; ROT is wiring, RC is inverters) | + +What this means for the honest miner and the verifier. The M1 gain is the adder count of an FPGA datapath +synthesised for one calendar day. It is not a wall-time shortcut against the honest GPU and not a skipped +application at the bit-exact verifier. The chip model prices the mixer at 9,360 ops per item hoisted; a 1.17x cut +in the multiply layer's adder count on the single best day in 2^24 does not move the chip rows, which are bound +by the 8 cache reads and the fixed op count, not by the FPGA adder count of one day. Over 2^24 days (about 45,900 +years of calendar days) the worst day hands a per-day FPGA a 1.17x smaller multiply datapath, once. + +The spec's open worry (1.8.4: a ROT draw of eight equal values is possible and untested). ROT all equal did NOT +occur in 2^24 days. The analytic rate is 1 in 2.751e10 days (about 1 day in 75 million years). The worst realized +ROT concentration is 2 days with all eight ROT in {1,2,30,31}, at M1 gain 1.0645x. + +Class table, the members that matter (full table in the log): + +| Class | Count / 2^24 | Fraction | Analytic expected | Worst day: M1 cost, gain | +|---|---|---|---|---| +| ROT all equal | 0 | 0 | 3.64e-11 | none | +| ROT distinct <= 3 | 534 | 3.18e-5 | 3.07e-5 | day 11482247: 208, 1.1106x | +| ROT max multiplicity >= 4 | 35631 | 2.12e-3 | 2.35e-3 | day 9506389: 206, 1.1214x | +| ROT any pair sums to 32 | 10022037 | 5.97e-1 | 6.01e-1 | day 4819563: 197, 1.1726x | +| ROT all 8 in {1,2,30,31} | 2 | 1.19e-7 | 7.68e-8 | day 14330190: 217, 1.0645x | +| MUL any = 1 | 0 | 0 | 7.45e-9 | none | +| MUL any popcount <= 4 | 612 | 3.65e-5 | 3.72e-5 | day 7275755: 200, 1.1550x | +| MUL any NAF weight <= 2 | 4 | 2.38e-7 | (expect run) | day 7786546: 221, M2 1.067x | +| MUL any NAF weight <= 3 | 216 | 1.29e-5 | (expect run) | day 332924: 207, M2 1.067x | +| MUL two equal | 0 | 0 | 5.59e-8 | none | +| MUL M2 k >= 2 (gain >= 1.14x) | 0 | 0 | (expect run) | none | +| RC any = 0 | 0 | 0 | 3.73e-9 | none | +| RC + rk = 0 for any of 72 keys | 10 | 5.96e-7 | 2.68e-7 | day 3194363: 218, 1.0596x | + +Every counted fraction tracks the analytic expectation (the draw is unbiased). The M2 DSP metric found zero days +with two or more low-NAF multiplies, so no day frees a second DSP block. The analytic expect run (box 1) is +cross-checking the NAF-weight tail; its numbers land in this section when it finishes. + +Verdict for Q3. A measured weak-day tail exists on the generous M1 FPGA-adder metric: 3.26e-4 of days beat 1.1x, +the single best day reaches 1.1726x. It is bounded and small, zero on the DSP metric and zero on any wall-time +metric, and the spec's untested ROT-all-equal case never occurs and is astronomically rare. A weak day is a +public calendar, so an FPGA attacker could target day 4819563 of the chain for a 1.17x smaller multiply datapath, +which the chip model does not credit as a hash-rate gain. This is a FINDING in that the tail is nonzero, a BOUND +in that the worst case is 1.17x on a metric that does not move the honest or verifier cost. + +## Q2: the round margin (RUNNING) + +Command (box 2), per K in 1..8: +``` +nice -n 10 attack-adv-mixer diffusion --day 20729 --apps K --states 2000000 --threads 32 +``` +Seed: probe states from the harness SplitMix64 seeded per thread from the day index; mixer params the real day +20729 draw. Log: /srv/builds/igneum-wt-adv-mixer/adv/diffusion-20261007T181948Z.log on box 2. + +The census band at 2e6 states is 8 sigma = 0.00566, so a per-cell bias below 0.57 percent is invisible; this +limit is quoted with every row. The plant fired: the degenerate day (MUL all 1, RC all 0, ROT all 16) at K = 1 +gave 7894 dependency holes and 236269 strong-bias cells of 262144, mean flip 0.1739, worst cell 223.6 sigma. A +real day must clear to zero holes and zero strong cells to call the distinguisher out at that K. Results land here +per K as the sweep runs. + +## Q1: the structural shortcut (BOUND, no fold) + +Command (box 2): +``` +attack-adv-mixer fold --day 20729 --trials 1000000 +``` +Seed: harness SplitMix64 seeded from the day index; mixer params the real day 20729 draw. + +| Probe | Result | Reading | +|---|---|---| +| (a) GF(2) affinity of the 2-application map | 1,000,000 of 1,000,000 quadruples violate affinity | the two multiply layers do not fold through the double round; the map is far from affine | +| (b) dead (in_word, out_word) pairs over the full 8-application block | 0 of 256 | every output word depends on every input word after 8 applications | +| (c) key-order agreements M(M(.,rk1),rk2) == M(M(.,rk2),rk1) | 0 of 1,000,000 | key order matters; the 8 round keys cannot be folded | + +Verdict for Q1. On these probes the 8 keyed applications show no cheap composition. The multiply layers of +adjacent applications are separated by a nonlinear double round, so they do not merge (candidate 1 fails). The +drawn double round gives no surviving commutation that would fold keys (candidate 3 fails). The word-dependency +is complete at 8 applications (no separability). This bounds the cheapest folds. It does not rule out a high-order +algebraic or integral distinguisher below the probe's reach; that is owed work (plan section 7). No gain is +priced against the 9,360 ops per item: the 8 applications cost 8x on this evidence. + +## Q4: anything else (RUNNING) + +Two structural notes, both covered by Q3 classes. The 72 round keys are fixed multiples of 0x9E3779B9, not drawn, +so a bad round key is the same every day; the RC + rk = 0 class counts the one interaction (10 days in 2^24). The +item init s[8+i] = t*MUL[i] + RC[i] reuses MUL and RC, so a MUL[i] = 1 would collapse an init word to t + RC[i]; +MUL any = 1 occurred on 0 days. Nothing further found yet. + +## Box-hours spent (so far) + +| Step | Box | Wall | Slot-hours | +|---|---|---|---| +| Build adv-mixer | box 2 | 21 s | 0.006 | +| Build f4-weakday | box 2 | 4 s | 0.001 | +| adv-mixer diffusion plant K=1 (50k) | box 2 | 5 s | 0.001 | +| adv-mixer fold 1e6 | box 2 | ~6 s | 0.002 | +| f4 five plant firings | box 2 | ~3 min | 0.05 | +| f4 census 2^24 | box 2 | 4.4 s | 0.001 | +| Build f4 on box 1 | box 1 | 39 s | 0.011 | +| Q2 diffusion sweep K=1..8 | box 2 | running | tracked at end | +| f4 expect tail | box 1 | running | tracked at end | + +Spent before the two running sweeps: about 0.08 box-hours of the 8-hour first-results budget.