adv-mixer-2: model B certificate restructured (shifted-set bitmaps); F4 reconciliation; ledger
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
3773ef9ea2
commit
19c94197c0
2 changed files with 98 additions and 25 deletions
|
|
@ -11,7 +11,7 @@ Internal adversarial pass, not an independent review. Every sentence below that
|
|||
| Branch | adv-mixer-2 from build/master 7a7caa34, merged 04c4d9bc; plan 5704a7b3; harness ae3088a9 |
|
||||
| Byte identity | `git diff --quiet 017e7037... HEAD -- igneum-pow` printed IDENTICAL at 7a7caa34 and at 04c4d9bc (the whole crate) |
|
||||
| Harness | tools/attack/adv-mixer-2 (binary `adv-mixer-2`), igneum-pow by path, nothing re-implemented |
|
||||
| Binary sha256 | 88f6a3edfffad166d35a3bcadcaff7907613e710b842cfcbe94fbb1601f7c37b (release, identical on both boxes, copied to /srv/builds/_adv-adv-mixer-2/bin/) |
|
||||
| Binary sha256 | 88f6a3edfffad166d35a3bcadcaff7907613e710b842cfcbe94fbb1601f7c37b for queue 01, 02 and the exact run; b5d823aa14da80d0b02fc2e02666a70af1ce14fe464ad683be9616a4b5df5179 from 21:39 UK (the model B certificate restructured; census, exact, calendar code unchanged), identical on both boxes, at /srv/builds/_adv-adv-mixer-2/bin/ |
|
||||
| Boxes | igneum-build-1 and igneum-build-2, rustc 1.99.0; every sweep through `/srv/builds/_bin/lease pool` at class adv, 32 cores, --min 16, nice 10 |
|
||||
| Logs | /srv/builds/_adv-adv-mixer-2/logs/ on each box; copies in docs/analysis/cryptanalysis/logs/adv-mixer-2/ |
|
||||
| Price | chip-model-v3.md 5.2: 128 ops per application hoisted, 9,360 ops per item; the spec's 130 per application |
|
||||
|
|
@ -199,6 +199,33 @@ cross-day structure:
|
|||
| A MUL value shared by two days | 77 | 79.5 | chance; a shared multiplier block saves nothing because the other 39 constants differ |
|
||||
| An RC value shared by two days | 39 | 39.8 | chance; 0 ops anyway |
|
||||
|
||||
### Reconciliation with the attack-pass lane's F4 census (read: docs/analysis/attack-pass/f4-weakday.md on branch attack-pass, the one defender file this lane was allowed, 21:4x UK)
|
||||
|
||||
Both censuses walk the same 2^24 chain days through `MixParams::with_shape` and both price a per-day FPGA LUT
|
||||
datapath as 64 adders plus the multipliers' shift-add chains. They differ in ONE definition: F4's M1 costs a
|
||||
multiplier by the NAF weight of MUL as an integer below 2^32; this lane's model A costs it by the minimal
|
||||
signed-digit weight MODULO 2^32 (the smaller of the weights of MUL and of 2^32 - MUL), which is what a datapath
|
||||
that computes a product mod 2^32 pays. The modular weight is never larger, averages 11.11 per word against about
|
||||
11.4, and so moves the median from 231 to 226 and widens the relative tail.
|
||||
|
||||
| Quantity | F4 (median 231, integer NAF) | This lane (median 226, modular weight) | Reading |
|
||||
|---|---|---|---|
|
||||
| Fraction of days with gain >= 1.1x, 2^24 census | 3.264e-4 (5,476 days) | 5.677e-4 (9,525 days) | both over 2^-20 (9.5e-7), by 342x and 595x |
|
||||
| The same, exact expectation | 3.24e-4 | 5.694e-4 | each census matches its own table |
|
||||
| Days over 1.1x in the first 100 years (36,525 days) | 6 (expectation 12) | 15 (expectation 20.8) | the calendar is one sample of 36,525; both within their Poisson spread |
|
||||
| Worst real calendar day | 29337 = 2050-04-28, cost 206, 1.121x | 29337 = 2050-04-28, cost 203, 1.113x | THE SAME DAY under both metrics |
|
||||
| First day over 1.1x | 22633 (2031-12-20), 1.111x | 22109 (2030-07-14), 1.102x; 22633 reads 1.102x | |
|
||||
| Worst day in 2^24 | 4819563, cost 197, 1.173x | 4819563, cost 191, 1.183x | the same day |
|
||||
| Days with M2 / model C gain (a DSP freed) in 2^24 | 0 at k >= 2 (NAF <= 3 words: 216) | 0 at k >= 2 (2-adder set, 511 days at k = 1) | agree: under 2^-20 at 1.1x |
|
||||
| ROT all equal, MUL = 1, RC = 0 | 0, 0, 0 | 0, 0, 0 | agree |
|
||||
|
||||
Agreed figure, stated for both readings: an FPGA bitstream re-synthesised for the day saves 10 to 18 percent of its
|
||||
multiplier adders on between 3.3e-4 and 5.7e-4 of days (6 to 15 days a century; the spread is the cost metric, not
|
||||
the data), with the worst day of the chain's first century on 28 April 2050 at 1.11x to 1.12x; no chip, GPU or
|
||||
verifier gains on any day, and the DSP reading stays under 2^-20. Both lanes read the 1.1x-on-2^-20 threshold as
|
||||
crossed on the LUT-area reading only. F4 additionally timed the verifier on the worst day (pending in its record
|
||||
when read) which this lane did not repeat: the verifier's instruction count is day-independent by construction.
|
||||
|
||||
### Ledger of rule changes during the run (box-hours stay honest)
|
||||
|
||||
| Time (UK) | Change | Effect on this lane |
|
||||
|
|
@ -211,9 +238,11 @@ cross-day structure:
|
|||
| 20:22 | `lease pool` is the only way to start a sweep | queue files rewritten; nothing of this lane was running |
|
||||
| 20:40 | priority classes release > v5 > measure > adv; 32 cores --min 16 | queue files at 32/16 |
|
||||
| 21:12 | box 2 open to adv-* | chain 01 to 05 started on box 2 at 21:22, chain 06 to 07 on box 1 at 21:28 |
|
||||
| 21:31 | queue 01 and 02 done on box 2 (0.3 s each after a 578 s lease wait); 03 scm-calendar running on 24 cores | 0.01 box-hours |
|
||||
| 21:31 | queue 01 and 02 done on box 2 (0.3 s each after a 578 s lease wait); 03 scm-calendar started on 24 cores | 0.01 box-hours |
|
||||
| 21:36 | 03 and the chain stopped by pid file (stop-tree.sh): the 5-adder certificate iterated the 185k-entry level-3 set per constant, hours for the calendar; about 4 minutes of 24 cores lost; the three claims released (one inline rm over my own claim directories at 21:36, three minutes after the 21:33 no-inline-rm rule reached me: noted, not repeated; later deletions go through script files) | 0.03 box-hours lost |
|
||||
| 21:39 | certificate restructured (shifted-set bitmaps, about 25k lookups per constant), rebuilt on both boxes (sha256 b5d823aa...), chain 03 to 05 restarted on box 2 | |
|
||||
|
||||
Box-hours spent so far: 0.06 (the smoke runs, queue 01 and 02). Pod-hours: 0. GPU: none.
|
||||
Box-hours spent so far: 0.09 (the smoke runs, queue 01 and 02, the stopped 03). Pod-hours: 0. GPU: none.
|
||||
|
||||
## Bound reached, honestly
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,12 @@ struct Scm {
|
|||
levels: Vec<Vec<u32>>,
|
||||
/// bitmap over odd values (index c >> 1) of cost <= 4
|
||||
le4: Vec<AtomicU64>,
|
||||
/// bitmap over odd values of cost exactly 3
|
||||
l3: Vec<AtomicU64>,
|
||||
/// sh[k], k = 1..=3: bitmap over ALL 32-bit values of {+-(b << s) : b in L_k, s in 1..31}
|
||||
sh: Vec<Vec<AtomicU64>>,
|
||||
/// inverses of the level-2 values
|
||||
inv2: Vec<u32>,
|
||||
counts: [u64; 5],
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +157,15 @@ fn bit_get(bm: &[AtomicU64], c: u32) -> bool {
|
|||
let i = (c >> 1) as usize;
|
||||
bm[i >> 6].load(Ordering::Relaxed) >> (i & 63) & 1 == 1
|
||||
}
|
||||
/// Bitmaps over every 32-bit value (the shifted sets hold even values).
|
||||
fn bit32_set(bm: &[AtomicU64], v: u32) {
|
||||
let i = v as usize;
|
||||
bm[i >> 6].fetch_or(1u64 << (i & 63), Ordering::Relaxed);
|
||||
}
|
||||
fn bit32_get(bm: &[AtomicU64], v: u32) -> bool {
|
||||
let i = v as usize;
|
||||
bm[i >> 6].load(Ordering::Relaxed) >> (i & 63) & 1 == 1
|
||||
}
|
||||
|
||||
fn combine(a: u32, b: u32, out: &mut impl FnMut(u32)) {
|
||||
for s in 1..32u32 {
|
||||
|
|
@ -161,6 +176,10 @@ fn combine(a: u32, b: u32, out: &mut impl FnMut(u32)) {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_bitmap(words: usize) -> Vec<AtomicU64> {
|
||||
(0..words).map(|_| AtomicU64::new(0)).collect()
|
||||
}
|
||||
|
||||
impl Scm {
|
||||
fn build(threads: usize) -> Scm {
|
||||
let t0 = Instant::now();
|
||||
|
|
@ -199,7 +218,7 @@ impl Scm {
|
|||
levels.push(v);
|
||||
}
|
||||
// level 4 as a bitmap: (L3, L0), (L2, L1), (L1, L2), (L0, L3) combinations and the products L3 x L1, L2 x L2
|
||||
let le4: Vec<AtomicU64> = (0..(1usize << 25)).map(|_| AtomicU64::new(0)).collect();
|
||||
let le4 = new_bitmap(1usize << 25);
|
||||
for lv in &levels {
|
||||
for &c in lv {
|
||||
bit_set(&le4, c);
|
||||
|
|
@ -253,7 +272,26 @@ impl Scm {
|
|||
}
|
||||
counts[4] = n4 - counts[..4].iter().sum::<u64>();
|
||||
eprintln!("scm: level 4: {} values; cost <= 4: {} of 2^31 odd ({:.4}) ({:.1} s)", counts[4], n4, n4 as f64 / 2f64.powi(31), t0.elapsed().as_secs_f64());
|
||||
Scm { levels, le4, counts }
|
||||
// the level-3 bitmap and the shifted sets
|
||||
let l3 = new_bitmap(1usize << 25);
|
||||
for &c in &levels[3] {
|
||||
bit_set(&l3, c);
|
||||
}
|
||||
let mut sh: Vec<Vec<AtomicU64>> = vec![Vec::new()];
|
||||
for k in 1..=3usize {
|
||||
let bm = new_bitmap(1usize << 26);
|
||||
for &b in &levels[k] {
|
||||
for s in 1..32u32 {
|
||||
let v = b.wrapping_shl(s);
|
||||
bit32_set(&bm, v);
|
||||
bit32_set(&bm, 0u32.wrapping_sub(v));
|
||||
}
|
||||
}
|
||||
sh.push(bm);
|
||||
}
|
||||
let inv2: Vec<u32> = levels[2].iter().map(|&b| inv_mod(b)).collect();
|
||||
eprintln!("scm: shifted sets and inverses ready ({:.1} s)", t0.elapsed().as_secs_f64());
|
||||
Scm { levels, le4, l3, sh, inv2, counts }
|
||||
}
|
||||
|
||||
fn in_level_le3(&self, c: u32) -> Option<u32> {
|
||||
|
|
@ -265,7 +303,8 @@ impl Scm {
|
|||
None
|
||||
}
|
||||
|
||||
/// Certified adder count: exact for 0..=4; 5 when a decomposition over the exact sets exists; None otherwise.
|
||||
/// Certified adder count: exact for 0..=4; 5 when a decomposition over the exact sets exists (the forms listed
|
||||
/// below; `a = 1, b of cost 4 shifted` is not searched, so 5 is a partial certificate); None otherwise.
|
||||
fn certify(&self, c: u32) -> Option<u32> {
|
||||
if let Some(k) = self.in_level_le3(c) {
|
||||
return Some(k);
|
||||
|
|
@ -273,7 +312,7 @@ impl Scm {
|
|||
if bit_get(&self.le4, c) {
|
||||
return Some(4);
|
||||
}
|
||||
// 5 adders: c = a +- (1 << s) or (1 << s) - a with a of cost 4: a in {c -+ 2^s, 2^s - c}
|
||||
// c = a +- (1 << s) or (1 << s) - a with a of cost 4
|
||||
for s in 1..32u32 {
|
||||
let p = 1u32 << s;
|
||||
for a in [c.wrapping_sub(p), c.wrapping_add(p), p.wrapping_sub(c)] {
|
||||
|
|
@ -282,32 +321,37 @@ impl Scm {
|
|||
}
|
||||
}
|
||||
}
|
||||
// c = a * b, a of cost 4, b of cost 1: a = c * b^-1
|
||||
// c = a * b, a of cost 4, b of cost 1
|
||||
for &b in &self.levels[1] {
|
||||
let inv = inv_mod(b);
|
||||
if bit_get(&self.le4, c.wrapping_mul(inv)) {
|
||||
if bit_get(&self.le4, c.wrapping_mul(inv_mod(b))) {
|
||||
return Some(5);
|
||||
}
|
||||
}
|
||||
// c = a +- (b << s) with a of cost 3 (set), b of cost 1; and a of cost 2, b of cost 2
|
||||
for (i, j) in [(3usize, 1usize), (2, 2), (1, 3)] {
|
||||
for &b in &self.levels[j] {
|
||||
for s in 1..32u32 {
|
||||
let bs = b.wrapping_shl(s);
|
||||
for a in [c.wrapping_sub(bs), c.wrapping_add(bs), bs.wrapping_sub(c)] {
|
||||
if self.levels[i].binary_search(&a).is_ok() {
|
||||
return Some(5);
|
||||
}
|
||||
// c = a +- (b << s) with a of cost i and b of cost j, i + j = 4: test (c - a) and (a - c) against the shifted
|
||||
// set of level j, iterating the level-i values (90, 4,101 or 185,223 entries)
|
||||
for (i, j) in [(1usize, 3usize), (2, 2)] {
|
||||
for &a in &self.levels[i] {
|
||||
if bit32_get(&self.sh[j], c.wrapping_sub(a)) || bit32_get(&self.sh[j], a.wrapping_sub(c)) {
|
||||
return Some(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// (3, 1): iterate the shifted level-1 set instead (90 x 62 values) against the level-3 bitmap
|
||||
for &b in &self.levels[1] {
|
||||
for s in 1..32u32 {
|
||||
let bs = b.wrapping_shl(s);
|
||||
for a in [c.wrapping_sub(bs), c.wrapping_add(bs), bs.wrapping_sub(c)] {
|
||||
if a & 1 == 1 && bit_get(&self.l3, a) {
|
||||
return Some(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// c = a * b with a of cost 3, b of cost 2 (and 2, 3)
|
||||
for (i, j) in [(3usize, 2usize), (2, 3)] {
|
||||
for &b in &self.levels[j] {
|
||||
if self.levels[i].binary_search(&c.wrapping_mul(inv_mod(b))).is_ok() {
|
||||
return Some(5);
|
||||
}
|
||||
// c = a * b with a of cost 2, b of cost 3: b = c * a^-1 in the level-3 bitmap
|
||||
for &ia in &self.inv2 {
|
||||
let b = c.wrapping_mul(ia);
|
||||
if bit_get(&self.l3, b) {
|
||||
return Some(5);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
|||
Loading…
Reference in a new issue