adv-mixer-2: attack plan for the day-key weakness class of M_r
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
63f4437f71
commit
bffda48097
1 changed files with 112 additions and 0 deletions
112
docs/plans/cryptanalysis/plan-mixer-2.md
Normal file
112
docs/plans/cryptanalysis/plan-mixer-2.md
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# Attack plan: the day-key weakness class of the mixer M_r (lane adv-mixer-2)
|
||||
|
||||
Internal adversarial pass, not an independent review. Every sentence below that could be quoted carries that label.
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Lane | adv-mixer-2, question class: weak parameter draws of M_r (the day-key weakness class) |
|
||||
| Target commit | 017e70376489251e18564c0abce7e466e606c8b3 (class v4 sub-version 3, object byte 7) |
|
||||
| Branch | adv-mixer-2, cut from build/master 7a7caa34 at 19:22 BST, 7 October 2026; merged build/master 04c4d9bc at 19:40 BST |
|
||||
| Byte identity | `git diff --quiet 017e7037... HEAD -- igneum-pow` printed IDENTICAL at both 7a7caa34 and 04c4d9bc (the whole crate, every file) |
|
||||
| Attacker | an outsider with the public kit; nothing read under docs/ beyond the spec, chip-model-v3.md sections 1, 2, 5, 6 and the siblings' cryptanalysis files |
|
||||
| Plan due | 20:25 BST, 7 October 2026. First report rows due 00:00 BST, 8 October |
|
||||
| Toolchain | rustc 1.99.0 on both boxes; the Mac's PATH rustc is 1.69.0 and is never used (no cargo on the Mac) |
|
||||
|
||||
## 1. The target, restated from spec and code
|
||||
|
||||
Spec 01 sections 1.3, 1.8.1, 1.8.4, 1.8.5, 1.12; code `igneum-pow/src/seed.rs`, `memhard.rs`, `bind.rs`, `generator.rs`.
|
||||
|
||||
1. The day. `bind::day_index(ts_ms) = ts_ms / 86,400,000`, so the day is the Unix day count. Day bytes are
|
||||
`"igneum-day/" || le64(day)` (19 bytes). The Devnet 3 pack carries day 20733 and the public epoch-0 pack day
|
||||
20730; the genesis day of the chain is 20729 (3 October 2026, `bind.rs` test). Nothing from the chain enters the
|
||||
day key: every future day's parameters are computable today.
|
||||
2. The day key. `K[0..7] = seed_words_from_bytes(day_bytes)`: four FNV-1a 64 passes with salted bases, each
|
||||
finished with the murmur mix, split into two 32-bit words. Only `K[0] | K[1] << 32` (salt 0, 64 bits) seeds the
|
||||
mixer stream. K[2..7] enter the item init only.
|
||||
3. The draw. One SplitMix64 stream from that 64-bit seed: `ROT[i] = 1 + next() mod 31` for i in 0..7, then
|
||||
`MUL[i] = low32(next()) | 1` for 0..15, then `RC[i] = low32(next())` for 0..15. Forty draws, in that order.
|
||||
4. The mixer. `M(s, rk)`: per word `s[i] = (s[i] ^ (RC[i] + rk)) * MUL[i]`, then one ChaCha-shaped double round
|
||||
(four column quarter rounds with ROT[0..3], four diagonal with ROT[4..7]). Class v4 is `MX8` plus a shadow
|
||||
block: `mixer_mult = 8`, `derive_len = 0`, so M is applied 8 times between dependent reads with round keys
|
||||
`(r*8 + j + 1) * 0x9E3779B9`, 72 applications per item, 9 rounds of 8.
|
||||
5. The price. chip-model-v3.md 5.2: 128 ops per application with `RC[i] + rk` hoisted, 9,360 ops per item
|
||||
(72 x 128 + 144 init and fold). Every gain below is priced against 9,360 per item, and against 130 per
|
||||
application where the spec's figure is the reference.
|
||||
|
||||
A weak day is a draw whose constants let a datapath BUILT FOR THAT DAY do less than 9,360 ops' worth of work per
|
||||
item. A bit-exact verifier never lets any attacker skip an application, so the per-day gain lives only in what a
|
||||
constant costs when it is baked into hardware: a constant rotation is wiring (0 ops on every day), a constant XOR
|
||||
is inverters (0 ops on every day), and a constant multiply is a shift-add chain whose length depends on the day.
|
||||
The only per-day attacker that exists is an FPGA bitstream synthesised for the day (an ASIC cannot be masked per
|
||||
day). The absolute standing of that attacker against a GPU is a separate question and is stated as unknown.
|
||||
|
||||
## 2. The questions, in order
|
||||
|
||||
| # | Question | Result shape |
|
||||
|---|---|---|
|
||||
| Q1 | Census of structural classes over 2^24 consecutive chain days from genesis (ROT, MUL, RC, cross-field) | counts, fractions, analytic expectation, worst day per class |
|
||||
| Q2 | Per-day gain under three cost models (below), over the same 2^24, then 2^32 days | gain histogram, fraction over 1.1x, 1.2x, 1.5x, 2x, largest gain, its day |
|
||||
| Q3 | Exact tail by convolution: per-word cost table over all 2^31 odd constants, 16-fold convolution | P(gain > 1.1x) exact under model A; compared with Q2's census |
|
||||
| Q4 | The real calendar: every day from genesis for 100 years (20729 to 57253) | worst day with ISO date and gain under each model; the first ten |
|
||||
| Q5 | Cross-day structure: 64-bit seed collisions, stream shifts (seeds differing by k x 0x9E3779B97F4A7C15, |k| <= 72), shared constants between days | counts over the calendar and over 2^24 days |
|
||||
| Q6 | ROT functional check: avalanche of 1, 2, 4, 8 applications and of the 22 address bits, on the worst ROT days found and on the planted all-equal day | diffusion numbers against a median day; a per-day gain only if a bit-exact shortcut follows, else 0 |
|
||||
| Q7 | Redraw rule if the fraction with gain over 1.1x exceeds 2^-20 per day | the rule, its own census, its cost to the honest miner |
|
||||
| Q8 | Anything else seen in Q1 to Q7 | measured or stated unknown |
|
||||
|
||||
Cost models, defined here and not borrowed:
|
||||
|
||||
| Model | Cost per application | What it prices |
|
||||
|---|---|---|
|
||||
| A, LUT shift-add | 64 + sum_i (w32(MUL_i) - 1), with w32 the minimal signed-digit weight of MUL_i MODULO 2^32 (the smaller of the NAF weight of the constant and of its 2^32 complement, digits at position 32 and above discarded) | an FPGA datapath for the day: adders for the quarter rounds (32 add + 32 xor) plus a canonical signed-digit multiplier per word; constant rotations and XORs free |
|
||||
| B, certified shift-add | 64 + sum_i scm_i, with scm_i the smallest adder count for which a chain is CERTIFIED (exact sets for 1, 2, 3 adders by bitmap; a 4-adder certificate by decomposition over those sets; otherwise w32 - 1) | the same datapath with the multiplier optimised, as a synthesiser would; an upper bound on the attacker's cost, so a lower bound on his gain |
|
||||
| C, DSP | 16 / (16 - k), k the words whose constant has w32 <= 3 and leaves its DSP block for LUTs | an FPGA whose multipliers sit in DSP blocks, value-independent, with the cheap ones moved out |
|
||||
|
||||
Gain of a day under a model = the median day's cost over the day's cost. A day's MUL = 1 words count 0 adders
|
||||
under A and B (the planted shape).
|
||||
|
||||
## 3. Method and tool per question
|
||||
|
||||
Harness: `tools/attack/adv-mixer-2/` (crate `attack-adv-mixer-2`, binary `adv-mixer-2`, `igneum-pow` by path,
|
||||
nothing re-implemented: every key and draw comes from `bind::day_bytes`, `seed_words_from_bytes`,
|
||||
`MixParams::with_shape(key, Shape::for_class(&V4_CLASS))`, and `memhard::mixer` for Q6). Commands:
|
||||
|
||||
| Command | Question | Known-failed shape (must fire) | Box-hours (estimate) |
|
||||
|---|---|---|---|
|
||||
| `census --from 20729 --count 2^24 --threads N` | Q1, Q2 (models A, C; B on the tail) | `plant alleq`, `plant mul1`, `plant mul1all`, `plant rcrk0`: the day-20729 draw with the field replaced, run through the same classifier, must land in its class and show its gain (mul1all: cost 64 under A, gain about 3.4x) | 0.1 |
|
||||
| `census --from 20729 --count 2^32 --threads N` | Q2 extended | same plants | 1.5 |
|
||||
| `exact --threads N` | Q3 | the table must give P(MUL = 1) = 2^-31 and the convolution's mean must match the census mean within 0.01 | 0.3 |
|
||||
| `scm-build` then `scm-refine --days <file>` | Q2 model B on the calendar, on the census tail (lowest 2^14 days under A) and on a 2^16-day random sample | `scm-refine` on MUL = 3, 5, 7, 9 must certify 1 adder; on 0x9E3779B9 it must certify at most w32 - 1 | 1.5 |
|
||||
| `calendar --from 20729 --years 100` | Q4, Q5 (collisions, shifts) | a planted pair of days with seeds differing by one gamma must be found by the shift scan | 0.1 |
|
||||
| `avalanche --index <day> [--plant alleq]` | Q6 | the planted all-equal ROT day runs beside a median day; a `--plant rot1` (all ROT = 1) must show weaker single-application diffusion than the median | 0.5 |
|
||||
| `redraw-census` | Q7 | the proposed rule applied to 2^24 days: fraction redrawn, fraction over 1.1x after the rule, which must be 0 | 0.2 |
|
||||
|
||||
Runs over 10 minutes go through `tools/attack/adv-mixer-2/run-box.sh` on the box: `nohup nice -n 10` in a setsid
|
||||
process group, pid file beside the log under `/srv/builds/igneum-wt-adv-mixer-2/adv/`, a 5 s poll of
|
||||
`/srv/builds/_locks` (build-k, quiet, core-*) that SIGSTOPs the group while any is held and SIGCONTs when clear,
|
||||
the pattern of `infra/build-server/capacity/run.sh`. Every sweep is a queue file
|
||||
`/srv/builds/_adv/mixer/queue/NN-adv-mixer-2-<name>.sh` on build-2, claimed by `mkdir .../claims/<file>` before it
|
||||
runs. CPU-bound sweeps run on build-1 (load 9 to 16 at 19:40 BST against build-2's 55 to 65); the binary is
|
||||
built on both boxes so a queue file runs on either. No GPU is used; no row needs one.
|
||||
|
||||
Total estimate: about 4 box-hours. 8 is the reading line, 16 the ask line.
|
||||
|
||||
## 4. What is already known from the siblings (read, not relied on)
|
||||
|
||||
adv-mixer's report (branch build/adv-mixer) ran the f4 census: M1 cost mean 231, 3.26e-4 of days over 1.1x on
|
||||
its generous metric, 0 days with M2 gain, ROT all equal never seen. This lane recomputes with its own cost models
|
||||
(modular weight, certified chains), adds the exact tail, the real calendar with dates, the cross-day structure and a
|
||||
redraw rule. Where the two censuses agree the agreement is stated; where they differ the difference is explained.
|
||||
|
||||
## 5. Files opened (the outsider rule)
|
||||
|
||||
| File | Why |
|
||||
|---|---|
|
||||
| igneum-pow/Cargo.toml, Cargo.lock (listed), src/seed.rs, src/memhard.rs, src/bind.rs, src/generator.rs (LoadClass, MX8, V3_CLASS, V4_CLASS), tests/mixer.rs (header, contract) | the target |
|
||||
| docs/spec/01-lottery-hash.md at 017e7037: 1.2, 1.3, 1.8, 1.12 | the target |
|
||||
| docs/analysis/chip-model-v3.md sections 1, 2, 5, 6 | the price |
|
||||
| proto-cuda/packs-ca3-v4/ (listing), v4-devnet-epoch0/program.json (day fields) | the public kit |
|
||||
| /srv/artefacts/packs/v4-devnet3-epoch0.zip on build-1: sha256 e025750f... verified | the public kit |
|
||||
| tools/attack/f4-weakday/{Cargo.toml, src/main.rs} from build/attack-pass | prior harness, read only |
|
||||
| tools/attack/f8-uniform/{Cargo.toml, src/main.rs} (header) | prior harness, read only |
|
||||
| tools/build-remote.sh, infra/build-server/lib.sh, remote-run.sh, capacity/lib.sh, capacity/run.sh, capacity/ (listing) | operating files |
|
||||
| build/adv-mixer: docs/plans/cryptanalysis/plan-mixer.md, docs/analysis/cryptanalysis/report-mixer.md; build/adv-accept and build/adv-cache: file listings only | siblings |
|
||||
Loading…
Reference in a new issue