From e1a910c7fc2e0c5dc3fe4e632f073b1a239e04f2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:39:54 +0000 Subject: [PATCH 01/19] X4 (1.5x): byte-identical reg64c address-mix forms (direct, generated, prefix) behind --reg64-form and --reg64-cpu-form; the fold stays the definition and the default Co-Authored-By: Claude Opus 5.5 --- igneum-pow/src/emit.rs | 83 +++++++++- igneum-pow/src/lib.rs | 1 + igneum-pow/src/main.rs | 9 +- igneum-pow/src/reg64form.rs | 322 ++++++++++++++++++++++++++++++++++++ igneum-pow/src/verify.rs | 29 +++- 5 files changed, 433 insertions(+), 11 deletions(-) create mode 100644 igneum-pow/src/reg64form.rs diff --git a/igneum-pow/src/emit.rs b/igneum-pow/src/emit.rs index 13ffe7d88..220db4306 100644 --- a/igneum-pow/src/emit.rs +++ b/igneum-pow/src/emit.rs @@ -1174,7 +1174,9 @@ fn reg_decl(p: &Program, ty: &str) -> String { } let names: Vec = (0..p.registers()).map(|k| format!("r{k}")).collect(); let m = if p.address_mix() { - if ty == "uint32_t" && reg64_prefix() { + if ty == "uint32_t" && reg64_form() == crate::reg64form::Reg64Form::Generated { + format!("\n {ty} m, S, p_, g0, g1, g2, g3, g4, g5, g6, g7; // reg64 full chain in the X4 generated form: the eight group sums, recomputed where the schedule wrote") + } else if ty == "uint32_t" && reg64_prefix() { format!("\n {ty} m, S, p_, t_; // reg64 full chain in the F05 prefix form: S the running xor of the rotated registers, p_ the prefix, t_ the old term") } else { format!("\n {ty} m; // reg64 full chain: the address mix of all 64 registers before every load") @@ -1194,14 +1196,65 @@ fn reg_decl(p: &Program, ty: &str) -> String { /// `r[s] ^ ror(P_s, 1) ^ (S ^ P_s ^ a[s])` with `P_s` the xor of the first `s` terms. The same hash, the same vectors /// (`verify::reg64_address_source`); a measurement text for the fleet, never the definition. OpenCL and Metal keep /// the fold. -static REG64_PREFIX: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); - +/// X4 of the 1.5x programme (9 October 2026): the switch is one value of the CUDA text's form +/// (`crate::reg64form`, `igneum-pow export --reg64-form fold|direct|generated|prefix`); `--reg64-prefix` is `prefix`. pub fn set_reg64_prefix(on: bool) { - REG64_PREFIX.store(on, std::sync::atomic::Ordering::Relaxed); + crate::reg64form::set_gpu_form(if on { crate::reg64form::Reg64Form::Prefix } else { crate::reg64form::Reg64Form::Fold }); } pub fn reg64_prefix() -> bool { - REG64_PREFIX.load(std::sync::atomic::Ordering::Relaxed) + crate::reg64form::gpu_form() == crate::reg64form::Reg64Form::Prefix +} + +/// The CUDA text's form of the reg64 address mix (the fold unless `--reg64-form` names another). +fn reg64_form() -> crate::reg64form::Reg64Form { + crate::reg64form::gpu_form() +} + +/// X4 direct form: the mix statement before a load of source `src` as the definition's closed sum, one rotation +/// per term (`rotl(rK, (62 - k) mod 32)` before the source, `(63 - k) mod 32` after it), xored as a balanced tree. +fn reg64_direct_mix_line(src: u8) -> String { + let s = src as usize; + let terms: Vec = (0..64) + .filter(|&k| k != s) + .map(|k| { + let n = crate::reg64form::direct_rot(k, s); + if n == 0 { format!("r{k}") } else { format!("rotl_imm(r{k}, {n}u)") } + }) + .collect(); + format!("m = {};", xor_tree(&terms)) +} + +/// A balanced xor tree of `terms` as text (parenthesised so the compiler is handed the tree, not a chain). +fn xor_tree(terms: &[String]) -> String { + match terms.len() { + 0 => "0u".to_string(), + 1 => terms[0].clone(), + n => format!("({} ^ {})", xor_tree(&terms[..n / 2]), xor_tree(&terms[n / 2..])), + } +} + +/// X4 generated form: one group sum `gJ = a[8J] ^ ... ^ a[8J + 7]` as a statement. +fn reg64_group_line(j: usize) -> String { + let terms: Vec = (j * 8..j * 8 + 8).map(reg64_term).collect(); + format!("g{j} = {};", xor_tree(&terms)) +} + +/// X4 generated form: the statements before a load of source `src` (the plan's stale groups recomputed, then +/// `m = ror(P, 1) ^ S ^ P ^ a[src]` with `S` the eight groups and `P` the groups before src's plus the partial). +fn reg64_generated_mix_line(recompute: &[usize], src: u8) -> String { + let s = src as usize; + let mut out = String::new(); + for &j in recompute { + out.push_str(®64_group_line(j)); + out.push(' '); + } + let groups: Vec = (0..8).map(|j| format!("g{j}")).collect(); + let jj = s / 8; + let mut prefix: Vec = (0..jj).map(|j| format!("g{j}")).collect(); + prefix.extend((jj * 8..s).map(reg64_term)); + out.push_str(&format!("S = {}; p_ = {}; m = rotr_var(p_, 1u) ^ S ^ p_ ^ {};", xor_tree(&groups), xor_tree(&prefix), reg64_term(s))); + out } /// `rotl(rK, (63 - k) mod 32)` as text; a rotation of 0 is the register itself (`rotl_imm` takes 1..31). @@ -1220,6 +1273,13 @@ fn reg64_prefix_mix_line(src: u8) -> String { /// The prefix form's running total after the register init: `S = a[0] ^ ... ^ a[63]`. fn reg64_prefix_init(p: &Program) -> String { + if p.class.reg64 && p.address_mix() && reg64_form() == crate::reg64form::Reg64Form::Generated { + let mut s = String::from(" // X4 generated form: the eight group sums of the rotated registers\n"); + for j in 0..8 { + s.push_str(&format!(" {}\n", reg64_group_line(j))); + } + return s; + } if !p.class.reg64 || !p.address_mix() || !reg64_prefix() { return String::new(); } @@ -1278,13 +1338,22 @@ fn cuda_instr_lines(p: &Program, geom: DatasetGeom) -> String { // just before the load (the verifier's addr_src, the same chain) let address_mix = p.address_mix(); let addr_src = |a: &str| -> String { if address_mix { format!("({a} ^ m)") } else { a.to_string() } }; - for (k, ins) in p.scheduled().iter().enumerate() { + let scheduled = p.scheduled(); + let form = reg64_form(); + let plan = if address_mix && form == crate::reg64form::Reg64Form::Generated { crate::reg64form::generated_plan(&scheduled, &p.shadow) } else { Vec::new() }; + for (k, ins) in scheduled.iter().enumerate() { let d = format!("r{}", ins.dst); let a = format!("r{}", ins.src); let b = format!("r{}", ins.src2); let prefix = address_mix && reg64_prefix(); if address_mix && ins.op == Op::Load { - s.push_str(&format!(" {}\n", if prefix { reg64_prefix_mix_line(ins.src) } else { reg64_mix_line(p, ins.src) })); + let line = match form { + crate::reg64form::Reg64Form::Prefix => reg64_prefix_mix_line(ins.src), + crate::reg64form::Reg64Form::Direct => reg64_direct_mix_line(ins.src), + crate::reg64form::Reg64Form::Generated => reg64_generated_mix_line(&plan[k], ins.src), + _ => reg64_mix_line(p, ins.src), + }; + s.push_str(&format!(" {line}\n")); } if prefix { // the old term of the destination, so S can drop it after the write diff --git a/igneum-pow/src/lib.rs b/igneum-pow/src/lib.rs index 690ddb0bc..32aa9d7d0 100644 --- a/igneum-pow/src/lib.rs +++ b/igneum-pow/src/lib.rs @@ -30,6 +30,7 @@ pub mod emit; pub mod generator; pub mod memhard; pub mod packcheck; +pub mod reg64form; pub mod seed; pub mod state; pub mod verify; diff --git a/igneum-pow/src/main.rs b/igneum-pow/src/main.rs index 205f6ce66..fc81d0955 100644 --- a/igneum-pow/src/main.rs +++ b/igneum-pow/src/main.rs @@ -123,7 +123,9 @@ fn usage() -> ! { \x20 --dataset-words N research class ds55: the dataset at N words (a multiple of 65,536 in 2^28 ..= 2^31; 1476395008 = 5.5 GiB); a non-power-of-two uses idx = (src * N) >> 32 in every load (spec 01 section 1.13.3), a power of two is --dataset-log2\n\\ \x20 --reg64 the 64-register window per lane over the class (research; the same as --class +reg64; CUDA, OpenCL and Metal texts)\n\ \x20 --reg64-chain reg64 with the full-chain address mix: every load's address consumes all 64 registers (the same as --class +reg64c)\n\ - \x20 --reg64-prefix export: the CUDA texts carry the reg64 chain in its closed prefix form (review B's F05; the same hash and vectors, a measurement text)" + \x20 --reg64-prefix export: the CUDA texts carry the reg64 chain in its closed prefix form (review B's F05; the same hash and vectors, a measurement text)\n\ + \x20 --reg64-form export: the CUDA texts' reg64 address-mix form, fold (the default), direct, generated or prefix (X4, 1.5x programme; the same hash)\n\ + \x20 --reg64-cpu-form the CPU interpreter computes the reg64 address mix in form f (fold, direct, generated, prefix, or wrong: the known-failed form), the X4 differential only" ); std::process::exit(2) } @@ -191,6 +193,11 @@ fn parse() -> Args { a.reg64_chain = true; } "--reg64-prefix" => igneum_pow::emit::set_reg64_prefix(true), + "--reg64-form" => match igneum_pow::reg64form::Reg64Form::parse(&val()) { + Some(igneum_pow::reg64form::Reg64Form::Wrong) | None => usage(), + Some(f) => igneum_pow::reg64form::set_gpu_form(f), + }, + "--reg64-cpu-form" => igneum_pow::reg64form::set_cpu_form(igneum_pow::reg64form::Reg64Form::parse(&val()).unwrap_or_else(|| usage())), _ => usage(), } } diff --git a/igneum-pow/src/reg64form.rs b/igneum-pow/src/reg64form.rs new file mode 100644 index 000000000..d0de3dbfb --- /dev/null +++ b/igneum-pow/src/reg64form.rs @@ -0,0 +1,322 @@ +//! X4 of the 1.5x programme (9 October 2026, the k lane): byte-identical implementation forms of the class v6 +//! reg64c address mix (`docs/analysis/class-v6/1p5x/x4/README.md`). The DEFINITION stays the verifier's fold +//! (`verify::step`'s `addr_src`: `m = r[k0]; m = rotl(m, 1) ^ r[k1]; ...` over the 63 registers other than the load's +//! source `s`, in index order, the address source `r[s] ^ m`). Every form here computes the same 32-bit word on every +//! register state and every source; none of them is a consensus change, and the default everywhere is the fold. +//! +//! * `Fold`: the frozen text (the 63-term dependent chain per load). +//! * `Direct`: the definition's closed sum written directly, `m = XOR_{ks} rotl(r[k], (63 - k) mod 32)`, a balanced XOR tree with no carried chain and no state. +//! * `Generated`: a code-generated form over eight group sums `g_j = XOR_{k in 8j..8j+7} a[k]`, `a[k] = rotl(r[k], +//! (63 - k) mod 32)`. The generator reads the static schedule and recomputes, before each load, only the groups +//! written since the previous load ([`generated_plan`]); the shadow block draws its registers from r0..r7 +//! (`generator.rs`, `dst = rng.below(8)`), so the 55,296 shadow writes dirty group 0 only. A load's source is +//! `r[s] ^ ror(P_s, 1) ^ S ^ P_s ^ a[s]` with `S = XOR g_j` and `P_s` the whole groups before `s`'s group plus the +//! in-group partial (review B's F05 identity, `verify::reg64_address_source`). +//! * `Prefix`: review B's F05 text as landed (`--reg64-prefix`): a running `S` updated after every write (main and +//! shadow), `P_s` recomputed per load. +//! * `Wrong`: the known-failed variant for the differential test only (`r[s] ^ S ^ a[s]`, every term rotated as if it +//! sat after the source); the differential must refuse it. Never emitted. + +use std::sync::atomic::{AtomicU8, Ordering}; + +use crate::generator::{Instr, Op, LANES}; + +/// Registers per group of the generated form. +pub const GROUP: usize = 8; +/// Groups of the generated form (64 registers). +pub const GROUPS: usize = 8; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Reg64Form { + Fold, + Direct, + Generated, + Prefix, + Wrong, +} + +impl Reg64Form { + pub fn parse(s: &str) -> Option { + Some(match s { + "fold" => Reg64Form::Fold, + "direct" => Reg64Form::Direct, + "generated" => Reg64Form::Generated, + "prefix" => Reg64Form::Prefix, + "wrong" => Reg64Form::Wrong, + _ => return None, + }) + } + pub fn name(self) -> &'static str { + match self { + Reg64Form::Fold => "fold", + Reg64Form::Direct => "direct", + Reg64Form::Generated => "generated", + Reg64Form::Prefix => "prefix", + Reg64Form::Wrong => "wrong", + } + } + fn code(self) -> u8 { + self as u8 + } + fn from_code(c: u8) -> Reg64Form { + [Reg64Form::Fold, Reg64Form::Direct, Reg64Form::Generated, Reg64Form::Prefix, Reg64Form::Wrong][c as usize] + } +} + +static GPU_FORM: AtomicU8 = AtomicU8::new(0); +static CPU_FORM: AtomicU8 = AtomicU8::new(0); + +/// The CUDA text's form (`igneum-pow export --reg64-form
`; `--reg64-prefix` is `prefix`). `Wrong` is refused. +pub fn set_gpu_form(f: Reg64Form) { + assert!(f != Reg64Form::Wrong, "the known-failed form is never emitted"); + GPU_FORM.store(f.code(), Ordering::Relaxed); +} +pub fn gpu_form() -> Reg64Form { + Reg64Form::from_code(GPU_FORM.load(Ordering::Relaxed)) +} +/// The CPU interpreter's form (`--reg64-cpu-form `, the differential test's switch). The fold is the +/// definition and the default; every other form runs beside it only in the X4 differential. +pub fn set_cpu_form(f: Reg64Form) { + CPU_FORM.store(f.code(), Ordering::Relaxed); +} +pub fn cpu_form() -> Reg64Form { + Reg64Form::from_code(CPU_FORM.load(Ordering::Relaxed)) +} + +/// `a[k] = rotl(r[k], (63 - k) mod 32)`: register k's rotation in the full 64-register chain. +#[inline(always)] +pub fn term(r: &[u32; 64], k: usize) -> u32 { + r[k].rotate_left(((63 - k) % 32) as u32) +} + +/// The rotation register `k` carries in the chain of a load whose source is `s` (k != s). +#[inline(always)] +pub fn direct_rot(k: usize, s: usize) -> u32 { + if k < s { ((62 - k) % 32) as u32 } else { ((63 - k) % 32) as u32 } +} + +/// The definition, one lane: `r[s] ^ m` with the 63-term chain (the same loop as `verify::step`). +pub fn fold(r: &[u32; 64], s: usize) -> u32 { + let mut m = 0u32; + let mut started = false; + for (k, &v) in r.iter().enumerate() { + if k == s { + continue; + } + m = if started { m.rotate_left(1) ^ v } else { v }; + started = true; + } + r[s] ^ m +} + +/// The direct form: the closed sum, one rotation per term. +pub fn direct(r: &[u32; 64], s: usize) -> u32 { + let mut m = 0u32; + for k in 0..64 { + if k != s { + m ^= r[k].rotate_left(direct_rot(k, s)); + } + } + r[s] ^ m +} + +/// One group sum of the generated form. +#[inline(always)] +pub fn group(r: &[u32; 64], j: usize) -> u32 { + let mut g = 0u32; + for k in j * GROUP..(j + 1) * GROUP { + g ^= term(r, k); + } + g +} + +/// The generated form's query from the cached group sums `g` (stale groups give a wrong word: the plan's job). +pub fn grouped(g: &[u32; GROUPS], r: &[u32; 64], s: usize) -> u32 { + let total = g.iter().fold(0u32, |x, y| x ^ y); + let j = s / GROUP; + let mut p = g[..j].iter().fold(0u32, |x, y| x ^ y); + for k in j * GROUP..s { + p ^= term(r, k); + } + r[s] ^ p.rotate_right(1) ^ total ^ p ^ term(r, s) +} + +/// The prefix form's query from a running total `total` (= XOR of every `a[k]` when kept fresh). +pub fn prefixed(total: u32, r: &[u32; 64], s: usize) -> u32 { + let mut p = 0u32; + for k in 0..s { + p ^= term(r, k); + } + r[s] ^ p.rotate_right(1) ^ total ^ p ^ term(r, s) +} + +/// The known-failed form (the F05 test's wrong variant). +pub fn wrong(r: &[u32; 64], s: usize) -> u32 { + let total = (0..64).map(|k| term(r, k)).fold(0, |x, y| x ^ y); + r[s] ^ total ^ term(r, s) +} + +/// The generated form's static plan: for each statement of the scheduled list, the groups to recompute just before +/// it (non-empty only at loads). The groups entering an iteration are those written after the last load of the +/// previous iteration's list plus every group the shadow block writes (group 0 on the shipped class); the kernel +/// computes all eight after the register init, so iteration 0 recomputes a superset (idempotent). +pub fn generated_plan(scheduled: &[Instr], shadow: &[Instr]) -> Vec> { + let all: u8 = 0xff; + let bit = |ins: &Instr| 1u8 << (ins.dst as usize / GROUP); + let mut dirty = all; + for ins in scheduled { + if ins.op == Op::Load { + dirty = 0; + } + dirty |= bit(ins); + } + let shadow_groups = shadow.iter().fold(0u8, |m, ins| m | bit(ins)); + let mut dirty = dirty | shadow_groups; + let mut plan = Vec::with_capacity(scheduled.len()); + for ins in scheduled { + if ins.op == Op::Load { + plan.push((0..GROUPS).filter(|j| dirty & (1 << j) != 0).collect()); + dirty = 0; + } else { + plan.push(Vec::new()); + } + dirty |= bit(ins); + } + plan +} + +/// The groups the shadow block writes (a bit per group). +pub fn shadow_group_mask(shadow: &[Instr]) -> u8 { + shadow.iter().fold(0u8, |m, ins| m | (1u8 << (ins.dst as usize / GROUP))) +} + +/// Counts of the generated plan per iteration: (loads, group recomputes) — the op count's input. +pub fn plan_counts(plan: &[Vec], scheduled: &[Instr]) -> (usize, usize) { + let loads = scheduled.iter().filter(|i| i.op == Op::Load).count(); + let recomputes = plan.iter().map(|v| v.len()).sum(); + (loads, recomputes) +} + +/// The CPU interpreter's state for a form (the differential's emulation of each kernel text): the generated +/// form's eight cached group sums per lane, recomputed only where [`generated_plan`] says; the prefix form's running +/// total per lane, updated after every write (main list and shadow), as the F05 text does. +pub struct FormState { + form: Reg64Form, + plan: Vec>, + groups: [[u32; LANES]; GROUPS], + total: [u32; LANES], +} + +fn lane_regs(r: &[[u32; LANES]], lane: usize) -> [u32; 64] { + std::array::from_fn(|k| r[k][lane]) +} + +impl FormState { + pub fn new(form: Reg64Form, plan: Vec>) -> FormState { + FormState { form, plan, groups: [[0; LANES]; GROUPS], total: [0; LANES] } + } + /// After the register init (and the probe's flip): every group and the running total from the live registers. + pub fn init(&mut self, r: &[[u32; LANES]]) { + for lane in 0..LANES { + let regs = lane_regs(r, lane); + for j in 0..GROUPS { + self.groups[j][lane] = group(®s, j); + } + self.total[lane] = (0..64).map(|k| term(®s, k)).fold(0, |x, y| x ^ y); + } + } + /// After a write of register `d` whose value before the write was `old`: the prefix form's running total moves + /// by the term's change; the generated form keeps its groups stale until the plan recomputes them. + pub fn after_write(&mut self, r: &[[u32; LANES]], d: usize, old: &[u32; LANES]) { + if self.form == Reg64Form::Prefix { + let rot = ((63 - d) % 32) as u32; + for lane in 0..LANES { + self.total[lane] ^= old[lane].rotate_left(rot) ^ r[d][lane].rotate_left(rot); + } + } + } + /// The address source of the load at scheduled position `k` with source `s`, per lane, in this form. + pub fn source(&mut self, r: &[[u32; LANES]], k: usize, s: usize) -> [u32; LANES] { + if self.form == Reg64Form::Generated { + for &j in &self.plan[k] { + for lane in 0..LANES { + let regs = lane_regs(r, lane); + self.groups[j][lane] = group(®s, j); + } + } + } + std::array::from_fn(|lane| { + let regs = lane_regs(r, lane); + match self.form { + Reg64Form::Fold => fold(®s, s), + Reg64Form::Direct => direct(®s, s), + Reg64Form::Generated => grouped(&std::array::from_fn(|j| self.groups[j][lane]), ®s, s), + Reg64Form::Prefix => prefixed(self.total[lane], ®s, s), + Reg64Form::Wrong => wrong(®s, s), + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn stream(seed: u64) -> impl FnMut() -> u32 { + let mut x = seed; + move || { + x = x.wrapping_add(0x9e37_79b9_7f4a_7c15); + let mut z = x; + z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); + (z ^ (z >> 31)) as u32 + } + } + + /// Known-failed first: the wrong form must disagree with the fold somewhere; then the three forms agree with the + /// fold on every source over 4,096 random states and on the structured states (all zero, all ones, one bit, + /// the init rule's registers). + #[test] + fn x4_forms_equal_the_fold_and_the_wrong_form_is_refused() { + let mut next = stream(0x1505_0004); + let mut wrong_differs = 0usize; + let mut states: Vec<[u32; 64]> = Vec::new(); + for _ in 0..4096 { + let mut r = [0u32; 64]; + for v in r.iter_mut() { + *v = next(); + } + states.push(r); + } + states.push([0u32; 64]); + states.push([u32::MAX; 64]); + for b in 0..64 * 32 { + let mut r = [0u32; 64]; + r[b / 32] = 1 << (b % 32); + states.push(r); + } + let mut r = [0u32; 64]; + for k in 0..8 { + r[k] = next(); + } + for k in 8..64 { + r[k] = r[k & 7].wrapping_mul(0x9e37_79b9).wrapping_add(k as u32); + } + states.push(r); + for r in &states { + let g: [u32; GROUPS] = std::array::from_fn(|j| group(r, j)); + let total = (0..64).map(|k| term(r, k)).fold(0, |x, y| x ^ y); + for s in 0..64 { + let want = fold(r, s); + if wrong(r, s) != want { + wrong_differs += 1; + } + assert_eq!(direct(r, s), want, "direct, source r{s}"); + assert_eq!(grouped(&g, r, s), want, "generated, source r{s}"); + assert_eq!(prefixed(total, r, s), want, "prefix, source r{s}"); + } + } + assert!(wrong_differs > 0, "the known-failed form must be refused"); + } +} diff --git a/igneum-pow/src/verify.rs b/igneum-pow/src/verify.rs index c0dc217b8..895a409ec 100644 --- a/igneum-pow/src/verify.rs +++ b/igneum-pow/src/verify.rs @@ -581,6 +581,10 @@ fn interpret_warp_core( // the iteration's statements: the drawn program, or its interleaved two-window form under reg64 let scheduled = program.scheduled(); let address_mix = program.address_mix(); + // X4: a byte-identical form of the address mix beside the definition (crate::reg64form), off by default + let cpu_form = crate::reg64form::cpu_form(); + let form_on = address_mix && cpu_form != crate::reg64form::Reg64Form::Fold; + let mut fs = crate::reg64form::FormState::new(cpu_form, if form_on { crate::reg64form::generated_plan(&scheduled, &program.shadow) } else { Vec::new() }); let mut items_derived = 0usize; let mut idx = [0u32; LANES]; let mut val = [0u32; LANES]; @@ -606,9 +610,15 @@ fn interpret_warp_core( } } } + if it == 0 && form_on { + // X4: the form's state from the registers as iteration 0 sees them (after the init and any probe flip) + fs.init(&r); + } let sel = r[0]; - for ins in &scheduled { - step(ins, &mut r, &sel, geom, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived, address_mix); + for (k, ins) in scheduled.iter().enumerate() { + let old = if form_on { r[ins.dst as usize] } else { [0u32; LANES] }; + let ovr = if form_on && ins.op == Op::Load { Some(fs.source(&r, k, ins.src as usize)) } else { None }; + step(ins, &mut r, &sel, geom, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived, address_mix, ovr.as_ref()); if it == 0 && ins.op == Op::Load { if let Some(pr) = probe.as_deref_mut() { if !pr.seen_first_load { @@ -625,12 +635,19 @@ fn interpret_warp_core( r[d][lane] = m.rmw(&program.seed, base_nonce, lane, slot, r[d][lane]); } } + if form_on { + fs.after_write(&r, ins.dst as usize, &old); + } } // Latency-shadow block (Counter ASIC 3.0 item 8): the block runs `reps` times after instruction 63 with the // iteration's `sel`; it is empty on every class without a shadow, so version 2 and class v3 run nothing here. for _ in 0..program.shadow_reps() { for ins in &program.shadow { - step(ins, &mut r, &sel, geom, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived, address_mix); + let old = if form_on { r[ins.dst as usize] } else { [0u32; LANES] }; + step(ins, &mut r, &sel, geom, era.as_ref(), layout, ds, &mut idx, &mut val, &mut items_derived, address_mix, None); + if form_on { + fs.after_write(&r, ins.dst as usize, &old); + } } } } @@ -668,6 +685,7 @@ fn step( val: &mut [u32; LANES], items_derived: &mut usize, address_mix: bool, + src_override: Option<&[u32; LANES]>, ) { let d = ins.dst as usize; let a = ins.src as usize; @@ -679,6 +697,11 @@ fn step( if !address_mix { return r[a][lane]; } + // X4 (1.5x programme): a byte-identical form computed by the caller; never set unless the differential's + // `--reg64-cpu-form` names a form other than the fold (crate::reg64form) + if let Some(o) = src_override { + return o[lane]; + } let mut m = 0u32; let mut started = false; for k in 0..r.len() { From 611910101657893adc554c470633e316940571ff Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:08:29 +0000 Subject: [PATCH 02/19] X4 (1.5x): the reg64c forms' equivalence verdicts, the 4090 pairs, the chip rows and the arithmetic; the differential, the pod script and the generators under tools/1p5x/x4; the registry batch NOT RUN Co-Authored-By: Claude Opus 5.5 --- docs/analysis/class-v6/1p5x/x4/README.md | 214 ++++++++++++++++++ .../1p5x/x4/pod-s1/bench-01-hl-v6-all.log | 4 + .../1p5x/x4/pod-s1/bench-02-x4-direct.log | 4 + .../1p5x/x4/pod-s1/bench-03-x4-generated.log | 4 + .../1p5x/x4/pod-s1/bench-04-x4-prefix.log | 4 + .../1p5x/x4/pod-s1/bench-05-x4-prefix.log | 4 + .../1p5x/x4/pod-s1/bench-06-x4-generated.log | 4 + .../1p5x/x4/pod-s1/bench-07-x4-direct.log | 4 + .../1p5x/x4/pod-s1/bench-08-hl-v6-all.log | 4 + .../class-v6/1p5x/x4/pod-s1/out-run.log | 35 +++ .../1p5x/x4/pod-s1/smi-01-hl-v6-all.csv | 118 ++++++++++ .../1p5x/x4/pod-s1/smi-02-x4-direct.csv | 117 ++++++++++ .../1p5x/x4/pod-s1/smi-03-x4-generated.csv | 117 ++++++++++ .../1p5x/x4/pod-s1/smi-04-x4-prefix.csv | 117 ++++++++++ .../1p5x/x4/pod-s1/smi-05-x4-prefix.csv | 118 ++++++++++ .../1p5x/x4/pod-s1/smi-06-x4-generated.csv | 116 ++++++++++ .../1p5x/x4/pod-s1/smi-07-x4-direct.csv | 118 ++++++++++ .../1p5x/x4/pod-s1/smi-08-hl-v6-all.csv | 118 ++++++++++ docs/analysis/class-v6/1p5x/x4/rows/VERDICT | 3 + docs/analysis/class-v6/1p5x/x4/rows/arith.txt | 12 + .../class-v6/1p5x/x4/rows/chip-rows.txt | 19 ++ .../class-v6/1p5x/x4/rows/gpu-rows.txt | 15 ++ .../class-v6/1p5x/x4/rows/suite-b51d8c04b.txt | 15 ++ .../class-v6/1p5x/x4/rows/verdicts.txt | 188 +++++++++++++++ tools/1p5x/x4/arith.py | 33 +++ tools/1p5x/x4/chip_rows.py | 102 +++++++++ tools/1p5x/x4/differential.sh | 84 +++++++ tools/1p5x/x4/gpu_rows.py | 43 ++++ tools/1p5x/x4/pod-x4.sh | 28 +++ tools/ci/batches/1p5x-x4-20261009.json | 24 ++ tools/ci/export-exclude.txt | 2 + 31 files changed, 1788 insertions(+) create mode 100644 docs/analysis/class-v6/1p5x/x4/README.md create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-01-hl-v6-all.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-02-x4-direct.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-03-x4-generated.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-04-x4-prefix.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-05-x4-prefix.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-06-x4-generated.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-07-x4-direct.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/bench-08-hl-v6-all.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/out-run.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-01-hl-v6-all.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-02-x4-direct.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-03-x4-generated.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-04-x4-prefix.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-05-x4-prefix.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-06-x4-generated.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-07-x4-direct.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s1/smi-08-hl-v6-all.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/VERDICT create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/arith.txt create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/chip-rows.txt create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/gpu-rows.txt create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/suite-b51d8c04b.txt create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/verdicts.txt create mode 100644 tools/1p5x/x4/arith.py create mode 100644 tools/1p5x/x4/chip_rows.py create mode 100755 tools/1p5x/x4/differential.sh create mode 100644 tools/1p5x/x4/gpu_rows.py create mode 100755 tools/1p5x/x4/pod-x4.sh create mode 100644 tools/ci/batches/1p5x-x4-20261009.json diff --git a/docs/analysis/class-v6/1p5x/x4/README.md b/docs/analysis/class-v6/1p5x/x4/README.md new file mode 100644 index 000000000..3399ccc07 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/README.md @@ -0,0 +1,214 @@ +# X4: byte-identical implementation forms of the reg64c layer (the 1.5x programme, 9 October 2026) + +Lane: the k lane (X4). Item in the founder's brief (sha256 74ee0732...): "Byte-identical reg64 implementation +alternatives: direct/generated/prefix alternative performance; state/storage/port update costs on both sides". +The frozen control: the class v6 generator tree 1a938abe4 (igneum-pow fingerprint 5f4d6dc6...), the class string +mx8-erad810f22d+sh256x27+state+reg64c+fold+rw. This document claims no pass. It changes nothing on the chain and +activates nothing. + +## 1. The layer and the four forms + +The reg64c layer is defined in `igneum-pow/src/verify.rs`, `step`'s `addr_src`. Every load's address source is +`r[s] ^ m`, where `m = r[k0]; m = rotl(m, 1) ^ r[k1]; ...` runs over the 63 registers other than the source `s`, in +index order. The fold stays the definition. Each form below computes the same 32-bit word on every register state and +every source. + +| Form | What it computes | State beyond the 64-register window | Source | +|---|---|---|---| +| fold (frozen) | the 63-term dependent chain per load | none | `emit.rs` `reg64_mix_line` (the frozen text) | +| direct | the closed sum `XOR_{ks} rotl(r[k], (63-k) mod 32)` as a balanced tree, depth 6 | none | `reg64form::direct`, `emit.rs` `reg64_direct_mix_line` | +| generated | 8 group sums `g_j = XOR_{k in 8j..8j+7} rotl(r[k], (63-k) mod 32)`. Before each load the generator recomputes only the groups the static schedule wrote since the last load (`reg64form::generated_plan`). Then `r[s] ^ ror(P,1) ^ S ^ P ^ a[s]`, with `S` the 8 groups and `P` the whole groups before `s`'s group plus the in-group partial | 8 x 32 bits per lane | `reg64form::grouped`, `emit.rs` `reg64_generated_mix_line` | +| prefix | review B's F05 text as landed: a running `S` updated after every write (main list and shadow), and `P_s` recomputed per load | 1 x 32 bits per lane | `verify::reg64_address_source`, `emit.rs` `reg64_prefix_mix_line` | +| grouped incremental (chip only) | the generated form's query, with groups 1..7 kept up to date on the base program's writes to r8..r63, and group 0 recomputed at each load | 8 x 32 bits per lane | modelled only; no GPU text | + +The fact that makes the generated and grouped forms cheap: the shadow block draws its destination as +`dst = rng.below(8)` (`generator.rs`, the shadow draw). So all 55,296 shadow writes per hash land in r0..r7 (group 0), +and the shadow moves no other group. `tools/1p5x/x4/chip_rows.py` asserts this on the exported text. + +Code, on branch 1p5x-x4: +- b51d8c04b: the crate's forms. + - `igneum-pow/src/reg64form.rs`: new. + - `verify.rs`: an override hook in `step`. It is off unless `--reg64-cpu-form` names a form other than the fold. + - `emit.rs`: `--reg64-form`. It changes only the CUDA text, and `--reg64-prefix` is the same as `prefix`. + - `main.rs`: the two switches. +- The tools: `tools/1p5x/x4/` (`differential.sh`, `pod-x4.sh`, `chip_rows.py`, `gpu_rows.py`, `arith.py`). + +The texts, exported on build-9 from the frozen object by the b51d8c04b binary (`igneum-pow` sha256 ccb1bf0e...): + +| Form | kernel.cu sha256 | kernel_bound.cu sha256 | kernel.cu blake2b-256 (identity.json) | bytes | +|---|---|---|---|---| +| fold | b73ed77eb55d1b49 | 77cabb0602ee7ad5 | 368068868cbff44f | 86,027 | +| direct | 1fdd27fb8eff2bf5 | 010ae3a6dea7d431 | 895f573979f37b51 | 77,035 | +| generated | c1935ca84e7626dd | c39ff235fdff09ad | 6994fbdafe8e4bd1 | 54,664 | +| prefix | 3fe78c3928ba9b77 | 23fb860b5a258b52 | a859b9d88dc4a731 | 84,948 | + +The four packs, as one tarball: x4-packs.tgz, sha256 6666d915.... It holds the frozen pack and the three alternatives. + +## 2. Equivalence verdicts + +| Test | Result | Evidence | +|---|---|---| +| Fold text check: `export` with no switch on b51d8c04b, compared with the frozen tarball hl-v6-all.tgz (91314310...) | kernel.cu, kernel_bound.cu, program.h and identity.json byte-identical | build-9 `/srv/builds/igneum-wt-1p5x-x4/ex/` | +| Prefix text check: `--reg64-form prefix`, compared with hl-v6-all-prefix.tgz (d4b07747...) | all 14 files byte-identical | as above | +| Unit test, known-failed first (`reg64form::tests::x4_forms_equal_the_fold_and_the_wrong_form_is_refused`): the wrong form (`r[s] ^ S ^ a[s]`) must disagree with the fold. Then direct, grouped and prefix must equal the fold on every source, over 4,096 random states, all zero, all ones, 2,048 single-bit states and the init rule's registers | PASS | `rows/suite-b51d8c04b.txt` | +| The crate suite on build-9 (rule 24) | green: 76 lib tests plus 12 test binaries, 0 failed | `rows/suite-b51d8c04b.txt` | +| CPU differential, whole hashes (`tools/1p5x/x4/differential.sh out 4096 32`): the CPU interpreter runs each form and keeps its state per form (the generated plan's stale groups, the prefix's running S) | **EQUIVALENT**. The known-failed form is refused on all 8 reg64c windows and all 32 fuzz seeds. Direct, generated and prefix agree on 44 of 44 checks each: 12 same-work windows, plus 32 fuzz seeds against the fold. Context 03 (class v5, no reg64) is the no-op control: every form agrees there, the wrong one too | `rows/VERDICT`, `rows/verdicts.txt` | +| GPU, the pack self-test and the 2^24 fingerprint at base nonce 0: the gen-6 worker 804a6f7f on an RTX 4090, eight runs | **EQUIVALENT**. check=PASS (96 of 96 vector lanes) and fingerprint e8f4f3289c6ee1fc on all four texts in both passes | `pod-s1/bench-*.log` | + +The same-work windows: contexts 01 and 02 (`docs/analysis/class-v6/same-work/same-work-20261008-0{1,2}`), days D and +D+1. Each window is 4,096 nonces: nonce 0, the last 4,096 before the boundary 1,572,864, the first 4,096 after it, and +the last 4,096 of D+1. Each window is checked against that context's own `references/ref-D*.txt` from build-1. Context +03 (`same-work-20261008-03`, class v5) uses the same four windows. + +The fuzz set: 32 seeds `i`. Each seed takes the epoch, era and prehash from `sha256("x4-fuzz-i")`, `"x4-era-i"` and +`"x4-pre-i"`, a nonce from `"x4-nonce-i"`, and runs 1,024 nonces on the class v6 string over the node1 state stream +(abb58003...). + +## 3. The GPU side (measured) + +The recipe is the hash lane's (build-1:/srv/artefacts/1p5x/gpu-row-recipe.md, sha256 cbab453c...): +- Run: worker `--bench`, 250 x 2^24, block-warps 1. +- Rate: the worker's own `mhs=`. +- Power: board power, `power.draw` mean from 8 s in to the end of the timed dispatches. No wall meter; idle is not + subtracted. +- The sampler read power.draw, clocks.sm, utilization.gpu and temperature.gpu at 1 Hz. The recipe's instant and average + fields were not read. + +Hardware: one rented RTX 4090 (fk-x4-4090: a RunPod container, driver 595.91.07, CUDA 12.8 image, 450 W limit), at +stock. Worker igneum-worker-cuda-gen6, sha256 804a6f7fea10a62e (the class v6 zip 3 worker). + +Session 1 ran 2026-10-09 08:45:43Z to 09:05Z in the order A B C D D C B A (`tools/1p5x/x4/pod-x4.sh`). On an island, +not a network. + +| Run | Pack | MH/s | W | nJ per hash | Registers | Blocks per SM | Fingerprint | +|---|---|---|---|---|---|---|---| +| 1 | hl-v6-all (frozen fold) | 35.080 | 285.4 | 8,134 | 93 | 20 | e8f4f3289c6ee1fc | +| 2 | direct | 35.021 | 274.5 | 7,839 | 182 | 8 | e8f4f3289c6ee1fc | +| 3 | generated | 35.053 | 274.2 | 7,824 | 142 | 12 | e8f4f3289c6ee1fc | +| 4 | prefix | 35.056 | 277.1 | 7,905 | 154 | 12 | e8f4f3289c6ee1fc | +| 5 | prefix | 35.053 | 277.8 | 7,926 | 154 | 12 | e8f4f3289c6ee1fc | +| 6 | generated | 35.056 | 274.8 | 7,840 | 142 | 12 | e8f4f3289c6ee1fc | +| 7 | direct | 35.020 | 274.9 | 7,851 | 182 | 8 | e8f4f3289c6ee1fc | +| 8 | hl-v6-all (frozen fold) | 35.054 | 287.4 | 8,199 | 93 | 20 | e8f4f3289c6ee1fc | + +Pass 1 compares runs 2 to 4 with run 1. Pass 2 compares runs 5 to 7 with run 8. g is the mean of the two joules-per-hash +ratios. + +| Pair | Pass 1 rate / J per hash | Pass 2 rate / J per hash | Mean rate / J per hash | g | +|---|---|---|---|---| +| A/A: frozen run 8 against run 1 | -0.07% / +0.80% | | | (noise floor) | +| direct | -0.17% / -3.63% | -0.10% / -4.25% | -0.13% / -3.94% | 0.961 | +| generated | -0.08% / -3.82% | +0.01% / -4.38% | -0.04% / -4.10% | 0.959 | +| prefix | -0.07% / -2.82% | -0.00% / -3.33% | -0.04% / -3.07% | 0.969 | + +What the rows say: on the 4090 at stock, every form keeps the rate within 0.13 percent. Every form cuts board joules per +hash by 3 to 4 percent, about four times the A/A spread, in both passes. + +The confound, open (BLOCKED row B2 below): nvcc gives the frozen fold 93 registers and 20 resident blocks per SM, and +the alternatives 142 to 182 registers and 8 to 12 blocks. The kernel is memory-bound: the rate is equal at every +occupancy. So the saving may come from fewer resident warps rather than from the form. Yesterday's F05 rows point the +other way on the other card (`docs/analysis/class-v6/rows/fleet-f05-20261008.md`): on the 5090 the prefix text halved +the blocks and cost 14 percent more joules per hash. + +What it means per tier: +- A 24 GB card (4090) with a generated or direct pack would mine at the same rate for about 4 percent less board power. + That is about 11 W of 285. +- 8, 12 and 16 GB cards, AMD (OpenCL) and Apple (Metal) are not measured. The OpenCL and Metal texts keep the fold. +- No pack ships from this. A form change is a text change to a fleet kit, and it would go through the hash lane and + the kit lane. + +## 4. The chip side (modelled) + +Every row is modelled; no chip was measured. The counts come from the exported texts +(`tools/1p5x/x4/chip_rows.py ex`, `rows/chip-rows.txt`). + +The constants are the adversary lane's calibrated row (its message of 09:4x UK; class-v6-adversary 43c9f7cd8 +`tools/chip-model/mf/`): +- e_op: 6.55 pJ per lane-op at N5 (band 6.01 to 7.77). An xor-rotate that does not pass the slot's macro read costs + about 1.0 pJ. +- e_rf: 3.5 pJ per 256-bit macro access shared by 8 lanes (band 2.0 to 7.0). +- Flop bits written: 0.03 pJ per bit. +- The slot already reads 3 and writes 1 window register per instruction. +- The machine: 1.528 microjoules per hash (N5, GDDR7 board), of which the shadow is 0.672. + +Counted from the texts: 256 executed loads per hash (32 per iteration x 8; the worker's RESULT line also says +loads=256). 128 base writes per iteration, 112 of them to r8..r63. 256 shadow writes per pass, all to r0..r7. + +Two pricings are given. "Slot" prices each mix op as a full lane-op at 6.55 pJ, the adversary's literal-fold row. +"Datapath" prices each mix op as an xor at 1.0 pJ, the adversary's running-total row. In both, every extra window read +costs e_rf / 8. + +| Form | Mix ops per hash | Extra window reads per hash | Flop bits written per hash | State per lane | Ports | nJ per hash, slot (lo / c / hi) | nJ per hash, datapath (lo / c / hi) | pJ per lane-op delta at N5 (slot / datapath) | +|---|---|---|---|---|---|---|---|---| +| fold (frozen) | 16,128 | 16,128 | 0 | 64 registers | 63 reads per load | 101.0 / 112.7 / 139.4 | 20.2 / 23.2 / 30.2 | +1.10 / +0.23 | +| direct | 15,872 | 16,128 | 0 | 64 registers | 63 reads per load (tree) | 99.4 / 111.0 / 137.4 | 19.9 / 22.9 / 30.0 | +1.08 / +0.22 | +| generated | 8,400 | 5,792 | 20,224 | +32 B (8 flop registers) | 8 reads per recomputed group | 52.5 / 58.2 / 70.9 | 10.5 / 11.5 / 14.1 | +0.57 / +0.11 | +| prefix (F05) | 121,320 | 8,160 | 1,802,240 | +4 B | a read-modify-write of S on every write, shadow included | 785.2 / 852.3 / 1003.9 | 177.4 / 179.0 / 182.5 | +8.31 / +1.74 | +| grouped incremental | 7,560 | 2,784 | 36,864 | +32 B | 1 group RMW per base write to r8..r63, 8 reads per load | 47.2 / 51.8 / 62.3 | 9.4 / 9.9 / 11.1 | +0.50 / +0.10 | + +The per-lane-op delta spreads the mix's energy over the 102,612 shadow and base lane-ops. + +Readings: +- The specialist's cheapest byte-identical form is the grouped incremental one: 10 to 52 nJ per hash, against 23 to + 113 nJ for the literal fold. +- The adversary lane's 7 nJ running-total figure (5 to 10) counts 128 loads, and it leaves out the prefix `P_s` that + every load needs. It is corrected here and sent back to that lane. +- The adversary's section 17 Fenwick tree costs more on every reading. Its seven read-modify-writes land on every + write, the shadow's included. + +## 5. The arithmetic (`tools/1p5x/x4/arith.py`, `rows/arith.txt`) + +`r_new = r0 * g / a`. g comes from section 3. a is the specialist's machine energy with a form, divided by its energy +on a reference, at 1.528 microjoules. Two references: +- fold: a specialist that implements the frozen literal fold. +- model: the served machine, which carries no address-mix term at all. Against it, any form raises the specialist's + energy; that is a model correction, not a design gain. + +Each side picks its cheapest form on its own. The card takes generated (g 0.959). The specialist takes grouped +incremental. + +| r0 | vs fold, slot | vs fold, datapath | vs model, slot | vs model, datapath | +|---|---|---|---|---| +| 2.0 | a 0.963, r_new 1.99 | a 0.991, r_new 1.94 | a 1.034, r_new 1.86 | a 1.007, r_new 1.91 | +| 1.9 | 1.89 | 1.84 | 1.76 | 1.81 | +| 2.1 | 2.09 | 2.03 | 1.95 | 2.00 | + +Per form, with both sides on the same form, from 2.0: + +| Form | g | r_new vs fold (slot / datapath) | r_new vs model (slot / datapath) | +|---|---|---|---| +| direct | 0.961 | 1.92 / 1.92 | 1.79 / 1.89 | +| generated | 0.959 | 1.98 / 1.93 | 1.85 / 1.90 | +| prefix | 0.969 | 1.34 / 1.76 | 1.24 / 1.74 | + +The prefix rows are not a credible opponent: no specialist would choose the costlier form. + +Reaching 1.5 from 2.0 needs g / a = 0.75. The best credible pair gives 0.93 to 1.00. **X4 does not reach 1.5x**, and +no pass is claimed. What X4 does move: +- The card side: a 3 to 4 percent cut in board joules per hash on the 4090, open on the occupancy confound. +- The model side: the served chip omits a 10 to 52 nJ per hash term, worth 0.7 to 3.4 percent of the machine. +- Together, about 0.05 to 0.15 off a 2.0x ratio. + +## 6. BLOCKED and NOT RUN rows + +| Row | Status | Reason | What it needs | +|---|---|---|---| +| B1: the knee (the 4090 locked), every form | NOT RUN | The rented container refuses `nvidia-smi -lgc` and `-pl`. The worker has no duty-cycle throttle. The house rigs are blocked for every lane (the brief's amendment 2) | a pod host that grants clock locks, or the rigs after the relay lane's "agent back" line | +| B2: the occupancy control (the frozen fold text at 12 and 8 blocks per SM) | BLOCKED | The worker sets no register or occupancy cap for a base-variant pack (`--warps` applies to variant 5 only) | a worker flag or a `__launch_bounds__` text variant from the hash lane. It decides whether g is the form or the occupancy | +| B3: the RTX 5090 pairs (and the 5080, the cohort cards) | NOT RUN | one pod in this item's clock | a 5090 pod from the fleet lane. The F05 row says the sign can flip there | +| B4: OpenCL and Metal texts of the alternatives | NOT RUN | the switch is CUDA-only by design | emitter work in the three dialects, if a form is adopted | +| B5: the grouped incremental form as an executable text | NOT RUN | a chip-side design. Its equivalence rests on the prefix form's tested update rule and the generated form's tested query, and was not emulated on its own | a FormState arm in `reg64form.rs` and the differential, if the adversary lane carries the row | +| B6: the chip rows on the adversary lane's placed core run | BLOCKED | the model has no input file for an address-form row (its own answer). The rows above are this script's arithmetic on its constants | the adversary lane taking `rows/chip-rows.txt` into its section 17 | + +## 7. Reproduce + +All on a build box, never the Mac: +1. Build: `cargo build --release` in `igneum-pow` at 1p5x-x4. +2. Fetch the inputs from build-1 (the paths are in `differential.sh`'s header). +3. Export: `igneum-pow export --epoch-hex edc4fa84... --day-hex 69676e65756d2d6461792ffa50000000000000 --class mx8+sh256x27+state+reg64c+fold+rw --era 0:edc4fa84... --era-widths 4 --state node1-state.igsd1 --reg64-form --out `. +4. Differential: `tools/1p5x/x4/differential.sh out 4096 32`. +5. Chip rows: `tools/1p5x/x4/chip_rows.py ex > chip-rows.txt`. +6. On the pod: `pod-x4.sh` with the worker and the packs, then `gpu_rows.py out out-run.log > gpu-rows.txt`. +7. Arithmetic: `arith.py gpu-rows.txt chip-rows.txt`. + +The registry batch is `tools/ci/batches/1p5x-x4-20261009.json`, every cell NOT RUN. diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-01-hl-v6-all.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-01-hl-v6-all.log new file mode 100644 index 000000000..f0b063f7a --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-01-hl-v6-all.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2644 cache 2 dataset 29 hot 0 check 1352 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.05 ms; 250 timed dispatches of 16777216 nonces: mean 478.25 ms +RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.080 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-02-x4-direct.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-02-x4-direct.log new file mode 100644 index 000000000..411a40fd9 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-02-x4-direct.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1486 cache 2 dataset 29 hot 0 check 1168 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.90 ms; 250 timed dispatches of 16777216 nonces: mean 479.07 ms +RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.021 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-03-x4-generated.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-03-x4-generated.log new file mode 100644 index 000000000..99a3a38a4 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-03-x4-generated.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1426 cache 3 dataset 29 hot 0 check 1119 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.37 ms; 250 timed dispatches of 16777216 nonces: mean 478.62 ms +RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-04-x4-prefix.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-04-x4-prefix.log new file mode 100644 index 000000000..16131a981 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-04-x4-prefix.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1745 cache 2 dataset 29 hot 0 check 1163 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.73 ms; 250 timed dispatches of 16777216 nonces: mean 478.58 ms +RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.056 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-05-x4-prefix.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-05-x4-prefix.log new file mode 100644 index 000000000..38e7b703e --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-05-x4-prefix.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1588 cache 2 dataset 29 hot 0 check 1183 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.50 ms; 250 timed dispatches of 16777216 nonces: mean 478.62 ms +RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-06-x4-generated.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-06-x4-generated.log new file mode 100644 index 000000000..2bd9806bb --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-06-x4-generated.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1588 cache 2 dataset 28 hot 0 check 1170 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.37 ms; 250 timed dispatches of 16777216 nonces: mean 478.58 ms +RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.056 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-07-x4-direct.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-07-x4-direct.log new file mode 100644 index 000000000..61b9bef69 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-07-x4-direct.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1646 cache 8 dataset 47 hot 0 check 1147 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 479.00 ms; 250 timed dispatches of 16777216 nonces: mean 479.07 ms +RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.020 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-08-hl-v6-all.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-08-hl-v6-all.log new file mode 100644 index 000000000..e3b95da58 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/bench-08-hl-v6-all.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2367 cache 3 dataset 29 hot 0 check 1105 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.05 ms; 250 timed dispatches of 16777216 nonces: mean 478.61 ms +RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.054 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/out-run.log b/docs/analysis/class-v6/1p5x/x4/pod-s1/out-run.log new file mode 100644 index 000000000..13be71f03 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/out-run.log @@ -0,0 +1,35 @@ +RESULT start 2026-10-09T08:45:43Z NVIDIA GeForce RTX 4090, 595.91.07, 450.00 W, 3105 MHz +RESULT worker sha256 804a6f7fea10a62e +RESULT run 01-hl-v6-all rc=0 secs=125 t0=1791535543 t1=1791535668 +BENCH 01-hl-v6-all | pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2644 cache 2 dataset 29 hot 0 check 1352 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 01-hl-v6-all | warm-up dispatch (base 0): 478.05 ms; 250 timed dispatches of 16777216 nonces: mean 478.25 ms +BENCH 01-hl-v6-all | RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.080 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 02-x4-direct rc=0 secs=123 t0=1791535688 t1=1791535811 +BENCH 02-x4-direct | pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1486 cache 2 dataset 29 hot 0 check 1168 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 02-x4-direct | warm-up dispatch (base 0): 478.90 ms; 250 timed dispatches of 16777216 nonces: mean 479.07 ms +BENCH 02-x4-direct | RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.021 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 03-x4-generated rc=0 secs=124 t0=1791535831 t1=1791535955 +BENCH 03-x4-generated | pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1426 cache 3 dataset 29 hot 0 check 1119 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 03-x4-generated | warm-up dispatch (base 0): 478.37 ms; 250 timed dispatches of 16777216 nonces: mean 478.62 ms +BENCH 03-x4-generated | RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 04-x4-prefix rc=0 secs=124 t0=1791535975 t1=1791536099 +BENCH 04-x4-prefix | pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1745 cache 2 dataset 29 hot 0 check 1163 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 04-x4-prefix | warm-up dispatch (base 0): 478.73 ms; 250 timed dispatches of 16777216 nonces: mean 478.58 ms +BENCH 04-x4-prefix | RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.056 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 05-x4-prefix rc=0 secs=123 t0=1791536119 t1=1791536242 +BENCH 05-x4-prefix | pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1588 cache 2 dataset 29 hot 0 check 1183 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 05-x4-prefix | warm-up dispatch (base 0): 478.50 ms; 250 timed dispatches of 16777216 nonces: mean 478.62 ms +BENCH 05-x4-prefix | RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 06-x4-generated rc=0 secs=124 t0=1791536262 t1=1791536386 +BENCH 06-x4-generated | pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1588 cache 2 dataset 28 hot 0 check 1170 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 06-x4-generated | warm-up dispatch (base 0): 478.37 ms; 250 timed dispatches of 16777216 nonces: mean 478.58 ms +BENCH 06-x4-generated | RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.056 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 07-x4-direct rc=0 secs=124 t0=1791536406 t1=1791536530 +BENCH 07-x4-direct | pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1646 cache 8 dataset 47 hot 0 check 1147 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 07-x4-direct | warm-up dispatch (base 0): 479.00 ms; 250 timed dispatches of 16777216 nonces: mean 479.07 ms +BENCH 07-x4-direct | RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.020 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 08-hl-v6-all rc=0 secs=124 t0=1791536550 t1=1791536674 +BENCH 08-hl-v6-all | pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2367 cache 3 dataset 29 hot 0 check 1105 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 08-hl-v6-all | warm-up dispatch (base 0): 478.05 ms; 250 timed dispatches of 16777216 nonces: mean 478.61 ms +BENCH 08-hl-v6-all | RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.054 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT end 2026-10-09T09:04:54Z diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-01-hl-v6-all.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-01-hl-v6-all.csv new file mode 100644 index 000000000..75dd3ec54 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-01-hl-v6-all.csv @@ -0,0 +1,118 @@ +1791535543,25.73,210,0,23 +1791535544,41.92,2520,0,24 +1791535545,80.03,2520,0,24 +1791535546,79.72,2520,0,24 +1791535547,83.98,2520,0,25 +1791535548,214.87,2655,100,30 +1791535549,280.28,2655,100,31 +1791535551,280.39,2655,100,32 +1791535552,280.38,2655,100,32 +1791535553,280.40,2655,100,33 +1791535554,280.54,2655,100,33 +1791535555,280.64,2655,100,34 +1791535556,280.79,2655,100,34 +1791535557,280.88,2655,100,34 +1791535558,280.84,2655,100,35 +1791535559,281.21,2685,100,35 +1791535560,281.50,2685,100,35 +1791535561,281.46,2685,100,36 +1791535562,281.81,2685,100,36 +1791535563,282.10,2685,100,36 +1791535564,282.20,2685,100,37 +1791535565,282.20,2685,100,37 +1791535566,282.62,2685,100,37 +1791535567,282.67,2685,100,37 +1791535568,282.63,2685,100,38 +1791535570,282.77,2685,100,38 +1791535571,282.88,2685,100,38 +1791535572,282.96,2685,100,38 +1791535573,282.77,2685,100,38 +1791535574,283.22,2685,100,39 +1791535575,283.19,2685,100,39 +1791535576,283.71,2685,100,39 +1791535577,283.31,2685,99,39 +1791535578,283.61,2685,100,39 +1791535579,283.69,2685,100,40 +1791535580,283.76,2685,100,40 +1791535581,284.29,2685,100,40 +1791535582,284.29,2685,100,40 +1791535583,284.29,2685,100,40 +1791535584,284.29,2685,100,40 +1791535585,284.08,2685,100,41 +1791535586,284.09,2685,100,41 +1791535587,284.27,2685,100,41 +1791535589,284.52,2685,100,41 +1791535590,284.69,2685,100,41 +1791535591,285.17,2685,100,41 +1791535592,284.58,2685,100,41 +1791535593,284.85,2685,100,42 +1791535594,285.05,2685,100,42 +1791535595,285.57,2685,100,42 +1791535596,285.45,2685,100,42 +1791535597,285.14,2685,100,42 +1791535598,285.25,2685,100,42 +1791535599,285.37,2685,100,42 +1791535600,285.58,2685,100,42 +1791535601,285.74,2685,100,43 +1791535602,285.55,2685,100,43 +1791535603,285.70,2685,100,43 +1791535605,285.65,2685,100,43 +1791535606,285.56,2685,100,43 +1791535607,285.64,2685,100,43 +1791535608,286.10,2685,100,43 +1791535609,285.48,2685,100,43 +1791535610,285.57,2685,100,43 +1791535611,285.86,2685,100,43 +1791535612,285.49,2685,100,43 +1791535613,285.84,2685,100,44 +1791535614,286.10,2685,100,44 +1791535615,286.06,2685,100,44 +1791535616,285.77,2685,100,44 +1791535617,285.92,2685,100,44 +1791535618,286.16,2685,100,44 +1791535619,286.63,2685,100,44 +1791535620,286.40,2685,100,44 +1791535621,286.33,2685,100,44 +1791535623,286.91,2685,100,44 +1791535624,286.25,2685,100,44 +1791535625,286.94,2685,100,44 +1791535626,287.21,2685,100,44 +1791535627,287.43,2685,100,44 +1791535628,287.06,2685,100,45 +1791535629,287.04,2685,100,45 +1791535630,287.20,2685,100,45 +1791535631,287.46,2685,100,45 +1791535632,287.78,2685,100,45 +1791535633,288.03,2685,100,45 +1791535634,287.81,2685,100,45 +1791535635,287.69,2685,100,45 +1791535636,288.01,2685,100,45 +1791535637,287.39,2685,100,45 +1791535638,287.20,2670,100,45 +1791535639,287.27,2670,100,45 +1791535640,287.52,2670,100,45 +1791535641,287.89,2670,100,45 +1791535643,287.58,2670,100,45 +1791535644,287.44,2670,100,45 +1791535645,287.64,2670,100,45 +1791535646,287.27,2670,100,45 +1791535647,287.41,2670,100,45 +1791535648,287.34,2670,100,45 +1791535649,287.58,2670,100,45 +1791535650,287.78,2670,100,46 +1791535651,287.32,2670,100,46 +1791535652,287.36,2670,100,46 +1791535653,287.67,2670,100,46 +1791535654,287.97,2670,100,46 +1791535655,287.86,2670,100,46 +1791535656,287.72,2670,100,46 +1791535658,288.10,2670,100,46 +1791535659,287.65,2670,100,46 +1791535660,288.01,2670,100,46 +1791535661,287.50,2670,100,46 +1791535662,287.42,2670,100,46 +1791535663,288.01,2670,100,46 +1791535664,287.81,2670,100,46 +1791535665,287.93,2670,100,46 +1791535666,287.92,2670,100,46 +1791535667,287.99,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-02-x4-direct.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-02-x4-direct.csv new file mode 100644 index 000000000..1e574854e --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-02-x4-direct.csv @@ -0,0 +1,117 @@ +1791535688,27.52,210,0,33 +1791535689,69.40,2520,0,33 +1791535690,85.81,2520,11,33 +1791535691,80.89,2520,1,35 +1791535692,217.63,2685,100,38 +1791535693,271.20,2685,100,39 +1791535694,272.12,2685,100,39 +1791535695,272.26,2685,100,39 +1791535696,272.58,2685,100,40 +1791535697,273.06,2685,100,40 +1791535698,272.48,2685,100,40 +1791535700,272.13,2685,100,40 +1791535701,272.77,2685,100,40 +1791535702,273.29,2685,100,41 +1791535703,273.24,2685,100,41 +1791535704,273.06,2685,100,41 +1791535705,273.71,2685,100,41 +1791535706,273.73,2685,100,41 +1791535707,273.53,2685,100,41 +1791535708,273.34,2685,100,41 +1791535709,273.05,2685,100,42 +1791535710,273.11,2685,100,42 +1791535711,273.22,2685,100,42 +1791535712,273.33,2685,100,42 +1791535713,273.39,2685,100,42 +1791535714,273.43,2685,100,42 +1791535715,273.09,2685,100,42 +1791535716,273.15,2685,100,42 +1791535718,273.32,2685,100,42 +1791535719,273.34,2685,100,42 +1791535720,273.08,2685,100,42 +1791535721,273.26,2685,100,43 +1791535722,273.36,2685,100,43 +1791535723,273.81,2685,100,43 +1791535724,273.88,2685,100,43 +1791535725,274.15,2685,100,43 +1791535726,274.29,2685,100,43 +1791535727,274.35,2685,100,43 +1791535728,274.49,2685,100,43 +1791535729,274.58,2685,100,43 +1791535730,274.31,2685,100,43 +1791535731,273.94,2685,100,43 +1791535732,274.05,2685,100,43 +1791535734,274.08,2685,100,43 +1791535735,274.50,2685,100,43 +1791535736,274.56,2685,100,43 +1791535737,274.41,2685,100,43 +1791535738,274.16,2685,100,44 +1791535739,274.39,2685,100,44 +1791535740,274.76,2685,100,44 +1791535741,274.97,2685,100,44 +1791535742,274.87,2685,100,44 +1791535743,274.46,2685,100,44 +1791535744,274.72,2685,100,44 +1791535745,274.83,2685,100,44 +1791535746,275.01,2685,100,44 +1791535747,274.87,2685,100,44 +1791535748,274.77,2685,100,44 +1791535749,274.91,2685,100,44 +1791535751,274.91,2685,100,44 +1791535752,275.30,2685,100,44 +1791535753,275.23,2685,100,44 +1791535754,275.14,2685,100,44 +1791535755,275.17,2685,100,44 +1791535756,275.04,2685,100,44 +1791535757,274.95,2685,100,44 +1791535758,274.85,2685,100,44 +1791535759,274.61,2685,100,44 +1791535760,274.70,2685,100,44 +1791535761,274.73,2685,100,44 +1791535762,274.67,2685,100,45 +1791535763,274.85,2685,100,45 +1791535764,274.88,2685,100,45 +1791535765,275.33,2685,100,45 +1791535766,275.20,2685,100,45 +1791535768,275.22,2685,100,45 +1791535769,274.88,2685,100,45 +1791535770,275.15,2685,100,45 +1791535771,275.35,2685,100,45 +1791535772,275.56,2685,100,45 +1791535773,275.42,2685,100,45 +1791535774,275.36,2685,100,45 +1791535775,275.31,2685,100,45 +1791535776,275.20,2685,100,45 +1791535777,274.76,2685,100,45 +1791535778,275.26,2685,100,45 +1791535779,275.42,2685,100,45 +1791535780,275.17,2685,100,45 +1791535781,275.35,2685,100,45 +1791535782,275.11,2670,100,45 +1791535783,275.03,2670,100,45 +1791535784,275.04,2670,100,45 +1791535786,275.02,2670,100,45 +1791535787,275.10,2670,100,45 +1791535788,275.11,2670,100,45 +1791535789,275.12,2670,100,45 +1791535790,275.40,2670,100,45 +1791535791,275.03,2670,100,45 +1791535792,275.15,2670,100,45 +1791535793,275.04,2670,100,45 +1791535794,275.05,2670,100,45 +1791535795,275.22,2670,100,45 +1791535796,274.60,2670,100,45 +1791535797,275.23,2670,100,45 +1791535798,275.25,2670,100,45 +1791535799,275.49,2670,100,45 +1791535800,275.52,2670,100,45 +1791535801,275.48,2670,100,45 +1791535802,275.28,2670,100,45 +1791535803,275.30,2670,100,45 +1791535805,275.35,2670,100,45 +1791535806,275.39,2670,100,45 +1791535807,275.68,2670,100,45 +1791535808,275.70,2670,100,45 +1791535809,275.25,2670,100,45 +1791535810,274.96,2670,100,45 +1791535811,275.22,2670,100,45 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-03-x4-generated.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-03-x4-generated.csv new file mode 100644 index 000000000..58db81ec9 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-03-x4-generated.csv @@ -0,0 +1,117 @@ +1791535831,27.25,210,0,32 +1791535833,49.74,2520,0,33 +1791535834,85.31,2520,22,33 +1791535835,88.45,2520,64,33 +1791535836,224.31,2685,100,38 +1791535837,271.14,2685,100,39 +1791535838,271.38,2685,100,39 +1791535839,271.62,2685,100,40 +1791535840,272.30,2685,100,40 +1791535841,272.25,2685,100,40 +1791535842,272.54,2685,100,40 +1791535843,272.06,2685,100,40 +1791535844,272.07,2685,100,41 +1791535845,272.16,2685,100,41 +1791535846,272.17,2685,100,41 +1791535847,272.37,2685,100,41 +1791535848,272.78,2685,100,41 +1791535849,272.36,2685,100,41 +1791535851,272.49,2685,100,41 +1791535852,272.80,2685,100,42 +1791535853,272.65,2685,100,42 +1791535854,273.15,2685,100,42 +1791535855,272.84,2685,100,42 +1791535856,272.83,2685,100,42 +1791535857,272.61,2685,100,42 +1791535858,272.90,2685,100,42 +1791535859,272.84,2685,100,42 +1791535860,272.77,2685,100,42 +1791535861,273.01,2685,100,42 +1791535862,273.06,2685,100,42 +1791535863,273.05,2685,100,43 +1791535864,273.18,2685,100,43 +1791535865,273.01,2685,100,43 +1791535866,273.25,2685,100,43 +1791535867,273.29,2685,100,43 +1791535869,273.23,2685,100,43 +1791535870,273.46,2685,100,43 +1791535871,273.69,2685,100,43 +1791535872,273.69,2685,100,43 +1791535873,273.89,2685,100,43 +1791535874,274.04,2685,100,43 +1791535875,273.84,2685,100,43 +1791535876,273.99,2685,100,43 +1791535877,273.86,2685,100,43 +1791535878,273.83,2685,100,44 +1791535879,273.71,2685,100,44 +1791535880,273.68,2685,100,44 +1791535881,273.66,2685,100,44 +1791535882,274.34,2685,100,44 +1791535883,274.34,2685,100,44 +1791535885,274.30,2685,100,44 +1791535886,274.42,2685,100,44 +1791535887,274.77,2685,100,44 +1791535888,273.87,2685,100,44 +1791535889,274.47,2685,100,44 +1791535890,274.31,2685,100,44 +1791535891,274.41,2685,100,44 +1791535892,274.47,2685,100,44 +1791535893,274.72,2685,100,44 +1791535894,274.63,2685,100,44 +1791535895,274.57,2685,100,44 +1791535896,274.82,2685,100,44 +1791535897,274.97,2685,100,44 +1791535898,275.07,2685,100,44 +1791535899,274.86,2685,100,44 +1791535900,275.02,2685,100,44 +1791535901,275.05,2685,100,44 +1791535903,274.89,2685,100,44 +1791535904,274.55,2685,100,44 +1791535905,274.19,2685,100,45 +1791535906,274.60,2685,100,45 +1791535907,274.92,2685,100,45 +1791535908,274.77,2685,100,45 +1791535909,274.70,2685,100,45 +1791535910,274.42,2685,100,45 +1791535911,274.79,2685,100,45 +1791535912,274.67,2685,100,45 +1791535913,274.90,2685,100,45 +1791535914,274.70,2685,100,45 +1791535915,274.62,2685,100,45 +1791535916,275.07,2685,100,45 +1791535917,275.22,2685,100,45 +1791535918,274.96,2670,100,45 +1791535919,274.87,2670,100,45 +1791535921,275.05,2670,100,45 +1791535922,275.33,2670,100,45 +1791535923,275.34,2670,100,45 +1791535924,275.29,2670,100,45 +1791535925,275.45,2670,100,45 +1791535926,275.76,2670,100,45 +1791535927,275.78,2670,100,45 +1791535928,275.33,2670,100,45 +1791535929,275.23,2670,100,45 +1791535930,275.19,2670,100,45 +1791535931,275.16,2670,100,45 +1791535932,275.17,2670,100,45 +1791535933,275.62,2670,100,45 +1791535934,275.60,2670,100,45 +1791535935,275.57,2670,100,45 +1791535936,275.15,2670,100,45 +1791535937,275.25,2670,100,45 +1791535939,275.21,2670,100,45 +1791535940,275.23,2670,100,45 +1791535941,275.19,2670,100,45 +1791535942,275.31,2670,100,45 +1791535943,275.45,2670,100,45 +1791535944,275.72,2670,100,45 +1791535945,275.94,2670,100,45 +1791535946,275.33,2670,100,45 +1791535947,275.23,2670,100,45 +1791535948,274.83,2670,100,45 +1791535949,274.60,2670,100,45 +1791535950,274.83,2670,100,45 +1791535951,275.42,2670,100,45 +1791535952,275.43,2670,100,45 +1791535953,275.14,2670,100,45 +1791535954,275.43,2670,100,45 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-04-x4-prefix.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-04-x4-prefix.csv new file mode 100644 index 000000000..3990d977c --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-04-x4-prefix.csv @@ -0,0 +1,117 @@ +1791535975,27.63,210,0,33 +1791535976,70.46,2520,0,33 +1791535977,84.48,2520,0,35 +1791535978,84.79,2520,0,33 +1791535979,184.00,2685,38,37 +1791535980,274.23,2685,100,39 +1791535981,274.58,2685,100,39 +1791535982,274.89,2685,100,40 +1791535983,274.91,2685,100,40 +1791535984,274.85,2685,100,40 +1791535985,274.90,2685,100,40 +1791535987,275.24,2685,100,41 +1791535988,275.67,2685,100,41 +1791535989,275.32,2685,100,41 +1791535990,275.45,2685,100,41 +1791535991,275.68,2685,100,41 +1791535992,275.32,2685,100,41 +1791535993,275.49,2685,100,41 +1791535994,275.38,2685,100,42 +1791535995,275.61,2685,100,42 +1791535996,275.51,2685,100,42 +1791535997,275.56,2685,100,42 +1791535998,275.83,2685,100,42 +1791535999,276.10,2685,100,42 +1791536000,276.18,2685,100,42 +1791536001,276.22,2685,100,42 +1791536002,275.97,2685,100,42 +1791536003,275.76,2685,100,42 +1791536005,275.83,2685,100,43 +1791536006,276.27,2685,100,43 +1791536007,276.33,2685,100,43 +1791536008,276.27,2685,100,43 +1791536009,276.44,2685,100,43 +1791536010,276.55,2685,100,43 +1791536011,276.41,2685,100,43 +1791536012,276.32,2685,100,43 +1791536013,276.25,2685,100,43 +1791536014,276.77,2685,100,43 +1791536015,276.57,2685,100,43 +1791536016,276.93,2685,100,43 +1791536017,276.51,2685,100,43 +1791536018,276.32,2685,100,43 +1791536019,276.52,2685,100,43 +1791536020,276.63,2685,100,44 +1791536022,276.20,2685,100,44 +1791536023,276.42,2685,100,44 +1791536024,276.52,2685,100,44 +1791536025,276.70,2685,100,44 +1791536026,276.72,2685,100,44 +1791536027,277.21,2685,100,44 +1791536028,277.27,2685,100,44 +1791536029,277.52,2685,100,44 +1791536030,277.48,2685,100,44 +1791536031,277.17,2685,100,44 +1791536032,277.19,2685,100,44 +1791536033,277.62,2685,100,44 +1791536034,277.53,2685,100,44 +1791536035,277.41,2685,100,44 +1791536036,277.33,2685,100,44 +1791536037,277.19,2685,100,44 +1791536038,277.43,2685,100,44 +1791536040,277.14,2685,100,44 +1791536041,276.92,2685,100,44 +1791536042,277.00,2685,100,44 +1791536043,277.45,2685,100,44 +1791536044,277.70,2685,100,44 +1791536045,277.84,2685,100,44 +1791536046,277.77,2685,100,44 +1791536047,277.65,2685,100,45 +1791536048,277.70,2685,100,45 +1791536049,277.43,2685,100,45 +1791536050,277.80,2685,100,45 +1791536051,277.65,2685,100,45 +1791536052,277.70,2685,100,45 +1791536053,277.70,2685,100,45 +1791536054,277.76,2685,100,45 +1791536055,277.66,2685,100,45 +1791536057,277.46,2685,100,45 +1791536058,277.61,2685,100,45 +1791536059,277.44,2685,100,45 +1791536060,277.64,2685,100,45 +1791536061,277.70,2685,100,45 +1791536062,277.62,2685,100,45 +1791536063,277.50,2685,100,45 +1791536064,277.41,2670,100,45 +1791536065,277.47,2670,100,45 +1791536066,277.35,2670,100,45 +1791536067,277.39,2670,100,45 +1791536068,277.63,2670,100,45 +1791536069,277.67,2670,100,45 +1791536070,277.78,2670,100,45 +1791536071,277.88,2670,100,45 +1791536072,277.93,2670,100,45 +1791536073,278.37,2670,100,45 +1791536075,278.32,2670,100,45 +1791536076,278.23,2670,100,45 +1791536077,278.16,2670,100,45 +1791536078,277.95,2670,100,45 +1791536079,277.93,2670,100,45 +1791536080,278.41,2670,100,45 +1791536081,278.61,2670,100,45 +1791536082,278.41,2670,100,45 +1791536083,278.26,2670,100,45 +1791536084,278.21,2670,100,45 +1791536085,278.17,2670,100,45 +1791536086,278.15,2670,100,45 +1791536087,278.33,2670,100,45 +1791536088,278.08,2670,100,45 +1791536089,278.18,2670,100,45 +1791536090,278.43,2670,100,45 +1791536091,278.36,2670,100,45 +1791536093,278.36,2670,100,45 +1791536094,278.60,2670,100,45 +1791536095,278.60,2670,100,45 +1791536096,278.50,2670,100,45 +1791536097,278.64,2670,100,45 +1791536098,278.22,2670,100,45 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-05-x4-prefix.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-05-x4-prefix.csv new file mode 100644 index 000000000..48f94816c --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-05-x4-prefix.csv @@ -0,0 +1,118 @@ +1791536119,27.42,210,0,32 +1791536120,46.44,2520,0,33 +1791536121,80.51,2520,0,33 +1791536122,84.09,2520,0,33 +1791536123,162.79,2685,0,35 +1791536124,252.19,2685,100,39 +1791536125,274.83,2685,100,39 +1791536126,275.12,2685,100,40 +1791536127,275.51,2685,100,40 +1791536128,275.73,2685,100,40 +1791536129,275.47,2685,100,40 +1791536130,275.54,2685,100,40 +1791536131,275.97,2685,100,41 +1791536132,276.06,2685,100,41 +1791536133,275.98,2685,100,41 +1791536134,276.30,2685,100,41 +1791536136,276.28,2685,100,41 +1791536137,276.26,2685,100,41 +1791536138,276.54,2685,100,41 +1791536139,276.40,2685,100,42 +1791536140,276.72,2685,100,42 +1791536141,276.51,2685,100,42 +1791536142,276.54,2685,100,42 +1791536143,276.39,2685,100,42 +1791536144,276.48,2685,100,42 +1791536145,276.59,2685,100,42 +1791536146,277.00,2685,100,42 +1791536147,276.94,2685,100,42 +1791536148,276.95,2685,100,42 +1791536149,276.96,2685,100,43 +1791536150,277.07,2685,100,43 +1791536151,277.21,2685,100,43 +1791536152,277.40,2685,100,43 +1791536154,277.45,2685,100,43 +1791536155,277.56,2685,100,43 +1791536156,277.65,2685,100,43 +1791536157,277.60,2685,100,43 +1791536158,277.47,2685,100,43 +1791536159,277.64,2685,100,43 +1791536160,277.66,2685,100,43 +1791536161,278.01,2685,100,43 +1791536162,278.20,2685,100,43 +1791536163,278.12,2685,100,43 +1791536164,278.05,2685,100,44 +1791536165,277.90,2685,100,44 +1791536166,278.01,2685,100,44 +1791536167,278.00,2685,100,44 +1791536168,278.24,2685,100,44 +1791536169,278.14,2685,100,44 +1791536170,278.00,2685,100,44 +1791536171,277.94,2685,100,44 +1791536173,277.95,2685,100,44 +1791536174,278.15,2685,100,44 +1791536175,278.29,2685,100,44 +1791536176,278.26,2685,100,44 +1791536177,278.58,2685,100,44 +1791536178,278.41,2685,100,44 +1791536179,278.51,2685,100,44 +1791536180,278.36,2685,100,44 +1791536181,277.93,2685,100,44 +1791536182,278.20,2685,100,44 +1791536183,278.05,2685,100,44 +1791536184,277.98,2685,100,44 +1791536185,277.91,2685,100,44 +1791536186,278.07,2685,100,45 +1791536187,278.10,2685,100,45 +1791536188,278.10,2685,100,45 +1791536189,278.35,2685,100,45 +1791536190,278.29,2685,100,45 +1791536191,278.22,2685,100,45 +1791536192,278.36,2685,100,45 +1791536194,278.56,2685,100,45 +1791536195,278.19,2685,100,45 +1791536196,278.21,2685,100,45 +1791536197,278.46,2685,100,45 +1791536198,278.67,2670,100,45 +1791536199,278.57,2670,100,45 +1791536200,278.30,2670,100,45 +1791536201,278.27,2670,100,45 +1791536202,278.49,2670,100,45 +1791536203,278.13,2670,100,45 +1791536204,278.25,2670,100,45 +1791536205,278.53,2670,100,45 +1791536206,278.37,2670,100,45 +1791536207,278.25,2670,100,45 +1791536208,278.35,2670,100,45 +1791536209,278.34,2670,100,45 +1791536210,278.46,2670,100,45 +1791536211,278.27,2670,100,45 +1791536213,278.51,2670,100,45 +1791536214,278.33,2670,100,45 +1791536215,278.56,2670,100,45 +1791536216,278.57,2670,100,45 +1791536217,278.54,2670,100,45 +1791536218,278.68,2670,100,45 +1791536219,278.48,2670,100,45 +1791536220,278.57,2670,100,45 +1791536221,278.55,2670,100,45 +1791536222,278.15,2670,100,45 +1791536223,278.38,2670,100,45 +1791536224,278.28,2670,100,45 +1791536225,277.98,2670,100,45 +1791536226,278.02,2670,100,45 +1791536227,278.02,2670,100,45 +1791536228,278.19,2670,100,46 +1791536229,278.29,2670,100,46 +1791536231,278.26,2670,100,46 +1791536232,278.38,2670,100,46 +1791536233,278.38,2670,100,46 +1791536234,278.29,2670,100,46 +1791536235,278.22,2670,100,46 +1791536236,278.52,2670,100,46 +1791536237,278.37,2670,100,46 +1791536238,278.84,2670,100,46 +1791536239,278.82,2670,100,46 +1791536240,278.72,2670,100,46 +1791536241,278.38,2670,100,46 +1791536242,278.26,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-06-x4-generated.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-06-x4-generated.csv new file mode 100644 index 000000000..a435f0650 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-06-x4-generated.csv @@ -0,0 +1,116 @@ +1791536262,28.12,210,0,33 +1791536263,45.22,2520,0,33 +1791536264,86.39,2520,13,33 +1791536266,83.65,2520,27,33 +1791536267,221.16,2685,100,38 +1791536268,271.83,2685,100,39 +1791536269,271.62,2685,100,40 +1791536270,271.83,2685,100,40 +1791536271,271.95,2685,100,40 +1791536272,272.41,2685,100,40 +1791536274,272.62,2685,100,41 +1791536275,273.05,2685,100,41 +1791536276,272.71,2685,100,41 +1791536277,272.42,2685,100,41 +1791536278,273.08,2685,100,41 +1791536279,273.56,2685,100,41 +1791536280,273.76,2685,100,41 +1791536281,273.98,2685,100,42 +1791536282,273.49,2685,100,42 +1791536283,273.72,2685,100,42 +1791536284,273.59,2685,100,42 +1791536285,274.44,2685,100,42 +1791536286,274.20,2685,100,42 +1791536288,274.36,2685,100,42 +1791536289,274.20,2685,100,42 +1791536290,274.58,2685,100,42 +1791536291,274.60,2685,100,43 +1791536292,274.28,2685,100,43 +1791536293,274.16,2685,100,43 +1791536294,274.61,2685,100,43 +1791536295,274.58,2685,100,43 +1791536296,274.69,2685,100,43 +1791536297,274.48,2685,100,43 +1791536298,274.05,2685,100,43 +1791536299,274.47,2685,100,43 +1791536300,274.74,2685,100,43 +1791536301,274.72,2685,100,43 +1791536302,274.21,2685,100,43 +1791536303,274.35,2685,100,43 +1791536305,274.51,2685,100,43 +1791536306,274.27,2685,100,44 +1791536307,274.30,2685,100,44 +1791536308,274.39,2685,100,44 +1791536309,274.46,2685,100,44 +1791536310,274.56,2685,100,44 +1791536311,274.28,2685,100,44 +1791536312,274.35,2685,100,44 +1791536313,274.34,2685,100,44 +1791536314,274.94,2685,100,44 +1791536315,274.96,2685,100,44 +1791536316,275.16,2685,100,44 +1791536317,274.94,2685,100,44 +1791536318,275.14,2685,100,44 +1791536319,275.30,2685,100,44 +1791536320,275.43,2685,100,44 +1791536321,275.68,2685,100,44 +1791536323,275.28,2685,100,44 +1791536324,275.09,2685,100,44 +1791536325,275.04,2685,100,44 +1791536326,275.32,2685,100,44 +1791536327,275.37,2685,100,45 +1791536328,275.01,2685,100,45 +1791536329,275.25,2685,100,45 +1791536330,275.58,2685,100,45 +1791536331,275.47,2685,100,45 +1791536332,275.31,2670,100,45 +1791536333,274.92,2670,100,45 +1791536334,275.14,2670,100,45 +1791536335,275.06,2670,100,45 +1791536336,274.90,2670,100,45 +1791536337,274.87,2670,100,45 +1791536338,274.95,2670,100,45 +1791536339,275.16,2670,100,45 +1791536341,275.11,2670,100,45 +1791536342,275.24,2670,100,45 +1791536343,275.62,2670,100,45 +1791536344,275.53,2670,100,45 +1791536345,275.52,2670,100,45 +1791536346,275.66,2670,100,45 +1791536347,275.52,2670,100,45 +1791536348,275.30,2670,100,45 +1791536349,275.38,2670,100,45 +1791536350,275.12,2670,100,45 +1791536351,275.18,2670,100,45 +1791536352,275.64,2670,100,45 +1791536353,275.77,2670,100,45 +1791536354,275.83,2670,100,45 +1791536355,275.69,2670,100,45 +1791536356,275.42,2670,100,45 +1791536357,275.40,2670,100,45 +1791536358,275.39,2670,100,45 +1791536360,275.35,2670,100,45 +1791536361,275.18,2670,100,45 +1791536362,275.49,2670,100,45 +1791536363,275.30,2670,100,45 +1791536364,275.49,2670,100,45 +1791536365,275.52,2670,100,45 +1791536366,275.42,2670,100,45 +1791536367,275.55,2670,100,45 +1791536368,275.41,2670,100,45 +1791536369,275.51,2670,100,45 +1791536370,275.74,2670,100,45 +1791536371,275.93,2670,100,45 +1791536372,275.71,2670,100,45 +1791536373,275.59,2670,100,45 +1791536374,275.64,2670,100,45 +1791536375,275.63,2670,100,45 +1791536376,275.64,2670,100,45 +1791536377,275.20,2670,100,45 +1791536379,275.46,2670,100,46 +1791536380,275.75,2670,100,46 +1791536381,275.81,2670,100,46 +1791536382,275.48,2670,100,46 +1791536383,275.74,2670,100,46 +1791536384,275.67,2670,100,46 +1791536385,275.55,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-07-x4-direct.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-07-x4-direct.csv new file mode 100644 index 000000000..343539e09 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-07-x4-direct.csv @@ -0,0 +1,118 @@ +1791536406,81.86,2520,0,34 +1791536407,82.61,2520,0,34 +1791536408,81.17,2520,0,34 +1791536409,84.94,2520,0,34 +1791536410,161.93,2685,0,37 +1791536411,255.04,2685,100,39 +1791536412,271.83,2685,100,40 +1791536414,272.05,2685,100,40 +1791536415,272.34,2685,100,40 +1791536416,272.39,2685,100,40 +1791536417,272.58,2685,100,41 +1791536418,272.46,2685,100,41 +1791536419,272.73,2685,100,41 +1791536420,272.76,2685,100,41 +1791536421,273.18,2685,100,41 +1791536422,273.53,2685,100,41 +1791536423,273.18,2685,100,41 +1791536424,273.10,2685,100,42 +1791536425,273.57,2685,100,42 +1791536426,273.57,2685,100,42 +1791536427,273.70,2685,100,42 +1791536428,273.65,2685,100,42 +1791536429,273.97,2685,100,42 +1791536430,273.85,2685,100,42 +1791536431,273.86,2685,100,42 +1791536433,273.15,2685,100,42 +1791536434,273.28,2685,100,43 +1791536435,273.96,2685,100,43 +1791536436,273.66,2685,100,43 +1791536437,273.58,2685,100,43 +1791536438,273.76,2685,100,43 +1791536439,273.79,2685,100,43 +1791536440,274.06,2685,100,43 +1791536441,273.95,2685,100,43 +1791536442,273.91,2685,100,43 +1791536443,273.31,2685,100,43 +1791536444,274.12,2685,100,43 +1791536445,274.60,2685,100,43 +1791536446,274.74,2685,100,43 +1791536447,275.15,2685,100,43 +1791536448,275.27,2685,100,43 +1791536449,275.23,2685,100,44 +1791536450,275.21,2685,100,44 +1791536451,275.15,2685,100,44 +1791536452,274.94,2685,100,44 +1791536454,274.99,2685,100,44 +1791536455,274.55,2685,100,44 +1791536456,274.55,2685,100,44 +1791536457,274.17,2685,100,44 +1791536458,274.52,2685,100,44 +1791536459,274.63,2685,100,44 +1791536460,274.92,2685,100,44 +1791536461,274.98,2685,100,44 +1791536462,274.93,2685,100,44 +1791536463,274.99,2685,100,44 +1791536464,274.79,2685,100,44 +1791536465,274.97,2685,100,44 +1791536466,275.01,2685,100,44 +1791536467,275.02,2685,100,44 +1791536468,275.00,2685,100,44 +1791536469,274.83,2685,100,44 +1791536470,274.89,2670,100,44 +1791536471,274.91,2670,100,45 +1791536472,275.43,2670,100,45 +1791536474,275.52,2670,100,45 +1791536475,275.33,2670,100,45 +1791536476,275.53,2670,100,45 +1791536477,275.92,2670,100,45 +1791536478,275.80,2670,100,45 +1791536479,275.93,2670,100,45 +1791536480,275.83,2670,100,45 +1791536481,275.52,2670,100,45 +1791536482,275.53,2670,100,45 +1791536483,275.63,2670,100,45 +1791536484,275.48,2670,100,45 +1791536485,275.54,2670,100,45 +1791536486,275.52,2670,100,45 +1791536487,275.50,2670,100,45 +1791536488,275.49,2670,100,45 +1791536489,275.57,2670,100,45 +1791536490,275.48,2670,100,45 +1791536491,275.97,2670,100,45 +1791536493,276.09,2670,100,45 +1791536494,275.72,2670,100,45 +1791536495,275.89,2670,100,45 +1791536496,275.75,2670,100,45 +1791536497,275.57,2670,100,45 +1791536498,275.65,2670,100,45 +1791536499,275.46,2670,100,45 +1791536500,275.24,2670,100,45 +1791536501,275.60,2670,100,45 +1791536502,275.50,2670,100,45 +1791536503,275.70,2670,100,45 +1791536504,275.83,2670,100,45 +1791536505,275.92,2670,100,45 +1791536506,276.33,2670,100,45 +1791536507,276.05,2670,100,45 +1791536508,275.96,2670,100,45 +1791536510,276.06,2670,100,45 +1791536511,276.02,2670,100,45 +1791536512,275.94,2670,100,45 +1791536513,275.80,2670,100,45 +1791536514,275.54,2670,100,45 +1791536515,275.71,2670,100,45 +1791536516,275.78,2670,100,45 +1791536517,276.05,2670,100,45 +1791536518,275.77,2670,100,45 +1791536519,275.95,2670,100,45 +1791536520,275.71,2670,100,45 +1791536521,276.18,2670,100,45 +1791536522,276.31,2670,100,45 +1791536523,276.28,2670,100,45 +1791536524,275.84,2670,100,45 +1791536525,275.84,2670,100,45 +1791536526,276.17,2670,100,45 +1791536528,276.52,2670,100,45 +1791536529,276.46,2670,100,45 +1791536530,276.26,2670,100,45 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-08-hl-v6-all.csv b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-08-hl-v6-all.csv new file mode 100644 index 000000000..b49dc5b47 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s1/smi-08-hl-v6-all.csv @@ -0,0 +1,118 @@ +1791536550,27.22,210,0,33 +1791536551,70.72,2520,0,33 +1791536552,80.23,2520,0,33 +1791536553,83.13,2520,0,33 +1791536554,121.69,2685,100,38 +1791536555,246.83,2685,100,39 +1791536556,284.11,2685,100,40 +1791536557,284.58,2685,100,40 +1791536558,285.01,2685,100,40 +1791536559,284.97,2685,100,41 +1791536561,285.17,2685,100,41 +1791536562,285.15,2685,100,41 +1791536563,285.45,2685,100,41 +1791536564,285.45,2685,100,41 +1791536565,285.62,2685,100,42 +1791536566,285.60,2685,100,42 +1791536567,285.28,2685,100,42 +1791536568,285.67,2685,100,42 +1791536569,285.45,2685,100,42 +1791536570,286.00,2685,100,42 +1791536571,286.44,2685,100,42 +1791536572,286.33,2685,100,43 +1791536573,285.72,2685,100,43 +1791536574,270.98,2685,100,43 +1791536575,286.06,2685,100,43 +1791536576,286.34,2685,100,43 +1791536577,286.22,2685,100,43 +1791536578,286.79,2685,100,43 +1791536580,286.43,2685,100,43 +1791536581,286.62,2685,100,43 +1791536582,286.93,2685,100,43 +1791536583,286.74,2685,100,44 +1791536584,286.87,2685,100,44 +1791536585,287.43,2685,100,44 +1791536586,287.43,2685,100,44 +1791536587,287.36,2685,100,44 +1791536588,287.42,2685,100,44 +1791536589,287.30,2685,99,44 +1791536590,286.99,2685,100,44 +1791536591,287.13,2685,100,44 +1791536592,287.50,2685,100,44 +1791536593,287.59,2670,100,44 +1791536594,287.57,2670,100,44 +1791536595,287.72,2670,100,44 +1791536596,287.69,2670,100,45 +1791536597,287.35,2670,100,45 +1791536598,287.59,2670,100,45 +1791536600,287.33,2670,100,45 +1791536601,287.55,2670,100,45 +1791536602,287.71,2670,100,45 +1791536603,288.11,2670,100,45 +1791536604,287.80,2670,100,45 +1791536605,288.04,2670,100,45 +1791536606,287.35,2670,100,45 +1791536607,287.53,2670,100,45 +1791536608,287.66,2670,100,45 +1791536609,287.89,2670,100,45 +1791536610,287.96,2670,100,45 +1791536611,288.00,2670,100,45 +1791536612,288.10,2670,100,45 +1791536613,287.76,2670,100,45 +1791536614,287.67,2670,100,45 +1791536615,287.89,2670,100,45 +1791536616,287.79,2670,100,45 +1791536617,287.85,2670,100,45 +1791536619,287.77,2670,100,46 +1791536620,288.14,2670,100,46 +1791536621,287.73,2670,100,46 +1791536622,287.70,2670,100,46 +1791536623,286.94,2670,100,46 +1791536624,288.00,2670,100,46 +1791536625,287.60,2670,100,46 +1791536626,288.13,2670,100,46 +1791536627,287.82,2670,100,46 +1791536628,288.33,2670,100,46 +1791536629,287.87,2670,100,46 +1791536630,288.07,2670,100,46 +1791536631,287.86,2670,100,46 +1791536632,287.82,2670,100,46 +1791536633,287.90,2670,100,46 +1791536634,287.91,2670,100,46 +1791536635,288.30,2670,100,46 +1791536636,288.10,2670,100,46 +1791536638,287.83,2670,100,46 +1791536639,287.74,2670,100,46 +1791536640,287.73,2670,100,46 +1791536641,287.73,2670,100,46 +1791536642,288.01,2670,100,46 +1791536643,288.17,2670,100,46 +1791536644,288.14,2670,100,46 +1791536645,288.11,2670,100,46 +1791536646,288.37,2670,100,46 +1791536647,288.34,2670,100,46 +1791536648,288.06,2670,100,46 +1791536649,288.03,2670,100,46 +1791536650,288.05,2670,100,46 +1791536651,288.24,2670,100,46 +1791536652,287.95,2670,100,46 +1791536653,288.25,2670,100,46 +1791536654,288.16,2670,100,46 +1791536656,288.24,2670,100,46 +1791536657,288.70,2670,100,46 +1791536658,289.14,2670,100,46 +1791536659,289.04,2670,100,46 +1791536660,289.00,2670,100,46 +1791536661,288.88,2670,100,46 +1791536662,288.70,2670,100,46 +1791536663,288.77,2670,100,47 +1791536664,288.74,2670,100,47 +1791536665,289.04,2670,100,47 +1791536666,288.94,2670,100,47 +1791536667,288.78,2670,100,47 +1791536668,288.69,2670,100,47 +1791536669,288.47,2670,100,47 +1791536670,289.04,2670,100,47 +1791536672,289.11,2670,100,47 +1791536673,289.05,2670,100,47 +1791536674,288.86,2670,100,47 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/VERDICT b/docs/analysis/class-v6/1p5x/x4/rows/VERDICT new file mode 100644 index 000000000..bd24c4769 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/VERDICT @@ -0,0 +1,3 @@ +tally {('direct', 'AGREE'): 44, ('fold', 'AGREE'): 12, ('generated', 'AGREE'): 44, ('prefix', 'AGREE'): 44, ('wrong', 'DISAGREE'): 40, ('wrong', 'AGREE'): 4} +known-failed refused on every reg64c window and seed: True +VERDICT EQUIVALENT mismatches 0 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/arith.txt b/docs/analysis/class-v6/1p5x/x4/rows/arith.txt new file mode 100644 index 000000000..baa867ac7 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/arith.txt @@ -0,0 +1,12 @@ +form g a vs fold (slot, datapath) a vs model (slot, datapath) r_new at r0 2.0, same form both sides (vs fold slot, dp; vs model slot, dp) +direct 0.9606 0.9990, 0.9998 1.0726, 1.0150 1.923, 1.922, 1.791, 1.893 +generated 0.9590 0.9668, 0.9925 1.0381, 1.0075 1.984, 1.933, 1.848, 1.904 +prefix 0.9693 1.4508, 1.1004 1.5578, 1.1171 1.336, 1.762, 1.244, 1.735 +grouped incremental 1.0000 (no GPU text) 0.9629, 0.9914 1.0339, 1.0065 2.077, 2.017, 1.934, 1.987 + +best pair: the card on 'generated' (g 0.9590), the specialist on 'grouped incremental' +r0 2.0: vs fold slot: a 0.9629 r_new 1.992; vs fold datapath: a 0.9914 r_new 1.935; vs model slot: a 1.0339 r_new 1.855; vs model datapath: a 1.0065 r_new 1.906 +r0 1.9: vs fold slot: a 0.9629 r_new 1.892; vs fold datapath: a 0.9914 r_new 1.838; vs model slot: a 1.0339 r_new 1.762; vs model datapath: a 1.0065 r_new 1.810 +r0 2.1: vs fold slot: a 0.9629 r_new 2.092; vs fold datapath: a 0.9914 r_new 2.031; vs model slot: a 1.0339 r_new 1.948; vs model datapath: a 1.0065 r_new 2.001 + +the yardstick: from 2.0, 1.5 needs g / a = 0.75 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/chip-rows.txt b/docs/analysis/class-v6/1p5x/x4/rows/chip-rows.txt new file mode 100644 index 000000000..933418310 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/chip-rows.txt @@ -0,0 +1,19 @@ +# loads per hash executed 256 (32 per iteration x 8); base writes per iteration 128 (112 to r8..r63); shadow writes per pass 256, all in r0..r7 +form mix ops X extra reads A flop bits F state bits per lane slot nJ (lo c hi) datapath nJ (lo c hi) state ports +fold (frozen) 16128 16128 0 0 101.0 112.7 139.4 20.2 23.2 30.2 the 64 x 32-bit window only 63 window reads per load +direct 15872 16128 0 0 99.4 111.0 137.4 19.9 22.9 30.0 the window only 63 window reads per load (a tree: depth 6, same reads) +generated (GPU text: recompute at load) 8400 5792 20224 256 52.5 58.2 70.9 10.5 11.5 14.1 +8 x 32-bit group sums per lane (32 B, flops) group recomputes read 8 registers each; the in-group partial reads up to 7 +prefix (F05 text: running S on every write) 121320 8160 1802240 32 785.2 852.3 1003.9 177.4 179.0 182.5 +1 x 32-bit running total per lane (flops) the old value of every written register (main and shadow) rotated into S +grouped incremental (chip only, by the same identity) 7560 2784 36864 256 47.2 51.8 62.3 9.4 9.9 11.1 +8 x 32-bit group sums per lane (32 B) groups 1..7 move on base writes to r8..r63; group 0 recomputed at each load (8 reads) + +# a = (machine + form) / machine, machine 1.528 microjoules (N5, GDDR7 board, no mix term); per-lane-op delta over the 102,612 shadow+base lane-ops +fold (frozen) slot +112.7 nJ a 1.0738 per lane-op +1.098 pJ of the shadow +16.8 percent +fold (frozen) dp +23.2 nJ a 1.0152 per lane-op +0.226 pJ of the shadow +3.5 percent +direct slot +111.0 nJ a 1.0727 per lane-op +1.082 pJ of the shadow +16.5 percent +direct dp +22.9 nJ a 1.0150 per lane-op +0.223 pJ of the shadow +3.4 percent +generated (GPU text: recompute at load) slot +58.2 nJ a 1.0381 per lane-op +0.567 pJ of the shadow +8.7 percent +generated (GPU text: recompute at load) dp +11.5 nJ a 1.0076 per lane-op +0.112 pJ of the shadow +1.7 percent +prefix (F05 text: running S on every write) slot +852.3 nJ a 1.5578 per lane-op +8.306 pJ of the shadow +126.8 percent +prefix (F05 text: running S on every write) dp +179.0 nJ a 1.1171 per lane-op +1.744 pJ of the shadow +26.6 percent +grouped incremental (chip only, by the same identity) slot +51.8 nJ a 1.0339 per lane-op +0.505 pJ of the shadow +7.7 percent +grouped incremental (chip only, by the same identity) dp +9.9 nJ a 1.0065 per lane-op +0.096 pJ of the shadow +1.5 percent diff --git a/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows.txt b/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows.txt new file mode 100644 index 000000000..77f431451 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows.txt @@ -0,0 +1,15 @@ +run pack MH/s W nJ per hash sm MHz util samples regs blocks/SM fingerprint check +01-hl-v6-all hl-v6-all 35.080 285.4 8134 2679 100 111 93 20 e8f4f3289c6ee1fc PASS +02-x4-direct x4-direct 35.021 274.5 7839 2681 100 109 182 8 e8f4f3289c6ee1fc PASS +03-x4-generated x4-generated 35.053 274.2 7824 2680 100 110 142 12 e8f4f3289c6ee1fc PASS +04-x4-prefix x4-prefix 35.056 277.1 7905 2680 100 109 154 12 e8f4f3289c6ee1fc PASS +05-x4-prefix x4-prefix 35.053 277.8 7926 2679 100 110 154 12 e8f4f3289c6ee1fc PASS +06-x4-generated x4-generated 35.056 274.8 7840 2678 100 109 142 12 e8f4f3289c6ee1fc PASS +07-x4-direct x4-direct 35.020 274.9 7851 2677 100 111 182 8 e8f4f3289c6ee1fc PASS +08-hl-v6-all hl-v6-all 35.054 287.4 8199 2674 100 110 93 20 e8f4f3289c6ee1fc PASS + +pair form pass 1 rate % pass 1 J/hash % pass 2 rate % pass 2 J/hash % mean rate % mean J/hash % g (J/hash ratio) +A/A hl-v6-all run 8 vs run 1 -0.07 +0.80 +pair x4-direct -0.17 -3.63 -0.10 -4.25 -0.13 -3.94 0.9606 +pair x4-generated -0.08 -3.82 +0.01 -4.38 -0.04 -4.10 0.9590 +pair x4-prefix -0.07 -2.82 -0.00 -3.33 -0.04 -3.07 0.9693 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/suite-b51d8c04b.txt b/docs/analysis/class-v6/1p5x/x4/rows/suite-b51d8c04b.txt new file mode 100644 index 000000000..0d22fd313 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/suite-b51d8c04b.txt @@ -0,0 +1,15 @@ +test reg64form::tests::x4_forms_equal_the_fold_and_the_wrong_form_is_refused ... ok +test result: ok. 76 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 140.72s +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.42s +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.80s +test result: ok. 27 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.37s +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.03s +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.85s +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.01s +test result: ok. 12 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 20.99s +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +EXIT 0 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/verdicts.txt b/docs/analysis/class-v6/1p5x/x4/rows/verdicts.txt new file mode 100644 index 000000000..2931fadef --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/verdicts.txt @@ -0,0 +1,188 @@ +ctx01 direct D@0 AGREE +ctx01 direct D1@1572864 AGREE +ctx01 direct D1@3141632 AGREE +ctx01 direct D@1568768 AGREE +ctx01 fold D@0 AGREE +ctx01 fold D1@1572864 AGREE +ctx01 fold D1@3141632 AGREE +ctx01 fold D@1568768 AGREE +ctx01 generated D@0 AGREE +ctx01 generated D1@1572864 AGREE +ctx01 generated D1@3141632 AGREE +ctx01 generated D@1568768 AGREE +ctx01 prefix D@0 AGREE +ctx01 prefix D1@1572864 AGREE +ctx01 prefix D1@3141632 AGREE +ctx01 prefix D@1568768 AGREE +ctx01 wrong D@0 DISAGREE +ctx01 wrong D1@1572864 DISAGREE +ctx01 wrong D1@3141632 DISAGREE +ctx01 wrong D@1568768 DISAGREE +ctx02 direct D@0 AGREE +ctx02 direct D1@1572864 AGREE +ctx02 direct D1@3141632 AGREE +ctx02 direct D@1568768 AGREE +ctx02 fold D@0 AGREE +ctx02 fold D1@1572864 AGREE +ctx02 fold D1@3141632 AGREE +ctx02 fold D@1568768 AGREE +ctx02 generated D@0 AGREE +ctx02 generated D1@1572864 AGREE +ctx02 generated D1@3141632 AGREE +ctx02 generated D@1568768 AGREE +ctx02 prefix D@0 AGREE +ctx02 prefix D1@1572864 AGREE +ctx02 prefix D1@3141632 AGREE +ctx02 prefix D@1568768 AGREE +ctx02 wrong D@0 DISAGREE +ctx02 wrong D1@1572864 DISAGREE +ctx02 wrong D1@3141632 DISAGREE +ctx02 wrong D@1568768 DISAGREE +ctx03 direct D@0 AGREE +ctx03 direct D1@1572864 AGREE +ctx03 direct D1@3141632 AGREE +ctx03 direct D@1568768 AGREE +ctx03 fold D@0 AGREE +ctx03 fold D1@1572864 AGREE +ctx03 fold D1@3141632 AGREE +ctx03 fold D@1568768 AGREE +ctx03 generated D@0 AGREE +ctx03 generated D1@1572864 AGREE +ctx03 generated D1@3141632 AGREE +ctx03 generated D@1568768 AGREE +ctx03 prefix D@0 AGREE +ctx03 prefix D1@1572864 AGREE +ctx03 prefix D1@3141632 AGREE +ctx03 prefix D@1568768 AGREE +ctx03 wrong D@0 AGREE +ctx03 wrong D1@1572864 AGREE +ctx03 wrong D1@3141632 AGREE +ctx03 wrong D@1568768 AGREE +fuzz0 direct AGREE +fuzz0 generated AGREE +fuzz0 prefix AGREE +fuzz0 wrong DISAGREE +fuzz10 direct AGREE +fuzz10 generated AGREE +fuzz10 prefix AGREE +fuzz10 wrong DISAGREE +fuzz11 direct AGREE +fuzz11 generated AGREE +fuzz11 prefix AGREE +fuzz11 wrong DISAGREE +fuzz12 direct AGREE +fuzz12 generated AGREE +fuzz12 prefix AGREE +fuzz12 wrong DISAGREE +fuzz13 direct AGREE +fuzz13 generated AGREE +fuzz13 prefix AGREE +fuzz13 wrong DISAGREE +fuzz14 direct AGREE +fuzz14 generated AGREE +fuzz14 prefix AGREE +fuzz14 wrong DISAGREE +fuzz15 direct AGREE +fuzz15 generated AGREE +fuzz15 prefix AGREE +fuzz15 wrong DISAGREE +fuzz16 direct AGREE +fuzz16 generated AGREE +fuzz16 prefix AGREE +fuzz16 wrong DISAGREE +fuzz17 direct AGREE +fuzz17 generated AGREE +fuzz17 prefix AGREE +fuzz17 wrong DISAGREE +fuzz18 direct AGREE +fuzz18 generated AGREE +fuzz18 prefix AGREE +fuzz18 wrong DISAGREE +fuzz19 direct AGREE +fuzz19 generated AGREE +fuzz19 prefix AGREE +fuzz19 wrong DISAGREE +fuzz1 direct AGREE +fuzz1 generated AGREE +fuzz1 prefix AGREE +fuzz1 wrong DISAGREE +fuzz20 direct AGREE +fuzz20 generated AGREE +fuzz20 prefix AGREE +fuzz20 wrong DISAGREE +fuzz21 direct AGREE +fuzz21 generated AGREE +fuzz21 prefix AGREE +fuzz21 wrong DISAGREE +fuzz22 direct AGREE +fuzz22 generated AGREE +fuzz22 prefix AGREE +fuzz22 wrong DISAGREE +fuzz23 direct AGREE +fuzz23 generated AGREE +fuzz23 prefix AGREE +fuzz23 wrong DISAGREE +fuzz24 direct AGREE +fuzz24 generated AGREE +fuzz24 prefix AGREE +fuzz24 wrong DISAGREE +fuzz25 direct AGREE +fuzz25 generated AGREE +fuzz25 prefix AGREE +fuzz25 wrong DISAGREE +fuzz26 direct AGREE +fuzz26 generated AGREE +fuzz26 prefix AGREE +fuzz26 wrong DISAGREE +fuzz27 direct AGREE +fuzz27 generated AGREE +fuzz27 prefix AGREE +fuzz27 wrong DISAGREE +fuzz28 direct AGREE +fuzz28 generated AGREE +fuzz28 prefix AGREE +fuzz28 wrong DISAGREE +fuzz29 direct AGREE +fuzz29 generated AGREE +fuzz29 prefix AGREE +fuzz29 wrong DISAGREE +fuzz2 direct AGREE +fuzz2 generated AGREE +fuzz2 prefix AGREE +fuzz2 wrong DISAGREE +fuzz30 direct AGREE +fuzz30 generated AGREE +fuzz30 prefix AGREE +fuzz30 wrong DISAGREE +fuzz31 direct AGREE +fuzz31 generated AGREE +fuzz31 prefix AGREE +fuzz31 wrong DISAGREE +fuzz3 direct AGREE +fuzz3 generated AGREE +fuzz3 prefix AGREE +fuzz3 wrong DISAGREE +fuzz4 direct AGREE +fuzz4 generated AGREE +fuzz4 prefix AGREE +fuzz4 wrong DISAGREE +fuzz5 direct AGREE +fuzz5 generated AGREE +fuzz5 prefix AGREE +fuzz5 wrong DISAGREE +fuzz6 direct AGREE +fuzz6 generated AGREE +fuzz6 prefix AGREE +fuzz6 wrong DISAGREE +fuzz7 direct AGREE +fuzz7 generated AGREE +fuzz7 prefix AGREE +fuzz7 wrong DISAGREE +fuzz8 direct AGREE +fuzz8 generated AGREE +fuzz8 prefix AGREE +fuzz8 wrong DISAGREE +fuzz9 direct AGREE +fuzz9 generated AGREE +fuzz9 prefix AGREE +fuzz9 wrong DISAGREE diff --git a/tools/1p5x/x4/arith.py b/tools/1p5x/x4/arith.py new file mode 100644 index 000000000..9ab376e22 --- /dev/null +++ b/tools/1p5x/x4/arith.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""X4 (1.5x programme): r_new = r0 * g / a from the GPU pairs (gpu_rows.py output) and the chip rows (chip_rows.py +output). g: the card's joules per hash with the form over the frozen text's, the mean of the two same-session passes. +a: the specialist's machine energy with a form over the reference, at the adversary lane's 1.528 microjoules (N5, GDDR7 +board), two references: (fold) a specialist that implements the frozen literal fold, (model) the served machine, which +carries no address-mix term. Each side picks its cheapest form on its own; the per-form rows (both sides on one form) are +printed for the record. Usage: arith.py [r0 ...] (default r0 2.0, 1.9, 2.1).""" +import re, sys +gtxt, ctxt = open(sys.argv[1]).read(), open(sys.argv[2]).read() +r0s = [float(x) for x in sys.argv[3:]] or [2.0, 1.9, 2.1] +M = 1528.0 +g = {m.group(1).replace("x4-", ""): float(m.group(2)) for m in re.finditer(r"^pair\t(x4-\S+)\t.*\t([0-9.]+)$", gtxt, re.M)} +chip = {} +for line in ctxt.splitlines(): + p = line.split("\t") + if len(p) >= 7 and re.match(r"[\d.]+ [\d.]+ [\d.]+$", p[5]): + chip[p[0].split(" (")[0]] = (float(p[5].split()[1]), float(p[6].split()[1])) +fold_s, fold_d = chip["fold"] +print("form\tg\ta vs fold (slot, datapath)\ta vs model (slot, datapath)\tr_new at r0 2.0, same form both sides (vs fold slot, dp; vs model slot, dp)") +for k in ("direct", "generated", "prefix", "grouped incremental"): + s, d = chip[k] + gg = g.get(k, 1.0) + af = ((M + s) / (M + fold_s), (M + d) / (M + fold_d)); am = ((M + s) / M, (M + d) / M) + print(f"{k}\t{gg:.4f}{'' if k in g else ' (no GPU text)'}\t{af[0]:.4f}, {af[1]:.4f}\t{am[0]:.4f}, {am[1]:.4f}\t" + ", ".join(f"{2.0*gg/a:.3f}" for a in (*af, *am))) +gk = min(g, key=g.get); ck = min((k for k in chip if k != "fold"), key=lambda k: chip[k][0]) +s, d = chip[ck] +print(f"\nbest pair: the card on '{gk}' (g {g[gk]:.4f}), the specialist on '{ck}'") +for r0 in r0s: + out = [] + for lab, a in (("vs fold slot", (M + s) / (M + fold_s)), ("vs fold datapath", (M + d) / (M + fold_d)), ("vs model slot", (M + s) / M), ("vs model datapath", (M + d) / M)): + out.append(f"{lab}: a {a:.4f} r_new {r0 * g[gk] / a:.3f}") + print(f"r0 {r0}: " + "; ".join(out)) +print("\nthe yardstick: from 2.0, 1.5 needs g / a = 0.75") diff --git a/tools/1p5x/x4/chip_rows.py b/tools/1p5x/x4/chip_rows.py new file mode 100644 index 000000000..9c702d08f --- /dev/null +++ b/tools/1p5x/x4/chip_rows.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""X4 (1.5x programme): the chip-side cost of each byte-identical reg64c address-mix form, counted from the exported +kernel texts of the frozen object and priced with the adversary lane's calibrated constants (its message of 09:4x UK, +9 October 2026, on class-v6-adversary 43c9f7cd8 tools/chip-model/mf/: e_op 6.55 pJ per lane-op at N5, band 6.01 to +7.77; an xor-rotate that does not pass the slot's macro read about 1.0 pJ; e_rf 3.5 pJ per 256-bit macro access shared by +8 lanes, band 2.0 to 7.0; flop state 0.03 pJ per bit written; the slot reads 3 and writes 1 window register per +instruction already; the chip's shadow 0.672 microjoules and the GDDR7 machine 1.528 microjoules per hash at N5). +Counts per hash per lane: X = xor or rotate-xor ops of the mix, A = window reads beyond the slot's own, F = flop bits +written for the form's state. Two pricings: 'slot' (each mix op a full lane-op, the adversary's literal-fold row) and +'datapath' (each mix op an xor at 1.0 pJ, the running-total row). Usage: chip_rows.py [--tsv out.tsv]. Modelled, no chip measured.""" +import re, sys + +EX = sys.argv[1] +ITS, REPS = 8, 27 +E_OP = {"lo": 6.01, "c": 6.55, "hi": 7.77} +E_X_DP = 1.0 +E_RF = {"lo": 2.0, "c": 3.5, "hi": 7.0} +E_FLOP_BIT = 0.03 +SHADOW_UJ, MACHINE_UJ = 0.672, 1.528 + +def loop_body(path): + t = open(path).read() + k = t.index("__global__ void igneum_hash(") + t = t[k:] + a = t.index("for (uint32_t it = 0u;") + b = t.index("latency-shadow block", a) + c = t.index("for (uint32_t sh = 0u;", b) + d = t.index("\n }\n", c) + return t[a:b], t[c:d], t[:a] + +def terms(expr): + return len(re.findall(r"rotl_imm\(r\d+, \d+u\)|\br\d+\b|\bg\d\b", expr)) + +def writes(body): + return [int(m.group(1)) for m in re.finditer(r"^\s+r(\d+) = .*//\s*s?\d+ \w+$", body, re.M)] + +rows = [] +main_f, shadow_f, _ = loop_body(f"{EX}/fold/kernel.cu") +loads_per_it = len(re.findall(r"// \d+ load", main_f)) +main_w = writes(main_f) +shadow_w = writes(shadow_f) +assert all(d < 8 for d in shadow_w), "a shadow write outside r0..r7" +L = loads_per_it * ITS +# fold and direct: 63 terms, 63 reads, 63 (fold: rotl(m,1)^r) or 62 (tree) ops per load +rows.append(("fold (frozen)", 63 * L, 63 * L, 0, 0, "the 64 x 32-bit window only", "63 window reads per load")) +rows.append(("direct", 62 * L, 63 * L, 0, 0, "the window only", "63 window reads per load (a tree: depth 6, same reads)")) +# generated: parse each load's statement line +gm, _, ginit = loop_body(f"{EX}/generated/kernel.cu") +X = A = F = 0 +for line in gm.splitlines(): + if "S = " not in line: + continue + n_groups = len(re.findall(r"\bg\d = \(", line)) + X += n_groups * 7; A += n_groups * 8; F += n_groups * 32 + p = re.search(r"p_ = (.*?); m =", line).group(1) + pt = terms(p); pr = len(re.findall(r"\br\d+\b", p)) + X += 7 + max(pt - 1, 0) + 3 + A += pr +X *= ITS; A *= ITS; F *= ITS +rows.append(("generated (GPU text: recompute at load)", X, A, F, 8 * 32, "+8 x 32-bit group sums per lane (32 B, flops)", "group recomputes read 8 registers each; the in-group partial reads up to 7")) +# prefix (F05 text): every write moves S; per load p_ over the first s terms +pm, ps, _ = loop_body(f"{EX}/prefix/kernel.cu") +nw = len(writes(pm)) * ITS + len(writes(ps)) * REPS * ITS +X = 2 * nw; F = 32 * nw; A = 0 +for line in pm.splitlines(): + m = re.search(r"p_ = (.*?); m =", line) + if m: + pt = terms(m.group(1)); X += (max(pt - 1, 0) + 3) * ITS; A += len(re.findall(r"\br\d+\b", m.group(1))) * ITS +rows.append(("prefix (F05 text: running S on every write)", X, A, F, 32, "+1 x 32-bit running total per lane (flops)", "the old value of every written register (main and shadow) rotated into S")) +# the chip's best: group sums 1..7 kept on main-program writes (dst >= 8), group 0 recomputed at each load +# (the shadow's 55,296 writes land in r0..r7 only, so they move nothing kept) +upd = sum(1 for d in main_w if d >= 8) * ITS +X = 2 * upd; F = 32 * upd; A = 0 +for line in gm.splitlines(): + m = re.search(r"p_ = (.*?); m =", line) + if m: + p = m.group(1) + X += (7 + 7 + max(terms(p) - 1, 0) + 3) * ITS + A += (8 + len(re.findall(r"\br\d+\b", p))) * ITS + F += 32 * ITS +rows.append(("grouped incremental (chip only, by the same identity)", X, A, F, 8 * 32, "+8 x 32-bit group sums per lane (32 B)", "groups 1..7 move on base writes to r8..r63; group 0 recomputed at each load (8 reads)")) + +def price(X, A, F, pr, b): + e_x = E_OP[b] if pr == "slot" else E_X_DP + return (X * e_x + A * E_RF[b] / 8 + F * E_FLOP_BIT) / 1000.0 # nJ + +out = [] +hdr = "form\tmix ops X\textra reads A\tflop bits F\tstate bits per lane\tslot nJ (lo c hi)\tdatapath nJ (lo c hi)\tstate\tports" +out.append(hdr) +for name, X, A, F, sb, state, ports in rows: + s = [price(X, A, F, "slot", b) for b in ("lo", "c", "hi")] + d = [price(X, A, F, "dp", b) for b in ("lo", "c", "hi")] + out.append(f"{name}\t{X}\t{A}\t{F}\t{sb}\t{s[0]:.1f} {s[1]:.1f} {s[2]:.1f}\t{d[0]:.1f} {d[1]:.1f} {d[2]:.1f}\t{state}\t{ports}") +print(f"# loads per hash executed {L} ({loads_per_it} per iteration x {ITS}); base writes per iteration {len(main_w)} ({sum(1 for d in main_w if d >= 8)} to r8..r63); shadow writes per pass {len(shadow_w)}, all in r0..r7") +print("\n".join(out)) +# per-lane-op delta and a: machine energy with the form against the model's machine (which carries no mix cost) +print("\n# a = (machine + form) / machine, machine 1.528 microjoules (N5, GDDR7 board, no mix term); per-lane-op delta over the 102,612 shadow+base lane-ops") +for name, X, A, F, sb, *_ in rows: + for pr in ("slot", "dp"): + e = price(X, A, F, pr, "c") + print(f"{name}\t{pr}\t+{e:.1f} nJ\ta {(MACHINE_UJ*1000 + e)/(MACHINE_UJ*1000):.4f}\tper lane-op +{e*1000/102612:.3f} pJ\tof the shadow +{100*e/(SHADOW_UJ*1000):.1f} percent") diff --git a/tools/1p5x/x4/differential.sh b/tools/1p5x/x4/differential.sh new file mode 100755 index 000000000..99cd8edbc --- /dev/null +++ b/tools/1p5x/x4/differential.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# X4 (1.5x programme): the CPU differential of the reg64c address-mix forms against the frozen definition. +# Runs on a build box (never the Mac), from the box worktree root holding igneum-pow/ (built --release) and in/: +# in/node1-state.igsd1 (sha256 abb58003...), in/state-epoch2.igsd1 (f36e6bba...), +# in/ref0{1,2,3}/{ref-D.txt,ref-D1.txt,job-context.json} (build-1:/srv/artefacts/tas/same-work-20261008-0N/). +# Order: the known-failed form first (it must disagree on every reg64c context, or the test is void), then the +# forms fold, direct, generated and prefix must equal the same-work references on every sampled nonce, then the +# fuzz set (random epoch, era and prehash on the class v6 string) where each form must equal the fold. +# Usage: tools/1p5x/x4/differential.sh [count per window, default 4096] [fuzz seeds, default 32] +set -u +OUT=${1:?out dir}; N=${2:-4096}; FZ=${3:-32} +B=igneum-pow/target/release/igneum-pow +mkdir -p "$OUT" +PRE=0000000000000000000000000000000000000000000000000000000000000001 +G=edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07 +CS=af89be5ddbadb6f6b4aee28ac8f249713be5d4c12621e3cea7f83ceada3c66b3 +V5E=3c3fab434f7fd894ce6db0b09f298c3865726253e4fc68fd77acd163ccea8221 +V5ERA=7c36b83374a673e990213be462509dcb08bcfc85144306aa9517cf3ad66faf6e +day() { printf '69676e65756d2d6461792f%s' "$(python3 -c "import struct,sys; print(struct.pack(' "$JOBS" +for c in 01 02 03; do + d0=$( [ $c = 03 ] && echo 20734 || echo 20730 ) + for form in wrong fold direct generated prefix; do + for w in "D 0" "D $((1572864 - N))" "D1 1572864" "D1 $((3145728 - N))"; do + set -- $w; dd=$([ $1 = D ] && echo $d0 || echo $((d0 + 1))) + echo "ctx $c $form $1 $2 $dd" >> "$JOBS" + done + done +done +for i in $(seq 0 $((FZ - 1))); do + for form in wrong fold direct generated prefix; do echo "fuzz $i $form" >> "$JOBS"; done +done +run_job() { + set -- $1 + if [ "$1" = ctx ]; then + local c=$2 form=$3 ref=$4 start=$5 dd=$6 + local f=$OUT/ctx$c-$form-$ref-$start.txt + $B hash-bound $(args_for $c $dd) --prehash $PRE --nonce $start --count $N --reg64-cpu-form $form > $f 2>$f.err + local lineno + [ "$ref" = D ] && lineno=$((start + 1)) || lineno=$((start - 1572864 + 1)) + if tail -n +$lineno in/ref$c/ref-$ref.txt | head -n $N | cmp -s - $f; then echo "ctx$c $form $ref@$start AGREE"; else echo "ctx$c $form $ref@$start DISAGREE"; fi + else + local i=$2 form=$3 + local h=$(printf 'x4-fuzz-%d' $i | sha256sum | cut -c1-64) + local era=$(printf 'x4-era-%d' $i | sha256sum | cut -c1-64) + local pre=$(printf 'x4-pre-%d' $i | sha256sum | cut -c1-64) + local nonce=$(( 0x$(printf 'x4-nonce-%d' $i | sha256sum | cut -c1-6) * 32 )) + $B hash-bound --epoch-hex $h --day-hex $(day 20730) --class mx8+sh256x27+state+reg64c+fold+rw --era 0:$era --era-widths 4 --state in/node1-state.igsd1 --prehash $pre --nonce $nonce --count 1024 --reg64-cpu-form $form > $OUT/fuzz$i-$form.txt 2>$OUT/fuzz$i-$form.txt.err + echo "fuzz$i $form DONE" + fi +} +export -f run_job args_for day; export B OUT N PRE G CS V5E V5ERA +xargs -P ${PAR:-24} -I{} bash -c 'run_job "{}"' < "$JOBS" > "$OUT/runs.txt" +# fuzz verdicts against the fold +for i in $(seq 0 $((FZ - 1))); do + for form in wrong direct generated prefix; do + if cmp -s $OUT/fuzz$i-fold.txt $OUT/fuzz$i-$form.txt; then echo "fuzz$i $form AGREE"; else echo "fuzz$i $form DISAGREE"; fi + done +done >> "$OUT/runs.txt" +grep -v DONE "$OUT/runs.txt" | sort > "$OUT/verdicts.txt" +# the verdict: known-failed refused on every reg64c window and fuzz seed; every other form agrees everywhere; +# context 03 (class v5, no reg64) is the no-op control: every form, the wrong one too, agrees with the reference +python3 - "$OUT/verdicts.txt" <<'PY' | tee "$OUT/VERDICT" +import sys, collections +rows=[l.split() for l in open(sys.argv[1])] +bad=[]; t=collections.Counter() +for key, form, *rest in rows: + v=rest[-1]; t[(form,v)]+=1 + reg64 = not key.startswith("ctx03") + want = "DISAGREE" if (form=="wrong" and reg64) else "AGREE" + if v!=want: bad.append(" ".join([key,form]+rest)) +print("tally", dict(t)) +print("known-failed refused on every reg64c window and seed:", all(r[-1]=="DISAGREE" for r in rows if r[1]=="wrong" and not r[0].startswith("ctx03"))) +print("VERDICT", "EQUIVALENT" if not bad else "FAIL", "mismatches", len(bad)) +for b in bad[:20]: print(" ", b) +PY diff --git a/tools/1p5x/x4/gpu_rows.py b/tools/1p5x/x4/gpu_rows.py new file mode 100644 index 000000000..c049bc0cb --- /dev/null +++ b/tools/1p5x/x4/gpu_rows.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""X4 (1.5x programme): the GPU rows of a pod-x4.sh run (the hash lane's recipe, build-1:/srv/artefacts/1p5x/ +gpu-row-recipe.md sha cbab453c: rate = the worker's own mhs=, watts = mean power.draw from 8 s in to the end of the +timed dispatches, nJ per hash = W / MH/s x 1,000, check=PASS and the fingerprint gate the row; pairs inside one +session). Usage: gpu_rows.py . Prints the per-run rows, then each form against the frozen +pack: pass 1 against run 1, pass 2 against run 8 (the order A B C D D C B A), and the mean of the two.""" +import re, sys, glob, os, statistics as st + +d, runlog = sys.argv[1], sys.argv[2] +times = {m.group(1): (int(m.group(2)), int(m.group(3))) for m in re.finditer(r"RESULT run (\S+) rc=0 secs=\d+ t0=(\d+) t1=(\d+)", open(runlog).read())} +rows = {} +for name, (t0, t1) in sorted(times.items()): + log = open(f"{d}/bench-{name}.log").read() + r = re.search(r"^RESULT (.*)$", log, re.M).group(1) + f = dict(kv.split("=", 1) for kv in r.split() if "=" in kv) + w, clk, util = [], [], [] + for line in open(f"{d}/smi-{name}.csv"): + p = line.strip().split(",") + if len(p) < 5 or not p[1].replace(".", "").isdigit(): + continue + t = int(p[0]) + if t0 + 8 <= t <= t1: + w.append(float(p[1])); clk.append(float(p[2])); util.append(float(p[3])) + mhs = float(f["mhs"]); W = st.mean(w) + rows[name] = dict(pack=name.split("-", 1)[1], mhs=mhs, W=W, nj=W / mhs * 1000, fp=f["fingerprint"], check=f["check"], regs=f["regs"], bps=f["blocks_per_sm"], sm=st.mean(clk), util=st.mean(util), n=len(w)) +print("run\tpack\tMH/s\tW\tnJ per hash\tsm MHz\tutil\tsamples\tregs\tblocks/SM\tfingerprint\tcheck") +for k, r in rows.items(): + print(f"{k}\t{r['pack']}\t{r['mhs']:.3f}\t{r['W']:.1f}\t{r['nj']:.0f}\t{r['sm']:.0f}\t{r['util']:.0f}\t{r['n']}\t{r['regs']}\t{r['bps']}\t{r['fp']}\t{r['check']}") +ks = list(rows) +frozen = [k for k in ks if k.endswith("hl-v6-all")] +print("\npair\tform\tpass 1 rate %\tpass 1 J/hash %\tpass 2 rate %\tpass 2 J/hash %\tmean rate %\tmean J/hash %\tg (J/hash ratio)") +f1, f2 = rows[frozen[0]], rows[frozen[-1]] +aa_r = 100 * (f2["mhs"] / f1["mhs"] - 1); aa_e = 100 * (f2["nj"] / f1["nj"] - 1) +print(f"A/A\thl-v6-all run 8 vs run 1\t{aa_r:+.2f}\t{aa_e:+.2f}\t\t\t\t\t") +for form in ("x4-direct", "x4-generated", "x4-prefix"): + rs = [k for k in ks if k.endswith(form)] + if len(rs) < 2: + continue + a, b = rows[rs[0]], rows[rs[1]] + p1r, p1e = 100 * (a["mhs"] / f1["mhs"] - 1), 100 * (a["nj"] / f1["nj"] - 1) + p2r, p2e = 100 * (b["mhs"] / f2["mhs"] - 1), 100 * (b["nj"] / f2["nj"] - 1) + g = ((a["nj"] / f1["nj"]) + (b["nj"] / f2["nj"])) / 2 + print(f"pair\t{form}\t{p1r:+.2f}\t{p1e:+.2f}\t{p2r:+.2f}\t{p2e:+.2f}\t{(p1r+p2r)/2:+.2f}\t{(p1e+p2e)/2:+.2f}\t{g:.4f}") diff --git a/tools/1p5x/x4/pod-x4.sh b/tools/1p5x/x4/pod-x4.sh new file mode 100755 index 000000000..da2736a93 --- /dev/null +++ b/tools/1p5x/x4/pod-x4.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# X4 (1.5x programme) on one rented card: same-session pairs of the frozen pack against the three alternative +# packs, stock clocks, the gen-6 worker --bench (250 x 2^24, block-warps 1, the pack self-test first: check=PASS and +# the 2^24 fingerprint), nvidia-smi power.draw at 1 Hz for each run. Order A B C D D C B A (the second pass reversed, +# so drift and heat land on both sides of every pair). Logs under /root/x4/out. Started under /root/x4/pids/bench.pid. +set -u +cd /root/x4 +W=${W:-/root/x4/igneum-worker-cuda-gen6} +mkdir -p out pids +echo $$ > pids/bench.pid +echo "RESULT start $(date -u +%FT%TZ) $(nvidia-smi --query-gpu=name,driver_version,power.limit,clocks.max.sm --format=csv,noheader -i 0)" +echo "RESULT worker sha256 $(sha256sum $W | cut -c1-16)" +ORDER=${ORDER:-"hl-v6-all x4-direct x4-generated x4-prefix x4-prefix x4-generated x4-direct hl-v6-all"} +i=0 +for P in $ORDER; do + i=$((i + 1)); N=$(printf '%02d-%s' $i $P) + ( while :; do echo "$(date -u +%s),$(nvidia-smi --query-gpu=power.draw,clocks.sm,utilization.gpu,temperature.gpu --format=csv,noheader,nounits -i 0 | tr -d ' ')"; sleep 1; done ) > out/smi-$N.csv 2>/dev/null & + SMI=$!; echo $SMI > pids/smi.pid + T0=$(date +%s) + timeout 900 $W --bench --pack packs/$P --batches ${BATCHES:-250} --batch-log2 24 --block-warps 1 --device 0 > out/bench-$N.log 2>&1; RC=$? + T1=$(date +%s) + kill $SMI 2>/dev/null; rm -f pids/smi.pid + echo "RESULT run $N rc=$RC secs=$((T1 - T0)) t0=$T0 t1=$T1" + grep -E "^RESULT|self-test|timed dispatches" out/bench-$N.log | sed "s/^/BENCH $N | /" + sleep ${GAP:-20} +done +echo "RESULT end $(date -u +%FT%TZ)" +rm -f pids/bench.pid diff --git a/tools/ci/batches/1p5x-x4-20261009.json b/tools/ci/batches/1p5x-x4-20261009.json new file mode 100644 index 000000000..a96dbecfa --- /dev/null +++ b/tools/ci/batches/1p5x-x4-20261009.json @@ -0,0 +1,24 @@ +{ + "run_id": "1p5x-x4-20261009", + "manifest_sha": "1a938abe4 (the frozen control); the forms on 1p5x-x4 b51d8c04b", + "evidence_dir": "docs/analysis/class-v6/1p5x/x4/README.md", + "boxes": [ + "build-9", + "runpod:fk-x4-4090" + ], + "cells": [ + { + "cell": "rows:1p5x-x4", + "status": "NOT RUN", + "evidence": "docs/analysis/class-v6/1p5x/x4/README.md", + "note": "X4 of the 1.5x programme: three byte-identical reg64c address-mix forms (direct, generated, prefix). Equivalence measured: CPU differential EQUIVALENT (rows/VERDICT; the known-failed form refused first) and GPU self-test plus fingerprint e8f4f3289c6ee1fc on all forms. GPU pairs: RTX 4090 at stock only, g 0.959 to 0.969 at equal rate, with an occupancy confound. Chip rows modelled: 10 to 52 nJ per hash for the cheapest form. Arithmetic from 2.0x: r_new 1.86 to 1.99. No pass claimed. NOT RUN by the brief's rule (rows stay NOT RUN until the steward's X6). The knee, the 5090 and the occupancy control are BLOCKED or NOT RUN (README section 6). Island: the 4090 rows are on an island, not a network." + } + ], + "method": "GPU", + "release_identity": { + "commit": "b51d8c04b (branch 1p5x-x4 off master a7f81d9a9)", + "binary": "igneum-pow ccb1bf0efebce4bb (build-9 release build of b51d8c04b); igneum-worker-cuda-gen6 804a6f7fea10a62e", + "network_object": "none (packs exported from the frozen object, program id 0x4de7b836cc40a4ea; no network)", + "activation": "none" + } +} diff --git a/tools/ci/export-exclude.txt b/tools/ci/export-exclude.txt index 33848ab1b..1b90fa934 100644 --- a/tools/ci/export-exclude.txt +++ b/tools/ci/export-exclude.txt @@ -52,3 +52,5 @@ docs/analysis/class-v6/reference-population.md docs/analysis/class-v6/eco-05-scenarios.md docs/analysis/class-v6/eco-05-results.md docs/analysis/proving-outcome-ledger.md +docs/analysis/class-v6/1p5x/x4 +tools/1p5x/x4 From 84a34569e71464d658fc3401317e1dfe54424dea Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:25:43 +0000 Subject: [PATCH 03/19] X4 (1.5x): the replicate 4090 session (g 0.960 / 0.959 / 0.969, A/A 0.15 percent) Co-Authored-By: Claude Opus 5.5 --- docs/analysis/class-v6/1p5x/x4/README.md | 16 ++- .../1p5x/x4/pod-s2/bench-01-hl-v6-all.log | 4 + .../1p5x/x4/pod-s2/bench-02-x4-direct.log | 4 + .../1p5x/x4/pod-s2/bench-03-x4-generated.log | 4 + .../1p5x/x4/pod-s2/bench-04-x4-prefix.log | 4 + .../1p5x/x4/pod-s2/bench-05-x4-prefix.log | 4 + .../1p5x/x4/pod-s2/bench-06-x4-generated.log | 4 + .../1p5x/x4/pod-s2/bench-07-x4-direct.log | 4 + .../1p5x/x4/pod-s2/bench-08-hl-v6-all.log | 4 + .../class-v6/1p5x/x4/pod-s2/out-run.log | 35 ++++++ .../1p5x/x4/pod-s2/smi-01-hl-v6-all.csv | 118 ++++++++++++++++++ .../1p5x/x4/pod-s2/smi-02-x4-direct.csv | 117 +++++++++++++++++ .../1p5x/x4/pod-s2/smi-03-x4-generated.csv | 117 +++++++++++++++++ .../1p5x/x4/pod-s2/smi-04-x4-prefix.csv | 118 ++++++++++++++++++ .../1p5x/x4/pod-s2/smi-05-x4-prefix.csv | 117 +++++++++++++++++ .../1p5x/x4/pod-s2/smi-06-x4-generated.csv | 117 +++++++++++++++++ .../1p5x/x4/pod-s2/smi-07-x4-direct.csv | 117 +++++++++++++++++ .../1p5x/x4/pod-s2/smi-08-hl-v6-all.csv | 118 ++++++++++++++++++ .../class-v6/1p5x/x4/rows/gpu-rows-s2.txt | 15 +++ 19 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-01-hl-v6-all.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-02-x4-direct.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-03-x4-generated.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-04-x4-prefix.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-05-x4-prefix.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-06-x4-generated.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-07-x4-direct.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/bench-08-hl-v6-all.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/out-run.log create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-01-hl-v6-all.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-02-x4-direct.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-03-x4-generated.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-04-x4-prefix.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-05-x4-prefix.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-06-x4-generated.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-07-x4-direct.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/pod-s2/smi-08-hl-v6-all.csv create mode 100644 docs/analysis/class-v6/1p5x/x4/rows/gpu-rows-s2.txt diff --git a/docs/analysis/class-v6/1p5x/x4/README.md b/docs/analysis/class-v6/1p5x/x4/README.md index 3399ccc07..cae8b982a 100644 --- a/docs/analysis/class-v6/1p5x/x4/README.md +++ b/docs/analysis/class-v6/1p5x/x4/README.md @@ -101,8 +101,20 @@ ratios. | generated | -0.08% / -3.82% | +0.01% / -4.38% | -0.04% / -4.10% | 0.959 | | prefix | -0.07% / -2.82% | -0.00% / -3.33% | -0.04% / -3.07% | 0.969 | -What the rows say: on the 4090 at stock, every form keeps the rate within 0.13 percent. Every form cuts board joules per -hash by 3 to 4 percent, about four times the A/A spread, in both passes. +Session 2 is the replicate: the same pod, 09:05:41Z to 09:25Z, the same order (`pod-s2/`, `rows/gpu-rows-s2.txt`). + +| Pair (session 2) | Mean rate | Mean J per hash | g | +|---|---|---|---| +| A/A: frozen run 8 against run 1 | +0.00% | +0.15% | (noise floor) | +| direct | -0.17% | -3.97% | 0.960 | +| generated | -0.08% | -4.08% | 0.959 | +| prefix | -0.20% | -3.11% | 0.969 | + +The two sessions agree to 0.001 in g on every form. Session 2's frozen runs read 35.081 MH/s at 8,172 and 8,184 nJ per +hash. + +What the rows say: on the 4090 at stock, every form keeps the rate within 0.2 percent. Every form cuts board joules per +hash by 3 to 4 percent, about four times the A/A spread (0.15 to 0.8 percent), in both passes of both sessions. The confound, open (BLOCKED row B2 below): nvcc gives the frozen fold 93 registers and 20 resident blocks per SM, and the alternatives 142 to 182 registers and 8 to 12 blocks. The kernel is memory-bound: the rate is equal at every diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-01-hl-v6-all.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-01-hl-v6-all.log new file mode 100644 index 000000000..79810f36f --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-01-hl-v6-all.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2347 cache 2 dataset 29 hot 0 check 1092 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 477.97 ms; 250 timed dispatches of 16777216 nonces: mean 478.24 ms +RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.081 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-02-x4-direct.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-02-x4-direct.log new file mode 100644 index 000000000..237dde173 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-02-x4-direct.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1626 cache 3 dataset 28 hot 0 check 1163 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 479.01 ms; 250 timed dispatches of 16777216 nonces: mean 479.05 ms +RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.022 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-03-x4-generated.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-03-x4-generated.log new file mode 100644 index 000000000..9a1ae7c49 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-03-x4-generated.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1479 cache 2 dataset 29 hot 0 check 1190 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.44 ms; 250 timed dispatches of 16777216 nonces: mean 478.59 ms +RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.055 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-04-x4-prefix.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-04-x4-prefix.log new file mode 100644 index 000000000..e0bf04a80 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-04-x4-prefix.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1676 cache 3 dataset 28 hot 0 check 1158 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.39 ms; 250 timed dispatches of 16777216 nonces: mean 479.74 ms +RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=34.971 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-05-x4-prefix.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-05-x4-prefix.log new file mode 100644 index 000000000..abf6781c5 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-05-x4-prefix.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1552 cache 2 dataset 29 hot 0 check 1183 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.53 ms; 250 timed dispatches of 16777216 nonces: mean 478.66 ms +RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.050 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-06-x4-generated.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-06-x4-generated.log new file mode 100644 index 000000000..b504d31fc --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-06-x4-generated.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1566 cache 2 dataset 29 hot 0 check 1652 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.47 ms; 250 timed dispatches of 16777216 nonces: mean 478.63 ms +RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-07-x4-direct.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-07-x4-direct.log new file mode 100644 index 000000000..40f96e719 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-07-x4-direct.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1454 cache 2 dataset 29 hot 0 check 1187 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 479.02 ms; 250 timed dispatches of 16777216 nonces: mean 479.05 ms +RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.022 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-08-hl-v6-all.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-08-hl-v6-all.log new file mode 100644 index 000000000..8d24ca312 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/bench-08-hl-v6-all.log @@ -0,0 +1,4 @@ +info igneum-worker-cuda 1.0 (4 October 2026): device 0 NVIDIA_GeForce_RTX_4090 (sm_89, 128 SMs), driver 13.2 from libcuda.so.1, NVRTC 12.8 from libnvrtc.so.12, target sm_89 (the device's architecture, listed by NVRTC) +pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2538 cache 2 dataset 29 hot 0 check 1105 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +warm-up dispatch (base 0): 478.21 ms; 250 timed dispatches of 16777216 nonces: mean 478.24 ms +RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.081 loads=256 bytes=1024 scratch_ops=0 time=wall diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/out-run.log b/docs/analysis/class-v6/1p5x/x4/pod-s2/out-run.log new file mode 100644 index 000000000..5cb5ca6b2 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/out-run.log @@ -0,0 +1,35 @@ +RESULT start 2026-10-09T09:05:41Z NVIDIA GeForce RTX 4090, 595.91.07, 450.00 W, 3105 MHz +RESULT worker sha256 804a6f7fea10a62e +RESULT run 01-hl-v6-all rc=0 secs=124 t0=1791536741 t1=1791536865 +BENCH 01-hl-v6-all | pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2347 cache 2 dataset 29 hot 0 check 1092 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 01-hl-v6-all | warm-up dispatch (base 0): 477.97 ms; 250 timed dispatches of 16777216 nonces: mean 478.24 ms +BENCH 01-hl-v6-all | RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.081 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 02-x4-direct rc=0 secs=124 t0=1791536885 t1=1791537009 +BENCH 02-x4-direct | pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1626 cache 3 dataset 28 hot 0 check 1163 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 02-x4-direct | warm-up dispatch (base 0): 479.01 ms; 250 timed dispatches of 16777216 nonces: mean 479.05 ms +BENCH 02-x4-direct | RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.022 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 03-x4-generated rc=0 secs=123 t0=1791537029 t1=1791537152 +BENCH 03-x4-generated | pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1479 cache 2 dataset 29 hot 0 check 1190 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 03-x4-generated | warm-up dispatch (base 0): 478.44 ms; 250 timed dispatches of 16777216 nonces: mean 478.59 ms +BENCH 03-x4-generated | RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.055 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 04-x4-prefix rc=0 secs=124 t0=1791537172 t1=1791537296 +BENCH 04-x4-prefix | pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1676 cache 3 dataset 28 hot 0 check 1158 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 04-x4-prefix | warm-up dispatch (base 0): 478.39 ms; 250 timed dispatches of 16777216 nonces: mean 479.74 ms +BENCH 04-x4-prefix | RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=34.971 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 05-x4-prefix rc=0 secs=124 t0=1791537316 t1=1791537440 +BENCH 05-x4-prefix | pack packs/x4-prefix on NVIDIA_GeForce_RTX_4090: nvrtc 1552 cache 2 dataset 29 hot 0 check 1183 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 05-x4-prefix | warm-up dispatch (base 0): 478.53 ms; 250 timed dispatches of 16777216 nonces: mean 478.66 ms +BENCH 05-x4-prefix | RESULT pack=packs/x4-prefix class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=154 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.050 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 06-x4-generated rc=0 secs=124 t0=1791537460 t1=1791537584 +BENCH 06-x4-generated | pack packs/x4-generated on NVIDIA_GeForce_RTX_4090: nvrtc 1566 cache 2 dataset 29 hot 0 check 1652 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 06-x4-generated | warm-up dispatch (base 0): 478.47 ms; 250 timed dispatches of 16777216 nonces: mean 478.63 ms +BENCH 06-x4-generated | RESULT pack=packs/x4-generated class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=142 blocks_per_sm=12 warps=0 resident=1536 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.053 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 07-x4-direct rc=0 secs=123 t0=1791537604 t1=1791537727 +BENCH 07-x4-direct | pack packs/x4-direct on NVIDIA_GeForce_RTX_4090: nvrtc 1454 cache 2 dataset 29 hot 0 check 1187 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 07-x4-direct | warm-up dispatch (base 0): 479.02 ms; 250 timed dispatches of 16777216 nonces: mean 479.05 ms +BENCH 07-x4-direct | RESULT pack=packs/x4-direct class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=182 blocks_per_sm=8 warps=0 resident=1024 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.022 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT run 08-hl-v6-all rc=0 secs=125 t0=1791537747 t1=1791537872 +BENCH 08-hl-v6-all | pack packs/hl-v6-all on NVIDIA_GeForce_RTX_4090: nvrtc 2538 cache 2 dataset 29 hot 0 check 1105 race 0 ms variant base class v6 (state leaves 93, uploaded for the build and freed); self-test PASS (cache head, last line and FNV-1a 64 448274a57f508cbc; dataset head, word [268435455] and 64 samples; 96 of 96 vector lanes) +BENCH 08-hl-v6-all | warm-up dispatch (base 0): 478.21 ms; 250 timed dispatches of 16777216 nonces: mean 478.24 ms +BENCH 08-hl-v6-all | RESULT pack=packs/hl-v6-all class=mx8-erad810f22d+sh256x27+state+reg64c+fold+rw device=NVIDIA_GeForce_RTX_4090 arch=sm_89 regs=93 blocks_per_sm=20 warps=0 resident=2560 arena_mib=0 hot_mib=0 hot_slots=0 hot_fill_ms=0.00 nonces=16777216 batches=250 check=PASS fingerprint=e8f4f3289c6ee1fc mhs=35.081 loads=256 bytes=1024 scratch_ops=0 time=wall +RESULT end 2026-10-09T09:24:52Z diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-01-hl-v6-all.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-01-hl-v6-all.csv new file mode 100644 index 000000000..3c63cd089 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-01-hl-v6-all.csv @@ -0,0 +1,118 @@ +1791536741,27.54,210,0,26 +1791536742,56.07,2520,0,27 +1791536743,82.60,2520,0,27 +1791536744,85.62,2520,11,28 +1791536745,90.67,2520,57,27 +1791536746,251.28,2655,100,34 +1791536747,281.96,2685,100,35 +1791536748,282.36,2685,100,35 +1791536749,282.45,2685,100,35 +1791536750,282.71,2685,100,36 +1791536751,282.52,2685,100,36 +1791536752,282.61,2685,100,36 +1791536753,282.40,2685,100,37 +1791536754,282.54,2685,100,37 +1791536756,282.72,2685,100,37 +1791536757,283.36,2685,100,38 +1791536758,283.44,2685,100,38 +1791536759,283.25,2685,100,38 +1791536760,283.73,2685,100,38 +1791536761,284.11,2685,100,38 +1791536762,284.14,2685,100,39 +1791536763,284.19,2685,100,39 +1791536764,284.22,2685,100,39 +1791536765,284.22,2685,100,39 +1791536766,284.55,2685,100,40 +1791536767,284.48,2685,100,40 +1791536768,284.77,2685,100,40 +1791536769,284.98,2685,100,40 +1791536770,284.96,2685,100,40 +1791536771,284.94,2685,100,40 +1791536772,285.17,2685,100,41 +1791536773,285.14,2685,100,41 +1791536775,284.91,2685,100,41 +1791536776,285.24,2685,100,41 +1791536777,285.16,2685,100,41 +1791536778,285.23,2685,100,41 +1791536779,285.40,2685,100,41 +1791536780,285.35,2685,100,42 +1791536781,285.25,2685,100,42 +1791536782,285.20,2685,100,42 +1791536783,285.48,2685,100,42 +1791536784,285.70,2685,100,42 +1791536785,286.04,2685,100,42 +1791536786,286.20,2685,100,42 +1791536787,286.10,2685,100,42 +1791536788,286.15,2685,100,43 +1791536789,285.95,2685,100,43 +1791536790,286.59,2685,100,43 +1791536791,286.56,2685,100,43 +1791536793,286.33,2685,100,43 +1791536794,286.56,2685,100,43 +1791536795,286.70,2685,100,43 +1791536796,286.51,2685,100,43 +1791536797,286.30,2685,100,43 +1791536798,286.80,2685,100,43 +1791536799,286.39,2685,100,43 +1791536800,286.27,2685,100,44 +1791536801,286.57,2685,100,44 +1791536802,286.67,2685,100,44 +1791536803,286.65,2685,100,44 +1791536804,286.59,2685,100,44 +1791536805,286.91,2685,100,44 +1791536806,286.94,2685,100,44 +1791536807,286.84,2685,100,44 +1791536808,286.92,2685,100,44 +1791536810,287.06,2670,100,44 +1791536811,287.07,2670,100,44 +1791536812,287.24,2670,100,44 +1791536813,287.26,2670,100,44 +1791536814,287.13,2670,100,44 +1791536815,287.39,2670,100,45 +1791536816,287.57,2670,100,45 +1791536817,287.45,2670,100,45 +1791536818,287.37,2670,100,45 +1791536819,287.87,2670,100,45 +1791536820,287.90,2670,100,45 +1791536821,287.97,2670,100,45 +1791536822,287.47,2670,100,45 +1791536823,287.40,2670,100,45 +1791536824,287.09,2670,100,45 +1791536825,287.00,2670,100,45 +1791536827,287.51,2670,100,45 +1791536828,288.05,2670,100,45 +1791536829,288.44,2670,100,45 +1791536830,288.36,2670,100,45 +1791536831,288.67,2670,100,45 +1791536832,288.64,2670,100,45 +1791536833,288.62,2670,100,45 +1791536834,288.22,2670,100,45 +1791536835,288.23,2670,100,46 +1791536836,288.16,2670,100,46 +1791536837,288.39,2670,100,46 +1791536838,288.55,2670,100,46 +1791536839,288.68,2670,100,46 +1791536840,288.95,2670,100,46 +1791536841,289.35,2670,100,46 +1791536842,288.96,2670,100,46 +1791536843,288.62,2670,100,46 +1791536845,288.23,2670,100,46 +1791536846,288.88,2670,100,46 +1791536847,289.12,2670,100,46 +1791536848,289.02,2670,100,46 +1791536849,289.05,2670,100,46 +1791536850,289.06,2670,100,46 +1791536851,288.89,2670,100,46 +1791536852,288.90,2670,100,46 +1791536853,288.96,2670,100,46 +1791536854,288.76,2670,100,46 +1791536855,288.70,2670,100,46 +1791536856,288.69,2670,100,46 +1791536857,288.75,2670,100,46 +1791536858,288.92,2670,100,46 +1791536859,288.92,2670,100,46 +1791536860,288.77,2670,100,46 +1791536862,289.04,2670,100,46 +1791536863,289.11,2670,100,46 +1791536864,289.12,2670,100,46 +1791536865,288.96,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-02-x4-direct.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-02-x4-direct.csv new file mode 100644 index 000000000..95242f9df --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-02-x4-direct.csv @@ -0,0 +1,117 @@ +1791536885,28.32,210,0,33 +1791536886,45.95,2520,0,33 +1791536887,81.58,2520,0,33 +1791536888,92.40,2520,1,35 +1791536889,236.97,2685,100,39 +1791536890,271.90,2685,100,39 +1791536891,272.15,2685,100,39 +1791536892,272.65,2685,100,40 +1791536893,272.92,2685,100,40 +1791536894,272.83,2685,100,40 +1791536895,273.21,2685,100,40 +1791536897,273.50,2685,100,41 +1791536898,273.73,2685,100,41 +1791536899,274.07,2685,100,41 +1791536900,274.05,2685,100,41 +1791536902,274.03,2685,100,41 +1791536903,273.95,2685,100,41 +1791536904,273.79,2685,100,41 +1791536905,273.93,2685,100,42 +1791536906,273.85,2685,100,42 +1791536907,273.32,2685,100,42 +1791536908,273.64,2685,100,42 +1791536909,273.77,2685,100,42 +1791536910,274.04,2685,100,42 +1791536911,273.89,2685,100,42 +1791536912,273.93,2685,100,42 +1791536913,273.90,2685,100,42 +1791536914,274.49,2685,100,42 +1791536915,274.20,2685,100,42 +1791536916,274.49,2685,100,43 +1791536918,274.60,2685,100,43 +1791536919,274.71,2685,100,43 +1791536920,274.73,2685,100,43 +1791536921,274.92,2685,100,43 +1791536922,274.90,2685,100,43 +1791536923,274.51,2685,100,43 +1791536924,274.92,2685,100,43 +1791536925,275.17,2685,100,43 +1791536926,275.02,2685,100,43 +1791536927,274.99,2685,100,43 +1791536928,274.83,2685,100,43 +1791536929,275.14,2685,100,43 +1791536930,275.21,2685,100,44 +1791536931,274.90,2685,100,44 +1791536932,275.20,2685,100,44 +1791536933,274.90,2685,100,44 +1791536934,275.14,2685,100,44 +1791536935,275.32,2685,100,44 +1791536937,275.12,2685,100,44 +1791536938,275.21,2685,100,44 +1791536939,275.60,2685,100,44 +1791536940,275.48,2685,100,44 +1791536941,275.73,2685,100,44 +1791536942,275.49,2685,100,44 +1791536943,275.42,2685,100,44 +1791536944,275.24,2670,100,44 +1791536945,275.29,2670,100,44 +1791536946,274.87,2670,100,44 +1791536947,275.12,2670,100,44 +1791536948,275.17,2670,100,44 +1791536949,275.04,2670,100,44 +1791536950,275.22,2670,100,44 +1791536951,275.48,2670,100,44 +1791536952,275.39,2670,100,44 +1791536953,275.36,2670,100,45 +1791536954,275.43,2670,100,45 +1791536956,275.14,2670,100,45 +1791536957,275.07,2670,100,45 +1791536958,275.15,2670,100,45 +1791536959,274.97,2670,100,45 +1791536960,274.90,2670,100,45 +1791536961,275.13,2670,100,45 +1791536962,275.48,2670,100,45 +1791536963,275.73,2670,100,45 +1791536964,275.68,2670,100,45 +1791536965,275.81,2670,100,45 +1791536966,275.70,2670,100,45 +1791536967,276.07,2670,100,45 +1791536968,276.11,2670,100,45 +1791536969,275.77,2670,100,45 +1791536970,275.46,2670,100,45 +1791536971,276.10,2670,100,45 +1791536972,275.91,2670,100,45 +1791536974,275.78,2670,100,45 +1791536975,275.83,2670,100,45 +1791536976,276.08,2670,100,45 +1791536977,275.75,2670,100,45 +1791536978,275.88,2670,100,45 +1791536979,276.15,2670,100,45 +1791536980,276.06,2670,100,45 +1791536981,276.06,2670,100,45 +1791536982,276.08,2670,100,45 +1791536983,275.98,2670,100,45 +1791536984,275.48,2670,99,45 +1791536985,275.74,2670,100,45 +1791536986,276.10,2670,100,45 +1791536987,275.86,2670,100,45 +1791536988,275.90,2670,100,45 +1791536989,275.91,2670,100,45 +1791536990,275.75,2670,100,45 +1791536991,275.67,2670,100,45 +1791536993,275.41,2670,100,45 +1791536994,275.77,2670,100,45 +1791536995,275.87,2670,100,45 +1791536996,275.66,2670,100,45 +1791536997,275.86,2670,100,45 +1791536998,275.86,2670,100,45 +1791536999,275.53,2670,100,46 +1791537000,275.66,2670,100,46 +1791537001,276.23,2670,100,46 +1791537002,276.32,2670,100,46 +1791537003,276.15,2670,100,46 +1791537004,276.25,2670,100,46 +1791537005,276.30,2670,100,46 +1791537006,276.02,2670,100,46 +1791537007,276.08,2670,100,46 +1791537008,276.01,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-03-x4-generated.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-03-x4-generated.csv new file mode 100644 index 000000000..87de8c358 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-03-x4-generated.csv @@ -0,0 +1,117 @@ +1791537029,27.66,210,0,33 +1791537030,49.07,2520,0,33 +1791537031,85.97,2520,5,34 +1791537032,81.32,2520,0,33 +1791537033,203.31,2685,100,39 +1791537034,272.00,2685,100,39 +1791537035,272.31,2685,100,40 +1791537036,272.09,2685,100,40 +1791537037,272.53,2685,100,40 +1791537038,272.13,2685,100,40 +1791537039,272.68,2685,100,41 +1791537040,272.79,2685,100,41 +1791537041,272.94,2685,100,41 +1791537042,273.07,2685,100,41 +1791537043,273.10,2685,100,41 +1791537045,273.07,2685,100,41 +1791537046,273.30,2685,100,42 +1791537047,273.49,2685,100,42 +1791537048,273.49,2685,100,42 +1791537049,273.74,2685,100,42 +1791537050,273.77,2685,99,42 +1791537051,273.86,2685,100,42 +1791537052,273.77,2685,100,42 +1791537053,273.90,2685,100,42 +1791537054,274.03,2685,100,42 +1791537055,273.97,2685,100,43 +1791537056,274.10,2685,100,43 +1791537057,273.77,2685,100,43 +1791537058,273.93,2685,100,43 +1791537059,274.38,2685,100,43 +1791537060,274.26,2685,100,43 +1791537061,274.35,2685,100,43 +1791537062,274.69,2685,100,43 +1791537064,274.33,2685,100,43 +1791537065,274.71,2685,100,43 +1791537066,275.16,2685,100,43 +1791537067,275.14,2685,100,43 +1791537068,275.09,2685,100,43 +1791537069,274.91,2685,100,44 +1791537070,275.14,2685,100,44 +1791537071,274.98,2685,100,44 +1791537072,275.21,2685,100,44 +1791537073,275.32,2685,100,44 +1791537074,275.83,2685,100,44 +1791537075,275.63,2685,100,44 +1791537076,275.89,2685,100,44 +1791537077,275.54,2685,100,44 +1791537078,275.65,2670,100,44 +1791537079,275.15,2670,100,44 +1791537081,275.23,2670,100,44 +1791537082,275.42,2670,100,44 +1791537083,275.24,2670,100,44 +1791537084,274.85,2670,100,44 +1791537085,274.88,2670,100,44 +1791537086,274.88,2670,100,44 +1791537087,275.05,2670,100,44 +1791537088,275.16,2670,100,44 +1791537089,275.00,2670,100,44 +1791537090,275.00,2670,100,45 +1791537091,275.17,2670,100,45 +1791537092,274.95,2670,100,45 +1791537093,274.98,2670,100,45 +1791537094,275.10,2670,100,45 +1791537095,274.61,2670,100,45 +1791537096,274.99,2670,100,45 +1791537097,275.37,2670,100,45 +1791537099,275.49,2670,100,45 +1791537100,275.48,2670,100,45 +1791537101,275.46,2670,100,45 +1791537102,275.20,2670,100,45 +1791537103,275.04,2670,100,45 +1791537104,275.05,2670,100,45 +1791537105,274.96,2670,100,45 +1791537106,275.33,2670,100,45 +1791537107,275.64,2670,100,45 +1791537108,275.24,2670,100,45 +1791537109,275.51,2670,100,45 +1791537110,275.32,2670,100,45 +1791537111,275.23,2670,100,45 +1791537112,275.09,2670,100,45 +1791537113,274.94,2670,100,45 +1791537114,275.56,2670,100,45 +1791537116,275.22,2670,100,45 +1791537117,275.43,2670,100,45 +1791537118,275.17,2670,100,45 +1791537119,275.43,2670,100,45 +1791537120,275.65,2670,100,45 +1791537121,275.96,2670,100,45 +1791537122,276.02,2670,100,45 +1791537123,276.05,2670,100,45 +1791537124,276.19,2670,100,45 +1791537125,276.01,2670,100,45 +1791537126,275.80,2670,100,45 +1791537127,276.15,2670,100,45 +1791537128,275.88,2670,100,45 +1791537129,275.86,2670,100,46 +1791537130,275.82,2670,100,46 +1791537131,276.18,2670,100,46 +1791537133,276.09,2670,100,46 +1791537134,276.21,2670,100,46 +1791537135,276.31,2670,100,46 +1791537136,275.97,2670,100,46 +1791537137,276.20,2670,100,46 +1791537138,276.17,2670,100,46 +1791537139,276.55,2670,100,46 +1791537140,276.47,2670,100,46 +1791537141,276.25,2670,100,46 +1791537142,276.45,2670,100,46 +1791537143,276.54,2670,100,46 +1791537144,276.25,2670,100,46 +1791537145,276.14,2670,100,46 +1791537146,275.65,2670,100,46 +1791537147,275.82,2670,100,46 +1791537148,275.87,2670,100,46 +1791537150,275.84,2670,99,46 +1791537151,275.64,2670,100,46 +1791537152,275.50,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-04-x4-prefix.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-04-x4-prefix.csv new file mode 100644 index 000000000..d3714c5c8 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-04-x4-prefix.csv @@ -0,0 +1,118 @@ +1791537172,27.55,210,0,33 +1791537173,49.83,2520,0,34 +1791537174,85.09,2520,71,34 +1791537175,86.21,2520,0,33 +1791537176,176.96,2685,100,38 +1791537177,273.90,2685,100,40 +1791537178,274.80,2685,100,40 +1791537180,275.31,2685,100,40 +1791537181,251.76,2685,100,40 +1791537182,275.78,2685,100,41 +1791537183,275.75,2685,100,41 +1791537184,275.88,2685,100,41 +1791537185,276.04,2685,100,41 +1791537186,276.14,2685,100,41 +1791537187,276.04,2685,100,41 +1791537188,276.39,2685,100,42 +1791537189,276.51,2685,100,42 +1791537190,276.10,2685,100,42 +1791537191,276.01,2685,100,42 +1791537192,276.19,2685,100,42 +1791537193,276.18,2685,100,42 +1791537194,276.23,2685,100,42 +1791537195,275.99,2685,100,42 +1791537196,275.65,2685,100,43 +1791537197,276.30,2685,100,43 +1791537199,276.45,2685,100,43 +1791537200,276.75,2685,100,43 +1791537201,276.50,2685,100,43 +1791537202,276.57,2685,100,43 +1791537203,276.60,2685,100,43 +1791537204,276.50,2685,100,43 +1791537205,276.72,2685,100,43 +1791537206,276.79,2685,100,43 +1791537207,276.95,2685,100,43 +1791537208,276.75,2685,100,43 +1791537209,276.63,2685,100,44 +1791537210,276.71,2685,100,44 +1791537211,276.93,2685,100,44 +1791537212,276.96,2685,100,44 +1791537213,277.20,2685,100,44 +1791537214,277.07,2685,100,44 +1791537215,277.02,2670,100,44 +1791537216,277.23,2670,100,44 +1791537217,276.90,2670,100,44 +1791537218,277.42,2670,100,44 +1791537220,277.38,2670,100,44 +1791537221,277.29,2670,100,44 +1791537222,277.39,2670,100,44 +1791537223,277.32,2670,100,44 +1791537224,277.05,2670,100,44 +1791537225,276.94,2670,100,44 +1791537226,277.20,2670,100,45 +1791537227,277.11,2670,100,45 +1791537228,277.12,2670,100,45 +1791537229,277.30,2670,100,45 +1791537230,277.46,2670,100,45 +1791537231,277.33,2670,100,45 +1791537232,277.62,2670,100,45 +1791537233,277.38,2670,100,45 +1791537234,277.40,2670,100,45 +1791537235,277.39,2670,100,45 +1791537236,277.69,2670,100,45 +1791537238,277.74,2670,100,45 +1791537239,277.82,2670,100,45 +1791537240,277.68,2670,100,45 +1791537241,277.54,2670,100,45 +1791537242,277.77,2670,100,45 +1791537243,277.42,2670,100,45 +1791537244,277.49,2670,100,45 +1791537245,277.50,2670,100,45 +1791537246,277.93,2670,100,45 +1791537247,277.96,2670,100,45 +1791537248,277.77,2670,100,45 +1791537249,277.73,2670,100,45 +1791537250,278.01,2670,100,45 +1791537251,278.07,2670,100,45 +1791537252,277.63,2670,100,45 +1791537253,277.54,2670,100,45 +1791537254,277.78,2670,100,45 +1791537255,277.58,2670,100,45 +1791537257,277.66,2670,100,45 +1791537258,277.74,2670,100,46 +1791537259,277.60,2670,100,46 +1791537260,277.61,2670,100,46 +1791537261,277.58,2670,100,46 +1791537262,277.83,2670,100,46 +1791537263,277.81,2670,100,46 +1791537264,277.81,2670,100,46 +1791537265,277.90,2670,100,46 +1791537266,278.02,2670,100,46 +1791537267,278.03,2670,100,46 +1791537268,277.99,2670,100,46 +1791537269,277.90,2670,100,46 +1791537270,277.93,2670,100,46 +1791537271,278.03,2670,100,46 +1791537272,278.14,2670,100,46 +1791537273,278.04,2670,100,46 +1791537275,278.23,2670,100,46 +1791537276,278.15,2670,100,46 +1791537277,278.39,2670,100,46 +1791537278,278.79,2670,100,46 +1791537279,278.81,2670,100,46 +1791537280,279.02,2670,100,46 +1791537281,278.82,2670,100,46 +1791537282,278.50,2670,100,46 +1791537283,278.51,2670,100,46 +1791537284,278.43,2670,100,46 +1791537285,278.59,2670,100,46 +1791537286,278.35,2670,100,46 +1791537287,278.38,2670,100,46 +1791537288,278.77,2670,100,46 +1791537289,278.72,2670,100,46 +1791537290,278.69,2670,100,46 +1791537292,278.47,2670,100,46 +1791537293,278.36,2670,100,46 +1791537294,278.64,2670,100,46 +1791537295,278.44,2670,100,46 +1791537296,278.32,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-05-x4-prefix.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-05-x4-prefix.csv new file mode 100644 index 000000000..008624d06 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-05-x4-prefix.csv @@ -0,0 +1,117 @@ +1791537316,27.58,210,0,33 +1791537317,39.70,2520,0,34 +1791537318,86.60,2520,17,34 +1791537319,80.95,2520,1,34 +1791537320,205.81,2685,100,39 +1791537321,274.61,2685,100,40 +1791537322,274.92,2685,100,40 +1791537324,275.11,2685,100,40 +1791537325,275.49,2685,100,41 +1791537326,275.89,2685,100,41 +1791537327,275.90,2685,100,41 +1791537328,275.99,2685,100,41 +1791537329,276.30,2685,100,41 +1791537330,276.09,2685,100,41 +1791537331,276.41,2685,100,42 +1791537332,276.95,2685,100,42 +1791537333,276.94,2685,100,42 +1791537334,276.71,2685,100,42 +1791537335,276.70,2685,100,42 +1791537336,276.50,2685,100,42 +1791537337,276.80,2685,100,42 +1791537338,276.93,2685,100,42 +1791537339,276.93,2685,100,43 +1791537340,276.72,2685,100,43 +1791537341,276.92,2685,100,43 +1791537343,277.05,2685,100,43 +1791537344,277.20,2685,100,43 +1791537345,277.20,2685,100,43 +1791537346,277.04,2685,100,43 +1791537347,276.66,2685,100,43 +1791537348,277.09,2685,100,43 +1791537349,277.14,2685,100,43 +1791537350,276.90,2685,100,43 +1791537351,277.09,2685,100,43 +1791537352,277.24,2685,100,44 +1791537353,277.51,2685,100,44 +1791537354,277.56,2685,100,44 +1791537355,277.63,2685,100,44 +1791537356,277.40,2685,100,44 +1791537357,277.61,2685,100,44 +1791537358,277.57,2670,100,44 +1791537359,277.49,2670,100,44 +1791537361,277.69,2670,100,44 +1791537362,277.84,2670,100,44 +1791537363,277.68,2670,100,44 +1791537364,277.75,2670,100,44 +1791537365,277.51,2670,100,44 +1791537366,277.55,2670,100,44 +1791537367,278.13,2670,100,44 +1791537368,278.24,2670,100,44 +1791537369,278.02,2670,100,44 +1791537370,277.86,2670,100,44 +1791537371,277.76,2670,100,45 +1791537372,277.91,2670,100,45 +1791537373,277.75,2670,100,45 +1791537374,277.59,2670,100,45 +1791537375,277.47,2670,100,45 +1791537376,277.33,2670,100,45 +1791537377,277.59,2670,100,45 +1791537378,277.71,2670,100,45 +1791537380,277.94,2670,100,45 +1791537381,277.90,2670,100,45 +1791537382,278.12,2670,100,45 +1791537383,277.92,2670,100,45 +1791537384,277.86,2670,100,45 +1791537385,278.00,2670,100,45 +1791537386,278.04,2670,100,45 +1791537387,277.95,2670,100,45 +1791537388,277.85,2670,100,45 +1791537389,277.88,2670,100,45 +1791537390,277.84,2670,100,45 +1791537391,278.05,2670,100,45 +1791537392,278.12,2670,100,45 +1791537393,277.99,2670,100,45 +1791537394,277.53,2670,100,45 +1791537395,277.46,2670,100,45 +1791537396,277.26,2670,100,45 +1791537397,278.12,2670,100,45 +1791537399,277.80,2670,100,45 +1791537400,278.03,2670,100,45 +1791537401,278.02,2670,100,45 +1791537402,278.27,2670,100,45 +1791537403,278.34,2670,100,45 +1791537404,278.03,2670,100,45 +1791537405,277.64,2670,96,45 +1791537406,277.62,2670,100,45 +1791537407,278.54,2670,100,45 +1791537408,277.84,2670,100,45 +1791537409,278.21,2670,100,46 +1791537410,277.92,2670,100,46 +1791537411,277.84,2670,100,46 +1791537412,278.15,2670,100,46 +1791537413,278.53,2670,100,46 +1791537414,278.28,2670,100,46 +1791537415,278.30,2670,100,46 +1791537416,278.34,2670,100,46 +1791537417,278.46,2670,100,46 +1791537419,278.55,2670,100,46 +1791537420,278.02,2670,100,46 +1791537421,278.13,2670,100,46 +1791537422,278.29,2670,100,46 +1791537423,278.64,2670,100,46 +1791537424,278.41,2670,100,46 +1791537425,278.55,2670,100,46 +1791537426,278.51,2670,100,46 +1791537427,278.23,2670,100,46 +1791537428,278.15,2670,100,46 +1791537429,278.11,2670,100,46 +1791537430,277.91,2670,100,46 +1791537431,278.18,2670,100,46 +1791537432,278.55,2670,100,46 +1791537433,278.61,2670,100,46 +1791537434,278.94,2670,100,46 +1791537436,278.91,2670,100,46 +1791537437,278.68,2670,100,46 +1791537438,278.70,2670,100,46 +1791537439,278.99,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-06-x4-generated.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-06-x4-generated.csv new file mode 100644 index 000000000..c0bf74a6e --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-06-x4-generated.csv @@ -0,0 +1,117 @@ +1791537460,27.78,210,0,33 +1791537461,49.56,2520,0,34 +1791537462,86.83,2520,43,34 +1791537463,86.76,2520,0,33 +1791537464,128.93,2685,100,38 +1791537465,271.06,2685,100,39 +1791537466,272.26,2685,100,40 +1791537467,272.39,2685,100,40 +1791537468,272.47,2685,100,40 +1791537469,272.55,2685,100,40 +1791537470,273.35,2685,100,40 +1791537472,273.18,2685,100,41 +1791537473,272.39,2685,100,41 +1791537474,273.84,2685,100,41 +1791537475,273.62,2685,99,41 +1791537476,273.85,2685,100,41 +1791537477,273.70,2685,100,41 +1791537478,273.80,2685,100,41 +1791537479,273.46,2685,100,42 +1791537480,273.37,2685,100,42 +1791537481,273.42,2685,100,42 +1791537482,273.84,2685,100,42 +1791537483,274.07,2685,100,42 +1791537484,274.21,2685,100,42 +1791537485,274.43,2685,100,42 +1791537486,274.73,2685,100,42 +1791537487,274.43,2685,100,42 +1791537488,274.43,2685,100,43 +1791537489,274.33,2685,100,43 +1791537490,273.98,2685,100,43 +1791537492,274.48,2685,100,43 +1791537493,274.78,2685,100,43 +1791537494,274.71,2685,100,43 +1791537495,274.56,2685,100,43 +1791537496,274.80,2685,100,43 +1791537497,274.70,2685,100,43 +1791537498,274.75,2685,100,43 +1791537499,274.66,2685,100,43 +1791537500,274.46,2685,100,43 +1791537501,274.53,2685,100,43 +1791537502,274.48,2685,100,43 +1791537503,274.67,2685,100,44 +1791537504,274.49,2685,100,44 +1791537505,274.22,2685,100,44 +1791537506,274.42,2685,100,44 +1791537507,274.69,2685,100,44 +1791537509,274.79,2685,100,44 +1791537510,274.49,2685,100,44 +1791537511,274.48,2670,100,44 +1791537512,274.73,2670,100,44 +1791537513,274.59,2670,100,44 +1791537514,274.79,2670,100,44 +1791537515,274.33,2670,100,44 +1791537516,274.62,2670,100,44 +1791537517,274.60,2670,100,44 +1791537518,274.78,2670,100,44 +1791537519,274.37,2670,97,44 +1791537520,274.47,2670,100,44 +1791537521,274.94,2670,100,44 +1791537522,275.42,2670,100,44 +1791537523,275.34,2670,100,44 +1791537524,275.12,2670,100,44 +1791537525,275.26,2670,100,44 +1791537526,275.38,2670,100,45 +1791537528,275.47,2670,100,45 +1791537529,275.05,2670,100,44 +1791537530,275.18,2670,100,45 +1791537531,275.41,2670,100,45 +1791537532,275.73,2670,100,45 +1791537533,275.77,2670,100,45 +1791537534,275.38,2670,100,45 +1791537535,275.20,2670,100,45 +1791537536,275.27,2670,100,45 +1791537537,275.29,2670,100,45 +1791537538,275.40,2670,100,45 +1791537539,274.98,2670,100,45 +1791537540,275.19,2670,100,45 +1791537541,275.27,2670,100,45 +1791537542,275.15,2670,100,45 +1791537543,275.28,2670,100,45 +1791537545,275.53,2670,100,45 +1791537546,275.58,2670,100,45 +1791537547,275.81,2670,100,45 +1791537548,275.49,2670,100,45 +1791537549,275.24,2670,100,45 +1791537550,275.24,2670,100,45 +1791537551,275.51,2670,100,45 +1791537552,275.41,2670,100,45 +1791537553,275.43,2670,100,45 +1791537554,275.48,2670,100,45 +1791537555,275.57,2670,100,45 +1791537556,275.73,2670,100,45 +1791537557,276.05,2670,100,45 +1791537558,275.66,2670,100,45 +1791537559,275.39,2670,100,45 +1791537560,275.60,2670,100,45 +1791537562,275.39,2670,100,45 +1791537563,275.62,2670,100,45 +1791537564,275.68,2670,100,45 +1791537565,275.84,2670,100,45 +1791537566,275.54,2670,100,45 +1791537567,275.51,2670,100,45 +1791537568,275.70,2670,100,45 +1791537569,275.59,2670,100,45 +1791537570,274.98,2670,100,45 +1791537571,275.85,2670,100,45 +1791537572,276.00,2670,100,45 +1791537573,275.61,2670,100,45 +1791537574,275.47,2670,100,45 +1791537575,275.48,2670,100,45 +1791537576,275.54,2670,100,45 +1791537577,275.87,2670,100,45 +1791537579,275.84,2670,100,45 +1791537580,275.49,2670,100,45 +1791537581,275.34,2670,100,46 +1791537582,275.41,2670,100,46 +1791537583,275.46,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-07-x4-direct.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-07-x4-direct.csv new file mode 100644 index 000000000..7ef39f6a2 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-07-x4-direct.csv @@ -0,0 +1,117 @@ +1791537604,27.51,210,0,33 +1791537605,47.95,2520,0,33 +1791537606,86.03,2520,0,34 +1791537607,81.64,2520,0,33 +1791537608,192.44,2685,100,38 +1791537609,271.61,2685,100,39 +1791537610,271.80,2685,100,40 +1791537611,271.72,2685,100,40 +1791537612,272.13,2685,100,40 +1791537613,272.34,2685,100,40 +1791537615,272.41,2685,100,40 +1791537616,272.02,2685,100,41 +1791537617,271.95,2685,100,41 +1791537618,272.37,2685,100,41 +1791537619,272.10,2685,100,41 +1791537620,272.14,2685,100,41 +1791537621,272.49,2685,100,41 +1791537622,272.52,2685,100,41 +1791537623,272.54,2685,100,42 +1791537624,272.59,2685,100,42 +1791537625,273.15,2685,100,42 +1791537626,273.42,2685,100,42 +1791537627,273.12,2685,100,42 +1791537628,273.47,2685,100,42 +1791537629,273.56,2685,100,42 +1791537630,273.83,2685,100,42 +1791537632,273.72,2685,100,42 +1791537633,274.03,2685,100,43 +1791537634,274.26,2685,100,43 +1791537635,273.67,2685,100,43 +1791537636,273.82,2685,100,43 +1791537637,273.91,2685,100,43 +1791537638,274.09,2685,100,43 +1791537639,274.06,2685,100,43 +1791537640,274.09,2685,100,43 +1791537641,274.11,2685,100,43 +1791537642,273.97,2685,100,43 +1791537643,274.58,2685,100,43 +1791537644,274.49,2685,100,43 +1791537645,274.88,2685,100,43 +1791537646,275.07,2685,100,43 +1791537647,275.20,2685,100,44 +1791537649,275.51,2685,100,44 +1791537650,275.23,2685,100,44 +1791537651,275.10,2685,100,44 +1791537652,275.18,2685,100,44 +1791537653,275.02,2685,100,44 +1791537654,275.15,2670,100,44 +1791537655,274.88,2670,100,44 +1791537656,275.16,2670,100,44 +1791537657,275.14,2670,100,44 +1791537658,275.09,2670,100,44 +1791537659,274.88,2670,100,44 +1791537660,274.87,2670,100,44 +1791537661,275.16,2670,100,44 +1791537662,275.24,2670,100,44 +1791537663,274.98,2670,100,44 +1791537664,274.68,2670,100,44 +1791537666,274.64,2670,100,44 +1791537667,275.03,2670,100,44 +1791537668,275.03,2670,100,44 +1791537669,274.77,2670,100,44 +1791537670,274.99,2670,100,45 +1791537671,275.12,2670,100,45 +1791537672,275.27,2670,100,45 +1791537673,275.44,2670,100,45 +1791537674,275.14,2670,100,45 +1791537675,275.09,2670,100,45 +1791537676,275.39,2670,100,45 +1791537677,275.51,2670,100,45 +1791537678,275.53,2670,100,45 +1791537679,275.66,2670,100,45 +1791537680,275.76,2670,100,45 +1791537681,275.70,2670,100,45 +1791537682,276.13,2670,100,45 +1791537684,275.75,2670,100,45 +1791537685,275.75,2670,100,45 +1791537686,275.86,2670,100,45 +1791537687,275.65,2670,100,45 +1791537688,275.73,2670,100,45 +1791537689,275.67,2670,100,45 +1791537690,275.65,2670,100,45 +1791537691,275.67,2670,100,45 +1791537692,275.95,2670,100,45 +1791537693,276.16,2670,100,45 +1791537694,275.87,2670,100,45 +1791537695,276.40,2670,100,45 +1791537696,275.88,2670,100,45 +1791537697,275.58,2670,100,45 +1791537698,275.83,2670,100,45 +1791537699,275.79,2670,100,45 +1791537701,275.62,2670,100,45 +1791537702,275.62,2670,100,45 +1791537703,275.67,2670,100,45 +1791537704,275.69,2670,100,45 +1791537705,275.80,2670,100,45 +1791537706,275.79,2670,100,45 +1791537707,275.96,2670,100,45 +1791537708,275.91,2670,100,45 +1791537709,276.00,2670,100,45 +1791537710,276.33,2670,100,45 +1791537711,276.05,2670,100,45 +1791537712,275.82,2670,100,45 +1791537713,275.83,2670,100,45 +1791537714,275.79,2670,100,45 +1791537715,275.68,2670,100,45 +1791537716,276.52,2670,100,45 +1791537717,276.24,2670,100,45 +1791537719,275.78,2670,100,45 +1791537720,276.03,2670,100,46 +1791537721,276.27,2670,100,46 +1791537722,276.12,2670,100,46 +1791537723,276.33,2670,100,46 +1791537724,276.52,2670,100,46 +1791537725,276.54,2670,100,46 +1791537726,276.20,2670,100,46 +1791537727,276.32,2670,100,46 diff --git a/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-08-hl-v6-all.csv b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-08-hl-v6-all.csv new file mode 100644 index 000000000..ef35ed5e8 --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/pod-s2/smi-08-hl-v6-all.csv @@ -0,0 +1,118 @@ +1791537747,27.40,210,0,33 +1791537749,46.65,2520,0,33 +1791537750,81.12,2520,0,33 +1791537751,81.00,2520,0,33 +1791537752,130.12,2685,100,38 +1791537753,253.26,2685,100,39 +1791537754,284.53,2685,100,40 +1791537755,284.60,2685,100,40 +1791537756,284.13,2685,100,40 +1791537757,284.60,2685,100,41 +1791537758,285.18,2685,100,41 +1791537759,285.54,2685,100,41 +1791537760,285.55,2685,100,41 +1791537761,285.42,2685,100,42 +1791537762,285.53,2685,100,42 +1791537763,285.24,2685,100,42 +1791537764,285.26,2685,100,42 +1791537765,285.26,2685,100,42 +1791537767,285.40,2685,100,42 +1791537768,285.45,2685,100,42 +1791537769,285.73,2685,100,43 +1791537770,286.00,2685,100,43 +1791537771,285.87,2685,100,43 +1791537772,286.22,2685,100,43 +1791537773,285.95,2685,100,43 +1791537774,285.96,2685,100,43 +1791537775,285.92,2685,100,43 +1791537776,286.01,2685,100,43 +1791537777,285.96,2685,100,44 +1791537778,286.32,2685,100,44 +1791537779,286.23,2685,100,44 +1791537780,286.25,2685,100,44 +1791537781,286.63,2670,100,44 +1791537782,286.44,2670,100,44 +1791537783,286.19,2670,100,44 +1791537785,286.31,2670,100,44 +1791537786,286.45,2670,100,44 +1791537787,286.55,2670,100,44 +1791537788,286.82,2670,100,44 +1791537789,286.51,2670,100,44 +1791537790,286.82,2670,100,44 +1791537791,286.42,2670,100,45 +1791537792,286.90,2670,100,45 +1791537793,286.84,2670,100,45 +1791537794,286.63,2670,100,45 +1791537795,286.54,2670,100,45 +1791537796,286.65,2670,100,45 +1791537797,286.94,2670,100,45 +1791537798,287.28,2670,100,45 +1791537799,287.34,2670,100,45 +1791537800,287.54,2670,100,45 +1791537801,287.22,2670,100,45 +1791537802,287.30,2670,100,45 +1791537804,287.25,2670,100,45 +1791537805,287.18,2670,100,45 +1791537806,287.52,2670,100,45 +1791537807,287.50,2670,100,45 +1791537808,287.69,2670,100,45 +1791537809,287.54,2670,100,45 +1791537810,287.32,2670,100,46 +1791537811,287.32,2670,100,46 +1791537812,287.42,2670,100,46 +1791537813,287.60,2670,100,46 +1791537814,287.20,2670,100,46 +1791537815,287.45,2670,100,46 +1791537816,287.47,2670,100,46 +1791537817,287.26,2670,100,46 +1791537818,287.34,2670,100,46 +1791537819,287.37,2670,100,46 +1791537820,287.47,2670,100,46 +1791537822,287.50,2670,100,46 +1791537823,287.43,2670,100,46 +1791537824,287.26,2670,100,46 +1791537825,287.65,2670,100,46 +1791537826,287.80,2670,100,46 +1791537827,287.65,2670,100,46 +1791537828,287.52,2670,100,46 +1791537829,287.68,2670,100,46 +1791537830,287.58,2670,100,46 +1791537831,287.68,2670,100,46 +1791537832,287.86,2670,100,46 +1791537833,287.38,2670,100,46 +1791537834,287.53,2670,100,46 +1791537835,287.71,2670,100,46 +1791537836,287.42,2670,100,46 +1791537837,287.53,2670,100,46 +1791537838,287.72,2670,100,46 +1791537840,287.56,2670,100,46 +1791537841,287.89,2670,100,46 +1791537842,287.81,2670,100,46 +1791537843,287.87,2670,100,46 +1791537844,287.82,2670,100,46 +1791537845,287.81,2670,100,46 +1791537846,287.95,2670,100,46 +1791537847,288.20,2670,100,46 +1791537848,288.24,2670,100,46 +1791537849,288.27,2670,100,46 +1791537850,288.44,2670,100,46 +1791537851,288.34,2670,100,46 +1791537852,288.13,2670,100,47 +1791537853,288.21,2670,100,47 +1791537854,288.27,2670,100,47 +1791537855,287.92,2670,100,47 +1791537856,288.00,2670,100,47 +1791537857,287.95,2670,100,47 +1791537859,287.98,2670,100,47 +1791537860,287.47,2670,100,46 +1791537861,287.57,2670,100,47 +1791537862,288.09,2670,100,47 +1791537863,288.23,2670,100,47 +1791537864,288.52,2670,100,47 +1791537865,288.55,2670,100,47 +1791537866,288.64,2670,100,47 +1791537867,288.74,2670,100,47 +1791537868,288.98,2670,100,47 +1791537869,288.61,2670,100,47 +1791537870,288.70,2670,100,47 +1791537871,288.71,2670,100,47 diff --git a/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows-s2.txt b/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows-s2.txt new file mode 100644 index 000000000..7490d7fcb --- /dev/null +++ b/docs/analysis/class-v6/1p5x/x4/rows/gpu-rows-s2.txt @@ -0,0 +1,15 @@ +run pack MH/s W nJ per hash sm MHz util samples regs blocks/SM fingerprint check +01-hl-v6-all hl-v6-all 35.081 286.7 8172 2678 100 110 93 20 e8f4f3289c6ee1fc PASS +02-x4-direct x4-direct 35.022 275.2 7857 2676 100 109 182 8 e8f4f3289c6ee1fc PASS +03-x4-generated x4-generated 35.055 275.1 7847 2675 100 109 142 12 e8f4f3289c6ee1fc PASS +04-x4-prefix x4-prefix 34.971 277.2 7926 2675 100 111 154 12 e8f4f3289c6ee1fc PASS +05-x4-prefix x4-prefix 35.050 277.7 7922 2674 100 110 154 12 e8f4f3289c6ee1fc PASS +06-x4-generated x4-generated 35.053 274.9 7842 2676 100 109 142 12 e8f4f3289c6ee1fc PASS +07-x4-direct x4-direct 35.022 274.9 7850 2675 100 109 182 8 e8f4f3289c6ee1fc PASS +08-hl-v6-all hl-v6-all 35.081 287.1 8184 2673 100 111 93 20 e8f4f3289c6ee1fc PASS + +pair form pass 1 rate % pass 1 J/hash % pass 2 rate % pass 2 J/hash % mean rate % mean J/hash % g (J/hash ratio) +A/A hl-v6-all run 8 vs run 1 +0.00 +0.15 +pair x4-direct -0.17 -3.85 -0.17 -4.08 -0.17 -3.97 0.9603 +pair x4-generated -0.07 -3.98 -0.08 -4.18 -0.08 -4.08 0.9592 +pair x4-prefix -0.31 -3.01 -0.09 -3.21 -0.20 -3.11 0.9689 From bd5e9cb203f069aa4f6c11572c4cfa39305799d6 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:35:50 +0000 Subject: [PATCH 04/19] X4 (1.5x): the registry batch beside the README for the steward (its cell is not in the map) Co-Authored-By: Claude Opus 5.5 --- docs/analysis/class-v6/1p5x/x4/README.md | 2 +- .../class-v6/1p5x/x4/registry-batch-1p5x-x4-20261009.json | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tools/ci/batches/1p5x-x4-20261009.json => docs/analysis/class-v6/1p5x/x4/registry-batch-1p5x-x4-20261009.json (100%) diff --git a/docs/analysis/class-v6/1p5x/x4/README.md b/docs/analysis/class-v6/1p5x/x4/README.md index cae8b982a..24a48e468 100644 --- a/docs/analysis/class-v6/1p5x/x4/README.md +++ b/docs/analysis/class-v6/1p5x/x4/README.md @@ -223,4 +223,4 @@ All on a build box, never the Mac: 6. On the pod: `pod-x4.sh` with the worker and the packs, then `gpu_rows.py out out-run.log > gpu-rows.txt`. 7. Arithmetic: `arith.py gpu-rows.txt chip-rows.txt`. -The registry batch is `tools/ci/batches/1p5x-x4-20261009.json`, every cell NOT RUN. +The registry batch is `registry-batch-1p5x-x4-20261009.json` beside this file, every cell NOT RUN. It names the cell `rows:1p5x-x4`, which is not in the test map; the steward records it through `tools/ci/test-record.mjs`. diff --git a/tools/ci/batches/1p5x-x4-20261009.json b/docs/analysis/class-v6/1p5x/x4/registry-batch-1p5x-x4-20261009.json similarity index 100% rename from tools/ci/batches/1p5x-x4-20261009.json rename to docs/analysis/class-v6/1p5x/x4/registry-batch-1p5x-x4-20261009.json From 468918c98ed670136db4b4b318e9fcc4dc1f91e2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:35:56 +0000 Subject: [PATCH 05/19] X2: run-prod-then-pairs.sh, the campaign script the README cites (the text as it ran on the pod) Co-Authored-By: Claude Opus 5.5 --- tools/1p5x/x2/run-prod-then-pairs.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 tools/1p5x/x2/run-prod-then-pairs.sh diff --git a/tools/1p5x/x2/run-prod-then-pairs.sh b/tools/1p5x/x2/run-prod-then-pairs.sh new file mode 100755 index 000000000..1c1af6a21 --- /dev/null +++ b/tools/1p5x/x2/run-prod-then-pairs.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# X2: the prod plan again (with the separators, after finding X2-F1), then the measured pairs; one GPU process at a time. +# The text as it ran on fk-x2-4090 at 08:49 UTC on 9 October 2026 (paths are the pod's /root/x2 layout). +set -uo pipefail +P=/root/x2/pids; O=/root/x2/out/equiv; D=/root/x2/tools/x2-equiv.py; W=/root/x2/bin/igneum-worker-cuda +echo "$$ $(date -u +%FT%TZ) x2 run-prod-then-pairs" > $P/x2-run-prod-then-pairs.pid +for c in same-work-20261008-01 same-work-20261008-02 same-work-20261008-03; do + echo "== $(date -u +%T) $c prod" + python3 $D expect --ctx /root/x2/ctx/$c --shape prod --out $O > /dev/null + python3 $D run --worker $W --ctx /root/x2/ctx/$c --mode full --shape prod --out $O --pid-dir $P > /dev/null + python3 $D run --worker $W --ctx /root/x2/ctx/$c --mode select --shape prod --out $O --pid-dir $P > /dev/null + python3 $D compare --out $O --ctx-id $c --shape prod > /dev/null + python3 -c "import json,sys; r=json.load(open(sys.argv[1])); print(r[\"ctx\"], r[\"shape\"], r[\"verdict\"], {m: (v if isinstance(v, str) else (v[\"equal_to_expected\"], v[\"sha256\"][:16], v[\"first_difference\"])) for m, v in r[\"modes\"].items()}, \"expected\", r[\"expected_sha256\"][:16])" $O/$c.prod.compare.json +done +echo "== $(date -u +%T) pairs" +/root/x2/tools/run-pairs.sh $W /root/x2/ctx/same-work-20261008-02/packs/chain-seed-d20730 /root/x2/out/pairs $P 4 1024 22 +rm -f $P/x2-run-prod-then-pairs.pid From 55e9e70d3014b455f08778678915739303d39cb6 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:36:15 +0000 Subject: [PATCH 06/19] memory guard: the syncing band is 100 blocks and a unit in its first two minutes without an RPC answer is not counted (the seed's reopen restart at 10:32 UK was read as a second sync and the hand was refused once). Co-Authored-By: Claude Fable 5.1 --- infra/build-server/guard/memory-guard.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/infra/build-server/guard/memory-guard.sh b/infra/build-server/guard/memory-guard.sh index 2b76c3ea7..0bfcccc79 100644 --- a/infra/build-server/guard/memory-guard.sh +++ b/infra/build-server/guard/memory-guard.sh @@ -12,7 +12,10 @@ height() { curl -s --max-time 5 -X POST -H 'content-type: application/json' --da hub=$(cut -d' ' -f1 /srv/canary/hub1-tip.txt 2>/dev/null); hub=${hub:-0} syncing=(); for pair in igneum-dn4-seed:27810 igneum-dn4-hand:26870 igneum-light-reader:26881; do u=${pair%%:*}; p=${pair##*:} systemctl is-active --quiet "$u" || continue; h=$(height "$p"); d=$(( hub - h )) - if [ "$h" -lt 0 ] || [ "$d" -gt 10 ] || [ "$d" -lt -10 ]; then syncing+=("$u"); fi + # a fresh sync is thousands behind; the band is 100 blocks so a moving feed never reads a synced node as syncing, and a unit in its + # first two minutes whose RPC has not answered yet is not counted (10:32 UK, 9 Oct: the seed's reopen restart was read as a second sync) + age=$(( $(date +%s) - $(date -d "$(systemctl show -p ActiveEnterTimestamp --value "$u")" +%s 2>/dev/null || echo 0) )) + if [ "$h" -lt 0 ] && [ "$age" -lt 120 ]; then :; elif [ "$h" -lt 0 ] || [ "$d" -gt 100 ] || [ "$d" -lt -100 ]; then syncing+=("$u"); fi done if [ "${#syncing[@]}" -gt 1 ]; then # keep the earliest-started, stop the rest by unit From 29d7bfebd14dce4c05cdb76d6dfdc0f35fd36665 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:38:00 +0000 Subject: [PATCH 07/19] B1 (R15-05): the published MTP/DRSample primitive reproduced, with its complete verifier and fixtures Blocki and Smearsoll (eprint 2025/1456 as archived, sha256 13c3646e...) Sec 2.2, 3.2 and App. C over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived): CPython reference in tools/mhpow/b1 (params, drsample, mtp, attacks), the verifier's named checks in the paper's order with a known-failed test each (17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest rows n 12 to 24, the malicious provers A1 to A6 (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1; the LuckyQuery regrind) and the k table. Encoding pinned with B2 (BLAKE2b-256, tags L/M/C/G, u64 LE, raw leaves, LSB-at-root, public graph seed). Findings: proven k with ABH17's constant exceeds N to about n 25 (F-3); one labelling yields many accepted roots (F-4); lambda 256 meets Lemma 3 only for q <= 2^31.5 (F-5). Research paths added to tools/ci/export-exclude.txt beside B2's. Registry batch NOT RUN for the steward. Co-Authored-By: Claude Opus 5.5 --- docs/analysis/mhpow/b1/README.md | 290 ++++ .../registry-batch-mhpow-b1-20261009-01.json | 32 + tools/ci/export-exclude.txt | 2 + tools/mhpow/b1/attacks.py | 239 +++ tools/mhpow/b1/drsample.py | 87 ++ tools/mhpow/b1/fixtures/SHA256SUMS | 19 + tools/mhpow/b1/fixtures/attacks-n10-k16.json | 177 +++ tools/mhpow/b1/fixtures/k-table.json | 249 +++ tools/mhpow/b1/fixtures/k-table.log | 19 + tools/mhpow/b1/fixtures/kat-n04.json | 118 ++ tools/mhpow/b1/fixtures/kat-n04.proof.bin | Bin 0 -> 3893 bytes tools/mhpow/b1/fixtures/kat-n08.json | 1374 +++++++++++++++++ tools/mhpow/b1/fixtures/kat-n08.proof.bin | Bin 0 -> 55405 bytes tools/mhpow/b1/fixtures/kat-n12.json | 93 ++ tools/mhpow/b1/fixtures/kat-n12.proof.bin | Bin 0 -> 79981 bytes tools/mhpow/b1/fixtures/kat-n16.json | 93 ++ tools/mhpow/b1/fixtures/kat-n16.proof.bin | Bin 0 -> 104557 bytes tools/mhpow/b1/fixtures/kat-n20.json | 93 ++ tools/mhpow/b1/fixtures/kat-n20.proof.bin | Bin 0 -> 129133 bytes tools/mhpow/b1/fixtures/row-n12-k64.json | 24 + tools/mhpow/b1/fixtures/row-n16-k64.json | 24 + tools/mhpow/b1/fixtures/row-n20-k64.json | 24 + tools/mhpow/b1/fixtures/row-n22-k64.json | 24 + tools/mhpow/b1/fixtures/row-n24-k64.json | 24 + tools/mhpow/b1/fixtures/tests.log | 22 + tools/mhpow/b1/gen_fixtures.py | 139 ++ tools/mhpow/b1/k_table.py | 57 + tools/mhpow/b1/mtp.py | 304 ++++ tools/mhpow/b1/params.py | 62 + tools/mhpow/b1/run-b1.sh | 23 + tools/mhpow/b1/test_b1.py | 162 ++ 31 files changed, 3774 insertions(+) create mode 100644 docs/analysis/mhpow/b1/README.md create mode 100644 docs/analysis/mhpow/b1/registry-batch-mhpow-b1-20261009-01.json create mode 100644 tools/mhpow/b1/attacks.py create mode 100644 tools/mhpow/b1/drsample.py create mode 100644 tools/mhpow/b1/fixtures/SHA256SUMS create mode 100644 tools/mhpow/b1/fixtures/attacks-n10-k16.json create mode 100644 tools/mhpow/b1/fixtures/k-table.json create mode 100644 tools/mhpow/b1/fixtures/k-table.log create mode 100644 tools/mhpow/b1/fixtures/kat-n04.json create mode 100644 tools/mhpow/b1/fixtures/kat-n04.proof.bin create mode 100644 tools/mhpow/b1/fixtures/kat-n08.json create mode 100644 tools/mhpow/b1/fixtures/kat-n08.proof.bin create mode 100644 tools/mhpow/b1/fixtures/kat-n12.json create mode 100644 tools/mhpow/b1/fixtures/kat-n12.proof.bin create mode 100644 tools/mhpow/b1/fixtures/kat-n16.json create mode 100644 tools/mhpow/b1/fixtures/kat-n16.proof.bin create mode 100644 tools/mhpow/b1/fixtures/kat-n20.json create mode 100644 tools/mhpow/b1/fixtures/kat-n20.proof.bin create mode 100644 tools/mhpow/b1/fixtures/row-n12-k64.json create mode 100644 tools/mhpow/b1/fixtures/row-n16-k64.json create mode 100644 tools/mhpow/b1/fixtures/row-n20-k64.json create mode 100644 tools/mhpow/b1/fixtures/row-n22-k64.json create mode 100644 tools/mhpow/b1/fixtures/row-n24-k64.json create mode 100644 tools/mhpow/b1/fixtures/tests.log create mode 100644 tools/mhpow/b1/gen_fixtures.py create mode 100644 tools/mhpow/b1/k_table.py create mode 100644 tools/mhpow/b1/mtp.py create mode 100644 tools/mhpow/b1/params.py create mode 100755 tools/mhpow/b1/run-b1.sh create mode 100644 tools/mhpow/b1/test_b1.py diff --git a/docs/analysis/mhpow/b1/README.md b/docs/analysis/mhpow/b1/README.md new file mode 100644 index 000000000..f77b154c3 --- /dev/null +++ b/docs/analysis/mhpow/b1/README.md @@ -0,0 +1,290 @@ +# B1 (R15-05): the published MTP/DRSample primitive, reproduced + +Track B of the 1.5x Research Programme, item B1, 9 October 2026. Lane: the cryptography lane. Box: build-6 (32 vCPU, +CPU only). Status of every row: NOT RUN until the panel reads it. This lane writes no PASS. + +What this is: an exact CPU reference of the Merkle Tree Proof framework of Blocki and Smearsoll (TCC 2025) over the +DRSample graph, its complete verifier, known-answer fixtures, honest-prover rows and malicious-prover fixtures. It is a +control and a specification. It is not an Igneum work unit, it carries no lottery, and nothing here activates. + +## 1. Sources (full PDFs, fetched on build-6, sha256 of the bytes as fetched) + +eprint.iacr.org answers the build boxes with a Cloudflare managed challenge. No check was bypassed: the eprint PDFs +were taken from the Internet Archive's snapshot of the eprint URL (`web.archive.org/web/id_/https://eprint.iacr.org/.pdf`). + +| key | paper | source as fetched | sha256 | pages | +|---|---|---|---|---| +| [BS25] | Blocki, Smearsoll, Provably Memory-Hard Proofs of Work With Memory-Easy Verification, TCC 2025 | eprint 2025/1456, archive snapshot 2025-12-31T15:20:15Z | `13c3646e7d85c1aa58a92914582caab5798d90cf2a3cad33e58d81d49c1d31db` | 46 | +| [DN17] | Dinur, Nadler, Time-Memory Tradeoff Attacks on the MTP Proof-of-Work Scheme, CRYPTO 2017 | eprint 2017/497, archive snapshot 2026-05-09T02:34:47Z | `d2fd7774535dd3226bb4a767d4930a5c3a91ac6ed2f1421ee511b66ea37b0b03` | 30 | +| [ABH17] | Alwen, Blocki, Harsha, Practical Graphs for Optimal Side-Channel Resistant Memory-Hard Functions, CCS 2017 | eprint 2017/443, archive snapshot 2025-12-10T21:05:18Z | `f8e08d361118120c905550d3ac63efffe2a806d68276b070c24e7aa15d8fa8eb` | 17 | +| [BK16] | Biryukov, Khovratovich, Egalitarian computing (MTP 1.2) | arXiv 1606.03588v2 | `5dca4aef485f480cf010b744a9c0252a8460dd4a31152ffedeba70ef77399623` | 16 | + +The [BS25] bytes were fetched twice, once by the B3 lane and once by this lane from the same snapshot. Both reads gave the +same sha256. The copies are at `build-6:/srv/builds/mhpow-b1/papers/`. Row O-3 records that each is "the revision as +archived" and has not been checked against eprint's current revision. + +What each source supplies to the code: + +| what | where in the paper | code | +|---|---|---| +| labelling game, local consistency, parents in ascending order | [BS25] Sec 2.2 | `mtp.label_of`, `mtp.compute_labels` | +| the framework: Prove steps 1 to 4, Verify steps 1 to 4 | [BS25] Sec 3.2 | `mtp.prove_commit`, `mtp.respond`, `mtp.verify` | +| Merkle construction, reveal, check | [BS25] Sec 3.2 step 2, Sec 4.1, App. C.1, Def. 15, App. C.2 | `mtp.MerkleTree`, `MerkleTree.reveal`, `mtp.merkle_tree_check` | +| challenges c_i = H(chi, i, tau) mod N | [BS25] Sec 3.2 step 3, Sec 5 Def. 14 | `mtp.challenges` | +| soundness chain implemented against | [BS25] Theorem 4, Theorem 6, Theorem 7, Corollary 1, Corollary 2, Fact 8, Corollary 3 | section 6 (k), section 7 (attacks) | +| the paper's own attack | [BS25] Sec 7.1 Attack 1 | `attacks.a5_attack1` | +| the DRSample edge rule (cited by [BS25] Sec 6.1, defined only here) | [ABH17] Sec 3, Algorithm 1 | `drsample.get_parent`, `drsample.parents` | +| DRSample's proven depth-robustness constants | [ABH17] Theorem 3.1 | `k_table.py` | +| the attacks on MTP-Argon2d | [DN17] Sec 4.1, 4.3, 5, 8 | `attacks.a1` to `a4` | + +## 2. Parameters and the decisions the paper leaves open + +[BS25] fixes the construction abstractly. It has a random oracle H with lambda-bit output, labels H(chi, v, parent +labels), Merkle nodes H(chi, left, right) and challenges H(chi, i, tau) mod N. It names no hash, no lambda, no byte +encoding, no domain tag, and no concrete N or k. Every such choice below is this lane's. Each is pinned in +`tools/mhpow/b1/params.py` with its reason. The B2 lane agreed to them before the first fixture was cut and moved its instance layout to them. + +| symbol | value | basis | +|---|---|---| +| H | BLAKE2b, 32-byte digest, unkeyed | B1 decision: one oracle for B1, B2 (chi) and B3 (GPU oracle) | +| lambda | 256 | B1 decision; see row O-4 for what [BS25] Lemma 3 then covers | +| chi | 32 bytes (B2: BLAKE2b-256('I' \|\| 328-byte instance)) | [BS25] Def. 5 input string; layout is B2's | +| domain tags | 'L' label, 'M' Merkle node, 'C' challenge, 'G' graph draw ('I' is B2's) | B1 decision on top of the paper's salt-only separation (finding F-1) | +| integers | node index v and challenge index i as u64 little-endian | B1 decision | +| G | DRSample(N), [ABH17] Alg. 1, indegree 2, sampled once from a public 32-byte seed | [BS25] Sec 1.2 needs G fixed a priori (finding F-2) | +| N | 2^n with n = 4, 8, 12, 16, 20 (fixtures) and 12 to 24 (rows) | the paper states no N (row O-2) | +| k | 8 at n = 4, 64 otherwise | fixture sizes only, NOT a security level (row O-1) | +| leaves | the raw 32-byte labels, not hashed | [BS25] Sec 3.2 step 2: tau_v = l_{1+bin(v)} | +| tree layout | the bit taken at depth j from the root is bit j-1 of the leaf index | [BS25] Sec 3.2: bin(v) = sum v_i 2^(i-1) (row R-3) | +| openings | per challenge: node c_i + 1 and each of its parents, each with its own full path | [BS25] Sec 3.2 step 3(a)(b); no path sharing | + +Exact query byte layouts (every query is one BLAKE2b block, 41 to 105 bytes): + +``` +label, node 1 H('L' || chi || u64(1)) +label, node v >= 2 H('L' || chi || u64(v) || l_p1 || ... ) parents ascending; node 2 has the one parent 1 +Merkle inner node H('M' || chi || left || right) +challenge i (1..k) c_i = int_le(H('C' || chi || u64(i) || tau)) mod N opened node c_i + 1, leaf index c_i +graph draw H('G' || graph_seed || u64(v) || u8(which) || u64(ctr)) first 8 bytes, rejection sampling +proof container "B1MTPDR1" | n u8 | k u32le | tau 32 | per challenge: label 32 | n x 32 | count u8 | per parent: label 32 | n x 32 +``` + +graph_seed = BLAKE2b-256("igneum/mhpow/b1/drsample-graph-seed/v1") = +`params.GRAPH_SEED` (the fixtures carry it in hex). + +## 3. The construction in words, tied to the code + +1. Graph ([ABH17] Alg. 1; `drsample.parents`). Nodes 1..N. Node 1 has no parent and node 2 has the parent 1. Every + node v >= 3 has the parents v - 1 and v - r. To pick r, first draw g' uniformly from [1, floor(log2 v) + 1] and set + g = min(v - 1, 2^g'). Then draw r uniformly from [max(ceil(g/2), 2), g]. So r >= 2 and the two parents are distinct. + The draws come from the public seed, so the graph is a fixed public object, never a function of chi. +2. Labels ([BS25] Sec 2.2, Sec 3.2 step 1; `mtp.compute_labels`). In topological order, l_v = H('L', chi, v, parent + labels). This is one sequential pass of N oracle calls, holding 32N bytes. +3. Commitment ([BS25] Sec 3.2 step 2, App. C.1; `mtp.MerkleTree`). A binary tree of depth n over the raw labels. The + tree is salted by chi, and the leaf for node w sits at leaf index w - 1 with LSB-at-root position bits. tau is the root. +4. Challenges ([BS25] Sec 3.2 step 3; `mtp.challenges`). c_i = H('C', chi, i, tau) mod N for i = 1..k. N divides + 2^256, so the reduction is exactly uniform. +5. Proof ([BS25] Sec 3.2 step 3(a)(b) and step 4; `mtp.respond`, `Proof.to_bytes`). For each i, the proof carries + l_{c_i+1} with its n siblings, then each parent's label with its n siblings. No positions are carried: the verifier + derives every position. +6. Verifier ([BS25] Sec 3.2 Verify; `mtp.verify`). Each check is a named function. They run in the paper's order and the + first failure is returned by name: + +| check | paper | refuses | +|---|---|---| +| `check_0_container` | B1 addition (parsing) | wrong N, wrong k, truncation, trailing bytes, bad magic | +| `check_1_challenges` | Verify step 1 | (derives c'_i from the proof's tau; it cannot fail, it binds positions) | +| `check_2a_parent_set` | Verify step 2 (separating L into the parents of c_i + 1) | a skipped or extra parent opening | +| `check_2b_merkle_openings` | Verify step 2, App. C.2 MerkleTreeCheck | a wrong label, wrong path, wrong position, wrong chi, wrong Merkle tag | +| `check_3_local_consistency` | Verify step 3 | a red challenged node (including a label made with the wrong tag) | +| accept | Verify step 4 | | + +Known-failed tests (`tools/mhpow/b1/test_b1.py`). The suite has 17 tests and all 17 ran OK on build-6. Each refusal is +asserted by the name of the check that fires: + +| test | the wrong thing | refused by | +|---|---|---| +| test_wrong_label | one bit of a challenged label | check_2b_merkle_openings | +| test_wrong_parent_label | one bit of a parent label | check_2b_merkle_openings | +| test_wrong_path | one bit of one sibling hash | check_2b_merkle_openings | +| test_wrong_challenge | responses for i = 2..k+1 instead of 1..k | check_2a_parent_set or check_2b_merkle_openings | +| test_skipped_parent | one parent opening dropped | check_2a_parent_set | +| test_duplicated_parent_position | both openings for the same parent ([BK16] App. B, Bevand's attack 2 class) | check_2b_merkle_openings | +| test_wrong_domain_tag_label | the whole array labelled with tag 'M', committed honestly | check_3_local_consistency | +| test_wrong_domain_tag_merkle | the tree built with tag 'L' | check_2b_merkle_openings | +| test_wrong_chi | a valid proof verified against another chi | check_2b_merkle_openings | +| test_container | truncated, extended, wrong k, wrong n | check_0_container | +| test_every_check_has_a_refusal | each refusing check shown to fire at least once | all four | +| graph and Merkle tests | edge rule and bucket ranges, determinism, bucket spread, every-leaf reveal and check, LSB-at-root layout | | + +## 4. Known-answer fixtures + +Command (build-6, under `/srv/builds/mhpow-b1/run.pid`, mirrored to `build-1:/srv/queue/pids/build-6-b1.pid`): +`tools/mhpow/b1/run-b1.sh /srv/builds/mhpow-b1/out-final2 all` (09:33:52Z to 09:36:50Z). The fixtures are deterministic. +Four runs (`out`, `out-repeat`, `out-final`, `out-final2`) produced byte-identical kat files, and two runs byte-identical attack +files (attacks-n10-k16.json sha256 `805035ebfc8d2f34441325b5d5ca46c67e81f7d0b0b86f62ba1a906964b8c51f`). chi for the fixture at n is +BLAKE2b-256("B1-fixture" || "kat" || u64(n)). + +| fixture | n | k | tau (first 16 hex) | proof bytes | json sha256 | proof.bin sha256 | +|---|---|---|---|---|---|---| +| kat-n04 | 4 | 8 | 9f98a28d3d84dbdc | 3,893 | `9f85b22ae54785e0e078630f890036713cf3925b7e1345bd949c6945d2702f7f` | `481a39fa47ff4d3393f34e15e318ee4bda7683ee457d3b9da79d277c9ba2831d` | +| kat-n08 | 8 | 64 | 90cb87eabf42f4c1 | 55,405 | `2c741be9a5a7c47773f902ed024c49188eacfc84f9cabdf34244f289e77f51f7` | `d45a9756b8d66357eaee34f1efa3b5fc975e25fcf7b7eb5a516746c6e078bbc7` | +| kat-n12 | 12 | 64 | 884d36cd2df99fa9 | 79,981 | `51ccacd3030d97ec371d8cc8ea64fbb362f00bd323bd84827105c89b4eb30864` | `3c7de0539a8715e75d3d64eb11ec3af7d8a2a338c101958a0c29e300c3ad4f7f` | +| kat-n16 | 16 | 64 | 41e05146c5819b21 | 104,557 | `240f50bc5ac5e12c7630f24c072bf291fb6ab9644530badcd1c41c7a7341440c` | `793fd4d505155f133c8acf1c657a98795f29f7d6cba2568570c8324c42fb1118` | +| kat-n20 | 20 | 64 | e3d83489e27af44b | 129,133 | `fd0d75b66af9cbd9ef12e63d571036f41bdac0e1d21e1f4d98559deb98502392` | `a49367d9c80f0855504fe1f0994acbd5ddc4b023eaf5904a28ad5f7e71ce951c` | + +kat-n04 and kat-n08 carry every parent, every label and the proof inline. kat-n12 to kat-n20 carry chi, tau, the +challenges, the sha256 of the parent table (u64le), the sha256 of the label array and the proof sha256. The verifier +accepted each one from bytes. The fixture files are in `tools/mhpow/b1/fixtures/` with their `SHA256SUMS`. + +## 5. Honest-prover rows (no hash-rate comparison anywhere) + +Software: `tools/mhpow/b1` at this branch, CPython 3.12.3, single thread. Hardware: build-6 (Hetzner Cloud ccx53, +32 vCPU), shared with two other lanes' fuzz and sweep jobs at the time, so the times are loaded wall times. Boundary: +process wall clock only, no power measured, stock clocks. These are a reference implementation's times. They are not a +GPU figure, an optimised figure or an energy figure. Command: `run-b1.sh rows` (one process per N, so each RSS is +its own). Rows: `fixtures/row-nXX-k64.json`. + +| n | N | prover sequential s (labels + Merkle + proof) | labels s | Merkle s | graph sample s (one-time, public) | prover state model bytes (96N - 32) | peak RSS measured | proof bytes (k 64) | verify s (from bytes) | verifier oracle calls | +|---|---|---|---|---|---|---|---|---|---|---| +| 12 | 4,096 | 0.010 | 0.004 | 0.006 | 0.013 | 393,184 | 19.7 MB | 79,981 | 0.0027 | 2,432 | +| 16 | 65,536 | 0.180 | 0.062 | 0.115 | 0.204 | 6,291,424 | 39.9 MB | 104,557 | 0.0032 | 3,200 | +| 20 | 1,048,576 | 3.48 | 1.03 | 2.41 | 3.31 | 100,663,264 | 355.7 MB | 129,133 | 0.0040 | 3,968 | +| 22 | 4,194,304 | 14.91 | 4.35 | 10.39 | 13.80 | 402,653,152 | 1,365.7 MB | 141,421 | 0.0483 | 4,352 | +| 24 | 16,777,216 | 66.97 | 17.54 | 48.69 | 52.28 | 1,610,612,704 | 5,407.2 MB | 153,709 | 0.0047 | 4,736 | + +What the rows mean: +- Honest work is linear in N, as [BS25] Sec 3.2 "Efficiency" states (O(N + k log N) sequential). 2N - 1 + k oracle calls + are made in one pass, and the label array (32N bytes) is held for the whole pass. The CPython RSS is about 3.4 times + the 96N-byte model because of object overhead. A packed implementation holds 32N bytes of labels plus 64N bytes of + tree, or 32N if the tree is streamed and the openings are recomputed. That trade-off is B3's to measure. +- The proof grows with n: proof bytes = 45 + k (1 + 96 (n + 1)) when every challenged node has indegree 2 (the exact + formula is `mtp.proof_bytes_formula`). Verification is k (3n + 2) oracle calls plus 2k graph draws. It needs no + memory beyond the proof and no table. +- The n = 22 verify time (0.047 and 0.048 s in two runs, against 0.004 to 0.005 s at n = 20 and n = 24) is not the + verifier's work. Its oracle-call count rises smoothly (4,352). The cause inside the measuring CPython process is not + established. A clean cold-verification budget at an admitted rate is B6's row (O-11). +- Per user tier: a GPU miner never runs this CPython path. What carries over is the shape: one N-label sequential pass + per instance (about 96 MiB of state at n = 20, about 1.5 GiB at n = 24 with the tree held) and a proof of 129 KB + (n = 20, k = 64) that a validator checks with about 4,000 BLAKE2b calls. The B3 lane owns the GPU adaptation and B6 + the node budget. + +## 6. The challenge count k: proven against attacked (code-generated) + +Command: `python3 tools/mhpow/b1/k_table.py `. Output: `fixtures/k-table.json`. + +(a) PROVEN. [BS25] Corollary 2 gives k = ceil(2 N ln2 lambda / e) for an (e, d)-depth-robust G. [ABH17] Theorem 3.1 +gives DRSample, with high probability over the sample, (e, d, b)-block depth-robustness with e >= 2.43 x 10^-4 N / log N +and d >= 0.03 N. Block depth-robustness implies depth-robustness. Here log is read as log2 (row R-4). At lambda = 256: + +| n | k (Cor. 2 with [ABH17]'s e) | k / N | proof bytes at that k | proof / label array | +|---|---|---|---|---| +| 12 | 17,525,500 | 4,279 | 21.9 GB | 167,002 x | +| 16 | 23,367,333 | 357 | 38.2 GB | 18,196 x | +| 20 | 29,209,166 | 27.9 | 58.9 GB | 1,756 x | +| 24 | 35,050,999 | 2.09 | 84.2 GB | 157 x | +| 30 | 43,813,748 | 0.041 | 130.4 GB | 3.8 x | +| 32 | 46,734,665 | 0.011 | 148.1 GB | 1.08 x | + +FINDING F-3: with the only proven DRSample constant in the literature cited, the theorem's k exceeds N up to about +n = 25. The certificate exceeds the whole label array up to n = 32. So the proven regime has no practical parameter +today. The paper says the constants are not tight. A usable k needs a better proven constant or an accepted heuristic +constant, and either is a decision for the panel (row O-1). + +(b) ATTACKED (a floor on k, not a security level). [BS25] Sec 7.1 Attack 1 was run with a greedy depth-reducing set +measured on this exact graph. The greedy rule puts v in S whenever v's depth in G - S would exceed d. The k below pushes +that attack's acceptance (1 - |S|/N)^k under 2^-s: + +| n | d | abs(S) / N | k for 2^-40 | k for 2^-128 | proof bytes at k for 2^-128 | +|---|---|---|---|---|---| +| 12 | N/4 | 0.160 | 160 | 510 | 637,035 | +| 12 | N/256 | 0.266 | 90 | 287 | 358,508 | +| 16 | N/4 | 0.161 | 158 | 504 | 823,077 | +| 16 | N/256 | 0.240 | 101 | 323 | 527,504 | +| 20 | N/4 | 0.168 | 151 | 482 | 972,239 | +| 20 | N/256 | 0.242 | 100 | 320 | 645,485 | + +The greedy set is a weak depth-reducing attack. Stronger ones (layered and recursive, [BS25] Sec 7.2, [ABH17] Sec 5) +remove fewer nodes for the same d. Those move these k values UP. Row O-9 holds them. + +## 7. Malicious-prover fixtures and verdicts + +Command: `run-b1.sh attacks`. Output: `fixtures/attacks-n10-k16.json`. N = 2^10 and k = 16 were chosen so that the +accepting probabilities can be measured. Each adversary is implemented to win, and its verdict is measured. + +| id | adversary (source) | what it does | measured | verdict and mechanism | +|---|---|---|---|---| +| A1 | [DN17] Sec 4.1 first attack | replays a valid proof made for chi' as a proof for chi | 0 of 50 accepted (check_2b, check_2a) | REFUSED. chi salts every label, Merkle node and challenge ([BS25] Sec 3.2). | +| A2 | [DN17] Sec 4.1 second attack | commits a constant array with no memory, then (a) answers with the label the verifier would recompute or (b) opens the constant label | (a) 0 of 50, check_2b; (b) 0 of 50, check_3 | REFUSED. [BS25] Sec 3.2 opens l_{c_i+1} itself at the derived position and checks it against its opened parents. | +| A3 | [DN17] Sec 4.3 and Sec 5, control blocks (the attack that broke MTP-Argon2d) | t = 20; grinds each control block up to 1,000 times to steer the next t - 1 parents into the stored set (Eq. 5), then stores only control blocks as red values | Eq. 5 met in 0 of 50 intervals after 1 try and 0 of 50 after 1,000; steering gain 0; red-node fallback accepted 191 of 400 = 0.478 (analytic (1 - 1/t)^k = 0.442) | STEERING REFUSED BY CONSTRUCTION. DRSample's parents are fixed a priori, so no label value moves an edge. What remains is a red-node cheat, accepted with (1 - abs(S)/N)^k: the probability [BS25] Lemma 4 bounds and k must make small. | +| A4 | [DN17] Sec 8, self-similarity of data-independent MTP (Y2 := X2 gives Y1 = X1) | copies a label into a node that shares a long-edge parent | 0 of 200 copies reproduced a label; 189 of 200 accepted (one red node each) | SAVING REFUSED. The node index v is in every prelabel ([BS25] Sec 2.2; [DN17] Sec 8's own HAIFA countermeasure). The one red node is caught only when challenged. | +| A5 | [BS25] Sec 7.1 Attack 1 | labels 0^lambda on a greedy depth-reducing set S, the rest in parallel | d = 64: abs(S)/N 0.222, depth of G - S 64, accepted 6 of 400 = 0.015 (analytic 0.018); d = 256: abs(S)/N 0.151, accepted 26 of 400 = 0.065 (analytic 0.072) | ACCEPTED WITH PROBABILITY (1 - abs(S)/N)^k, as the paper states. The cheater needs only d parallel rounds and O(N d lambda) cumulative memory. This is what sets k (section 6). | +| A6 | [BS25] Sec 5 Def. 14 and Lemma 4 (LuckyQuery); B2's O-07 | one labelling; re-rolls tau by rewriting one red leaf and its path only (n + k = 26 oracle calls per try, no relabelling) | 1 red sink: 193 to 200 of 200 tries are accepted roots per labelling; 64 red: 140 to 152 of 400; first accept at try 1.2 and 1.6 on average | ACCEPTED: one labelling yields many accepted (tau, proof) pairs for one chi. The paper's soundness counts this in its q(1 - beta)^k term and still bounds cmc per accepted proof. But nothing in the primitive makes a second accepted root cost a second labelling. A lottery value derived from tau would be re-rolled for n + k calls (finding F-4, handed to B2 and B4). | + +A1 to A4 are the Dinur and Nadler adversaries against the data-independent instantiation. The two that broke +MTP-Argon2d (A2 and A3) have no foothold. A2 is closed by the opening rule and A3 by the fixed graph. No Dinur-Nadler +adversary gained anything beyond the red-node probability that the theorem already prices. A5 and A6 are accepted with +exactly the probability the paper's own bound names. They are not new breaks. They are the reason k and the lottery +binding are open (O-1, O-8). + +## 8. Findings (each with its consequence) + +- F-1 Domain separation. [BS25] separates query kinds only by the chi salt and the query shape. With a common integer + width, the challenge query H(chi, i, tau) has the shape of the prelabel of an indegree-1 node (DRSample's node 2). + B1 pins one-byte tags (L, M, C, G). Any implementation that drops them is a different function and needs its own + argument. Consequence: B2 and B3 pin to the tags. +- F-2 The graph must be a public constant. [BS25] proves soundness for a graph fixed a priori. If the graph came from + chi, a prover who varies a nonce inside chi could grind for a weak sample. Consequence: the graph seed is a constant + and never per instance. Whether the one fixed sample is in fact depth-robust is unverified (row O-12). +- F-3 Proven k is impractical (section 6a): about 2.9 x 10^7 challenges at n = 20 with the cited constant. + Consequence: a Track B candidate cannot claim [BS25]'s theorem at any practical k today. A heuristic k must be + labelled as such. +- F-4 One labelling, many accepted roots (A6). Consequence: an Igneum lottery cannot be a hash of tau alone. B2's O-07 + and B4's composed theorem must bind the lottery to the labelling. +- F-5 [BS25] Lemma 3 needs lambda/4 >= 2 log2(q) + log2(indeg). At lambda = 256 that covers q <= 2^31.5 oracle calls. + q = 2^64 needs lambda >= 516. Consequence: at network scale, the theorem's extraction step does not cover lambda = 256 + as written (row O-4). + +## 9. Open questions (BLOCKED rows) + +| row | question | why blocked | owner | clock | +|---|---|---|---|---| +| O-1 | a practical k with a proof: a better proven DRSample (e, d) constant, or a panel-approved heuristic k | [ABH17] Theorem 3.1's constant gives k > N (section 6a); [BS25] states no concrete k | B4 (theory) with R15-07 | not set by B1 | +| O-2 | "the paper's smallest stated N" | [BS25] states no concrete N, lambda, k or hash; B1's fixture sizes are its own | B1 records; the panel picks N | n/a | +| O-3 | the archived revision against eprint's current revision of 2025/1456 and 2017/497 | eprint challenges the boxes; the snapshot dates are in section 1 | B1 or B4 when any box is served | open | +| O-4 | lambda against Lemma 3's precondition at network q (F-5): lambda = 512 (BLAKE2b-512) or a tighter extractor | a theory question; changing lambda changes every fixture and B2's chi | B4 | open | +| O-5 | the log base and constants in [BS25] Fact 8 and Corollary 3 (c1, c3, c4) and in [ABH17] Theorem 3.1 | the papers write "log"; B1 reads log2 (R-4) | B4 | open | +| O-6 | [BS25] App. C.2's loop processes x_1 first from the leaf, which matches Def. 15 / Sec 3.2 only if x is read leaf-first | an erratum question for the authors; B1 pins Sec 3.2's bin(v) and Def. 15's sibling order (R-3) | B1 to the panel | open | +| O-7 | Verify step 2 writes MerkleTreeReveal(chi, i, ...) with the challenge number i; B1 checks at the derived leaf index c_i and parent index u - 1 (R-5) | wording in the paper; B1's reading is the one under which the attacks are refused | B1 to the panel | open | +| O-8 | lottery binding: one labelling gives many accepted roots (F-4) | the primitive has no lottery; binding is B2's spec and B4's theorem | B2, B4 | open | +| O-9 | stronger depth-reducing attacks on this exact graph (layered, recursive, [BS25] Sec 7.2, [ABH17] Sec 5) to raise section 6b's floor | not implemented in this window | B4 / R15-07 | open | +| O-10 | energy: [BS25] bounds cumulative memory in the parallel random oracle model (bits of state per round). It says nothing about joules, SRAM or a chip | the physical translation is B4/B5's | B4, B5 | open | +| O-11 | a compiled verifier and cold verification at the admitted rate | only the CPython reference exists | B6 (node lane), B3 | open | +| O-12 | is the one fixed DRSample sample (graph_seed) actually (e, d)-depth-robust? [ABH17] Theorem 3.1 holds with high probability over the sample, not for every seed | no tool here certifies a sampled graph | B4 | open | +| O-13 | does [R4] (de Rezende, Engstrom, Reyzin 2026) touch [BS25]? [BS25]'s bound is on the PROM state size \|sigma_i\| in bits (Theorem 6), so encoded state is counted, but the reduction must be read against [R4] | a theory read | B4 | open | +| O-14 | the quantum case | [BS25] is classical (PROM); the plan's rule keeps the claim classical | none today | n/a | + +Resolutions B1 made where a source was ambiguous (each one pinned in code): + +- R-1. [ABH17] "[max(g/2, 2), g]" with g = v - 1 odd: the integer range starts at ceil(g/2). +- R-2. [ABH17]'s uniform draws: rejection sampling over 64-bit words of the 'G' oracle with the public seed. +- R-3. Tree layout: Sec 3.2 and Sec 4.1, with LSB-at-root; Def. 15 sibling order root-first. +- R-4. log means log2 wherever a constant is evaluated. +- R-5. Merkle positions are always the verifier's own (c_i for the node, u - 1 for parent u). + +## 10. Files + +| path | what | +|---|---| +| `tools/mhpow/b1/params.py` | the oracle, lambda, tags, integer encoding, graph seed, with the paper section beside each | +| `tools/mhpow/b1/drsample.py` | [ABH17] Alg. 1 DRSample, the derandomisation, depth of G - S | +| `tools/mhpow/b1/mtp.py` | labels, Merkle tree, reveal and check, challenges, the certificate container, honest prover, verifier | +| `tools/mhpow/b1/attacks.py` | adversaries A1 to A6 | +| `tools/mhpow/b1/test_b1.py` | the 17-test suite (known-failed cases by check name) | +| `tools/mhpow/b1/gen_fixtures.py`, `k_table.py`, `run-b1.sh` | fixture, row, attack and k-table generators; the box driver (pid file first) | +| `tools/mhpow/b1/fixtures/` | every fixture, row and table above, with `SHA256SUMS` | +| `docs/analysis/mhpow/b1/registry-batch-mhpow-b1-20261009-01.json` | the registry batch, rows NOT RUN, for the steward to record | + +Run everything again (a build box only, never the Mac): `tools/mhpow/b1/run-b1.sh all`. Then compare +`/SHA256SUMS` with `tools/mhpow/b1/fixtures/SHA256SUMS`. The kat, attack and k-table files must be +byte-identical. The row files and tests.log differ in their timings only. diff --git a/docs/analysis/mhpow/b1/registry-batch-mhpow-b1-20261009-01.json b/docs/analysis/mhpow/b1/registry-batch-mhpow-b1-20261009-01.json new file mode 100644 index 000000000..eccce1021 --- /dev/null +++ b/docs/analysis/mhpow/b1/registry-batch-mhpow-b1-20261009-01.json @@ -0,0 +1,32 @@ +{ + "run_id": "mhpow-b1-20261009-01", + "manifest_sha": "13c3646e", + "evidence_dir": "docs/analysis/mhpow/b1", + "method": "model", + "boxes": ["build-6"], + "note": "B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS.", + "cells": [ + { + "cell": "model:mhpow-b1-reference", + "cases": ["POW-05", "POW-06"], + "status": "NOT RUN", + "method": "model", + "evidence": "docs/analysis/mhpow/b1/README.md", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11).", + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "in_progress": true + } + ], + "map_cell_requested": { + "model:mhpow-b1-reference": { + "command": "tools/mhpow/b1/run-b1.sh all (a build box under its pid file; kat, attack and k-table files byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS)", + "box_class": "build box, CPU only (build-6)", + "fixtures": ["tools/mhpow/b1/fixtures/"], + "cases": ["POW-05", "POW-06"], + "coverage": { + "POW-05": "partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's", + "POW-06": "partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing" + } + } + } +} diff --git a/tools/ci/export-exclude.txt b/tools/ci/export-exclude.txt index 2366d9186..dfb5e185b 100644 --- a/tools/ci/export-exclude.txt +++ b/tools/ci/export-exclude.txt @@ -55,3 +55,5 @@ docs/analysis/proving-outcome-ledger.md # 9 October 2026: the 1.5x programme Track B, the B2 binding spec lane (research documents and their generator) docs/analysis/mhpow/b2 tools/mhpow/b2 +docs/analysis/mhpow/b1 +tools/mhpow/b1 diff --git a/tools/mhpow/b1/attacks.py b/tools/mhpow/b1/attacks.py new file mode 100644 index 000000000..591796d21 --- /dev/null +++ b/tools/mhpow/b1/attacks.py @@ -0,0 +1,239 @@ +"""Malicious provers against the B1 verifier. Each adversary is implemented honestly (it tries to win) and its verdict is +measured, never assumed. Sources: [DN17] Dinur and Nadler, eprint 2017/497 as archived 2026-05-09 (Sec 4.1, 4.3, 8); +[BS25] Sec 5 (LuckyQuery), Sec 7.1 (Attack 1). + +Verdict vocabulary per adversary: REFUSED (never accepted, the refusing check named) or ACCEPTED-WITH-PROBABILITY p (measured +over trials, beside the analytic value the paper's bound uses) with the exact mechanism. +""" +from __future__ import annotations + +from typing import Dict, List, Set, Tuple + +import drsample +import mtp +import params +from params import H, u64 + +D = params.DIGEST_BYTES +ZERO = b"\0" * D + + +def _chi(tag: str, j: int) -> bytes: + return H(b"B1-attack", tag.encode(), u64(j)) + + +def _respond_from(chi: bytes, n: int, k: int, par, labels, tree) -> mtp.Proof: + return mtp.respond(mtp.ProverState(chi, n, par, labels, tree), k) + + +# A1 [DN17] Sec 4.1 "A First Attack": replay a proof made for another challenge (chi') ------------------------------------------- +def a1_replay(n: int, k: int, par, trials: int) -> Dict: + acc, checks = 0, set() + for j in range(trials): + old = mtp.prove(_chi("a1-old", j), n, k, par) + r = mtp.verify(_chi("a1-new", j), n, k, old) + acc += r.accepted + checks.add(r.check) + return {"id": "A1", "source": "[DN17] Sec 4.1 first attack (proof replay across challenges)", + "mechanism": "every label, Merkle node and challenge query carries chi ([BS25] Sec 3.2): a proof for chi' opens a tree " + "whose root and challenges are bound to chi'", + "trials": trials, "accepted": acc, "refusing_checks": sorted(checks), + "verdict": "REFUSED" if acc == 0 else "ACCEPTED"} + + +# A2 [DN17] Sec 4.1 "A Second Attack": constant array committed, the challenged block not truly opened ----------------------------- +def a2_unopened_block(n: int, k: int, par, trials: int) -> Dict: + """The cheater commits to an all-constant array (no memory), then (a) answers each challenge with the label the verifier + would recompute from the opened parents but the constant array's path, or (b) opens the constant label honestly.""" + N = 1 << n + res = {} + for variant in ("a_recomputed_label", "b_constant_label"): + acc, checks = 0, set() + for j in range(trials): + chi = _chi("a2", j) + labels = [None] + [ZERO] * N + tree = mtp.MerkleTree(chi, labels, n) + proof = _respond_from(chi, n, k, par, labels, tree) + if variant == "a_recomputed_label": + for c, r in zip(mtp.challenges(chi, tree.root, k, n), proof.responses): + r.node.label = mtp.label_of(chi, c + 1, [p.label for p in r.parents]) + v = mtp.verify(chi, n, k, proof) + acc += v.accepted + checks.add(v.check) + res[variant] = {"accepted": acc, "refusing_checks": sorted(checks)} + total = sum(x["accepted"] for x in res.values()) + return {"id": "A2", "source": "[DN17] Sec 4.1 second attack (the challenged block X[i_j] not opened in MTP 1.0)", + "mechanism": "[BS25] Sec 3.2 step 3(a) opens l_{c_i+1} itself at the verifier-derived position and step 3 checks it " + "against its opened parents; the constant array is red everywhere", + "trials": trials, "variants": res, "verdict": "REFUSED" if total == 0 else "ACCEPTED"} + + +# A3 [DN17] Sec 4.3 / Sec 5 control blocks: grind control labels to steer later parents into the stored set ----------------------- +def a3_control_block_steering(n: int, k: int, par, t: int, grind: int, trials: int) -> Dict: + """[DN17] Sec 5 step 2(b): for each interval s, try control-block values X[s t] until the parents of the next t-1 blocks + fall in the stored set S_s (Eq. 5). Under Argon2d phi depends on X[i-1]; here parents() is a function of v alone, so the + attacker's grind is run and its effect measured: the fraction of intervals meeting Eq. 5 with 1 try and with `grind` tries. + Then the cheater does what [DN17] does next: stores only the control blocks, writes them as inconsistent (red) values, and + computes the rest; acceptance is measured against (1 - 1/t)^k.""" + N = 1 << n + def eq5_holds(s: int) -> bool: + base = s * t + stored = {s2 * t for s2 in range(0, s + 1)} + for l in range(1, t): + v = base + l + if v > N: + break + for u in par[v]: + if not (u in stored or base < u < v or u == v - 1): + return False + return True + intervals = range(1, N // t) + # grinding: the control block's value does not enter parents(); each "try" re-evaluates Eq. 5 on the same graph + one_try = sum(eq5_holds(s) for s in intervals) + many = 0 + for s in intervals: + ok = False + for _ in range(grind): + if eq5_holds(s): + ok = True + break + many += ok + # the fallback cheat: control nodes red (stored as attacker-chosen values), everything else honest from them + acc = 0 + red = set(range(t, N + 1, t)) + for j in range(trials): + chi = _chi("a3", j) + lab: List = [None] * (N + 1) + for v in range(1, N + 1): + lab[v] = H(b"attacker-control", chi, u64(v)) if v in red else mtp.label_of(chi, v, [lab[u] for u in par[v]]) + tree = mtp.MerkleTree(chi, lab, n) + acc += mtp.verify(chi, n, k, _respond_from(chi, n, k, par, lab, tree)).accepted + return {"id": "A3", "source": "[DN17] Sec 4.3 and Sec 5 (control blocks steering the data-dependent phi), the attack that " + "broke MTP-Argon2d", + "t": t, "grind_tries_per_control_block": grind, "intervals": len(intervals), + "eq5_intervals_met_one_try": one_try, "eq5_intervals_met_after_grind": many, + "steering_gain": many - one_try, + "fallback_red_fraction": len(red) / N, "trials": trials, "accepted": acc, + "accept_rate": acc / trials, "analytic_accept": (1 - len(red) / N) ** k, + "mechanism": "DRSample's parents(v) are fixed a priori ([ABH17] Alg. 1, public seed): no label value moves an edge, so " + "grinding has zero steering gain; what remains is a red-node cheat accepted with (1-|S|/N)^k, the " + "probability [BS25] Lemma 4 bounds", + "verdict": "STEERING REFUSED BY CONSTRUCTION; RED-NODE FALLBACK ACCEPTED WITH PROBABILITY (1-1/t)^k"} + + +# A4 [DN17] Sec 8 self-similarity: Y2 := X2 so that Y1 = X1 (copy a label to another node sharing a parent) -------------------------- +def a4_self_similarity(n: int, k: int, par, trials: int) -> Dict: + N = 1 << n + # find pairs (x, y) of nodes sharing their long-edge parent: X1 = F(X2, X3), Y1 = F(Y2, Y3) with X3 == Y3 + by_parent: Dict[int, List[int]] = {} + for v in range(3, N + 1): + by_parent.setdefault(par[v][0], []).append(v) + pairs = [(vs[0], vs[1]) for vs in by_parent.values() if len(vs) >= 2 and vs[0] + 1 < vs[1]] + equal = 0 + acc = 0 + for j in range(trials): + chi = _chi("a4", j) + lab = mtp.compute_labels(chi, par) + x, y = pairs[j % len(pairs)] + # Y2 := X2 (the predecessor of y takes the predecessor of x's label), then y is computed from it honestly + lab2 = list(lab) + lab2[y - 1] = lab[x - 1] + lab2[y] = mtp.label_of(chi, y, [lab2[u] for u in par[y]]) + equal += lab2[y] == lab[x] + tree = mtp.MerkleTree(chi, lab2, n) + acc += mtp.verify(chi, n, k, _respond_from(chi, n, k, par, lab2, tree)).accepted + return {"id": "A4", "source": "[DN17] Sec 8 (self-similarity of data-independent MTP: Y2 = X2 gives Y1 = X1)", + "pairs_available": len(pairs), "trials": trials, "copies_that_reproduced_a_label": equal, + "accepted": acc, "accept_rate": acc / trials, + "mechanism": "the node index v is inside every prelabel ([BS25] Sec 2.2; [DN17] Sec 8's HAIFA countermeasure): " + "copying X2 into Y2 never reproduces X1 at y, so nothing is saved; the one red node (y-1) is caught " + "only when challenged, as any single red node", + "verdict": "SAVING REFUSED (0 reproduced labels); ONE RED NODE ACCEPTED WITH PROBABILITY ~ (1-1/N)^k"} + + +# A5 [BS25] Sec 7.1 Attack 1: depth-reducing set S given label 0^lambda, the rest in parallel ------------------------------------- +def greedy_depth_reducing_set(par, d: int) -> Set[int]: + """Topological greedy: put v in S when its depth in G - S would exceed d. G - S then has no path longer than d.""" + n_nodes = len(par) - 1 + depth = [0] * (n_nodes + 1) + S: Set[int] = set() + for v in range(1, n_nodes + 1): + dv = 1 + max((depth[u] for u in par[v] if u not in S), default=0) + if dv > d: + S.add(v) + depth[v] = 0 + else: + depth[v] = dv + return S + + +def a5_attack1(n: int, k: int, par, d: int, trials: int) -> Dict: + N = 1 << n + S = greedy_depth_reducing_set(par, d) + depth = drsample.depth_after_removal(par, S) + acc = 0 + for j in range(trials): + chi = _chi("a5", j) + lab: List = [None] * (N + 1) + for v in range(1, N + 1): + lab[v] = ZERO if v in S else mtp.label_of(chi, v, [lab[u] for u in par[v]]) + tree = mtp.MerkleTree(chi, lab, n) + acc += mtp.verify(chi, n, k, _respond_from(chi, n, k, par, lab, tree)).accepted + return {"id": "A5", "source": "[BS25] Sec 7.1 Attack 1 (labels 0^lambda on a depth-reducing set S, G - S pebbled in parallel)", + "d_target": d, "S_size": len(S), "S_fraction": len(S) / N, "depth_G_minus_S": depth, + "parallel_rounds_bound": depth, "trials": trials, "accepted": acc, "accept_rate": acc / trials, + "analytic_accept": (1 - len(S) / N) ** k, + "mechanism": "the paper's own attack: |S| red nodes escape all k challenges with probability (1-|S|/N)^k; the " + "cheater's cumulative memory is O(N d lambda + N lambda log N) against the honest O(N^2 lambda)", + "verdict": "ACCEPTED WITH PROBABILITY (1-|S|/N)^k (as the paper states; this is what sets k)"} + + +# A6 [BS25] Sec 5 LuckyQuery: regrind the Merkle root cheaply until every challenge is green ----------------------------------------- +def a6_root_regrind(n: int, k: int, par, red_count: int, max_tries: int, trials: int) -> Dict: + """One labelling with `red_count` red nodes (the last nodes, sinks of the honest order); the cheater re-rolls tau by + rewriting the value of one red leaf (the sink, node N) and rehashing its path only: n Merkle calls + k challenge calls per + try. Measured: tries to the first accepted root, and how many distinct accepted roots one labelling yields (B2's O-07).""" + N = 1 << n + results = [] + for j in range(trials): + chi = _chi("a6", j) + lab = mtp.compute_labels(chi, par) + red = set(range(N - red_count + 1, N + 1)) + for v in red: + lab[v] = H(b"red", chi, u64(v)) + tree = mtp.MerkleTree(chi, lab, n) + p = mtp._bitrev(N - 1, n) + tries, accepted_roots, first = 0, 0, None + for g in range(max_tries): + tries += 1 + leaf = H(b"regrind", chi, u64(g)) + # rewrite leaf N-1 (node N) and its path to the root + tree.levels[n][p] = leaf + cur, pos = leaf, p + for depth in range(n, 0, -1): + sib = tree.levels[depth][pos ^ 1] + cur = mtp.merkle_node(chi, cur, sib) if pos % 2 == 0 else mtp.merkle_node(chi, sib, cur) + pos >>= 1 + tree.levels[depth - 1][pos] = cur + lab[N] = leaf + cs = mtp.challenges(chi, tree.root, k, n) + if not any((c + 1) in red for c in cs): + if first is None: + first = tries + proof = _respond_from(chi, n, k, par, lab, tree) + assert mtp.verify(chi, n, k, proof).accepted + accepted_roots += 1 + results.append({"first_accept_try": first, "accepted_roots": accepted_roots, "tries": tries}) + firsts = [r["first_accept_try"] for r in results if r["first_accept_try"] is not None] + return {"id": "A6", "source": "[BS25] Sec 5 Def. 14 and Lemma 4 (LuckyQuery, the q(1-beta)^k term); B2's O-07", + "red_count": red_count, "red_fraction": red_count / N, "k": k, "max_tries": max_tries, "trials": trials, + "per_try_oracle_calls": n + k, "trials_with_accept": len(firsts), + "mean_first_accept_try": (sum(firsts) / len(firsts)) if firsts else None, + "predicted_tries": (1 - red_count / N) ** (-k), + "accepted_roots_per_labelling": [r["accepted_roots"] for r in results], + "mechanism": "tau is a fresh oracle output per rewrite of one red leaf (n + k calls, no relabelling): with beta = " + "red fraction the expected tries are (1-beta)^-k, and with ONE red sink nearly every try is an " + "accepted root, so one labelling yields many accepted (tau, proof) pairs for one chi; the theorem's " + "cmc bound still holds per accepted proof but nothing in the primitive makes a second accepted root " + "cost a second labelling", + "verdict": "ACCEPTED (many accepted roots per labelling): a lottery over tau is not bound to the labelling cost"} diff --git a/tools/mhpow/b1/drsample.py b/tools/mhpow/b1/drsample.py new file mode 100644 index 000000000..7677be5f9 --- /dev/null +++ b/tools/mhpow/b1/drsample.py @@ -0,0 +1,87 @@ +"""DRSample, [ABH17] Algorithm 1, verbatim edge rule, derandomised by a public seed. + +[ABH17] Algorithm 1 (eprint 2017/443, Sec 3): + Function DRSample(n): V := [n]; E := {(1, 2)}; for v in [3, n] and i in [2]: E := E u {(v, GetParent(v, i))} + Function GetParent(v, i): + if i = 1 then r := 1 + else + g' <- [1, floor(log2(v)) + 1] // random range size + g := min(v - 1, 2^g') // don't make edges too long + r <- [max(g/2, 2), g] // random edge length + return v - r +Nodes are 1-indexed, node 1 is the only source, node 2 has the single parent 1, every v >= 3 has the two distinct parents +v - 1 and v - r with r >= 2. [BS25] Sec 2.2 orders parents ascending (v1 < v2), so parents(v) = (v - r, v - 1). + +Resolutions of what the pseudocode leaves open (README rows R-1, R-2): + R-1 "[max(g/2, 2), g]" with g = v - 1 odd: the integer range starts at ceil(g/2). + R-2 "<-" (uniform draw): uniform_int() below, rejection sampling over 64-bit words of H('G' || GRAPH_SEED || v || which || ctr), + so the graph is a deterministic public function of GRAPH_SEED (fixed a priori, never chi). +""" +from __future__ import annotations + +from typing import List, Tuple + +import params + +_TWO64 = 1 << 64 + + +def uniform_int(lo: int, hi: int, v: int, which: int) -> int: + """Uniform integer in [lo, hi] (inclusive) for draw `which` of node v; rejection sampling, no modulo bias.""" + m = hi - lo + 1 + if m <= 0: + raise ValueError("empty range") + if m == 1: + return lo + limit = _TWO64 - (_TWO64 % m) + ctr = 0 + while True: + d = params.H(params.TAG_GRAPH, params.GRAPH_SEED, params.u64(v), bytes([which]), params.u64(ctr)) + x = int.from_bytes(d[:8], "little") + if x < limit: + return lo + (x % m) + ctr += 1 + + +def get_parent(v: int, i: int) -> int: + """[ABH17] Alg. 1 GetParent(v, i) for v >= 3.""" + if v < 3: + raise ValueError("GetParent is defined for v >= 3; node 1 has no parent and node 2 has parent 1") + if i == 1: + r = 1 + else: + gp = uniform_int(1, v.bit_length(), v, 1) # floor(log2 v) + 1 == v.bit_length() + g = min(v - 1, 1 << gp) + r = uniform_int(max(-(-g // 2), 2), g, v, 2) # R-1: ceil(g/2) + return v - r + + +def parents(v: int) -> Tuple[int, ...]: + """parents(v, G) in ascending order ([BS25] Sec 2.2). Node 1: (); node 2: (1,); v >= 3: (v - r, v - 1).""" + if v == 1: + return () + if v == 2: + return (1,) + p2 = get_parent(v, 2) + p1 = get_parent(v, 1) + assert 1 <= p2 < p1 == v - 1 + return (p2, p1) + + +def all_parents(n_nodes: int) -> List[Tuple[int, ...]]: + """Index 0 unused; all_parents(N)[v] = parents(v) for v in 1..N.""" + return [()] + [parents(v) for v in range(1, n_nodes + 1)] + + +def depth_after_removal(par: List[Tuple[int, ...]], removed: set) -> int: + """Length (nodes) of the longest directed path in G - S ([BS25] Sec 7.1 uses this to bound parallel rounds).""" + n = len(par) - 1 + d = [0] * (n + 1) + best = 0 + for v in range(1, n + 1): + if v in removed: + continue + dv = 1 + max((d[u] for u in par[v] if u not in removed), default=0) + d[v] = dv + best = max(best, dv) + return best diff --git a/tools/mhpow/b1/fixtures/SHA256SUMS b/tools/mhpow/b1/fixtures/SHA256SUMS new file mode 100644 index 000000000..e75540fe7 --- /dev/null +++ b/tools/mhpow/b1/fixtures/SHA256SUMS @@ -0,0 +1,19 @@ +805035ebfc8d2f34441325b5d5ca46c67e81f7d0b0b86f62ba1a906964b8c51f attacks-n10-k16.json +9f85b22ae54785e0e078630f890036713cf3925b7e1345bd949c6945d2702f7f kat-n04.json +481a39fa47ff4d3393f34e15e318ee4bda7683ee457d3b9da79d277c9ba2831d kat-n04.proof.bin +2c741be9a5a7c47773f902ed024c49188eacfc84f9cabdf34244f289e77f51f7 kat-n08.json +d45a9756b8d66357eaee34f1efa3b5fc975e25fcf7b7eb5a516746c6e078bbc7 kat-n08.proof.bin +51ccacd3030d97ec371d8cc8ea64fbb362f00bd323bd84827105c89b4eb30864 kat-n12.json +3c7de0539a8715e75d3d64eb11ec3af7d8a2a338c101958a0c29e300c3ad4f7f kat-n12.proof.bin +240f50bc5ac5e12c7630f24c072bf291fb6ab9644530badcd1c41c7a7341440c kat-n16.json +793fd4d505155f133c8acf1c657a98795f29f7d6cba2568570c8324c42fb1118 kat-n16.proof.bin +fd0d75b66af9cbd9ef12e63d571036f41bdac0e1d21e1f4d98559deb98502392 kat-n20.json +a49367d9c80f0855504fe1f0994acbd5ddc4b023eaf5904a28ad5f7e71ce951c kat-n20.proof.bin +1ceca69b04d46083bf7d6d6fa51e21b7ecd49e71eb6051324a439ebcb519336a k-table.json +06f50be652157fb685e17d65853c95628c336980174b238ca8738ebe0ac0de5d k-table.log +0e9f907ed4ffca6f558988ac91066475dcf60da21a9ba3106b79d014db268178 row-n12-k64.json +0dbd2103af742b3f9bb38e679615de34f128db30baa8dd7bdc1b1eaa6c4732bc row-n16-k64.json +23e1cd2749ca933abcde77602557b6228cefc76c6776bc8370720b8bcca833dc row-n20-k64.json +21cf88c3151cb5007304bf1ba8d75764878626c2384b5471e6cc5ceb5f8aa4f4 row-n22-k64.json +48d890a92c5bda6a55ddf65e2780fec63afc7f7adc8d6143f6b6270705b68e7c row-n24-k64.json +55c663b3ab539741aad0ff97fa11a2a52308f715e0ed5047b2c2add82243f5bf tests.log diff --git a/tools/mhpow/b1/fixtures/attacks-n10-k16.json b/tools/mhpow/b1/fixtures/attacks-n10-k16.json new file mode 100644 index 000000000..c6ac60886 --- /dev/null +++ b/tools/mhpow/b1/fixtures/attacks-n10-k16.json @@ -0,0 +1,177 @@ +[ + { + "accepted": 0, + "id": "A1", + "mechanism": "every label, Merkle node and challenge query carries chi ([BS25] Sec 3.2): a proof for chi' opens a tree whose root and challenges are bound to chi'", + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "refusing_checks": [ + "check_2a_parent_set", + "check_2b_merkle_openings" + ], + "source": "[DN17] Sec 4.1 first attack (proof replay across challenges)", + "trials": 50, + "verdict": "REFUSED" + }, + { + "id": "A2", + "mechanism": "[BS25] Sec 3.2 step 3(a) opens l_{c_i+1} itself at the verifier-derived position and step 3 checks it against its opened parents; the constant array is red everywhere", + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "source": "[DN17] Sec 4.1 second attack (the challenged block X[i_j] not opened in MTP 1.0)", + "trials": 50, + "variants": { + "a_recomputed_label": { + "accepted": 0, + "refusing_checks": [ + "check_2b_merkle_openings" + ] + }, + "b_constant_label": { + "accepted": 0, + "refusing_checks": [ + "check_3_local_consistency" + ] + } + }, + "verdict": "REFUSED" + }, + { + "accept_rate": 0.4775, + "accepted": 191, + "analytic_accept": 0.44157668828816804, + "eq5_intervals_met_after_grind": 0, + "eq5_intervals_met_one_try": 0, + "fallback_red_fraction": 0.0498046875, + "grind_tries_per_control_block": 1000, + "id": "A3", + "intervals": 50, + "mechanism": "DRSample's parents(v) are fixed a priori ([ABH17] Alg. 1, public seed): no label value moves an edge, so grinding has zero steering gain; what remains is a red-node cheat accepted with (1-|S|/N)^k, the probability [BS25] Lemma 4 bounds", + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "source": "[DN17] Sec 4.3 and Sec 5 (control blocks steering the data-dependent phi), the attack that broke MTP-Argon2d", + "steering_gain": 0, + "t": 20, + "trials": 400, + "verdict": "STEERING REFUSED BY CONSTRUCTION; RED-NODE FALLBACK ACCEPTED WITH PROBABILITY (1-1/t)^k" + }, + { + "accept_rate": 0.945, + "accepted": 189, + "copies_that_reproduced_a_label": 0, + "id": "A4", + "mechanism": "the node index v is inside every prelabel ([BS25] Sec 2.2; [DN17] Sec 8's HAIFA countermeasure): copying X2 into Y2 never reproduces X1 at y, so nothing is saved; the one red node (y-1) is caught only when challenged, as any single red node", + "pairs_available": 253, + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "source": "[DN17] Sec 8 (self-similarity of data-independent MTP: Y2 = X2 gives Y1 = X1)", + "trials": 200, + "verdict": "SAVING REFUSED (0 reproduced labels); ONE RED NODE ACCEPTED WITH PROBABILITY ~ (1-1/N)^k" + }, + { + "S_fraction": 0.2216796875, + "S_size": 227, + "accept_rate": 0.015, + "accepted": 6, + "analytic_accept": 0.01813567966356165, + "d_target": 64, + "depth_G_minus_S": 64, + "id": "A5", + "mechanism": "the paper's own attack: |S| red nodes escape all k challenges with probability (1-|S|/N)^k; the cheater's cumulative memory is O(N d lambda + N lambda log N) against the honest O(N^2 lambda)", + "parallel_rounds_bound": 64, + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "source": "[BS25] Sec 7.1 Attack 1 (labels 0^lambda on a depth-reducing set S, G - S pebbled in parallel)", + "trials": 400, + "verdict": "ACCEPTED WITH PROBABILITY (1-|S|/N)^k (as the paper states; this is what sets k)" + }, + { + "S_fraction": 0.1513671875, + "S_size": 155, + "accept_rate": 0.065, + "accepted": 26, + "analytic_accept": 0.07236309223391428, + "d_target": 256, + "depth_G_minus_S": 256, + "id": "A5", + "mechanism": "the paper's own attack: |S| red nodes escape all k challenges with probability (1-|S|/N)^k; the cheater's cumulative memory is O(N d lambda + N lambda log N) against the honest O(N^2 lambda)", + "parallel_rounds_bound": 256, + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "source": "[BS25] Sec 7.1 Attack 1 (labels 0^lambda on a depth-reducing set S, G - S pebbled in parallel)", + "trials": 400, + "verdict": "ACCEPTED WITH PROBABILITY (1-|S|/N)^k (as the paper states; this is what sets k)" + }, + { + "accepted_roots_per_labelling": [ + 193, + 199, + 198, + 200, + 195 + ], + "id": "A6", + "k": 16, + "max_tries": 200, + "mean_first_accept_try": 1.2, + "mechanism": "tau is a fresh oracle output per rewrite of one red leaf (n + k calls, no relabelling): with beta = red fraction the expected tries are (1-beta)^-k, and with ONE red sink nearly every try is an accepted root, so one labelling yields many accepted (tau, proof) pairs for one chi; the theorem's cmc bound still holds per accepted proof but nothing in the primitive makes a second accepted root cost a second labelling", + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "per_try_oracle_calls": 26, + "predicted_tries": 1.0157554632052712, + "red_count": 1, + "red_fraction": 0.0009765625, + "source": "[BS25] Sec 5 Def. 14 and Lemma 4 (LuckyQuery, the q(1-beta)^k term); B2's O-07", + "trials": 5, + "trials_with_accept": 5, + "verdict": "ACCEPTED (many accepted roots per labelling): a lottery over tau is not bound to the labelling cost" + }, + { + "accepted_roots_per_labelling": [ + 140, + 146, + 140, + 151, + 152 + ], + "id": "A6", + "k": 16, + "max_tries": 400, + "mean_first_accept_try": 1.6, + "mechanism": "tau is a fresh oracle output per rewrite of one red leaf (n + k calls, no relabelling): with beta = red fraction the expected tries are (1-beta)^-k, and with ONE red sink nearly every try is an accepted root, so one labelling yields many accepted (tau, proof) pairs for one chi; the theorem's cmc bound still holds per accepted proof but nothing in the primitive makes a second accepted root cost a second labelling", + "params": { + "N": 1024, + "k": 16, + "n": 10 + }, + "per_try_oracle_calls": 26, + "predicted_tries": 2.808403965576447, + "red_count": 64, + "red_fraction": 0.0625, + "source": "[BS25] Sec 5 Def. 14 and Lemma 4 (LuckyQuery, the q(1-beta)^k term); B2's O-07", + "trials": 5, + "trials_with_accept": 5, + "verdict": "ACCEPTED (many accepted roots per labelling): a lottery over tau is not bound to the labelling cost" + } +] \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/k-table.json b/tools/mhpow/b1/fixtures/k-table.json new file mode 100644 index 000000000..76fe4b87b --- /dev/null +++ b/tools/mhpow/b1/fixtures/k-table.json @@ -0,0 +1,249 @@ +[ + { + "N": 4096, + "d_ABH17": 122.88, + "e_ABH17": 0.082944, + "k_cor2": 17525500, + "k_over_N": 4278.6865234375, + "label_array_bytes": 131072, + "lambda": 256, + "n": 12, + "proof_bytes": 21889349545, + "proof_over_label_array": 167002.48371124268, + "table": "proven" + }, + { + "N": 65536, + "d_ABH17": 1966.08, + "e_ABH17": 0.995328, + "k_cor2": 23367333, + "k_over_N": 356.5572052001953, + "label_array_bytes": 2097152, + "lambda": 256, + "n": 16, + "proof_bytes": 38158854834, + "proof_over_label_array": 18195.55989933014, + "table": "proven" + }, + { + "N": 1048576, + "d_ABH17": 31457.28, + "e_ABH17": 12.7401984, + "k_cor2": 29209166, + "k_over_N": 27.85603141784668, + "label_array_bytes": 33554432, + "lambda": 256, + "n": 20, + "proof_bytes": 58914887867, + "proof_over_label_array": 1755.800481647253, + "table": "proven" + }, + { + "N": 4194304, + "d_ABH17": 125829.12, + "e_ABH17": 46.327994181818184, + "k_cor2": 32130082, + "k_over_N": 7.6604084968566895, + "label_array_bytes": 134217728, + "lambda": 256, + "n": 22, + "proof_bytes": 70975351183, + "proof_over_label_array": 528.8075743839145, + "table": "proven" + }, + { + "N": 16777216, + "d_ABH17": 503316.48, + "e_ABH17": 169.869312, + "k_cor2": 35050999, + "k_over_N": 2.089202344417572, + "label_array_bytes": 536870912, + "lambda": 256, + "n": 24, + "proof_bytes": 84157448644, + "proof_over_label_array": 156.75546348839998, + "table": "proven" + }, + { + "N": 1073741824, + "d_ABH17": 32212254.72, + "e_ABH17": 8697.3087744, + "k_cor2": 43813748, + "k_over_N": 0.04080473259091377, + "label_array_bytes": 34359738368, + "lambda": 256, + "n": 30, + "proof_bytes": 130433527841, + "proof_over_label_array": 3.7961152801581193, + "table": "proven" + }, + { + "N": 4294967296, + "d_ABH17": 128849018.88, + "e_ABH17": 32614.907904, + "k_cor2": 46734665, + "k_over_N": 0.010881262132897973, + "label_array_bytes": 137438953472, + "lambda": 256, + "n": 32, + "proof_bytes": 148102153430, + "proof_over_label_array": 1.0775849909259705, + "table": "proven" + }, + { + "N": 4096, + "S": 655, + "beta": 0.159912109375, + "cheater_parallel_rounds": 1024, + "d": 1024, + "k_for_2^-128": 510, + "k_for_2^-40": 160, + "n": 12, + "proof_bytes_2^-128": 637035, + "proof_bytes_2^-40": 199885, + "table": "attack1-greedy" + }, + { + "N": 4096, + "S": 900, + "beta": 0.2197265625, + "cheater_parallel_rounds": 256, + "d": 256, + "k_for_2^-128": 358, + "k_for_2^-40": 112, + "n": 12, + "proof_bytes_2^-128": 447187, + "proof_bytes_2^-40": 139933, + "table": "attack1-greedy" + }, + { + "N": 4096, + "S": 964, + "beta": 0.2353515625, + "cheater_parallel_rounds": 64, + "d": 64, + "k_for_2^-128": 331, + "k_for_2^-40": 104, + "n": 12, + "proof_bytes_2^-128": 413464, + "proof_bytes_2^-40": 129941, + "table": "attack1-greedy" + }, + { + "N": 4096, + "S": 1090, + "beta": 0.26611328125, + "cheater_parallel_rounds": 16, + "d": 16, + "k_for_2^-128": 287, + "k_for_2^-40": 90, + "n": 12, + "proof_bytes_2^-128": 358508, + "proof_bytes_2^-40": 112455, + "table": "attack1-greedy" + }, + { + "N": 65536, + "S": 10582, + "beta": 0.161468505859375, + "cheater_parallel_rounds": 16384, + "d": 16384, + "k_for_2^-128": 504, + "k_for_2^-40": 158, + "n": 16, + "proof_bytes_2^-128": 823077, + "proof_bytes_2^-40": 258059, + "table": "attack1-greedy" + }, + { + "N": 65536, + "S": 14404, + "beta": 0.21978759765625, + "cheater_parallel_rounds": 4096, + "d": 4096, + "k_for_2^-128": 358, + "k_for_2^-40": 112, + "n": 16, + "proof_bytes_2^-128": 584659, + "proof_bytes_2^-40": 182941, + "table": "attack1-greedy" + }, + { + "N": 65536, + "S": 15375, + "beta": 0.2346038818359375, + "cheater_parallel_rounds": 1024, + "d": 1024, + "k_for_2^-128": 332, + "k_for_2^-40": 104, + "n": 16, + "proof_bytes_2^-128": 542201, + "proof_bytes_2^-40": 169877, + "table": "attack1-greedy" + }, + { + "N": 65536, + "S": 15745, + "beta": 0.2402496337890625, + "cheater_parallel_rounds": 256, + "d": 256, + "k_for_2^-128": 323, + "k_for_2^-40": 101, + "n": 16, + "proof_bytes_2^-128": 527504, + "proof_bytes_2^-40": 164978, + "table": "attack1-greedy" + }, + { + "N": 1048576, + "S": 176424, + "beta": 0.16825103759765625, + "cheater_parallel_rounds": 262144, + "d": 262144, + "k_for_2^-128": 482, + "k_for_2^-40": 151, + "n": 20, + "proof_bytes_2^-128": 972239, + "proof_bytes_2^-40": 304612, + "table": "attack1-greedy" + }, + { + "N": 1048576, + "S": 232446, + "beta": 0.2216777801513672, + "cheater_parallel_rounds": 65536, + "d": 65536, + "k_for_2^-128": 355, + "k_for_2^-40": 111, + "n": 20, + "proof_bytes_2^-128": 716080, + "proof_bytes_2^-40": 223932, + "table": "attack1-greedy" + }, + { + "N": 1048576, + "S": 249184, + "beta": 0.237640380859375, + "cheater_parallel_rounds": 16384, + "d": 16384, + "k_for_2^-128": 327, + "k_for_2^-40": 103, + "n": 20, + "proof_bytes_2^-128": 659604, + "proof_bytes_2^-40": 207796, + "table": "attack1-greedy" + }, + { + "N": 1048576, + "S": 253922, + "beta": 0.2421588897705078, + "cheater_parallel_rounds": 4096, + "d": 4096, + "k_for_2^-128": 320, + "k_for_2^-40": 100, + "n": 20, + "proof_bytes_2^-128": 645485, + "proof_bytes_2^-40": 201745, + "table": "attack1-greedy" + } +] \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/k-table.log b/tools/mhpow/b1/fixtures/k-table.log new file mode 100644 index 000000000..abc072a2d --- /dev/null +++ b/tools/mhpow/b1/fixtures/k-table.log @@ -0,0 +1,19 @@ +{"table": "attack1-greedy", "n": 12, "N": 4096, "d": 1024, "S": 655, "beta": 0.159912109375, "k_for_2^-40": 160, "proof_bytes_2^-40": 199885, "k_for_2^-128": 510, "proof_bytes_2^-128": 637035, "cheater_parallel_rounds": 1024} +{"table": "attack1-greedy", "n": 12, "N": 4096, "d": 256, "S": 900, "beta": 0.2197265625, "k_for_2^-40": 112, "proof_bytes_2^-40": 139933, "k_for_2^-128": 358, "proof_bytes_2^-128": 447187, "cheater_parallel_rounds": 256} +{"table": "attack1-greedy", "n": 12, "N": 4096, "d": 64, "S": 964, "beta": 0.2353515625, "k_for_2^-40": 104, "proof_bytes_2^-40": 129941, "k_for_2^-128": 331, "proof_bytes_2^-128": 413464, "cheater_parallel_rounds": 64} +{"table": "attack1-greedy", "n": 12, "N": 4096, "d": 16, "S": 1090, "beta": 0.26611328125, "k_for_2^-40": 90, "proof_bytes_2^-40": 112455, "k_for_2^-128": 287, "proof_bytes_2^-128": 358508, "cheater_parallel_rounds": 16} +{"table": "attack1-greedy", "n": 16, "N": 65536, "d": 16384, "S": 10582, "beta": 0.161468505859375, "k_for_2^-40": 158, "proof_bytes_2^-40": 258059, "k_for_2^-128": 504, "proof_bytes_2^-128": 823077, "cheater_parallel_rounds": 16384} +{"table": "attack1-greedy", "n": 16, "N": 65536, "d": 4096, "S": 14404, "beta": 0.21978759765625, "k_for_2^-40": 112, "proof_bytes_2^-40": 182941, "k_for_2^-128": 358, "proof_bytes_2^-128": 584659, "cheater_parallel_rounds": 4096} +{"table": "attack1-greedy", "n": 16, "N": 65536, "d": 1024, "S": 15375, "beta": 0.2346038818359375, "k_for_2^-40": 104, "proof_bytes_2^-40": 169877, "k_for_2^-128": 332, "proof_bytes_2^-128": 542201, "cheater_parallel_rounds": 1024} +{"table": "attack1-greedy", "n": 16, "N": 65536, "d": 256, "S": 15745, "beta": 0.2402496337890625, "k_for_2^-40": 101, "proof_bytes_2^-40": 164978, "k_for_2^-128": 323, "proof_bytes_2^-128": 527504, "cheater_parallel_rounds": 256} +{"table": "attack1-greedy", "n": 20, "N": 1048576, "d": 262144, "S": 176424, "beta": 0.16825103759765625, "k_for_2^-40": 151, "proof_bytes_2^-40": 304612, "k_for_2^-128": 482, "proof_bytes_2^-128": 972239, "cheater_parallel_rounds": 262144} +{"table": "attack1-greedy", "n": 20, "N": 1048576, "d": 65536, "S": 232446, "beta": 0.2216777801513672, "k_for_2^-40": 111, "proof_bytes_2^-40": 223932, "k_for_2^-128": 355, "proof_bytes_2^-128": 716080, "cheater_parallel_rounds": 65536} +{"table": "attack1-greedy", "n": 20, "N": 1048576, "d": 16384, "S": 249184, "beta": 0.237640380859375, "k_for_2^-40": 103, "proof_bytes_2^-40": 207796, "k_for_2^-128": 327, "proof_bytes_2^-128": 659604, "cheater_parallel_rounds": 16384} +{"table": "attack1-greedy", "n": 20, "N": 1048576, "d": 4096, "S": 253922, "beta": 0.2421588897705078, "k_for_2^-40": 100, "proof_bytes_2^-40": 201745, "k_for_2^-128": 320, "proof_bytes_2^-128": 645485, "cheater_parallel_rounds": 4096} +{"table": "proven", "n": 12, "N": 4096, "lambda": 256, "e_ABH17": 0.082944, "d_ABH17": 122.88, "k_cor2": 17525500, "k_over_N": 4278.6865234375, "proof_bytes": 21889349545, "label_array_bytes": 131072, "proof_over_label_array": 167002.48371124268} +{"table": "proven", "n": 16, "N": 65536, "lambda": 256, "e_ABH17": 0.995328, "d_ABH17": 1966.08, "k_cor2": 23367333, "k_over_N": 356.5572052001953, "proof_bytes": 38158854834, "label_array_bytes": 2097152, "proof_over_label_array": 18195.55989933014} +{"table": "proven", "n": 20, "N": 1048576, "lambda": 256, "e_ABH17": 12.7401984, "d_ABH17": 31457.28, "k_cor2": 29209166, "k_over_N": 27.85603141784668, "proof_bytes": 58914887867, "label_array_bytes": 33554432, "proof_over_label_array": 1755.800481647253} +{"table": "proven", "n": 22, "N": 4194304, "lambda": 256, "e_ABH17": 46.327994181818184, "d_ABH17": 125829.12, "k_cor2": 32130082, "k_over_N": 7.6604084968566895, "proof_bytes": 70975351183, "label_array_bytes": 134217728, "proof_over_label_array": 528.8075743839145} +{"table": "proven", "n": 24, "N": 16777216, "lambda": 256, "e_ABH17": 169.869312, "d_ABH17": 503316.48, "k_cor2": 35050999, "k_over_N": 2.089202344417572, "proof_bytes": 84157448644, "label_array_bytes": 536870912, "proof_over_label_array": 156.75546348839998} +{"table": "proven", "n": 30, "N": 1073741824, "lambda": 256, "e_ABH17": 8697.3087744, "d_ABH17": 32212254.72, "k_cor2": 43813748, "k_over_N": 0.04080473259091377, "proof_bytes": 130433527841, "label_array_bytes": 34359738368, "proof_over_label_array": 3.7961152801581193} +{"table": "proven", "n": 32, "N": 4294967296, "lambda": 256, "e_ABH17": 32614.907904, "d_ABH17": 128849018.88, "k_cor2": 46734665, "k_over_N": 0.010881262132897973, "proof_bytes": 148102153430, "label_array_bytes": 137438953472, "proof_over_label_array": 1.0775849909259705} diff --git a/tools/mhpow/b1/fixtures/kat-n04.json b/tools/mhpow/b1/fixtures/kat-n04.json new file mode 100644 index 000000000..ecba0b070 --- /dev/null +++ b/tools/mhpow/b1/fixtures/kat-n04.json @@ -0,0 +1,118 @@ +{ + "N": 16, + "challenges_c_i": [ + 12, + 7, + 2, + 15, + 6, + 3, + 4, + 9 + ], + "chi": "75168b68af436370850fc257391cca6e142b1fd979759f6b2f9e0ae4d5152684", + "construction": "[BS25] Sec 3.2 over [ABH17] Alg. 1 DRSample; encoding params.py", + "fixture": "kat-n04", + "graph_parents_u64le_sha256": "047a39399e002b1a969c6e29cd0de1d0e992a2bb1aee3929564f0f657e36511d", + "graph_seed": "9f25395581b8a72f3e17a812fede366102eba1dbd75cb3a02ad8054d5d79af2d", + "hash": "BLAKE2b-256 unkeyed", + "k": 8, + "labels": { + "1": "0b9342b619f347666d15b082f64efd1f91f67a56e9c46f000ce39a75ceb7ebb7", + "10": "343b493d7e88e4f1f1f868d983a60058238ad94bb4590f54033e12ccb6d9e642", + "11": "9a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e30", + "12": "1db94fc0e7c14fa7afcc7f5c99885ab95f4e95d9f316512956064d0fefc66a8a", + "13": "6fd42d129cbedae49af0fb5d5d41bd1a53a1f3bfd87524b8a73440a6a9cc0401", + "14": "29fc1a8d5c3789b6940a1b04c3e14199de572013ae9063d2c41b6aa9472ee02b", + "15": "e4042c7232f1271f9cc43695981e21d3901b835871982387b80165e968b76339", + "16": "9e7b194961681e542d0472ab6499078214967182ab7db92538090e6f611e33c1", + "2": "fc9c52cca417d6cd4d95fd7d55dbf28cb1d75b208dcba27569eebf8942ad82f2", + "3": "9fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69", + "4": "d7d0d9587db85d7a290b55f8e0c3b7175e05fe24378ad275edcfb4a5f8115596", + "5": "3db654ab23b3aee4bdf3cec1db9f272d30ddb14385dd410e973a0844919b0be6", + "6": "cb34e3a84e963b79162aa1594d07412e7bf7571d1002384d49f7f78f7713e434", + "7": "ccca11bd463b7851f1ca9660b1de2291ea777e956055922672e6f83bca1fa3c4", + "8": "d3709c943267a1a2d610c7ea0708b49b0a295647b4d20c9dc7c4bfb7ec535382", + "9": "a8daef8534d21139b1125a2388c9dd1086c76452fe0ccb3abf76a3566198145b" + }, + "labels_concat_sha256": "eb2956617e73418eb49261317e01e26249c47552edcb951e194489879331548e", + "lambda_bits": 256, + "n": 4, + "parents": { + "1": [], + "10": [ + 2, + 9 + ], + "11": [ + 3, + 10 + ], + "12": [ + 5, + 11 + ], + "13": [ + 9, + 12 + ], + "14": [ + 12, + 13 + ], + "15": [ + 13, + 14 + ], + "16": [ + 3, + 15 + ], + "2": [ + 1 + ], + "3": [ + 1, + 2 + ], + "4": [ + 2, + 3 + ], + "5": [ + 3, + 4 + ], + "6": [ + 4, + 5 + ], + "7": [ + 5, + 6 + ], + "8": [ + 3, + 7 + ], + "9": [ + 1, + 8 + ] + }, + "proof_bytes": 3893, + "proof_hex": "42314d545044523104080000009f98a28d3d84dbdcf48e3052ba873eb5cf84e7e19013c13b880f86b8eb2767046fd42d129cbedae49af0fb5d5d41bd1a53a1f3bfd87524b8a73440a6a9cc0401896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e649b88b4924261f1094fc39e34301d7b4fdedd30f44e6bec31c88c395c789536903db654ab23b3aee4bdf3cec1db9f272d30ddb14385dd410e973a0844919b0be602a8daef8534d21139b1125a2388c9dd1086c76452fe0ccb3abf76a3566198145b896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e64796f67292e8caa8d841ec8b7958073ef514bb73ae5b19297fe6b29c8d87cabcb0b9342b619f347666d15b082f64efd1f91f67a56e9c46f000ce39a75ceb7ebb71db94fc0e7c14fa7afcc7f5c99885ab95f4e95d9f316512956064d0fefc66a8a92c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cfcda953bd597f23008b45756f2c1b7f101e9325d541d6ae6fa97321630531b2b969f0e8939ac0820f25a2f856a053ce0ca5092c22cb0a357017ed1c6157f1842dd7d0d9587db85d7a290b55f8e0c3b7175e05fe24378ad275edcfb4a5f8115596d3709c943267a1a2d610c7ea0708b49b0a295647b4d20c9dc7c4bfb7ec53538292c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cfcda953bd597f23008b45756f2c1b7f101e9325d541d6ae6fa97321630531b2b9fac8fa6fd0bbb96af5e54337492a042b60b86c7e07cc88695205e94fb48f75429e7b194961681e542d0472ab6499078214967182ab7db92538090e6f611e33c1029fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e5194b398a0f369ad7b00f6436fac769c3c350018916d1fba533fa5e4d8725e7909a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e30ccca11bd463b7851f1ca9660b1de2291ea777e956055922672e6f83bca1fa3c4896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e58fa447d0d961410ccec5d524e4bd9af83ffc76212c9bdaa5c93320db318744c1e4042c7232f1271f9cc43695981e21d3901b835871982387b80165e968b763399fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e5194b398a0f369ad7b00f6436fac769c3c350018916d1fba533fa5e4d8725e7909a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e30020b9342b619f347666d15b082f64efd1f91f67a56e9c46f000ce39a75ceb7ebb7896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e64796f67292e8caa8d841ec8b7958073ef514bb73ae5b19297fe6b29c8d87cabcba8daef8534d21139b1125a2388c9dd1086c76452fe0ccb3abf76a3566198145bfc9c52cca417d6cd4d95fd7d55dbf28cb1d75b208dcba27569eebf8942ad82f292c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cf206d957e5c65468217cd4fd465c03e742fb47ffd03b00f519f62da3ffb9c1f499e5a22a2279bc548e2134ca0f39f4c656f12ade3d176bddc8dbc419b99d6686c343b493d7e88e4f1f1f868d983a60058238ad94bb4590f54033e12ccb6d9e6429e7b194961681e542d0472ab6499078214967182ab7db92538090e6f611e33c192c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cfcda953bd597f23008b45756f2c1b7f101e9325d541d6ae6fa97321630531b2b9fac8fa6fd0bbb96af5e54337492a042b60b86c7e07cc88695205e94fb48f7542d3709c943267a1a2d610c7ea0708b49b0a295647b4d20c9dc7c4bfb7ec535382029fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e5194b398a0f369ad7b00f6436fac769c3c350018916d1fba533fa5e4d8725e7909a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e30e4042c7232f1271f9cc43695981e21d3901b835871982387b80165e968b76339896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e58fa447d0d961410ccec5d524e4bd9af83ffc76212c9bdaa5c93320db318744c1ccca11bd463b7851f1ca9660b1de2291ea777e956055922672e6f83bca1fa3c4ccca11bd463b7851f1ca9660b1de2291ea777e956055922672e6f83bca1fa3c4896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e58fa447d0d961410ccec5d524e4bd9af83ffc76212c9bdaa5c93320db318744c1e4042c7232f1271f9cc43695981e21d3901b835871982387b80165e968b76339023db654ab23b3aee4bdf3cec1db9f272d30ddb14385dd410e973a0844919b0be6896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e649b88b4924261f1094fc39e34301d7b4fdedd30f44e6bec31c88c395c789536906fd42d129cbedae49af0fb5d5d41bd1a53a1f3bfd87524b8a73440a6a9cc0401cb34e3a84e963b79162aa1594d07412e7bf7571d1002384d49f7f78f7713e43492c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cf206d957e5c65468217cd4fd465c03e742fb47ffd03b00f519f62da3ffb9c1f4960b8eb6bcc4521e29af5c966e599ccfab145c25e54cf2f34af9fe5d5e90fc9a129fc1a8d5c3789b6940a1b04c3e14199de572013ae9063d2c41b6aa9472ee02bd7d0d9587db85d7a290b55f8e0c3b7175e05fe24378ad275edcfb4a5f811559692c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cfcda953bd597f23008b45756f2c1b7f101e9325d541d6ae6fa97321630531b2b969f0e8939ac0820f25a2f856a053ce0ca5092c22cb0a357017ed1c6157f1842d1db94fc0e7c14fa7afcc7f5c99885ab95f4e95d9f316512956064d0fefc66a8a02fc9c52cca417d6cd4d95fd7d55dbf28cb1d75b208dcba27569eebf8942ad82f292c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cf206d957e5c65468217cd4fd465c03e742fb47ffd03b00f519f62da3ffb9c1f499e5a22a2279bc548e2134ca0f39f4c656f12ade3d176bddc8dbc419b99d6686c343b493d7e88e4f1f1f868d983a60058238ad94bb4590f54033e12ccb6d9e6429fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e5194b398a0f369ad7b00f6436fac769c3c350018916d1fba533fa5e4d8725e7909a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e303db654ab23b3aee4bdf3cec1db9f272d30ddb14385dd410e973a0844919b0be6896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e649b88b4924261f1094fc39e34301d7b4fdedd30f44e6bec31c88c395c789536906fd42d129cbedae49af0fb5d5d41bd1a53a1f3bfd87524b8a73440a6a9cc0401029fbd50d907752c5737783220689efd6e0a4e5c65b79daa4f93a86c80c89aed69896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b33656c23e081cf9973bb458aa30657a0d362075176971e92cbe08ed23bb153e5194b398a0f369ad7b00f6436fac769c3c350018916d1fba533fa5e4d8725e7909a00da7b646ee6b2033ce775818d0b16188b8da7f5adcb77d5256f4373a19e30d7d0d9587db85d7a290b55f8e0c3b7175e05fe24378ad275edcfb4a5f811559692c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cfcda953bd597f23008b45756f2c1b7f101e9325d541d6ae6fa97321630531b2b969f0e8939ac0820f25a2f856a053ce0ca5092c22cb0a357017ed1c6157f1842d1db94fc0e7c14fa7afcc7f5c99885ab95f4e95d9f316512956064d0fefc66a8a343b493d7e88e4f1f1f868d983a60058238ad94bb4590f54033e12ccb6d9e64292c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cf206d957e5c65468217cd4fd465c03e742fb47ffd03b00f519f62da3ffb9c1f499e5a22a2279bc548e2134ca0f39f4c656f12ade3d176bddc8dbc419b99d6686cfc9c52cca417d6cd4d95fd7d55dbf28cb1d75b208dcba27569eebf8942ad82f202fc9c52cca417d6cd4d95fd7d55dbf28cb1d75b208dcba27569eebf8942ad82f292c3a19a0029085cb228fe9f0b1f807178184bce0a9add7e70471b178d6517cf206d957e5c65468217cd4fd465c03e742fb47ffd03b00f519f62da3ffb9c1f499e5a22a2279bc548e2134ca0f39f4c656f12ade3d176bddc8dbc419b99d6686c343b493d7e88e4f1f1f868d983a60058238ad94bb4590f54033e12ccb6d9e642a8daef8534d21139b1125a2388c9dd1086c76452fe0ccb3abf76a3566198145b896d5ce75908cff5f77cb436a14062180ad4025d85bba904710e1019455bca3b5f0451a5aefd1326e96ff26bf16e4e343a0978190f9f864e28d293d024611e64796f67292e8caa8d841ec8b7958073ef514bb73ae5b19297fe6b29c8d87cabcb0b9342b619f347666d15b082f64efd1f91f67a56e9c46f000ce39a75ceb7ebb7", + "proof_sha256": "481a39fa47ff4d3393f34e15e318ee4bda7683ee457d3b9da79d277c9ba2831d", + "tags": { + "challenge": "C", + "graph": "G", + "label": "L", + "merkle": "M" + }, + "tau": "9f98a28d3d84dbdcf48e3052ba873eb5cf84e7e19013c13b880f86b8eb276704", + "verifier": { + "accepted": true, + "check": "accept", + "oracle_calls": 112 + } +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/kat-n04.proof.bin b/tools/mhpow/b1/fixtures/kat-n04.proof.bin new file mode 100644 index 0000000000000000000000000000000000000000..8639f9d6aaf1cb3e0d1707eb52402ff8032b69de GIT binary patch literal 3893 zcmZ=V^bHAc2{L5iU|?XFKVwm^ZOiRDU-}G!cD37WJ>T;D;RNA>)*bw9J6@}&v*cgV z6`Hf}){|Kue#gc-?v)B&_<8@0Qk5OcO&pf3Jj24+nH%#wlH>f>?=@S@7CIzJa9v@F zZQZ?+rI1fR(lz>&bv#Sp(sh4@)n4X*%Kn(=XJW-!A;~|#%}?Xf|tH_LnUVOPnDRO{oJb^V2o; zdRFze$eq|ewW0WZp!asGryD0t|Cgh8o`|ItpJN*wlKj^=F{h9ihnH^C(XEA7U z#B9>|H=kR+p|C>2`yAJ-yLAQb(&D|T;^)t<4Bi`AuguWxTAHsTT`wRvS@o*pwRQO` zixrbu4L9w~{P1G(tOHH_s*8SvEeJlxvy@Xu=`@#Vf%sdQ#PE+Ty4Nqn!xc_>>OKWb7_XTZ@I)X_xO?h z+usBSH&N=oUnhR$U)a4f>+4fzb5AW6?SvgUb?j$4GJ{xO`fuqkb(&W#>6w@z7oy8j zv^r%bdy~kt!lu==J5?<>`SKIxj1Mx+-y3j~y;LXMyuwH!W8U99F29)6?Q>W8PhOGJ zaAMZmOhOTCoSLKjpz-|7;@z%Yi`l{#Tux#SESoMj>GXrXOV%5MpGtaLcJZ6dy1s!w z#q8Jd%)^HR7(2x-{$6VQE6%rF_4$NZ47aLN@}6yCws~IK*vl;@(cQcJ>)O-hS5@Lgh`_|Hv#tOF$+g%PmVbLiv`lv2H=ZM+V8FGr3CrCF(6wXj?-@%yr zGGlwPfqJ?BL!EmEI-)Z>w` z&w|hMeNyv<);_*iw)al&9>>`;uVv(zSbN&mbv*g_@khqZ=4A{K%3U|Tw?y)XFxv^8 z*>>|8!5l=$eS}IFLOGaF2{Pz&FrgeoC;<{GVF=}5LL~?xd0M-VQ1~zrs-y`ykWdaL z)JP!INI7ltc!l3I>q;@Lg^|AOj(XMK!(|1SEPOq`fA23Bequr>hY-ra2|HeApK(=u zH0$fhw5K!A{MzVxC@$o@zRCLePp`h@Ke_y;Uuj2-L1{w54^kB~+gz9KQIharhL#T~F WD1#3A989PYMrjp7s1Zo05efj8EH;b) literal 0 HcmV?d00001 diff --git a/tools/mhpow/b1/fixtures/kat-n08.json b/tools/mhpow/b1/fixtures/kat-n08.json new file mode 100644 index 000000000..2ebff4a0a --- /dev/null +++ b/tools/mhpow/b1/fixtures/kat-n08.json @@ -0,0 +1,1374 @@ +{ + "N": 256, + "challenges_c_i": [ + 86, + 56, + 218, + 41, + 28, + 161, + 78, + 65, + 220, + 16, + 149, + 61, + 181, + 159, + 206, + 106, + 236, + 177, + 36, + 215, + 110, + 109, + 215, + 154, + 98, + 51, + 225, + 23, + 155, + 157, + 220, + 4, + 28, + 135, + 102, + 173, + 19, + 248, + 233, + 57, + 65, + 87, + 109, + 234, + 78, + 139, + 2, + 29, + 36, + 170, + 100, + 152, + 153, + 134, + 31, + 189, + 110, + 133, + 206, + 140, + 160, + 204, + 71, + 52 + ], + "chi": "c4cc6a434c736b0783cf2ea81a15c8184876095554dc90fbcbd1a5d3dfd70e0d", + "construction": "[BS25] Sec 3.2 over [ABH17] Alg. 1 DRSample; encoding params.py", + "fixture": "kat-n08", + "graph_parents_u64le_sha256": "4cc50712a6ef808c0a0254ac2b9f6cd6a5cc08003c262086c4e9fe1312c05133", + "graph_seed": "9f25395581b8a72f3e17a812fede366102eba1dbd75cb3a02ad8054d5d79af2d", + "hash": "BLAKE2b-256 unkeyed", + "k": 64, + "labels": { + "1": "2c980288e2b82cc321c0645de9c9a068ec509c7788c5787a598098b42f098b1a", + "10": "2ee94829270489e2789e6c953f4a08991aee166cc5a706408ceb0121d0562aeb", + "100": "84ee43bdcde7c1a1067aa1468d6fddfb8e165ab526283b0ef82a76eea08aef29", + "101": "4b0f2e449fbef9bbd4204caf0568f78ec856f0c586d98a472f2cf8889fb1f263", + "102": "8a58d9c3db5c0960ad11e9b1ad3a86e7e091c518b13ca8e0ec7f6073afdbd4c0", + "103": "3866814f63423e40eea23f5d3a775a3db609785f9144ac4c2a950fe252bb1255", + "104": "1ad2a077bb94fe29c738e8a887e850f82f64429c636c1fbb10e984b3e801372a", + "105": "d5908cb4505ba63472b1923eb1c34bce6fd255b71ff72dba545e0ca231e4e20a", + "106": "2ad3ee89757fde4ea78328f454f51fdbadbe19d6f7f5d07799274f3787576e21", + "107": "e66456a01ccd1fac39e7af6d9935ccc342a0c1a55c0a5d47baad214fa1daa434", + "108": "0ce92f8f2c00afc455250fb123496987f04e2b23ece870811b1f862f7081e823", + "109": "1819079699a0249d73ec6ef53c2bd18230bc605bacfcdedd4c29acc4e65ae750", + "11": "3a66ed2f43c0eb2e5196d48123df1a4722ab34215b464df322e5c2962534a7f5", + "110": "31f53cdeeab00dcd9f878a69bf0e4523e8e0d80a04c78eb0dace6254eac9d10c", + "111": "f98e4d444ef79cf4c1fdbe89c1cb66051bee85483e842875afce6c60dab425fc", + "112": "002fcb46145e856b8fd7c0012b88c13c31dc11cda7049291e131ea852690c66c", + "113": "8c95db1d350a5061d1419473cfa0103345bdf1c0c51c4b115d6a75856a27b25e", + "114": "e2837cba0283ab49873e0b804cada4c96ddca939fa57a35ea66f9b10be002b4e", + "115": "b5ab48890e08e3cf9cf9bb00f096dd9296e4a577a97417480bc017019ee3bdfa", + "116": "118127af830ae72b41ff43dfd77457e0acf8549bc347fe4132c98f5541ba4caf", + "117": "b4d0ecd32f61d2717ca88db140c5f261186727c64dee9f596abc8619b006d69f", + "118": "8117845a7ac2e5d75eff4fe397e69fc148d8a65f0577ccfaf3284b890496d03a", + "119": "ff7c571ba0567ec36dade070f625d81222e4e6c9e8a0aca25ba1a2473c17ba09", + "12": "1b9ca9637a4c0ba9732a223986fb8670cdc7661e5226876836fcd417165980c0", + "120": "13e620e2f52d8e6b925817f0d0da978a5556d8a1ea0a34905d3d223822e9ff54", + "121": "be12db6c2ce592c080ffa43a5b31f0c9f7092cdb8e133e4f747314cb1b1d9d1f", + "122": "7e2f6d83e2ec519ac2c69e30f58c9e43c93ccfeeccbfff4efe9edc4efcc213eb", + "123": "2f50cc9559e72d11858c68fdd8682b4415fc7aa242d64c96f36173c1d58e6994", + "124": "bb5823eb20f0ee614006c9295cac604925ed3c1e66d70bf7cb45367ea553d898", + "125": "2df93029e1c9d0ca15f20b4692e22622aee0d411f015176dc107d2865ebcfa31", + "126": "69b6f4911c8c0e7f9dfb5ff03cf4e2f8fe0ab8eefebac93f2826c1783d8f4f3f", + "127": "bb3299c778ceb8dd0131e8fbef662715bbb338e2c7754270220b02a3edc48200", + "128": "9d8ffbd9a6ed6435633c87df1646a373dffc56582b2be094b44e8bb9e539f31b", + "129": "4916cb995f103b3ed19424572ff332feaef953866ccde799161ac50a7b4a3a30", + "13": "cb136476b4ac17dcc9c39a1a67651ad3bb59fe5b0f5f7e8a798c1e627d3a3945", + "130": "f481a02f8669e684c77a1d3797d5c3bf9e6ba5c97f717d80a1aa536f33d0d474", + "131": "152e9f623e5ed008c4231479488947749a5ce870e3d013d3788d5fd5f647006b", + "132": "833f95e8b204adfb77da9420aab0ccfbc2794f34af9031b42b1a8e7d05de1342", + "133": "63b23b13a94ef8b013bb36ceec3622ed84a03657f9c76dff4c5734bb53a86405", + "134": "1bffdb58af6073c4200623b4ea3e7731571a2f7cd6fb9800962985ebfbb45bf9", + "135": "699cfcc8a802c18a5d3fc502352e242116ead356b2b77515a3ca6a128cb811a0", + "136": "85a606192946e307f729d69cf92c9f42830c7ce5922162746ff8d2f241c68bf2", + "137": "9964a04b61885d221732079e1aec0bb70999ef33a30db1e3454bfbbdba1b49af", + "138": "423a6afb49a92cd1f9bcfcda6508e45fcd28eb3f0ffb6032d90d1457f83e0004", + "139": "be23e8d689b5429ffdd8f0b38bd60befa78d83b77ddc73bd360088b6229a678d", + "14": "072faaddbfaa767a91fc111c322e1465e0b109820cf2bfca10a4f3b2bcd2f6c9", + "140": "8244d58d24a98ffbc552e182f6eab77171265fd481f3ae8d16122231bdb48504", + "141": "68b60ec11424e8f217e61460fb69035a60319a21b08f89259640b646cdeb6924", + "142": "ca027a634dd0e200654177f6a54c524f452ad129fcf0713fbebff1f1dfc6088c", + "143": "868a4e4bb8398438163188f1a9382bb8b6d43698a59c4194db629bac696befea", + "144": "b66cf2ae548365eee9f422caed24aa6cf9aeffeea21194238a98b89d7d1c3f2b", + "145": "494361641dd0eada9ada0432cbf2c3b788d44814823df2df56a7ca3ef60af2db", + "146": "5c1a9e08ce0388eac99975df49506f7f9cfa7cb5a6b337ba7c4c5d75f4f32ce8", + "147": "51446b84d226cfd57adc2df0b5e9a8b3b89d9cca8262d22e9c69f4ac55859b80", + "148": "72452d48cb44c1e41bc72a0997799f9326ae1b8b131357fa36231010e9d6581c", + "149": "996ebfcfd2ca222370831e0b7e32ce0c4683fc95869b0dd6164644619a1e2ae5", + "15": "5a0c24d6432d28d80e65ccf55d7d194761752a7c0933cb6db371d841fb8f6a22", + "150": "b3612ab6ffc5802b0d18a21986c099926ba7aa74c2f3c9c83f8417e265511a50", + "151": "285ae08af1a363f8de8c8e1f1b899bd95bf919b7052c24595feca1e39ee25f4f", + "152": "18e1d821b674f55fd73d41830a1a60f6d1e7f2b2dc78e8c75dfaafc5992ec58f", + "153": "102f7f1e4ac26cd49f9c248b571570711c0c6b7927bef14f19d031fa83584944", + "154": "e843889eeef71c1a96c9e33eab9256df25998013e17121d0c2bc7ba9d6492a3f", + "155": "31f1f49fdd14c72311bc94d0105ce6dd20119f0e16f1edf4e7b62de293c00110", + "156": "113a38c33618ae769077332f7c15bb0d66499b566be7b20ce97acbe0c3526e91", + "157": "d32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c137536344", + "158": "f03eb85756e1ea89cb3ad2ac61479e97ab2cc9e59ebd0ecf70e2aad6e2bb692a", + "159": "77ef7583c1c7f39f2a8729090c5e4c2e7a22890d1f8727cb6e2bd0992707f61f", + "16": "b82e6838ea2d6935252ce336232df6583ec016db2146302b8f5ddde8d11be2ef", + "160": "17c109c2bab37700237f74069210516d4066404ee979417c37eae627ce50a898", + "161": "3fdf1e05f5dff421950a11faa4b7e2fb92de49df004d6c8cf8bb059d174372b6", + "162": "7b4f328adf0c137fa7048a6733531049aec840d6097e6f8558ee0be0c6d3c943", + "163": "724f075ff3e960332793a44a40fbb591c0b69af37a32ee2356d8a50f14743389", + "164": "cab22f7c044dfaefcf970ec1179dc32c1e99298727839dad9107c9b4d2f2f735", + "165": "654295a4193f299799a23cae6179f1a07e54288623e265531c3ae322f51eb8af", + "166": "91fd84af6fb0f44070d537f22b87f032d7a23289d935d6535f0d12b40fca76e9", + "167": "bf1bea3406284150afee2709a421e3c742ad8aa2af1c5fde881a75cace5c7315", + "168": "7079799279c8b8f1c12b4c4937c150ca28c1c0db975e2bae4a4162d3d91be7a2", + "169": "21395e6896956131207b1db67336e39f2197ae9c00b974e4fa1eedeb15249c4c", + "17": "4676b663b554b13222d2033c1b0ae94d1a2123d39e01ae23b2c31b731ecfe19d", + "170": "8d8b752fe8478855a70ccd16a49371fedac6234667d603cd30ebf4bcc6003cc2", + "171": "da8070a07dc1b06194d7c1586ec1c5ea248bdfc0c9b4d7895681da8ead9ea052", + "172": "4ed8c97352f6ef3a1c3c97deecb4a32e44ddd849a6366a2dd09151e49328f272", + "173": "b66b4752e276a7afbc8c5b6b29a84ff18fb488fb693f5a313e21a938d6bd650a", + "174": "85f564e1d096d93c0073c244a9ed658ee27391299c7de0583a2986d5abdc312d", + "175": "267c86c61b19a152504456298184e2906fd5cf0b51a33bcb6f9227f7a5ca6800", + "176": "4775b4a767386b90c6c70bf58435dd772faf82c1986d9222ab6b52fd7cd5fdb5", + "177": "84d9cc703961887e3d445d5fd960230f43b84a25a8be72d015a51c2e6b6861ac", + "178": "f4cd0c7229218401b08ec1d76c2b0b7ea1a14ff9f78a8f73208ef469f264ab15", + "179": "88c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae76", + "18": "bdad47746313cf12411f185f78acc15dcf1fc8c9f05e9792bae74aad3cbed2cd", + "180": "a8968aeb2cf78a397a9a1fbe15e17d85e40a96c9c9a92e0cde9d7d3aab2f56d1", + "181": "a65437912a85304ec669b9c92cd4c17f57309c267b8f8edffbf17aa943726afe", + "182": "13defe8b771852b4607ec014e5aaf1e41db6c4565a89eac8059ea32ec8d6a9e4", + "183": "de7ed7c316662f980c2bc0f0e12d3955da679c5dd7e28399dcb755775cf498e1", + "184": "1f5cb1f65f0493734f78a4c0e9f797407e6fd7363d34a9bd32f9cc6c334e48bf", + "185": "ca00ac440ac549cc810c949fe21a2fae5b0dd5ebc2e3860a1aa5a28d60e794af", + "186": "bab8c7c01e545ecd6e433aca5fa360e25b4cf9758d9eb62d14cc73e055da2e19", + "187": "a71709ad8f6b5858a8b301b4f9a0e8a8324b7122bd6a2a1638a70070ae25c3c5", + "188": "e0c7bfbc9ac5b696995401350b16ad6037ea0ca7e6d610f2a8ca4780fa7744db", + "189": "efb4ac8834d6bbe4eb7f2e4c58c5895ff75c58256ceec70d9992b046d4261c3d", + "19": "4a4353e11b2e3fd7a244a0703d4d3397b54ebb6c98bf649fca2f5fc1e0ad913c", + "190": "64c8dbd0b2c3e68fcc10ff89757c0bc025cfab57a015441a59b8e82d3ccf6464", + "191": "23eec8d88ff294e68474b99787ee96da3a7d47283268746e0c908519c44aeb46", + "192": "17765ada1eb2856c2e9ed19606416ef1d2ce2d0a2f21675b7cfac41adf1d65b8", + "193": "fdfa2ef90b5d775f01eff318e70d73df2dcdf1f04cfb19ca5cd18731be34b636", + "194": "ab672ddd064309778a80ac0800d58e73e9e797757638368f70736f18f8729089", + "195": "b1f95104c13cbeb266ab7727e8eb52ba5be8bd8ee6963a15bedf2fd5f387a9fd", + "196": "03aa3ba7adabc1ca777813bff7b89735eb3ff96dd42b3f16e235d2498eb773e6", + "197": "3465f761e500576d646ecc1b87794228ce6fb82116edad40cf12f2566ca7fa55", + "198": "11d416743ad92a5ab2d405022c59124a59940e5f154e95b7bbd4849ed2106c45", + "199": "ace0428b3344348f3233a4b2b065a97127ece70bc5a7ee2df66f762cfb976573", + "2": "b77a438bbd19f663a3c9db01f4bfc86e56a8f6dabd491d3a411a3dcde0284ea5", + "20": "e164aecf24127f8d7f0f3851a24a11c534cd01249ca3cadab0917cb46a9a9f65", + "200": "7fdc37cd65793411ddba22c383480419a67d5056e3cba869315931c1b7ecd692", + "201": "6962a589e00a4b4cd1ed8788d10f48e3a78fd1f0ca9925db7b5fcc551a043f6b", + "202": "dea9bfead67f93fc535fce7cd3d6381559c9d84509d913464785388607b9fd12", + "203": "24db70c11b9b729619d1437dfeb8f4a9ad4fd532cbeaa2c2b10713f981ff9709", + "204": "039cebdef41e2edbee7d8886c26732b181064d7998b605a4e94683064f343a63", + "205": "2e05cd37d76a8acf344f742b9b8492e7f7c282d6daf706731043a2c3bbb10fe9", + "206": "e8473aba78e24017e895ef639c37f90a1ca39467635abeba021cc7e21ae502db", + "207": "f36a8a2107d572d2e982e00a25915632023d0e377a1f06a263c575fa3100dd12", + "208": "0199c5e7bce33341ebf37e44a5ee2566debb425dd9ee9b20c1d3c55aba7c69ef", + "209": "d353f82f86609882f48ea06f3ee10277de9ce2f539c0ccf534c9e1288d31f7cc", + "21": "b347951f5348806b2e1dbd65cdc9c4fc9b31895a6818ecfc37fc97e8990d048c", + "210": "a2268acc5a0e037f596b6fe85d030190a14278e9b6ec456f785c6ce4e1adc7a7", + "211": "eb99f904a61e12a53cd2f8a869b4a18db9c84d1d951da7878b2bd258a1ec5d33", + "212": "0d71e59652478b21715aa4e970a0128d817ce86810ee921667b13f5eef854ed7", + "213": "0e73846108029955dffb2889100f29fe8d02ee96099ab9aaea29fb579a7cc3ae", + "214": "a647fedabc5543b8e0e0e1f918b8c6023329ee81b221a81b6975632e5e1cb95b", + "215": "aa84da3d88c99c847fbf61ed0145d387c9d58f1cc34189c6e7eb64217a6b1ca2", + "216": "4d0e41d628c32a51f9ef2ebdb438ffdb836881d33774ffba67ade97cd093fd85", + "217": "51d10b55da6841ecc3153295973a443a5c3da930ea3c8936fd2de3222dfc1185", + "218": "cbd378ad3e92aefa681297d2ff63678cc2d4d0b80bebab90b2cbacb9d9605092", + "219": "d2bc095e758141ef766f4b13a486303aaaddee640d9746244b5f248ffa1d2363", + "22": "10c4f64b2f5838701f9009e217ec54baeaea2b9fb9d205cb5aa3e7cfe2082eb7", + "220": "295e031a083d72d967cf3f301f608dcb22956c676c02f6a0a14e0945675eb9d6", + "221": "35292999cef86bb6849124c92859dd306fd0e6bf7be9d86cbb387e838acceec7", + "222": "254ef2cf3d1f42381206808e0d5f7e2a466f6390ceb1eec3b2f100260e2f4ba1", + "223": "a4892c4322d7813580fc949a7efac7e1e9a83773002b6bde490255faff1baf79", + "224": "46ed2401a1b23725d86ce3dd098fd8df282fe9f9832d593630e95881df66a121", + "225": "e62d2dcfe473310f8747edf3d417ae6cdff98d0610130f3e04b64d09a7ace265", + "226": "1adf17e9f086319c22be397c793f84f1c31af689aea3753616612bfd2b6ad38b", + "227": "70272da38d7de0f7bb8b8a5852bffd9161097f2d7008335e9212429cc1373979", + "228": "895f50f8236fea5f49c491cbbd19041e7799a0242ec32bf9c53963ede13f88bf", + "229": "26dfd3cbd5809f590c9fe32a5d21540f4081d847168b8b325e808b178432074d", + "23": "59466cbb6d4ef2b9f80dfef4ac7da76f320bb7d5ae7c2dc27bd601c6a3365f30", + "230": "19affec3fa4cb019f1acb1a889966a7cf6be055d37fb692cb99756a5550cc107", + "231": "18618b06492a8529c6a2a493155d43c093deed2d6afab43e0b1a87369da912e7", + "232": "c582653dd77aaf0acdbf775398a95b1da40b1e59049d54c50ceee1524999cba9", + "233": "542395f0718450f715b95e91939dcb7c588e2f72482b929d425043e9e258c891", + "234": "589195a8fc2a269e475cad21c8581118e244c1aceb9e057e5424e9372f071575", + "235": "efe1e28cd566509f0ae3e691e853f8a013997c856179970169634e0869b597ad", + "236": "620100875f0e016b9413c0c82e4fe3c9dad1cc92accd3955f2e23162c9f42f77", + "237": "640e3bf37f99beb20359117de982be84a1d420c896689e55e0fb50d6d4cdeb21", + "238": "23589582482baf1bfe5ea2507b9ed0ade68662d152b71acba9310ee4fc3df210", + "239": "ff545241ffe9ac13511bcea11fbd857abcce63dd2b6a9efb7c4948657c3b53f0", + "24": "8f60911463de55684f83a17922c5200ab44b7e0a9fe05f988d6e8a54503792e6", + "240": "ba33b49b6d4be58993159e564c82ad883c21a1ac36e8e3e86e24f3159b9d3a84", + "241": "7380aa0f74a325682725087b35a052f41e134d794093da1d0079b19ce599320d", + "242": "78908819a945765ec323085a40221384ceeb91f4261414116e7c8494a327eea7", + "243": "7ca2dabe7cbe00d4e9cc36ff81bd113ff6f025eea80cea7fdf034f74bc36f336", + "244": "eda53672a1737faac7f3ea0f93e30d08ffa3c615b3e97d5740b2edc917954074", + "245": "1c9c4e4bd1efcdbaff58f883fe4df489d83ff5031f26f0523f1333c94f1ce1c6", + "246": "a979b4ddd88dd9720fb1fd82b1d1fab0d2891f41e7ca3b6556c90c75b3fddbbf", + "247": "1ae62a01f4a7140504db3468834f51e59904ce717147ad72e98deada051e033a", + "248": "442b242b9aeda3a73d38149f70f82b7b85638a16781f0339b5044c94416c6fa2", + "249": "1ee038737c7311bea5b5de81b7bf321efd7fd91559f96083628f12033cd2e788", + "25": "7db12cc3b9a7bff755fa37bb1b5f229f897e452e195873871fbe00473f60d565", + "250": "7f2d8f7627f2b5ec22a6223d10606850face773cd2ced0d25e55074bfac19730", + "251": "10ac9abfdf519ccc1784ba9d5016478e3c1bcc075bda8d1ca5bbff783e80a465", + "252": "824785cf3d3aaa4e0a6e66df7dd90447bc04f2694fc606b3b60781352306895d", + "253": "026d5436e4c63258ddefc38c0e6995e094dac20020399bfdb93052035e529643", + "254": "98d983d01d851d7e79f88d6969a1153669fe666fc434eae290675fe142f887ac", + "255": "cd5b325ede4ff3c935a35aa4e8877571d2866ec8951c2f20e7b24907d9c0d515", + "256": "e010d3847f52108c8ca21f58bc2aacd87fd128fbf959dea55467b625272f6474", + "26": "f45504ec687ddba0176856f7e4cf90035395b2fb03092f84f5e0867c78208f7c", + "27": "dee6c49da18fbbccad6e815171d75512afc64c88e3fa12febb166f03d5c8073c", + "28": "b57f31bb65903dcf1b310d184b0909670953a1a76ed43cf0344a356d0b3df4ac", + "29": "2bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd93338", + "3": "cb4ea5ef845cfe017abe9f56955f645a7c078b3331b372e9356d58c4f208b43a", + "30": "ea59a564456ba0f9d9eed56bdec2b73cf0cc6f7a3073e71d1bb5a25197028994", + "31": "c9074efb6e52141111c0e43bd78a25772cff8084072388397ef7358531d85fe9", + "32": "c74544c0a6979e7c37e322b970df199083a11b93f89bc7ddd390769af74e12fc", + "33": "f78aa2986894fdcaecd827564f9e641edfd1d35d0aef3184d5d3c91d976f56ca", + "34": "0b2bd983521973b2d3a6626ad1c37ae119d1cac347c0598dbe1bae95fc7ac14e", + "35": "487ade82d5f95b9d1fe804cdf3e85e03953ac6878457a74e015a34c5c98073ea", + "36": "2ed8b8173be8b51cabe43288140905327cab82ffcfa300de313a68abbbe198b1", + "37": "6a01b8b0346842960fb64e14062cba6a50c3e8edcd89a0cad30a4094815282f6", + "38": "3e2e87d33b9fb1389b472b0f094cae46963eb99e307e2acbfe6e8265bd70e4cd", + "39": "856f3512a7ba4cc5252806334e54dde68a3c3839a6d5ff621778dc73f6b165d7", + "4": "643cf0a33eccd27c7e046f2584608fdcee3af58250c6b9b94df5c3ee10698e23", + "40": "ebc0d4f59fa696137f0b096269c56998b02662a19c9b295ecc85d8abdfcc971a", + "41": "001f72cf0ab6835479c6e63d06d54f1cda1eb405c3073be2b90ec333c6f6875f", + "42": "5e01d58226733ffde8ae0833d24bfcb0d8e6efa00b69472d2cea73dd4d86feca", + "43": "fd59e74549a4b118967d7dce597d5dc7a2c13fefa9239d061aefe27157909869", + "44": "f152c1ddcec36438a21a8e3ccbed58d58638b95c0466c81400fe7749f628eeb5", + "45": "aab01c1021f63e7d9bb4f3b9b4e89aacec88fb938417452388ea16f39eb42efd", + "46": "96d81e9d590b4e189b77f483d22a81bd0990ef3130f858436d44dcbe5556693c", + "47": "113c6ba93d5c9b17a71f254d603a3326b7e31fbdef5f07fd605142954b34ecd3", + "48": "c66a7b11ef7844ef0850cf768ea6a12f2fcfa1c75118eac678efdb17876e3855", + "49": "2b414c09cb30b2c44fff9a5feadfb4ac6e6ad88fc023a82af10e994d359e9b5a", + "5": "c9aa115b438cf9a576e9447ba0d1cde19ff07ccc9ce0fde96d78e02aff80f8fd", + "50": "b8452b0548d20ecd8b76cc53e6cd4af8e856e8dad6d16474858a8c240ce93640", + "51": "b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1d", + "52": "6122c9028271b0ff6d4579ef9de1603dc70ccbfbaba99b280c96647ec496713b", + "53": "80c86a33f7d00bcfb5274ab452cdcb539f7ef164de25a5503c4a3115e35f6336", + "54": "7936e3fcda810d8095d83015d43eb23e7b11efbbae8ef8598cf9480c7751ca2b", + "55": "3591e0d7eab9421132928460f5d9997587a084576f4c229fa559164b16d818f6", + "56": "9b31f974fc3f2027fcee8bd50aab232de75237401a9dcad80719742078279954", + "57": "75869550e337d7846815f928c4f2ecdcbe49ff621ca8de23c690bff5ed88acbd", + "58": "3f9b7c485dcffdba1a2e44445bbe27f800ba62347e2e2d66e953e9618dbcb4c5", + "59": "abdd1bd500f2b133cf80c8c34f72270f24d805c0ebd0054ad18b22a80c6fa494", + "6": "7d76aa0edf868a713e574ab91cec25728b2b8436ae20c1a89b73875b1085f33c", + "60": "9cd8fd2ff310e8c1575002f9b91c6e3d3ad0b144db9659d584fd49f3217d27dc", + "61": "b391eaf621a8a2d5706663989614a178b8605c3c47ee17d95ad202851fdb9dcf", + "62": "8c646d1e10512689b64ed99a90ebdefeb70e5f512b0acabfa23eaebcbc7f09ec", + "63": "7fc5fdc2aaaaa3c7df28b8fee9af534e55a06cd4e7de3762f1bcc53791ded251", + "64": "3bac4729a4c42139fd08860f498f292f4aa14c0495873d36812b6aafe392a54f", + "65": "8e6effdbeeedd51fa38912d73884561bd5f6b92a78b5046e471c0a38b46607dd", + "66": "b5d8b14fd077480d5c395f14144ec106f1b4445c7e8048d552921cc71b44bc5f", + "67": "a37350e03eceefea61586896cec6c60a48556dff473d47d27fad1473669bc628", + "68": "bebd047f32d6c2ccd525edf0110ad454afa2fec523fe7e4e6a01bc60448cfc22", + "69": "212201d8313be7ca57ee7b6be91a8d9ab8c8d1d6e568741fec2584ffefd9a2b6", + "7": "3bd49b80e46ba4a953b0b41248db1ef33f0804f1de424eb213446abcb4d1d1ac", + "70": "3bb6f3177ff6d96f939b570b326ab9646de5cbb2a0d6b99c4e9270796e581d3f", + "71": "2c9da84875ce97e6d3a0df98b8709b2da24233648c39dd4d07d3ca7e53080805", + "72": "a2889c0ef3642da4b017e31f203904ea288cfe27a965c1e1ae60a0b88c150ab6", + "73": "8602fb3386007a97bf729822083db883f5eb08abe05e532f02ceefa728aa2edd", + "74": "ff1976473c9d0b9a69639f23a29e37a9e4a5154d044911656bd0c3fbc3c16f25", + "75": "9ead1883a1904c09134aae8648e6a60cb886dc789f476c7d26514b14a90e7aaa", + "76": "7b79206702e7835dbae6a0f7b6b868bb14768bc8ac2f1f1ce217e2c772e7ba81", + "77": "1fa3801c2c0ed677671d1348782ab66504ec5275f3a4a0f8d1d26e6ebbf8b557", + "78": "e365d768a9126fb809745cb720ac2c61162c42c919c136b02c69645cb3c9e1f1", + "79": "0ebf872aeacce6970014ff9c1f51ae81d5c5040011742e094b112f61cd86691e", + "8": "cd8d564cad7aa424d24c5fce6f719457cc0bc7eefb3d77bfdba8761ab30651b9", + "80": "5e3931bf1a032e6cacded89070f88dce14de82c2daa991c1b8baa9720a4cc9d4", + "81": "7e2c3d837925e053d853810e82745132c8dbaf6b11a901349e1545cbf0279360", + "82": "5075bef1d81729ff4102743491d63914cb895904ef22e98d035d0e3e98ea4a69", + "83": "275360fb192ad03f697c19d7a855971741e59031cc981ab6e0410ebf1c95e189", + "84": "b5b67dda2b90394190bfe0dcea2a6fb226dece80df349aecff04ebfc37f8c0a9", + "85": "9510719446b2b43f68e9dd45ea39c0d17e61e6ad3c31cf6fb53993b5badcc04a", + "86": "b29bd878932e92aaf12a7d9ac5c7d7f45f2abfd1897a6925ad2d835c3f0294b1", + "87": "7155f6c1b22fb1aaab7fbfd1be7597326dca6377349fd37ddd54f4ad74426800", + "88": "ede90873683e203ec010eb4fae657aefde4a293e1a5284de0f9e5c34c1a32859", + "89": "d5d3ee3fa155333a81f6281a55b5274e239ff60c5cce555fea14b0a4839b77ec", + "9": "21c5d7b6c25e6eb1e591bb89895daec91b9328026accf8dadf13df5a894b75fe", + "90": "7e140fd334911b4bfdb6031eb1eaaf040d2b98673de3c51079d1c066d336eb05", + "91": "6d896629cd33f8ec2d5cadbf07903c8d81e3ab335f4691591b358285fb9ccadc", + "92": "1dd81b09b9608944e94e86330fcffe12e89542dd57d961d20baac137629809f6", + "93": "9ab76ef902da4eebedb727ea11575434707e1c2f21b837c780c040f2cace8546", + "94": "71d4200634c3fba2ec6ed0df3dc97a40d6a15f0fdf30338598eb3d51524cfd3d", + "95": "e8edb033c20e3e48a238ac4cce920044c002fdfb1401512a4070b8985808917c", + "96": "024ab31c508dec2a22e0d810cf2ca84c068bcb275c5c2a2e31451ff12280e1ce", + "97": "6aa6c602fd435a2c8c9e4b8d2d8882bf8963c6e44a0326828f10587cab12f31a", + "98": "bf464d5b0fb39a73f1945bed495bbac2e3c87bcb12031dd06e5281d6af70b8e2", + "99": "a950ad0dad368903b2b6508391255db20c9eec8725b4855ac8e8ff56df6f9390" + }, + "labels_concat_sha256": "14c4f5755c4ffebb630cfde57e85e0b3040e1d45d656ed5e4d15ebef339c7c00", + "lambda_bits": 256, + "n": 8, + "parents": { + "1": [], + "10": [ + 2, + 9 + ], + "100": [ + 80, + 99 + ], + "101": [ + 96, + 100 + ], + "102": [ + 93, + 101 + ], + "103": [ + 94, + 102 + ], + "104": [ + 84, + 103 + ], + "105": [ + 103, + 104 + ], + "106": [ + 89, + 105 + ], + "107": [ + 3, + 106 + ], + "108": [ + 102, + 107 + ], + "109": [ + 15, + 108 + ], + "11": [ + 3, + 10 + ], + "110": [ + 53, + 109 + ], + "111": [ + 15, + 110 + ], + "112": [ + 104, + 111 + ], + "113": [ + 76, + 112 + ], + "114": [ + 100, + 113 + ], + "115": [ + 109, + 114 + ], + "116": [ + 88, + 115 + ], + "117": [ + 115, + 116 + ], + "118": [ + 112, + 117 + ], + "119": [ + 102, + 118 + ], + "12": [ + 5, + 11 + ], + "120": [ + 118, + 119 + ], + "121": [ + 54, + 120 + ], + "122": [ + 16, + 121 + ], + "123": [ + 121, + 122 + ], + "124": [ + 120, + 123 + ], + "125": [ + 19, + 124 + ], + "126": [ + 124, + 125 + ], + "127": [ + 119, + 126 + ], + "128": [ + 107, + 127 + ], + "129": [ + 124, + 128 + ], + "13": [ + 9, + 12 + ], + "130": [ + 127, + 129 + ], + "131": [ + 113, + 130 + ], + "132": [ + 24, + 131 + ], + "133": [ + 104, + 132 + ], + "134": [ + 52, + 133 + ], + "135": [ + 45, + 134 + ], + "136": [ + 114, + 135 + ], + "137": [ + 48, + 136 + ], + "138": [ + 94, + 137 + ], + "139": [ + 54, + 138 + ], + "14": [ + 12, + 13 + ], + "140": [ + 137, + 139 + ], + "141": [ + 133, + 140 + ], + "142": [ + 140, + 141 + ], + "143": [ + 141, + 142 + ], + "144": [ + 142, + 143 + ], + "145": [ + 141, + 144 + ], + "146": [ + 48, + 145 + ], + "147": [ + 143, + 146 + ], + "148": [ + 102, + 147 + ], + "149": [ + 131, + 148 + ], + "15": [ + 13, + 14 + ], + "150": [ + 70, + 149 + ], + "151": [ + 30, + 150 + ], + "152": [ + 136, + 151 + ], + "153": [ + 100, + 152 + ], + "154": [ + 122, + 153 + ], + "155": [ + 102, + 154 + ], + "156": [ + 96, + 155 + ], + "157": [ + 34, + 156 + ], + "158": [ + 139, + 157 + ], + "159": [ + 155, + 158 + ], + "16": [ + 3, + 15 + ], + "160": [ + 129, + 159 + ], + "161": [ + 138, + 160 + ], + "162": [ + 157, + 161 + ], + "163": [ + 156, + 162 + ], + "164": [ + 30, + 163 + ], + "165": [ + 149, + 164 + ], + "166": [ + 164, + 165 + ], + "167": [ + 81, + 166 + ], + "168": [ + 160, + 167 + ], + "169": [ + 165, + 168 + ], + "17": [ + 9, + 16 + ], + "170": [ + 129, + 169 + ], + "171": [ + 165, + 170 + ], + "172": [ + 170, + 171 + ], + "173": [ + 171, + 172 + ], + "174": [ + 67, + 173 + ], + "175": [ + 149, + 174 + ], + "176": [ + 109, + 175 + ], + "177": [ + 148, + 176 + ], + "178": [ + 174, + 177 + ], + "179": [ + 151, + 178 + ], + "18": [ + 15, + 17 + ], + "180": [ + 43, + 179 + ], + "181": [ + 136, + 180 + ], + "182": [ + 14, + 181 + ], + "183": [ + 179, + 182 + ], + "184": [ + 180, + 183 + ], + "185": [ + 171, + 184 + ], + "186": [ + 184, + 185 + ], + "187": [ + 175, + 186 + ], + "188": [ + 180, + 187 + ], + "189": [ + 185, + 188 + ], + "19": [ + 12, + 18 + ], + "190": [ + 17, + 189 + ], + "191": [ + 182, + 190 + ], + "192": [ + 190, + 191 + ], + "193": [ + 121, + 192 + ], + "194": [ + 178, + 193 + ], + "195": [ + 96, + 194 + ], + "196": [ + 194, + 195 + ], + "197": [ + 186, + 196 + ], + "198": [ + 182, + 197 + ], + "199": [ + 169, + 198 + ], + "2": [ + 1 + ], + "20": [ + 13, + 19 + ], + "200": [ + 172, + 199 + ], + "201": [ + 193, + 200 + ], + "202": [ + 191, + 201 + ], + "203": [ + 151, + 202 + ], + "204": [ + 198, + 203 + ], + "205": [ + 203, + 204 + ], + "206": [ + 188, + 205 + ], + "207": [ + 201, + 206 + ], + "208": [ + 170, + 207 + ], + "209": [ + 205, + 208 + ], + "21": [ + 19, + 20 + ], + "210": [ + 207, + 209 + ], + "211": [ + 209, + 210 + ], + "212": [ + 166, + 211 + ], + "213": [ + 126, + 212 + ], + "214": [ + 212, + 213 + ], + "215": [ + 211, + 214 + ], + "216": [ + 214, + 215 + ], + "217": [ + 156, + 216 + ], + "218": [ + 213, + 217 + ], + "219": [ + 119, + 218 + ], + "22": [ + 20, + 21 + ], + "220": [ + 139, + 219 + ], + "221": [ + 192, + 220 + ], + "222": [ + 197, + 221 + ], + "223": [ + 209, + 222 + ], + "224": [ + 83, + 223 + ], + "225": [ + 221, + 224 + ], + "226": [ + 19, + 225 + ], + "227": [ + 216, + 226 + ], + "228": [ + 224, + 227 + ], + "229": [ + 227, + 228 + ], + "23": [ + 10, + 22 + ], + "230": [ + 214, + 229 + ], + "231": [ + 229, + 230 + ], + "232": [ + 228, + 231 + ], + "233": [ + 217, + 232 + ], + "234": [ + 231, + 233 + ], + "235": [ + 91, + 234 + ], + "236": [ + 62, + 235 + ], + "237": [ + 235, + 236 + ], + "238": [ + 188, + 237 + ], + "239": [ + 226, + 238 + ], + "24": [ + 22, + 23 + ], + "240": [ + 225, + 239 + ], + "241": [ + 237, + 240 + ], + "242": [ + 240, + 241 + ], + "243": [ + 59, + 242 + ], + "244": [ + 181, + 243 + ], + "245": [ + 237, + 244 + ], + "246": [ + 243, + 245 + ], + "247": [ + 245, + 246 + ], + "248": [ + 243, + 247 + ], + "249": [ + 8, + 248 + ], + "25": [ + 23, + 24 + ], + "250": [ + 248, + 249 + ], + "251": [ + 243, + 250 + ], + "252": [ + 249, + 251 + ], + "253": [ + 200, + 252 + ], + "254": [ + 252, + 253 + ], + "255": [ + 251, + 254 + ], + "256": [ + 252, + 255 + ], + "26": [ + 18, + 25 + ], + "27": [ + 15, + 26 + ], + "28": [ + 26, + 27 + ], + "29": [ + 20, + 28 + ], + "3": [ + 1, + 2 + ], + "30": [ + 16, + 29 + ], + "31": [ + 26, + 30 + ], + "32": [ + 3, + 31 + ], + "33": [ + 29, + 32 + ], + "34": [ + 32, + 33 + ], + "35": [ + 33, + 34 + ], + "36": [ + 27, + 35 + ], + "37": [ + 34, + 36 + ], + "38": [ + 34, + 37 + ], + "39": [ + 13, + 38 + ], + "4": [ + 2, + 3 + ], + "40": [ + 1, + 39 + ], + "41": [ + 27, + 40 + ], + "42": [ + 6, + 41 + ], + "43": [ + 39, + 42 + ], + "44": [ + 10, + 43 + ], + "45": [ + 17, + 44 + ], + "46": [ + 44, + 45 + ], + "47": [ + 40, + 46 + ], + "48": [ + 17, + 47 + ], + "49": [ + 22, + 48 + ], + "5": [ + 3, + 4 + ], + "50": [ + 48, + 49 + ], + "51": [ + 44, + 50 + ], + "52": [ + 32, + 51 + ], + "53": [ + 51, + 52 + ], + "54": [ + 47, + 53 + ], + "55": [ + 52, + 54 + ], + "56": [ + 40, + 55 + ], + "57": [ + 51, + 56 + ], + "58": [ + 51, + 57 + ], + "59": [ + 57, + 58 + ], + "6": [ + 4, + 5 + ], + "60": [ + 52, + 59 + ], + "61": [ + 56, + 60 + ], + "62": [ + 47, + 61 + ], + "63": [ + 61, + 62 + ], + "64": [ + 48, + 63 + ], + "65": [ + 63, + 64 + ], + "66": [ + 42, + 65 + ], + "67": [ + 65, + 66 + ], + "68": [ + 60, + 67 + ], + "69": [ + 63, + 68 + ], + "7": [ + 5, + 6 + ], + "70": [ + 32, + 69 + ], + "71": [ + 57, + 70 + ], + "72": [ + 68, + 71 + ], + "73": [ + 20, + 72 + ], + "74": [ + 14, + 73 + ], + "75": [ + 59, + 74 + ], + "76": [ + 72, + 75 + ], + "77": [ + 24, + 76 + ], + "78": [ + 49, + 77 + ], + "79": [ + 17, + 78 + ], + "8": [ + 3, + 7 + ], + "80": [ + 30, + 79 + ], + "81": [ + 74, + 80 + ], + "82": [ + 68, + 81 + ], + "83": [ + 41, + 82 + ], + "84": [ + 53, + 83 + ], + "85": [ + 81, + 84 + ], + "86": [ + 56, + 85 + ], + "87": [ + 49, + 86 + ], + "88": [ + 51, + 87 + ], + "89": [ + 25, + 88 + ], + "9": [ + 1, + 8 + ], + "90": [ + 76, + 89 + ], + "91": [ + 31, + 90 + ], + "92": [ + 29, + 91 + ], + "93": [ + 2, + 92 + ], + "94": [ + 90, + 93 + ], + "95": [ + 79, + 94 + ], + "96": [ + 94, + 95 + ], + "97": [ + 83, + 96 + ], + "98": [ + 96, + 97 + ], + "99": [ + 97, + 98 + ] + }, + "proof_bytes": 55405, + "proof_hex": "42314d5450445231084000000090cb87eabf42f4c14936c936d37e536aa6e2ba7eba4ec5a1c48ee52b88d324237155f6c1b22fb1aaab7fbfd1be7597326dca6377349fd37ddd54f4ad74426800d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d942dea60ac728bf8fd91fac99773f0337996b515439c24f9fadbb33d76472102b763293b793482163d3e17bda4d911eadfd85044430cb58a94e5c8c4359fcb3727aa84da3d88c99c847fbf61ed0145d387c9d58f1cc34189c6e7eb64217a6b1ca2022b414c09cb30b2c44fff9a5feadfb4ac6e6ad88fc023a82af10e994d359e9b5ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd30f40c4c59a5e09f8717da346133688fd5949cd48b191a58715ba9958a2184931fea0fc96e448b379d7e9728083e5888780be506c91b13093988402c87fdbfc0b84d9cc703961887e3d445d5fd960230f43b84a25a8be72d015a51c2e6b6861acb29bd878932e92aaf12a7d9ac5c7d7f45f2abfd1897a6925ad2d835c3f0294b17a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690c0e0751a4a36d50ef4a2392cfa98c2d74f34a2df8f4c1e04e9afd0a06d959bdf964da06351b8b14f0888c36833f100e8704692c721cd91a364476fe2291d8266a647fedabc5543b8e0e0e1f918b8c6023329ee81b221a81b6975632e5e1cb95b75869550e337d7846815f928c4f2ecdcbe49ff621ca8de23c690bff5ed88acbdd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f71d2d30bb7635cbe00b365df7cf16bd16eade457e84fe6a48bfeebc3a50c5d5bb10c1a682751fe3043ec771924933eb7c33f39b9353b578a66c428edf5aff1e10cb91adefbd1bada1f7712783c6fee2bde4c46f94959d641c7fd71646706aa2deca00ac440ac549cc810c949fe21a2fae5b0dd5ebc2e3860a1aa5a28d60e794af02b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab1325773497609f32961860d65c658d6bb938343f35c9c1f987d72425cd21aebd078181e6ac08b7899cbf2432aa08d2958b467b623644394b4b8bbd812a8cef59e414488c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae769b31f974fc3f2027fcee8bd50aab232de75237401a9dcad807197420782799547a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be411b19e9045189ea4cebcac9f2e99aba1e2f4ed7d0184c148144fb82d5b6bd545bd43a96fe4379c0ccfc5794df3e2d4ba3e86698bab2d3b03b6649e85dd949e681f5cb1f65f0493734f78a4c0e9f797407e6fd7363d34a9bd32f9cc6c334e48bfd2bc095e758141ef766f4b13a486303aaaddee640d9746244b5f248ffa1d2363d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e8e26a61abb0582c580b1c9afc4e3e0cd5187d6dd5383bbc43f60049db396bed80150b087517d43972402c040ed40b08058271277c5cd5f1fdf24205656c026c0099c24340eb06b0bac76ecdc98275f6d2c4edf897a5d459871731e07d67fa2fc6d896629cd33f8ec2d5cadbf07903c8d81e3ab335f4691591b358285fb9ccadc02ff7c571ba0567ec36dade070f625d81222e4e6c9e8a0aca25ba1a2473c17ba09d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d94760f007331483ea6fc0bc28a0b6c4073729ea8666271fd66f048f416d75b3b884ac3baf509c348fa1601eb819b749f97514a5a351bd1e410db6978580dcd15fd1ae62a01f4a7140504db3468834f51e59904ce717147ad72e98deada051e033acbd378ad3e92aefa681297d2ff63678cc2d4d0b80bebab90b2cbacb9d96050927a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edaefadb919dcdc13fdf98f830f3e2a45eb732f4cbe7880b56e0b8bc6efc168e65c32677a7dba4f7f14cc6c510a05d08ebcf05aeca98acee8b7a8b4ad3a5f8f7712ccafd58a4ce8f497d8d87cbb83e61e2c522ed8a4faf88c0cc17ef689dfc82edf27e140fd334911b4bfdb6031eb1eaaf040d2b98673de3c51079d1c066d336eb055e01d58226733ffde8ae0833d24bfcb0d8e6efa00b69472d2cea73dd4d86feca7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d75b2ab1735f9a574431bbb6f9f0333f6e02bd290b1039895e12aefc1ee4719a4d48d8b752fe8478855a70ccd16a49371fedac6234667d603cd30ebf4bcc6003cc2027d76aa0edf868a713e574ab91cec25728b2b8436ae20c1a89b73875b1085f33c7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d645da888654d2ada519cb950ddf6a0717f506a314e34128b07c85bf2ed2903dcf44c9aac724ee8d3ee168849c44d9fd145c558094e516a6c4e2e0cdf53cb16bdda1bffdb58af6073c4200623b4ea3e7731571a2f7cd6fb9800962985ebfbb45bf9001f72cf0ab6835479c6e63d06d54f1cda1eb405c3073be2b90ec333c6f6875fd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc88606c20a867681ab5bb6518e39fbd9013c5642dbd008839cc25669b83f088d6ffbb04aee8dad9d126b77a109024fc60d5ba7f6af76b5cd880e48cd4522b03c89b21395e6896956131207b1db67336e39f2197ae9c00b974e4fa1eedeb15249c4c2bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd93338d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498c832645cebd4051c4cae72f92e67209a37043d15de81aa84449708004d992ddcd32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c13753634402e164aecf24127f8d7f0f3851a24a11c534cd01249ca3cadab0917cb46a9a9f657a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef1264a9838c149243989585adc54c1815d489c1cb7a54a589034e3b1b76a75421ac7ca97a64b155478178921e2b89b21d1bb9c819427b761bb5c0fd7a834e98da9efb72452d48cb44c1e41bc72a0997799f9326ae1b8b131357fa36231010e9d6581cb57f31bb65903dcf1b310d184b0909670953a1a76ed43cf0344a356d0b3df4ac7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456e39a5a5b1785b6fd5e120eca37511143950315b6ac7c698a31142d818e319e019b866693002501c03a91e2093e7ba37182bc0dd82647c0503a6438d48eb91be10441f17a13e37c7f69255953105416cd168e308f38e258e4ccb63be106aa80f94113a38c33618ae769077332f7c15bb0d66499b566be7b20ce97acbe0c3526e917b4f328adf0c137fa7048a6733531049aec840d6097e6f8558ee0be0c6d3c9437a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f5d7150a247e712232d09cb2ab6c14927b33f7e999e2e8de5cc5574bd72c8fd8fe00278b60f1d6f843ca3fc082856b33afce9a8e9f4f94a81ea24acea7effe306e0b2bd983521973b2d3a6626ad1c37ae119d1cac347c0598dbe1bae95fc7ac14e02d32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c137536344d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498c832645cebd4051c4cae72f92e67209a37043d15de81aa84449708004d992ddc2bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd933383fdf1e05f5dff421950a11faa4b7e2fb92de49df004d6c8cf8bb059d174372b6d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b76155b27ac1fad208922fcc91735ff7d427406b4264fa4ddb165ef5d9e16bcc018158be804621634ccc10a85f07e55363b0f025ca77e193f274948fbfe6aec7b2f78aa2986894fdcaecd827564f9e641edfd1d35d0aef3184d5d3c91d976f56ca0ebf872aeacce6970014ff9c1f51ae81d5c5040011742e094b112f61cd86691ed260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7e4e9364324d989c5e01a75f2ae0a73ecdfd6ec97bf77e35e5a65f5e1996f84edcf36a8a2107d572d2e982e00a25915632023d0e377a1f06a263c575fa3100dd12024676b663b554b13222d2033c1b0ae94d1a2123d39e01ae23b2c31b731ecfe19dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd3bce71c6cbeb692a824c86aa5124fad90f116bbdac8a907b97045d31029cdd240c250b803ad337b7ef069bf0741daafaa41dc5c50f592482b4dda00f92b17f808494361641dd0eada9ada0432cbf2c3b788d44814823df2df56a7ca3ef60af2dbe365d768a9126fb809745cb720ac2c61162c42c919c136b02c69645cb3c9e1f17a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b2c0a9681692acb6114480092744c6015f812b255f01f43f22e16af39ca72d5808e6f25e26c6ec0a4d14e8e8abd698e5c8ae7722572e9deba7d61415dd9b348e5e8473aba78e24017e895ef639c37f90a1ca39467635abeba021cc7e21ae502dbb5d8b14fd077480d5c395f14144ec106f1b4445c7e8048d552921cc71b44bc5f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f59bf5c1a841463f9c01d2a55ded6ce8ed980e0dcc4d43878d854c8360323788d70e52bb12cbcc682e06aed119bfd79336ebde5ec4cad7cfd17f201d4350f60512ab672ddd064309778a80ac0800d58e73e9e797757638368f70736f18f8729089025e01d58226733ffde8ae0833d24bfcb0d8e6efa00b69472d2cea73dd4d86feca7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d75b2ab1735f9a574431bbb6f9f0333f6e02bd290b1039895e12aefc1ee4719a4d48d8b752fe8478855a70ccd16a49371fedac6234667d603cd30ebf4bcc6003cc28e6effdbeeedd51fa38912d73884561bd5f6b92a78b5046e471c0a38b46607ddd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b7ff36f927f80baeea63b32fa489b3291e7f3681eef9dd48b68b77627eab003017b2f2edd628b8e57caae6d2b9161485ad547520f208638c83ccf0b3cbf3df1030fdfa2ef90b5d775f01eff318e70d73df2dcdf1f04cfb19ca5cd18731be34b63635292999cef86bb6849124c92859dd306fd0e6bf7be9d86cbb387e838acceec7d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498e436da2799d7878436c70e6c3e98863488311f9331fa9b528de7a40ff346cfb19ab76ef902da4eebedb727ea11575434707e1c2f21b837c780c040f2cace85460217765ada1eb2856c2e9ed19606416ef1d2ce2d0a2f21675b7cfac41adf1d65b87a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75c3837d47df1e00ea0050457bd6fcd31acf8f2c7719d17719ded7d8ba4888a13457e865ce38d01daf8bf3f70e122a3401f9b2793cadc0dc91fad928db13e4f1f2f3bac4729a4c42139fd08860f498f292f4aa14c0495873d36812b6aafe392a54f295e031a083d72d967cf3f301f608dcb22956c676c02f6a0a14e0945675eb9d67a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456e39a5a5b1785b6fd5e120eca37511143950315b6ac7c698a31142d818e319e019b866693002501c03a91e2093e7ba37182bc0dd82647c0503a6438d48eb91be1051246496e868c97a8ff4380150c64908fd59f1ad35dd6960b91c0618b3f7c8501dd81b09b9608944e94e86330fcffe12e89542dd57d961d20baac137629809f64676b663b554b13222d2033c1b0ae94d1a2123d39e01ae23b2c31b731ecfe19dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd3bce71c6cbeb692a824c86aa5124fad90f116bbdac8a907b97045d31029cdd240c250b803ad337b7ef069bf0741daafaa41dc5c50f592482b4dda00f92b17f808494361641dd0eada9ada0432cbf2c3b788d44814823df2df56a7ca3ef60af2db0221c5d7b6c25e6eb1e591bb89895daec91b9328026accf8dadf13df5a894b75fed260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc887ae64ad4b67851a649a84a04c8525c5e8e29812a8668dfe97195ee43b072feca0df690f1a21622e2c8d28660c3fe8512c6c425340fc7249d630a091ba3e24c179964a04b61885d221732079e1aec0bb70999ef33a30db1e3454bfbbdba1b49afb82e6838ea2d6935252ce336232df6583ec016db2146302b8f5ddde8d11be2ef7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d66c68c2dec1bec64acac7b5a9ef669318900f23d3717a2739636323f502e3ee9350ac10c99bcbf7ee1fe6cb298464d1696bc353465d6937803684820774b715a5abd32e56b4e74b446dde3200eaae232cbdc3a950bb28d211c740062a77db17cb66cf2ae548365eee9f422caed24aa6cf9aeffeea21194238a98b89d7d1c3f2bb3612ab6ffc5802b0d18a21986c099926ba7aa74c2f3c9c83f8417e265511a507a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690c0e0751a4a36d50ef4a2392cfa98c2d74f34a2df8f4c1e04e9afd0a06d959bdfafe7f596251de57599e12df11d7183bdff1a8ea8b58be578bb75232c2cb7bef610c4f64b2f5838701f9009e217ec54baeaea2b9fb9d205cb5aa3e7cfe2082eb7023bb6f3177ff6d96f939b570b326ab9646de5cbb2a0d6b99c4e9270796e581d3f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d645da888654d2ada519cb950ddf6a0717f506a314e34128b07c85bf2ed2903dcf4f085c351ae1f8985cc58916b111ce6d39096731d1b0d40fa73f9f14313bd096511d416743ad92a5ab2d405022c59124a59940e5f154e95b7bbd4849ed2106c45996ebfcfd2ca222370831e0b7e32ce0c4683fc95869b0dd6164644619a1e2ae5d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728a0745f6231563c70d9df23ff8d9a8ce5ddb24e977c9018b78271a2e745490aea85aa221877b5b374edf6faec3cad59437ff4cff13d41673c502e79b9983c0b81ff0a900b9ecba787835193dc995f276f4adab2abbdf2405094849b433d7794488b347951f5348806b2e1dbd65cdc9c4fc9b31895a6818ecfc37fc97e8990d048c8c646d1e10512689b64ed99a90ebdefeb70e5f512b0acabfa23eaebcbc7f09ec7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fe366ac77b67b9bdde5d738e26e15138d9cd03bb54d42e422776c4e942e1efd0385929e89dd242fb41f6dec9b60a57e022364813dfef03a6ad09725147523fa38f52d6dd66c67d166b54d597ef8946e555ae881988424eedf198c50edc53ec737264c8dbd0b2c3e68fcc10ff89757c0bc025cfab57a015441a59b8e82d3ccf646402113c6ba93d5c9b17a71f254d603a3326b7e31fbdef5f07fd605142954b34ecd3d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b851651989c59c7f915f50f2d581e6faf6f229ca5b1a5aa9e2a42c37744ab713aa639ef5ecb4049202acb538bf689b475b69a335f0195a8e784f66e61edd02f13267c86c61b19a152504456298184e2906fd5cf0b51a33bcb6f9227f7a5ca6800b391eaf621a8a2d5706663989614a178b8605c3c47ee17d95ad202851fdb9dcfd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ace2c9eaf0504253977cc14e7a65ee95aa8fc59624668458773a92ac98708c21551917a5b5d35890bf09190ddbe1602745924ac0489aa1c7d0a42d9a1c04baefb4ac8834d6bbe4eb7f2e4c58c5895ff75c58256ceec70d9992b046d4261c3d13defe8b771852b4607ec014e5aaf1e41db6c4565a89eac8059ea32ec8d6a9e47a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690ecd171644814eb0515e8033b244cd746648a423500c2bbcdf4fc04774b5f7bc950338e32e18d094db888199fbb2627c2efe369a9d3418d6d193414858815472d7936e3fcda810d8095d83015d43eb23e7b11efbbae8ef8598cf9480c7751ca2b02072faaddbfaa767a91fc111c322e1465e0b109820cf2bfca10a4f3b2bcd2f6c97a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b2c0a9681692acb6114480092744c6015f812b255f01f43f22e16af39ca72d5803ee45e31d7f2f10d3b6a9e2fad5160f07a6ddd01637009ad88e9ddb74ed0bb08ca027a634dd0e200654177f6a54c524f452ad129fcf0713fbebff1f1dfc6088ca65437912a85304ec669b9c92cd4c17f57309c267b8f8edffbf17aa943726afed260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728a0745f6231563c70d9df23ff8d9a8ce5ddb24e977c9018b78271a2e745490aea807d4352754ca060f5a6021253b04bb53c63db90946fa453ec12e450b4f1960066cb9190aa160dd35a0a0a5c0079c27022021227b1392fc53fdab219c2c0a573f80c86a33f7d00bcfb5274ab452cdcb539f7ef164de25a5503c4a3115e35f633617c109c2bab37700237f74069210516d4066404ee979417c37eae627ce50a8987a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3637c8550a50814cc02ec9353ee556542249ffcdaf983ec57a679df35b2072d1c74544c0a6979e7c37e322b970df199083a11b93f89bc7ddd390769af74e12fc024916cb995f103b3ed19424572ff332feaef953866ccde799161ac50a7b4a3a30d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b7ff36f927f80baeea63b32fa489b3291e7f3681eef9dd48b68b77627eab003017791a4d6b5523c56d55e1181d9b00d77548fb5ee6ad59e0ee813b1daba5d16e742c980288e2b82cc321c0645de9c9a068ec509c7788c5787a598098b42f098b1a77ef7583c1c7f39f2a8729090c5e4c2e7a22890d1f8727cb6e2bd0992707f61fd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc1fef87093132117c137ddb0d0dfbc35bc776a8ac8e6bb3a3ad1383756fbd21ac214ea0372c2a028a245fc25938183ae33e5d44a6a40f5d956c713b3b30b9b73ce9a2cf1aef260ef232e16f988ecec03eb7e342ebc2d97850d40fce106108d20e4c9074efb6e52141111c0e43bd78a25772cff8084072388397ef7358531d85fe9f36a8a2107d572d2e982e00a25915632023d0e377a1f06a263c575fa3100dd12d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7e4e9364324d989c5e01a75f2ae0a73ecdfd6ec97bf77e35e5a65f5e1996f84edc0ebf872aeacce6970014ff9c1f51ae81d5c5040011742e094b112f61cd86691e026962a589e00a4b4cd1ed8788d10f48e3a78fd1f0ca9925db7b5fcc551a043f6bd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc887ae64ad4b67851a649a84a04c8525c5e8e29812a8668dfe97195ee43b072fecac50e9db5b5b75aa85ab101ad0228677e0250588aece0cd0d9b32a51029d9214c8602fb3386007a97bf729822083db883f5eb08abe05e532f02ceefa728aa2edde8473aba78e24017e895ef639c37f90a1ca39467635abeba021cc7e21ae502db7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b2c0a9681692acb6114480092744c6015f812b255f01f43f22e16af39ca72d5808e6f25e26c6ec0a4d14e8e8abd698e5c8ae7722572e9deba7d61415dd9b348e5e365d768a9126fb809745cb720ac2c61162c42c919c136b02c69645cb3c9e1f1e66456a01ccd1fac39e7af6d9935ccc342a0c1a55c0a5d47baad214fa1daa434d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b965927d84774afc3e337c16f0a9b10656cdafddc9b5561bf69c64de4ae20240fd9014d76fcb53f1a5b0c1062e774f53a80b7162d2e786e600b1decf7d3937ddd48efe1e28cd566509f0ae3e691e853f8a013997c856179970169634e0869b597ad02cb4ea5ef845cfe017abe9f56955f645a7c078b3331b372e9356d58c4f208b43ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65f64a4bdfbed0ec09e9022a449eb6bba5f05f6ad40542493d3ac3b7314a944fc31a9bceb02458b4e0cef21d6981932ce01500890c16f7a87eae8ce93e08739714152e9f623e5ed008c4231479488947749a5ce870e3d013d3788d5fd5f647006b2ad3ee89757fde4ea78328f454f51fdbadbe19d6f7f5d07799274f3787576e217a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d7518d6ec7a2438aef9684007b2465689da3b335982b5d11c192201cda810e0a587589195a8fc2a269e475cad21c8581118e244c1aceb9e057e5424e9372f071575640e3bf37f99beb20359117de982be84a1d420c896689e55e0fb50d6d4cdeb21d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0ab436e9765144f12212f8016ee699e44f053b3715483c6ef0eba5a1e63750e474ef42877cfdd17f5fe0263bb9527819dbeeddde046807e99ba1863890fe0efdd21819079699a0249d73ec6ef53c2bd18230bc605bacfcdedd4c29acc4e65ae75002efe1e28cd566509f0ae3e691e853f8a013997c856179970169634e0869b597add260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b965927d84774afc3e337c16f0a9b10656cdafddc9b5561bf69c64de4ae20240fd9014d76fcb53f1a5b0c1062e774f53a80b7162d2e786e600b1decf7d3937ddd48e66456a01ccd1fac39e7af6d9935ccc342a0c1a55c0a5d47baad214fa1daa434620100875f0e016b9413c0c82e4fe3c9dad1cc92accd3955f2e23162c9f42f777a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456eb85eb07e1177f4f3dbb7125714c22fd592b0b3e689067cb378562ddbb82af5dd516f9b7e697d312cc40f4fb43b6fabfaa427e6aacfc29037a19850031963acc23b5d7c4c79e1a7eb41d3f77b14fef238936171dc5ce73f6d063698b37790659b0ce92f8f2c00afc455250fb123496987f04e2b23ece870811b1f862f7081e823f4cd0c7229218401b08ec1d76c2b0b7ea1a14ff9f78a8f73208ef469f264ab157a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6caa3e65c39a645d40bf967ef4a701927e10722c137b119c52f7f5fc8656507c7c05f131980dd362a0a57727c000f6a5df01495848398a469e3083b4c440a7adeb97e33694767b9fa6437f82bb2be0b3085c07ce8f2639fe96e3623c55124170e8b8452b0548d20ecd8b76cc53e6cd4af8e856e8dad6d16474858a8c240ce936400285f564e1d096d93c0073c244a9ed658ee27391299c7de0583a2986d5abdc312d7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a2685d3e2700643155ce892aa133fe5467eadd5df312175834802acd595b1cfa1290896d81e9d590b4e189b77f483d22a81bd0990ef3130f858436d44dcbe5556693c84d9cc703961887e3d445d5fd960230f43b84a25a8be72d015a51c2e6b6861acd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd30f40c4c59a5e09f8717da346133688fd5949cd48b191a58715ba9958a2184931fea0fc96e448b379d7e9728083e5888780be506c91b13093988402c87fdbfc0b2b414c09cb30b2c44fff9a5feadfb4ac6e6ad88fc023a82af10e994d359e9b5a6a01b8b0346842960fb64e14062cba6a50c3e8edcd89a0cad30a4094815282f6d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e952294975cbb0de32b6b86ff2557595ab9609853ffafbee50a9a877f4897b8d5681ac9fb82a14d11733b16bfa4a79a2b625ee34f71d829f5d6e1c99eb3d95122ddb64cc2654295a4193f299799a23cae6179f1a07e54288623e265531c3ae322f51eb8af020b2bd983521973b2d3a6626ad1c37ae119d1cac347c0598dbe1bae95fc7ac14e7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f5d7150a247e712232d09cb2ab6c14927b33f7e999e2e8de5cc5574bd72c8fd8fe00278b60f1d6f843ca3fc082856b33afce9a8e9f4f94a81ea24acea7effe306e7b4f328adf0c137fa7048a6733531049aec840d6097e6f8558ee0be0c6d3c9432ed8b8173be8b51cabe43288140905327cab82ffcfa300de313a68abbbe198b17a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74cf884927542b74251960a1d134e0cd84c985d9218e08c88757c2f63b496835489a5badc79de6ccbbdab23b02313358e36f3331dcc175bf14d14bbaebc6bbb1bacab22f7c044dfaefcf970ec1179dc32c1e99298727839dad9107c9b4d2f2f7354d0e41d628c32a51f9ef2ebdb438ffdb836881d33774ffba67ade97cd093fd857a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be438091a03f98ecad521e99d5e837c56af546e8628e7761092f8e306456460063d1e54d567858e5070e3537ee3cb85f3983c5132e2c0da29eda329d9ce64dc0209ede90873683e203ec010eb4fae657aefde4a293e1a5284de0f9e5c34c1a3285902a647fedabc5543b8e0e0e1f918b8c6023329ee81b221a81b6975632e5e1cb95b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690c0e0751a4a36d50ef4a2392cfa98c2d74f34a2df8f4c1e04e9afd0a06d959bdf964da06351b8b14f0888c36833f100e8704692c721cd91a364476fe2291d8266b29bd878932e92aaf12a7d9ac5c7d7f45f2abfd1897a6925ad2d835c3f0294b1aa84da3d88c99c847fbf61ed0145d387c9d58f1cc34189c6e7eb64217a6b1ca2d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d942dea60ac728bf8fd91fac99773f0337996b515439c24f9fadbb33d76472102b763293b793482163d3e17bda4d911eadfd85044430cb58a94e5c8c4359fcb37277155f6c1b22fb1aaab7fbfd1be7597326dca6377349fd37ddd54f4ad74426800f98e4d444ef79cf4c1fdbe89c1cb66051bee85483e842875afce6c60dab425fcd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b851651989c59c7f915f50f2d581e6faf6f229ca5b1a5aa9e2a42c37744ab713aa345eb1681c1f4130d08fd614bfeee0a5810462eae789d83a997472b82935156ff545241ffe9ac13511bcea11fbd857abcce63dd2b6a9efb7c4948657c3b53f0025a0c24d6432d28d80e65ccf55d7d194761752a7c0933cb6db371d841fb8f6a22d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7ee0b0dd649465547ea5f14c1bf262df14c93fdae97ea9f13ad6d9b42b87b51812868a4e4bb8398438163188f1a9382bb8b6d43698a59c4194db629bac696befea31f53cdeeab00dcd9f878a69bf0e4523e8e0d80a04c78eb0dace6254eac9d10c7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a26852d6de0887008fc74b561ac7770ccbefe298086d4a5cf437fd723c73fdac65ff123589582482baf1bfe5ea2507b9ed0ade68662d152b71acba9310ee4fc3df21031f53cdeeab00dcd9f878a69bf0e4523e8e0d80a04c78eb0dace6254eac9d10c7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a26852d6de0887008fc74b561ac7770ccbefe298086d4a5cf437fd723c73fdac65ff123589582482baf1bfe5ea2507b9ed0ade68662d152b71acba9310ee4fc3df2100280c86a33f7d00bcfb5274ab452cdcb539f7ef164de25a5503c4a3115e35f6336d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728a0745f6231563c70d9df23ff8d9a8ce5ddb24e977c9018b78271a2e745490aea807d4352754ca060f5a6021253b04bb53c63db90946fa453ec12e450b4f1960066cb9190aa160dd35a0a0a5c0079c27022021227b1392fc53fdab219c2c0a573fa65437912a85304ec669b9c92cd4c17f57309c267b8f8edffbf17aa943726afe1819079699a0249d73ec6ef53c2bd18230bc605bacfcdedd4c29acc4e65ae750d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0ab436e9765144f12212f8016ee699e44f053b3715483c6ef0eba5a1e63750e474ef42877cfdd17f5fe0263bb9527819dbeeddde046807e99ba1863890fe0efdd2640e3bf37f99beb20359117de982be84a1d420c896689e55e0fb50d6d4cdeb214d0e41d628c32a51f9ef2ebdb438ffdb836881d33774ffba67ade97cd093fd857a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be438091a03f98ecad521e99d5e837c56af546e8628e7761092f8e306456460063d1e54d567858e5070e3537ee3cb85f3983c5132e2c0da29eda329d9ce64dc0209ede90873683e203ec010eb4fae657aefde4a293e1a5284de0f9e5c34c1a3285902a647fedabc5543b8e0e0e1f918b8c6023329ee81b221a81b6975632e5e1cb95b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690c0e0751a4a36d50ef4a2392cfa98c2d74f34a2df8f4c1e04e9afd0a06d959bdf964da06351b8b14f0888c36833f100e8704692c721cd91a364476fe2291d8266b29bd878932e92aaf12a7d9ac5c7d7f45f2abfd1897a6925ad2d835c3f0294b1aa84da3d88c99c847fbf61ed0145d387c9d58f1cc34189c6e7eb64217a6b1ca2d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d942dea60ac728bf8fd91fac99773f0337996b515439c24f9fadbb33d76472102b763293b793482163d3e17bda4d911eadfd85044430cb58a94e5c8c4359fcb37277155f6c1b22fb1aaab7fbfd1be7597326dca6377349fd37ddd54f4ad7442680031f1f49fdd14c72311bc94d0105ce6dd20119f0e16f1edf4e7b62de293c00110d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e8e26a61abb0582c580b1c9afc4e3e0cd5187d6dd5383bbc43f60049db396bed80150b087517d43972402c040ed40b08058271277c5cd5f1fdf24205656c026c02b0a86454f6458df8e684f0c8753be6214a639539769faf21c65e5ec96030c7bdee6c49da18fbbccad6e815171d75512afc64c88e3fa12febb166f03d5c8073c028a58d9c3db5c0960ad11e9b1ad3a86e7e091c518b13ca8e0ec7f6073afdbd4c07a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d647ef4823f03fde4e997ffed3fa63eb0593adb939217ac3646960c97a1b843fbdb4ff59f2a1d5ed70f352e8ccfcc5d504370f0188424e8584f8a29cd140292af7119affec3fa4cb019f1acb1a889966a7cf6be055d37fb692cb99756a5550cc107e843889eeef71c1a96c9e33eab9256df25998013e17121d0c2bc7ba9d6492a3f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edaefadb919dcdc13fdf98f830f3e2a45eb732f4cbe7880b56e0b8bc6efc168e65c32677a7dba4f7f14cc6c510a05d08ebcf05aeca98acee8b7a8b4ad3a5f8f7712ce6fd29f7777bd8abfce96a9e6668452ec512bbae8a86b15453f69208db254afef45504ec687ddba0176856f7e4cf90035395b2fb03092f84f5e0867c78208f7ca950ad0dad368903b2b6508391255db20c9eec8725b4855ac8e8ff56df6f9390d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65c74cd65d09e9f22aa61acb0e46a4d8f5799007c3d3028b25bf821f9551a8584e0912e594068aa2ccb716cdfaede8a5308a287c03d6b9354ee8bb63a9e8af86a070272da38d7de0f7bb8b8a5852bffd9161097f2d7008335e9212429cc1373979026aa6c602fd435a2c8c9e4b8d2d8882bf8963c6e44a0326828f10587cab12f31ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b76155b27ac1fad208922fcc91735ff7d427406b4264fa4ddb165ef5d9e16bcc015765c9624b3c9b6860983e09d680388cdb193b673ff9efdba22ca288c25c1e24e62d2dcfe473310f8747edf3d417ae6cdff98d0610130f3e04b64d09a7ace265bf464d5b0fb39a73f1945bed495bbac2e3c87bcb12031dd06e5281d6af70b8e27a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f5d7150a247e712232d09cb2ab6c14927b33f7e999e2e8de5cc5574bd72c8fd8fecda68952bdcac818d2e16e0394b05bb7f4398c73ef59523a58f4b723ef11345d1adf17e9f086319c22be397c793f84f1c31af689aea3753616612bfd2b6ad38b6122c9028271b0ff6d4579ef9de1603dc70ccbfbaba99b280c96647ec496713b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef126423cecc6fc9657c529e33b5df0f6e5f7f1d825bb2914c3ed5fa2f49bfd7e17abe89f40c7afd9ab40fb84fbe2e6b8df05f26980324efb139a101267dc20c94901ba8968aeb2cf78a397a9a1fbe15e17d85e40a96c9c9a92e0cde9d7d3aab2f56d102c74544c0a6979e7c37e322b970df199083a11b93f89bc7ddd390769af74e12fc7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3637c8550a50814cc02ec9353ee556542249ffcdaf983ec57a679df35b2072d117c109c2bab37700237f74069210516d4066404ee979417c37eae627ce50a898b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab1325773497609f32961860d65c658d6bb938343f35c9c1f987d72425cd21aebd078181e6ac08b7899cbf2432aa08d2958b467b623644394b4b8bbd812a8cef59e414488c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae761adf17e9f086319c22be397c793f84f1c31af689aea3753616612bfd2b6ad38b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f5d7150a247e712232d09cb2ab6c14927b33f7e999e2e8de5cc5574bd72c8fd8fecda68952bdcac818d2e16e0394b05bb7f4398c73ef59523a58f4b723ef11345dbf464d5b0fb39a73f1945bed495bbac2e3c87bcb12031dd06e5281d6af70b8e2024a4353e11b2e3fd7a244a0703d4d3397b54ebb6c98bf649fca2f5fc1e0ad913cd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab13257c437c42819e6205313085d4a401e6b4f988334a9cefefaa65e3ae09ef905545813d12e1b0ff053e1cc29098fe0d4ed6be1012034b4d0756f0f7c42cfaa38cfe151446b84d226cfd57adc2df0b5e9a8b3b89d9cca8262d22e9c69f4ac55859b80e62d2dcfe473310f8747edf3d417ae6cdff98d0610130f3e04b64d09a7ace265d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b76155b27ac1fad208922fcc91735ff7d427406b4264fa4ddb165ef5d9e16bcc015765c9624b3c9b6860983e09d680388cdb193b673ff9efdba22ca288c25c1e246aa6c602fd435a2c8c9e4b8d2d8882bf8963c6e44a0326828f10587cab12f31a8f60911463de55684f83a17922c5200ab44b7e0a9fe05f988d6e8a54503792e67a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be438091a03f98ecad521e99d5e837c56af546e8628e7761092f8e306456460063d0db22229b18a7da9ae5120e174183db78d218e69630e39d46763c4cac71bca7918e1d821b674f55fd73d41830a1a60f6d1e7f2b2dc78e8c75dfaafc5992ec58f0210c4f64b2f5838701f9009e217ec54baeaea2b9fb9d205cb5aa3e7cfe2082eb77a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2b480ebd1e54494c04b68137b567242aaccaf1c37c924fe68cf721a6fe11216690c0e0751a4a36d50ef4a2392cfa98c2d74f34a2df8f4c1e04e9afd0a06d959bdfafe7f596251de57599e12df11d7183bdff1a8ea8b58be578bb75232c2cb7bef6b3612ab6ffc5802b0d18a21986c099926ba7aa74c2f3c9c83f8417e265511a5059466cbb6d4ef2b9f80dfef4ac7da76f320bb7d5ae7c2dc27bd601c6a3365f30d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d942dea60ac728bf8fd91fac99773f0337996b515439c24f9fadbb33d76472102b73160ccc9a5dab18c995ba018f1d07f399243865198b15742d6145ad5d1b1a9ed285ae08af1a363f8de8c8e1f1b899bd95bf919b7052c24595feca1e39ee25f4f113a38c33618ae769077332f7c15bb0d66499b566be7b20ce97acbe0c3526e917a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456e39a5a5b1785b6fd5e120eca37511143950315b6ac7c698a31142d818e319e019b866693002501c03a91e2093e7ba37182bc0dd82647c0503a6438d48eb91be10441f17a13e37c7f69255953105416cd168e308f38e258e4ccb63be106aa80f94b57f31bb65903dcf1b310d184b0909670953a1a76ed43cf0344a356d0b3df4ac02024ab31c508dec2a22e0d810cf2ca84c068bcb275c5c2a2e31451ff12280e1ce7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3d708afb6220ebd6f3dfd32d218acceb4cfd691eb93601ba886928523ce99d1846ed2401a1b23725d86ce3dd098fd8df282fe9f9832d593630e95881df66a12131f1f49fdd14c72311bc94d0105ce6dd20119f0e16f1edf4e7b62de293c00110d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e8e26a61abb0582c580b1c9afc4e3e0cd5187d6dd5383bbc43f60049db396bed80150b087517d43972402c040ed40b08058271277c5cd5f1fdf24205656c026c02b0a86454f6458df8e684f0c8753be6214a639539769faf21c65e5ec96030c7bdee6c49da18fbbccad6e815171d75512afc64c88e3fa12febb166f03d5c8073cf03eb85756e1ea89cb3ad2ac61479e97ab2cc9e59ebd0ecf70e2aad6e2bb692a7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fe366ac77b67b9bdde5d738e26e15138d9cd03bb54d42e422776c4e942e1efd03870e3925575941613c0e065ddb8fd5b1c85e6d9782fda92ca6482bf78b250b5723673c60d9f29df6ae5741988382bbba7b92d3586d24bfb784a118c29face06feea59a564456ba0f9d9eed56bdec2b73cf0cc6f7a3073e71d1bb5a2519702899402be23e8d689b5429ffdd8f0b38bd60befa78d83b77ddc73bd360088b6229a678dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b96a8332048262676a7827e2e6a99d04c7f4e030999a21cf92b2be5d0042e4d2f76bb3ca62f1a0f0a75fa84e9c5e10f7737ffcf0dd810df514cdc851b508dad8bcc3a66ed2f43c0eb2e5196d48123df1a4722ab34215b464df322e5c2962534a7f5d32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c137536344d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498c832645cebd4051c4cae72f92e67209a37043d15de81aa84449708004d992ddc2bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd9333835292999cef86bb6849124c92859dd306fd0e6bf7be9d86cbb387e838acceec7d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498e436da2799d7878436c70e6c3e98863488311f9331fa9b528de7a40ff346cfb19ab76ef902da4eebedb727ea11575434707e1c2f21b837c780c040f2cace85460217765ada1eb2856c2e9ed19606416ef1d2ce2d0a2f21675b7cfac41adf1d65b87a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75c3837d47df1e00ea0050457bd6fcd31acf8f2c7719d17719ded7d8ba4888a13457e865ce38d01daf8bf3f70e122a3401f9b2793cadc0dc91fad928db13e4f1f2f3bac4729a4c42139fd08860f498f292f4aa14c0495873d36812b6aafe392a54f295e031a083d72d967cf3f301f608dcb22956c676c02f6a0a14e0945675eb9d67a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456e39a5a5b1785b6fd5e120eca37511143950315b6ac7c698a31142d818e319e019b866693002501c03a91e2093e7ba37182bc0dd82647c0503a6438d48eb91be1051246496e868c97a8ff4380150c64908fd59f1ad35dd6960b91c0618b3f7c8501dd81b09b9608944e94e86330fcffe12e89542dd57d961d20baac137629809f6c9aa115b438cf9a576e9447ba0d1cde19ff07ccc9ce0fde96d78e02aff80f8fdd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e95229497460ea30039c2c5753c8e3922e2b40bdb45c3ecb0be153f3b396510ae97eba83d6de38fd6aede97c70f11bfd59b42549b5b58da0f4a39a1d427929182fa4d173863b23b13a94ef8b013bb36ceec3622ed84a03657f9c76dff4c5734bb53a8640502cb4ea5ef845cfe017abe9f56955f645a7c078b3331b372e9356d58c4f208b43ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65f64a4bdfbed0ec09e9022a449eb6bba5f05f6ad40542493d3ac3b7314a944fc31a9bceb02458b4e0cef21d6981932ce01500890c16f7a87eae8ce93e08739714152e9f623e5ed008c4231479488947749a5ce870e3d013d3788d5fd5f647006b643cf0a33eccd27c7e046f2584608fdcee3af58250c6b9b94df5c3ee10698e237a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74e48c187a35459d43b6eb1fe9397abbd5944f0793164fdebab38f21d62a786a51ee2ff295a52ca3c3629a4900cbc174bb3a601f41b9fc3155b61d4ee124f824b1833f95e8b204adfb77da9420aab0ccfbc2794f34af9031b42b1a8e7d05de13422bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd93338d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498c832645cebd4051c4cae72f92e67209a37043d15de81aa84449708004d992ddcd32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c13753634402e164aecf24127f8d7f0f3851a24a11c534cd01249ca3cadab0917cb46a9a9f657a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef1264a9838c149243989585adc54c1815d489c1cb7a54a589034e3b1b76a75421ac7ca97a64b155478178921e2b89b21d1bb9c819427b761bb5c0fd7a834e98da9efb72452d48cb44c1e41bc72a0997799f9326ae1b8b131357fa36231010e9d6581cb57f31bb65903dcf1b310d184b0909670953a1a76ed43cf0344a356d0b3df4ac7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456e39a5a5b1785b6fd5e120eca37511143950315b6ac7c698a31142d818e319e019b866693002501c03a91e2093e7ba37182bc0dd82647c0503a6438d48eb91be10441f17a13e37c7f69255953105416cd168e308f38e258e4ccb63be106aa80f94113a38c33618ae769077332f7c15bb0d66499b566be7b20ce97acbe0c3526e9185a606192946e307f729d69cf92c9f42830c7ce5922162746ff8d2f241c68bf27a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a32062b098a2dd55fb66c14cecc5f28d7fc1b96c58da3222b302f906ba2dfa7fc3d4ceacb0c37f6118d71e8f481a2dda213bc20768fea06687a89fd8dc2638c7b2c072f15085fbd4d83dbb801e6747f0180aebc55e0fc8825f089490f74abb5264cd8d564cad7aa424d24c5fce6f719457cc0bc7eefb3d77bfdba8761ab30651b902e2837cba0283ab49873e0b804cada4c96ddca939fa57a35ea66f9b10be002b4e7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6caa3e65c39a645d40bf967ef4a701927e10722c137b119c52f7f5fc8656507c7c05f131980dd362a0a57727c000f6a5df01495848398a469e3083b4c440a7adeb72645839227e0c922796a8451b17e91a9b4bcdce0164adb52baa9b308c3e8d9278908819a945765ec323085a40221384ceeb91f4261414116e7c8494a327eea7699cfcc8a802c18a5d3fc502352e242116ead356b2b77515a3ca6a128cb811a0d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c1499962274a7bf7daab46c23f4c5ea24691f256e70cf86f9ed7bf31ce40fd17a20ad2e93073d6897ed87885c918161439134a99c0c0e25cbae8e9931e66104d8efe63865f96c71b9e6dac3a18598d432cf1b26873ae6baaa5b2fb02d6ae81820dd63bd49b80e46ba4a953b0b41248db1ef33f0804f1de424eb213446abcb4d1d1ac3866814f63423e40eea23f5d3a775a3db609785f9144ac4c2a950fe252bb1255d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c1499962274a7bf7daab46c23f4c5ea24691f256e70cf86f9ed7bf31ce40fd17a20a909935a7f7ef67c542cbf1b06b366eda292d14d50aeb210822e5e93ab310f6c708b05769616d9a8db80300d8b3167297c5543f8c48fe1ef605f0ae021043ac6518618b06492a8529c6a2a493155d43c093deed2d6afab43e0b1a87369da912e70271d4200634c3fba2ec6ed0df3dc97a40d6a15f0fdf30338598eb3d51524cfd3d7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fe366ac77b67b9bdde5d738e26e15138d9cd03bb54d42e422776c4e942e1efd03870e3925575941613c0e065ddb8fd5b1c85e6d9782fda92ca6482bf78b250b57267c48f3a0061878230e132866ef7508adefe6f63eba9f3f83240bd49ecfe5858254ef2cf3d1f42381206808e0d5f7e2a466f6390ceb1eec3b2f100260e2f4ba18a58d9c3db5c0960ad11e9b1ad3a86e7e091c518b13ca8e0ec7f6073afdbd4c07a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d647ef4823f03fde4e997ffed3fa63eb0593adb939217ac3646960c97a1b843fbdb4ff59f2a1d5ed70f352e8ccfcc5d504370f0188424e8584f8a29cd140292af7119affec3fa4cb019f1acb1a889966a7cf6be055d37fb692cb99756a5550cc10785f564e1d096d93c0073c244a9ed658ee27391299c7de0583a2986d5abdc312d7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a2685d3e2700643155ce892aa133fe5467eadd5df312175834802acd595b1cfa1290896d81e9d590b4e189b77f483d22a81bd0990ef3130f858436d44dcbe5556693c02a37350e03eceefea61586896cec6c60a48556dff473d47d27fad1473669bc628d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65f64a4bdfbed0ec09e9022a449eb6bba5f05f6ad40542493d3ac3b7314a944fc30cff94f7219a530b70cb887402d1928c4b27caac69525eb25a1e33251bc615e1b1f95104c13cbeb266ab7727e8eb52ba5be8bd8ee6963a15bedf2fd5f387a9fdb66b4752e276a7afbc8c5b6b29a84ff18fb488fb693f5a313e21a938d6bd650ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0ab436e9765144f12212f8016ee699e44f053b3715483c6ef0eba5a1e63750e474f54c9511b843a3ccc99a6c1e4f41396b0e99ca5746be3377c6570d29a55f2e5faab01c1021f63e7d9bb4f3b9b4e89aacec88fb938417452388ea16f39eb42efde164aecf24127f8d7f0f3851a24a11c534cd01249ca3cadab0917cb46a9a9f657a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef1264a9838c149243989585adc54c1815d489c1cb7a54a589034e3b1b76a75421ac7ca97a64b155478178921e2b89b21d1bb9c819427b761bb5c0fd7a834e98da9efb72452d48cb44c1e41bc72a0997799f9326ae1b8b131357fa36231010e9d6581c02cb136476b4ac17dcc9c39a1a67651ad3bb59fe5b0f5f7e8a798c1e627d3a3945d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0a9567e4fb9f821af7c84f92a8b4cfc53b6a069f70e5145ad60ad5dae071a0933be3b92f3e093314adad9117b3eafe0d27cbb57de49a1b338c2112d5cb71bcf72568b60ec11424e8f217e61460fb69035a60319a21b08f89259640b646cdeb69244a4353e11b2e3fd7a244a0703d4d3397b54ebb6c98bf649fca2f5fc1e0ad913cd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab13257c437c42819e6205313085d4a401e6b4f988334a9cefefaa65e3ae09ef905545813d12e1b0ff053e1cc29098fe0d4ed6be1012034b4d0756f0f7c42cfaa38cfe151446b84d226cfd57adc2df0b5e9a8b3b89d9cca8262d22e9c69f4ac55859b801ee038737c7311bea5b5de81b7bf321efd7fd91559f96083628f12033cd2e788d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f71d2d30bb7635cbe00b365df7cf16bd16eade457e84fe6a48bfeebc3a50c5d5bb10c1a682751fe3043ec771924933eb7c33f39b9353b578a66c428edf5aff1e10417aab7ba948b8c2d8042340bde3a7a9478cadb8de2dbfbc96a2a3c2d5b07401be12db6c2ce592c080ffa43a5b31f0c9f7092cdb8e133e4f747314cb1b1d9d1f02cd8d564cad7aa424d24c5fce6f719457cc0bc7eefb3d77bfdba8761ab30651b97a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a32062b098a2dd55fb66c14cecc5f28d7fc1b96c58da3222b302f906ba2dfa7fc3d4ceacb0c37f6118d71e8f481a2dda213bc20768fea06687a89fd8dc2638c7b2c072f15085fbd4d83dbb801e6747f0180aebc55e0fc8825f089490f74abb526485a606192946e307f729d69cf92c9f42830c7ce5922162746ff8d2f241c68bf2442b242b9aeda3a73d38149f70f82b7b85638a16781f0339b5044c94416c6fa27a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be411b19e9045189ea4cebcac9f2e99aba1e2f4ed7d0184c148144fb82d5b6bd545838e95556178e3ba26bf6392751200b04805dd9c842963bd4136a926256064e913e620e2f52d8e6b925817f0d0da978a5556d8a1ea0a34905d3d223822e9ff54589195a8fc2a269e475cad21c8581118e244c1aceb9e057e5424e9372f0715757a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d7518d6ec7a2438aef9684007b2465689da3b335982b5d11c192201cda810e0a5872ad3ee89757fde4ea78328f454f51fdbadbe19d6f7f5d07799274f3787576e210218618b06492a8529c6a2a493155d43c093deed2d6afab43e0b1a87369da912e7d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c1499962274a7bf7daab46c23f4c5ea24691f256e70cf86f9ed7bf31ce40fd17a20a909935a7f7ef67c542cbf1b06b366eda292d14d50aeb210822e5e93ab310f6c708b05769616d9a8db80300d8b3167297c5543f8c48fe1ef605f0ae021043ac653866814f63423e40eea23f5d3a775a3db609785f9144ac4c2a950fe252bb1255542395f0718450f715b95e91939dcb7c588e2f72482b929d425043e9e258c891d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc88606c20a867681ab5bb6518e39fbd9013c5642dbd008839cc25669b83f088d6ffb7d984e65c78b6deb02b591f498e70409c69c383f9b3a051a009319a11fe0c60d5908cb4505ba63472b1923eb1c34bce6fd255b71ff72dba545e0ca231e4e20a3f9b7c485dcffdba1a2e44445bbe27f800ba62347e2e2d66e953e9618dbcb4c57a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edaefadb919dcdc13fdf98f830f3e2a45eb732f4cbe7880b56e0b8bc6efc168e65c338333cd1eb8fefe12577bbd1c27f3da7a12b3123f8ef0e3811fd788914136f370bb707d5984a16d8e569d1398a99ccc6266bd50cee6138a32a179ca91ba2e60ebab8c7c01e545ecd6e433aca5fa360e25b4cf9758d9eb62d14cc73e055da2e1902b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab1325773497609f32961860d65c658d6bb938343f35c9c1f987d72425cd21aebd078181e6ac08b7899cbf2432aa08d2958b467b623644394b4b8bbd812a8cef59e414488c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae7675869550e337d7846815f928c4f2ecdcbe49ff621ca8de23c690bff5ed88acbdd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f71d2d30bb7635cbe00b365df7cf16bd16eade457e84fe6a48bfeebc3a50c5d5bb10c1a682751fe3043ec771924933eb7c33f39b9353b578a66c428edf5aff1e10cb91adefbd1bada1f7712783c6fee2bde4c46f94959d641c7fd71646706aa2deca00ac440ac549cc810c949fe21a2fae5b0dd5ebc2e3860a1aa5a28d60e794afb5d8b14fd077480d5c395f14144ec106f1b4445c7e8048d552921cc71b44bc5f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f59bf5c1a841463f9c01d2a55ded6ce8ed980e0dcc4d43878d854c8360323788d70e52bb12cbcc682e06aed119bfd79336ebde5ec4cad7cfd17f201d4350f60512ab672ddd064309778a80ac0800d58e73e9e797757638368f70736f18f8729089025e01d58226733ffde8ae0833d24bfcb0d8e6efa00b69472d2cea73dd4d86feca7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d75b2ab1735f9a574431bbb6f9f0333f6e02bd290b1039895e12aefc1ee4719a4d48d8b752fe8478855a70ccd16a49371fedac6234667d603cd30ebf4bcc6003cc28e6effdbeeedd51fa38912d73884561bd5f6b92a78b5046e471c0a38b46607ddd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b7ff36f927f80baeea63b32fa489b3291e7f3681eef9dd48b68b77627eab003017b2f2edd628b8e57caae6d2b9161485ad547520f208638c83ccf0b3cbf3df1030fdfa2ef90b5d775f01eff318e70d73df2dcdf1f04cfb19ca5cd18731be34b636ede90873683e203ec010eb4fae657aefde4a293e1a5284de0f9e5c34c1a328597a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be438091a03f98ecad521e99d5e837c56af546e8628e7761092f8e306456460063d1e54d567858e5070e3537ee3cb85f3983c5132e2c0da29eda329d9ce64dc02094d0e41d628c32a51f9ef2ebdb438ffdb836881d33774ffba67ade97cd093fd8502b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab1325773497609f32961860d65c658d6bb938343f35c9c1f987d72425cd21aebd078181e6ac08b7899cbf2432aa08d2958b467b623644394b4b8bbd812a8cef59e414488c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae767155f6c1b22fb1aaab7fbfd1be7597326dca6377349fd37ddd54f4ad74426800d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c149c5a3c086a41786a6379c465bfec54c5a68421677f5e9cd15c3bed93f0ef25d942dea60ac728bf8fd91fac99773f0337996b515439c24f9fadbb33d76472102b763293b793482163d3e17bda4d911eadfd85044430cb58a94e5c8c4359fcb3727aa84da3d88c99c847fbf61ed0145d387c9d58f1cc34189c6e7eb64217a6b1ca231f53cdeeab00dcd9f878a69bf0e4523e8e0d80a04c78eb0dace6254eac9d10c7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a26852d6de0887008fc74b561ac7770ccbefe298086d4a5cf437fd723c73fdac65ff123589582482baf1bfe5ea2507b9ed0ade68662d152b71acba9310ee4fc3df2100280c86a33f7d00bcfb5274ab452cdcb539f7ef164de25a5503c4a3115e35f6336d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728a0745f6231563c70d9df23ff8d9a8ce5ddb24e977c9018b78271a2e745490aea807d4352754ca060f5a6021253b04bb53c63db90946fa453ec12e450b4f1960066cb9190aa160dd35a0a0a5c0079c27022021227b1392fc53fdab219c2c0a573fa65437912a85304ec669b9c92cd4c17f57309c267b8f8edffbf17aa943726afe1819079699a0249d73ec6ef53c2bd18230bc605bacfcdedd4c29acc4e65ae750d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0ab436e9765144f12212f8016ee699e44f053b3715483c6ef0eba5a1e63750e474ef42877cfdd17f5fe0263bb9527819dbeeddde046807e99ba1863890fe0efdd2640e3bf37f99beb20359117de982be84a1d420c896689e55e0fb50d6d4cdeb21efe1e28cd566509f0ae3e691e853f8a013997c856179970169634e0869b597add260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b965927d84774afc3e337c16f0a9b10656cdafddc9b5561bf69c64de4ae20240fd9014d76fcb53f1a5b0c1062e774f53a80b7162d2e786e600b1decf7d3937ddd48e66456a01ccd1fac39e7af6d9935ccc342a0c1a55c0a5d47baad214fa1daa434026d896629cd33f8ec2d5cadbf07903c8d81e3ab335f4691591b358285fb9ccadcd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e8e26a61abb0582c580b1c9afc4e3e0cd5187d6dd5383bbc43f60049db396bed80150b087517d43972402c040ed40b08058271277c5cd5f1fdf24205656c026c0099c24340eb06b0bac76ecdc98275f6d2c4edf897a5d459871731e07d67fa2fcd2bc095e758141ef766f4b13a486303aaaddee640d9746244b5f248ffa1d2363589195a8fc2a269e475cad21c8581118e244c1aceb9e057e5424e9372f0715757a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d7518d6ec7a2438aef9684007b2465689da3b335982b5d11c192201cda810e0a5872ad3ee89757fde4ea78328f454f51fdbadbe19d6f7f5d07799274f3787576e210ebf872aeacce6970014ff9c1f51ae81d5c5040011742e094b112f61cd86691ed260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7e4e9364324d989c5e01a75f2ae0a73ecdfd6ec97bf77e35e5a65f5e1996f84edcf36a8a2107d572d2e982e00a25915632023d0e377a1f06a263c575fa3100dd12024676b663b554b13222d2033c1b0ae94d1a2123d39e01ae23b2c31b731ecfe19dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd3bce71c6cbeb692a824c86aa5124fad90f116bbdac8a907b97045d31029cdd240c250b803ad337b7ef069bf0741daafaa41dc5c50f592482b4dda00f92b17f808494361641dd0eada9ada0432cbf2c3b788d44814823df2df56a7ca3ef60af2dbe365d768a9126fb809745cb720ac2c61162c42c919c136b02c69645cb3c9e1f17a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b2c0a9681692acb6114480092744c6015f812b255f01f43f22e16af39ca72d5808e6f25e26c6ec0a4d14e8e8abd698e5c8ae7722572e9deba7d61415dd9b348e5e8473aba78e24017e895ef639c37f90a1ca39467635abeba021cc7e21ae502db8244d58d24a98ffbc552e182f6eab77171265fd481f3ae8d16122231bdb485047a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456eb85eb07e1177f4f3dbb7125714c22fd592b0b3e689067cb378562ddbb82af5dd172f7bc7cc121208e11fffa22ef0650c7ffbff1bcc5ee78d0374072019d63740cf1b14b0b37aaa1c35c1d454f7b12d299c8af74e4a0244bcdbf3d4b554729efe1b9ca9637a4c0ba9732a223986fb8670cdc7661e5226876836fcd417165980c0029964a04b61885d221732079e1aec0bb70999ef33a30db1e3454bfbbdba1b49afd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc887ae64ad4b67851a649a84a04c8525c5e8e29812a8668dfe97195ee43b072feca0df690f1a21622e2c8d28660c3fe8512c6c425340fc7249d630a091ba3e24c1721c5d7b6c25e6eb1e591bb89895daec91b9328026accf8dadf13df5a894b75febe23e8d689b5429ffdd8f0b38bd60befa78d83b77ddc73bd360088b6229a678dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b96a8332048262676a7827e2e6a99d04c7f4e030999a21cf92b2be5d0042e4d2f76bb3ca62f1a0f0a75fa84e9c5e10f7737ffcf0dd810df514cdc851b508dad8bcc3a66ed2f43c0eb2e5196d48123df1a4722ab34215b464df322e5c2962534a7f5cb4ea5ef845cfe017abe9f56955f645a7c078b3331b372e9356d58c4f208b43ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65f64a4bdfbed0ec09e9022a449eb6bba5f05f6ad40542493d3ac3b7314a944fc31a9bceb02458b4e0cef21d6981932ce01500890c16f7a87eae8ce93e08739714152e9f623e5ed008c4231479488947749a5ce870e3d013d3788d5fd5f647006b022c980288e2b82cc321c0645de9c9a068ec509c7788c5787a598098b42f098b1ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b7ff36f927f80baeea63b32fa489b3291e7f3681eef9dd48b68b77627eab003017791a4d6b5523c56d55e1181d9b00d77548fb5ee6ad59e0ee813b1daba5d16e744916cb995f103b3ed19424572ff332feaef953866ccde799161ac50a7b4a3a30b77a438bbd19f663a3c9db01f4bfc86e56a8f6dabd491d3a411a3dcde0284ea57a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f59bf5c1a841463f9c01d2a55ded6ce8ed980e0dcc4d43878d854c8360323788d707d1410bcc6dded26ae4229b712fb9407f4232c9356a23e673c69c8db7e033b8f481a02f8669e684c77a1d3797d5c3bf9e6ba5c97f717d80a1aa536f33d0d474ea59a564456ba0f9d9eed56bdec2b73cf0cc6f7a3073e71d1bb5a251970289947a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fe366ac77b67b9bdde5d738e26e15138d9cd03bb54d42e422776c4e942e1efd03870e3925575941613c0e065ddb8fd5b1c85e6d9782fda92ca6482bf78b250b5723673c60d9f29df6ae5741988382bbba7b92d3586d24bfb784a118c29face06fef03eb85756e1ea89cb3ad2ac61479e97ab2cc9e59ebd0ecf70e2aad6e2bb692a02b82e6838ea2d6935252ce336232df6583ec016db2146302b8f5ddde8d11be2ef7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d66c68c2dec1bec64acac7b5a9ef669318900f23d3717a2739636323f502e3ee9350ac10c99bcbf7ee1fe6cb298464d1696bc353465d6937803684820774b715a5abd32e56b4e74b446dde3200eaae232cbdc3a950bb28d211c740062a77db17cb66cf2ae548365eee9f422caed24aa6cf9aeffeea21194238a98b89d7d1c3f2b2bb13181b06171107cde7442cce16a50c79f1848cc7dae71764cb475dbd93338d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ea8588ada673913af700735d3806870232d083e47e9ec03d010c5fb6f62498c832645cebd4051c4cae72f92e67209a37043d15de81aa84449708004d992ddcd32ad8a798a235bc3d909dfbaed553c43be2a55ef8e90abebcede2c1375363446a01b8b0346842960fb64e14062cba6a50c3e8edcd89a0cad30a4094815282f6d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e952294975cbb0de32b6b86ff2557595ab9609853ffafbee50a9a877f4897b8d5681ac9fb82a14d11733b16bfa4a79a2b625ee34f71d829f5d6e1c99eb3d95122ddb64cc2654295a4193f299799a23cae6179f1a07e54288623e265531c3ae322f51eb8af020b2bd983521973b2d3a6626ad1c37ae119d1cac347c0598dbe1bae95fc7ac14e7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c8737942230201ee1407866e7070918306e72ef000904ec0dcada67ada28e7e6c7afa67d89de8510a61f4fe6e4342ac0957e55503cacb7e423ddc37c71b4a96f5d7150a247e712232d09cb2ab6c14927b33f7e999e2e8de5cc5574bd72c8fd8fe00278b60f1d6f843ca3fc082856b33afce9a8e9f4f94a81ea24acea7effe306e7b4f328adf0c137fa7048a6733531049aec840d6097e6f8558ee0be0c6d3c9432ed8b8173be8b51cabe43288140905327cab82ffcfa300de313a68abbbe198b17a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74cf884927542b74251960a1d134e0cd84c985d9218e08c88757c2f63b496835489a5badc79de6ccbbdab23b02313358e36f3331dcc175bf14d14bbaebc6bbb1bacab22f7c044dfaefcf970ec1179dc32c1e99298727839dad9107c9b4d2f2f735da8070a07dc1b06194d7c1586ec1c5ea248bdfc0c9b4d7895681da8ead9ea052d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b965927d84774afc3e337c16f0a9b10656cdafddc9b5561bf69c64de4ae20240fd9bf9eb2e425dfc04748b4d48911ee759a9369396c4bea37d6965b9a3b52cffe86fd59e74549a4b118967d7dce597d5dc7a2c13fefa9239d061aefe2715790986902654295a4193f299799a23cae6179f1a07e54288623e265531c3ae322f51eb8afd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e952294975cbb0de32b6b86ff2557595ab9609853ffafbee50a9a877f4897b8d5681ac9fb82a14d11733b16bfa4a79a2b625ee34f71d829f5d6e1c99eb3d95122ddb64cc26a01b8b0346842960fb64e14062cba6a50c3e8edcd89a0cad30a4094815282f68d8b752fe8478855a70ccd16a49371fedac6234667d603cd30ebf4bcc6003cc27a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525f92d248fa70eb0056465ead69ecb8f5fc37580c6f19f5d1a80a99ddeab2b7d75b2ab1735f9a574431bbb6f9f0333f6e02bd290b1039895e12aefc1ee4719a4d45e01d58226733ffde8ae0833d24bfcb0d8e6efa00b69472d2cea73dd4d86feca4b0f2e449fbef9bbd4204caf0568f78ec856f0c586d98a472f2cf8889fb1f263d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e952294975cbb0de32b6b86ff2557595ab9609853ffafbee50a9a877f4897b8d5681ac9fb04c4bab85a83b96bc4ab1fcfeba960af85b96fb64667f00de965c3a0dfbce5e526dfd3cbd5809f590c9fe32a5d21540f4081d847168b8b325e808b178432074d02024ab31c508dec2a22e0d810cf2ca84c068bcb275c5c2a2e31451ff12280e1ce7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3d708afb6220ebd6f3dfd32d218acceb4cfd691eb93601ba886928523ce99d1846ed2401a1b23725d86ce3dd098fd8df282fe9f9832d593630e95881df66a12184ee43bdcde7c1a1067aa1468d6fddfb8e165ab526283b0ef82a76eea08aef297a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74cf884927542b74251960a1d134e0cd84c985d9218e08c88757c2f63b4968354847f313343bae1e4a694d7b579782056327e6a6d56cb795eb4c900eb7ce0040f1895f50f8236fea5f49c491cbbd19041e7799a0242ec32bf9c53963ede13f88bf102f7f1e4ac26cd49f9c248b571570711c0c6b7927bef14f19d031fa83584944d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f71d2d30bb7635cbe00b365df7cf16bd16eade457e84fe6a48bfeebc3a50c5d5bb71f2da928686328734b821b381ae54180a9a2eac1b922470a102debe1cd67aba09210b56f1708f4d9ba9d5ada961cac9d1ee8a02d8bc520130f203d41c87af157db12cc3b9a7bff755fa37bb1b5f229f897e452e195873871fbe00473f60d5650284ee43bdcde7c1a1067aa1468d6fddfb8e165ab526283b0ef82a76eea08aef297a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74cf884927542b74251960a1d134e0cd84c985d9218e08c88757c2f63b4968354847f313343bae1e4a694d7b579782056327e6a6d56cb795eb4c900eb7ce0040f1895f50f8236fea5f49c491cbbd19041e7799a0242ec32bf9c53963ede13f88bf18e1d821b674f55fd73d41830a1a60f6d1e7f2b2dc78e8c75dfaafc5992ec58f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a34fbec1e7a201ae4c0e4a96fef3813683c1a36a75fb58ae15417d20ac63803be438091a03f98ecad521e99d5e837c56af546e8628e7761092f8e306456460063d0db22229b18a7da9ae5120e174183db78d218e69630e39d46763c4cac71bca798f60911463de55684f83a17922c5200ab44b7e0a9fe05f988d6e8a54503792e6e843889eeef71c1a96c9e33eab9256df25998013e17121d0c2bc7ba9d6492a3f7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edaefadb919dcdc13fdf98f830f3e2a45eb732f4cbe7880b56e0b8bc6efc168e65c32677a7dba4f7f14cc6c510a05d08ebcf05aeca98acee8b7a8b4ad3a5f8f7712ce6fd29f7777bd8abfce96a9e6668452ec512bbae8a86b15453f69208db254afef45504ec687ddba0176856f7e4cf90035395b2fb03092f84f5e0867c78208f7c027e2f6d83e2ec519ac2c69e30f58c9e43c93ccfeeccbfff4efe9edc4efcc213eb7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edaefadb919dcdc13fdf98f830f3e2a45eb732f4cbe7880b56e0b8bc6efc168e65c338333cd1eb8fefe12577bbd1c27f3da7a12b3123f8ef0e3811fd788914136f37aa1770a8c80f1e781c513049ef3b25b68bab46da2beffa2117c1842ce302bfda7f2d8f7627f2b5ec22a6223d10606850face773cd2ced0d25e55074bfac19730102f7f1e4ac26cd49f9c248b571570711c0c6b7927bef14f19d031fa83584944d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f71d2d30bb7635cbe00b365df7cf16bd16eade457e84fe6a48bfeebc3a50c5d5bb71f2da928686328734b821b381ae54180a9a2eac1b922470a102debe1cd67aba09210b56f1708f4d9ba9d5ada961cac9d1ee8a02d8bc520130f203d41c87af157db12cc3b9a7bff755fa37bb1b5f229f897e452e195873871fbe00473f60d565699cfcc8a802c18a5d3fc502352e242116ead356b2b77515a3ca6a128cb811a0d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c1499962274a7bf7daab46c23f4c5ea24691f256e70cf86f9ed7bf31ce40fd17a20ad2e93073d6897ed87885c918161439134a99c0c0e25cbae8e9931e66104d8efe63865f96c71b9e6dac3a18598d432cf1b26873ae6baaa5b2fb02d6ae81820dd63bd49b80e46ba4a953b0b41248db1ef33f0804f1de424eb213446abcb4d1d1ac02aab01c1021f63e7d9bb4f3b9b4e89aacec88fb938417452388ea16f39eb42efdd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0ab436e9765144f12212f8016ee699e44f053b3715483c6ef0eba5a1e63750e474f54c9511b843a3ccc99a6c1e4f41396b0e99ca5746be3377c6570d29a55f2e5fb66b4752e276a7afbc8c5b6b29a84ff18fb488fb693f5a313e21a938d6bd650a1bffdb58af6073c4200623b4ea3e7731571a2f7cd6fb9800962985ebfbb45bf97a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d645da888654d2ada519cb950ddf6a0717f506a314e34128b07c85bf2ed2903dcf44c9aac724ee8d3ee168849c44d9fd145c558094e516a6c4e2e0cdf53cb16bdda7d76aa0edf868a713e574ab91cec25728b2b8436ae20c1a89b73875b1085f33cc74544c0a6979e7c37e322b970df199083a11b93f89bc7ddd390769af74e12fc7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3637c8550a50814cc02ec9353ee556542249ffcdaf983ec57a679df35b2072d117c109c2bab37700237f74069210516d4066404ee979417c37eae627ce50a89802cb4ea5ef845cfe017abe9f56955f645a7c078b3331b372e9356d58c4f208b43ad260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859e1ecfe68fce1d0a61b156c9ab7619bbfca106540b150458904106bbd6fc631a65f64a4bdfbed0ec09e9022a449eb6bba5f05f6ad40542493d3ac3b7314a944fc31a9bceb02458b4e0cef21d6981932ce01500890c16f7a87eae8ce93e08739714152e9f623e5ed008c4231479488947749a5ce870e3d013d3788d5fd5f647006bc9074efb6e52141111c0e43bd78a25772cff8084072388397ef7358531d85fe9d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc1fef87093132117c137ddb0d0dfbc35bc776a8ac8e6bb3a3ad1383756fbd21ac214ea0372c2a028a245fc25938183ae33e5d44a6a40f5d956c713b3b30b9b73ce9a2cf1aef260ef232e16f988ecec03eb7e342ebc2d97850d40fce106108d20e477ef7583c1c7f39f2a8729090c5e4c2e7a22890d1f8727cb6e2bd0992707f61f64c8dbd0b2c3e68fcc10ff89757c0bc025cfab57a015441a59b8e82d3ccf64647a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fe366ac77b67b9bdde5d738e26e15138d9cd03bb54d42e422776c4e942e1efd0385929e89dd242fb41f6dec9b60a57e022364813dfef03a6ad09725147523fa38f52d6dd66c67d166b54d597ef8946e555ae881988424eedf198c50edc53ec73728c646d1e10512689b64ed99a90ebdefeb70e5f512b0acabfa23eaebcbc7f09ec024676b663b554b13222d2033c1b0ae94d1a2123d39e01ae23b2c31b731ecfe19dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946bad9d1c26408a80f256418816bf8c43c8787bdfa152814dd1d024fb2644d97cd3bce71c6cbeb692a824c86aa5124fad90f116bbdac8a907b97045d31029cdd240c250b803ad337b7ef069bf0741daafaa41dc5c50f592482b4dda00f92b17f808494361641dd0eada9ada0432cbf2c3b788d44814823df2df56a7ca3ef60af2dbefb4ac8834d6bbe4eb7f2e4c58c5895ff75c58256ceec70d9992b046d4261c3dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be0889cc083a427e10642159c2480ceb98b6ae2baa681598c34dee930848e8b4cedf15d5ace2c9eaf0504253977cc14e7a65ee95aa8fc59624668458773a92ac98708c21551917a5b5d35890bf09190ddbe1602745924ac0489aa1c7d0a42d9a1c04bab391eaf621a8a2d5706663989614a178b8605c3c47ee17d95ad202851fdb9dcff98e4d444ef79cf4c1fdbe89c1cb66051bee85483e842875afce6c60dab425fcd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b851651989c59c7f915f50f2d581e6faf6f229ca5b1a5aa9e2a42c37744ab713aa345eb1681c1f4130d08fd614bfeee0a5810462eae789d83a997472b82935156ff545241ffe9ac13511bcea11fbd857abcce63dd2b6a9efb7c4948657c3b53f0025a0c24d6432d28d80e65ccf55d7d194761752a7c0933cb6db371d841fb8f6a22d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7ee0b0dd649465547ea5f14c1bf262df14c93fdae97ea9f13ad6d9b42b87b51812868a4e4bb8398438163188f1a9382bb8b6d43698a59c4194db629bac696befea31f53cdeeab00dcd9f878a69bf0e4523e8e0d80a04c78eb0dace6254eac9d10c7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b743af4b61714d58c1e44fff6f1ec64a225647ebaa7ad3e40c151d08c623a26852d6de0887008fc74b561ac7770ccbefe298086d4a5cf437fd723c73fdac65ff123589582482baf1bfe5ea2507b9ed0ade68662d152b71acba9310ee4fc3df2101bffdb58af6073c4200623b4ea3e7731571a2f7cd6fb9800962985ebfbb45bf97a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d32bef68cd2b9ec286922e69ad70df8f83fcf24eddc959dde04bd9e8b69934d2bf7057037a57117071ef0f4238f9082899fa264a26f0fe41f3ac2a2aeedec2d645da888654d2ada519cb950ddf6a0717f506a314e34128b07c85bf2ed2903dcf44c9aac724ee8d3ee168849c44d9fd145c558094e516a6c4e2e0cdf53cb16bdda7d76aa0edf868a713e574ab91cec25728b2b8436ae20c1a89b73875b1085f33c026122c9028271b0ff6d4579ef9de1603dc70ccbfbaba99b280c96647ec496713b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef126423cecc6fc9657c529e33b5df0f6e5f7f1d825bb2914c3ed5fa2f49bfd7e17abe89f40c7afd9ab40fb84fbe2e6b8df05f26980324efb139a101267dc20c94901ba8968aeb2cf78a397a9a1fbe15e17d85e40a96c9c9a92e0cde9d7d3aab2f56d163b23b13a94ef8b013bb36ceec3622ed84a03657f9c76dff4c5734bb53a86405d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e95229497460ea30039c2c5753c8e3922e2b40bdb45c3ecb0be153f3b396510ae97eba83d6de38fd6aede97c70f11bfd59b42549b5b58da0f4a39a1d427929182fa4d1738c9aa115b438cf9a576e9447ba0d1cde19ff07ccc9ce0fde96d78e02aff80f8fdf36a8a2107d572d2e982e00a25915632023d0e377a1f06a263c575fa3100dd12d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a54406843a696ac0a2bd44ef3074f974f7b013ae8244fdd76f36caf805d8dbefc175edad7acfdee7da842e0f2e630dfb57f74abc0c1b7b909f00400bba9440dd0b6f793caf06cff7aa80ccf98930d2d9409186713efdbacc6e2633c2c2cb70db7e4e9364324d989c5e01a75f2ae0a73ecdfd6ec97bf77e35e5a65f5e1996f84edc0ebf872aeacce6970014ff9c1f51ae81d5c5040011742e094b112f61cd86691e026962a589e00a4b4cd1ed8788d10f48e3a78fd1f0ca9925db7b5fcc551a043f6bd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd6172b72e4df93abd57406df304ba079645034ea41b6d9e3fd37e260fdee41f789c381f7ab2a8f3d2ea770ec4653fd2ac601b832f9a526b9836896afa376fc887ae64ad4b67851a649a84a04c8525c5e8e29812a8668dfe97195ee43b072fecac50e9db5b5b75aa85ab101ad0228677e0250588aece0cd0d9b32a51029d9214c8602fb3386007a97bf729822083db883f5eb08abe05e532f02ceefa728aa2edde8473aba78e24017e895ef639c37f90a1ca39467635abeba021cc7e21ae502db7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16f821d6b5f61a94e96fe3b12d1cc7c52955d3ac3a2f4d6e7576ae3ba78511c1d8a11d31b84db45e19608423bafd3c5ef985c4207295bf23a73693e28e68e38fefc770867d59c39da66189047a438cdc52faca443eb76594b6ea53a31da70cd4b2c0a9681692acb6114480092744c6015f812b255f01f43f22e16af39ca72d5808e6f25e26c6ec0a4d14e8e8abd698e5c8ae7722572e9deba7d61415dd9b348e5e365d768a9126fb809745cb720ac2c61162c42c919c136b02c69645cb3c9e1f168b60ec11424e8f217e61460fb69035a60319a21b08f89259640b646cdeb6924d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0a9567e4fb9f821af7c84f92a8b4cfc53b6a069f70e5145ad60ad5dae071a0933be3b92f3e093314adad9117b3eafe0d27cbb57de49a1b338c2112d5cb71bcf725cb136476b4ac17dcc9c39a1a67651ad3bb59fe5b0f5f7e8a798c1e627d3a39450263b23b13a94ef8b013bb36ceec3622ed84a03657f9c76dff4c5734bb53a86405d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728af8a93500fb1baf227704f987e85acec6b48456d9b31599b47751497e95229497460ea30039c2c5753c8e3922e2b40bdb45c3ecb0be153f3b396510ae97eba83d6de38fd6aede97c70f11bfd59b42549b5b58da0f4a39a1d427929182fa4d1738c9aa115b438cf9a576e9447ba0d1cde19ff07ccc9ce0fde96d78e02aff80f8fd8244d58d24a98ffbc552e182f6eab77171265fd481f3ae8d16122231bdb485047a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456eb85eb07e1177f4f3dbb7125714c22fd592b0b3e689067cb378562ddbb82af5dd172f7bc7cc121208e11fffa22ef0650c7ffbff1bcc5ee78d0374072019d63740cf1b14b0b37aaa1c35c1d454f7b12d299c8af74e4a0244bcdbf3d4b554729efe1b9ca9637a4c0ba9732a223986fb8670cdc7661e5226876836fcd417165980c03fdf1e05f5dff421950a11faa4b7e2fb92de49df004d6c8cf8bb059d174372b6d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a8096e5b2dafdb3962b326e4f097372273b4e862b4bb7bd6d51d9f4c2bcf34bb6dd5c8f2c2705cccfaa1abde1676bfc0fc402fb4d1e9d142d8ab8c4d12ccd2946b68408f13417a02b5b7341cdcdc30ab8e9046d7057f6a2e90a5c7f3c20f2197b76155b27ac1fad208922fcc91735ff7d427406b4264fa4ddb165ef5d9e16bcc018158be804621634ccc10a85f07e55363b0f025ca77e193f274948fbfe6aec7b2f78aa2986894fdcaecd827564f9e641edfd1d35d0aef3184d5d3c91d976f56ca02423a6afb49a92cd1f9bcfcda6508e45fcd28eb3f0ffb6032d90d1457f83e00047a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b662845b55206b8113b75cb1a98d73283136c4cf8a9caded23e74f139d347d4adde9a16724cd4e7c124267fd83b7220724d18dc71834ad47c077adb43109b9b4b53b3c52ac73d436baec9ef750e3428887bbcf751daac7af228e972a67d38d6cd1edae9bf32eff9ce544c5841fe19fa42c83fefdee2a92f40ddc8e57b80c31c3597525ff2831cbb1bce6daa5ff01615267ecbef60e2bd0bd28068df59bf8f2d192a01bfcf94253e1588657c661f3e04e81c18462f27ccc468801ee7cfaae9a40f6802d2ee94829270489e2789e6c953f4a08991aee166cc5a706408ceb0121d0562aeb17c109c2bab37700237f74069210516d4066404ee979417c37eae627ce50a8987a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9de214d1576b1a6ef4d04315a5bf8686266ca3a1944550846170fcca00189516e4d8e3ae4dd878e983b9ceb5ebb2acee878d8461509d08ba20f97aca2bcb4b7e75ca32adc138e9b93cf92a5c9b37f83a9fa61e28653ebb61451c2556d8240a32fea3637c8550a50814cc02ec9353ee556542249ffcdaf983ec57a679df35b2072d1c74544c0a6979e7c37e322b970df199083a11b93f89bc7ddd390769af74e12fc2e05cd37d76a8acf344f742b9b8492e7f7c282d6daf706731043a2c3bbb10fe9d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0eddcd80fe6f9842d58cd08addb1220ea6f99ffdf658402a5ac93d33c9c683be08891500f896bebfabf3797b80b9828293b134845fb42aaab852eac3435edc72ce0a9567e4fb9f821af7c84f92a8b4cfc53b6a069f70e5145ad60ad5dae071a0933b090aa9b155bd5ddc180f69d1c945cec720eaa099d3cb4911832c9f1db7d382dd1fa3801c2c0ed677671d1348782ab66504ec5275f3a4a0f8d1d26e6ebbf8b5570224db70c11b9b729619d1437dfeb8f4a9ad4fd532cbeaa2c2b10713f981ff9709d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548f3d3dbb94726699563dc15256df94796bab8a1af805312b4f1ea46a5f9abd480e7b1d14766e3ad5d4fb27cb595b952af2c92ee4de4b9d1a769ec7981a4b073b96a8332048262676a7827e2e6a99d04c7f4e030999a21cf92b2be5d0042e4d2f7634c137170fd512f97a0eceb130a25b3daa19835250e88c1194e199da1dea61ba9ead1883a1904c09134aae8648e6a60cb886dc789f476c7d26514b14a90e7aaa039cebdef41e2edbee7d8886c26732b181064d7998b605a4e94683064f343a637a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577b41c447fbc3bacdb400947ade28efe2991f809ceb3aadbde00e830fef0f3456eb85eb07e1177f4f3dbb7125714c22fd592b0b3e689067cb378562ddbb82af5dd172f7bc7cc121208e11fffa22ef0650c7ffbff1bcc5ee78d0374072019d63740bae3a5404c3a4e985d57aea1846a15ec4bfe1f4e373172278142700eeac2d4fa7b79206702e7835dbae6a0f7b6b868bb14768bc8ac2f1f1ce217e2c772e7ba81a2889c0ef3642da4b017e31f203904ea288cfe27a965c1e1ae60a0b88c150ab67a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba7e4e448bdc1a6faf8cd7884435cff75c2a7b52fb5f44808d6a9a008d274ae9deeab6eef7c7397791c075c406a80c543d0d54bbb886f7253a08729dc997c2d5a32062b098a2dd55fb66c14cecc5f28d7fc1b96c58da3222b302f906ba2dfa7fc3d4ceacb0c37f6118d71e8f481a2dda213bc20768fea06687a89fd8dc2638c7b2076e6161390dba3b19f16bc06723cd44faea59d488439398f1a1ec0bf68226637fdc37cd65793411ddba22c383480419a67d5056e3cba869315931c1b7ecd69202bebd047f32d6c2ccd525edf0110ad454afa2fec523fe7e4e6a01bc60448cfc227a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb726959460b48d9978e77aef0bf5956747702b67111f72dea1dec088a2fdd6b74e48c187a35459d43b6eb1fe9397abbd5944f0793164fdebab38f21d62a786a5130163b9a583c2a5447d508fe85a8e07f498763bf00b20e91af11894cada3fa4803aa3ba7adabc1ca777813bff7b89735eb3ff96dd42b3f16e235d2498eb773e62c9da84875ce97e6d3a0df98b8709b2da24233648c39dd4d07d3ca7e53080805d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f240c040ec6471198293e17417276606067fe42ae62b5bfb97a869603938b343a5f1bb407e4b788ce6a66f95e96b0acbe39ffcc96bccafc59f0f811cf68855c1499962274a7bf7daab46c23f4c5ea24691f256e70cf86f9ed7bf31ce40fd17a20ad2e93073d6897ed87885c918161439134a99c0c0e25cbae8e9931e66104d8efebf0d7be04855765c3c85526958a2e3229341a8c935251802714ad39c153d8495ace0428b3344348f3233a4b2b065a97127ece70bc5a7ee2df66f762cfb97657380c86a33f7d00bcfb5274ab452cdcb539f7ef164de25a5503c4a3115e35f6336d260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f5825d6dcd3862df8dee11dd83ad2162d4ff732bba8da8065c4e52b891f4fddf4a874960e48a0e3eb184fc9b0663b16a3bea528652cf960bc67cee4dd5ba78f0edda9da036aa934704f028d71e059233b898affcd2d3710c8b808a8a96aa3b7728a0745f6231563c70d9df23ff8d9a8ce5ddb24e977c9018b78271a2e745490aea807d4352754ca060f5a6021253b04bb53c63db90946fa453ec12e450b4f1960066cb9190aa160dd35a0a0a5c0079c27022021227b1392fc53fdab219c2c0a573fa65437912a85304ec669b9c92cd4c17f57309c267b8f8edffbf17aa943726afe02b5e42d1aae777350b549341f7d75314c2ace55a7b41c7ddc7fc1111ad1a3fa1dd260ebda534678081fae5ac740506c7bc8fa82b28cff3f41833565e255389f586911a46bd4bd4952825d596b78bc59d66a23939cf408f07abf3aa406e55714f2733bac0c1cf84f14c8a0aa27edbd14340abb3d311ed6d609e306f89ba123548fa8193864e240e247920489bd6f4501e11ddd8f417748577bea925eff7861859edacdd5e0ce01837bfe4c1e051a405046f15c099f2b59e584ee856bc93ab1325773497609f32961860d65c658d6bb938343f35c9c1f987d72425cd21aebd078181e6ac08b7899cbf2432aa08d2958b467b623644394b4b8bbd812a8cef59e414488c2cffbdf77cde62e72bc568dd2ec0d5fefbd8807fa1cd7dd48e8d8f0c0ae766122c9028271b0ff6d4579ef9de1603dc70ccbfbaba99b280c96647ec496713b7a5071b42b5d2a4a896170ef262a43bee839d27ad651513ea3da353171b66284e4b7974e0b52006591ef0da90d5f1fdc48f323a616cbcd5c11f0cddae89073ba48533727aefe588276a4f66bfeafac198ad65ec2750bf6059ec6df4f2b4ea577423072d703ee985e41e85137eed5857e9e726a9f8af60bfc562b35c98e375cdb3f9e3c001fcbe980d5a4da3213313e48fdcf161df3c0b6f697231b09d5ef126423cecc6fc9657c529e33b5df0f6e5f7f1d825bb2914c3ed5fa2f49bfd7e17abe89f40c7afd9ab40fb84fbe2e6b8df05f26980324efb139a101267dc20c94901ba8968aeb2cf78a397a9a1fbe15e17d85e40a96c9c9a92e0cde9d7d3aab2f56d1", + "proof_sha256": "d45a9756b8d66357eaee34f1efa3b5fc975e25fcf7b7eb5a516746c6e078bbc7", + "tags": { + "challenge": "C", + "graph": "G", + "label": "L", + "merkle": "M" + }, + "tau": "90cb87eabf42f4c14936c936d37e536aa6e2ba7eba4ec5a1c48ee52b88d32423", + "verifier": { + "accepted": true, + "check": "accept", + "oracle_calls": 1664 + } +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/kat-n08.proof.bin b/tools/mhpow/b1/fixtures/kat-n08.proof.bin new file mode 100644 index 0000000000000000000000000000000000000000..1c0000b410a815a5f0a27ce6ff37a259ea83520d GIT binary patch literal 55405 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 literal 0 HcmV?d00001 diff --git a/tools/mhpow/b1/fixtures/kat-n12.json b/tools/mhpow/b1/fixtures/kat-n12.json new file mode 100644 index 000000000..e3f79a10a --- /dev/null +++ b/tools/mhpow/b1/fixtures/kat-n12.json @@ -0,0 +1,93 @@ +{ + "N": 4096, + "challenges_c_i": [ + 2331, + 739, + 401, + 182, + 691, + 3144, + 301, + 3840, + 1473, + 3907, + 3027, + 782, + 1184, + 3316, + 331, + 3084, + 2937, + 3059, + 3432, + 2573, + 1944, + 2975, + 591, + 3706, + 556, + 3167, + 2343, + 3262, + 3890, + 4081, + 2659, + 3382, + 756, + 2746, + 1108, + 3817, + 1788, + 2129, + 972, + 3805, + 3363, + 245, + 1375, + 3444, + 2029, + 1672, + 3403, + 43, + 635, + 94, + 2323, + 2054, + 1986, + 1239, + 2175, + 3712, + 1677, + 2346, + 2707, + 560, + 4095, + 2662, + 3468, + 592 + ], + "chi": "286bb44f63729d7b19b40f08071e3a9cb42e812edf4079e5a0189ff7c92fa030", + "construction": "[BS25] Sec 3.2 over [ABH17] Alg. 1 DRSample; encoding params.py", + "fixture": "kat-n12", + "graph_parents_u64le_sha256": "a12e9e1e0a063833687df3a7486cff329593079b6b63f24198c7cd4ddc2f8aed", + "graph_seed": "9f25395581b8a72f3e17a812fede366102eba1dbd75cb3a02ad8054d5d79af2d", + "hash": "BLAKE2b-256 unkeyed", + "k": 64, + "labels_concat_sha256": "5b2188573c4143fa1c69a262ebd656fc1bd3afa38e96c44ceca6533506cd5c75", + "lambda_bits": 256, + "n": 12, + "proof_bytes": 79981, + "proof_sha256": "3c7de0539a8715e75d3d64eb11ec3af7d8a2a338c101958a0c29e300c3ad4f7f", + "tags": { + "challenge": "C", + "graph": "G", + "label": "L", + "merkle": "M" + }, + "tau": "884d36cd2df99fa94e49bc0c358d7cdd3663ebac944d21fee983c3176dfe2687", + "verifier": { + "accepted": true, + "check": "accept", + "oracle_calls": 2432 + } +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/kat-n12.proof.bin b/tools/mhpow/b1/fixtures/kat-n12.proof.bin new file mode 100644 index 0000000000000000000000000000000000000000..261ac82b2f0b00bee05006d1069fb9ef72f0a5b5 GIT binary patch literal 79981 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 n%a&l)xC?YYW6E~295`wB@A_-76 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%0A7!LQeyou=LEU;7;qCGgC>Z(caIZ<|%n8#d0K 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 WyJ|yIyyv@%A##vV@|^V~-v0rS<8%H1 literal 0 HcmV?d00001 diff --git a/tools/mhpow/b1/fixtures/kat-n20.json b/tools/mhpow/b1/fixtures/kat-n20.json new file mode 100644 index 000000000..58e01c197 --- /dev/null +++ b/tools/mhpow/b1/fixtures/kat-n20.json @@ -0,0 +1,93 @@ +{ + "N": 1048576, + "challenges_c_i": [ + 478328, + 234763, + 962086, + 987402, + 136367, + 302234, + 907558, + 945947, + 443172, + 200341, + 196554, + 615131, + 1032010, + 24137, + 31777, + 462029, + 299644, + 270093, + 905498, + 969459, + 16578, + 368025, + 859298, + 419728, + 841167, + 1025362, + 687240, + 176569, + 580698, + 957290, + 784586, + 978457, + 36129, + 577448, + 392226, + 711776, + 949535, + 343819, + 281553, + 809444, + 857405, + 904463, + 334337, + 577019, + 794312, + 477162, + 351630, + 104684, + 479418, + 685136, + 782054, + 333943, + 78240, + 784632, + 143051, + 787678, + 84897, + 883533, + 614079, + 250175, + 999091, + 869462, + 825523, + 955417 + ], + "chi": "842efbdf693296a28d46e967fe9930bacd9c48cb06b518a4e9529308fabc2560", + "construction": "[BS25] Sec 3.2 over [ABH17] Alg. 1 DRSample; encoding params.py", + "fixture": "kat-n20", + "graph_parents_u64le_sha256": "a3c61becd7b467711f5ca3e44ec1faf51905f221d3e8be71ea8515b02523d5d5", + "graph_seed": "9f25395581b8a72f3e17a812fede366102eba1dbd75cb3a02ad8054d5d79af2d", + "hash": "BLAKE2b-256 unkeyed", + "k": 64, + "labels_concat_sha256": "02e355ae74233acbe451012ad58c438cee307ab5821204231e14e64da31daa96", + "lambda_bits": 256, + "n": 20, + "proof_bytes": 129133, + "proof_sha256": "a49367d9c80f0855504fe1f0994acbd5ddc4b023eaf5904a28ad5f7e71ce951c", + "tags": { + "challenge": "C", + "graph": "G", + "label": "L", + "merkle": "M" + }, + "tau": "e3d83489e27af44b199e2a73db33ee2b9492b38e777e778b694bba152b53786b", + "verifier": { + "accepted": true, + "check": "accept", + "oracle_calls": 3968 + } +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/kat-n20.proof.bin b/tools/mhpow/b1/fixtures/kat-n20.proof.bin new file mode 100644 index 0000000000000000000000000000000000000000..88112aa3b483ee363843f07af4b1a37e3341553f GIT binary patch literal 129133 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�cw( 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 HHP` literal 0 HcmV?d00001 diff --git a/tools/mhpow/b1/fixtures/row-n12-k64.json b/tools/mhpow/b1/fixtures/row-n12-k64.json new file mode 100644 index 000000000..ffdeb8347 --- /dev/null +++ b/tools/mhpow/b1/fixtures/row-n12-k64.json @@ -0,0 +1,24 @@ +{ + "N": 4096, + "boundary": "process wall time, no power measured", + "graph_sample_s": 0.012868257996160537, + "host": "igneum-build-6", + "k": 64, + "labels_bytes_model": 131072, + "labels_s": 0.003818661003606394, + "merkle_bytes_model": 262112, + "merkle_s": 0.005726456998672802, + "n": 12, + "oracle_calls_prover": 8255, + "peak_rss_bytes_measured": 19660800, + "proof_bytes": 79981, + "prover_sequential_s_excl_graph": 0.01040476000343915, + "prover_state_bytes_model": 393184, + "python": "3.12.3", + "respond_s": 0.0008596420011599548, + "row": "honest-n12-k64", + "setting": "stock", + "software": "tools/mhpow/b1 (CPython reference, single thread)", + "verifier_oracle_calls": 2432, + "verify_s": 0.002651128997968044 +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/row-n16-k64.json b/tools/mhpow/b1/fixtures/row-n16-k64.json new file mode 100644 index 000000000..1b64307a7 --- /dev/null +++ b/tools/mhpow/b1/fixtures/row-n16-k64.json @@ -0,0 +1,24 @@ +{ + "N": 65536, + "boundary": "process wall time, no power measured", + "graph_sample_s": 0.20376398300140863, + "host": "igneum-build-6", + "k": 64, + "labels_bytes_model": 2097152, + "labels_s": 0.06238005399791291, + "merkle_bytes_model": 4194272, + "merkle_s": 0.11455441799625987, + "n": 16, + "oracle_calls_prover": 131135, + "peak_rss_bytes_measured": 39870464, + "proof_bytes": 104557, + "prover_sequential_s_excl_graph": 0.17990126999939093, + "prover_state_bytes_model": 6291424, + "python": "3.12.3", + "respond_s": 0.002966798005218152, + "row": "honest-n16-k64", + "setting": "stock", + "software": "tools/mhpow/b1 (CPython reference, single thread)", + "verifier_oracle_calls": 3200, + "verify_s": 0.003200609004124999 +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/row-n20-k64.json b/tools/mhpow/b1/fixtures/row-n20-k64.json new file mode 100644 index 000000000..b4215e15b --- /dev/null +++ b/tools/mhpow/b1/fixtures/row-n20-k64.json @@ -0,0 +1,24 @@ +{ + "N": 1048576, + "boundary": "process wall time, no power measured", + "graph_sample_s": 3.311251960003574, + "host": "igneum-build-6", + "k": 64, + "labels_bytes_model": 33554432, + "labels_s": 1.0262025019983412, + "merkle_bytes_model": 67108832, + "merkle_s": 2.4088434259974747, + "n": 20, + "oracle_calls_prover": 2097215, + "peak_rss_bytes_measured": 355725312, + "proof_bytes": 129133, + "prover_sequential_s_excl_graph": 3.4809705539955758, + "prover_state_bytes_model": 100663264, + "python": "3.12.3", + "respond_s": 0.04592462599975988, + "row": "honest-n20-k64", + "setting": "stock", + "software": "tools/mhpow/b1 (CPython reference, single thread)", + "verifier_oracle_calls": 3968, + "verify_s": 0.004032391007058322 +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/row-n22-k64.json b/tools/mhpow/b1/fixtures/row-n22-k64.json new file mode 100644 index 000000000..1e88cd847 --- /dev/null +++ b/tools/mhpow/b1/fixtures/row-n22-k64.json @@ -0,0 +1,24 @@ +{ + "N": 4194304, + "boundary": "process wall time, no power measured", + "graph_sample_s": 13.798183551996772, + "host": "igneum-build-6", + "k": 64, + "labels_bytes_model": 134217728, + "labels_s": 4.345659284001158, + "merkle_bytes_model": 268435424, + "merkle_s": 10.386853066003823, + "n": 22, + "oracle_calls_prover": 8388671, + "peak_rss_bytes_measured": 1365721088, + "proof_bytes": 141421, + "prover_sequential_s_excl_graph": 14.914240817000973, + "prover_state_bytes_model": 402653152, + "python": "3.12.3", + "respond_s": 0.18172846699599177, + "row": "honest-n22-k64", + "setting": "stock", + "software": "tools/mhpow/b1 (CPython reference, single thread)", + "verifier_oracle_calls": 4352, + "verify_s": 0.04833257199788932 +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/row-n24-k64.json b/tools/mhpow/b1/fixtures/row-n24-k64.json new file mode 100644 index 000000000..b2ddd5397 --- /dev/null +++ b/tools/mhpow/b1/fixtures/row-n24-k64.json @@ -0,0 +1,24 @@ +{ + "N": 16777216, + "boundary": "process wall time, no power measured", + "graph_sample_s": 52.28400299400528, + "host": "igneum-build-6", + "k": 64, + "labels_bytes_model": 536870912, + "labels_s": 17.542553989995213, + "merkle_bytes_model": 1073741792, + "merkle_s": 48.69316720600182, + "n": 24, + "oracle_calls_prover": 33554495, + "peak_rss_bytes_measured": 5407219712, + "proof_bytes": 153709, + "prover_sequential_s_excl_graph": 66.96936401799758, + "prover_state_bytes_model": 1610612704, + "python": "3.12.3", + "respond_s": 0.7336428220005473, + "row": "honest-n24-k64", + "setting": "stock", + "software": "tools/mhpow/b1 (CPython reference, single thread)", + "verifier_oracle_calls": 4736, + "verify_s": 0.004654051001125481 +} \ No newline at end of file diff --git a/tools/mhpow/b1/fixtures/tests.log b/tools/mhpow/b1/fixtures/tests.log new file mode 100644 index 000000000..f6f493639 --- /dev/null +++ b/tools/mhpow/b1/fixtures/tests.log @@ -0,0 +1,22 @@ +test_bucket_spread (test_b1.GraphTests.test_bucket_spread) ... ok +test_deterministic (test_b1.GraphTests.test_deterministic) ... ok +test_edge_rule (test_b1.GraphTests.test_edge_rule) ... ok +test_layout_lsb_at_root (test_b1.MerkleTests.test_layout_lsb_at_root) ... ok +test_reveal_check_every_leaf (test_b1.MerkleTests.test_reveal_check_every_leaf) ... ok +test_container (test_b1.VerifierTests.test_container) ... ok +test_duplicated_parent_position (test_b1.VerifierTests.test_duplicated_parent_position) ... ok +test_every_check_has_a_refusal (test_b1.VerifierTests.test_every_check_has_a_refusal) ... ok +test_honest_accepts_object_and_bytes (test_b1.VerifierTests.test_honest_accepts_object_and_bytes) ... ok +test_skipped_parent (test_b1.VerifierTests.test_skipped_parent) ... ok +test_wrong_challenge (test_b1.VerifierTests.test_wrong_challenge) ... ok +test_wrong_chi (test_b1.VerifierTests.test_wrong_chi) ... ok +test_wrong_domain_tag_label (test_b1.VerifierTests.test_wrong_domain_tag_label) ... ok +test_wrong_domain_tag_merkle (test_b1.VerifierTests.test_wrong_domain_tag_merkle) ... ok +test_wrong_label (test_b1.VerifierTests.test_wrong_label) ... ok +test_wrong_parent_label (test_b1.VerifierTests.test_wrong_parent_label) ... ok +test_wrong_path (test_b1.VerifierTests.test_wrong_path) ... ok + +---------------------------------------------------------------------- +Ran 17 tests in 0.086s + +OK diff --git a/tools/mhpow/b1/gen_fixtures.py b/tools/mhpow/b1/gen_fixtures.py new file mode 100644 index 000000000..b92d5af00 --- /dev/null +++ b/tools/mhpow/b1/gen_fixtures.py @@ -0,0 +1,139 @@ +"""Known-answer fixtures, honest-prover rows and attack fixtures for B1. Deterministic; run on a build box only. + + python3 gen_fixtures.py kat known-answer fixtures n = 4, 8, 12, 16, 20 (k = 8 at n = 4, else 64) + python3 gen_fixtures.py row one honest-prover row (own process, so its peak RSS is its own) + python3 gen_fixtures.py attacks the malicious-prover fixtures +Every file written is listed with its sha256 in /SHA256SUMS by the driver (run-b1.sh). +""" +from __future__ import annotations + +import json +import os +import platform +import resource +import sys +import time + +import attacks +import drsample +import mtp +import params +from params import H + +D = params.DIGEST_BYTES + + +def kat_chi(n: int) -> bytes: + return H(b"B1-fixture", b"kat", params.u64(n)) + + +def sha(b: bytes) -> str: + import hashlib + return hashlib.sha256(b).hexdigest() + + +def kat(out: str) -> None: + for n, k in ((4, 8), (8, 64), (12, 64), (16, 64), (20, 64)): + N = 1 << n + chi = kat_chi(n) + par = drsample.all_parents(N) + st = mtp.prove_commit(chi, n, par) + proof = mtp.respond(st, k) + pb = proof.to_bytes() + v = mtp.verify(chi, n, k, pb) + assert v.accepted, v + graph_bytes = b"".join(params.u64(u) for vv in range(1, N + 1) for u in par[vv]) + label_bytes = b"".join(st.labels[1:]) + cs = mtp.challenges(chi, st.tree.root, k, n) + fx = { + "fixture": f"kat-n{n:02d}", "construction": "[BS25] Sec 3.2 over [ABH17] Alg. 1 DRSample; encoding params.py", + "lambda_bits": params.LAMBDA_BITS, "hash": "BLAKE2b-256 unkeyed", "tags": {"label": "L", "merkle": "M", + "challenge": "C", "graph": "G"}, "graph_seed": params.GRAPH_SEED.hex(), + "n": n, "N": N, "k": k, "chi": chi.hex(), + "graph_parents_u64le_sha256": sha(graph_bytes), + "labels_concat_sha256": sha(label_bytes), + "tau": st.tree.root.hex(), "challenges_c_i": cs, + "proof_bytes": len(pb), "proof_sha256": sha(pb), + "verifier": {"accepted": v.accepted, "check": v.check, "oracle_calls": v.hashes}, + } + if n <= 8: + fx["parents"] = {str(vv): list(par[vv]) for vv in range(1, N + 1)} + fx["labels"] = {str(vv): st.labels[vv].hex() for vv in range(1, N + 1)} + fx["proof_hex"] = pb.hex() + with open(os.path.join(out, f"kat-n{n:02d}.json"), "w") as f: + json.dump(fx, f, indent=1, sort_keys=True) + with open(os.path.join(out, f"kat-n{n:02d}.proof.bin"), "wb") as f: + f.write(pb) + print(f"kat n={n} tau={st.tree.root.hex()[:16]} proof={len(pb)}B accepted={v.accepted}", flush=True) + + +def row(out: str, n: int, k: int) -> None: + N = 1 << n + chi = kat_chi(n) + t0 = time.perf_counter() + par = drsample.all_parents(N) + t1 = time.perf_counter() + labels = mtp.compute_labels(chi, par) + t2 = time.perf_counter() + tree = mtp.MerkleTree(chi, labels, n) + t3 = time.perf_counter() + st = mtp.ProverState(chi, n, par, labels, tree) + proof = mtp.respond(st, k) + pb = proof.to_bytes() + t4 = time.perf_counter() + rss_kb = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + del st, tree, labels + # cold verification: a fresh process state is not available here, so the verifier is timed from bytes with the graph + # parents re-derived on demand (no table), which is the network verifier's real path + t5 = time.perf_counter() + v = mtp.verify(chi, n, k, pb) + t6 = time.perf_counter() + assert v.accepted + r = { + "row": f"honest-n{n:02d}-k{k}", "n": n, "N": N, "k": k, + "graph_sample_s": t1 - t0, "labels_s": t2 - t1, "merkle_s": t3 - t2, "respond_s": t4 - t3, + "prover_sequential_s_excl_graph": t4 - t1, + "labels_bytes_model": N * D, "merkle_bytes_model": (2 * N - 1) * D, + "prover_state_bytes_model": N * D + (2 * N - 1) * D, + "peak_rss_bytes_measured": rss_kb * 1024, + "proof_bytes": len(pb), "verify_s": t6 - t5, "verifier_oracle_calls": v.hashes, + "oracle_calls_prover": N + (N - 1) + k, + "software": "tools/mhpow/b1 (CPython reference, single thread)", "python": platform.python_version(), + "host": platform.node(), "boundary": "process wall time, no power measured", "setting": "stock", + } + with open(os.path.join(out, f"row-n{n:02d}-k{k}.json"), "w") as f: + json.dump(r, f, indent=1, sort_keys=True) + print(json.dumps(r), flush=True) + + +def run_attacks(out: str) -> None: + n, k = 10, 16 + par = drsample.all_parents(1 << n) + res = [ + attacks.a1_replay(n, k, par, trials=50), + attacks.a2_unopened_block(n, k, par, trials=50), + attacks.a3_control_block_steering(n, k, par, t=20, grind=1000, trials=400), + attacks.a4_self_similarity(n, k, par, trials=200), + attacks.a5_attack1(n, k, par, d=64, trials=400), + attacks.a5_attack1(n, k, par, d=256, trials=400), + attacks.a6_root_regrind(n, k, par, red_count=1, max_tries=200, trials=5), + attacks.a6_root_regrind(n, k, par, red_count=64, max_tries=400, trials=5), + ] + for r in res: + r["params"] = {"n": n, "N": 1 << n, "k": k} + print(json.dumps({x: r[x] for x in r if x not in ("mechanism",)}), flush=True) + with open(os.path.join(out, "attacks-n10-k16.json"), "w") as f: + json.dump(res, f, indent=1, sort_keys=True) + + +if __name__ == "__main__": + cmd, out = sys.argv[1], sys.argv[2] + os.makedirs(out, exist_ok=True) + if cmd == "kat": + kat(out) + elif cmd == "row": + row(out, int(sys.argv[3]), int(sys.argv[4])) + elif cmd == "attacks": + run_attacks(out) + else: + raise SystemExit("usage") diff --git a/tools/mhpow/b1/k_table.py b/tools/mhpow/b1/k_table.py new file mode 100644 index 000000000..1d3c381c7 --- /dev/null +++ b/tools/mhpow/b1/k_table.py @@ -0,0 +1,57 @@ +"""The challenge count k two ways, code-generated (README section 6): + +(a) PROVEN: [BS25] Corollary 2, k = ceil(2 N ln2 lambda / e) for an (e, d)-depth-robust G, with e from [ABH17] Theorem 3.1 + (DRSample is (e, d, b)-block depth-robust w.h.p. with e >= 2.43e-4 N / log N, d >= 0.03 N; log read as log2, README R-4). +(b) ATTACK-DRIVEN (a lower bound on k, not a security claim): for [BS25] Sec 7.1 Attack 1 with the greedy depth-reducing set S + measured on THIS graph at depth targets d = N / 2^j, the k that pushes the attack's acceptance (1 - |S|/N)^k under 2^-s. +Proof bytes follow mtp.proof_bytes_formula with every challenged node of indegree 2. + + python3 k_table.py +""" +import json +import math +import os +import sys + +import attacks +import drsample + +LAMBDA = 256 + + +def proof_bytes(n: int, k: int) -> int: + return 45 + k * (1 + 32 * (n + 1) * 3) + + +def main(out: str) -> None: + rows = [] + for n in (12, 16, 20, 22, 24, 30, 32): + N = 1 << n + e = 2.43e-4 * N / n + k = math.ceil(2 * N * math.log(2) * LAMBDA / e) + rows.append({"table": "proven", "n": n, "N": N, "lambda": LAMBDA, "e_ABH17": e, "d_ABH17": 0.03 * N, + "k_cor2": k, "k_over_N": k / N, "proof_bytes": proof_bytes(n, k), + "label_array_bytes": 32 * N, "proof_over_label_array": proof_bytes(n, k) / (32 * N)}) + for n in (12, 16, 20): + N = 1 << n + par = drsample.all_parents(N) + for j in (2, 4, 6, 8): + d = N >> j + S = attacks.greedy_depth_reducing_set(par, d) + beta = len(S) / N + row = {"table": "attack1-greedy", "n": n, "N": N, "d": d, "S": len(S), "beta": beta} + for s in (40, 128): + row[f"k_for_2^-{s}"] = math.ceil(s * math.log(2) / -math.log1p(-beta)) if beta > 0 else None + row[f"proof_bytes_2^-{s}"] = proof_bytes(n, row[f"k_for_2^-{s}"]) if beta > 0 else None + row["cheater_parallel_rounds"] = drsample.depth_after_removal(par, S) + rows.append(row) + print(json.dumps(row), flush=True) + with open(os.path.join(out, "k-table.json"), "w") as f: + json.dump(rows, f, indent=1, sort_keys=True) + for r in rows: + if r["table"] == "proven": + print(json.dumps(r)) + + +if __name__ == "__main__": + main(sys.argv[1]) diff --git a/tools/mhpow/b1/mtp.py b/tools/mhpow/b1/mtp.py new file mode 100644 index 000000000..e5844524b --- /dev/null +++ b/tools/mhpow/b1/mtp.py @@ -0,0 +1,304 @@ +"""The Merkle Tree Proof framework of [BS25] Sec 3.2 over DRSample: honest prover, proof container, complete verifier. + +Every step names the paragraph it implements. Section numbers are [BS25] = eprint 2025/1456 as archived 2025-12-31. + +Merkle layout ([BS25] Sec 3.2 step 2, Sec 4.1, App. C.1). The tree position of a leaf is a bit string x = x_1 ... x_n read from +the root (x_1 picks the root's child), and the leaf holds tau_x = l_{1 + bin(x)} with bin(x) = sum_i x_i 2^(i-1). So the bit +chosen at depth j is bit j-1 of the leaf index (the root splits even and odd indices). Leaves are the raw labels (the paper +does not hash them). Inner nodes tau_x = H(chi, tau_x0, tau_x1). README row R-3 records App. C.2's printed loop order, which +walks x_1 first from the leaf and is consistent with this layout only if x is read leaf-first; B1 follows Sec 3.2 / 4.1 / +Def. 15's x(j) = x_1 ... x_{j-1} not(x_j) (sibling at depth j from the root). +""" +from __future__ import annotations + +import struct +from dataclasses import dataclass, field +from typing import List, Optional, Sequence, Tuple + +import drsample +import params +from params import H, u64 + +D = params.DIGEST_BYTES + + +# ---------------------------------------------------------------------------------------------------------------------------- +# Labels: [BS25] Sec 2.2 "The Labeling Game" and Sec 3.2 Prove step 1. +# ---------------------------------------------------------------------------------------------------------------------------- + +def label_of(chi: bytes, v: int, parent_labels: Sequence[bytes], tag: bytes = params.TAG_LABEL) -> bytes: + """l_v = H(chi, v, l_v1, ..., l_vk) with parents ascending; l_1 = H(chi, 1). `tag` is overridable only for the + wrong-domain-tag test adversary.""" + return H(tag, chi, u64(v), *parent_labels) + + +def compute_labels(chi: bytes, par: List[Tuple[int, ...]], tag: bytes = params.TAG_LABEL) -> List[bytes]: + """Prove step 1: every label in topological order 1..N. Returns a list indexed 0..N with index 0 unused (None).""" + n_nodes = len(par) - 1 + lab: List[Optional[bytes]] = [None] * (n_nodes + 1) + for v in range(1, n_nodes + 1): + lab[v] = H(tag, chi, u64(v), *[lab[u] for u in par[v]]) + return lab + + +# ---------------------------------------------------------------------------------------------------------------------------- +# Merkle commitment: [BS25] Sec 3.2 Prove step 2, App. C.1 (construction), Def. 15 (reveal), App. C.2 (check). +# ---------------------------------------------------------------------------------------------------------------------------- + +def _bitrev(x: int, n: int) -> int: + r = 0 + for _ in range(n): + r = (r << 1) | (x & 1) + x >>= 1 + return r + + +def merkle_node(chi: bytes, left: bytes, right: bytes, tag: bytes = params.TAG_MERKLE) -> bytes: + return H(tag, chi, left, right) + + +class MerkleTree: + """levels[j] holds the 2^j tree nodes at depth j, indexed by their root-first position bits read as a binary number; + levels[0] = [tau].""" + + def __init__(self, chi: bytes, labels: List[bytes], n: int, tag: bytes = params.TAG_MERKLE): + N = 1 << n + assert len(labels) == N + 1 + self.n = n + leaves = [labels[_bitrev(p, n) + 1] for p in range(N)] # tree position p holds leaf index bitrev(p) + levels = [leaves] + cur = leaves + for _ in range(n): + cur = [merkle_node(chi, cur[2 * q], cur[2 * q + 1], tag) for q in range(len(cur) // 2)] + levels.append(cur) + levels.reverse() + self.levels = levels + + @property + def root(self) -> bytes: + return self.levels[0][0] + + def reveal(self, leaf_index: int) -> List[bytes]: + """Def. 15: the sibling labels tau_{x(j)} for j = 1..n (root-first), x = the tree position of leaf `leaf_index`.""" + p = _bitrev(leaf_index, self.n) + return [self.levels[j][(p >> (self.n - j)) ^ 1] for j in range(1, self.n + 1)] + + +def merkle_tree_check(chi: bytes, leaf_index: int, leaf: bytes, path: Sequence[bytes], tau: bytes, n: int, + counter: Optional[list] = None) -> bool: + """App. C.2 MerkleTreeCheck(chi, i, l_i, mu_i, tau): recompute the root from the leaf up and compare with tau.""" + if len(path) != n or not (0 <= leaf_index < (1 << n)) or len(leaf) != D or any(len(s) != D for s in path): + return False + sigma = leaf + for j in range(n, 0, -1): # from the leaf (depth n) to the root (depth 1) + bit = (leaf_index >> (j - 1)) & 1 # x_j = bit j-1 of the index (bin(x) = sum x_j 2^(j-1)) + sib = path[j - 1] + sigma = merkle_node(chi, sigma, sib) if bit == 0 else merkle_node(chi, sib, sigma) + if counter is not None: + counter[0] += 1 + return sigma == tau + + +# ---------------------------------------------------------------------------------------------------------------------------- +# Challenges: [BS25] Sec 3.2 Prove step 3 / Verify step 1; Sec 5 Def. 14. +# ---------------------------------------------------------------------------------------------------------------------------- + +def challenges(chi: bytes, tau: bytes, k: int, n: int, tag: bytes = params.TAG_CHALLENGE) -> List[int]: + """c_i = H(chi, i, tau) mod N for i = 1..k (0-based leaf index; the challenged node is c_i + 1). N = 2^n divides + 2^256, so the reduction is exactly uniform.""" + N = 1 << n + return [int.from_bytes(H(tag, chi, u64(i), tau), "little") % N for i in range(1, k + 1)] + + +# ---------------------------------------------------------------------------------------------------------------------------- +# The certificate: [BS25] Sec 3.2 Prove step 4, c = (tau, {(l_i, mu_i, L_i)}_{i=1..k}), L_i = {(l_v, mu_{i,v})}_{v in parents}. +# ---------------------------------------------------------------------------------------------------------------------------- + +@dataclass +class Opening: + label: bytes + path: List[bytes] + + +@dataclass +class ChallengeResponse: + node: Opening # (l_i, mu_i) for node c_i + 1 + parents: List[Opening] = field(default_factory=list) # L_i in ascending parent order + + +@dataclass +class Proof: + n: int + tau: bytes + responses: List[ChallengeResponse] + + def to_bytes(self) -> bytes: + """B1 container: magic(8) | n(u8) | k(u32 le) | tau(32) | per challenge: node label(32) | n siblings(32 n) | + parent count(u8) | per parent: label(32) | n siblings(32 n). Positions are never carried: the verifier derives them.""" + out = [params.PROOF_MAGIC, bytes([self.n]), struct.pack(" "Proof": + """Parser; raises ValueError on any malformed container (truncation, trailing bytes, bad magic).""" + if len(b) < 8 + 1 + 4 + D or b[:8] != params.PROOF_MAGIC: + raise ValueError("bad magic or short header") + n = b[8] + k = struct.unpack(" bytes: + nonlocal off + if off + m > len(b): + raise ValueError("truncated") + s = b[off:off + m] + off += m + return s + + def opening() -> Opening: + lab = take(D) + return Opening(lab, [take(D) for _ in range(n)]) + + resps = [] + for _ in range(k): + node = opening() + cnt = take(1)[0] + resps.append(ChallengeResponse(node, [opening() for _ in range(cnt)])) + if off != len(b): + raise ValueError("trailing bytes") + return Proof(n, tau, resps) + + +def proof_bytes_formula(n: int, k: int, indegs: Sequence[int]) -> int: + """Exact container size: 45 + sum_i (1 + 32(n+1) (1 + indeg(c_i + 1))).""" + return 8 + 1 + 4 + D + sum(1 + D * (n + 1) * (1 + d) for d in indegs) + + +# ---------------------------------------------------------------------------------------------------------------------------- +# Honest prover: [BS25] Sec 3.2 Prove^H(chi, N, k), steps 1 to 4. +# ---------------------------------------------------------------------------------------------------------------------------- + +@dataclass +class ProverState: + chi: bytes + n: int + par: List[Tuple[int, ...]] + labels: List[bytes] + tree: MerkleTree + + +def prove_commit(chi: bytes, n: int, par: List[Tuple[int, ...]]) -> ProverState: + labels = compute_labels(chi, par) # step 1 + tree = MerkleTree(chi, labels, n) # step 2 + return ProverState(chi, n, par, labels, tree) + + +def respond(st: ProverState, k: int) -> Proof: + resps = [] + for c in challenges(st.chi, st.tree.root, k, st.n): # step 3: c_i + v = c + 1 + node = Opening(st.labels[v], st.tree.reveal(c)) # step 3(a): mu_i for l_{c_i + 1} at bin(c_i) + pars = [Opening(st.labels[u], st.tree.reveal(u - 1)) for u in st.par[v]] # step 3(b): mu_{i,v} at bin(v - 1) + resps.append(ChallengeResponse(node, pars)) + return Proof(st.n, st.tree.root, resps) # step 4 + + +def prove(chi: bytes, n: int, k: int, par: Optional[List[Tuple[int, ...]]] = None) -> Proof: + if par is None: + par = drsample.all_parents(1 << n) + return respond(prove_commit(chi, n, par), k) + + +# ---------------------------------------------------------------------------------------------------------------------------- +# The complete verifier: [BS25] Sec 3.2 Verify^H(chi, R, c', k), every check a named function, run in the paper's order. +# ---------------------------------------------------------------------------------------------------------------------------- + +class Refused(Exception): + def __init__(self, check: str, detail: str): + super().__init__(f"{check}: {detail}") + self.check = check + self.detail = detail + + +def check_0_container(proof: Proof, n: int, k: int) -> None: + """B1 addition (parsing): the certificate is for this N and carries exactly k responses of the right widths.""" + if proof.n != n: + raise Refused("check_0_container", f"n {proof.n} != {n}") + if len(proof.responses) != k: + raise Refused("check_0_container", f"{len(proof.responses)} responses != k {k}") + if len(proof.tau) != D: + raise Refused("check_0_container", "tau width") + + +def check_1_challenges(chi: bytes, proof: Proof, k: int, n: int, counter: list) -> List[int]: + """Verify step 1: identify tau from c' and compute every challenge c'_i = H(chi, i, tau) mod N.""" + counter[0] += k + return challenges(chi, proof.tau, k, n) + + +def check_2a_parent_set(cs: List[int], proof: Proof) -> List[Tuple[int, ...]]: + """Verify step 2, the separation of L into {(l_j, mu_j)}_{j in parents(c_i + 1)}: the response must open exactly the + parents of c_i + 1 in G (the verifier derives them; a skipped or extra parent is refused). Returns the parent tuples.""" + out = [] + for i, (c, r) in enumerate(zip(cs, proof.responses), 1): + ps = drsample.parents(c + 1) + if len(r.parents) != len(ps): + raise Refused("check_2a_parent_set", f"challenge {i}: node {c + 1} has {len(ps)} parents, response opens {len(r.parents)}") + out.append(ps) + return out + + +def check_2b_merkle_openings(chi: bytes, cs: List[int], pss: List[Tuple[int, ...]], proof: Proof, n: int, counter: list) -> None: + """Verify step 2: MerkleTreeCheck on every reveal, each at the position the verifier derived (node c_i + 1 at index c_i, + parent u at index u - 1), never at a position the prover names (the MTP 1.2 / Bevand 'Attack 2' class).""" + for i, (c, ps, r) in enumerate(zip(cs, pss, proof.responses), 1): + if not merkle_tree_check(chi, c, r.node.label, r.node.path, proof.tau, n, counter): + raise Refused("check_2b_merkle_openings", f"challenge {i}: node {c + 1} opening") + for u, op in zip(ps, r.parents): + if not merkle_tree_check(chi, u - 1, op.label, op.path, proof.tau, n, counter): + raise Refused("check_2b_merkle_openings", f"challenge {i}: parent {u} of node {c + 1} opening") + + +def check_3_local_consistency(chi: bytes, cs: List[int], proof: Proof, counter: list) -> None: + """Verify step 3: l_v = H(chi, v, l_v1, ..., l_vk) for v = c_i + 1 with the committed parent labels.""" + for i, (c, r) in enumerate(zip(cs, proof.responses), 1): + counter[0] += 1 + if label_of(chi, c + 1, [p.label for p in r.parents]) != r.node.label: + raise Refused("check_3_local_consistency", f"challenge {i}: node {c + 1} is red") + + +@dataclass +class Verdict: + accepted: bool + check: str # "accept" or the first refusing check + detail: str + hashes: int # oracle calls made by the verifier (challenges + Merkle + local consistency; graph draws counted apart) + + +def verify(chi: bytes, n: int, k: int, proof_or_bytes) -> Verdict: + """[BS25] Sec 3.2 Verify, steps 1 to 4, in order; returns the first refusing check by name.""" + counter = [0] + try: + if isinstance(proof_or_bytes, (bytes, bytearray)): + try: + proof = Proof.from_bytes(bytes(proof_or_bytes)) + except ValueError as e: + raise Refused("check_0_container", str(e)) + else: + proof = proof_or_bytes + check_0_container(proof, n, k) + cs = check_1_challenges(chi, proof, k, n, counter) + pss = check_2a_parent_set(cs, proof) + check_2b_merkle_openings(chi, cs, pss, proof, n, counter) + check_3_local_consistency(chi, cs, proof, counter) + except Refused as r: + return Verdict(False, r.check, r.detail, counter[0]) + return Verdict(True, "accept", "", counter[0]) # step 4 diff --git a/tools/mhpow/b1/params.py b/tools/mhpow/b1/params.py new file mode 100644 index 000000000..49037a4b6 --- /dev/null +++ b/tools/mhpow/b1/params.py @@ -0,0 +1,62 @@ +"""Pinned constants of the B1 reference (R15-05): the MTP framework instantiated with DRSample. + +Sources (full PDFs, sha256 recorded in docs/analysis/mhpow/b1/README.md): + [BS25] Blocki and Smearsoll, "Provably Memory-Hard Proofs of Work With Memory-Easy Verification", TCC 2025, + IACR eprint 2025/1456 as archived 2025-12-31T15:20:15Z (46 pp). + [ABH17] Alwen, Blocki and Harsha, "Practical Graphs for Optimal Side-Channel Resistant Memory-Hard Functions", + CCS 2017, IACR eprint 2017/443 as archived 2025-12-10T21:05:18Z; Algorithm 1 (DRSample, GetParent). + +[BS25] fixes the construction abstractly: a random oracle H : {0,1}* -> {0,1}^lambda, labels H(chi, v, parents' labels) +(Sec 2.2 "The Labeling Game", Sec 3.2 step 1), Merkle inner nodes H(chi, left, right) with chi as the salt (Sec 3.2 step 2, +Sec 4.1, App. C.1), challenges H(chi, i, tau) mod N (Sec 3.2 step 3). It names no concrete hash, lambda, byte encoding or +domain tag; the paper's only domain separation is the salt chi and the shape of each query. Everything in this file that the +paper leaves open is a B1 decision, stated here with its reason, agreed with the B2 lane (instance layout) before the first +fixture. +""" +import hashlib + +# lambda (bits) and the oracle. B1 decision: BLAKE2b with a 32-byte digest, lambda = 256. Reason: one primitive across B1, B2 +# (chi = BLAKE2b('I' || instance)) and B3's GPU oracle; a 256-bit output keeps [BS25] Corollary 1's collision term +# 2^-lambda * C(q,2) negligible for any q a network could make. NOTE (README row O-4): [BS25] Lemma 3 also needs +# lambda/4 >= 2 log2(q) + log2(indeg), which lambda = 256 meets only for q <= 2^31.5 oracle calls. +LAMBDA_BITS = 256 +DIGEST_BYTES = LAMBDA_BITS // 8 + + +def H(*parts: bytes) -> bytes: + """The random oracle instantiation: BLAKE2b-256 over the plain concatenation of fixed-width fields.""" + h = hashlib.blake2b(digest_size=DIGEST_BYTES) + for p in parts: + h.update(p) + return h.digest() + + +# Domain tags: one leading byte per query kind. B1 decision on top of [BS25]'s salt-only separation. Reason: without a tag the +# challenge query H(chi, i, tau) (Sec 3.2 step 3) has exactly the shape of the prelabel H(chi, v, l_u) of an indegree-1 node +# (node 2 of DRSample, [ABH17] Alg. 1 E := {(1,2)}) when i and v share a width; the tags make the four query families disjoint +# by their first byte. The paper's proof (Sec 4.2, the extractor reads a parent label at offset |chi| + log2 N + h*lambda) +# is unaffected by a fixed one-byte prefix. +TAG_LABEL = b"L" # [BS25] Sec 2.2 labeling game; Sec 3.2 step 1: l_1 = H(chi, 1), l_v = H(chi, v, l_v1, ..., l_vk) +TAG_MERKLE = b"M" # [BS25] Sec 3.2 step 2; App. C.1: tau_x = H(chi, tau_x0, tau_x1), tau = H(chi, tau_0, tau_1) +TAG_CHALLENGE = b"C" # [BS25] Sec 3.2 step 3; Sec 5 Def. 14: c_i = H(chi, i, tau) mod N, i = 1..k +TAG_GRAPH = b"G" # [ABH17] Alg. 1 random draws (g', r): B1's derandomisation of DRSample, see drsample.py +TAG_INSTANCE = b"I" # owned by B2 (chi = BLAKE2b('I' || 328-byte instance)); listed so B1 never reuses it + +ALL_TAGS = (TAG_LABEL, TAG_MERKLE, TAG_CHALLENGE, TAG_GRAPH, TAG_INSTANCE) +assert len(set(ALL_TAGS)) == len(ALL_TAGS) + +CHI_BYTES = 32 # chi is the 32-byte BLAKE2b digest of B2's instance; B1's own fixtures use chi = H(b"B1-fixture", tag) + + +def u64(x: int) -> bytes: + """Node indices v (1..N) and challenge indices i (1..k): unsigned 64-bit little-endian, fixed width.""" + return int(x).to_bytes(8, "little") + + +# The DRSample graph is sampled ONCE from a public constant seed, never from chi. Reason: [BS25] proves soundness for a graph +# fixed a priori (Sec 1.2: "sound as long as the underlying graph is fixed a priori (i.e., cannot be adversarially modified)"); +# a chi-derived graph would let a prover that chooses chi (a nonce) grind for a weak graph. +GRAPH_SEED = hashlib.blake2b(b"igneum/mhpow/b1/drsample-graph-seed/v1", digest_size=32).digest() + +# Proof serialisation magic (B1's container; the paper defines the certificate c = (tau, {(l_i, mu_i, L_i)}) abstractly). +PROOF_MAGIC = b"B1MTPDR1" diff --git a/tools/mhpow/b1/run-b1.sh b/tools/mhpow/b1/run-b1.sh new file mode 100755 index 000000000..08a9a52de --- /dev/null +++ b/tools/mhpow/b1/run-b1.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# B1 driver for a build box (never the Mac). Writes its pid file first, runs the tests, the known-answer fixtures, the honest +# rows and the attack fixtures, then SHA256SUMS. Stop it only by its pid file: kill "$(cut -d' ' -f1 "$PIDFILE")". +# tools/mhpow/b1/run-b1.sh [tests|kat|rows|attacks|ktable|all] +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +OUT="${1:?out dir}"; WHAT="${2:-all}" +PIDFILE="${B1_PIDFILE:-/srv/builds/mhpow-b1/run.pid}" +printf '%s %s b1-%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$WHAT" > "$PIDFILE" +mkdir -p "$OUT" +cd "$HERE" +if [ "$WHAT" = tests ] || [ "$WHAT" = all ]; then + python3 -m unittest -v test_b1 2>&1 | tee "$OUT/tests.log" + grep -q '^OK' "$OUT/tests.log" +fi +if [ "$WHAT" = kat ] || [ "$WHAT" = all ]; then python3 gen_fixtures.py kat "$OUT"; fi +if [ "$WHAT" = rows ] || [ "$WHAT" = all ]; then + for n in 12 16 20 22 24; do python3 gen_fixtures.py row "$OUT" "$n" 64; done +fi +if [ "$WHAT" = attacks ] || [ "$WHAT" = all ]; then python3 gen_fixtures.py attacks "$OUT"; fi +if [ "$WHAT" = ktable ] || [ "$WHAT" = all ]; then python3 k_table.py "$OUT" | tee "$OUT/k-table.log"; fi +(cd "$OUT" && sha256sum $(ls | grep -v '^SHA256SUMS$') > SHA256SUMS) +echo "B1 DONE $WHAT $(date -u +%Y-%m-%dT%H:%M:%SZ)" diff --git a/tools/mhpow/b1/test_b1.py b/tools/mhpow/b1/test_b1.py new file mode 100644 index 000000000..097e5fc6b --- /dev/null +++ b/tools/mhpow/b1/test_b1.py @@ -0,0 +1,162 @@ +"""B1 tests: the honest path accepts, and every verifier check refuses its own known-failed case by name. + +Run on a build box only (the founder's rule): cd tools/mhpow/b1 && python3 -m unittest -v test_b1 +""" +import copy +import unittest + +import drsample +import mtp +import params + +CHI = params.H(b"B1-test", b"chi-0") +CHI2 = params.H(b"B1-test", b"chi-1") + + +class GraphTests(unittest.TestCase): + def test_edge_rule(self): + par = drsample.all_parents(1 << 12) + self.assertEqual(par[1], ()) + self.assertEqual(par[2], (1,)) + for v in range(3, len(par)): + u, w = par[v] + self.assertEqual(w, v - 1) + r = v - u + self.assertGreaterEqual(r, 2) + self.assertLessEqual(r, v - 1) + # r lies in some bucket [max(ceil(g/2),2), g] with g = min(v-1, 2^g'), 1 <= g' <= floor(log2 v)+1 + ok = any(max(-(-min(v - 1, 1 << gp) // 2), 2) <= r <= min(v - 1, 1 << gp) for gp in range(1, v.bit_length() + 1)) + self.assertTrue(ok, (v, r)) + + def test_deterministic(self): + self.assertEqual(drsample.all_parents(512), drsample.all_parents(512)) + + def test_bucket_spread(self): + # [ABH17] Sec 3 intuition: each bucket B_i (2^(i-1) <= dist <= 2^i) is hit; a sanity check that the derandomisation + # did not collapse the distribution. + par = drsample.all_parents(1 << 14) + buckets = set((v - par[v][0]).bit_length() for v in range(3, len(par))) + self.assertGreaterEqual(len(buckets), 13) + + +class MerkleTests(unittest.TestCase): + def test_reveal_check_every_leaf(self): + n = 5 + par = drsample.all_parents(1 << n) + lab = mtp.compute_labels(CHI, par) + t = mtp.MerkleTree(CHI, lab, n) + for x in range(1 << n): + self.assertTrue(mtp.merkle_tree_check(CHI, x, lab[x + 1], t.reveal(x), t.root, n)) + self.assertFalse(mtp.merkle_tree_check(CHI, x ^ 1, lab[x + 1], t.reveal(x), t.root, n)) + + def test_layout_lsb_at_root(self): + # [BS25] Sec 3.2: tau_v = l_{1+bin(v)}, bin(v) = sum v_i 2^(i-1): the root's left subtree holds even leaf indices. + n = 3 + lab = [None] + [bytes([v]) * 32 for v in range(1, 9)] + t = mtp.MerkleTree(CHI, lab, n) + left = mtp.merkle_node(CHI, mtp.merkle_node(CHI, lab[1], lab[5]), mtp.merkle_node(CHI, lab[3], lab[7])) + self.assertEqual(t.levels[1][0], left) + + +class VerifierTests(unittest.TestCase): + n, k = 8, 16 + + @classmethod + def setUpClass(cls): + cls.par = drsample.all_parents(1 << cls.n) + cls.st = mtp.prove_commit(CHI, cls.n, cls.par) + cls.proof = mtp.respond(cls.st, cls.k) + + def v(self, proof, chi=CHI): + return mtp.verify(chi, self.n, self.k, proof) + + def test_honest_accepts_object_and_bytes(self): + self.assertTrue(self.v(self.proof).accepted) + b = self.proof.to_bytes() + self.assertTrue(self.v(b).accepted) + self.assertEqual(mtp.Proof.from_bytes(b).to_bytes(), b) + indeg = [len(self.par[c + 1]) for c in mtp.challenges(CHI, self.proof.tau, self.k, self.n)] + self.assertEqual(len(b), mtp.proof_bytes_formula(self.n, self.k, indeg)) + + def test_wrong_label(self): + p = copy.deepcopy(self.proof) + p.responses[3].node.label = bytes([p.responses[3].node.label[0] ^ 1]) + p.responses[3].node.label[1:] + self.assertEqual(self.v(p).check, "check_2b_merkle_openings") + + def test_wrong_parent_label(self): + p = copy.deepcopy(self.proof) + lab = p.responses[2].parents[0].label + p.responses[2].parents[0].label = bytes([lab[0] ^ 0x80]) + lab[1:] + self.assertEqual(self.v(p).check, "check_2b_merkle_openings") + + def test_wrong_path(self): + p = copy.deepcopy(self.proof) + s = p.responses[0].node.path[4] + p.responses[0].node.path[4] = s[:-1] + bytes([s[-1] ^ 1]) + self.assertEqual(self.v(p).check, "check_2b_merkle_openings") + + def test_wrong_challenge(self): + # answer the challenges for i = 2..k+1 instead of 1..k (each response opens a node the verifier did not derive) + cs = mtp.challenges(CHI, self.st.tree.root, self.k + 1, self.n)[1:] + resps = [] + for c in cs: + v = c + 1 + resps.append(mtp.ChallengeResponse(mtp.Opening(self.st.labels[v], self.st.tree.reveal(c)), + [mtp.Opening(self.st.labels[u], self.st.tree.reveal(u - 1)) for u in self.par[v]])) + r = self.v(mtp.Proof(self.n, self.st.tree.root, resps)) + self.assertFalse(r.accepted) + self.assertIn(r.check, ("check_2a_parent_set", "check_2b_merkle_openings")) + + def test_skipped_parent(self): + p = copy.deepcopy(self.proof) + i = next(j for j, r in enumerate(p.responses) if len(r.parents) == 2) + p.responses[i].parents = p.responses[i].parents[1:] + self.assertEqual(self.v(p).check, "check_2a_parent_set") + + def test_duplicated_parent_position(self): + # the Bevand 'Attack 2' class: both openings for the same parent; positions are bound by the verifier + p = copy.deepcopy(self.proof) + i = next(j for j, r in enumerate(p.responses) if len(r.parents) == 2) + p.responses[i].parents[0] = copy.deepcopy(p.responses[i].parents[1]) + self.assertEqual(self.v(p).check, "check_2b_merkle_openings") + + def test_wrong_domain_tag_label(self): + # a prover that labels with the Merkle tag instead of the label tag, consistently, and commits honestly to that array + lab = mtp.compute_labels(CHI, self.par, tag=params.TAG_MERKLE) + st = mtp.ProverState(CHI, self.n, self.par, lab, mtp.MerkleTree(CHI, lab, self.n)) + self.assertEqual(self.v(mtp.respond(st, self.k)).check, "check_3_local_consistency") + + def test_wrong_domain_tag_merkle(self): + tree = mtp.MerkleTree(CHI, self.st.labels, self.n, tag=params.TAG_LABEL) + st = mtp.ProverState(CHI, self.n, self.par, self.st.labels, tree) + self.assertEqual(self.v(mtp.respond(st, self.k)).check, "check_2b_merkle_openings") + + def test_wrong_chi(self): + self.assertEqual(self.v(self.proof, chi=CHI2).check, "check_2b_merkle_openings") + + def test_container(self): + b = self.proof.to_bytes() + self.assertEqual(self.v(b[:-1]).check, "check_0_container") + self.assertEqual(self.v(b + b"\0").check, "check_0_container") + self.assertEqual(mtp.verify(CHI, self.n, self.k + 1, b).check, "check_0_container") + self.assertEqual(mtp.verify(CHI, self.n + 1, self.k, b).check, "check_0_container") + + def test_every_check_has_a_refusal(self): + # the named checks of the verifier, each shown to fire above (a watcher is trusted only after it fires) + names = {"check_0_container", "check_2a_parent_set", "check_2b_merkle_openings", "check_3_local_consistency"} + fired = { + self.v(self.proof.to_bytes()[:-1]).check, + self.v(self.proof, chi=CHI2).check, + } + p = copy.deepcopy(self.proof) + i = next(j for j, r in enumerate(p.responses) if len(r.parents) == 2) + p.responses[i].parents = p.responses[i].parents[1:] + fired.add(self.v(p).check) + lab = mtp.compute_labels(CHI, self.par, tag=params.TAG_MERKLE) + st = mtp.ProverState(CHI, self.n, self.par, lab, mtp.MerkleTree(CHI, lab, self.n)) + fired.add(self.v(mtp.respond(st, self.k)).check) + self.assertEqual(fired, names) + + +if __name__ == "__main__": + unittest.main() From 51ab950a38df12bc3b1b4434f04382b442388cd5 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:39:03 +0000 Subject: [PATCH 08/19] mhpow B4: the lottery draw as the composed statement's first obligation (B4-OB-LOT), the control in the head as BOUND (L) Section 5b: why the naive root lottery fails in the composed statement's terms (B4 Lemma C, the sink re-roll: one trace, one cmc bound, log2 N + 1 queries per draw, accepted with probability (1 - 1/N)^k, 0.9946 at log2 N = 22), what a draw must cost (a fresh labelling, phi = 1), the construction change (trial id in chi, v = H(tag_lot, chi, tau), full verification of winners, spot checks as the pre-filter) and its effect on the losses (L2 and L10 removed for winners, L11 open for terms 2 and 3, the generic route 0.151 -> 0.213, the red-blue route unchanged). Rows B4-OB-LOT and -1 to -4 taken by name (B2, B1, B4, B6). params.py section 8. Co-Authored-By: Claude Opus 5.5 --- docs/analysis/mhpow/b4/README.md | 72 +++++++++++++++++++ docs/analysis/mhpow/b4/RUNS.md | 1 + docs/analysis/mhpow/b4/params.txt | 9 +++ docs/analysis/mhpow/b4/registry-batch-b4.json | 4 +- tools/mhpow/b4/params.py | 10 +++ 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/docs/analysis/mhpow/b4/README.md b/docs/analysis/mhpow/b4/README.md index 91beca37a..456df6a8b 100644 --- a/docs/analysis/mhpow/b4/README.md +++ b/docs/analysis/mhpow/b4/README.md @@ -8,6 +8,17 @@ Track B item B4 of the 1.5x research programme (plan: docs/plans/igneum-2.0-mast NEW line below is a proof obligation until the independent panel reads it. The composed claim is a theorem shape with named holes; where a hole is decision-critical it is a BLOCKED row with its exact question. +**THE CONTROL (BOUND (L), negative, it stands).** Through the published constants no 1.5x certificate is reachable. The generic +route (R2 Theorem 4.5 on R1's cmc bound) certifies at most 0.151 of an honest prover's energy (log2 N = 22, depth-robustness +constants c1 c2 = 1, c_b = c_r; ratio floor 6.63x; 0.213 and 4.69x for a fully verified winner, section 5b); the red-blue route +(R2 Theorem 3.3 x Lemma 5.5) loses at least 256/(1 - rho): 341x at rho = 0.25, 512x at rho = 0.5. A 1.5x certificate G_upper / L +would need the GPU at 0.23 (generic) or 0.0044 (red-blue) of the honest specialist's energy. Labelled BOUND (L), kept as a control. + +**THE FIRST OBLIGATION: the lottery draw (section 5b, row B4-OB-LOT).** R1's MHPoW has no difficulty target; a lottery value over +the certificate root re-rolls for log2 N + 1 hashes per draw after one labelling (B2's finding; the naive rule reads FAIL). A draw +must cost a fresh labelling: trial id in chi, v = H(tag_lot, chi, tau), winners verified in full, spot checks kept as the +pre-filter. Owners by row: B4-OB-LOT (B4), -1 (B2), -2 (B1), -3 (B4), -4 (B2 with B6). + **The result in four lines.** 1. The 2025 theorem (Blocki and Smearsoll) proves, in the parallel random oracle model, that any prover whose MTP/DRSample @@ -181,6 +192,66 @@ c_r q part of R2's ecost and must not be added to it a second time. **What the claim does NOT say.** It is not a bound on the specialist's energy per hash of Igneum's current work; it is per accepted certificate of the published construction under the pROM. It gives no G_upper. It certifies nothing about the GPU side. +## 5b. The lottery draw: the first obligation of the composed statement (row B4-OB-LOT) + +Main's word through the coordinator (10:3x UK): the B2 lane found, from R1 Definition 5 and the certificate shape, that R1's MHPoW +has no difficulty target and that a lottery value drawn over the certificate root is re-rolled for about log2 N + 1 hashes per draw +after one labelling (make the sink red). The naive lottery rule reads FAIL. The replacement rule is BLOCKED and is this row. + +**Why the naive rule fails, in the composed statement's terms (B4 Lemma C, NOT RUN).** Any lottery value v computed from an MTP +certificate depends on the root tau (otherwise it does not depend on the labelling and can be pre-filtered for one hash). Holding +one honest labelling for chi, a prover sets the sink's label to a fresh value (the sink has no children, so only the sink turns red), +recomputes its Merkle path (log2 N + 1 queries) and obtains a new tau, new challenges and a new v. The certificate is accepted unless +a challenge lands on the sink: probability at least (1 - 1/N)^k >= 1 - k/N per draw (0.9946 at k = 22,528, N = 2^22; params.txt sec. 8). All these +certificates share ONE trace: R1's cmc bound and the composed claim's terms 2 and 3 are paid once, and term 1 grows by only +log2 N + 1 queries per draw. Over R draws per labelling the certified cost per draw is at most +(log2 N + 1) c_H + (terms 1 to 3 of one labelling) / R, which tends to Merkle hashing alone as R grows. The prover's choice of R is +free, so the per-draw energy the theorems certify is a hashing floor. The same holds for any red node with few descendants and for +any lottery function of the certificate: spot checks with k << N cannot make a labelling-dependent value non-malleable. + +**What a draw must cost (the obligation).** For the composed statement to price P04's unit (energy per equivalent accepted work), +each lottery draw must cost a fresh labelling: E_draw >= term 1 + term 2 + term 3 of one instance (section 5), with fraction +phi = 1, or a stated phi < 1 with its own proof. Three conditions are necessary: (D1) the draw value depends on the labelling, so it +cannot be pre-filtered; (D2) for one chi, at most one draw value is ACCEPTABLE, so re-rolls buy nothing; (D3) distinct draws are +distinct instances, so the costs add. + +**The construction change that meets D1 to D3 (proposal for B2 and B1, NOT RUN).** + +1. Bind the trial id into chi (network, version, epoch, template, trial id): every draw is a new instance; every label query and + every Merkle query carries chi, so instances share no RO answers (term 1 additive, section 5). +2. The draw value v = H(tag_lot, chi, tau) against the target (D1: tau needs the labelling). +3. A block that wins is verified IN FULL by validators: they recompute the labelling for chi and its root and accept only + tau = the honest root (D2: without collisions the honest root is a function of chi, so exactly one acceptable value per chi; a + re-rolled tau with any red node is rejected with certainty). The k-challenge certificate stays as a CHEAP PRE-FILTER: a header + whose spot checks fail is dropped before any full recomputation, and R1's theorem prices the attacker's cost of a fake winner + that passes the spot checks (at least the cmc bound of section 3), so a flood of fake winners costs the attacker about what it + costs a validator to reject them. +4. Pool shares may stay on spot checks (the pool's own risk); a share then proves R1's cmc bound per share chi, never a draw. + +**What the change does to the composed statement and to the reduction losses.** + +| loss row | effect of the change | why | +|---|---|---| +| L2 (red nodes, 2x) | removed for winning draws | a full-verified winner has beta = 0: cc(G), not min over S of cc(G - S) | +| L10 (MTP certificate vs full evaluation) | removed for winning draws | the winner is a plain iMHF evaluation f_G(chi) plus a Merkle root: AS15's extraction and R2 Theorem 3.3 apply as published, with no new composition | +| L11 (amortisation across instances) | term 1: none; terms 2 and 3: still open | distinct chi share no queries; cmc and red-blue cost of J parallel instances against J times one instance needs the union-graph form of AS15 and R2 Thm 3.3 (obligation B4-OB-LOT-3) | +| L5 (generic route) | improves by sqrt 2 only: share of honest <= 2 sqrt(c1 c2 / log2 N) x sqrt(c_b c_r)/(c_b + c_r), 0.213 at log2 N = 22, c1 c2 = 1, c_b = c_r (ratio floor 4.69x; params.txt sec. 8) | cc(G) >= e d instead of e d/2 | +| L6 x L7 (red-blue route) | unchanged: at least 256/(1 - rho) | R2's constants | +| new: verification | a validator recomputes one labelling per winning block (N + (N - 1) RO calls, N w bits of state); at 1 block/s that is one labelling per second per validator | this gives up R1's memory-easy verification for blocks; a B6 cost to size against the operator budget | + +The control does not move: through the published constants no 1.5x certificate is reachable with or without the change (the change +removes the MTP-specific losses, not R2's). + +**Rows taken by name.** + +| row | owner | obligation | +|---|---|---| +| B4-OB-LOT | B4 | B4 Lemma C (the re-roll bound) written as a proof; the per-draw cost statement E_draw >= one instance's terms with phi = 1 under items 1 to 3 above | +| B4-OB-LOT-1 | B2 (a717f5c9730229ea6) | the lottery rule: trial id in chi, v = H(tag_lot, chi, tau), full verification of winners, spot checks as the header pre-filter; state the DoS budget of a spot-check-passing fake winner from R1's bound | +| B4-OB-LOT-2 | B1 (a4490b2dfe9114a55) | a malicious fixture for the sink re-roll (one labelling, many accepted roots, the measured acceptance rate against (1 - 1/N)^k) and the full verifier for winners at the fixture's N | +| B4-OB-LOT-3 | B4 | multi-instance amortisation of terms 2 and 3 for J distinct chi in one trace (the union graph of J copies of G) | +| B4-OB-LOT-4 | B2 with B6 | the verification cost of one full labelling per winning block at the network's block rate and the cold-verification DoS bound | + ## 6. What each source gives, and what is new **R1 (2025) gives:** soundness of the MTP framework for data-independent depth-robust graphs in the pROM; cmc of any accepted prover @@ -326,6 +397,7 @@ Found while reading; each is a question for B1 to settle against the authors' la | B4-B07 | The encoded-state question of section 9. | B2 and B1 | | B4-B08 | Split lambda: label width w (must exceed about 520 bits for the cmc theorem and 1,280 bits for R2's reduction at q = 2^64) and soundness lambda_s for k. | B2 | | B4-B09 | Domain separation of the three query kinds (section 11 item 7). | B1 | +| B4-OB-LOT | The lottery draw's cost (section 5b): the replacement rule for the naive root lottery, which reads FAIL. | B4, with B2 and B1 by the rows of section 5b | | B4-B10 | Proof size: k (delta+1) openings at 128-bit soundness is 11.9 MiB at best (c1 = 1, log2 N = 22, 256-bit labels) and grows as 1/c1. Pool shares carry proofs too. | B6 (plan), via the coordinator | ## 13. Obligations for the B2 binding lane (a717f5c9730229ea6) and the B1 reference lane (a4490b2dfe9114a55) diff --git a/docs/analysis/mhpow/b4/RUNS.md b/docs/analysis/mhpow/b4/RUNS.md index 032042c54..fc8b8eb6a 100644 --- a/docs/analysis/mhpow/b4/RUNS.md +++ b/docs/analysis/mhpow/b4/RUNS.md @@ -9,5 +9,6 @@ build-1:/srv/queue/pids/build-9-b4.pid (queue entry B4, ended 10:12 UK). Clocks | 2026-10-09T09:05Z | Internet Archive copies of the eprint PDF URLs, arXiv 2207.11519 | curl -sSL https://web.archive.org/web/2026id_/https://eprint.iacr.org/.pdf | wb-2025-1456.pdf, wb-2018-221.pdf, wb-2017-225.pdf, wb-2026-1024.pdf, arxiv-2207.11519.pdf | SHA256SUMS in build-9:/srv/builds/b4 and README section 1 | | 2026-10-09T09:09Z | 2017/443 and 2016/875 (archived 429 and robots pages; not retried) | as above | removed | none | | 2026-10-09T09:17:30Z | parameter arithmetic | python3 tools/mhpow/b4/params.py > docs/analysis/mhpow/b4/params.txt | params.txt | params.py 7ac7fd48bde3e7962fe01045fa12a2ab1c204d9e34265a78ef9240f4f8433af1, params.txt a98ac460a5f6a16c000d5eda6311444044928f5f899931e0d3afa667d1529eba | +| 2026-10-09T09:38:50Z | parameter arithmetic with section 8 (the lottery draw) | python3 tools/mhpow/b4/params.py > docs/analysis/mhpow/b4/params.txt | params.txt (supersedes the 09:17 output) | params.py cb9ed2c065ec451e24f9f2331f461c7b1dfda644cb4e2d6dda4b788b87698010, params.txt 7804979e4d9a401b7dc560019118c54ece3d440caf68e88ea792208b4eb9d01e | Text extraction of the five PDFs for reading: pdftotext -layout (poppler), a document conversion, no build, test or benchmark. diff --git a/docs/analysis/mhpow/b4/params.txt b/docs/analysis/mhpow/b4/params.txt index 013c81b8c..da2d130e3 100644 --- a/docs/analysis/mhpow/b4/params.txt +++ b/docs/analysis/mhpow/b4/params.txt @@ -75,3 +75,12 @@ then G_upper / L = loss * (G_upper / E_honest_specialist), and the certificate n loss 6.6: a 1.5x certificate needs the GPU at <= 0.2273 of the honest specialist's energy (a GPU at parity certifies only 6.6x) loss 341: a 1.5x certificate needs the GPU at <= 0.0044 of the honest specialist's energy (a GPU at parity certifies only 341.0x) loss 512: a 1.5x certificate needs the GPU at <= 0.0029 of the honest specialist's energy (a GPU at parity certifies only 512.0x) + +== 8. the lottery draw (README section 5b) == +sink re-roll: log2 N=20, k=20480: 21 queries per draw, accepted with probability (1 - 1/N)^k = 0.9807 +sink re-roll: log2 N=22, k=22528: 23 queries per draw, accepted with probability (1 - 1/N)^k = 0.9946 +sink re-roll: log2 N=24, k=24576: 25 queries per draw, accepted with probability (1 - 1/N)^k = 0.9985 +full-verified winner (beta = 0), log2 N=17: generic-route share of honest <= 0.2425 (ratio floor 4.12x) at c1 c2 = 1, cb = cr +full-verified winner (beta = 0), log2 N=20: generic-route share of honest <= 0.2236 (ratio floor 4.47x) at c1 c2 = 1, cb = cr +full-verified winner (beta = 0), log2 N=22: generic-route share of honest <= 0.2132 (ratio floor 4.69x) at c1 c2 = 1, cb = cr +full-verified winner (beta = 0), log2 N=24: generic-route share of honest <= 0.2041 (ratio floor 4.90x) at c1 c2 = 1, cb = cr diff --git a/docs/analysis/mhpow/b4/registry-batch-b4.json b/docs/analysis/mhpow/b4/registry-batch-b4.json index 9ee2b5c56..b5dcd1e90 100644 --- a/docs/analysis/mhpow/b4/registry-batch-b4.json +++ b/docs/analysis/mhpow/b4/registry-batch-b4.json @@ -9,7 +9,7 @@ "binary": "", "network_object": "none: a theorem statement and an audit of published papers, no chain state read or written", "activation": "none (Track B lands documents and tests only)", - "profile_hashes": "R1 2025/1456 13c3646e...; R2 2018/221 2a466b97...; R3 2017/225 29c5a9c0...; R4 2026/1024 aa6caa39...; R16 arXiv 2207.11519 ac273393...; params.py 7ac7fd48..., params.txt a98ac460..." + "profile_hashes": "R1 2025/1456 13c3646e...; R2 2018/221 2a466b97...; R3 2017/225 29c5a9c0...; R4 2026/1024 aa6caa39...; R16 arXiv 2207.11519 ac273393...; params.py cb9ed2c0..., params.txt 7804979e..." }, "claim_impact": "none: the composed accepted-proof energy statement is a draft with named proof obligations; the published constants cannot carry a 1.5x certificate (loss at least 6.6x on the generic route, at least 341x on the red-blue route); every row NOT RUN until the panel reads it", "reviewer": "", @@ -20,7 +20,7 @@ "status": "NOT RUN", "method": "model", "evidence": "docs/analysis/mhpow/b4/README.md; docs/analysis/mhpow/b4/params.txt; docs/analysis/mhpow/b4/RUNS.md; tools/mhpow/b4/params.py", - "note": "NOT RUN: statement and losses written; terms 2 (transfers) and the amortisation of terms 2 and 3 are open theorems; L is BLOCKED (no lower-bound certificate for any technology coefficient); X5 rows stay WITNESS (E_D)", + "note": "NOT RUN: statement and losses written; the lottery draw (B4-OB-LOT: the naive root lottery FAIL, the replacement BLOCKED); terms 2 (transfers) and the amortisation of terms 2 and 3 are open theorems; L is BLOCKED (no lower-bound certificate for any technology coefficient); X5 rows stay WITNESS (E_D)", "in_progress": true } ] diff --git a/tools/mhpow/b4/params.py b/tools/mhpow/b4/params.py index 12740c9b7..1bc50ed98 100644 --- a/tools/mhpow/b4/params.py +++ b/tools/mhpow/b4/params.py @@ -80,3 +80,13 @@ print("the certificate is G_upper / L <= 1.5 (plan section 2). If the composed t print("then G_upper / L = loss * (G_upper / E_honest_specialist), and the certificate needs G_upper / E_honest_specialist <= 1.5 / loss.") for loss in (6.6, 341, 512): print(f"loss {loss:>5}: a 1.5x certificate needs the GPU at <= {1.5/loss:.4f} of the honest specialist's energy (a GPU at parity certifies only {loss:.1f}x)") + +print() +print("== 8. the lottery draw (README section 5b) ==") +for logN, k in ((20, 20480), (22, 22528), (24, 24576)): + N = 2**logN + acc = (1 - 1 / N) ** k + print(f"sink re-roll: log2 N={logN}, k={k}: {logN + 1} queries per draw, accepted with probability (1 - 1/N)^k = {acc:.4f}") +for logN in (17, 20, 22, 24): + f = math.sqrt(1.0 / logN) # full verification: cmc <= w e d, share <= 2 sqrt(c1 c2 / log2 N) * sqrt(cb cr)/(cb+cr), at c1 c2 = 1, cb = cr + print(f"full-verified winner (beta = 0), log2 N={logN}: generic-route share of honest <= {f:.4f} (ratio floor {1/f:.2f}x) at c1 c2 = 1, cb = cr") From 8dd7f281c67cc707e75075e0f5a4c9c8467b7790 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:40:07 +0000 Subject: [PATCH 09/19] mhpow B2: O-07 cites B1's executed re-roll fixture A6 B1's fixture A6 (attacks-n10-k16.json 805035eb, mhpow-b1 29d7bfebd) runs the O-07 counter-example: one labelling, a red sink, 26 calls a try, 193 to 200 of 200 tries accepted by the full verifier, matching (1 - 2^-10)^16. The row now says the paper's bound holds once per trace, not once per certificate. Co-Authored-By: Claude Opus 5.5 --- docs/analysis/mhpow/b2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/analysis/mhpow/b2/README.md b/docs/analysis/mhpow/b2/README.md index 9911614a2..48c75ac6d 100644 --- a/docs/analysis/mhpow/b2/README.md +++ b/docs/analysis/mhpow/b2/README.md @@ -117,7 +117,7 @@ parameter choice (B3, B4) fill them. They are not conformance vectors; the B1 la | O-04 | Reuse on another epoch, day, era, network or protocol version | the same: those fields are in the instance, and the verifier recomputes each from the chain (never from the certificate) | as O-03 | ANSWERED, conditional on B-N1 (the verifier's recomputation rule and the live day rule) | | O-05 | The graph is fixed before the prover acts (the Dinur and Nadler lesson) | DRSample sampled once from `graph_seed`, a consensus constant; never from `chi`, the epoch, the era or the template | the paper's own condition (section 1.2): MTP is sound "as long as the underlying graph is fixed a priori"; Fact 8 is an existence statement | BLOCKED B-T1: the probability that one sampled DRSample instance at the chosen `N` fails the `(c3 N / log N, c4 N)` depth-robustness, and whether a per-era re-seed is admissible | | O-06 | Grinding the commitment to dodge the challenges (try roots until all `k` challenges land on honestly computed nodes) | `k` from Corollary 2 | Lemma 4: `q (1 - beta)^k`; Corollary 2: `beta = e/(2N)`, `k = (2 N ln 2 / e) lambda` gives `q 2^-lambda`; figures section 4 | ANSWERED (the constants of `k` wait on `c3`: B-T2) | -| O-07 | Grinding the lottery: what the prover can vary per draw, at what cost, once one labelling exists | no lottery rule is adopted. Two candidate rules fail: (a) `W = H('W' || chi || tau) <= target`: after one honest labelling the prover sets the sink label `l'_N` to fresh bytes (the sink turns red), rehashes its Merkle path and draws again, `log2 N + 1` calls a draw, and the certificate still verifies unless a challenge lands on the sink, probability `(1 - 1/N)^k` (0.99988 at `N = 2^24`, `k = 2,000`); honest work per trial is `2N` calls, so one labelling buys about `1.3 x 10^6` draws at `N = 2^24` (figures section 5). Varying any unchallenged node with few descendants does the same; a fixed always-checked set of the last `m` nodes moves the cost to about `m` labels a draw, and only full verification removes it. (b) `W = H(chi) <= target`: the prover screens trials for free and labels only the winner, so the memory work per block is one labelling whatever the difficulty | the paper's theorems lower-bound the cost of a trace that outputs AN accepted certificate (Theorem 7); they say nothing about how many distinct accepted certificates one trace outputs for one `chi`, and Definition 5 has no target. The re-roll is consistent with every theorem in the paper | (a) FAIL, (b) FAIL; the replacement BLOCKED B-T3 | +| O-07 | Grinding the lottery: what the prover can vary per draw, at what cost, once one labelling exists | no lottery rule is adopted. Two candidate rules fail: (a) `W = H('W' || chi || tau) <= target`: after one honest labelling the prover sets the sink label `l'_N` to fresh bytes (the sink turns red), rehashes its Merkle path and draws again, `log2 N + 1` calls a draw, and the certificate still verifies unless a challenge lands on the sink, probability `(1 - 1/N)^k` (0.99988 at `N = 2^24`, `k = 2,000`); honest work per trial is `2N` calls, so one labelling buys about `1.3 x 10^6` draws at `N = 2^24` (figures section 5). Varying any unchallenged node with few descendants does the same; a fixed always-checked set of the last `m` nodes moves the cost to about `m` labels a draw, and only full verification removes it. (b) `W = H(chi) <= target`: the prover screens trials for free and labels only the winner, so the memory work per block is one labelling whatever the difficulty | Executed by B1 (fixture A6, `tools/mhpow/b1/fixtures/attacks-n10-k16.json`, sha256 805035eb..., branch mhpow-b1 e9f94df6a, every root checked by the full verifier): one labelling at N = 2^10, k = 16, the sink red, 26 calls a try, 193 to 200 of 200 tries accepted across 5 labellings (predicted `(1 - 2^-10)^16` = 0.985, so 197); with 64 red, 140 to 152 of 400 (predicted 0.356, so 142). The paper's theorems lower-bound the cost of a trace that outputs AN accepted certificate (Theorem 7), once per trace, not once per certificate; they say nothing about how many distinct accepted certificates one trace outputs for one `chi`, and Definition 5 has no target. The re-roll is consistent with every theorem in the paper | (a) FAIL, (b) FAIL; the replacement BLOCKED B-T3 | | O-08 | Grinding through the template: timestamp inside the window, coinbase extranonce, transaction set, parent choice, the nonce | each is a new `chi`, hence a full new labelling (no label query is shared across `chi`) | per `chi`: Corollary 3, `(lambda/4)(c3 c4 / 2) N^2 / log N` cumulative memory; across many `chi`: O-10 | ANSWERED per trial; the many-trial bound BLOCKED (O-10) | | O-09 | Chosen instance: the prover picks a favourable `chi` | the graph is data-independent and fixed (O-05), so no `chi` changes the graph's structure; the only freedom is which `chi` to label | Corollary 3 fixes `chi` before the oracle; a `chi` chosen after querying the oracle needs a union over the candidates (at most `q`), a loss the paper does not state | BLOCKED B-T4 | | O-10 | Amortisation: one labelling, or one shared state, serving many trials or many templates | none can share labels across `chi` (O-03); the lower bound for producing accepted certificates on `m` distinct inputs is the open part | not in the paper (every statement fixes one `chi`); the natural route is the disjoint union of `m` copies (cumulative pebbling cost adds over components), the extractor run on the union, LUCKYQUERY bounded per copy | BLOCKED B-T5 | From b13a804368b5790e916a6901dc9177b0b5b3685c Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:41:48 +0000 Subject: [PATCH 10/19] D02: fee dependence in TV-04's frame (one BU, the 0.1x to 10x multiples); TV-04's emission reconciled Co-Authored-By: Claude Opus 5.5 --- tools/token-value/d02/README.template.md | 17 ++-- tools/token-value/d02/d02_emission.py | 106 ++++++++++++++++------- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/tools/token-value/d02/README.template.md b/tools/token-value/d02/README.template.md index b8d3f53f9..94d415e00 100644 --- a/tools/token-value/d02/README.template.md +++ b/tools/token-value/d02/README.template.md @@ -15,6 +15,7 @@ Status: NOT RUN. A model, landed as a document and its tests; nothing activates. | `consensus/core/src/unit.rs` (8 and 18 decimals) | blob `6af7040f07b939e71f8930090f01d022c6136e87` | | `site/litepaper.html` in the tree the generator ran on (each quoted sentence is checked present) | sha256 `{{SHA_LITEPAPER}}` | | TV-01's supply spec, `docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json` (read by the generator; section 9) | {{SPEC_STATE}} | +| TV-04's security-budget model, `docs/plans/igneum-2.0-master/token-value/phase0/tv-04/` (its baseline and multiples used in section 6; its emission read in section 9) | {{TV04_STATE}} | ## What D02 asks @@ -35,7 +36,7 @@ The volume names the shape of the longer branch and no number. B is its literal - The split is the consensus split: {{MINER_PCT}} percent of each block's subsidy to the block's producer and {{PROVER_PCT}} percent to the proving escrow (igneum.rs `PROVING_POOL_SHARE_PERCENT`). It is applied to each year's total; the per-block floor moves at most one base unit a block toward the producer, and the signing bonus moves part of a silent block's producer share to the pool without changing the total. - Two views of the same rule. The supply and issuance tables use the node's closed form (`scheduled_supply_at`, per DAA second). The paid model sums one `block_subsidy` per DAA score at mainnet's {{MAIN_BPS}} blocks a second (params.rs `blockrate`, the coinbase's rate), which is what the coinbase pays and what TV-01's spec sums; the two differ by the per-block floors, under one IGN in total, except at the far tail, where the per-block floor reaches zero years before the per-second rate does (the schedules table). Per-block figures are at {{MAIN_BPS}} blocks a second. - No price appears. Every amount is native IGN or base units. -- Fee dependence uses a reference security budget of {{REF_BUDGET_PCT}} percent of the cap a year ({{REF_BUDGET_IGN}} IGN), a stated yardstick and not a cost estimate, scaled by TV-04's revenue multiples ({{MULTIPLES}}). "Fees needed" is the first year the subsidy alone falls under the budget; "fees exceed subsidy" is the first year the subsidy falls under half of it, after which fees must pay more than the subsidy for the budget to hold. Both read the subsidy's decline alone. The fee series is a parameter, never a forecast: `--fee-flat-ign N --fee-growth-bps G` prints the first year the subsidy plus that series falls under each budget. TV-04's own budget replaces the yardstick when it lands (BLOCKED row B2). +- Fee dependence uses TV-04's own frame. TV-04's baseline (one BU) is the current schedule's whole year-1 subsidy as paid, {{BASELINE_IGN}} IGN, and its scenarios hold each coin's purchasing power at a constant multiple of the baseline path ({{MULTIPLES}}; 0.1x is the minus-90-percent case). Holding the year-1 security level of one BU on the path at multiple m takes the baseline divided by m in native IGN a year, the same target for every schedule. "Fees needed" is the first year the subsidy paid alone falls under that; "fees exceed subsidy" is the first year it falls under half of it, after which fees must pay more than the subsidy for the level to hold. Both read the subsidy's decline alone. One BU is TV-04's yardstick, not a required cost: the minimum role costs are TV-04's panel cells (BLOCKED row B2). The fee series is a parameter, never a forecast: `--fee-flat-ign N --fee-growth-bps G` prints the first year the subsidy plus that series falls under each target. - The volume defines no Gini-style cohort measure, so concentration is the share of the cap issued by each horizon and the share issued in years 1 to 2 against years 3 to 20. ## The schedules as code @@ -78,11 +79,11 @@ Meaning: the ratio column is how many coins years 1 to 2 issue for every coin ye Meaning: a miner joining in year 10 sees {{M_LATE10_A}} of the year-1 block subsidy under A, {{M_LATE10_B}} under B and {{M_LATE10_C}} under C; B pays that miner {{M_LATE10_BA}} times what A pays. -## 6. Fee dependence at TV-04's revenue multiples (the subsidy's decline alone) +## 6. Fee dependence at TV-04's multiples (the subsidy's decline alone, the target one BU a year) {{T_FEES}} -Meaning: at the 1x budget, fees must exceed the subsidy from year {{M_EXC1_A}} under A, year {{M_EXC1_B}} under B and year {{M_EXC1_C}} under C, so a longer schedule moves fee dependence later at the cost of a smaller early subsidy. At the 10x budget the order can reverse: fees are first needed in year {{M_NEED10_A}} under A, {{M_NEED10_B}} under B and {{M_NEED10_C}} under C, because a large budget is crossed early by any curve that starts lower. +Meaning: at 1x, fees must exceed the subsidy from year {{M_EXC1_A}} under A, year {{M_EXC1_B}} under B and year {{M_EXC1_C}} under C, because B's and C's first-year subsidy is only {{M_Y1PAID_B}} and {{M_Y1PAID_C}} of the baseline. At 4x the years are {{M_EXC4_A}}, {{M_EXC4_B}} and {{M_EXC4_C}}, and at 10x {{M_EXC10_A}}, {{M_EXC10_B}} and {{M_EXC10_C}}, so a longer schedule moves fee dependence later only where each coin buys more than at launch; at 0.25x every schedule needs fees to exceed the subsidy from year {{M_EXC025_A}}, {{M_EXC025_B}} and {{M_EXC025_C}}. ## 7. The stretch factor (B on time axes x2, x3 and x4, beside A) @@ -96,13 +97,13 @@ The volume gives no factor; this sweep shows how the trade moves with it. Meaning: the litepaper's sentences describe the curve without the {{RAMP_DAYS}}-day ramp; the code, ramp included, issues slightly less in the first years. The words "approached and never reached" hold for every schedule here: each scheduled total is under the cap (table above, last column). -## 9. Reconciliation with TV-01's supply spec +## 9. Reconciliation with TV-01's supply spec and TV-04's emission -The generator reads TV-01's spec from the tree and compares every rule field, the cap, the unit and each profile's year-end supplies, terminal DAA score, terminal supply and cap shortfall, exact integers, against its own paid model of A. Result: {{RECONCILE_VERDICT}}. +The generator reads TV-01's spec and TV-04's `emission.csv` from the tree and compares every rule field, the cap, the unit, each TV-01 profile's year-end supplies, terminal DAA score, terminal supply and cap shortfall, and each of TV-04's yearly emissions, exact integers, against its own paid model of A. Result: {{RECONCILE_VERDICT}}. {{T_RECONCILE}} -Meaning: the schedule this comparison calls A is TV-01's mainnet contract profile to the base unit, so every difference shown for B and C is measured from the compiled mainnet schedule and not from a model of it. +Meaning: the schedule this comparison calls A is TV-01's mainnet contract profile and TV-04's emission to the base unit, so every difference shown for B and C is measured from the compiled mainnet schedule and not from a model of it. ## Commands and checksums @@ -137,10 +138,10 @@ Searches for a crossing year run to year {{SEARCH_YEARS}}; an empty cell means t | row | question | waits on | earliest clock (UK) | |---|---|---|---| | B0 | Which schedule launches: A, B (and at which factor), C, or another same-cap shape. This document does not pick it. | the founder ("pending evidence") after the independent panel reads this | the founder's word | -| B2 | Replace the {{REF_BUDGET_PCT}} percent yardstick with TV-04's role-by-role budget and its revenue multiples' base | TV-04's landing | TV-04's clock | +| B2 | The minimum cost of each role in BU (what the security budget must actually buy), so the fee-dependence years become pass or fail rows | TV-04's panel cells (N-min-hashrate, N-shards-year, N-min-hubs, N-maint-month, K-class) | the panel's word | | B3 | Arrival times and cohort shares under each schedule (delayed entrants as people, not blocks) | TV-03's simulation inputs and a cohort definition | TV-03's clock | -Closed since the first version (09:44 UK): B1, the reconciliation with TV-01's supply spec (section 9); B4, the litepaper's year-five tail-vote sentence, which the site lane rewrote under D01 (TV-01's conflict C01). +Closed since the first version (09:44 UK): B2's first half, the 1 percent yardstick, replaced by TV-04's baseline and multiples (section 6); B1, the reconciliation with TV-01's supply spec (section 9); B4, the litepaper's year-five tail-vote sentence, which the site lane rewrote under D01 (TV-01's conflict C01). ## Registry diff --git a/tools/token-value/d02/d02_emission.py b/tools/token-value/d02/d02_emission.py index 37413b2cc..2a5c04a55 100644 --- a/tools/token-value/d02/d02_emission.py +++ b/tools/token-value/d02/d02_emission.py @@ -44,8 +44,8 @@ CSV_YEARS = 40 B_STRETCH = 2 # the volume's shape, its literal instance: the same curve on a time axis x2 SWEEP_STRETCH = (2, 3, 4) C_HALF_LIFE_MONTHS = 48 # this lane's alternative: a smooth monthly glide, four-year half-life -TV04_MULTIPLES = ((1, 4), (1, 1), (4, 1), (10, 1)) # TV-04's .25x / 1x / 4x / 10x, as exact fractions -REF_BUDGET_BPS_OF_CAP = 100 # the reference security budget: 1 percent of the cap a year (stated, not a cost) +TV04_MULTIPLES = ((1, 10), (1, 4), (1, 1), (4, 1), (10, 1)) # TV-04's 0.1x (minus 90%) / .25x / 1x / 4x / 10x +TV04 = 'docs/plans/igneum-2.0-master/token-value/phase0/tv-04' SEARCH_YEARS = 1_000 @@ -208,18 +208,35 @@ class Table: self._memo[key] = tot * bps return self._memo[key] + def _cum(self, bps): + key = ('cum', bps) + memo = self.__dict__.setdefault('_memo', {}) + if key not in memo: + s = self.s + tot = self._ramp_paid(bps) # paid by the ramp's end + cum = [] + for k, rate in enumerate(self.rates): + a = max(k * s['step'], s['ramp']) + cum.append((a, tot)) # paid by second a + tot += (rate // bps) * bps * ((k + 1) * s['step'] - a) + cum.append((len(self.rates) * s['step'], tot)) + memo[key] = cum + return memo[key] + def paid_at(self, sec, bps): + if sec == 0: + return 0 s = self.s assert sec >= s['ramp'] - tot = self._ramp_paid(bps) - for k, rate in enumerate(self.rates): - a, b = max(k * s['step'], s['ramp']), min((k + 1) * s['step'], sec) - if b <= a: - if k * s['step'] >= sec: - break - continue - tot += (rate // bps) * bps * (b - a) - return tot + k = sec // s['step'] + cum = self._cum(bps) + if k >= len(self.rates): + return cum[-1][1] + a, base = cum[k] + return base + (self.rates[k] // bps) * bps * (sec - a) + + def year_paid(self, y, bps=MAIN_BPS): + return self.paid_at(y * YEAR, bps) - self.paid_at((y - 1) * YEAR, bps) def paid_zero_step(self, bps): for k, rate in enumerate(self.rates): @@ -248,14 +265,25 @@ def first_year(pred): return None +_BASE = {} + + +def baseline(dec): + """TV-04's baseline: the current schedule's whole year-1 subsidy as paid at mainnet's block rate (one BU).""" + if dec not in _BASE: + _BASE[dec] = Table(schedule_current(dec)).paid_at(YEAR, MAIN_BPS) + return _BASE[dec] + + def ref_budget(dec, m): + """Native units a year that hold one BU (the year-1 security level) on a path at constant multiple m.""" num, den = m - return cap_units(dec) * REF_BUDGET_BPS_OF_CAP * num // (10_000 * den) + return baseline(dec) * den // num def mult_label(m): num, den = m - return ('%d' % num if den == 1 else '0.%s' % fixed(num, den, 2).split('.')[1]) + 'x' + return ('%d' % num if den == 1 else fixed(num, den, 2).rstrip('0')) + 'x' def split(x): @@ -294,15 +322,15 @@ def csv_horizons(tables): def csv_fees(tables): - rows = ['key,multiple,reference_budget_base_units_per_year,fees_needed_from_year,fees_exceed_subsidy_from_year,' + rows = ['key,multiple,budget_one_bu_base_units_per_year,fees_needed_from_year,fees_exceed_subsidy_from_year,' + ','.join('fees_required_y%d_base_units' % y for y in HORIZONS)] for t in tables: dec = t.s['decimals'] for m in TV04_MULTIPLES: r = ref_budget(dec, m) - need = first_year(lambda y: t.year_issuance(y) < r) - exceed = first_year(lambda y: 2 * t.year_issuance(y) < r) - req = [max(0, r - t.year_issuance(y)) for y in HORIZONS] + need = first_year(lambda y: t.year_paid(y) < r) + exceed = first_year(lambda y: 2 * t.year_paid(y) < r) + req = [max(0, r - t.year_paid(y)) for y in HORIZONS] rows.append(','.join(str(v) for v in [t.s['key'], mult_label(m), r, need, exceed] + req)) return '\n'.join(rows) + '\n' @@ -348,8 +376,7 @@ def values(tables, sweep): v['RAMP_START'] = str(RAMP_START_PERCENT) v['B_STRETCH'] = str(B_STRETCH) v['C_HALF_LIFE_Y'] = str(C_HALF_LIFE_MONTHS // 12) - v['REF_BUDGET_PCT'] = fixed(REF_BUDGET_BPS_OF_CAP, 100, 0) - v['REF_BUDGET_IGN'] = mign(ref_budget(dec, (1, 1)), dec, 0) + v['BASELINE_IGN'] = ign(baseline(dec), dec, 2) v['CSV_YEARS'] = str(CSV_YEARS) v['SEARCH_YEARS'] = group(str(SEARCH_YEARS)) v['HORIZONS'] = ', '.join(str(h) for h in HORIZONS) @@ -416,11 +443,11 @@ def values(tables, sweep): r = ref_budget(dec, m) row = [mult_label(m), mign(r, dec, 0)] for t in tables: - need = first_year(lambda y: t.year_issuance(y) < r) - exceed = first_year(lambda y: 2 * t.year_issuance(y) < r) + need = first_year(lambda y: t.year_paid(y) < r) + exceed = first_year(lambda y: 2 * t.year_paid(y) < r) row.append('%s / %s' % (need, exceed)) rows.append(row) - v['T_FEES'] = md_table(['TV-04 multiple', 'reference budget a year (IGN)'] + + v['T_FEES'] = md_table(['TV-04 multiple', 'native budget a year that holds one BU (IGN)'] + ['%s: year fees are needed / year fees exceed the subsidy' % t.s['key'] for t in tables], rows) # stretch sweep rows = [] @@ -429,7 +456,7 @@ def values(tables, sweep): r1 = ref_budget(dec, (1, 1)) rows.append([s['key'], mign(t.year_issuance(1), dec)] + [pct(t.supply_at(y * YEAR), capu) for y in (2, 5, 10, 20)] + - [first_year(lambda y: 2 * t.year_issuance(y) < r1)]) + [first_year(lambda y: 2 * t.year_paid(y) < r1)]) v['T_SWEEP'] = md_table(['schedule', 'year 1 subsidy (IGN)', 'issued by year 2', 'by year 5', 'by year 10', 'by year 20', 'fees exceed subsidy at 1x (year)'], rows) # litepaper reconciliation (the litepaper's sentences are quoted inputs; the right-hand columns are computed) @@ -478,10 +505,13 @@ def values(tables, sweep): v['MAIN_BPS'] = str(MAIN_BPS) r1 = ref_budget(dec, (1, 1)) for t in tables: - v['M_EXC1_' + t.s['key']] = str(first_year(lambda y: 2 * t.year_issuance(y) < r1)) - r10 = ref_budget(dec, (10, 1)) - for t in tables: - v['M_NEED10_' + t.s['key']] = str(first_year(lambda y: t.year_issuance(y) < r10)) + v['M_EXC1_' + t.s['key']] = str(first_year(lambda y: 2 * t.year_paid(y) < r1)) + for tag, m in (('10', (10, 1)), ('4', (4, 1)), ('025', (1, 4))): + rm = ref_budget(dec, m) + for t in tables: + v['M_EXC%s_%s' % (tag, t.s['key'])] = str(first_year(lambda y: 2 * t.year_paid(y) < rm)) + v['M_Y1PAID_B'] = pct(B.year_paid(1), baseline(dec), 2) + v['M_Y1PAID_C'] = pct(C.year_paid(1), baseline(dec), 2) v['M_CLIFF_A'] = pct(A.year_issuance(3), A.year_issuance(2), 0) v['M_GLIDE_C'] = pct(C.year_issuance(3), C.year_issuance(2), 1) return v @@ -516,6 +546,17 @@ def spec_rows(): rows.append((prof, 'cap shortfall', sch['cap_shortfall'], str(cap_units(dec) - t.paid_total(bps)))) if sch.get('is_mainnet_contract'): rows.append((prof, 'block rate of the contract profile', str(bps), str(MAIN_BPS))) + tv4 = os.path.join(ROOT, TV04, 'emission.csv') + if os.path.exists(tv4): + t = Table(schedule_current(MAIN_DECIMALS)) + lines = read_bytes(tv4).decode('utf-8').splitlines() + head = lines[0].split(',') + iy, ie = head.index('year'), head.index('emission_base_units') + for ln in lines[1:]: + f = ln.split(',') + y = int(f[iy]) + rows.append(('TV-04 emission.csv (%d blocks/s)' % MAIN_BPS, 'emission in year %d' % y, f[ie], + str(t.year_paid(y)))) return hashlib.sha256(raw).hexdigest(), rows @@ -534,15 +575,20 @@ def render(tables, sweep, out, shas): spec_sha, rows = spec_rows() if spec_sha is None: v['SPEC_STATE'] = 'not in the tree at this run' + v['TV04_STATE'] = 'not read at this run' v['T_RECONCILE'] = '(TV-01\'s supply spec is not in the tree at this run.)' v['RECONCILE_VERDICT'] = 'not run' else: v['SPEC_STATE'] = 'sha256 `%s`' % spec_sha + tv4 = os.path.join(ROOT, TV04) + v['TV04_STATE'] = ', '.join('`%s` sha256 `%s`' % (n, sha256_file(os.path.join(tv4, n))) + for n in ('README.md', 'emission.csv') if os.path.exists(os.path.join(tv4, n))) \ + or 'not in the tree at this run' bad = [r for r in rows if r[2] != r[3]] v['T_RECONCILE'] = md_table(['profile', 'quantity', 'TV-01 supply spec', 'this generator (paid model)', 'agree'], [(a, b, '`%s`' % c, '`%s`' % d, 'yes' if c == d else 'NO') for a, b, c, d in rows]) v['RECONCILE_VERDICT'] = ('all %d rows agree exactly' % len(rows)) if not bad else \ - '%d of %d rows DIFFER (each listed above)' % (len(bad), len(rows)) + '%d of %d rows DIFFER (each listed below)' % (len(bad), len(rows)) v['RECONCILE_N'] = str(len(rows)) def sub(m): k = m.group(1) @@ -672,7 +718,7 @@ def node_csv(): def fee_series(flat_ign, growth_bps): print('fee series (a parameter, not a forecast): %s IGN in year 1, growing %s bps a year' % (flat_ign, growth_bps)) - print('first year the subsidy plus this fee series falls under the reference budget (none = holds through year %d)' + print('first year the subsidy plus this fee series falls under the budget that holds one BU (TV-04's baseline) (none = holds through year %d)' % SEARCH_YEARS) for s in main_schedules(): t = Table(s) @@ -681,7 +727,7 @@ def fee_series(flat_ign, growth_bps): fee = lambda y: f0 * (10_000 + growth_bps) ** (y - 1) // 10_000 ** (y - 1) for m in TV04_MULTIPLES: r = ref_budget(dec, m) - y = first_year(lambda y: t.year_issuance(y) + fee(y) < r) + y = first_year(lambda y: t.year_paid(y) + fee(y) < r) print('%s %s budget %s: %s' % (s['key'], mult_label(m), mign(r, dec, 0), y)) From efa188419c69591d11d2fa2b24f52497238496c9 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:42:45 +0000 Subject: [PATCH 11/19] D02: a quote in the fee-series line Co-Authored-By: Claude Opus 5.5 --- tools/token-value/d02/d02_emission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/token-value/d02/d02_emission.py b/tools/token-value/d02/d02_emission.py index 2a5c04a55..683eaaab7 100644 --- a/tools/token-value/d02/d02_emission.py +++ b/tools/token-value/d02/d02_emission.py @@ -718,7 +718,7 @@ def node_csv(): def fee_series(flat_ign, growth_bps): print('fee series (a parameter, not a forecast): %s IGN in year 1, growing %s bps a year' % (flat_ign, growth_bps)) - print('first year the subsidy plus this fee series falls under the budget that holds one BU (TV-04's baseline) (none = holds through year %d)' + print('first year the subsidy plus this fee series falls under the budget that holds one BU, TV-04 baseline (none = holds through year %d)' % SEARCH_YEARS) for s in main_schedules(): t = Table(s) From 0f79872e0da3be1f9acadee6bae4996fa3c9ccf2 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:44:08 +0000 Subject: [PATCH 12/19] D02: the stretch sweep reads 4x and 10x; B's 1x edge stated Co-Authored-By: Claude Opus 5.5 --- tools/token-value/d02/README.template.md | 2 +- tools/token-value/d02/d02_emission.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/token-value/d02/README.template.md b/tools/token-value/d02/README.template.md index 94d415e00..331606f71 100644 --- a/tools/token-value/d02/README.template.md +++ b/tools/token-value/d02/README.template.md @@ -83,7 +83,7 @@ Meaning: a miner joining in year 10 sees {{M_LATE10_A}} of the year-1 block subs {{T_FEES}} -Meaning: at 1x, fees must exceed the subsidy from year {{M_EXC1_A}} under A, year {{M_EXC1_B}} under B and year {{M_EXC1_C}} under C, because B's and C's first-year subsidy is only {{M_Y1PAID_B}} and {{M_Y1PAID_C}} of the baseline. At 4x the years are {{M_EXC4_A}}, {{M_EXC4_B}} and {{M_EXC4_C}}, and at 10x {{M_EXC10_A}}, {{M_EXC10_B}} and {{M_EXC10_C}}, so a longer schedule moves fee dependence later only where each coin buys more than at launch; at 0.25x every schedule needs fees to exceed the subsidy from year {{M_EXC025_A}}, {{M_EXC025_B}} and {{M_EXC025_C}}. +Meaning: at 1x, fees must exceed the subsidy from year {{M_EXC1_A}} under A, year {{M_EXC1_B}} under B and year {{M_EXC1_C}} under C, because B's and C's first-year subsidy is only {{M_Y1PAID_B}} and {{M_Y1PAID_C}} of the baseline. B is the current curve at half the rate by construction, so at 1x its fees must match its subsidy from the first year; the integer floors put it a few base units under half, which is why the table reads year 1. At 4x the years are {{M_EXC4_A}}, {{M_EXC4_B}} and {{M_EXC4_C}}, and at 10x {{M_EXC10_A}}, {{M_EXC10_B}} and {{M_EXC10_C}}, so a longer schedule moves fee dependence later only where each coin buys more than at launch; at 0.25x every schedule needs fees to exceed the subsidy from year {{M_EXC025_A}}, {{M_EXC025_B}} and {{M_EXC025_C}}. ## 7. The stretch factor (B on time axes x2, x3 and x4, beside A) diff --git a/tools/token-value/d02/d02_emission.py b/tools/token-value/d02/d02_emission.py index 683eaaab7..15627a676 100644 --- a/tools/token-value/d02/d02_emission.py +++ b/tools/token-value/d02/d02_emission.py @@ -453,12 +453,11 @@ def values(tables, sweep): rows = [] for t in [A] + sweep: s = t.s - r1 = ref_budget(dec, (1, 1)) rows.append([s['key'], mign(t.year_issuance(1), dec)] + [pct(t.supply_at(y * YEAR), capu) for y in (2, 5, 10, 20)] + - [first_year(lambda y: 2 * t.year_paid(y) < r1)]) + [first_year(lambda y: 2 * t.year_paid(y) < ref_budget(dec, m)) for m in ((4, 1), (10, 1))]) v['T_SWEEP'] = md_table(['schedule', 'year 1 subsidy (IGN)', 'issued by year 2', 'by year 5', 'by year 10', - 'by year 20', 'fees exceed subsidy at 1x (year)'], rows) + 'by year 20', 'fees exceed subsidy at 4x (year)', 'at 10x (year)'], rows) # litepaper reconciliation (the litepaper's sentences are quoted inputs; the right-hand columns are computed) curve12 = sum(A.rates[k] * A.s['step'] for k in range(6)) lp_text = read_bytes(os.path.join(ROOT, LITEPAPER)).decode('utf-8') From b70b27b8f48eeddd14b1bbe0a7572ce8091eb0d5 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:33:34 +0000 Subject: [PATCH 13/19] TV-02 recorded: the two independent supply replays (A on the node issuance code, B from the rules in words) EQUAL to the integer on devnet-4, mainnet and the TV-01 spec, NOT RUN in progress until the independent panel reads it; the cell native:tv-02 carried in the batch (map_cell_requested), the lane's proposed batch recorded as tools/ci/batches/tv-02-20261009-01.json Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-harness-map.md | 11 +++- docs/plans/igneum-2.0-test-registry.json | 68 ++++++++++++++--------- tools/ci/batches/tv-02-20261009-01.json | 45 +++++++++++++++ tools/ci/test-map.json | 14 ++++- 4 files changed, 108 insertions(+), 30 deletions(-) create mode 100644 tools/ci/batches/tv-02-20261009-01.json diff --git a/docs/plans/igneum-2.0-test-harness-map.md b/docs/plans/igneum-2.0-test-harness-map.md index 510b14e8d..ca97a537d 100644 --- a/docs/plans/igneum-2.0-test-harness-map.md +++ b/docs/plans/igneum-2.0-test-harness-map.md @@ -466,6 +466,14 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - ADV-05 Validate physical and complete-board costs: partial: the complete-board terms (PSU, VRM, cooling, host, controller) and the placed core's energies; the memory and SRAM figures claimed - ADV-08 Independently challenge the best-cost envelope: the worst credible design retained as the specialist side a with its capital gate; X6 re-runs it blind on held-out pairs +### native:tv-02 + +- Command: `the two independent supply replays of docs/plans/igneum-2.0-master/token-value/phase0/tv-02: tools/token-value/tv-02/run-a.sh (Rust on the node issuance code, build-5: build, genesis, straight devnet4|mainnet|devnet, reorg fixtures) and run-b.sh (Python from the rules in words, build-6: selftest, straight, reorg, the TV-01 spec through replay-spec/tv01_adapter.py), then compare-all.sh on build-5 (rules-v0.1-genesis-rule, rules-tv01-spec); each run under its pid file in the out dir` +- Box class: two build boxes (CPU only; A with the node code, B without) +- Fixtures: F0 +- Cases: + - TV-02 Reproduce complete supply accounting: partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it + ## Automated cases with no harness in the matrix (NOT RUN, the reason) - GOV-02 Approve thresholds before results: the approval is recorded in the registry's approval field; the automated half (thresholds frozen before any run_status) is the gate rule landing by 21:00 @@ -609,7 +617,6 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - R2-F14-R01 Public build has no default arbitrary remote execution and a documented least-privilege boundary.: R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map - R2-F14-R02 Automatic updates off remains off for urgent manifests until explicit action.: R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map - R2-F14-R03 A compromised fleet/update signing key cannot silently acquire wallet access or activate a consensus change.: R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map -- TV-02 Reproduce complete supply accounting: TV-02 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + measurement); a supplemental layer, never counted as independent evidence; not yet named in the map - TV-05 Strongest surviving specialist: TV-05 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Hardware reviewer + economics); a supplemental layer, never counted as independent evidence; not yet named in the map - TV-06 Every fee and payment reconciles: TV-06 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Economics + application); a supplemental layer, never counted as independent evidence; not yet named in the map - TV-07 Ownership-critical engineering closure: TV-07 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + independent security); a supplemental layer, never counted as independent evidence; not yet named in the map @@ -651,4 +658,4 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover ## Count -213 automated cases: 91 mapped to a cell, 180 NOT RUN with a reason. +213 automated cases: 92 mapped to a cell, 179 NOT RUN with a reason. diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 3e15765c3..2163764a6 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -17751,42 +17751,53 @@ "threshold_status": "PROPOSED - FREEZE BEFORE TEST", "run_status": "NOT RUN", "master_status": "NOT RUN", - "updated": "2026-10-09T08:45:39.119Z", + "updated": "2026-10-09T09:33:14.912Z", "evidence_record": { - "reason": "TV-02 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + measurement); a supplemental layer, never counted as independent evidence; not yet named in the map", - "at": "2026-10-09T08:45:39.119Z", - "method": "static", "requirement_id": "TV-02", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "native", + "cell": "native:tv-02", + "manifest_sha": "426c7c85", + "run_id": "tv-02-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/tv-02/README.md; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0.1-genesis-rule.log; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0-litepaper.log; build-1:/srv/artefacts/token-value/tv-02/build-5/a-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-6/b-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-tv01-spec.log; build-1:/srv/artefacts/token-value/tv-02/build-6/b-rules-tv01-spec-*.csv", + "in_progress": true, + "coverage": "partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it", "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" - } + "commit": "426c7c85 (master, the first TV-02 landing) and the spec-run landing after it (branch tv-02-supply-replay)", + "lockfile": "tools/token-value/tv-02/replay-node/Cargo.lock", + "binary": "tv02-replay-node sha256 ef3af79157947584... (the run), 25ff78695bd9d972... (rebuilt from af2c23bc, outputs byte-identical)", + "network_object": "the compiled objects of igneum-node bf60948a read by A (devnet4_params, MAINNET_PARAMS, DEVNET_PARAMS); no chain state read or written", + "activation": "none (Phase 0 lands documents and tests only)", + "profile_hashes": "igneum-node bf60948a (emission.rs, igneum.rs, coinbase.rs, params.rs, window.rs, difficulty.rs byte-identical in release-2.0.2-node a284380b); rules-and-gates.json 10ce3073...; B rules v0 67707b09..., v0.1 d72d5578...; replay_spec.py acd68e1b...; the TV-01 supply-spec.json at 9cd09130 sha256 3ffdd308...; replay_spec.py on the spec c07aba10..." + }, + "claim_impact": "none: no served figure moves; the supply ever issued on the 2.0 objects is 3,963,038,999.61 IGN under the 4,000,000,000 cap, with nothing after the terminal block", + "reviewer": "", + "at": "2026-10-09T09:33:14.912Z", + "note": "two supply replays, A (Rust on the node's issuance code at bf60948a, build-5) and B (Python from the rules in words, build-6), no shared code: with rule set v0.1 (the words plus the genesis rule, window.rs 176-179) EQUAL to the integer, byte-identical CSVs, at every transition's before/at/after, the terminal and one step past, on the devnet-4 (1 bps, 18 decimals), mainnet (10 bps, 18) and devnet (8) objects, and on two hand-written reorg fixtures with the no-undo ledger refused; with the words alone (v0) DIFFER at genesis (A 0, B 3168808781000000000 on devnet-4), a one-block shift with the terminal total unchanged (3963038999610200483289816000 base units on devnet-4); on the TV-01 supply spec (9cd09130) EQUAL on devnet-4 and mainnet and both fixtures, A's terminal rows equal to the spec's stated terminal supplies; paid/burned/locked accounting, the mainnet genesis DAA score (C09), DAG reds and independent signoff are open rows; NOT RUN until the independent panel reads it | recorded by the CI steward from docs/plans/igneum-2.0-master/token-value/phase0/tv-02/registry-batch-tv-02.json (sha256 1cae5953d438ef96..., the TV-02 lane, 10:25 UK); the cell native:tv-02 carried in map_cell_requested" }, "evidence_records": { - "record": { - "reason": "TV-02 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + measurement); a supplemental layer, never counted as independent evidence; not yet named in the map", - "at": "2026-10-09T08:45:39.119Z", - "method": "static", + "native:tv-02": { "requirement_id": "TV-02", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "native", + "cell": "native:tv-02", + "manifest_sha": "426c7c85", + "run_id": "tv-02-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/tv-02/README.md; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0.1-genesis-rule.log; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0-litepaper.log; build-1:/srv/artefacts/token-value/tv-02/build-5/a-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-6/b-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-tv01-spec.log; build-1:/srv/artefacts/token-value/tv-02/build-6/b-rules-tv01-spec-*.csv", + "in_progress": true, + "coverage": "partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it", "release_identity": { - "commit": "", - "lockfile": "", - "binary": "", - "network_object": "", - "activation": "", - "profile_hashes": "" + "commit": "426c7c85 (master, the first TV-02 landing) and the spec-run landing after it (branch tv-02-supply-replay)", + "lockfile": "tools/token-value/tv-02/replay-node/Cargo.lock", + "binary": "tv02-replay-node sha256 ef3af79157947584... (the run), 25ff78695bd9d972... (rebuilt from af2c23bc, outputs byte-identical)", + "network_object": "the compiled objects of igneum-node bf60948a read by A (devnet4_params, MAINNET_PARAMS, DEVNET_PARAMS); no chain state read or written", + "activation": "none (Phase 0 lands documents and tests only)", + "profile_hashes": "igneum-node bf60948a (emission.rs, igneum.rs, coinbase.rs, params.rs, window.rs, difficulty.rs byte-identical in release-2.0.2-node a284380b); rules-and-gates.json 10ce3073...; B rules v0 67707b09..., v0.1 d72d5578...; replay_spec.py acd68e1b...; the TV-01 supply-spec.json at 9cd09130 sha256 3ffdd308...; replay_spec.py on the spec c07aba10..." }, - "in_progress": false + "claim_impact": "none: no served figure moves; the supply ever issued on the 2.0 objects is 3,963,038,999.61 IGN under the 4,000,000,000 cap, with nothing after the terminal block", + "reviewer": "", + "at": "2026-10-09T09:33:14.912Z", + "note": "two supply replays, A (Rust on the node's issuance code at bf60948a, build-5) and B (Python from the rules in words, build-6), no shared code: with rule set v0.1 (the words plus the genesis rule, window.rs 176-179) EQUAL to the integer, byte-identical CSVs, at every transition's before/at/after, the terminal and one step past, on the devnet-4 (1 bps, 18 decimals), mainnet (10 bps, 18) and devnet (8) objects, and on two hand-written reorg fixtures with the no-undo ledger refused; with the words alone (v0) DIFFER at genesis (A 0, B 3168808781000000000 on devnet-4), a one-block shift with the terminal total unchanged (3963038999610200483289816000 base units on devnet-4); on the TV-01 supply spec (9cd09130) EQUAL on devnet-4 and mainnet and both fixtures, A's terminal rows equal to the spec's stated terminal supplies; paid/burned/locked accounting, the mainnet genesis DAA score (C09), DAG reds and independent signoff are open rows; NOT RUN until the independent panel reads it | recorded by the CI steward from docs/plans/igneum-2.0-master/token-value/phase0/tv-02/registry-batch-tv-02.json (sha256 1cae5953d438ef96..., the TV-02 lane, 10:25 UK); the cell native:tv-02 carried in map_cell_requested" } }, "approvals": { @@ -17794,7 +17805,10 @@ "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "run_id": "tv-02-20261009-01", + "evidence_path": "docs/plans/igneum-2.0-master/token-value/phase0/tv-02/README.md; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0.1-genesis-rule.log; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0-litepaper.log; build-1:/srv/artefacts/token-value/tv-02/build-5/a-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-6/b-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-tv01-spec.log; build-1:/srv/artefacts/token-value/tv-02/build-6/b-rules-tv01-spec-*.csv", + "in_progress_since": "2026-10-09T09:33:14.912Z" }, { "id": "TV-03", diff --git a/tools/ci/batches/tv-02-20261009-01.json b/tools/ci/batches/tv-02-20261009-01.json new file mode 100644 index 000000000..3c8290477 --- /dev/null +++ b/tools/ci/batches/tv-02-20261009-01.json @@ -0,0 +1,45 @@ +{ + "run_id": "tv-02-20261009-01", + "manifest_sha": "426c7c85", + "method": "native", + "evidence_dir": "build-1:/srv/artefacts/token-value/tv-02", + "release_identity": { + "commit": "426c7c85 (master, the first TV-02 landing) and the spec-run landing after it (branch tv-02-supply-replay)", + "lockfile": "tools/token-value/tv-02/replay-node/Cargo.lock", + "binary": "tv02-replay-node sha256 ef3af79157947584... (the run), 25ff78695bd9d972... (rebuilt from af2c23bc, outputs byte-identical)", + "network_object": "the compiled objects of igneum-node bf60948a read by A (devnet4_params, MAINNET_PARAMS, DEVNET_PARAMS); no chain state read or written", + "activation": "none (Phase 0 lands documents and tests only)", + "profile_hashes": "igneum-node bf60948a (emission.rs, igneum.rs, coinbase.rs, params.rs, window.rs, difficulty.rs byte-identical in release-2.0.2-node a284380b); rules-and-gates.json 10ce3073...; B rules v0 67707b09..., v0.1 d72d5578...; replay_spec.py acd68e1b...; the TV-01 supply-spec.json at 9cd09130 sha256 3ffdd308...; replay_spec.py on the spec c07aba10..." + }, + "claim_impact": "none: no served figure moves; the supply ever issued on the 2.0 objects is 3,963,038,999.61 IGN under the 4,000,000,000 cap, with nothing after the terminal block", + "reviewer": "", + "note": "recorded by the CI steward from docs/plans/igneum-2.0-master/token-value/phase0/tv-02/registry-batch-tv-02.json (sha256 1cae5953d438ef96..., the TV-02 lane, 10:25 UK); the cell native:tv-02 carried in map_cell_requested", + "cells": [ + { + "cell": "native:tv-02", + "cases": [ + "TV-02" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "native", + "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/tv-02/README.md; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0.1-genesis-rule.log; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-v0-litepaper.log; build-1:/srv/artefacts/token-value/tv-02/build-5/a-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-6/b-*.csv; build-1:/srv/artefacts/token-value/tv-02/build-5/compare-rules-tv01-spec.log; build-1:/srv/artefacts/token-value/tv-02/build-6/b-rules-tv01-spec-*.csv", + "note": "two supply replays, A (Rust on the node's issuance code at bf60948a, build-5) and B (Python from the rules in words, build-6), no shared code: with rule set v0.1 (the words plus the genesis rule, window.rs 176-179) EQUAL to the integer, byte-identical CSVs, at every transition's before/at/after, the terminal and one step past, on the devnet-4 (1 bps, 18 decimals), mainnet (10 bps, 18) and devnet (8) objects, and on two hand-written reorg fixtures with the no-undo ledger refused; with the words alone (v0) DIFFER at genesis (A 0, B 3168808781000000000 on devnet-4), a one-block shift with the terminal total unchanged (3963038999610200483289816000 base units on devnet-4); on the TV-01 supply spec (9cd09130) EQUAL on devnet-4 and mainnet and both fixtures, A's terminal rows equal to the spec's stated terminal supplies; paid/burned/locked accounting, the mainnet genesis DAA score (C09), DAG reds and independent signoff are open rows; NOT RUN until the independent panel reads it" + } + ], + "map_cell_requested": { + "native:tv-02": { + "command": "the two independent supply replays of docs/plans/igneum-2.0-master/token-value/phase0/tv-02: tools/token-value/tv-02/run-a.sh (Rust on the node issuance code, build-5: build, genesis, straight devnet4|mainnet|devnet, reorg fixtures) and run-b.sh (Python from the rules in words, build-6: selftest, straight, reorg, the TV-01 spec through replay-spec/tv01_adapter.py), then compare-all.sh on build-5 (rules-v0.1-genesis-rule, rules-tv01-spec); each run under its pid file in the out dir", + "box_class": "two build boxes (CPU only; A with the node code, B without)", + "fixtures": [ + "F0" + ], + "cases": [ + "TV-02" + ], + "coverage": { + "TV-02": "partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it" + } + } + } +} diff --git a/tools/ci/test-map.json b/tools/ci/test-map.json index 937e6872b..7c3c756bf 100644 --- a/tools/ci/test-map.json +++ b/tools/ci/test-map.json @@ -800,6 +800,19 @@ "ADV-05": "partial: the complete-board terms (PSU, VRM, cooling, host, controller) and the placed core's energies; the memory and SRAM figures claimed", "ADV-08": "the worst credible design retained as the specialist side a with its capital gate; X6 re-runs it blind on held-out pairs" } + }, + "native:tv-02": { + "command": "the two independent supply replays of docs/plans/igneum-2.0-master/token-value/phase0/tv-02: tools/token-value/tv-02/run-a.sh (Rust on the node issuance code, build-5: build, genesis, straight devnet4|mainnet|devnet, reorg fixtures) and run-b.sh (Python from the rules in words, build-6: selftest, straight, reorg, the TV-01 spec through replay-spec/tv01_adapter.py), then compare-all.sh on build-5 (rules-v0.1-genesis-rule, rules-tv01-spec); each run under its pid file in the out dir", + "box_class": "two build boxes (CPU only; A with the node code, B without)", + "fixtures": [ + "F0" + ], + "cases": [ + "TV-02" + ], + "coverage": { + "TV-02": "partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it" + } } }, "not_run": { @@ -944,7 +957,6 @@ "R2-F14-R01": "R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map", "R2-F14-R02": "R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map", "R2-F14-R03": "R2-F14 (P1, the external review): the regression's harness is the owner lane's (app lane, relay lane); not yet named in the map", - "TV-02": "TV-02 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + measurement); a supplemental layer, never counted as independent evidence; not yet named in the map", "TV-05": "TV-05 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Hardware reviewer + economics); a supplemental layer, never counted as independent evidence; not yet named in the map", "TV-06": "TV-06 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Economics + application); a supplemental layer, never counted as independent evidence; not yet named in the map", "TV-07": "TV-07 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Protocol + independent security); a supplemental layer, never counted as independent evidence; not yet named in the map", From 2ca9029f926d51ba4cbdce667cd1d8b3441262a0 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:44:41 +0000 Subject: [PATCH 14/19] Counter ASIC 3.0 status: TV-04's second cut and D02's second version, the build-1 guards, the founder's blocks on the explorer, the 10:35 per-box line, X7's chip side (s) and kit, X5's first row, the reset's fault and the re-roll of 30 boxes, the PCs mining, the mini's protoc, main's Track B pivot and the founder's clocks, B1's attack fixtures, B3's oracle on B1, B2's obligations landed Co-Authored-By: Claude Fable 5.1 --- docs/plans/counter-asic-3-status.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/plans/counter-asic-3-status.md b/docs/plans/counter-asic-3-status.md index 8c96da5e9..79155f63c 100644 --- a/docs/plans/counter-asic-3-status.md +++ b/docs/plans/counter-asic-3-status.md @@ -890,6 +890,10 @@ MAIN'S WITHDRAWAL OF THE CLOCK ORDER (10:1x UK, once): its own fault, its quoted THE 2.0.3 APP LINE (the shipper, 10:25 UK): release-2.0.3 on the build mirror at 3bae31e0 (the push gate GREEN, 61 checks in 110 s): 3e5eabc5 the version bump (rule 15, the first commit); 33caf9a5 the known-failed test (tools/ci/ota-mac-helper-check.sh: the Mac update helper decided on the engine's process alone with no launch seam, a dead or silent new engine reading ok; the behavioural half over a fake bundle pair with the launch stubbed to a process never answering api/state); 4561b43b the fix (the helper polls app.url and api/state for the new version for 120 s, launches again, else restores the previous bundle and reads it the same way; every path logged); 6ce7ffd2 the installer's relay-agent step (every install, silent ones included, runs the bundle's own install-agent.ps1 as the signed-in user, never elevated, on a machine holding the project's relay bundle; the Setup carries no bundle or secret, F14); e977ee75 the packaged dial targets (hub-1's pre-2.0 213.173.107.74:16516 out; the three lp hubs plus build-1's two hand nodes); 3bae31e0 the node pin and the release manifest's node block at release-2.0.3-node-k7 27f54124 (seven suites green on build-8, the digest be5f4068 unchanged; standing unless a red lands on build-7 by 12:30); the Windows helper shipping as it is (its 0.3.21 return sequence already waits on api/state); the cutter's 2.0.3 package order (node 27f54124, app 3bae31e0, the record 203-27f54124-3bae31e0, running on build-1 since 10:25, about 10:50, no push); every 2.0.3 entry only on its rule-33 PASS block to the moving tip. THE 2.0.3 MAC DMG (the shipper's block with a default; the coordinator's word at 10:3x): the mini lacks protoc (the node's build.rs compiles .proto files through tonic-build; Rust 1.99.0 and the Xcode tools present; no Homebrew; sudo needing the founder's password; a macOS target not cross-buildable on build-1, no darwin target or osxcross; this MacBook's Homebrew protoc linked against Homebrew's dylibs); the one way with no hand and no sudo a third-party download onto the founder's machine (the official protobuf release zip for macOS arm64 into ~/.local/protoc, about 5 MB, about ten minutes, after which the mini builds every later DMG): his word, asked through main; the default taken: the 2.0.3 DMG builds on this Mac under the build lock exactly as 2.0.2's did (the one DMG, nothing else), from node 27f54124 and app 3bae31e0, after the 27f54124 canary PASS and the cutter's record; the DMG to the mini for its rule-33 canary (the datadir aside and kept; the agent-kill and update legs; the reboot leg NOT RUN "founder's hold"); the Mac entry on PASS with min_supported 2.0.2 after the hubs' upgrade; the source trees onto the mini over its build-1 key, no build there; Node for the DMG build's UI tests not needed on the mini (the tests run on this MacBook, a test not a build). X7 (main, 10:2x UK; dispatched by the coordinator to the hash lane with the kit lane and to the adversary lane, by 12:30): from the plan's memory bridge r = 1 / (f/s + (1-f)/c), the two numbers nobody has measured: (1) f, the fraction of the GPU's energy on the frozen v6 object that is unavoidable DRAM traffic, on the 5090 and the 4090 at the knee and at stock, by a pure random-read microbenchmark over the 4 GiB dataset at v6's read width and count (no ALU beyond the address) paired with the full v6 kernel in the same session, wall power where a pod allows and board power beside it, f = E_read / E_v6, the same for the X1 candidate; (2) s, the chip's memory-path energy per byte for the same traffic at GDDR7 on a chip board (the DRAM-board witness's memory term), at HBM3, and with near-memory compute, from the adversary lane's chip model with its sources named, WITNESS; (3) the reading: r at the measured f and s for c free (r = s/f) and for c at the X0 shadow ratio, same node, with the yardstick line (what f a read-dominated design would need at each s to reach 1.5x and 1.25x); one line to main at 12:30 as it stands. TRACK B's FIRST RESULTS. B1 (the cryptography lane, 10:26 UK; build-6:/srv/builds/mhpow-b1/): the papers via the archive route, none by bypass (Blocki-Smearsoll eprint 2025/1456 as archived 2025-12-31, 46 pp, sha256 13c3646e (matching B3's copy); Dinur-Nadler 2017/497 as archived 2026-05-09, 30 pp, d2fd7774535dd322; ABH17 DRSample 2017/443 as archived 2025-12-10, f8e08d361118120c (the paper citing DRSample without defining it; its Algorithm 1 the edge rule); MTP 1.2 Biryukov-Khovratovich arXiv 1606.03588v2, 5dca4aef485f480c); implementing Sec 3.2 (the framework: labels, Merkle, challenges c_i = H(chi, i, tau) mod N, the 4-step verifier), App. C (the Merkle reveal and check), Sec 2.2 (the labeling game, local consistency), the soundness chain Theorem 4, Theorem 6, Theorem 7, Corollaries 1 and 2, Fact 8, Corollary 3 (DRSample), the attacks Sec 7.1 (Attack 1) and DN17's; the first BLOCKED row: with ABH17's proven constant (Theorem 3.1: e at least 2.43e-4 N/log N) Corollary 2's k = 2 N ln2 lambda / e is about 5,700 lambda log N, so at lambda 256 and N 2^20 k about 2.9e7 exceeds N: the proven regime has no practical parameter today, the paper stating no concrete N, lambda or k; the encoding agreed with B2 (BLAKE2b-256, the tags L/M/C/G, u64 LE, raw leaves, LSB-at-root, the graph from a public seed); the first known-answer fixtures at 10:26 (the suite 17 of 17 OK first, every verifier check refusing its known-failed case by name: wrong label, wrong parent label, wrong path, wrong challenge, skipped parent, duplicated parent position, wrong label tag, wrong Merkle tag, wrong chi, container; kat-n04 at k 8 with every label and the proof inline (json sha256 9f85b22ae54785e0); kat-n08/12/16/20 at k 64 (n20: the proof 129,133 bytes, proof.bin sha256 a49367d9c80f0855), each accepted by the verifier from bytes; k 64 a fixture size, not a security claim; the honest rows n 12/16/20/22, the attack fixtures and a determinism repeat running. B3 (the GPU feasibility lane): the pods fk-b3-5090 (Vast 54994203, EPYC 7K62) and fk-b3-4090 (Vast 54994221) at 10:06 UK; the first byte-identical label set at 10:1x on the 5090: the CUDA kernels (k1 one thread per instance, k2 two cooperating lanes per instance; SOA and AOS layouts) reproducing the spec-path CPU reference's labels, every Merkle node, the root and the proof bytes for 64 of 64, 64 of 64 and 37 of 37 instances (n = 10 and 12), the spec verifier accepting every GPU proof; the oracle B3's own provisional encoding "B3P1" (SHA-256, lambda 256, le64 integers, the paper's literal LSB-first Merkle order, ABH17 DRSample with SHA-256 coins) until B1's fixtures, every timing row "against B3P1, not yet against B1"; the first timing rows on the 5090 (stock, board power with the 5.8 W idle not subtracted, src 2079d0d8ce7eef96, k = 64, every row's oracle IDENTICAL): 32 MiB per instance, the card filled at 476 instances: 210 M labels/s with one thread per instance, 344 M with the two-lane cooperative kernel, 0.50 and 0.36 microjoules per label at a mean 105 and 123 W board (a 575 W card); 128 MiB, 119 instances: 52 M and 86 M labels/s, 2.0 and 1.2 microjoules per label, about 105 W; per instance one label 2.27 / 1.38 microseconds on the GPU against 0.127 on one sha_ni core of the pod's EPYC 7K62: the card cannot fill itself because each instance is one sequential hash chain and memory caps the instances in flight (476, then 119, then about 30 at 512 MiB), so the whole 5090 equals about 27 to 44 CPU cores at 32 MiB and 7 to 11 at 128 MiB and falls further at 512 MiB: at these sizes the function is principally CPU-friendly, which the plan's section 6 B3 says to reject; the commitment and proof cheap on the GPU (0.05 s per batch of 476); the 4090 rows, the 512 MiB rows, the ladder and the CPU rows by about 11:15. B4 (the theory lane, the draft on branch mhpow-b4, NOT RUN): (1) R1 (2025/1456) proves cumulative memory, not joules: any accepted MTP/DRSample prover has cmc at least (lambda/4)(e d/2) bit-rounds (Thm 6, Thm 7, Cor 1 to 3), the error C(q,2) 2^-l + n_in q^2 2^-l + N 2^-l + t 2^-l/2 + q 2^-l; its DRSample constants c1, c2 with no numeric value in the paper (BLOCKED B4-B03); its Lemma 3 covering only q up to 2^31.5 queries at 256-bit labels (520-bit labels needed for q = 2^64); (2) the composed claim three additive terms: hashing c_H (2(1-beta)N - 1), provable now and additive across trials (B4 Lemma A, new); transfers e_x L_x(m), OPEN (R2's red-blue reduction rebuilt for certificates and DRSample minus beta N nodes), zero above a cache of C N/log2 N labels (186 MiB x C for a 4 GiB state of 1 KiB labels: the full-SRAM case killing the transfer term by a legal pebbling, R2 sec 5.4); retention p_ret tau_H cmc with t at least d = c2 N rounds forced (B4 Lemma B, new); (3) the losses: the generic route (R2 Thm 4.5) certifying at most 0.151 of an honest prover's energy at log2 N = 22 even with c1 c2 = 1 (a 6.6x floor); the red-blue route's published constants losing at least 256/(1-rho) (341x at rho 0.25): no 1.5x certificate reachable from the published constants (a 1.5x G_upper/L needing the GPU at or under 0.23 of the honest specialist on the generic route, 0.0044 on the red-blue), kept as a negative control for Track B as published, BOUND; (4) R4 encoded state: R1's theorem surviving (the state counted in bits, extraction by incompressibility; R4 excluding iMHFs in the parallel model), NOT surviving any data dependence or a structured or chunk-absorbing label function (BLOCKED B4-B07 to B2 and B1); the obligations O-B2-1..5 and O-B1-1..5 named; main's word: B2's re-roll finding the first obligation (the lottery draw must cost a fresh labelling or a provable fraction of one). B6 (the node lane, 10:23 UK; docs/analysis/mhpow/b6/README.md on both box mirrors' master at 1ab735be9, gate GREEN 94 checks): the symbols (q, d, L, Delta, T_label from the B1 fixture, BLOCKED to 12:00; h = 32; bps 1/10 by params.rs); the proof bytes per block B_p = h + q(L + Delta L + d h) against P2P_MAX_MESSAGE_SIZE 256 MiB (connection_handler.rs 47), the header's about 222 + 32 x parents bytes and the per-second uplink at up to 136 peers; cold verification T_v = q(1 + Delta) d / r_64 + q(1 + Delta) L / r_L + q T_label with r_64 measured on build-7 (EPYC 9454, one core, openssl speed): 6.8 x 10^6 64-byte hashes a second (147 ns a Merkle node; a d = 20 path 2.9 microseconds; a q = 100, Delta = 3 proof about 1.2 ms of path hashing before labels) against the block time 1,000 / 100 ms; the minimum node BLOCKED (no file defining it); invalid-proof amplification against the PoW strike guard (2 strikes an hour, pow_guard.rs), ledger N6 (flow_context.rs), the class v5 state wait and the fd class closed this morning (keepalive 10 s / 20 s, 128 inbound); the pool's share check today one bound hash (pool/src/verify.rs 52-63, the verify_permits semaphore, PPLNS) and what a proof-carrying share adds; propagation, the epoch wall (POW_EPOCH_BLOCKS 3,600 / LEAD 600, V5_STATE_WAIT 300 s, IBD_BATCH_SIZE 99) and the record store's new class; the BLOCKED list with owners and clocks; every verdict NOT RUN; the 13:00 landing adding the B1 values if by 12:00. The node lane's queue passes on build-7 and build-3 red on their first passes for a box-layout cause (build-7 lacking the proto-cuda packs the miner suite reads; build-3 lacking the parent's igneum-pow crate), both placed from build-8 at 10:21; the fresh-sync RSS control on build-2 (5d53a591, no public listener, the three hubs only) 17.2 GB at DAA 22,940 eleven minutes in, climbing about a gigabyte a minute, against the swarmed seed's 34 GB at EVM 4,840 under 93 inbound island peers: the two growth paths (the executor's own, and the inbound traffic held in IBD) both real; the 12:00 line separating them with 27f54124's curve. THE STEWARD's R15 SUITE (f60a6c8a, 10:17 UK): ten rows R15-01 to R15-10 from packages.json, every one NOT RUN, the gate verbatim, the X and B lanes as cross-references, the suite note carrying the WITNESS-or-BOUND rule and the no-raw-hash-rate rule; the recorder taking the map cell inside the batch (dd87e55f, 10:20 UK: map_cell_requested adding an absent cell, refusing to change an existing cell's cases); X0 and X5 landed by the landing hand (f73434e61c267d13, 10:26 UK; thirty-nine landings). TV-02's FINAL ROWS (229ec9506, 10:25 UK): on the TV-01 spec as landed A and B agree to the integer at every row on devnet-4 (66 transitions, the terminal height 4,102,488,000, 3,963,038,999.610200483289816 IGN) and mainnet (63 transitions, 39,131,424,000, ...467816224), plus the 8-decimal devnet on rule set v0.1, both reorg fixtures equal, no differing row; the only divergence the words-only reading at genesis; the 30-day launch ramp holding back 36,960,999.88 IGN and the rounding at each halving 0.51 IGN of the 36,961,000.39 gap, a third calculation with bc matching; found along the way: the devnet-4 genesis block storing its subsidy field in the old 8-decimal layout (read at 18 decimals as about 1.35e38 base units, never paid, a 2.0.3 test by the node lane); the 18-decimal schedule issuing 10.74 IGN more than the 8-decimal; the node's mainnet object at 10 bps while the litepaper says 1 rising to 10; open: R8 (paid, burned, locked, the EVM ledger's C06 to C08), R10 (the mainnet genesis DAA score, C09), the panel's read; one lane wrote both A and B, their independence in code and method only, said for the panel; the batch to the steward (1cae5953). +TV-04's SECOND CUT (0cd1f422, 10:29 UK, NOT RUN, run tv-04-20261009-02 superseding -01): on build-9 the model reconciling 27 of 27 checks against TV-01's spec (3ffdd308), 10 of 10 green, all six known-bad inputs caught, two generations byte-identical; on the mainnet schedule (18 decimals, 10 bps, per-block rounding) the miners' (80 percent) and provers' (20 percent) subsidy falling to 25.96 percent of year 1 by year 5, 6.49 by year 10, 0.20 by year 20; validators and maintenance nothing from the protocol at any horizon; the measured unit costs (the fleet lane's rates, electricity inside): the 5090 on Vast USD 0.0048 per MH/s per hour and 0.0121 per proof record; the 4090 on Vast 0.0066 and 0.0125; the 4090 on RunPod 0.0129 and 0.0247; the hub box USD 0.74 an hour (the devnet's three hubs USD 19,460.52 a year, a configuration not a minimum); the committed build server USD 5,358.24 a year; the coverage as budget_BU x V / cost_USD with V* per role and per 1,000 MH/s or 1,000,000 records required; no miner or prover cell closing until the required capacity is named; validators and maintenance failing at any V until D03 names a payer; BLOCKED by exact name: the minimum network hashrate the security model requires, the proof records per year at the minimum workload, the minimum hub count (the founder's), committed maintenance, V (the panel's), the viable or collapse declarations, C04 (the founder's); C10, C01 and C12 resolved; the lane's one flag, once: dividing a V* by the year-1 coin count would give a USD-per-coin cost figure near the never-published "electricity-backed value"; the document never writes it and is not exported (the coordinator's ruling stands with that note). D02's SECOND VERSION (28b2c4e4, 10:39 UK): the generator reading TV-01's spec and reproducing it exactly (all 32 rows: the rules, the cap, the unit, the year-end supplies for years 1 to 100, the terminal DAA score and supply and the cap shortfall, for mainnet at 10 bps and devnet-4 at 1 bps); a paid model at mainnet's rate: under A the per-block subsidy reaching zero after year 124, under B after year 244, under C after year 235; B1 and B4 closed; the batch tv-d02-20261009-02 superseding -01; open B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). THE BUILD-1 GUARDS (the build-server lane, 10:30 UK; master 7792531d, infra/build-server/guard, the three scripts' sha256 524770b76c23ee7b): igneum-queue-reader.service, caddy, cron, atd, rsyslog under Restart=always with OOMScoreAdjust minus 1000, the three sync units at plus 500, Forgejo's container restart=always; igneum-memory-guard.timer every minute (a second fresh sync below within-ten stopped by its unit and written as a refusal to /srv/queue/faults.log and alerts.log; free memory under 15 GB an ALERT line relayed to main from the Mac); igneum-edge-check.timer every five minutes (workers.html, git.igneum.network, /light through the edge; an empty read a FAULT, a failed caddy started again); the memory rule on master in docs/ops/build-queue.md 02752de3; the guard's band read the restarting seed as a second sync and stopped the hand at 10:32:54 (a slip once; the band 100 blocks with a two-minute grace now). THE FOUNDER'S BLOCKS ON THE EXPLORER (the build-server lane, 10:36 UK): build-1's seed within ten at 10:32:01 UK (EVM 27,818 against lp-04's 27,808; the clean sync from 10:10 took 21 minutes, RSS peaking at 33 GB), reopened on 0.0.0.0:26631 at 10:32:08, the explorer indexer and the observer-dn4 reader on it from 10:32:11, caught up at 10:35:10 ("indexed 27950 of tip 27950, behind 0"): explorer.igneum.network and /live showing the hubs' chain from 10:35 UK; the hand on loopback since 10:34:30 (EVM 4,302 at 10:35), the readers back to it at its within-ten (about 10:55), the light-reader after. THE 10:35 PER-BOX LINE (read 10:33:29 UK by pid): build-1 (load 7.8, mem 10 percent, 115 GB free; the OOM kills by pid listed): the seed, the pow mixer fuzz, the hands observer-node and node1, the indexer and three observer.mjs, a class-v5 lease test; build-2 (load 17.8): the node lane's 27f54124 RSS measurement node and the site gate's chromium, the X5 dram pid file; build-3 (load 4.3): no process above 5 percent, the consensus-fuzz pid file (the driver on the Mac); build-4 (load 27.7): three OpenROAD runs and kepler-formal, the X5 hyb25 pid file and the floorplan lease; build-5 (load 0.00): nothing running behind the X5 hyb50 pid file: FAULT, the adversary lane (relaunched under its pid file at 10:4x); build-6 (load 1.2): the X5 hyb75, the HEAL fuzz (pass 10) and B1 pid files, no process above 5 percent at the read; build-7 (load 11.2): the node lane's igneum-exec suite (the flows pass 10), the winvm qemu (33 minutes), the dn4-roll node, the X5 sram pid file; build-8 (load 0.28): the dn4-roll node only behind the X5 recomp pid file: FAULT, the adversary lane (its row done, the box released); X1's census ended; build-9 (load 0.8): the pow suite compiling (pass 13), the X1, X4 and B2 pid files. X7's CHIP SIDE (the adversary lane, 85db138c1, 10:31 UK; tools/1p5x/x7/s.py on build-4; every row WITNESS; the batch adversary-20261009-x7 NOT RUN): s for the frozen object's traffic (256 random reads per hash over 4 GiB, every read opening a row; the record's HBM2 breakdown scaled, Micron's GDDR7 per-bit figure, the controller's dynamic share approximate), per read at the 32-byte sector the card fetches / the 64-byte item: GDDR7 on a chip board 2.1 nJ (1.8 to 2.5) / 3.3 nJ, 66 pJ per byte fetched; HBM3 through an interposer 1.2 nJ (1.1 to 1.8) / 1.8 nJ, 38 pJ per byte; near-memory compute (the hash unit beside the bank, the activation still paid, no interposer) 0.70 nJ (0.54 to 1.08) / 0.77 nJ, 22 pJ per byte; per hash 540, 311 and 178 nJ at the sector; against the card's measured 8.7 nJ per dependent read at the knee (10.9 at stock): s = 4.1 (3.5 to 4.8) on GDDR7, 7.2 on HBM3, 12.5 near-memory at the sector (2.7, 4.8 and 11.3 at the item); the bridge reading: f at least s/1.5 cannot be met on any design (it would need f over 2.7 on GDDR7); even f = 1 gives r = 4.1x at c free; at f = 0.5 and c = 2.35 (X0's board compute ratio) r reads 3.0x GDDR7, 3.5x HBM3, 4.0x near-memory; a more read-dominated honest workload moves r toward s, not toward 1, because the card's memory path (8.7 nJ per read all-in against its device's own 2.0) is its least efficient part against a chip; the only honest-side lever on s a GPU whose random read costs less (the Apple tier's LPDDR at about 6 nJ per read at the wall); the reading at 12:30 with the hash lane's measured f. X5's FIRST PER-BOX ROW (the adversary lane, 10:33 UK; 5526dc8d3, rows/build-8-recomp.md): build-8, the recomputation design (the placed 8-lane 18-family core at 40 percent, on the x8 mixer's op mix): the placed row reproduced to the digit on the box (9.36 pJ per lane-op on the class v4 draw, 227,069 cells, 0 wns) and the mixer mix 7.92 pJ per lane-op at ASAP7 (7.18 to 9.61), 5.54 at N5: a recompute op 15 percent cheaper than a shadow op (no shuffles, no mad), the recomputation design improving from 0.41x to 0.48x on pair A and 0.43x on pair B: never credible, closing recomputation as an opponent at every stored fraction; the five other placements routed or in simulation (build-2, 5, 6, 7 routed; the hybrid 0.25 design on build-4 since 10:20, build-3's pool held by the census and the family gate). X7's KIT (the kit lane, 10:33 UK): /srv/artefacts/packs/packs-x7-20261009T093204Z.zip sha256 267c6e2f0b20224a22494a80c5237d1a66839849e441037f35bc6db46845bc7f (1,099,641 B, 68 files, from branch x1-kit 96ed94b21): the X1 ds30 pair (the control 0x2a1d6caab4c24564, the candidate 0x34d0b421b17fe803) and their read-only twins by a textual pass (in both igneum_hash and igneum_hash_bound: the 32 loads per iteration with their full address chains kept, every other base statement and the whole shadow block dropped, vectors removed, "readonly": true; both twins compiling through the emulation shim), the Linux CUDA worker f5f3846c; one fact: the NVRTC worker benches igneum_hash_bound from kernel_bound.cu, so a kernel.cu-only transform would have left the benched hash untouched; the control in the kit X1's x1-ctrl export at 4 GiB (the same program as the signing object, a different export), not hl-v6-all, no recut (the coordinator's word). The hash lane's X7 bundle (build-1:/srv/artefacts/1p5x/x7-bundle.tgz bc1c485a: the ABBA run script, 250 x 2^24, nvidia-smi 1 Hz, a 15-second idle read, -lgc attempted and reported, wall power BLOCKED on a pod); fk-x7-4090 (Vast 54997089, the 450 W default, driver 580.95.05, idle 16 W) handed at 10:38, the ABBA run from 09:38:22Z under /root/x7/pids/run-x7.pid, the first f on the 4090 about 10:50; the 5090's first three hosts failing the gate (two with another tenant on the card, one with a 400 W cap against the 575 W default), the fourth try running; the default: a capped card taken and named in the row (f a ratio of two runs on the same card in the same state), the handover line by 11:00 or the physical reason. +THE RESET's FAULT AND THE RE-ROLL (the fleet lane, 10:33 UK, once with the default, taken): on the reset universe of 98 boxes (54 + 40 + three hubs + lp-43; the tracker's 101 including three non-reset rigs): 39 within ten, 12 syncing with the height rising, 15 syncing slower, 20 alive but islanded or stuck, 12 dead; the dead: ten nodes killed by their container's OOM killer mid-sync (cgroup oom_kill counters 1 to 2; limits 18, 20 and 31 GB on lc-3070-01, ln-node-03/09, lp-4090-03/08/17/22/23/24/30; the logs stopping mid-line between 09:42 and 10:27 UK), the fleet-scale form of build-1's 62 and 85 GB fresh syncs (the canary box lp-4090-36 with a 123 GB limit synced from genesis in 1,041 s); dn3-q04 of a full disk (1 MB free, a StorageFull panic); lp-4090-07 of a RocksDB lock-file race at its restart (124 GB limit); the islanded 20 (dn3-j1/p02/pool-b/q05/relay/x1, lc-3090-01, lp-4090-01/11/12/19/20/27/28/40/41/42, lp-48-06, w-relay, w-target) reading synced=true at EVM 5,2xx to 5,6xx or stuck at 9,987 with two to four peers: inbound island peers reaching them during their sync (the --addpeer roll leaving the listener open, the class the build-server lane closed on build-1 with --listen=127.0.0.1); lp-4090-27 banning lp-05 itself ("misbehaving peer: 72 PoW cache strikes within an hour (limit 2)"), a 2.0.2 ban-rule item for the node lane. The re-roll at 10:50 UK on 30 boxes (w-relay and w-target the HEAL lane's heal harness, out): from the mini's datadir snapshot (5.06 GB tgz on build-1, sha-checked, pushed from build-1 eight wide as lp-06 was) with connect-only to the three hubs and no inbound during the sync, the same sha everywhere, dn3-q04's old asides removed first, the tracker counting them in, done about 11:30 UK; the alternative (a plain restart on the partial datadirs) repeating the OOM on the 18 to 31 GB boxes. The 27f54124 canary passed its sync line (genesis to within ten of lp-04's chain in 1,041 s, 4 peers, EVM 27,763 against the feed's 27,753), its mining and shard phases running, the verdict about 10:52. The ghost sweep ended at 10:28: all eight hidden Vast instances destroyed by id and read back gone, each one's result dirs on build-1 with the sha equal. The tracker 10:32: 41 of 101. THE PCs MINING (the relay lane, from the apps' own intake uploads at 10:35 UK, no agent answering): PC 1 the RTX 5080 worker at 60.5 MH/s wall (46.6 averaged over 340 s since its restart at 10:29), 72 accepted and 0 rejected in that window, the last at 10:35:08 UK (template DAA 26,873); PC 2 now mining too (its node past the IBD wall after 10:01): the RTX 5060 Ti worker at 28.3 MH/s wall, 70 accepted, 6 rejected, 3 fee over 650 s since 10:24, the last at 10:35:31 UK (DAA 25,411); neither at the cut (their templates at DAA 25k to 27k; the cut at about 50,400), the worker restarts at 10:24 and 10:29 template-change restarts back within the 180 s watchdog; the 5090 workers' streams not in the intake's latest chunk. THE MINI's PROTOC (the shipper, 10:34:12 UK; the founder's own word taken through main's session): ~/.local/protoc/bin/protoc on the mini answering "libprotoc 36.2" (sha256 765ccb18be73e565); the build script ~/mini-build-203.sh staged (PROTOC and ~/.local/protoc/bin on the build's PATH only, the app tree at release-2.0.3 3bae31e0, the node tree vendor/igneum-node-203 at 27f54124, the served prover pair beside it); the build under ~/mini-build.pid beside the mini's mining (nice 19, four jobs of twelve cores, the miner not paused) the moment the 27f54124 canary PASS and the cutter's record are in; then the mini's rule-33 canary with the reboot leg NOT RUN on the hold, the Mac entry on PASS with min_supported 2.0.2 after the hubs' upgrade; the mini synced at DAA 52,815, 5 peers, mining. +MAIN'S PIVOT OF TRACK B (10:4x UK; relayed): on Track B's first results (B1: no practical parameter in the proven regime; B3: CPU-friendly at 32 to 512 MiB; B4: no 1.5x certificate from the published constants) the track pivots from reproducing the paper to building our own construction, the reproduction kept as the control: (1) B4 writes the requirements a construction must meet to be worth a proof (the lottery draw bound to a fresh labelling or a provable fraction, B2's finding; an instance shape filling a GPU by memory traffic rather than instance count, B3's finding: the label function's work per byte moved must fall, the dataset per instance must exceed any SRAM, the honest path bandwidth-bound on GDDR7; a certificate whose losses stay under 2x, the generic 0.151 and the red-blue 341x named as what to beat; the full-SRAM and near-memory opponents inside the bound); (2) B1 and B3 propose two candidate constructions against them, one each (a wide-label, low-arithmetic DRSample variant with a bandwidth-bound label function; a fresh-state variant of the current class v6 read pattern with a compact certificate), each with its CPU reference, verifier and a first GPU row, labelled research; (3) X7's f and s feed both; (4) the steward records the reproduction's three findings as BOUND and NOT RUN rows under R15-05 to R15-07. THE FOUNDER's CLOCKS (10:4x UK; every lane told): the three checkpoints inside the next 30 to 60 minutes: X7's f and s by 11:20 (the pods handed the minute they pass, ten minutes of runs; the adversary lane's s from the model it holds; the memory-route verdict r = s/f at the measured numbers, same-memory and HBM, in the same line); B4's requirements by 11:15 (one page); the two candidate constructions with their CPU reference, verifier and first GPU row by 11:45 (B1 candidate 1, B3 candidate 2; the label function and the instance shape the only changes to the reproduced control); X6's blind packs sealed by 11:30 and the blind rows by 12:15 on rented 5090 and 4090 (the AMD and Intel cells NOT RUN); the witness: the opponent sweep on each candidate's traces by 12:30 on the boxes, the already-routed placements reused with the candidate's traffic (no new routing), WITNESS, the first candidate's row the moment it exists; one line to main at 11:20, 11:45 and 12:30 as things stand; anything unreachable named with its physical reason. B1's ATTACK FIXTURES (10:38 UK, N 2^10, k 16, deterministic, attacks-n10-k16.json sha256 805035ebfc8d2f34, two runs identical): Dinur-Nadler first: A1 replay across chi (DN17 4.1) 0 of 50 accepted, REFUSED; A2 an unopened challenged block on a constant array 0 of 50 in both variants, REFUSED (check_2b, check_3); A3 control-block steering (DN17 4.3/5, the MTP-Argon2d break) steering gain 0 after 1,000 grinds per control block, REFUSED BY CONSTRUCTION (DRSample's edges fixed a priori), its red-node fallback accepted 191 of 400 against (1 minus 1/t)^k 0.44; A4 self-similarity (DN17 8) 0 of 200 labels reproduced, the saving refused; the paper's own: A5 Attack 1 with a greedy depth-reducing set accepted 6 of 400 (beta 0.22, the analytic 0.018) and 26 of 400 (beta 0.15, 0.072), as BS25 Sec 7.1 states; A6 LuckyQuery regrind: ONE labelling yielding 193 to 200 accepted roots in 200 tries at 26 oracle calls per try with one red sink: FINDING F-4, a lottery over tau not bound to the labelling cost (B2's O-07); k from BS25 Cor. 2 with ABH17's proven constant 2.9e7 at n 20 (F-3); the greedy Attack 1 floor k 100 to 160 for 2^-40; the honest rows n 12 to 24 (CPython, wall time): n 20 prover 3.48 s, the 96N-byte state model (RSS 356 MB), the proof 129,133 B, 3,968 verifier calls; n 24 67 s, RSS 5.4 GB. B3's ORACLE NOW B1's (the GPU feasibility lane, 10:3x UK): B1's working reference on build-6 (params.py d47b8ff5, drsample.py 4169a5fc, mtp.py c0feed31; BLAKE2b-256, tags L/M/C/G, rejection-sampled DRSample, container B1MTPDR1); B3's C port (cpu_ref_b1) reproducing all five B1 known-answer fixtures byte for byte (chi, the graph parents, the labels, tau, the proof bytes, the .proof.bin files); the CUDA kernel for that encoding (b3_gpu_b1) matching on the RTX 4090 (the labels, every Merkle node, the root and the proof container identical for every checked instance, instance 0 equal to B1's own fixture digests at n 8, 12, 16, every proof accepted; the known-failed case (DRSample's long edges deleted on the GPU) MISMATCH, 0 of 96 proofs accepted, test_known_failed_b1 PASS); one finding: in B1's encoding the whole 105-byte label message is ONE BLAKE2b block, so no lane split of a label exists (the SHA-256 reading had two blocks and the two-lane kernel cut the per-label time 1.6x), the per-label critical path one compression, about 1.7 microseconds on one 4090 thread; the B1 rows on the 4090 and the 5090, the B3P1 rows a labelled control. B2's OBLIGATIONS TABLE LANDED (81ee229e4, 10:3x UK; README sha256 d458f217, figures.txt 27bb414c from b2_figures.py 7b8664ea on build-9; the batch POW-05/POW-06 NOT RUN): the encoding re-cut to B1's pins; sixteen obligations: ANSWERED from the paper for reuse across template, trial, epoch, day, era, network and class object (O-01 to O-04, O-15, O-16), challenge grinding (O-06, Lemma 4, k = 2 ln2 lambda log N / c3) and partial evaluation (O-11, Theorem 7, Lemma 5, Corollary 2), precomputation from the epoch-seed lead or the day key gaining nothing; FAIL for two lottery rules (O-07): W over the root re-rolling by a red sink for log2 N + 1 calls a draw (pass probability 0.99988 at N = 2^24, k = 2,000, about 1.3 million draws per labelling), W over chi alone screened for free: as the paper stands an MTP certificate adds memory work per block, never per lottery trial, and cannot move the 1.5x ratio until B-T3 is answered; BLOCKED to B4: B-T1 graph sampling failure, B-T2 DRSample's c3, c4 (the certificate 19.5 MiB at c3 = 1, 194.9 MiB at 0.1, lambda 256, N = 2^24), B-T3 the lottery, B-T4 adaptive chi, B-T5 multi-instance, B-T6 lambda (Lemma 3 at lambda 256 only for q up to 2^31.5), B-T7 role bytes, B-T8 memory-time to energy; BLOCKED to the node lane: B-N1 the live day rule (bind.rs timestamp day against spec 1.12 DAA day) and the verifier's recomputation, B-N2 the block interval and stale fraction (binding the template capping N by N x t_seq at most rho x 1 s, pushing the instance toward SRAM size, the B5 question), B-N3 the state root bytes; the lane's stamp slip said once. + A SHARED-DEVNET FACT FROM THE FLEET (not this lane's, with the shipper and the infra lane): the Hetzner live seed 188.245.5.161:26611 is still on the old override object (digest eada4bda) 1 h 40 min after the 0.3.20 sweep (the fleet never touches Hetzner nodes, so it was outside the sweep); the 0.3.21 wipe canary c22-1 took five digest-mismatch rejects from it; an app with the packaged peers is refused at the seed and syncs through node1 and the hub only, a fresh joiner with only the seed cannot join, the 14 voters and the hub are unaffected; the owner puts the floor file ov16-floor-900000.json (sha 294f1f80) and the c4459193 pin on it. 0.3.21's STAGING (the node lane): the order dry-merges onto 55768f88 with nothing moving to 0.3.22; the late-join fix is 52e96c94 (70e4601e rebased onto 55768f88, exec suite 33 green with both new tests); f067f7c1, b0444f51 and 437f0438 merge clean in order; 2e32d5f6's one conflict (DST_ADDRESS beside pool-finish's DST_BINDING in consensus/core/src/finality.rs) kept both; the live-file digest eada4bda after each (every switch at never); the staging waits on the shipper's sweep-end word; the re-pin held. PC 2 DOWN AGAIN (main, 16:5x UK): the founder takes PC 2 down for cable work (PC 1 back but his desk); both PCs out of the sweep's waves, each updates on its poller on return; no PC job to PC 1; the Windows G1 completed before the outage, nothing reruns. 0.3.21's SECOND GATE LINE on 55768f88 (sha256 279b1b690e854fc9): the ten-minute mixed-version gate beside the 5899f603 pair, 13:37:40Z to 13:47:52Z, SUMMARY PASS (one digest b0afb2ee on five nodes; 223 new and 381 old blocks accepted by the old hub, 0 rejected; counts equal at 319, 486 and 604 through both clean joins and the restart step at 13:45:22Z; no panic); the node lane's two lines on 0.3.21's first candidate complete, in plan 6.9 on ca3-v4-node; the fleet's set on it (the bare-child 12 GB line, the wipe, the kept read, the cases) is the fleet's. 0.3.21's FIRST GATE LINE on 55768f88 (sha256 279b1b690e854fc9, the string read back; pairing igneum-pow 8c728ca3 at byte 5): the digest gate 13:35:41Z to 13:37:19Z SUMMARY PASS (a89be8a7 on both binaries with the peers; db9a85f9 refused, no peer; the live file's eada4bda unmoved); the ten-minute mixed-version gate from 13:37:40Z, line about 13:50Z. The 0.3.21 order as the shipper sent it: 55768f88; f067f7c1 and 70e4601e; b0444f51; 6eb21fc9; db28d331; then the re-pin from 8bdcbdd8 on the coordinator's word; suites between, the digest read after every one; the mirror's release-0.3.20-node back at the pin c4459193, release-0.3.21-node open at 55768f88. THE LATE-JOIN COMMIT (N9's second half, the node lane): 70e4601e on the box mirror as branch proof-hold-fix, from c4459193, two files (igneum/exec/src/proving.rs, protocol/flows/src/v10/proving.rs); the gap was the fetch side on the joiner (the served record ran the native check against the joiner's trailing exec state before anything was stored, the check refused it, the proof was never held, the body rule read "not held" for 20 s and failed the IBD); the fix holds the proof by hash before the checks (the pool entry still needs them) and the serve side says when it holds fewer than asked; the exec suite 32 passed at 13:26Z with the known-failed shape first, the flows check green 13:28Z, igneumd on build-1 at the 0321 worktree path built 13:32Z, sha256 17649eeb2f7d1290, string read back; with the testnet lane (the resume form, B alone); it joins the 0.3.21 staging as its own commit. THE WIPE CANARY ON c19-1, c4459193 (sha 45be9b02d1b002f5, string read back): FORM END rc 0 at 13:50:53Z. Wipe synced 13:35:50Z (57 minutes, inside the 98-minute class); mining 13:36:00Z to 13:47:07Z, 66 mined, 66 accepted, 0 rejected, isSynced true at the tip throughout; the hub holds 41 of its blocks in its last 700 with 0 rejects (13:47:09Z); the restart on its kept datadir at 13:47:15Z: the old process stopped at once (the new process's first lock line seven seconds after the marker; the watchdog held nothing, the b7cc37e7 fault closed), synced again at 13:48:39Z after 84 s, 109 templates read with max 3,432 ms and 0 timeouts; the kept read on pool-1's 0.3.17 copy on the same pod passed at 13:38Z (the rewrite line once, a clean second start). The pin's set on c4459193: the digest gate PASS, the mixed-version gate PASS, the wipe canary PASS, the kept read PASS, the restart PASS, the 12 GB line proves and verifies (paid is a race, not a gate); CASES END from c20-1 (about 14:50Z) is the last pin line. THE INTEROP FACT stands from the void run: the 5899f603 hub accepted 235 object-byte-5 blocks from the 8097d600 node with 0 rejected, one digest on all five nodes on the live sixteen-field file. The gates: the digest test and the kaspa-pow vector test (the amended devnet epoch-0 id 1a4230699a6b9c60 must equal, c120d7963abdcd96 must differ, the v3 control unchanged) on the box; the mixed-version Devnet 2 gate (the amended 0.3.20 node beside a 5899f603 node for ten minutes on the live file without the v4 fields) after the Mac build; the fresh-join canary the 0.3.20 cut's | | Main's rulings (7 October, morning) | no generator change to v4 on the live devnet; the record's null is the window model with numbers, sent by the hash lane to the attack-pass lane so AP-F8-1 re-gates against it; a fault beyond the model (a low-entropy source at site 15) stops at the coordinator with the two options priced (a 0.3.19 class amendment before the flip, or the flip held at the floor), nothing shipping without the founder's word; the tighter tail, an acceptance bound on the hot-set share, is a CLASS V5 item (sent to the v5 lane a6410f3b8abefb762 with the 64-seed census as its gate; the bound's number follows from the model) | From 45e09729ae8d834089c18ebb0c84f13db5538e34 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:45:31 +0000 Subject: [PATCH 15/19] D02: fee dependence in TV-04's frame, TV-04 emission reconciled (52 rows exact); rows move with the README (batch -03 supersedes -02) Co-Authored-By: Claude Opus 5.5 --- .../token-value/phase0/d02/README.md | 68 ++++++++++++------- .../phase0/d02/d02-fee-dependence.csv | 47 +++++++------ .../phase0/d02/d02-manifest.sha256 | 10 +-- .../phase0/d02/d02-tv01-reconcile.csv | 20 ++++++ .../phase0/d02/evidence/box-generate.log | 12 ++-- docs/plans/igneum-2.0-test-registry.json | 48 ++++++------- tools/ci/batches/tv-d02-20261009-03.json | 26 +++++++ 7 files changed, 152 insertions(+), 79 deletions(-) create mode 100644 tools/ci/batches/tv-d02-20261009-03.json diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md b/docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md index 4a368df19..bbb40fa06 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md +++ b/docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md @@ -15,6 +15,7 @@ Status: NOT RUN. A model, landed as a document and its tests; nothing activates. | `consensus/core/src/unit.rs` (8 and 18 decimals) | blob `6af7040f07b939e71f8930090f01d022c6136e87` | | `site/litepaper.html` in the tree the generator ran on (each quoted sentence is checked present) | sha256 `aec583e6e868eb2d3aa8474df3f8892eeebba8a98c887a019ea86bd2efc2f786` | | TV-01's supply spec, `docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json` (read by the generator; section 9) | sha256 `3ffdd3084aff06d963df6c326cda88719d576f07d9cbfb56079de1a8b40c4403` | +| TV-04's security-budget model, `docs/plans/igneum-2.0-master/token-value/phase0/tv-04/` (its baseline and multiples used in section 6; its emission read in section 9) | `README.md` sha256 `7fb02bcdab201470a152b09cfdff158639e70afd01fa2727c66c1c60c00ed03d`, `emission.csv` sha256 `29230149e2b030bbdb3c89fc6c3405f4b4ed248658ac4c2b4162a48849098b78` | ## What D02 asks @@ -35,7 +36,7 @@ The volume names the shape of the longer branch and no number. B is its literal - The split is the consensus split: 80 percent of each block's subsidy to the block's producer and 20 percent to the proving escrow (igneum.rs `PROVING_POOL_SHARE_PERCENT`). It is applied to each year's total; the per-block floor moves at most one base unit a block toward the producer, and the signing bonus moves part of a silent block's producer share to the pool without changing the total. - Two views of the same rule. The supply and issuance tables use the node's closed form (`scheduled_supply_at`, per DAA second). The paid model sums one `block_subsidy` per DAA score at mainnet's 10 blocks a second (params.rs `blockrate`, the coinbase's rate), which is what the coinbase pays and what TV-01's spec sums; the two differ by the per-block floors, under one IGN in total, except at the far tail, where the per-block floor reaches zero years before the per-second rate does (the schedules table). Per-block figures are at 10 blocks a second. - No price appears. Every amount is native IGN or base units. -- Fee dependence uses a reference security budget of 1 percent of the cap a year (40M IGN), a stated yardstick and not a cost estimate, scaled by TV-04's revenue multiples (0.25x / 1x / 4x / 10x). "Fees needed" is the first year the subsidy alone falls under the budget; "fees exceed subsidy" is the first year the subsidy falls under half of it, after which fees must pay more than the subsidy for the budget to hold. Both read the subsidy's decline alone. The fee series is a parameter, never a forecast: `--fee-flat-ign N --fee-growth-bps G` prints the first year the subsidy plus that series falls under each budget. TV-04's own budget replaces the yardstick when it lands (BLOCKED row B2). +- Fee dependence uses TV-04's own frame. TV-04's baseline (one BU) is the current schedule's whole year-1 subsidy as paid, 963,038,999.99 IGN, and its scenarios hold each coin's purchasing power at a constant multiple of the baseline path (0.1x / 0.25x / 1x / 4x / 10x; 0.1x is the minus-90-percent case). Holding the year-1 security level of one BU on the path at multiple m takes the baseline divided by m in native IGN a year, the same target for every schedule. "Fees needed" is the first year the subsidy paid alone falls under that; "fees exceed subsidy" is the first year it falls under half of it, after which fees must pay more than the subsidy for the level to hold. Both read the subsidy's decline alone. One BU is TV-04's yardstick, not a required cost: the minimum role costs are TV-04's panel cells (BLOCKED row B2). The fee series is a parameter, never a forecast: `--fee-flat-ign N --fee-growth-bps G` prints the first year the subsidy plus that series falls under each target. - The volume defines no Gini-style cohort measure, so concentration is the share of the cap issued by each horizon and the share issued in years 1 to 2 against years 3 to 20. ## The schedules as code @@ -133,27 +134,28 @@ Meaning: the ratio column is how many coins years 1 to 2 issue for every coin ye Meaning: a miner joining in year 10 sees 6.3% of the year-1 block subsidy under A, 25.0% under B and 21.0% under C; B pays that miner 2.0 times what A pays. -## 6. Fee dependence at TV-04's revenue multiples (the subsidy's decline alone) +## 6. Fee dependence at TV-04's multiples (the subsidy's decline alone, the target one BU a year) -| TV-04 multiple | reference budget a year (IGN) | A: year fees are needed / year fees exceed the subsidy | B: year fees are needed / year fees exceed the subsidy | C: year fees are needed / year fees exceed the subsidy | +| TV-04 multiple | native budget a year that holds one BU (IGN) | A: year fees are needed / year fees exceed the subsidy | B: year fees are needed / year fees exceed the subsidy | C: year fees are needed / year fees exceed the subsidy | |---|---|---|---|---| -| 0.25x | 10M | 15 / 17 | 25 / 29 | 25 / 29 | -| 1x | 40M | 11 / 13 | 17 / 21 | 17 / 21 | -| 4x | 160M | 7 / 9 | 9 / 13 | 9 / 13 | -| 10x | 400M | 5 / 7 | 5 / 9 | 4 / 8 | +| 0.1x | 9,630M | 1 / 1 | 1 / 1 | 1 / 1 | +| 0.25x | 3,852M | 1 / 1 | 1 / 1 | 1 / 1 | +| 1x | 963M | 3 / 5 | 1 / 1 | 1 / 3 | +| 4x | 241M | 7 / 9 | 9 / 13 | 7 / 11 | +| 10x | 96M | 9 / 11 | 13 / 17 | 12 / 16 | -Meaning: at the 1x budget, fees must exceed the subsidy from year 13 under A, year 21 under B and year 21 under C, so a longer schedule moves fee dependence later at the cost of a smaller early subsidy. At the 10x budget the order can reverse: fees are first needed in year 5 under A, 5 under B and 4 under C, because a large budget is crossed early by any curve that starts lower. +Meaning: at 1x, fees must exceed the subsidy from year 5 under A, year 1 under B and year 3 under C, because B's and C's first-year subsidy is only 50.00% and 63.44% of the baseline. B is the current curve at half the rate by construction, so at 1x its fees must match its subsidy from the first year; the integer floors put it a few base units under half, which is why the table reads year 1. At 4x the years are 9, 13 and 11, and at 10x 11, 17 and 16, so a longer schedule moves fee dependence later only where each coin buys more than at launch; at 0.25x every schedule needs fees to exceed the subsidy from year 1, 1 and 1. ## 7. The stretch factor (B on time axes x2, x3 and x4, beside A) The volume gives no factor; this sweep shows how the trade moves with it. -| schedule | year 1 subsidy (IGN) | issued by year 2 | by year 5 | by year 10 | by year 20 | fees exceed subsidy at 1x (year) | -|---|---|---|---|---|---|---| -| A | 963.0M | 49.08% | 80.33% | 95.95% | 98.98% | 13 | -| B | 481.5M | 24.54% | 55.79% | 80.79% | 96.41% | 21 | -| B3 | 321.0M | 16.36% | 41.36% | 66.36% | 89.28% | 31 | -| B4 | 240.8M | 12.27% | 31.02% | 56.02% | 81.02% | 33 | +| schedule | year 1 subsidy (IGN) | issued by year 2 | by year 5 | by year 10 | by year 20 | fees exceed subsidy at 4x (year) | at 10x (year) | +|---|---|---|---|---|---|---|---| +| A | 963.0M | 49.08% | 80.33% | 95.95% | 98.98% | 9 | 11 | +| B | 481.5M | 24.54% | 55.79% | 80.79% | 96.41% | 13 | 17 | +| B3 | 321.0M | 16.36% | 41.36% | 66.36% | 89.28% | 13 | 19 | +| B4 | 240.8M | 12.27% | 31.02% | 56.02% | 81.02% | 17 | 25 | ## 8. The litepaper against the code @@ -166,9 +168,9 @@ The volume gives no factor; this sweep shows how the trade moves with it. Meaning: the litepaper's sentences describe the curve without the 30-day ramp; the code, ramp included, issues slightly less in the first years. The words "approached and never reached" hold for every schedule here: each scheduled total is under the cap (table above, last column). -## 9. Reconciliation with TV-01's supply spec +## 9. Reconciliation with TV-01's supply spec and TV-04's emission -The generator reads TV-01's spec from the tree and compares every rule field, the cap, the unit and each profile's year-end supplies, terminal DAA score, terminal supply and cap shortfall, exact integers, against its own paid model of A. Result: all 32 rows agree exactly. +The generator reads TV-01's spec and TV-04's `emission.csv` from the tree and compares every rule field, the cap, the unit, each TV-01 profile's year-end supplies, terminal DAA score, terminal supply and cap shortfall, and each of TV-04's yearly emissions, exact integers, against its own paid model of A. Result: all 52 rows agree exactly. | profile | quantity | TV-01 supply spec | this generator (paid model) | agree | |---|---|---|---|---| @@ -204,8 +206,28 @@ The generator reads TV-01's spec from the tree and compares every rule field, th | devnet-4 (1 block/s) | terminal DAA score (first unpaid) | `4102488000` | `4102488000` | yes | | devnet-4 (1 block/s) | terminal supply | `3963038999610200483289816000` | `3963038999610200483289816000` | yes | | devnet-4 (1 block/s) | cap shortfall | `36961000389799516710184000` | `36961000389799516710184000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 1 | `963038999991632485488480000` | `963038999991632485488480000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 2 | `999999999872856000000000000` | `999999999872856000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 3 | `499999999936428000000000000` | `499999999936428000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 4 | `499999999936428000000000000` | `499999999936428000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 5 | `249999999968214000000000000` | `249999999968214000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 6 | `249999999968214000000000000` | `249999999968214000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 7 | `124999999984107000000000000` | `124999999984107000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 8 | `124999999984107000000000000` | `124999999984107000000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 9 | `62499999992053500000000000` | `62499999992053500000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 10 | `62499999992053500000000000` | `62499999992053500000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 11 | `31249999996026750000000000` | `31249999996026750000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 12 | `31249999996026750000000000` | `31249999996026750000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 13 | `15624999998013375000000000` | `15624999998013375000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 14 | `15624999998013375000000000` | `15624999998013375000000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 15 | `7812499999006687500000000` | `7812499999006687500000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 16 | `7812499999006687500000000` | `7812499999006687500000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 17 | `3906249999503343750000000` | `3906249999503343750000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 18 | `3906249999503343750000000` | `3906249999503343750000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 19 | `1953124999751671875000000` | `1953124999751671875000000` | yes | +| TV-04 emission.csv (10 blocks/s) | emission in year 20 | `1953124999751671875000000` | `1953124999751671875000000` | yes | -Meaning: the schedule this comparison calls A is TV-01's mainnet contract profile to the base unit, so every difference shown for B and C is measured from the compiled mainnet schedule and not from a model of it. +Meaning: the schedule this comparison calls A is TV-01's mainnet contract profile and TV-04's emission to the base unit, so every difference shown for B and C is measured from the compiled mainnet schedule and not from a model of it. ## Commands and checksums @@ -213,15 +235,15 @@ Every run is on build-3 under the pid file `~/tv-d02/run.pid` (`tools/token-valu | what | command | sha256 | |---|---|---| -| the generator | `python3 tools/token-value/d02/d02_emission.py --out docs/plans/igneum-2.0-master/token-value/phase0/d02` | `ef1d48182c1702ff59c21eb7373f4cea9e2de64f98a2a86426f2c3309b25ed03` | -| the README template | (read by the generator) | `009b07323513790a05e8bd4575ffd2d6b92d37d2d486796de29c55433dc195f0` | +| the generator | `python3 tools/token-value/d02/d02_emission.py --out docs/plans/igneum-2.0-master/token-value/phase0/d02` | `2a6bf3231d94618b049a08474de0544ddff7000c1e57eda290d07ef2882e6b8e` | +| the README template | (read by the generator) | `a7009a356a5c750327084f785fa641df55d5d49c8944d436add5b0fce715d249` | | the tests (known-failed first) | `python3 tools/token-value/d02/test_d02.py` | `87252bf447f7c4fcd894790ca42839e1e511a9fb1cda53e9eed3807313bae1b9` | | the byte-identical check | `python3 tools/token-value/d02/d02_emission.py --check docs/plans/igneum-2.0-master/token-value/phase0/d02` | (exit 0 = byte-identical) | | `d02-schedules.csv` (parameters, curve steps, terminal values) | the generator | `1abd30eb7879607a43052c74bf2a6ee4fc27202754d6700cacbfb342ea20e3ae` | | `d02-years.csv` (years 1 to 40, every schedule) | the generator | `c03933af686c9c11454a0b1c188bf2dfa7903549dcc274fdbe43cd2c609723fd` | | `d02-horizons.csv` (years 1, 2, 5, 10, 20) | the generator | `4329ec9f51015577f297f56440b486543e4a40f1cb075270f7b17b02da5f542f` | -| `d02-fee-dependence.csv` (every multiple, every schedule, fees required at each horizon) | the generator | `07375dc4cd075a720591326a792c238c54b28a0d8fa9decf38534bd2d738f854` | -| `d02-tv01-reconcile.csv` (section 9, every row) | the generator | `34fcfc388b138ffcd18600d661debe3458c82c37b087501d0d6b17f471dd2892` | +| `d02-fee-dependence.csv` (every multiple, every schedule, fees required at each horizon) | the generator | `bd71cbed36a6939185d71cf48e3c3d733112720247aefeff432bc07ee2ad81db` | +| `d02-tv01-reconcile.csv` (section 9, every row) | the generator | `4871f92ece47d43fe5a7188ef95d91984e878530d12f00430d795626ba9c591d` | | `d02-manifest.sha256` (this README and every CSV) | the generator | (lists this file's sha) | Searches for a crossing year run to year 1,000; an empty cell means the budget holds that long on the subsidy alone. @@ -240,10 +262,10 @@ Searches for a crossing year run to year 1,000; an empty cell means the budget h | row | question | waits on | earliest clock (UK) | |---|---|---|---| | B0 | Which schedule launches: A, B (and at which factor), C, or another same-cap shape. This document does not pick it. | the founder ("pending evidence") after the independent panel reads this | the founder's word | -| B2 | Replace the 1 percent yardstick with TV-04's role-by-role budget and its revenue multiples' base | TV-04's landing | TV-04's clock | +| B2 | The minimum cost of each role in BU (what the security budget must actually buy), so the fee-dependence years become pass or fail rows | TV-04's panel cells (N-min-hashrate, N-shards-year, N-min-hubs, N-maint-month, K-class) | the panel's word | | B3 | Arrival times and cohort shares under each schedule (delayed entrants as people, not blocks) | TV-03's simulation inputs and a cohort definition | TV-03's clock | -Closed since the first version (09:44 UK): B1, the reconciliation with TV-01's supply spec (section 9); B4, the litepaper's year-five tail-vote sentence, which the site lane rewrote under D01 (TV-01's conflict C01). +Closed since the first version (09:44 UK): B2's first half, the 1 percent yardstick, replaced by TV-04's baseline and multiples (section 6); B1, the reconciliation with TV-01's supply spec (section 9); B4, the litepaper's year-five tail-vote sentence, which the site lane rewrote under D01 (TV-01's conflict C01). ## Registry diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-fee-dependence.csv b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-fee-dependence.csv index ea71dcf35..224abb7c9 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-fee-dependence.csv +++ b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-fee-dependence.csv @@ -1,21 +1,26 @@ -key,multiple,reference_budget_base_units_per_year,fees_needed_from_year,fees_exceed_subsidy_from_year,fees_required_y1_base_units,fees_required_y2_base_units,fees_required_y5_base_units,fees_required_y10_base_units,fees_required_y20_base_units -A,0.25x,10000000000000000000000000,15,17,0,0,0,0,8046875000248328125000000 -A,1x,40000000000000000000000000,11,13,0,0,0,0,38046875000248328125000000 -A,4x,160000000000000000000000000,7,9,0,0,0,97500000007946500000000000,158046875000248328125000000 -A,10x,400000000000000000000000000,5,7,0,0,150000000031786000000000000,337500000007946500000000000,398046875000248328125000000 -B,0.25x,10000000000000000000000000,25,29,0,0,0,0,0 -B,1x,40000000000000000000000000,17,21,0,0,0,0,8750000013835000000000000 -B,4x,160000000000000000000000000,9,13,0,0,0,35000000055340000000000000,128750000013835000000000000 -B,10x,400000000000000000000000000,5,9,0,0,150000000110680000000000000,275000000055340000000000000,368750000013835000000000000 -C,0.25x,10000000000000000000000000,25,29,0,0,0,0,0 -C,1x,40000000000000000000000000,17,21,0,0,0,0,16349110655747632561636600 -C,4x,160000000000000000000000000,9,13,0,0,0,26210365993564584681976000,136349110655747632561636600 -C,10x,400000000000000000000000000,4,8,0,0,81792830514963727905583000,266210365993564584681976000,376349110655747632561636600 -B3,0.25x,10000000000000000000000000,37,43,0,0,0,0,0 -B3,1x,40000000000000000000000000,25,31,0,0,0,0,0 -B3,4x,160000000000000000000000000,13,19,0,0,0,0,118333333364929000000000000 -B3,10x,400000000000000000000000000,1,7,78987000205397168500000000,66666666919432000000000000,66666666919432000000000000,233333333459716000000000000,358333333364929000000000000 -B4,0.25x,10000000000000000000000000,41,49,0,0,0,0,0 -B4,1x,40000000000000000000000000,25,33,0,0,0,0,0 -B4,4x,160000000000000000000000000,9,17,0,0,0,35000000055340000000000000,97500000027670000000000000 -B4,10x,400000000000000000000000000,1,9,159240250078069877500000000,150000000110680000000000000,150000000110680000000000000,275000000055340000000000000,337500000027670000000000000 +key,multiple,budget_one_bu_base_units_per_year,fees_needed_from_year,fees_exceed_subsidy_from_year,fees_required_y1_base_units,fees_required_y2_base_units,fees_required_y5_base_units,fees_required_y10_base_units,fees_required_y20_base_units +A,0.1x,9630389999916324854884800000,1,1,8667350999924692369396320000,8630390000043468854884800000,9380389999948110854884800000,9567889999924271354884800000,9628436874916573183009800000 +A,0.25x,3852155999966529941953920000,1,1,2889116999974897456465440000,2852156000093673941953920000,3602155999998315941953920000,3789655999974476441953920000,3850202874966778270078920000 +A,1x,963038999991632485488480000,3,5,0,0,713039000023418485488480000,900538999999578985488480000,961085874991880813613480000 +A,4x,240759749997908121372120000,7,9,0,0,0,178259750005854621372120000,238806624998156449497120000 +A,10x,96303899999163248548848000,9,11,0,0,0,33803900007109748548848000,94350774999411576673848000 +B,0.1x,9630389999916324854884800000,1,1,9148870500072464609896320000,9130390000137684854884800000,9380390000027004854884800000,9505389999971664854884800000,9599139999930159854884800000 +B,0.25x,3852155999966529941953920000,1,1,3370636500122669696965440000,3352156000187889941953920000,3602156000077209941953920000,3727156000021869941953920000,3820905999980364941953920000 +B,1x,963038999991632485488480000,1,1,481519500147772240500000000,463039000212992485488480000,713039000102312485488480000,838039000046972485488480000,931789000005467485488480000 +B,4x,240759749997908121372120000,9,13,0,0,0,115759750053248121372120000,209509750011743121372120000 +B,10x,96303899999163248548848000,13,17,0,0,0,0,65053900012998248548848000 +C,0.1x,9630389999916324854884800000,1,1,9019410981380697609415098000,9095231463522175664043660000,9312182830431288582987618000,9496600365909889439698266000,9606739110572072487585816000 +C,0.25x,3852155999966529941953920000,1,1,3241176981430902696484218000,3316997463572380751112780000,3533948830481493670056738000,3718366365960094526767386000,3828505110622277574654936000 +C,1x,963038999991632485488480000,1,3,352059981456005240018778000,427880463597483294647340000,644831830506596213591298000,829249365985197070301946000,939388110647380118189496000 +C,4x,240759749997908121372120000,7,11,0,0,0,106970115991472706185586000,217108860653655754073136000 +C,10x,96303899999163248548848000,12,16,0,0,0,0,72653010654910881249864000 +B3,0.1x,9630389999916324854884800000,1,1,9309377000121722023396320000,9297056666835756854884800000,9297056666835756854884800000,9463723333376040854884800000,9588723333281253854884800000 +B3,0.25x,3852155999966529941953920000,1,1,3531143000171927110465440000,3518822666885961941953920000,3518822666885961941953920000,3685489333426245941953920000,3810489333331458941953920000 +B3,1x,963038999991632485488480000,1,1,642026000197029654000000000,629705666911064485488480000,629705666911064485488480000,796372333451348485488480000,921372333356561485488480000 +B3,4x,240759749997908121372120000,7,13,0,0,0,74093083457624121372120000,199093083362837121372120000 +B3,10x,96303899999163248548848000,13,19,0,0,0,0,54637233364092248548848000 +B4,0.1x,9630389999916324854884800000,1,1,9389630249994394732396320000,9380390000027004854884800000,9380390000027004854884800000,9505389999971664854884800000,9567889999943994854884800000 +B4,0.25x,3852155999966529941953920000,1,1,3611396250044599819465440000,3602156000077209941953920000,3602156000077209941953920000,3727156000021869941953920000,3789655999994199941953920000 +B4,1x,963038999991632485488480000,1,1,722279250069702363000000000,713039000102312485488480000,713039000102312485488480000,838039000046972485488480000,900539000019302485488480000 +B4,4x,240759749997908121372120000,1,17,75977998883640000,0,0,115759750053248121372120000,178259750025578121372120000 +B4,10x,96303899999163248548848000,17,25,0,0,0,0,33803900026833248548848000 diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-manifest.sha256 b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-manifest.sha256 index e8f10a55f..a59b819db 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-manifest.sha256 +++ b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-manifest.sha256 @@ -1,8 +1,8 @@ -# input ef1d48182c1702ff59c21eb7373f4cea9e2de64f98a2a86426f2c3309b25ed03 tools/token-value/d02/d02_emission.py -# input 009b07323513790a05e8bd4575ffd2d6b92d37d2d486796de29c55433dc195f0 tools/token-value/d02/README.template.md +# input 2a6bf3231d94618b049a08474de0544ddff7000c1e57eda290d07ef2882e6b8e tools/token-value/d02/d02_emission.py +# input a7009a356a5c750327084f785fa641df55d5d49c8944d436add5b0fce715d249 tools/token-value/d02/README.template.md 1abd30eb7879607a43052c74bf2a6ee4fc27202754d6700cacbfb342ea20e3ae d02-schedules.csv c03933af686c9c11454a0b1c188bf2dfa7903549dcc274fdbe43cd2c609723fd d02-years.csv 4329ec9f51015577f297f56440b486543e4a40f1cb075270f7b17b02da5f542f d02-horizons.csv -07375dc4cd075a720591326a792c238c54b28a0d8fa9decf38534bd2d738f854 d02-fee-dependence.csv -34fcfc388b138ffcd18600d661debe3458c82c37b087501d0d6b17f471dd2892 d02-tv01-reconcile.csv -4f5a7ac5aba5fee1aef646e4e3f55fdb491db197429654cfdba0bab9bfb38db3 README.md +bd71cbed36a6939185d71cf48e3c3d733112720247aefeff432bc07ee2ad81db d02-fee-dependence.csv +4871f92ece47d43fe5a7188ef95d91984e878530d12f00430d795626ba9c591d d02-tv01-reconcile.csv +e4292764e922a963de68ace7fca8520a6c334cf6754c869823670f5bac40be90 README.md diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-tv01-reconcile.csv b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-tv01-reconcile.csv index 3f7c3e6cf..1e653c5b2 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-tv01-reconcile.csv +++ b/docs/plans/igneum-2.0-master/token-value/phase0/d02/d02-tv01-reconcile.csv @@ -31,3 +31,23 @@ profile,quantity,tv01_spec,d02_generator,agree "devnet-4 (1 block/s)","terminal DAA score (first unpaid)",4102488000,4102488000,yes "devnet-4 (1 block/s)","terminal supply",3963038999610200483289816000,3963038999610200483289816000,yes "devnet-4 (1 block/s)","cap shortfall",36961000389799516710184000,36961000389799516710184000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 1",963038999991632485488480000,963038999991632485488480000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 2",999999999872856000000000000,999999999872856000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 3",499999999936428000000000000,499999999936428000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 4",499999999936428000000000000,499999999936428000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 5",249999999968214000000000000,249999999968214000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 6",249999999968214000000000000,249999999968214000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 7",124999999984107000000000000,124999999984107000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 8",124999999984107000000000000,124999999984107000000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 9",62499999992053500000000000,62499999992053500000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 10",62499999992053500000000000,62499999992053500000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 11",31249999996026750000000000,31249999996026750000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 12",31249999996026750000000000,31249999996026750000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 13",15624999998013375000000000,15624999998013375000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 14",15624999998013375000000000,15624999998013375000000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 15",7812499999006687500000000,7812499999006687500000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 16",7812499999006687500000000,7812499999006687500000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 17",3906249999503343750000000,3906249999503343750000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 18",3906249999503343750000000,3906249999503343750000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 19",1953124999751671875000000,1953124999751671875000000,yes +"TV-04 emission.csv (10 blocks/s)","emission in year 20",1953124999751671875000000,1953124999751671875000000,yes diff --git a/docs/plans/igneum-2.0-master/token-value/phase0/d02/evidence/box-generate.log b/docs/plans/igneum-2.0-master/token-value/phase0/d02/evidence/box-generate.log index b5a53fe8a..70d624ad0 100644 --- a/docs/plans/igneum-2.0-master/token-value/phase0/d02/evidence/box-generate.log +++ b/docs/plans/igneum-2.0-master/token-value/phase0/d02/evidence/box-generate.log @@ -1,11 +1,11 @@ -host igneum-build-3 python Python 3.12.3 commit 71e1e14841a1678b3357c42e3fd8376e1acf85c6 utc 2026-10-09T09:19:28Z pidfile /home/build/tv-d02/run.pid +host igneum-build-3 python Python 3.12.3 commit cc3416c5b27c5d0c5007352d86a38c456c97b88a utc 2026-10-09T09:45:06Z pidfile /home/build/tv-d02/run.pid 1abd30eb7879607a43052c74bf2a6ee4fc27202754d6700cacbfb342ea20e3ae d02-schedules.csv c03933af686c9c11454a0b1c188bf2dfa7903549dcc274fdbe43cd2c609723fd d02-years.csv 4329ec9f51015577f297f56440b486543e4a40f1cb075270f7b17b02da5f542f d02-horizons.csv -07375dc4cd075a720591326a792c238c54b28a0d8fa9decf38534bd2d738f854 d02-fee-dependence.csv -34fcfc388b138ffcd18600d661debe3458c82c37b087501d0d6b17f471dd2892 d02-tv01-reconcile.csv -4f5a7ac5aba5fee1aef646e4e3f55fdb491db197429654cfdba0bab9bfb38db3 README.md -f632f8d14e6c7446c47b0ec0cf03a934f47ed4a43d691e0a687451a6bd705431 d02-manifest.sha256 +bd71cbed36a6939185d71cf48e3c3d733112720247aefeff432bc07ee2ad81db d02-fee-dependence.csv +4871f92ece47d43fe5a7188ef95d91984e878530d12f00430d795626ba9c591d d02-tv01-reconcile.csv +e4292764e922a963de68ace7fca8520a6c334cf6754c869823670f5bac40be90 README.md +7d3e9ec30978c86f25464f66eaccc054f9ac8cd683ec3336e68848722cff0552 d02-manifest.sha256 test_a_one_byte_change_is_caught (__main__.ByteIdentical.test_a_one_byte_change_is_caught) ... ok test_outputs_regenerate_byte_identically (__main__.ByteIdentical.test_outputs_regenerate_byte_identically) ... ok test_current_at_8_decimals_is_the_33_step_table (__main__.NodeConstants.test_current_at_8_decimals_is_the_33_step_table) ... ok @@ -17,7 +17,7 @@ test_paid_and_closed_form_agree_within_one_coin (__main__.TV01Spec.test_paid_and test_the_paid_model_reproduces_tv01_exactly (__main__.TV01Spec.test_the_paid_model_reproduces_tv01_exactly) ... ok ---------------------------------------------------------------------- -Ran 9 tests in 4.011s +Ran 9 tests in 6.928s OK exit 0 diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index d3724932d..4299ceaf0 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -17641,16 +17641,16 @@ "threshold_status": "PROPOSED - FREEZE BEFORE TEST", "run_status": "NOT RUN", "master_status": "NOT RUN", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence_path": "docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.json; docs/plans/igneum-2.0-master/token-value/phase0/tv-01/supply-spec.md; tools/token-value/tv-01/check-spec.py; tools/token-value/tv-01/code-dump/schedule-bf60948a.jsonl; docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", - "updated": "2026-10-09T09:38:38.607Z", + "updated": "2026-10-09T09:45:30.970Z", "evidence_record": { "requirement_id": "TV-01", "decision": "NOT RUN", "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: the D02 evidence only; the other five decisions and the signed specification are other lanes'", @@ -17664,8 +17664,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." }, "evidence_records": { "token-value:tv-01": { @@ -17697,7 +17697,7 @@ "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: the D02 evidence only; the other five decisions and the signed specification are other lanes'", @@ -17711,8 +17711,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." } }, "in_progress_since": "2026-10-09T09:00:20.590Z", @@ -17824,16 +17824,16 @@ "threshold_status": "PROPOSED - FREEZE BEFORE TEST", "run_status": "NOT RUN", "master_status": "NOT RUN", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence_path": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", - "updated": "2026-10-09T09:38:38.607Z", + "updated": "2026-10-09T09:45:30.970Z", "evidence_record": { "requirement_id": "TV-03", "decision": "NOT RUN", "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: issuance timing and per-block subsidy for delayed entrants under three same-cap schedules; no genesis audit, no outsider rehearsal, no cohort", @@ -17847,8 +17847,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." }, "evidence_records": { "model:tv-d02-emission": { @@ -17857,7 +17857,7 @@ "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: issuance timing and per-block subsidy for delayed entrants under three same-cap schedules; no genesis audit, no outsider rehearsal, no cohort", @@ -17871,8 +17871,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." } }, "in_progress_since": "2026-10-09T09:00:20.590Z", @@ -17912,16 +17912,16 @@ "threshold_status": "PROPOSED - FREEZE BEFORE TEST", "run_status": "NOT RUN", "master_status": "NOT RUN", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence_path": "docs/plans/igneum-2.0-master/token-value/phase0/tv-04/README.md; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/budget.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/emission.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/fee-replacement.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/parameters.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/blocked.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/tv01-reconcile.csv; docs/plans/igneum-2.0-master/token-value/phase0/tv-04/RUNS.md; tools/token-value/tv-04/tv04_budget.py; tools/token-value/tv-04/test_tv04.py; tools/token-value/tv-04/inputs.json; build-9:/home/build/tv-04/runs/ea14c332-red/run.log; build-9:/home/build/tv-04/runs/53d47721-green/run.log; build-9:/home/build/tv-04/runs/53d47721-known-failed/run.log; build-9:/home/build/tv-04/runs/53d47721-generate/run.log; build-9:/home/build/tv-04/runs/a3d79901-check/run.log; docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", - "updated": "2026-10-09T09:38:38.607Z", + "updated": "2026-10-09T09:45:30.970Z", "evidence_record": { "requirement_id": "TV-04", "decision": "NOT RUN", "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: the subsidy's decline and the fee-dependence year at the four multiples; no role costs, fee volatility or zero-external-job scenario", @@ -17935,8 +17935,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." }, "evidence_records": { "model:tv-04": { @@ -17968,7 +17968,7 @@ "method": "model", "cell": "model:tv-d02-emission", "manifest_sha": "a284380b", - "run_id": "tv-d02-20261009-02", + "run_id": "tv-d02-20261009-03", "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", "in_progress": true, "coverage": "partial: the subsidy's decline and the fee-dependence year at the four multiples; no role costs, fee volatility or zero-external-job scenario", @@ -17982,8 +17982,8 @@ }, "claim_impact": "none: no public figure moves and no schedule is chosen", "reviewer": "", - "at": "2026-10-09T09:38:38.607Z", - "note": "TV-01: the D02 comparison the decision register asks for, its schedule A reconciled with TV-01's supply spec to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (TV-04's budget base), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the fee-dependence year at the .25x/1x/4x/10x multiples against a stated 1 percent yardstick, the fee series a parameter (table 6). | D02 second version (the D02 lane, 9 October 2026, 10:3x UK): the generator now reads TV-01's supply spec (sha256 3ffdd308..., master 163c9e3c) and reproduces its mainnet (10 blocks/s) and devnet-4 (1 block/s) profiles exactly, 32 of 32 rows (README section 9, d02-tv01-reconcile.csv); the paid model at mainnet's 10 blocks a second added beside the node's closed form; BLOCKED rows B1 (TV-01 spec) and B4 (the litepaper tail-vote sentence, rewritten under D01) closed. Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." + "at": "2026-10-09T09:45:30.970Z", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6). | D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it." } }, "in_progress_since": "2026-10-09T08:46:41.597Z", diff --git a/tools/ci/batches/tv-d02-20261009-03.json b/tools/ci/batches/tv-d02-20261009-03.json new file mode 100644 index 000000000..c3f132723 --- /dev/null +++ b/tools/ci/batches/tv-d02-20261009-03.json @@ -0,0 +1,26 @@ +{ + "run_id": "tv-d02-20261009-03", + "manifest_sha": "a284380b", + "evidence_dir": "docs/plans/igneum-2.0-master/token-value/phase0/d02", + "method": "model", + "supersedes": [ + "tv-d02-20261009-02" + ], + "note": "D02 third version (the D02 lane, 9 October 2026, 11:0x UK): fee dependence now in TV-04's frame (the baseline of one BU, the current schedule's whole year-1 paid subsidy, at TV-04's 0.1x, 0.25x, 1x, 4x and 10x multiples), replacing the lane's 1 percent yardstick; TV-04's emission.csv reconciled (20 years) beside TV-01's spec, 52 of 52 rows exact (README section 9). Run on build-3: 9 tests OK, --check byte-identical (evidence/box-generate.log). No schedule is picked. NOT RUN until the independent panel reads it.", + "cells": [ + { + "cell": "model:tv-d02-emission", + "cases": [ + "TV-01", + "TV-03", + "TV-04" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "model", + "evidence": "docs/plans/igneum-2.0-master/token-value/phase0/d02/README.md", + "note": "TV-01: the D02 comparison the decision register asks for, schedule A reconciled with TV-01's supply spec and TV-04's emission to the base unit; open BLOCKED rows B0 (the founder's pick), B2 (the role costs, TV-04's panel cells), B3 (TV-03's cohort inputs). TV-03: issuance timing under alternative same-cap schedules and the subsidy a delayed entrant sees at 10 blocks/s (tables 1, 4, 5). TV-04: falling issuance at horizons 1, 5, 10 and 20 and the year fees must exceed the subsidy to hold one BU at each of TV-04's multiples, the fee series a parameter (table 6).", + "claim_impact": "none: no public figure moves and no schedule is chosen" + } + ] +} From a9e933a9a0aa5addf05c2aaacc2289aa5407d25f Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:52:08 +0000 Subject: [PATCH 16/19] mhpow B4: the one-page requirements for a Track B construction (Q1 to Q5) and B2's B-T1 to B-T8 answered or BLOCKED docs/analysis/mhpow/b4/requirements.md: Q1 a lottery draw costs a fresh labelling (B4 Lemma C; B1's fixture A6 as witness); Q2 the honest path bandwidth-bound at row-sized access, GPU wall pJ per byte moved <= 99 / 57 / 33 against X7's GDDR7 board / HBM3 / near-memory rows; Q3 the instance above the declared SRAM ceiling for the graph's low-space schedule (log2 N x M_SRAM / C for DRSample); Q4 composed losses under 2x with the lemma to change per loss; Q5 B2's template cap. Rows R-Q2 (the kill test), R-Q3 (the panel's M_SRAM), R-Q4 (B4). NOT RUN. Co-Authored-By: Claude Opus 5.5 --- docs/analysis/mhpow/b4/README.md | 2 + docs/analysis/mhpow/b4/requirements.md | 53 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 docs/analysis/mhpow/b4/requirements.md diff --git a/docs/analysis/mhpow/b4/README.md b/docs/analysis/mhpow/b4/README.md index 456df6a8b..e7af85c9f 100644 --- a/docs/analysis/mhpow/b4/README.md +++ b/docs/analysis/mhpow/b4/README.md @@ -19,6 +19,8 @@ the certificate root re-rolls for log2 N + 1 hashes per draw after one labelling must cost a fresh labelling: trial id in chi, v = H(tag_lot, chi, tau), winners verified in full, spot checks kept as the pre-filter. Owners by row: B4-OB-LOT (B4), -1 (B2), -2 (B1), -3 (B4), -4 (B2 with B6). +**THE PIVOT (10:4x UK).** Track B now builds its own construction; the one-page requirements it must meet (Q1 lottery, Q2 bandwidth-bound honest path, Q3 instance above SRAM, Q4 losses under 2x, Q5 the template cap) and the answers to B2's B-T1 to B-T8 are in requirements.md beside this README. + **The result in four lines.** 1. The 2025 theorem (Blocki and Smearsoll) proves, in the parallel random oracle model, that any prover whose MTP/DRSample diff --git a/docs/analysis/mhpow/b4/requirements.md b/docs/analysis/mhpow/b4/requirements.md new file mode 100644 index 000000000..d40ad7c26 --- /dev/null +++ b/docs/analysis/mhpow/b4/requirements.md @@ -0,0 +1,53 @@ +# B4: what a Track B construction must meet to be worth a proof (one page) + +9 October 2026, 11:xx UK, for the B1 (a4490b2dfe9114a55) and B3 (a8e608abf1567ff87) candidates due 11:45. NOT RUN: requirements, +not results. The reproduction of R1 (Blocki and Smearsoll, eprint 2025/1456) stays the control; its numbers are BOUND (L) rows in +README.md beside this page. Inputs by row: B2's O-07 and B-T1 to B-T8 (docs/analysis/mhpow/b2/README.md), X7's s rows +(docs/analysis/class-v6/1p5x/x7/README.md), and B3's and B5's findings as the coordinator relayed them at 10:4x UK (not yet landed). + +## The four requirements + +| # | requirement | the number to meet | why (source) | what fails it | +|---|---|---|---|---| +| Q1 | Every lottery draw costs a fresh labelling (phi = 1), or a per-draw work bound is stated and proved | draws per labelling = 1. Today: 2N / (log2 N + 1), about 1.3 million at N = 2^24 (B2 O-07) | B4 Lemma C (README 5b): any value over an MTP certificate re-rolls through the sink for log2 N + 1 calls, accepted with (1 - 1/N)^k | a lottery over tau with spot-check verification only; a lottery over chi alone (screened for one hash) | +| Q2 | The honest path is bandwidth-bound on GDDR7 and fills the GPU by memory traffic, not by instance count | (a) GPU wall joules per byte moved, hashing included: at most 1.5 x the opponent's per byte: 99 pJ/B against a GDDR7 board (66), 57 against HBM3 (38), 33 against near-memory (22) (X7 s rows, 32 B sectors). (b) Access unit at least one DRAM row: X7 shows the 32 B random read at 8.7 nJ knee on the 5090 (272 pJ/B, s = 4.1 to 12.5), so 32 B dependent reads are excluded. (c) Hash input bytes per byte moved rho <= 1, and the hash's GPU energy per byte well under its memory energy per byte | R3 section 4: advantage >= (c_b,GPU + rho c_r,GPU) / (c_b,ASIC + rho c_r,ASIC), with c_r,ASIC near 0; B3: one sequential chain per instance leaves the 5090 equal to 27 to 44 CPU cores at 32 MiB | narrow labels (32 B); one chain per instance with no intra-label parallelism; a label hash costing more per byte than the memory | +| Q3 | Instance state exceeds the largest SRAM in the declared technology set, for the graph's best low-space schedule | DRSample: S_instance >= log2 N x M_SRAM / C (it has a pebbling in C N / log2 N labels and time N: README sec. 8; 186 MiB x C for a 4 GiB state). A graph with no o(N)-space, O(N)-time schedule: S_instance >= M_SRAM x a stated constant | R2 section 5.4 (no transfer bound above m = C N / log N); B5: the full-SRAM opponent at 32 MiB pays 7.4 to 7.6 mJ per instance, 92 percent label-hash core ops, i.e. it is hash-bound and an ASIC wins hashing | DRSample at any instance size below log2 N x M_SRAM; M_SRAM undeclared (the panel declares it: row R-Q3) | +| Q4 | The certificate's composed losses stay under 2x | bound >= E_honest / 2 in joules, with the full-SRAM and near-memory opponents inside it | today: the generic route certifies at most 0.151 of honest (0.213 for a fully verified winner); the red-blue route loses at least 341x at rho = 0.25 (README 7) | any route through R2 Theorem 4.5 (the square root is inherent); R2's published constants | + +## Q4 in detail: the lemma that has to change for each loss + +| loss (README 7) | published factor | what must change | candidate | +|---|---|---|---| +| L1 extraction hint | 4x | label width w >= 1 KiB: theta / w = 0.976 at q = 2^64 (B4 restatement of R1 Lemma 3, params.txt sec. 2) | wide labels (Q2 wants them anyway); the RO for wide labels from a permutation per R16 (eps/40, cache 20 delta m: a new loss to tighten) | +| L2 red nodes | 2x | beta = 0 for winners | full verification of winning blocks (Q1's fix does this) | +| L3 depth-robustness | c1 c2 / log2 N (4 log N / (c3 c4) in B2's form) | a graph with e + d <= (1 - eps) N (eps-extreme depth-robust, R1 sec. 6 citing ABP18, in-degree O(log N)): cc >= e d up to (1 - eps)^2 N^2 / 4 against the honest N^2 / 2 | ABP18's graphs; their in-degree O(log N) raises bytes per label hashed (Q2 (c)) | +| L5 generic cmc to joules | sqrt(c_b c_r) / (c_b + c_r) and a square root | do not use it; prove energy directly | none: inherent to R2 Theorem 4.5 | +| L6 energy to red-blue | eps/16, cache 9m | R2 Theorem 3.3's interval partition (3m and 4m QueryFirst sets, Lemma 3.9's 2^(-2mw/5)) re-proved with constant >= 1/2 and cache inflation <= 2m | new lemma (B4) | +| L7 the graph's red-blue cost | (1 - rho)/16 of N c_b, nothing above C N / log N | a graph whose red-blue cost is >= (1/2) N c_b for every cache up to M_SRAM | the bit-reversal shape of R3 Theorem 2 is near-tight in the pebbling model ((c_b + c_r) n (1 - ...) for n > 2 m c_b / c_r) but has low cc; a graph with both is the design target | +| L11 amortisation | open | the union-graph form of R1 and R2 for J distinct chi (B-T5) | B4 | + +**Q5 (a cap, from B2's B-T8).** One labelling per draw must finish inside the template's life: N t_seq <= rho x 1 s, so the instance is at most b rho / t_seq bytes (b = bytes per label, t_seq = one dependent label step). Q3 sets the floor; the construction must show the window between them is not empty at the declared M_SRAM. Wide labels (Q2) widen it: the cap grows with b, the floor does not. + +## B2's B-T rows, answered or BLOCKED + +| row | answer | +|---|---| +| B-T1 graph sampling failure | BLOCKED: needs ABH17's tail bound (eprint 2017/443 not fetched, README B4-B01). Q3 and L3 point away from sampled DRSample in any case. Question: the probability a seed-sampled DRSample at N = 2^20 to 2^24 is not (c3 N/log N, c4 N)-depth-robust, and whether an era re-seed lets a seed-biasing party search for a weak graph. | +| B-T2 c3, c4 | BLOCKED (README B4-B03): R1 Fact 8 is existential; ABH17 not fetched. Every DRSample number stays a sensitivity row. | +| B-T3 the lottery | ANSWERED in shape (README 5b, B4 Lemma C, NOT RUN): no W with polylog sampled verification meets the requested bound inside MTP; the replacement is full verification of winners (unique output, AS15 per trial) with spot checks as the DoS pre-filter. That is Q1. B1 executed the re-roll as fixture A6 (attacks-n10-k16.json 805035eb on mhpow-b1 e9f94df6a: 193 to 200 of 200 re-rolls accepted per labelling), a witness for Lemma C. | +| B-T4 adaptive chi | ANSWERED as a loss (B4 restatement, NOT RUN): Collision, BadOrder, IE and LuckyQuery are already unions over the whole trace; MisColor becomes q N 2^-lambda (a union over at most q candidate chi). | +| B-T5 multi-instance | BLOCKED (README B4-OB-LOT-3): the union graph of J copies, cc additive over components, the extractor on the union; the terms that scale with J are MisColor (J N 2^-lambda) and the per-copy LuckyQuery. Proof not written. | +| B-T6 lambda | ANSWERED as a constraint: w >= 8 log2 q + 4 under R1 Lemma 3 as stated (516 to 772 bits for q = 2^64 to 2^96), or the general charge w - 2 log2 q - 1 - s per pebble; R2 Theorem 3.3 needs w > 20 log2 q (1,280 bits at q = 2^64). Q2's labels of 1 KiB or more meet both; BLAKE2b's 512-bit cap means an XOF or a permutation (R16). | +| B-T7 role bytes | ANSWERED by reading (not a proof audit): the extractor locates labels by query index and offset (R1 Theorem 5's hint), so a fixed role prefix only shifts offsets; Lemmas 7, 8, 10 hold for any query form; the Merkle trace of Theorem 4 needs the Merkle query form to be distinct from the label form, which the role byte guarantees. No step uses a cross-role coincidence. | +| B-T8 memory-time to energy | ANSWERED: README sections 5, 7, 8 (generic 0.151, red-blue >= 341x, the transfer term void above C N / log N). B2's template cap N t_seq <= rho x 1 s bounds the instance from above (Q5); with Q3's floor the window is log2 N x M_SRAM / C <= N b <= b rho / t_seq, and for DRSample it may be empty. | + +## Rows this page opens + +| row | owner | question | +|---|---|---| +| R-Q2 | B3 with X7 | The 5090's wall pJ per byte moved at row-sized sequential access with the label hash folded in, at stock and at the knee. If it exceeds 33 pJ/B, no construction certifies 1.5x against near-memory by R3 section 4's limit, before any proof loss. This is the kill test and the first row to take. | +| R-Q3 | the panel | M_SRAM: the largest on-die or stacked SRAM in the declared technology set (plan section 8). Q3's instance size follows from it. | +| R-Q4 | B4 | The two lemmas of Q4 (L6 at constant >= 1/2, L7 for a graph with both high cc and near-tight red-blue cost), or a proof that 2x is out of reach for them. | + +The quantum claim stays classical: every bound here is in the classical parallel random oracle model and no quantum speedup is +claimed or estimated. From 840ef38549d7d8523ed96c76583c39c07e41e732 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:55:03 +0000 Subject: [PATCH 17/19] mhpow B2: O-17, B4's lottery rule adopted with its fake-winner budget; B4's answers to B-T1 to B-T8 B4 (requirements.md on mhpow-b4 a9e933a9a, README 5b on master b67b89cf8) answered B-T3 in shape: trial id in chi, W = H('W', chi || tau), winners verified in full, spot checks as the pre-filter. B2 adopts it as O-17 and states the budget B4 asked for (B4-OB-LOT-1): the pre-filter does not price a fake winner, which keeps one labelling and re-rolls the red sink, (log2 N + 1)/p calls against 2N/p for a real winner, so an attacker with 1e-6 of the network makes 1.34 fakes per real block at N = 2^24, each costing every validator it reaches a full labelling (figures section 6). B4 5b's sentence that R1's bound prices the fake is corrected here. New row B-N4 to the node lane with B6. B-T4, B-T6, B-T7, B-T8 answered; B-T1, B-T2, B-T5 stay BLOCKED. Co-Authored-By: Claude Opus 5.5 --- docs/analysis/mhpow/b2/README.md | 30 +++++++++++-------- docs/analysis/mhpow/b2/figures.txt | 22 ++++++++++++++ .../registry-batch-mhpow-b2-20261009-01.json | 4 +-- tools/mhpow/b2/b2_figures.py | 25 +++++++++++++++- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/docs/analysis/mhpow/b2/README.md b/docs/analysis/mhpow/b2/README.md index 48c75ac6d..e099b4f8a 100644 --- a/docs/analysis/mhpow/b2/README.md +++ b/docs/analysis/mhpow/b2/README.md @@ -15,7 +15,8 @@ registry until the panel reads it; this lane writes no PASS. The status words in | The spec | `docs/spec/01-lottery-hash.md` on master bc6bfa75e: 1.0 (the frozen object), 1.6, 1.10, 1.12, 1.13.3 | the dataset policy digest in full, the epoch, day and era clocks | | The signing pair | `igneum-pow/tests/composition.rs` at class-v6 755c2dbcf | epoch seed af89be5d..., era edc4fa84..., day 20730, program id 0x2a1d6caab4c24564 | | The B1 lane's encoding pins (R15-05, a4490b2dfe9114a55, 10:2x UK) | unkeyed BLAKE2b-256, `lambda = 256`, one ASCII role byte per query kind, u64 LE integers, raw-label leaves, path bit `j` = bit `j - 1` of the leaf index (LSB at the root), no path sharing, the graph from `'G' || graph_seed || u64 v || u64 ctr` by rejection sampling (DRSample from ABH17 Algorithm 1) | adopted here whole; B1 owns the primitive and its fixtures | -| Figures | `tools/mhpow/b2/b2_figures.py` (sha256 7b8664ea44b770c9f6af246898aa576f3f0a63e65e7bf50a0b278c5727a1ee8b) | output `figures.txt` (sha256 27bb414c8534a438fdeae98cba2d4b9ece9c21d0487aa872673b0da465d9702a), run on build-9 under `/srv/builds/b2/b2-run.pid`: `python3 tools/mhpow/b2/b2_figures.py > docs/analysis/mhpow/b2/figures.txt` | +| The B4 theory lane's answers (a46974623d72b032c) | `docs/analysis/mhpow/b4/requirements.md` (branch mhpow-b4 6d9c14596) and `docs/analysis/mhpow/b4/README.md` section 5b (build/master 80b127484) | the B-T rows of section 4 and the lottery rule of O-17 | +| Figures | `tools/mhpow/b2/b2_figures.py` (sha256 742b64d9c2f3f8bad0524c9cdf38ac3aeff0c33bb14e000eb17b278053d79103) | output `figures.txt` (sha256 90e0f3932e2d915b7b1bcc958d5a2a74ccba55c2a3a37e71f53390b42bb7a022), run on build-9 under `/srv/builds/b2/b2-run.pid`: `python3 tools/mhpow/b2/b2_figures.py > docs/analysis/mhpow/b2/figures.txt` | ## 1. What the paper proves, and what it does not @@ -96,7 +97,7 @@ The oracle and the domain separation: | Merkle node | `tau_x = H('M', chi || tau_x0 || tau_x1)`; leaves are the raw labels, node `w` at leaf index `w - 1`; root `tau = tau_empty`; a reveal is the label and `n` siblings | section 4.1, Appendix C, salt `chi` | | Challenge | `c_i = int_le(H('C', chi || u64 i || tau)) mod N`, `i = 1 .. k`; open node `c_i + 1` and each parent, each with its own path | `c_i = H(chi, i, tau) mod N` | | Graph | DRSample, indeg 2, its draws from `H('G', graph_seed || u64 v || u64 ctr)` by rejection sampling; `graph_seed` a 32-byte public consensus constant, never `chi` | Fact 8; section 1.2 (the graph fixed a priori) | -| Lottery value | NONE in this draft (O-07) | the paper has none | +| Lottery value | `W = int_le(H('W', chi || tau)) <= target`, the winner verified IN FULL (O-17, B4's rule; the naive spot-check-only forms FAIL, O-07) | the paper has none | Every query is fixed width once the role and the node are known, which keeps Theorem 5's parse unique (the extractor reads the `h`-th parent at a fixed offset after `chi` and `v`). The role byte keeps the query families disjoint (B1's note: without it the challenge query `H(chi, i, tau)` has the shape of @@ -127,30 +128,33 @@ parameter choice (B3, B4) fill them. They are not conformance vectors; the B1 la | O-14 | Rejected trials and cancellation: a trial in flight when the template changes | the instance binds the parent set, so a new block on the network stales every trial in flight; the honest trial takes `O(N)` sequential rounds (Definition 5, item 1) | not a soundness matter; it is a feasibility bound: `N x t_seq <= rho x T_block`, with `T_block` 1 s on the devnet (spec 1.12) and `rho` the stale fraction the chain accepts. The bound caps `N`, and a small `N` fits one instance in SRAM, which is the B5 question | BLOCKED B-N2 (the node lane: `T_block` and `rho` on devnet-4) and B3 (`t_seq` measured, never assumed) | | O-15 | The frozen class stays the chain's binding: the dataset policy 70a6c703 and the signing id 2a1d6caab4c24564 | the instance carries `dataset_policy` (all 32 bytes), `program_id`, `epoch_seed`, `epoch_start_daa`, `era_seed`, `day_index` and `state_root`; the verifier recomputes each from the chain and the header and rejects a mismatch, so no certificate carries across a class object, a policy or an epoch | by construction plus O-01, O-03. Two facts for the node lane: the policy digest sits outside the consensus digest until the class v6 floor is set (f0 manifest), so the instance is the only place a certificate binds it today; and the day rule differs between `bind.rs` (the interim `timestamp_ms / 86,400,000`) and spec 1.12 (DAA seconds) | ANSWERED by construction, conditional on B-N1 and B-N3 | | O-16 | The epoch-seed lead and the day-pack: no precomputation across trials | the labelling needs `chi`, which needs the template's parents; the 600 DAA-second epoch-seed lead and the day key (known before the day) give no label in advance. Static per-day work (the v6 dataset) stays amortisable by design; the instance removes it from the MHPoW part only | O-03 | ANSWERED | +| O-17 | The lottery rule (B4-OB-LOT-1, this lane's row): B4's replacement for O-07, and the cost of a fake winner that passes the spot checks | trial id in `chi`; `W = H('W', chi || tau) <= target`; a winner is verified IN FULL (the verifier recomputes all `N` labels and the root, so `tau` is unique per `chi` and one draw costs one labelling); the `k` spot checks stay as the header pre-filter. The pre-filter does NOT price a fake: the prover keeps one honest labelling and re-rolls the red sink until `W` passes, about `(log2 N + 1) / p` calls a fake against `2N / p` for a real winner, and the fake passes the spot checks with `(1 - 1/N)^k`. Every validator it reaches then pays one full labelling (`2N` calls, `N` sequential steps) to reject it. An attacker with share `s` of the honest network's oracle calls makes `s x 2N / (log2 N + 1)` fakes per real block: 1.34 at `s = 10^-6`, 134 at `10^-4`, 13,400 at `10^-2` (`N = 2^24`, figures section 6 (a)). Per fake the attacker pays `(log2 N + 1) D / (2N)` of one validator's rejection cost (`D` labellings per block interval network-wide): 0.745 at `D = 10^6`, 74.5 at `10^8` (section 6 (b)), and every node the fake reaches pays it again | B4 README 5b says R1's theorem prices a spot-check-passing fake at the cmc bound. It does not: Theorem 7 is paid once per trace, and one trace yields fakes at the re-roll price (O-07, B1's fixture A6). The rule's soundness per draw is B4 Lemma C (NOT RUN) with AS15 per fully verified labelling | the rule ADOPTED as the draft binding (work version 1); the fake-winner budget is the open part: BLOCKED B-N4 and B4-OB-LOT-4 (B6) | ## 4. The BLOCKED questions, with their owners | Id | Owner | The exact question | |---|---|---| -| B-T1 | B4 theory lane (to be named) | For DRSample sampled from a fixed public seed at `N = 2^20` to `2^24`, what is the probability that the sampled graph is not `(c3 N / log N, c4 N)`-depth-robust, with the constants written out? Is a per-era re-seed from the era seed admissible, given that a party able to bias the era seed could search for a weak graph? | -| B-T2 | B4 | The values of `c3` and `c4` (Fact 8, from ABH17 or ABP17) for the sampled DRSample at the chosen `N`, proved, so that Corollary 3's bound and `k = 2 lambda log N / c3` become numbers. Without them every certificate size and every lower bound in this README is a sensitivity row. | -| B-T3 | B4 | The lottery. Give a lottery value `W` (or prove none exists) such that the expected number of distinct accepted pairs (`chi`, certificate) with `W` under the target, output by an adversary of cumulative memory `C`, is at most `C` divided by a constant fraction of Corollary 3's bound, with sampled verification of polylog cost. Known: any `W` that depends on labels the verifier samples can be re-rolled through an unchallenged node at the cost of that node's descendants (O-07 (a)); any `W` of `chi` alone is screened for free (O-07 (b)). Candidates for the panel: a succinct proof of the full labelling (a unique output, so Alwen and Serbinenko's bound per trial applies, at a prover cost the paper's own section 1 calls non-egalitarian); or a construction that is not MTP. | -| B-T4 | B4 | The adaptive-input version of Corollary 3: the adversary chooses `chi` among at most `q` candidates after querying `H`. State the loss in the bad-event sum. | -| B-T5 | B4 | The multi-instance version: producing accepted certificates for `m` distinct inputs costs at least `m (lambda/4)(c3 c4 / 2) N^2 / log N` except with what probability, and how the `q` and `t` terms scale with `m`. | -| B-T6 | B4 | The label width `lambda` for an adversary of `q = 2^64` to `2^96` queries: either `lambda >= 8 log2 q + 4` under Lemma 3 as stated (516 to 772 bits, so an XOF in place of BLAKE2b's 512-bit maximum), or a tighter statement of Theorem 6 with the charge `lambda - 2 log2 q - log2 indeg` per pebble at `lambda = 256`. | -| B-T7 | B4 | Confirm that no step in Theorems 4 to 7 or Lemmas 2 to 4 uses a coincidence between a label query and a Merkle or challenge query that the role byte would remove (the role byte only splits the domain; the check is that the extractor's hint and parse still hold). | -| B-T8 | B4 with the adversary lane | The translation from cumulative memory to energy and bandwidth (the plan's R2, R3), including the full-SRAM design at the `N` that O-14 allows. | +| B-T1 | B4 theory lane a46974623d72b032c | STILL BLOCKED (B4-B01: ABH17 not fetched by B4; B1 holds the archived ABH17, eprint 2017/443, sha256 f8e08d36...). For DRSample sampled from a fixed public seed at `N = 2^20` to `2^24`, what is the probability that the sampled graph is not `(c3 N / log N, c4 N)`-depth-robust, with the constants written out? Is a per-era re-seed from the era seed admissible, given that a party able to bias the era seed could search for a weak graph? | +| B-T2 | B4 | STILL BLOCKED (B4-B03). The values of `c3` and `c4` (Fact 8, from ABH17 or ABP17) for the sampled DRSample at the chosen `N`, proved, so that Corollary 3's bound and `k = 2 lambda log N / c3` become numbers. Without them every certificate size and every lower bound in this README is a sensitivity row. | +| B-T3 | B4 | ANSWERED IN SHAPE by B4 Lemma C (NOT RUN): no `W` with polylog sampled verification meets the bound inside MTP; the replacement is full verification of winners, adopted here as O-17, whose fake-winner budget stays open. The lottery. Give a lottery value `W` (or prove none exists) such that the expected number of distinct accepted pairs (`chi`, certificate) with `W` under the target, output by an adversary of cumulative memory `C`, is at most `C` divided by a constant fraction of Corollary 3's bound, with sampled verification of polylog cost. Known: any `W` that depends on labels the verifier samples can be re-rolled through an unchallenged node at the cost of that node's descendants (O-07 (a)); any `W` of `chi` alone is screened for free (O-07 (b)). Candidates for the panel: a succinct proof of the full labelling (a unique output, so Alwen and Serbinenko's bound per trial applies, at a prover cost the paper's own section 1 calls non-egalitarian); or a construction that is not MTP. | +| B-T4 | B4 | ANSWERED AS A LOSS by B4 (NOT RUN): MISCOLOR becomes `q N 2^-lambda`; the other bad events are already unions over the trace. The adaptive-input version of Corollary 3: the adversary chooses `chi` among at most `q` candidates after querying `H`. State the loss in the bad-event sum. | +| B-T5 | B4 | STILL BLOCKED (B4-OB-LOT-3; the union-graph route, MISCOLOR `J N 2^-lambda`, proof not written). The multi-instance version: producing accepted certificates for `m` distinct inputs costs at least `m (lambda/4)(c3 c4 / 2) N^2 / log N` except with what probability, and how the `q` and `t` terms scale with `m`. | +| B-T6 | B4 | ANSWERED AS A CONSTRAINT by B4: `w >= 8 log2 q + 4`, or R2 Theorem 3.3's `w > 20 log2 q` (1,280 bits at `q = 2^64`); labels of 1 KiB or more meet both, through an XOF or R16's permutation. The instance's `label_bytes` field carries it; `chi` and every fixture move with it. The label width `lambda` for an adversary of `q = 2^64` to `2^96` queries: either `lambda >= 8 log2 q + 4` under Lemma 3 as stated (516 to 772 bits, so an XOF in place of BLAKE2b's 512-bit maximum), or a tighter statement of Theorem 6 with the charge `lambda - 2 log2 q - log2 indeg` per pebble at `lambda = 256`. | +| B-T7 | B4 | ANSWERED BY READING by B4 (not a proof audit): the role byte only shifts offsets, and Theorem 4's Merkle trace needs exactly that form separation. Confirm that no step in Theorems 4 to 7 or Lemmas 2 to 4 uses a coincidence between a label query and a Merkle or challenge query that the role byte would remove (the role byte only splits the domain; the check is that the extractor's hint and parse still hold). | +| B-T8 | B4 with the adversary lane | ANSWERED by B4 README sections 5, 7, 8 and its Q5: the window `log2 N x M_SRAM / C <= N b <= b rho / t_seq` may be empty for DRSample. The translation from cumulative memory to energy and bandwidth (the plan's R2, R3), including the full-SRAM design at the `N` that O-14 allows. | | B-N1 | node lane a283f5f0d364ceef0 | Which day rule is live on devnet-4 (`bind.rs`'s timestamp day or spec 1.12's DAA day), and the rule the verifier uses to recompute `epoch_seed`, `epoch_start_daa`, `era_seed`, `program_id` and the policy digest from a header and the chain. | | B-N2 | node lane | The block interval on devnet-4, the timestamp acceptance window (past median and future bound), and the stale fraction the chain accepts, so O-14's bound on `N x t_seq` is a number. | +| B-N4 | node lane with B6 | O-17's fake-winner budget at the network's scale: does a block that fails full verification cost its sender (peer score, ban, a relay rule of full verification before forwarding), and what full verifications per second per node can the chain absorb before the 1.34-fakes-per-block attacker at `s = 10^-6` (`N = 2^24`) stalls validation? | | B-N3 | node lane | The 32 bytes of the state stream root the class v6 dataset is keyed on for the signing pair (epoch af89be5d, era edc4fa84, day 20730), and whether that root is in the header's past by the epoch boundary. | ## 5. What this means for Track B 1. The input binding is complete for reuse: no certificate carries across a template, a trial, an epoch, a day, an era, a network or a class object (O-01 to O-04, O-15, O-16). -2. The economic binding is not: the reference construction has no lottery, and the two direct ways to add one either buy about a - million draws per labelling at `N = 2^24` or screen trials for free (O-07). Until B-T3 is answered, an MTP certificate per - block adds memory work per block, never per lottery trial, and cannot move the 1.5x ratio. +2. The economic binding is not in the paper: the reference construction has no lottery, and the two direct ways to add one either + buy about a million draws per labelling at `N = 2^24` or screen trials for free (O-07). B4's rule (O-17: full verification of + winners) restores one labelling per draw, at a price: a fake winner costs about a millionth of a real one and costs every + validator a full labelling, so the rule is adopted as the draft and its denial-of-service budget is the open row (B-N4). 3. Binding the template forces each trial to finish inside a fraction of the block interval (O-14), which caps `N` and pushes the instance toward a size that fits in SRAM. B3 and B5 own that collision; it is recorded here because the binding causes it. 4. Even granted a lottery, the proved bound sits a factor `4 log N / (c3 c4)` under the honest prover's cumulative memory with diff --git a/docs/analysis/mhpow/b2/figures.txt b/docs/analysis/mhpow/b2/figures.txt index 652bcd7fa..12b68683e 100644 --- a/docs/analysis/mhpow/b2/figures.txt +++ b/docs/analysis/mhpow/b2/figures.txt @@ -94,3 +94,25 @@ log2_N k honest_calls_per_trial reroll_calls_per_draw amortisation pass_probabil 20 9000 2097152 21 9.99e+04 0.991454 24 2000 33554432 25 1.34e+06 0.999881 24 9000 33554432 25 1.34e+06 0.999464 + +== 6. O-17: the fake-winner budget under B4's rule (trial id in chi, W = H(lot, chi, tau), winners verified in full, + the k spot checks as the header pre-filter). A fake winner keeps ONE honest labelling and re-rolls the red sink until + W <= target: about (log2 N + 1) / p calls per fake once the labelling exists; it passes the spot checks with (1 - 1/N)^k; + every validator it reaches recomputes the labelling in full (2N calls, N sequential label steps) before rejecting it. + A real winner costs 2N / p calls. p = 1 / D, D = labellings per block interval network-wide. + (a) fakes per real block for an attacker holding share s of the honest network's oracle calls: s * 2N / (log2 N + 1) +log2_N share fakes_per_real_block +20 1e-06 0.0999 +20 0.0001 9.99 +20 0.01 999 +24 1e-06 1.34 +24 0.0001 134 +24 0.01 1.34e+04 + (b) attacker calls per fake / one validator's calls to reject it: (log2 N + 1) D / (2N) +log2_N D attacker_over_validator +20 10000 0.1 +20 1e+06 10 +20 1e+08 1e+03 +24 10000 0.00745 +24 1e+06 0.745 +24 1e+08 74.5 diff --git a/docs/analysis/mhpow/b2/registry-batch-mhpow-b2-20261009-01.json b/docs/analysis/mhpow/b2/registry-batch-mhpow-b2-20261009-01.json index 1690e6867..69aae052d 100644 --- a/docs/analysis/mhpow/b2/registry-batch-mhpow-b2-20261009-01.json +++ b/docs/analysis/mhpow/b2/registry-batch-mhpow-b2-20261009-01.json @@ -14,14 +14,14 @@ "status": "NOT RUN", "method": "model", "evidence": "docs/analysis/mhpow/b2/README.md", - "note": "POW-05: obligations O-06 to O-11 and O-16 (grinding, chosen instance, amortisation, partial evaluation, precomputation); O-07 records two FAIL rules and B-T3 the open question. POW-06: O-11's certificate sizes as functions of DRSample's unproved constant c3 (13.6 to 194.9 MiB at lambda 256), a sensitivity table only; the verifier budget is B6's.", + "note": "POW-05: obligations O-06 to O-11 and O-16 (grinding, chosen instance, amortisation, partial evaluation, precomputation); O-07 records two FAIL rules (B1's fixture A6 executes the first); O-17 adopts B4's full-verification rule with its fake-winner budget open (B-N4). POW-06: O-11's certificate sizes as functions of DRSample's unproved constant c3 (13.6 to 194.9 MiB at lambda 256), a sensitivity table only; the verifier budget is B6's.", "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", "in_progress": true } ], "map_cell_requested": { "model:mhpow-b2-binding": { - "command": "python3 tools/mhpow/b2/b2_figures.py > docs/analysis/mhpow/b2/figures.txt (a build box under a pid file; byte-identical output, sha256 27bb414c...)", + "command": "python3 tools/mhpow/b2/b2_figures.py > docs/analysis/mhpow/b2/figures.txt (a build box under a pid file; byte-identical output, sha256 90e0f393...)", "box_class": "build box, CPU only (build-9)", "fixtures": [], "cases": [ diff --git a/tools/mhpow/b2/b2_figures.py b/tools/mhpow/b2/b2_figures.py index 50c7f58e2..0240f150a 100644 --- a/tools/mhpow/b2/b2_figures.py +++ b/tools/mhpow/b2/b2_figures.py @@ -12,7 +12,8 @@ Sections: 3. Lemma 3's precondition lambda/4 >= 2 log2 q + log2 indeg and the per-pebble charge lambda - 2 log2 q - log2 indeg (the extractor's bound before the paper rounds it to lambda/4); 4. Corollary 2's challenge count and the certificate size, as functions of DRSample's unproved constant c3; - 5. the lottery re-roll counter-example (obligation O-07): honest oracle calls per trial against the re-roll's. + 5. the lottery re-roll counter-example (obligation O-07): honest oracle calls per trial against the re-roll's; + 6. O-17, the fake-winner budget under B4's full-verification rule (B4-OB-LOT-1). Nothing here is a measurement. Every row is arithmetic on the paper's statements (eprint 2025/1456, the copy with sha256 13c3646e7d85c1aa58a92914582caab5798d90cf2a3cad33e58d81d49c1d31db) and on the draft layout. @@ -213,12 +214,34 @@ def section5(): print(f"{ln}\t{k}\t{honest}\t{reroll}\t{honest / reroll:.3g}\t{p:.6f}") +def section6(): + print() + print("== 6. O-17: the fake-winner budget under B4's rule (trial id in chi, W = H(lot, chi, tau), winners verified in full,") + print(" the k spot checks as the header pre-filter). A fake winner keeps ONE honest labelling and re-rolls the red sink until") + print(" W <= target: about (log2 N + 1) / p calls per fake once the labelling exists; it passes the spot checks with (1 - 1/N)^k;") + print(" every validator it reaches recomputes the labelling in full (2N calls, N sequential label steps) before rejecting it.") + print(" A real winner costs 2N / p calls. p = 1 / D, D = labellings per block interval network-wide.") + print(" (a) fakes per real block for an attacker holding share s of the honest network's oracle calls: s * 2N / (log2 N + 1)") + print("log2_N\tshare\tfakes_per_real_block") + for ln in (20, 24): + n = 2 ** ln + for share in (1e-6, 1e-4, 1e-2): + print(f"{ln}\t{share:g}\t{share * 2 * n / (ln + 1):.3g}") + print(" (b) attacker calls per fake / one validator's calls to reject it: (log2 N + 1) D / (2N)") + print("log2_N\tD\tattacker_over_validator") + for ln in (20, 24): + n = 2 ** ln + for d in (1e4, 1e6, 1e8): + print(f"{ln}\t{d:g}\t{(ln + 1) * d / (2 * n):.3g}") + + def main(): total = section1() section2(total) section3() section4() section5() + section6() return 0 From af7124c99df35d84cb56009c7399b8ab95bea468 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:58:12 +0000 Subject: [PATCH 18/19] R15 rows opened on main's orders: B1's reference batch recorded as the lane wrote it and the steward's R15-05 row carrying F-3 (BOUND) and F-4; the int8-dominated class's cell (class:int8 on R15-03 and R15-04, three weights and the ARX-only points, nothing measured yet); X7's memory-route verdict as a BOUND-side negative control under R15-02 (f 0.854 on the 4090, s 13 to 39), X8 to follow at its landing; every row NOT RUN; cells carried in the batches Co-Authored-By: Claude Fable 5.1 --- docs/plans/igneum-2.0-test-harness-map.md | 41 ++- docs/plans/igneum-2.0-test-registry.json | 329 ++++++++++++------ tools/ci/batches/mhpow-b1-20261009-01.json | 42 +++ tools/ci/batches/r15-02-x7-20261009-01.json | 48 +++ tools/ci/batches/r15-int8-20261009-01.json | 49 +++ tools/ci/batches/r15-track-b-20261009-02.json | 48 +++ tools/ci/test-map.json | 61 +++- 7 files changed, 498 insertions(+), 120 deletions(-) create mode 100644 tools/ci/batches/mhpow-b1-20261009-01.json create mode 100644 tools/ci/batches/r15-02-x7-20261009-01.json create mode 100644 tools/ci/batches/r15-int8-20261009-01.json create mode 100644 tools/ci/batches/r15-track-b-20261009-02.json diff --git a/docs/plans/igneum-2.0-test-harness-map.md b/docs/plans/igneum-2.0-test-harness-map.md index 158c37ddd..19b625fcf 100644 --- a/docs/plans/igneum-2.0-test-harness-map.md +++ b/docs/plans/igneum-2.0-test-harness-map.md @@ -483,6 +483,40 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - Cases: - TV-02 Reproduce complete supply accounting: partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it +### model:mhpow-b1-reference + +- Command: `tools/mhpow/b1/run-b1.sh all (a build box under its pid file; kat, attack and k-table files byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS)` +- Box class: build box, CPU only (build-6) +- Fixtures: tools/mhpow/b1/fixtures/ +- Cases: + - POW-05 Prevent amortised cheap winning attempts: partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's + - POW-06 Bound verifier work and malformed-input cost: partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing + +### theory:r15-05-track-b + +- Command: `the Track B cryptography read: docs/analysis/mhpow/b1 (the exact CPU reference of the MTP framework over DRSample, its verifier and the six malicious provers) by tools/mhpow/b1/run-b1.sh all on a build box under a pid file, outputs byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS` +- Box class: build box, CPU only +- Fixtures: tools/mhpow/b1/fixtures/ +- Cases: + - R15-05 R15-05: Cryptography: partial: the published primitive's reference, attacks and verifier refusals; the lottery binding (B2), the composed theorem (B4) and the panel's reading open + +### class:int8 + +- Command: `the int8-dominated research class: cut behind the research flag by the research lane at int8-50, int8-75, int8-90 and arx-16, arx-32 (igneum-pow export with the class string, on a build box); the hash lane's card rows in the P04 form (tools/1p5x/x1/gpu-pairs.sh, gpu-rows.py); the adversary lane's chip rows (tools/1p5x/x5/sweep.py, tools/1p5x/x8/mac.py); the census instruments (igneum-pow addrsite, x1cache)` +- Box class: build box for the cut and the census; rented pods for the card rows; a build box for the chip model +- Fixtures: F0 +- Cases: + - R15-03 R15-03: GPU + memory analysis: partial: the held-out cache curves of each weight against the frozen control; the layer-8-off control is X1's row + - R15-04 R15-04: GPU systems: partial: byte agreement and accepted-work savings of each weight's fold; X2 to X4's rows carry the rest + +### model:x7-memory-route + +- Command: `the X7 memory-route read: docs/analysis/class-v6/1p5x/x7 (the chip model's s on GDDR7, HBM3 and near-memory by tools/1p5x/x5/sweep.py on a build box under a pid file) against the hash lane's read-only twin row on a rented card at stock (the frozen object and its read-only twin, nvidia-smi beside it)` +- Box class: a build box for the model; a rented card for the twin row +- Fixtures: F0 +- Cases: + - R15-02 R15-02: GPU + hardware: partial: the memory route's f and s only; the component power and traffic model and its sensitivity are X0's and X5's rows + ## Automated cases with no harness in the matrix (NOT RUN, the reason) - GOV-02 Approve thresholds before results: the approval is recorded in the registry's approval field; the automated half (thresholds frozen before any run_status) is the gate rule landing by 21:00 @@ -491,7 +525,6 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - GPU-04 Find the memory-clock operating ladder: the memory-clock ladder has no harness tonight: the project's own rig mines nothing under the the earlier devnet off order - GPU-06 Measure accepted work under ordinary connectivity: accepted work under ordinary connectivity needs the fault network F4 - GPU-07 Survive sustained thermal and power operation: the sustained thermal and power soak has no harness tonight: the project's own rig mines nothing under the the earlier devnet off order -- POW-05 Prevent amortised cheap winning attempts: amortised cheap winning attempts are the attack lanes' grind and era harnesses (tools/attack/f7-era, f9-grind), not in the release matrix; their rows come from those lanes - ROT-03 Test miner-voted bring-forward governance: miner-voted bring-forward needs a vote harness on the fault network F4 - ROT-04 Resist seed selection and faster evaluators: seed-selection resistance is the census harness (the class v6 invention lane), not yet in the matrix - EVM-01 Match the selected EVM semantics: no EVM conformance-vector harness is mapped tonight; the exec suite does not run the reference test vectors @@ -655,10 +688,6 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover - TV-31 Public-claim and activity review: TV-31 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Qualified counsel); a supplemental layer, never counted as independent evidence; not yet named in the map - TV-32 Observed leadership, not a roadmap certificate: TV-32 (token value gate, scope LEADERSHIP CLAIM): no gate executed; the harness is the owner role's (Independent acceptance panel); a supplemental layer, never counted as independent evidence; not yet named in the map - R15-01 R15-01: Release + measurement: R15-01 (1.5x programme package): no package executed; the harness is the lane's (X0); its batch names the case when it lands; not yet named in the map -- R15-02 R15-02: GPU + hardware: R15-02 (1.5x programme package): no package executed; the harness is the lane's (X0, X5); its batch names the case when it lands; not yet named in the map -- R15-03 R15-03: GPU + memory analysis: R15-03 (1.5x programme package): no package executed; the harness is the lane's (X1); its batch names the case when it lands; not yet named in the map -- R15-04 R15-04: GPU systems: R15-04 (1.5x programme package): no package executed; the harness is the lane's (X2, X3, X4); its batch names the case when it lands; not yet named in the map -- R15-05 R15-05: Cryptography: R15-05 (1.5x programme package): no package executed; the harness is the lane's (B1); its batch names the case when it lands; not yet named in the map - R15-06 R15-06: GPU + cryptography: R15-06 (1.5x programme package): no package executed; the harness is the lane's (B3); its batch names the case when it lands; not yet named in the map - R15-07 R15-07: Cryptography + hardware: R15-07 (1.5x programme package): no package executed; the harness is the lane's (B2, B4); its batch names the case when it lands; not yet named in the map - R15-08 R15-08: Independent ASIC team: R15-08 (1.5x programme package): no package executed; the harness is the lane's (X5, B5); its batch names the case when it lands; not yet named in the map @@ -667,4 +696,4 @@ Rule: a case maps to a cell only where the cell's tests visibly answer it; cover ## Count -213 automated cases: 92 mapped to a cell, 179 NOT RUN with a reason. +213 automated cases: 97 mapped to a cell, 174 NOT RUN with a reason. diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 017d79c89..0e7ecea06 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -2016,25 +2016,31 @@ "manual_page": 25, "owner_lane": "pool design seat (a3832b1c3b274b310)", "run_status": "NOT RUN", - "evidence_path": "docs/analysis/binding-review-2026-10.md (sections 1 to 5a; master ad5a54c5)", - "run_id": "binding-review-2026-10-08-a05", - "updated": "2026-10-08T20:10:24.556Z", + "evidence_path": "docs/analysis/binding-review-2026-10.md (sections 1 to 5a; master ad5a54c5); docs/analysis/mhpow/b1/README.md", + "run_id": "mhpow-b1-20261009-01", + "updated": "2026-10-09T09:58:05.125Z", "evidence_record": { - "reason": "amortised cheap winning attempts are the attack lanes' grind and era harnesses (tools/attack/f7-era, f9-grind), not in the release matrix; their rows come from those lanes", - "at": "2026-10-08T20:10:24.556Z", - "method": "static", "requirement_id": "POW-05", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "model:mhpow-b1-reference", + "manifest_sha": "13c3646e", + "run_id": "mhpow-b1-20261009-01", + "evidence": "docs/analysis/mhpow/b1/README.md", + "in_progress": true, + "coverage": "partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's", "release_identity": { - "commit": "", + "commit": "13c3646e", "lockfile": "", "binary": "", "network_object": "", "activation": "", "profile_hashes": "" - } + }, + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "reviewer": "", + "at": "2026-10-09T09:58:05.125Z", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11). | B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS." }, "status_note": "REVIEWED: fixed by construction (binding), not applicable (final digest); native tests ok on build-2; no change for 2.0", "approvals": { @@ -2065,8 +2071,32 @@ "run_id": "binding-review-2026-10-08-a05", "evidence": "docs/analysis/binding-review-2026-10.md (sections 1 to 5a; master ad5a54c5)", "in_progress": false + }, + "model:mhpow-b1-reference": { + "requirement_id": "POW-05", + "decision": "NOT RUN", + "method": "model", + "cell": "model:mhpow-b1-reference", + "manifest_sha": "13c3646e", + "run_id": "mhpow-b1-20261009-01", + "evidence": "docs/analysis/mhpow/b1/README.md", + "in_progress": true, + "coverage": "partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's", + "release_identity": { + "commit": "13c3646e", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + }, + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "reviewer": "", + "at": "2026-10-09T09:58:05.125Z", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11). | B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS." } - } + }, + "in_progress_since": "2026-10-09T09:58:05.125Z" }, { "id": "POW-06", @@ -2095,29 +2125,31 @@ "manual_page": 25, "owner_lane": "hash lane (a690540514aa453d7)", "run_status": "NOT RUN", - "evidence_path": "build-1:/srv/artefacts/tas/p01-partb-20261008-01/summary.jsonl", - "run_id": "p01-partb-20261008-01", - "updated": "2026-10-08T18:28:32.463Z", + "evidence_path": "build-1:/srv/artefacts/tas/p01-partb-20261008-01/summary.jsonl; docs/analysis/mhpow/b1/README.md", + "run_id": "mhpow-b1-20261009-01", + "updated": "2026-10-09T09:58:05.125Z", "evidence_record": { - "cell": "harness:parser-malformed", - "manifest_sha": "417c4a57", - "coverage": { - "POW-06": "partial: three parsers of external bytes (the state stream, the igneum_ RPC params, the pool job line), ten thousand seeded malformed cases each, zero panics, every case under 500 ms (the slowest 152 microseconds); 'accepted' counts mutations that left a valid input, not a parser fault; the verifier work bound (the other half of the accept text) is the proving lane's measurement" - }, - "at": "2026-10-08T18:28:32.463Z", - "method": "static", "requirement_id": "POW-06", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "model:mhpow-b1-reference", + "manifest_sha": "13c3646e", + "run_id": "mhpow-b1-20261009-01", + "evidence": "docs/analysis/mhpow/b1/README.md", + "in_progress": true, + "coverage": "partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing", "release_identity": { - "commit": "417c4a57", + "commit": "13c3646e", "lockfile": "", "binary": "", "network_object": "", "activation": "", "profile_hashes": "" - } + }, + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "reviewer": "", + "at": "2026-10-09T09:58:05.125Z", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11). | B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS." }, "in_progress_since": "2026-10-08T18:28:32.463Z", "approvals": { @@ -2150,6 +2182,29 @@ "run_id": "p01-partb-20261008-01", "evidence": "build-1:/srv/artefacts/tas/p01-partb-20261008-01/summary.jsonl", "in_progress": true + }, + "model:mhpow-b1-reference": { + "requirement_id": "POW-06", + "decision": "NOT RUN", + "method": "model", + "cell": "model:mhpow-b1-reference", + "manifest_sha": "13c3646e", + "run_id": "mhpow-b1-20261009-01", + "evidence": "docs/analysis/mhpow/b1/README.md", + "in_progress": true, + "coverage": "partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing", + "release_identity": { + "commit": "13c3646e", + "lockfile": "", + "binary": "", + "network_object": "", + "activation": "", + "profile_hashes": "" + }, + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "reviewer": "", + "at": "2026-10-09T09:58:05.125Z", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11). | B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS." } } }, @@ -20321,42 +20376,53 @@ "manual_page": null, "run_status": "NOT RUN", "plan_status": "NOT RUN", - "updated": "2026-10-09T09:19:24.923Z", + "updated": "2026-10-09T09:58:05.337Z", "evidence_record": { - "reason": "R15-02 (1.5x programme package): no package executed; the harness is the lane's (X0, X5); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", "requirement_id": "R15-02", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "model:x7-memory-route", + "manifest_sha": "6ba3f01b", + "run_id": "r15-02-x7-20261009-01", + "evidence": "docs/analysis/class-v6/1p5x/x7/README.md; tools/ci/batches/adversary-20261009-x7.json", + "in_progress": true, + "coverage": "partial: the memory route's f and s only; the component power and traffic model and its sensitivity are X0's and X5's rows", "release_identity": { - "commit": "", + "commit": "master 6ba3f01b (the X7 README; the verdict commit ca2fb6b2 and X8's rows e64eb265 cited when the landing hand lands them)", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" - } + }, + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.337Z", + "note": "BOUND-side negative control (X7): f = 0.854 on the 4090 at stock, the frozen object at 8,077 nJ per hash against its read-only twin at 6,899 at the same rate (the hash lane's row, fk-x7-4090, 10:44 UK); s = 13 to 39 on the chip's GDDR7, HBM3 and near-memory (the adversary lane's X7 rows): no read-dominated design reaches 1.5x or 1.25x at any f, because the card's random-read path is its least efficient part against a chip. The chip figures are modelled (BOUND); the card figure is a WITNESS on a named rented card. X8's chip side (every int8 mix raising the ratio against a systolic array; the dp4a-only cells stopping at 1.54x) is the tensor route's first witness row set, pending the hash lane's measured card rows; recorded here when e64eb265 lands. R15-02 (no device or whole-machine boundary mismatch) stays NOT RUN until read | main's order through the coordinator (11:0x UK, 9 October 2026): X7's memory-route verdict recorded as a BOUND-side negative control under R15-02, NOT RUN; X8's tensor-route chip rows join when they land and the hash lane's measured card rows arrive" }, "evidence_records": { - "record": { - "reason": "R15-02 (1.5x programme package): no package executed; the harness is the lane's (X0, X5); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", + "model:x7-memory-route": { "requirement_id": "R15-02", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "model:x7-memory-route", + "manifest_sha": "6ba3f01b", + "run_id": "r15-02-x7-20261009-01", + "evidence": "docs/analysis/class-v6/1p5x/x7/README.md; tools/ci/batches/adversary-20261009-x7.json", + "in_progress": true, + "coverage": "partial: the memory route's f and s only; the component power and traffic model and its sensitivity are X0's and X5's rows", "release_identity": { - "commit": "", + "commit": "master 6ba3f01b (the X7 README; the verdict commit ca2fb6b2 and X8's rows e64eb265 cited when the landing hand lands them)", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" }, - "in_progress": false + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.337Z", + "note": "BOUND-side negative control (X7): f = 0.854 on the 4090 at stock, the frozen object at 8,077 nJ per hash against its read-only twin at 6,899 at the same rate (the hash lane's row, fk-x7-4090, 10:44 UK); s = 13 to 39 on the chip's GDDR7, HBM3 and near-memory (the adversary lane's X7 rows): no read-dominated design reaches 1.5x or 1.25x at any f, because the card's random-read path is its least efficient part against a chip. The chip figures are modelled (BOUND); the card figure is a WITNESS on a named rented card. X8's chip side (every int8 mix raising the ratio against a systolic array; the dp4a-only cells stopping at 1.54x) is the tensor route's first witness row set, pending the hash lane's measured card rows; recorded here when e64eb265 lands. R15-02 (no device or whole-machine boundary mismatch) stays NOT RUN until read | main's order through the coordinator (11:0x UK, 9 October 2026): X7's memory-route verdict recorded as a BOUND-side negative control under R15-02, NOT RUN; X8's tensor-route chip rows join when they land and the hash lane's measured card rows arrive" } }, "approvals": { @@ -20364,7 +20430,10 @@ "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "run_id": "r15-02-x7-20261009-01", + "evidence_path": "docs/analysis/class-v6/1p5x/x7/README.md; tools/ci/batches/adversary-20261009-x7.json", + "in_progress_since": "2026-10-09T09:58:05.337Z" }, { "id": "R15-03", @@ -20397,42 +20466,53 @@ "manual_page": null, "run_status": "NOT RUN", "plan_status": "NOT RUN", - "updated": "2026-10-09T09:19:24.923Z", + "updated": "2026-10-09T09:58:05.266Z", "evidence_record": { - "reason": "R15-03 (1.5x programme package): no package executed; the harness is the lane's (X1); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", "requirement_id": "R15-03", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "class:int8", + "manifest_sha": "d799c086", + "run_id": "r15-int8-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress": true, + "coverage": "partial: the held-out cache curves of each weight against the frozen control; the layer-8-off control is X1's row", "release_identity": { - "commit": "", + "commit": "master d799c086; the class is cut by the research lane behind a research flag, not in any release", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" - } + }, + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.266Z", + "note": "opened, nothing measured yet: the int8-dominated class behind a research flag at three weights (int8-50, int8-75, int8-90) and the ARX-only points (arx-16, arx-32); the research lane cuts the class, the hash lane measures the card rows, the adversary lane the chip rows, the census instruments read it; R15-03 (layer-8-off control and held-out cache curves) and R15-04 (compaction, exact-fold alternatives, tuning) take their rows from those batches | main's order through the coordinator (11:0x UK, 9 October 2026): the cells for the int8-dominated class opened, every row NOT RUN until read; the lanes land their own batches on these cells with map_cell_requested" }, "evidence_records": { - "record": { - "reason": "R15-03 (1.5x programme package): no package executed; the harness is the lane's (X1); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", + "class:int8": { "requirement_id": "R15-03", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "class:int8", + "manifest_sha": "d799c086", + "run_id": "r15-int8-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress": true, + "coverage": "partial: the held-out cache curves of each weight against the frozen control; the layer-8-off control is X1's row", "release_identity": { - "commit": "", + "commit": "master d799c086; the class is cut by the research lane behind a research flag, not in any release", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" }, - "in_progress": false + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.266Z", + "note": "opened, nothing measured yet: the int8-dominated class behind a research flag at three weights (int8-50, int8-75, int8-90) and the ARX-only points (arx-16, arx-32); the research lane cuts the class, the hash lane measures the card rows, the adversary lane the chip rows, the census instruments read it; R15-03 (layer-8-off control and held-out cache curves) and R15-04 (compaction, exact-fold alternatives, tuning) take their rows from those batches | main's order through the coordinator (11:0x UK, 9 October 2026): the cells for the int8-dominated class opened, every row NOT RUN until read; the lanes land their own batches on these cells with map_cell_requested" } }, "approvals": { @@ -20440,7 +20520,10 @@ "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "run_id": "r15-int8-20261009-01", + "evidence_path": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress_since": "2026-10-09T09:58:05.266Z" }, { "id": "R15-04", @@ -20483,42 +20566,53 @@ "manual_page": null, "run_status": "NOT RUN", "plan_status": "NOT RUN", - "updated": "2026-10-09T09:19:24.923Z", + "updated": "2026-10-09T09:58:05.266Z", "evidence_record": { - "reason": "R15-04 (1.5x programme package): no package executed; the harness is the lane's (X2, X3, X4); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", "requirement_id": "R15-04", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "class:int8", + "manifest_sha": "d799c086", + "run_id": "r15-int8-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress": true, + "coverage": "partial: byte agreement and accepted-work savings of each weight's fold; X2 to X4's rows carry the rest", "release_identity": { - "commit": "", + "commit": "master d799c086; the class is cut by the research lane behind a research flag, not in any release", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" - } + }, + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.266Z", + "note": "opened, nothing measured yet: the int8-dominated class behind a research flag at three weights (int8-50, int8-75, int8-90) and the ARX-only points (arx-16, arx-32); the research lane cuts the class, the hash lane measures the card rows, the adversary lane the chip rows, the census instruments read it; R15-03 (layer-8-off control and held-out cache curves) and R15-04 (compaction, exact-fold alternatives, tuning) take their rows from those batches | main's order through the coordinator (11:0x UK, 9 October 2026): the cells for the int8-dominated class opened, every row NOT RUN until read; the lanes land their own batches on these cells with map_cell_requested" }, "evidence_records": { - "record": { - "reason": "R15-04 (1.5x programme package): no package executed; the harness is the lane's (X2, X3, X4); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", + "class:int8": { "requirement_id": "R15-04", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "class:int8", + "manifest_sha": "d799c086", + "run_id": "r15-int8-20261009-01", + "evidence": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress": true, + "coverage": "partial: byte agreement and accepted-work savings of each weight's fold; X2 to X4's rows carry the rest", "release_identity": { - "commit": "", + "commit": "master d799c086; the class is cut by the research lane behind a research flag, not in any release", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" }, - "in_progress": false + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.266Z", + "note": "opened, nothing measured yet: the int8-dominated class behind a research flag at three weights (int8-50, int8-75, int8-90) and the ARX-only points (arx-16, arx-32); the research lane cuts the class, the hash lane measures the card rows, the adversary lane the chip rows, the census instruments read it; R15-03 (layer-8-off control and held-out cache curves) and R15-04 (compaction, exact-fold alternatives, tuning) take their rows from those batches | main's order through the coordinator (11:0x UK, 9 October 2026): the cells for the int8-dominated class opened, every row NOT RUN until read; the lanes land their own batches on these cells with map_cell_requested" } }, "approvals": { @@ -20526,7 +20620,10 @@ "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "run_id": "r15-int8-20261009-01", + "evidence_path": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "in_progress_since": "2026-10-09T09:58:05.266Z" }, { "id": "R15-05", @@ -20559,42 +20656,53 @@ "manual_page": null, "run_status": "NOT RUN", "plan_status": "NOT RUN", - "updated": "2026-10-09T09:19:24.923Z", + "updated": "2026-10-09T09:58:05.196Z", "evidence_record": { - "reason": "R15-05 (1.5x programme package): no package executed; the harness is the lane's (B1); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", "requirement_id": "R15-05", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "theory:r15-05-track-b", + "manifest_sha": "0f370527", + "run_id": "r15-track-b-20261009-02", + "evidence": "docs/analysis/mhpow/b1/README.md; tools/mhpow/b1/fixtures/attacks-n10-k16.json; tools/mhpow/b1/fixtures/SHA256SUMS", + "in_progress": true, + "coverage": "partial: the published primitive's reference, attacks and verifier refusals; the lottery binding (B2), the composed theorem (B4) and the panel's reading open", "release_identity": { - "commit": "", + "commit": "master 0f370527 (B1 e9f94df6 landed)", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" - } + }, + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.196Z", + "note": "BOUND (B1, F-3): with ABH17's proven constant the paper's challenge count k exceeds N at lambda 256 and N 2^20 (to about n 25): no practical parameter in the proven regime. FINDING (B1, F-4): one labelling yields 193 to 200 accepted roots in 200 tries at 26 oracle calls per try, so a lottery over tau is not bound to the labelling cost (fixture A6, attacks-n10-k16.json, run on build-6). The package R15-05 (no improvised sampled-memory soundness) stays NOT RUN until the independent panel reads the reference and its verifier (17 of 17 named checks with known-failed tests) | the coordinator's order (10:4x UK, 9 October 2026): Track B's reproduction findings as BOUND rows, NOT RUN, no pass or fail claimed for the package" }, "evidence_records": { - "record": { - "reason": "R15-05 (1.5x programme package): no package executed; the harness is the lane's (B1); its batch names the case when it lands; not yet named in the map", - "at": "2026-10-09T09:19:24.923Z", - "method": "static", + "theory:r15-05-track-b": { "requirement_id": "R15-05", "decision": "NOT RUN", - "reviewer": "", - "claim_impact": "", + "method": "model", + "cell": "theory:r15-05-track-b", + "manifest_sha": "0f370527", + "run_id": "r15-track-b-20261009-02", + "evidence": "docs/analysis/mhpow/b1/README.md; tools/mhpow/b1/fixtures/attacks-n10-k16.json; tools/mhpow/b1/fixtures/SHA256SUMS", + "in_progress": true, + "coverage": "partial: the published primitive's reference, attacks and verifier refusals; the lottery binding (B2), the composed theorem (B4) and the panel's reading open", "release_identity": { - "commit": "", + "commit": "master 0f370527 (B1 e9f94df6 landed)", "lockfile": "", "binary": "", - "network_object": "", - "activation": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", "profile_hashes": "" }, - "in_progress": false + "claim_impact": "none", + "reviewer": "", + "at": "2026-10-09T09:58:05.196Z", + "note": "BOUND (B1, F-3): with ABH17's proven constant the paper's challenge count k exceeds N at lambda 256 and N 2^20 (to about n 25): no practical parameter in the proven regime. FINDING (B1, F-4): one labelling yields 193 to 200 accepted roots in 200 tries at 26 oracle calls per try, so a lottery over tau is not bound to the labelling cost (fixture A6, attacks-n10-k16.json, run on build-6). The package R15-05 (no improvised sampled-memory soundness) stays NOT RUN until the independent panel reads the reference and its verifier (17 of 17 named checks with known-failed tests) | the coordinator's order (10:4x UK, 9 October 2026): Track B's reproduction findings as BOUND rows, NOT RUN, no pass or fail claimed for the package" } }, "approvals": { @@ -20602,7 +20710,10 @@ "implementation_complete": null, "evidence_reproduced": null, "claim_authorised": null - } + }, + "run_id": "r15-track-b-20261009-02", + "evidence_path": "docs/analysis/mhpow/b1/README.md; tools/mhpow/b1/fixtures/attacks-n10-k16.json; tools/mhpow/b1/fixtures/SHA256SUMS", + "in_progress_since": "2026-10-09T09:58:05.196Z" }, { "id": "R15-06", diff --git a/tools/ci/batches/mhpow-b1-20261009-01.json b/tools/ci/batches/mhpow-b1-20261009-01.json new file mode 100644 index 000000000..cd3fe3fea --- /dev/null +++ b/tools/ci/batches/mhpow-b1-20261009-01.json @@ -0,0 +1,42 @@ +{ + "run_id": "mhpow-b1-20261009-01", + "manifest_sha": "13c3646e", + "evidence_dir": "docs/analysis/mhpow/b1", + "method": "model", + "boxes": [ + "build-6" + ], + "note": "B1 (R15-05), the cryptography lane of the 1.5x programme's Track B (9 October 2026): the exact CPU reference of Blocki and Smearsoll's MTP framework (eprint 2025/1456 as archived, sha256 13c3646e..., Sec 2.2, 3.2, App. C) over DRSample (ABH17 Alg. 1, eprint 2017/443 as archived, sha256 f8e08d36...), its complete verifier (named checks in the paper's order, each with a known-failed test, 17 of 17 OK on build-6), five deterministic known-answer fixtures (n 4 to 20), honest-prover rows n 12 to 24 (CPython, wall time only, no power) and six malicious provers (Dinur-Nadler eprint 2017/497 Sec 4.1, 4.3/5, 8; the paper's Attack 1 and LuckyQuery regrind). Dinur-Nadler's steering and unopened-block attacks are refused; red-node cheats are accepted with the (1-|S|/N)^k probability the paper prices; one labelling yields many accepted roots (F-4). The proven k with ABH17's constant exceeds N to about n 25 (F-3). NOT RUN until the panel reads it; this lane writes no PASS.", + "cells": [ + { + "cell": "model:mhpow-b1-reference", + "cases": [ + "POW-05", + "POW-06" + ], + "status": "NOT RUN", + "method": "model", + "evidence": "docs/analysis/mhpow/b1/README.md", + "note": "POW-05: attack fixtures A1 to A6 (tools/mhpow/b1/fixtures/attacks-n10-k16.json): A1 replay and A2 unopened block REFUSED, A3 control-block steering gain 0 with the red-node fallback accepted at (1-1/t)^k, A4 self-similarity saving refused, A5 Attack 1 accepted at (1-|S|/N)^k, A6 many accepted roots per labelling (the lottery binding BLOCKED to B2/B4, rows O-1 and O-8). POW-06: the verifier's named checks refuse malformed containers, wrong positions, skipped parents and wrong tags (test_b1.py); proof bytes and verifier oracle calls per N are exact formulas with measured rows; cold verification at rate BLOCKED to B6 (O-11).", + "claim_impact": "none: no public figure moves; Track B's construction is not adopted and nothing activates", + "in_progress": true + } + ], + "map_cell_requested": { + "model:mhpow-b1-reference": { + "command": "tools/mhpow/b1/run-b1.sh all (a build box under its pid file; kat, attack and k-table files byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS)", + "box_class": "build box, CPU only (build-6)", + "fixtures": [ + "tools/mhpow/b1/fixtures/" + ], + "cases": [ + "POW-05", + "POW-06" + ], + "coverage": { + "POW-05": "partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's", + "POW-06": "partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing" + } + } + } +} diff --git a/tools/ci/batches/r15-02-x7-20261009-01.json b/tools/ci/batches/r15-02-x7-20261009-01.json new file mode 100644 index 000000000..db7120b73 --- /dev/null +++ b/tools/ci/batches/r15-02-x7-20261009-01.json @@ -0,0 +1,48 @@ +{ + "run_id": "r15-02-x7-20261009-01", + "manifest_sha": "6ba3f01b", + "method": "model", + "evidence_dir": "docs/analysis/class-v6/1p5x/x7", + "boxes": [ + "build-9" + ], + "release_identity": { + "commit": "master 6ba3f01b (the X7 README; the verdict commit ca2fb6b2 and X8's rows e64eb265 cited when the landing hand lands them)", + "lockfile": "", + "binary": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", + "profile_hashes": "" + }, + "claim_impact": "none: a negative control on the memory route; no served figure moves", + "note": "main's order through the coordinator (11:0x UK, 9 October 2026): X7's memory-route verdict recorded as a BOUND-side negative control under R15-02, NOT RUN; X8's tensor-route chip rows join when they land and the hash lane's measured card rows arrive", + "cells": [ + { + "cell": "model:x7-memory-route", + "cases": [ + "R15-02" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "model", + "evidence": "docs/analysis/class-v6/1p5x/x7/README.md; tools/ci/batches/adversary-20261009-x7.json", + "note": "BOUND-side negative control (X7): f = 0.854 on the 4090 at stock, the frozen object at 8,077 nJ per hash against its read-only twin at 6,899 at the same rate (the hash lane's row, fk-x7-4090, 10:44 UK); s = 13 to 39 on the chip's GDDR7, HBM3 and near-memory (the adversary lane's X7 rows): no read-dominated design reaches 1.5x or 1.25x at any f, because the card's random-read path is its least efficient part against a chip. The chip figures are modelled (BOUND); the card figure is a WITNESS on a named rented card. X8's chip side (every int8 mix raising the ratio against a systolic array; the dp4a-only cells stopping at 1.54x) is the tensor route's first witness row set, pending the hash lane's measured card rows; recorded here when e64eb265 lands. R15-02 (no device or whole-machine boundary mismatch) stays NOT RUN until read", + "claim_impact": "none" + } + ], + "map_cell_requested": { + "model:x7-memory-route": { + "command": "the X7 memory-route read: docs/analysis/class-v6/1p5x/x7 (the chip model's s on GDDR7, HBM3 and near-memory by tools/1p5x/x5/sweep.py on a build box under a pid file) against the hash lane's read-only twin row on a rented card at stock (the frozen object and its read-only twin, nvidia-smi beside it)", + "box_class": "a build box for the model; a rented card for the twin row", + "fixtures": [ + "F0" + ], + "cases": [ + "R15-02" + ], + "coverage": { + "R15-02": "partial: the memory route's f and s only; the component power and traffic model and its sensitivity are X0's and X5's rows" + } + } + } +} diff --git a/tools/ci/batches/r15-int8-20261009-01.json b/tools/ci/batches/r15-int8-20261009-01.json new file mode 100644 index 000000000..daf367681 --- /dev/null +++ b/tools/ci/batches/r15-int8-20261009-01.json @@ -0,0 +1,49 @@ +{ + "run_id": "r15-int8-20261009-01", + "manifest_sha": "d799c086", + "method": "model", + "evidence_dir": "docs/plans/igneum-2.0-master/1p5x/research-plan", + "boxes": [], + "release_identity": { + "commit": "master d799c086; the class is cut by the research lane behind a research flag, not in any release", + "lockfile": "", + "binary": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", + "profile_hashes": "" + }, + "claim_impact": "none: a research class behind a flag; no served figure moves and nothing activates", + "note": "main's order through the coordinator (11:0x UK, 9 October 2026): the cells for the int8-dominated class opened, every row NOT RUN until read; the lanes land their own batches on these cells with map_cell_requested", + "cells": [ + { + "cell": "class:int8", + "cases": [ + "R15-03", + "R15-04" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "model", + "evidence": "docs/plans/igneum-2.0-master/1p5x/research-plan/packages.json; docs/analysis/class-v6/1p5x/x1/README.md", + "note": "opened, nothing measured yet: the int8-dominated class behind a research flag at three weights (int8-50, int8-75, int8-90) and the ARX-only points (arx-16, arx-32); the research lane cuts the class, the hash lane measures the card rows, the adversary lane the chip rows, the census instruments read it; R15-03 (layer-8-off control and held-out cache curves) and R15-04 (compaction, exact-fold alternatives, tuning) take their rows from those batches", + "claim_impact": "none" + } + ], + "map_cell_requested": { + "class:int8": { + "command": "the int8-dominated research class: cut behind the research flag by the research lane at int8-50, int8-75, int8-90 and arx-16, arx-32 (igneum-pow export with the class string, on a build box); the hash lane's card rows in the P04 form (tools/1p5x/x1/gpu-pairs.sh, gpu-rows.py); the adversary lane's chip rows (tools/1p5x/x5/sweep.py, tools/1p5x/x8/mac.py); the census instruments (igneum-pow addrsite, x1cache)", + "box_class": "build box for the cut and the census; rented pods for the card rows; a build box for the chip model", + "fixtures": [ + "F0" + ], + "cases": [ + "R15-03", + "R15-04" + ], + "coverage": { + "R15-03": "partial: the held-out cache curves of each weight against the frozen control; the layer-8-off control is X1's row", + "R15-04": "partial: byte agreement and accepted-work savings of each weight's fold; X2 to X4's rows carry the rest" + } + } + } +} diff --git a/tools/ci/batches/r15-track-b-20261009-02.json b/tools/ci/batches/r15-track-b-20261009-02.json new file mode 100644 index 000000000..ba8c468fa --- /dev/null +++ b/tools/ci/batches/r15-track-b-20261009-02.json @@ -0,0 +1,48 @@ +{ + "run_id": "r15-track-b-20261009-02", + "manifest_sha": "0f370527", + "method": "model", + "evidence_dir": "docs/analysis/mhpow/b1", + "boxes": [ + "build-6" + ], + "release_identity": { + "commit": "master 0f370527 (B1 e9f94df6 landed)", + "lockfile": "", + "binary": "", + "network_object": "none: documents and models only, no chain state read or written", + "activation": "none", + "profile_hashes": "" + }, + "claim_impact": "none: no served figure moves; Track B's construction is not adopted and nothing activates", + "note": "the coordinator's order (10:4x UK, 9 October 2026): Track B's reproduction findings as BOUND rows, NOT RUN, no pass or fail claimed for the package", + "cells": [ + { + "cell": "theory:r15-05-track-b", + "cases": [ + "R15-05" + ], + "status": "NOT RUN", + "in_progress": true, + "method": "model", + "evidence": "docs/analysis/mhpow/b1/README.md; tools/mhpow/b1/fixtures/attacks-n10-k16.json; tools/mhpow/b1/fixtures/SHA256SUMS", + "note": "BOUND (B1, F-3): with ABH17's proven constant the paper's challenge count k exceeds N at lambda 256 and N 2^20 (to about n 25): no practical parameter in the proven regime. FINDING (B1, F-4): one labelling yields 193 to 200 accepted roots in 200 tries at 26 oracle calls per try, so a lottery over tau is not bound to the labelling cost (fixture A6, attacks-n10-k16.json, run on build-6). The package R15-05 (no improvised sampled-memory soundness) stays NOT RUN until the independent panel reads the reference and its verifier (17 of 17 named checks with known-failed tests)", + "claim_impact": "none" + } + ], + "map_cell_requested": { + "theory:r15-05-track-b": { + "command": "the Track B cryptography read: docs/analysis/mhpow/b1 (the exact CPU reference of the MTP framework over DRSample, its verifier and the six malicious provers) by tools/mhpow/b1/run-b1.sh all on a build box under a pid file, outputs byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS", + "box_class": "build box, CPU only", + "fixtures": [ + "tools/mhpow/b1/fixtures/" + ], + "cases": [ + "R15-05" + ], + "coverage": { + "R15-05": "partial: the published primitive's reference, attacks and verifier refusals; the lottery binding (B2), the composed theorem (B4) and the panel's reading open" + } + } + } +} diff --git a/tools/ci/test-map.json b/tools/ci/test-map.json index a3a8b6abd..5b897963d 100644 --- a/tools/ci/test-map.json +++ b/tools/ci/test-map.json @@ -822,6 +822,62 @@ "coverage": { "TV-02": "partial: scheduled issuance on a straight chain and its reorg, two independent implementations EQUAL to the integer on devnet-4, mainnet and the TV-01 spec; paid, burned, locked, outstanding, DAG reds, the EVM ledger and duplicate records open; the independent panel has not read it" } + }, + "model:mhpow-b1-reference": { + "command": "tools/mhpow/b1/run-b1.sh all (a build box under its pid file; kat, attack and k-table files byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS)", + "box_class": "build box, CPU only (build-6)", + "fixtures": [ + "tools/mhpow/b1/fixtures/" + ], + "cases": [ + "POW-05", + "POW-06" + ], + "coverage": { + "POW-05": "partial: the published primitive's attack fixtures only; the lottery binding and the composed accepted-proof theorem are B2/B4's", + "POW-06": "partial: verifier refusals and op counts in CPython; no compiled verifier, no admitted-rate timing" + } + }, + "theory:r15-05-track-b": { + "command": "the Track B cryptography read: docs/analysis/mhpow/b1 (the exact CPU reference of the MTP framework over DRSample, its verifier and the six malicious provers) by tools/mhpow/b1/run-b1.sh all on a build box under a pid file, outputs byte-identical to tools/mhpow/b1/fixtures/SHA256SUMS", + "box_class": "build box, CPU only", + "fixtures": [ + "tools/mhpow/b1/fixtures/" + ], + "cases": [ + "R15-05" + ], + "coverage": { + "R15-05": "partial: the published primitive's reference, attacks and verifier refusals; the lottery binding (B2), the composed theorem (B4) and the panel's reading open" + } + }, + "class:int8": { + "command": "the int8-dominated research class: cut behind the research flag by the research lane at int8-50, int8-75, int8-90 and arx-16, arx-32 (igneum-pow export with the class string, on a build box); the hash lane's card rows in the P04 form (tools/1p5x/x1/gpu-pairs.sh, gpu-rows.py); the adversary lane's chip rows (tools/1p5x/x5/sweep.py, tools/1p5x/x8/mac.py); the census instruments (igneum-pow addrsite, x1cache)", + "box_class": "build box for the cut and the census; rented pods for the card rows; a build box for the chip model", + "fixtures": [ + "F0" + ], + "cases": [ + "R15-03", + "R15-04" + ], + "coverage": { + "R15-03": "partial: the held-out cache curves of each weight against the frozen control; the layer-8-off control is X1's row", + "R15-04": "partial: byte agreement and accepted-work savings of each weight's fold; X2 to X4's rows carry the rest" + } + }, + "model:x7-memory-route": { + "command": "the X7 memory-route read: docs/analysis/class-v6/1p5x/x7 (the chip model's s on GDDR7, HBM3 and near-memory by tools/1p5x/x5/sweep.py on a build box under a pid file) against the hash lane's read-only twin row on a rented card at stock (the frozen object and its read-only twin, nvidia-smi beside it)", + "box_class": "a build box for the model; a rented card for the twin row", + "fixtures": [ + "F0" + ], + "cases": [ + "R15-02" + ], + "coverage": { + "R15-02": "partial: the memory route's f and s only; the component power and traffic model and its sensitivity are X0's and X5's rows" + } } }, "not_run": { @@ -831,7 +887,6 @@ "GPU-04": "the memory-clock ladder has no harness tonight: the project's own rig mines nothing under the the earlier devnet off order", "GPU-06": "accepted work under ordinary connectivity needs the fault network F4", "GPU-07": "the sustained thermal and power soak has no harness tonight: the project's own rig mines nothing under the the earlier devnet off order", - "POW-05": "amortised cheap winning attempts are the attack lanes' grind and era harnesses (tools/attack/f7-era, f9-grind), not in the release matrix; their rows come from those lanes", "ROT-03": "miner-voted bring-forward needs a vote harness on the fault network F4", "ROT-04": "seed-selection resistance is the census harness (the class v6 invention lane), not yet in the matrix", "EVM-01": "no EVM conformance-vector harness is mapped tonight; the exec suite does not run the reference test vectors", @@ -995,10 +1050,6 @@ "TV-31": "TV-31 (token value gate, scope CORE): no gate executed; the harness is the owner role's (Qualified counsel); a supplemental layer, never counted as independent evidence; not yet named in the map", "TV-32": "TV-32 (token value gate, scope LEADERSHIP CLAIM): no gate executed; the harness is the owner role's (Independent acceptance panel); a supplemental layer, never counted as independent evidence; not yet named in the map", "R15-01": "R15-01 (1.5x programme package): no package executed; the harness is the lane's (X0); its batch names the case when it lands; not yet named in the map", - "R15-02": "R15-02 (1.5x programme package): no package executed; the harness is the lane's (X0, X5); its batch names the case when it lands; not yet named in the map", - "R15-03": "R15-03 (1.5x programme package): no package executed; the harness is the lane's (X1); its batch names the case when it lands; not yet named in the map", - "R15-04": "R15-04 (1.5x programme package): no package executed; the harness is the lane's (X2, X3, X4); its batch names the case when it lands; not yet named in the map", - "R15-05": "R15-05 (1.5x programme package): no package executed; the harness is the lane's (B1); its batch names the case when it lands; not yet named in the map", "R15-06": "R15-06 (1.5x programme package): no package executed; the harness is the lane's (B3); its batch names the case when it lands; not yet named in the map", "R15-07": "R15-07 (1.5x programme package): no package executed; the harness is the lane's (B2, B4); its batch names the case when it lands; not yet named in the map", "R15-08": "R15-08 (1.5x programme package): no package executed; the harness is the lane's (X5, B5); its batch names the case when it lands; not yet named in the map", From 9e745ab72e8c779a1e1fe6968b6829c5b71ee816 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:58:47 +0000 Subject: [PATCH 19/19] Counter ASIC 3.0 status: X7's f and the memory-route verdict (no read-dominated design reaches 1.5x), main's redirect to the int8 class and the founder's first priority, X8's chip side, X5's placement bracket closed, X1, X2 and X3 landed, the 2.0.3 cut, the mini's worker watchdog class, the fresh-sync memory read, Track B's landings, the hash-rate facts and the miners started, the canary's harness fault, the pods Co-Authored-By: Claude Fable 5.1 --- docs/plans/counter-asic-3-status.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/plans/counter-asic-3-status.md b/docs/plans/counter-asic-3-status.md index 79155f63c..cf4c4c03d 100644 --- a/docs/plans/counter-asic-3-status.md +++ b/docs/plans/counter-asic-3-status.md @@ -894,6 +894,9 @@ TV-04's SECOND CUT (0cd1f422, 10:29 UK, NOT RUN, run tv-04-20261009-02 supersedi THE RESET's FAULT AND THE RE-ROLL (the fleet lane, 10:33 UK, once with the default, taken): on the reset universe of 98 boxes (54 + 40 + three hubs + lp-43; the tracker's 101 including three non-reset rigs): 39 within ten, 12 syncing with the height rising, 15 syncing slower, 20 alive but islanded or stuck, 12 dead; the dead: ten nodes killed by their container's OOM killer mid-sync (cgroup oom_kill counters 1 to 2; limits 18, 20 and 31 GB on lc-3070-01, ln-node-03/09, lp-4090-03/08/17/22/23/24/30; the logs stopping mid-line between 09:42 and 10:27 UK), the fleet-scale form of build-1's 62 and 85 GB fresh syncs (the canary box lp-4090-36 with a 123 GB limit synced from genesis in 1,041 s); dn3-q04 of a full disk (1 MB free, a StorageFull panic); lp-4090-07 of a RocksDB lock-file race at its restart (124 GB limit); the islanded 20 (dn3-j1/p02/pool-b/q05/relay/x1, lc-3090-01, lp-4090-01/11/12/19/20/27/28/40/41/42, lp-48-06, w-relay, w-target) reading synced=true at EVM 5,2xx to 5,6xx or stuck at 9,987 with two to four peers: inbound island peers reaching them during their sync (the --addpeer roll leaving the listener open, the class the build-server lane closed on build-1 with --listen=127.0.0.1); lp-4090-27 banning lp-05 itself ("misbehaving peer: 72 PoW cache strikes within an hour (limit 2)"), a 2.0.2 ban-rule item for the node lane. The re-roll at 10:50 UK on 30 boxes (w-relay and w-target the HEAL lane's heal harness, out): from the mini's datadir snapshot (5.06 GB tgz on build-1, sha-checked, pushed from build-1 eight wide as lp-06 was) with connect-only to the three hubs and no inbound during the sync, the same sha everywhere, dn3-q04's old asides removed first, the tracker counting them in, done about 11:30 UK; the alternative (a plain restart on the partial datadirs) repeating the OOM on the 18 to 31 GB boxes. The 27f54124 canary passed its sync line (genesis to within ten of lp-04's chain in 1,041 s, 4 peers, EVM 27,763 against the feed's 27,753), its mining and shard phases running, the verdict about 10:52. The ghost sweep ended at 10:28: all eight hidden Vast instances destroyed by id and read back gone, each one's result dirs on build-1 with the sha equal. The tracker 10:32: 41 of 101. THE PCs MINING (the relay lane, from the apps' own intake uploads at 10:35 UK, no agent answering): PC 1 the RTX 5080 worker at 60.5 MH/s wall (46.6 averaged over 340 s since its restart at 10:29), 72 accepted and 0 rejected in that window, the last at 10:35:08 UK (template DAA 26,873); PC 2 now mining too (its node past the IBD wall after 10:01): the RTX 5060 Ti worker at 28.3 MH/s wall, 70 accepted, 6 rejected, 3 fee over 650 s since 10:24, the last at 10:35:31 UK (DAA 25,411); neither at the cut (their templates at DAA 25k to 27k; the cut at about 50,400), the worker restarts at 10:24 and 10:29 template-change restarts back within the 180 s watchdog; the 5090 workers' streams not in the intake's latest chunk. THE MINI's PROTOC (the shipper, 10:34:12 UK; the founder's own word taken through main's session): ~/.local/protoc/bin/protoc on the mini answering "libprotoc 36.2" (sha256 765ccb18be73e565); the build script ~/mini-build-203.sh staged (PROTOC and ~/.local/protoc/bin on the build's PATH only, the app tree at release-2.0.3 3bae31e0, the node tree vendor/igneum-node-203 at 27f54124, the served prover pair beside it); the build under ~/mini-build.pid beside the mini's mining (nice 19, four jobs of twelve cores, the miner not paused) the moment the 27f54124 canary PASS and the cutter's record are in; then the mini's rule-33 canary with the reboot leg NOT RUN on the hold, the Mac entry on PASS with min_supported 2.0.2 after the hubs' upgrade; the mini synced at DAA 52,815, 5 peers, mining. MAIN'S PIVOT OF TRACK B (10:4x UK; relayed): on Track B's first results (B1: no practical parameter in the proven regime; B3: CPU-friendly at 32 to 512 MiB; B4: no 1.5x certificate from the published constants) the track pivots from reproducing the paper to building our own construction, the reproduction kept as the control: (1) B4 writes the requirements a construction must meet to be worth a proof (the lottery draw bound to a fresh labelling or a provable fraction, B2's finding; an instance shape filling a GPU by memory traffic rather than instance count, B3's finding: the label function's work per byte moved must fall, the dataset per instance must exceed any SRAM, the honest path bandwidth-bound on GDDR7; a certificate whose losses stay under 2x, the generic 0.151 and the red-blue 341x named as what to beat; the full-SRAM and near-memory opponents inside the bound); (2) B1 and B3 propose two candidate constructions against them, one each (a wide-label, low-arithmetic DRSample variant with a bandwidth-bound label function; a fresh-state variant of the current class v6 read pattern with a compact certificate), each with its CPU reference, verifier and a first GPU row, labelled research; (3) X7's f and s feed both; (4) the steward records the reproduction's three findings as BOUND and NOT RUN rows under R15-05 to R15-07. THE FOUNDER's CLOCKS (10:4x UK; every lane told): the three checkpoints inside the next 30 to 60 minutes: X7's f and s by 11:20 (the pods handed the minute they pass, ten minutes of runs; the adversary lane's s from the model it holds; the memory-route verdict r = s/f at the measured numbers, same-memory and HBM, in the same line); B4's requirements by 11:15 (one page); the two candidate constructions with their CPU reference, verifier and first GPU row by 11:45 (B1 candidate 1, B3 candidate 2; the label function and the instance shape the only changes to the reproduced control); X6's blind packs sealed by 11:30 and the blind rows by 12:15 on rented 5090 and 4090 (the AMD and Intel cells NOT RUN); the witness: the opponent sweep on each candidate's traces by 12:30 on the boxes, the already-routed placements reused with the candidate's traffic (no new routing), WITNESS, the first candidate's row the moment it exists; one line to main at 11:20, 11:45 and 12:30 as things stand; anything unreachable named with its physical reason. B1's ATTACK FIXTURES (10:38 UK, N 2^10, k 16, deterministic, attacks-n10-k16.json sha256 805035ebfc8d2f34, two runs identical): Dinur-Nadler first: A1 replay across chi (DN17 4.1) 0 of 50 accepted, REFUSED; A2 an unopened challenged block on a constant array 0 of 50 in both variants, REFUSED (check_2b, check_3); A3 control-block steering (DN17 4.3/5, the MTP-Argon2d break) steering gain 0 after 1,000 grinds per control block, REFUSED BY CONSTRUCTION (DRSample's edges fixed a priori), its red-node fallback accepted 191 of 400 against (1 minus 1/t)^k 0.44; A4 self-similarity (DN17 8) 0 of 200 labels reproduced, the saving refused; the paper's own: A5 Attack 1 with a greedy depth-reducing set accepted 6 of 400 (beta 0.22, the analytic 0.018) and 26 of 400 (beta 0.15, 0.072), as BS25 Sec 7.1 states; A6 LuckyQuery regrind: ONE labelling yielding 193 to 200 accepted roots in 200 tries at 26 oracle calls per try with one red sink: FINDING F-4, a lottery over tau not bound to the labelling cost (B2's O-07); k from BS25 Cor. 2 with ABH17's proven constant 2.9e7 at n 20 (F-3); the greedy Attack 1 floor k 100 to 160 for 2^-40; the honest rows n 12 to 24 (CPython, wall time): n 20 prover 3.48 s, the 96N-byte state model (RSS 356 MB), the proof 129,133 B, 3,968 verifier calls; n 24 67 s, RSS 5.4 GB. B3's ORACLE NOW B1's (the GPU feasibility lane, 10:3x UK): B1's working reference on build-6 (params.py d47b8ff5, drsample.py 4169a5fc, mtp.py c0feed31; BLAKE2b-256, tags L/M/C/G, rejection-sampled DRSample, container B1MTPDR1); B3's C port (cpu_ref_b1) reproducing all five B1 known-answer fixtures byte for byte (chi, the graph parents, the labels, tau, the proof bytes, the .proof.bin files); the CUDA kernel for that encoding (b3_gpu_b1) matching on the RTX 4090 (the labels, every Merkle node, the root and the proof container identical for every checked instance, instance 0 equal to B1's own fixture digests at n 8, 12, 16, every proof accepted; the known-failed case (DRSample's long edges deleted on the GPU) MISMATCH, 0 of 96 proofs accepted, test_known_failed_b1 PASS); one finding: in B1's encoding the whole 105-byte label message is ONE BLAKE2b block, so no lane split of a label exists (the SHA-256 reading had two blocks and the two-lane kernel cut the per-label time 1.6x), the per-label critical path one compression, about 1.7 microseconds on one 4090 thread; the B1 rows on the 4090 and the 5090, the B3P1 rows a labelled control. B2's OBLIGATIONS TABLE LANDED (81ee229e4, 10:3x UK; README sha256 d458f217, figures.txt 27bb414c from b2_figures.py 7b8664ea on build-9; the batch POW-05/POW-06 NOT RUN): the encoding re-cut to B1's pins; sixteen obligations: ANSWERED from the paper for reuse across template, trial, epoch, day, era, network and class object (O-01 to O-04, O-15, O-16), challenge grinding (O-06, Lemma 4, k = 2 ln2 lambda log N / c3) and partial evaluation (O-11, Theorem 7, Lemma 5, Corollary 2), precomputation from the epoch-seed lead or the day key gaining nothing; FAIL for two lottery rules (O-07): W over the root re-rolling by a red sink for log2 N + 1 calls a draw (pass probability 0.99988 at N = 2^24, k = 2,000, about 1.3 million draws per labelling), W over chi alone screened for free: as the paper stands an MTP certificate adds memory work per block, never per lottery trial, and cannot move the 1.5x ratio until B-T3 is answered; BLOCKED to B4: B-T1 graph sampling failure, B-T2 DRSample's c3, c4 (the certificate 19.5 MiB at c3 = 1, 194.9 MiB at 0.1, lambda 256, N = 2^24), B-T3 the lottery, B-T4 adaptive chi, B-T5 multi-instance, B-T6 lambda (Lemma 3 at lambda 256 only for q up to 2^31.5), B-T7 role bytes, B-T8 memory-time to energy; BLOCKED to the node lane: B-N1 the live day rule (bind.rs timestamp day against spec 1.12 DAA day) and the verifier's recomputation, B-N2 the block interval and stale fraction (binding the template capping N by N x t_seq at most rho x 1 s, pushing the instance toward SRAM size, the B5 question), B-N3 the state root bytes; the lane's stamp slip said once. +X7's FIRST f (the hash lane, 10:44 UK; the frozen object on fk-x7-4090 at stock, the 4 GiB dataset, the A1/B1 half of the ABBA): the full kernel x1-ctrl-ds30 30.693 MH/s at 247.9 W = 8,077 nJ per hash; the read-only twin 30.700 MH/s at 211.8 W = 6,899 nJ per hash; idle 16.1 W; f = E_read / E_v6 = 0.854 on board power (0.844 with the idle floor out of both); the rate identical to three digits with every base op and the whole shadow removed: on the 4090 the frozen object is purely memory-bound, the ALU (the 1,024 base statements, the 5,400 address ops, the 55,296 shadow) costing 36 W, 15 percent of the card's energy per hash, and no rate; with f 0.85, r = 1 / (0.85/s + 0.15/c): at c free r = s / 0.85, a 1.5x needing s = 1.28, a 1.25x s = 1.06. X7's MEMORY-ROUTE VERDICT (the adversary lane, 10:48 UK, ca2fb6b21; the s rows landed at 6ba3f01b): with the 4090 pair the card's memory path costs 27 nJ per random read all-in, so s (the card's memory energy over the chip's on the same traffic) is 12.8 on the chip's GDDR7 board (11 to 15), 22 on HBM3, 39 near the bank, and c (the card's non-memory energy over the chip's 0.312 microjoules of ALU) 3.8; r = s/f at c free 15x, 26x, 45x; r = 1/(f/s + (1-f)/c) 9.5x, 13x, 16.5x, device-level. THE VERDICT: the memory route cannot reach 1.5x or 1.25x at any f, because s would have to fall under 1.5 and it is 13 to 39: a read-dominated design moves r toward s, not toward 1; the yardstick's f for 1.5x at each s is s/1.5 (8.5 on GDDR7, 15 on HBM3, 26 near-memory, all over 1); the honest side's only lever on s its own memory path (a random read under 3.2 nJ all-in, which no discrete GPU does: the 5090 8.7 nJ marginal and 14 all-in at its knee, the Apple tier's LPDDR about 6 at the wall); the device-level bridge overstating the complete-machine ratio (the machine's static, PSU, cooling and host in neither s nor c; X0 5b's 2.35x at the 5090's knee the served form; the 4090's stock point about 4.7x on the machine model); the 5090's f and the X1 pair replacing the row when they land, the verdict not turning on the card. MAIN'S REDIRECT (10:5x UK): on X7's verdict the 11:45 candidates built on more memory traffic withdrawn before they waste the hour; one candidate, every lane on it: the only family in the placed rows a chip undercuts least is dense int8 multiply-accumulate (mm8 1.38 pJ per MAC on the chip against 2.2 on the card, k 0.63, about 1.6x on that component alone), FP32 FMA second (k 0.4 to 0.5); (1) the hash lane with the kit lane measures f_mac and the per-MAC energy on the 4090 and 5090 for a deterministic int8 tensor-core kernel (dp4a or mma.s8 with integer accumulation, bit-exact across cards, the census's determinism rule) at 10, 50 and 90 percent of the op mix beside the frozen object, by 11:45; (2) the adversary lane prices the same mixes on the placed core with a systolic int8 array at N5 and a node ahead, the machine terms in, WITNESS, by 12:00; (3) B4 writes the requirements for a tensor-dominated class that stays memory-hard enough to refuse a small-SRAM chip, one page by 11:30; (4) the reading at 12:00: the best achievable complete-machine ratio for an int8-dominated class against 1.5x and 1.25x, WITNESS, plus the one sentence on whether P04's 1.5x energy target is reachable by any class on a discrete GPU; the P04 scope unchanged; the steward recording X7's verdict as a BOUND-side negative control under R15-02. THE GROUND-UP REWRITE QUESTION (the founder; main's answer and order, 11:0x UK): the placed per-family rows point the other way from class v6: the chip's edge per op is 13x on random reads, 5x on mulhi and shfl, 2x on mul, but only about 1.25x to 1.3x on the ARX families (add, xor, rotate, sub: k 0.77 to 0.80 placed) and 1.6x on int8 MAC; class v6 doubled the reads and leans on mul and shfl, which is why it reads 2.35x; a second design point beside the int8 mixes, measured by 12:00: an ARX-only class (no mul, mulhi, shfl or FP) with the reads per hash cut from 256 to 16 and 32 over the same 4 GiB dataset (the dataset size forcing DRAM into the chip's bill; the read count costing the card its energy), the hash lane measuring the card's J/hash and its memory share at stock and the knee from the existing generator with a restricted family table and read count (a research class string, nothing frozen), the adversary lane pricing the same on the placed core with the board's DRAM channels sized to the read rate, complete machine, WITNESS; the census lane saying whether 16 and 32 reads keep the hot-set and bit-bias instruments clean; the reading at 12:00: the best complete-machine ratio any class reaches on a discrete GPU (int8-dominated, ARX-dominated, mixed) and the dollar side beside it (hardware per MH/s against the card's about 16), because an ARX-only class cheap in energy may be cheap in silicon too and fail the economic conditions. THE FOUNDER'S FIRST PRIORITY (11:0x UK): "get me the int8-dominated class asap"; every 1.5x lane serves it; the build fanned out by the coordinator: (1) the research lane (the X1 lane a6decc31f55cfbd00) with the hash lane: a class string "int8" on the frozen tree behind a research flag: the generator drawing a deterministic int8 multiply-accumulate family (dp4a or mma.s8 with 32-bit integer accumulation, the operands masked from the register window, every result xor-injected into the chain, bit-exact on CPU, CUDA, OpenCL and Metal by the FP32 work's rule without its exponent masking) at three weights (int8 at 50, 75 and 90 percent of the energy-weighted work), the ARX families for the rest, no mul, mulhi or shfl, 32 reads per hash over the same 4 GiB dataset, plus the ARX-only points at 16 and 32 reads; the CPU reference and the CUDA emitter by 12:00, OpenCL and Metal by 13:00; (2) the kit lane cutting its GPU kit the hour the CUDA emitter is bit-exact on the pack self-test (by 12:30); (3) the hash lane measuring J/hash, rate and the memory share on the 5090 and 4090 for each weight beside the frozen object (by 13:00) and the same-work pairing CPU against CUDA on one context; (4) the census instruments on the weights (the hot set, the bit bias, exhaustion, the family predicate) by 13:00; (5) the adversary lane pricing each weight on the placed core with the chip's best systolic int8 array at N5 and a node ahead, complete machine, the dollar column, WITNESS, by 13:00; (6) the steward opening the cells (R15-03/04 and "class:int8") with every row NOT RUN; the reading to main at 13:00 (the best weight's complete-machine ratio same node and one ahead, its dollar ratio, its GPU cost against the frozen object, the census verdict, the one sentence); lines at 12:00, 12:30 and 13:00. THE FOUNDER'S 15 MINUTES (11:1x UK): all the data by 11:25, measured where a run fits the window and modelled where it does not, each row labelled: the hash lane's deterministic int8 MAC microkernel (dp4a with 32-bit accumulation, the operands from a 64-register window, the results xor-folded, 32 random reads per hash over 4 GiB) at the three weights beside the frozen object on the rented 4090 and 5090, J/hash, rate and the memory share at stock, with the ARX-only 32-read point in the same session; the adversary lane's chip side of the same mixes on the placed core with its best systolic int8 array, the machine terms, the dollar column, from the rows it holds; the reading (the complete-machine ratio per weight and the ARX point, same node and one ahead, energy and dollars, against 1.5x and 1.25x, WITNESS, the one sentence); the bit-exact four-emitter class and the census said as the 13:00 items. X8's CHIP SIDE (the adversary lane, 10:54 UK, e64eb265c; docs/analysis/class-v6/1p5x/x8/README.md with the 32 cells; the batch adversary-20261009-x8 NOT RUN; WITNESS): the construction (the hash lane's measured mixes to replace it): a mix replacing 10, 50 or 90 percent of the card's measured shadow energy with int8 MACs at the card's measured per-MAC cost (2.2 pJ on the dependent u8 tile, 0.83 on its best wide s8 tile, at the lock), the card's joules per hash the frozen object's own (4.011 at the knee), the reads at the frozen floor; the chip's ARX at the placed 5.05 pJ per instruction, its dp4a at 1.38 pJ per MAC (the placed mm8 row), a systolic int8 array at 0.30 pJ per MAC (0.10 to 0.60, claimed: the record's k 0.03 to 0.3 band); same node at the knee, the complete GDDR7 machine: against the systolic array every mix moves the ratio UP (the board 2.38x at 10 percent, 2.53x at 50, 2.69x at 90 on the dependent tile; 2.36x, 2.39x, 2.42x on the wide tile; the die 8x to 14x); against the programmable dp4a on the wide tile the board falls to 1.82x at 50 percent and 1.54x (1.26 to 1.71) at 90, the hybrid 2.03x, the die 2.78x; a node ahead every cell 0.2x to 0.3x higher. THE ONE SENTENCE: no class on a discrete GPU reaches 1.5x or 1.25x on this route, because the adversary builds the systolic array (its MAC 4x to 20x cheaper than the card's measured tile) and against it every mix raises the ratio; the only cells that fall toward 1.5 assume it refuses the cheapest unit, and even they stop at 1.54x outside the band's low end; the card's measured mixes BLOCKED on the hash lane; the array's figure claimed (a placed systolic array about two host-hours; the verdict not turning on it inside the band). X5's PER-BOX ROWS 2 TO 5 (the adversary lane, 10:50 UK; 948c475f6): the 8-lane 18-family core placed and routed at 20, 30, 35 and 50 percent utilisation (build-2, 5, 6, 7; SPEF, the gate-level VCD, seven tags each), the placed energy per lane-op on the class v4 draw 9.36, 9.36, 9.63 and 9.48 pJ at ASAP7 (6.55 to 6.74 at N5) against the 40 percent row's 9.36: FLAT within 3 percent while the cell count moves 327,000 to 208,000, so the plus 42 percent placement factor is the design's own wires and clock tree, not a density artefact; the placement bracket CLOSED at the placed 6.55 pJ (N5), the SRAM access band (2.0 to 7.0 pJ per access) the one term still widening a row; the claims on build-2, 5, 6 and 7 released; build-4 keeping the hybrid 0.25 placement and the 32-lane 22 percent floorplan (the converged SPEF row, about 13:30). X1 LANDED (the research lane, 10:47 UK, ahead of 11:30): docs/analysis/class-v6/1p5x/x1/README.md with every row, rows/ and tools/1p5x/x1/, on master at 2e99fc116; the registry batch tools/ci/batches/1p5x-x1-20261009-01.json (the cell experiment:1p5x-x1, POW-02 and POW-04, NOT RUN); one slip (the first landing refusing a directory as evidence, fixed by naming the 55 files, about 15 minutes); the result: the candidate's live access distribution flat to the Poisson floor (17 programs, 0.998x to 1.002x), every policy's half store serving exactly half, at stock costing no card anything (g 0.983 to 1.001 on two 5090s and two 4090s, the rate within minus 0.15 percent); the frozen object's window concentration 56.25 percent at the half store on the signing program (61 mean over 256 seeds, 72 near the 95th percentile), so the hybrid's half-store misses rise only 14.3 percent on the object, the cache bound on a 1.14 there (1.29 at the seed mean), r from 2.4 falling at most to about 2.1 (1.85 at the seed mean); the DRAM board and the SRAM die not moving (a = 1): X1 alone does not reach 1.5x on any measured row; BLOCKED/NOT RUN: the knee, wall power, OpenCL/Metal same-work, a; the boxes handed back, every pod destroyed; X6 with its one line. X2 LANDED (the worker lane, 10:48 UK; 514c1096a; docs/analysis/class-v6/1p5x/x2/README.md with 89 evidence files; tools/1p5x/x2/; the outputs at build-1:/srv/artefacts/tas/x2-20261009/x2-equiv-outputs.tar.gz 64740f73): PARTIAL: the equivalence EQUAL on the three contexts with the known-failed flagged first; the 4090 stock pairs measured (rate plus 9.9 percent, g 0.971 against the full path); wall joules BLOCKED, the knee NOT RUN; g 1.0015 against the kernel timer, r_new = r0: X2 moving the 1.5x ratio by nothing measurable; the registry batch kept out of tools/ci/batches/ (a NOT RUN write over the shared cells would overwrite other lanes' POW-01 rows; the steward records it with the cases it chooses); X2-F1 (the stale-output detector exiting 3 on an identical job sent twice; the worker's owner) and the gen-6 Linux CUDA worker's missing select pass (the kit lane) for other owners; fk-x2-4090 destroyed. X3's BEST SETTING (the Ember lane, the search closed 10:44 UK, both cards at stock, board power, the frozen control via kit zip 4 / hl-v6-all, 0 rejected shares on every one of 20 tuned rows): the base kernel at batch 2^26 (--batch-log2 26, no variant): the 5090 rate plus 0.73 percent, nJ per hash minus 0.15 percent over two A-B-A pairs (70.66 against 70.15 MH/s; about 6,140 nJ), g = 0.9985; the 4090 rate plus 0.18, nJ plus 0.06, g = 1.0006; every other knob (17 race variants, batch 2^20 to 2^26, race on) inside plus or minus 0.5 percent energy: the in-container Ember knobs are not a 1.5x lever (r_new = 2.0 x 0.9985 = 1.997x against the 0.75 needed); the lever that is (the clock lock: the recipe's 5090 row 5,842 to 4,011 nJ, minus 31 percent) already inside the record's lock convention, its rented rows NOT RUN (both hosts refusing -lgc and -pl); a fault for the hash lane: the recipe names hl-v6-all's fingerprint 59e6708e46f1e87c on the first rig while both pods and the CPU emulation read e8f4f3289c6ee1fc on the same zip; the 30-minute stability runs ending 11:00 (4090) and 11:14 (5090). THE 2.0.3 PACKAGES CUT (the cutter, 10:47 UK, run pid 46702 10:25 to 10:47): /srv/artefacts/203-27f54124-3bae31e0 from node 27f54124 and app 3bae31e0, every sidecar OK, run-202.log naming the exceptions: the public hive igneum-hive-2.0.3-27f54124.tar.gz 4ba5a2dbc6e595c5da2fcb3730a94755af443c6f5d208dd62493f3d59310aeff (version.txt "igneumd 2.0.3-27f54124", h-run.sh with the sync gate and the open-files limit); the Windows payload igneum-windows-app-2.0.3-3bae31e0.zip 23354ecff5cf178605bdcdf204c4d137dd1711bc3c1b0a45386a2da14d866466 (the engine 15eb2cfa73ee02dd); the installer kit installer-kit-3bae31e0.zip 8070cdc82d59f1e0; the lab trio; the node pairs all "igneumd 2.0.3" with the commit string, fingerprint cbc5bd0aa10585c8, kit-isa 0 (seed 027bb12aedf1bb9f, hive 9f51ba678dbe9578, Windows 3328dab937259b3b); the fleet kit the evidence kit 19f7950b, not restamped (the never-restamp guard in run-202.sh); no push, no manifest; the shipper naming it the pipeline's dry run, not the entry (the watchdog-fix app sha to come). THE MINI's WORKER CLASS, THE EXACT STEP (the shipper, 10:51:57 UK): the mini mining in bursts the whole time: each miner run's worker prepared 2.5 s after its "seed mismatch" start fault and mining 11 s after it, then the APP ending the miner at exactly 180 s ("the worker did not come back within 180 s of the miner restarting it"), the next miner starting a fresh worker: about 170 s of mining in every 5.5 minutes, the card "0.00 MH/s, waiting" between the bursts, 222 blocks accepted this run (962 lifetime), the node synced at DAA 54,003; the step: the app's watchdog (src/watchdog.rs) sets its restart clock on the WORKER FAULT line and clears it only on a "worker: ready" line, and after a prepare the worker says "worker: prepared", never "ready" again, so the clock runs out while the card mines and the app kills a mining miner; no miner fix needed (the node lane's A/B cut withdrawn; the prepare-ahead already works: "PREPARE held for epoch seed a0a4685d" at the 10:00 cut); the fix on release-2.0.3: the known-failed tests on the branch as 800e641f (red on the mini's build box), the fix (the restart clock cleared by "worker: prepared" and by an accepted block or a status with hashes; the grace from the card's measured prepare time times two as the second guard, 180 s the floor; the card's words "preparing the new epoch's dataset"), the sha by 12:30 with the tests green on the mini; the cutter then re-cutting the Windows payload and the hive packages from it and the DMG building from it on the mini; the api/pause and api/resume at 10:35 bringing nothing (nothing held the worker). THE NODE LANE's MEMORY READ (10:50 UK, build-2, a quiet box, a loopback listener, the three hubs the only peers, one node at a time, RSS every 30 s for 20 minutes): fresh 5d53a591: 3.8 GB at DAA 4,358, 10.4 at 6,730, 14.2 at 7,621, 18.5 at 8,745, 21.0 at 14,244, 24.8 at 15,453, 28.1 at 16,875, 29.9 GB at 22,759 (headers at 43,816); fresh 27f54124: 4.4 at 4,368, 12.0 at 6,829, 17.5 at 7,936, 23.0 at 9,986, 26.1 at 14,856, 31.4 at 16,667, 33.8 at 24,112, 34.0 GB at the moving tip (exec 28,468 / DAA 53,670, synced in 20 minutes): the growth the executor's own during a fresh sync, linear in executed blocks at about 0.65 GB per 1,000 blocks (not the inbound traffic), and 27f54124 NOT bounding it (3 to 5 GB above 5d53a591 at equal height; the 2.0.3 rules' ring bound not the fresh-sync path, the record store and the held scratch set adding their own); the second path the inbound requests, votes and proof asks held during IBD (the swarmed seed 34 GB at EVM 4,840 under 93 inbound island peers against 1.1 GB on loopback); the fleet's ten OOM-killed boxes (cgroups at 18, 20 and 31 GB) the first path alone. THE PUBLIC ANSWER: a fresh sync of 2.0.2 reaches about 30 GB at DAA 44,000 and 35 to 40 GB by the tip; a 16 GB machine reaches DAA 7,000 to 8,000 (about four minutes in) then swaps on macOS or is killed on Linux; a 32 GB machine about DAA 20,000; the download page must state, until the bound ships: a fresh sync needs 64 GB of RAM (48 GB the floor today, the chain growing about 0.65 GB per 1,000 blocks, a gigabyte every 17 minutes at 1 bps), or the node syncs from the hubs' snapshot (the state at a checkpoint, no execution from genesis), the 16 GB path. THE 2.0.3 ITEM: the executor's fresh-sync working set (the per-block execution records and state the IBD path holds while executing from genesis; the ring of state clones bounded and not it): (a) a snapshot sync path in the node (the shipper's snapshot as the executor's start, verified by its state root against the headers' chain), a 2.0.3.x item with the shipper; (b) the bound on the records held during IBD (persist-and-drop below the executed tip's window): a heap profile of a fresh 27f54124 sync on build-2 to DAA 10,000 this afternoon, the fix on the next node sha after the prepare-ahead item, earliest tomorrow's cut; the curves on build-2 at /tmp/nl-rss-5d53a591.log and /tmp/nl-rss-27f54124.log, the build-server lane's at build-1:/srv/canary/1176efb9/logs/rss-0909.txt. B4 LANDED (80b127484, 10:38 UK first): the README heading with THE CONTROL as BOUND (L) (the generic 0.151 of honest, the floor 6.63x; the red-blue at least 341x at rho 0.25, 512x at 0.5) and section 5b row B4-OB-LOT: B4 Lemma C (any lottery value over an MTP certificate re-rolls via the sink: one trace, one cmc bound, log2 N + 1 queries per draw, accepted with (1 minus 1/N)^k = 0.9946 at log2 N 22), the requirement phi = 1 (a draw costs a fresh labelling), the change (the trial id in chi, v = H(tag_lot, chi, tau), winners verified IN FULL, the spot checks kept as the DoS pre-filter priced by R1's bound), its effect on the losses (L2 and L10 vanishing for winners, the generic 0.151 to 0.213, the red-blue unchanged, the verification one labelling per winning block: B6's cost); the rows by name: B4-OB-LOT (B4), -1 the lottery rule (B2), -2 the sink re-roll fixture and the full verifier (B1), -3 multi-instance amortisation (B4), -4 the verify cost at block rate (B2 with B6); the encoded state its own BLOCKED row. B6's SECOND LANDING (the node lane, 067dca706, 10:45 UK): the B1 reference values in (lambda 256, N = 2^n, depth n, 32-byte labels, three openings a challenge each with its own full path; the proof bytes exact 45 + k(1 + 96(n + 1)), 129,133 at n = 20 and k = 64; the verifier k(3n + 2) + 2k = 4,096 BLAKE2b calls); against build-7's measured BLAKE2b rate (261.0 MB/s at 64 bytes = 245 ns a call): about 1.0 ms per proof cold on one core (0.1 percent of a core at 1 bps, 1 percent at 10 bps); 12.8 MB of proof per 99-block IBD batch; 129 KB/s per peer at 1 bps, 176 MB/s of uplink at 10 bps across 136 peers; an invalid-proof flood about 2 ms of CPU and 258 KB per IP per hour under the strike guard; a pool verifying per share about 1,000 shares a second a core; THE ROW THAT DECIDES THE SHAPE: k = 64 a fixture size, not the soundness parameter; the paper's Corollary 2 with ABH17's constant giving k about 2.9 x 10^7 at n = 20, a proof of about 56 GB (200 times the message limit, about 7.5 minutes a core to verify), so a block-carried proof of this primitive BLOCKED on k; the primitive carrying no nonce and no target, the proof unable to travel in the header; a compiled verifier not existing. B2's A6 CITATION (1640322e2, 10:50 UK): O-07 citing B1's executed counter-example (fixture A6: one labelling at N = 2^10, k = 16 with a red sink, 193 to 200 of 200 roots accepted by the full verifier against 197 predicted; the paper's bound holding once per trace, not once per certificate); the eight B-T rows to B4 by name, B-T3 central. C2's FIXTURES (the B3 lane, 10:5x UK; the two physical holes named before the build: the chi-derived dataset recomputable by every prover at the same cost, the frozen closed-form word six ALU operations against a random 64-byte DRAM read, so the memory traffic optional; the hash chain a path graph, not depth-robust, O(N) only): the Rust reference over the frozen igneum-pow (the fingerprint 5f4d6dc6 read back; the program generator 6 ProgramClass::V6 from a fixed public epoch and era seed; labels l_v = H('L' | chi | v | l_{v-1} | the class v6 warp hashes at nonce l_{v-1}); B1's Merkle, challenge rule and verifier steps; the container C2MTPV61); the KATs (n = 4, k = 16) at the 4 MiB and the 1 GiB geometry in both dataset modes accepting; the known-failed cases refused by name; the honest row n = 8, k = 64, the 1 GiB geometry, one CPU thread: the closed-form dataset 1.71 ms per label, peak RSS 65 MB, the verifier 0.11 s; the memory-hard dataset 0.46 s per-trial cache fill then 14.97 ms per label (8,192 items of 64 bytes per label, each item 8 dependent cache reads), peak RSS 262 MB, the verifier 0.94 s and 262 MB per proof; the proof 36,973 bytes at k = 64: H1 measured (in closed form the "1 GiB" dataset costing the prover 65 MB, never stored; in the memory-hard mode the prover holding only the 256 MiB cache and the verifier the same, about 1 s per proof, not memory-easy); the candidate withdrawn by main's redirect, the holes the finding. B3's CONTROL (fce65393f gating): with B1's exact encoding a whole 5090 / 4090 labelling like 87 / 52 one-thread CPU instances at 32 MiB, 23 / 13 at 128 MiB, 5.8 / 3.5 at 512 MiB, at 80 to 110 W board; the card filling only at instances of 2 MiB or less. B1 LANDED (the landing hand, 10:53 UK: box master 0f3705273b16616b; forty-two landings). THE WINDOWS CANARY BOX UP (the relay lane, 10:43 to 10:50 UK): Windows Server 2022 Standard Evaluation (Desktop Experience) under KVM on build-7 (the container winvm, 4 vCPU, 8 GB, 80 GB, no GPU), the unattended install take 2 answering ssh at 10:43 UK (take 1 failing on the answer file's oobeSystem pass, its disk aside); ssh only through the box's loopback port; the relay id win-canary (hostname WIN-CANARY) seen on the relay at 10:50 UK, the agent running as the IgneumRelayService logon task with IgneumRelayWatchdog (five minutes) and IgneumRelayWatchdogLogon (the 10 s loop) from the hardened bundle (the install's first try failing on a class for the record: a workgroup box over ssh reporting its account domain as WORKGROUP and schtasks refusing it, fixed in install-agent.ps1 d3bcc134); the first workers report on build-1 at 10:49:06 UK (HTTP 200, /srv/workers/sources/pc-04383a0c.json, the "Windows canary" card live); left before the 2.0.2 record's nine lines: the Setup build on the VM (Inno Setup's download page serving HTML, the direct file URL taken), then the install and the canary through the agent; the 15:00 clock standing, likely well before. THE HASH-RATE FACTS FOR THE FOUNDER (the fleet lane, 10:45 to 10:54 UK): why 120 MH/s: at 10:45 exactly two fleet boxes mining on the reference chain (lp-4090-05 and lp-4090-06, 2 x 57 = 114 MH/s against the feed's 120); of the 98 reset boxes 40 had a synced node and NO miner (the roll's env carrying MINE=0, the census role "node" from the wave lists; the miner start never asked for), 41 still syncing (the 30 re-rolling plus eleven slow syncs), 15 dead (the OOM set), lp-4090-04's miner refused by the pack-id gate (the kit-2 miner's sha absent from its pair-miners.txt, the hubs outside the morning's push), lp-4090-36 stopped by the 27f54124 canary's quit; the mini and the PCs: the live feed counting 3 miners in ten minutes at 10:47; the fix done: 36 miners started under their pid files between 10:49 and 10:51 UK (MINER_ONLY start, MINE=1 written to each box's env), lp-04's pair file given the kit-2 sha and its miner started, lp-36 put back on the fleet kit; /api/live at 10:51: 184 MH/s, the difficulty 420 M (from 61 M), 120 blocks per 60 s, 30 miners in ten minutes, rising; the within-ten tracker now printing "N of them MINING" and naming the synced boxes not mining every five minutes; the full strength from the rows: 51 x 4090 at 57 MH = 2,907; 15 x 3090 at 46 = 690; one 5090 at 97; six L40S, one RTX 6000 Ada, three A5000, one A4000, seven 3060, three 3070, three 4070-class at 25 to 60 each (about 600): about 4.3 GH/s from all 101 boxes, about 3.7 GH/s from the ones alive at 11:00, the re-rolled 30 joining by about 11:30. THE 27f54124 CANARY FAILED ITS MINING LINE (the fleet lane): the sync from genesis to within ten in 1,041 s PASSED, then five minutes of mining with zero accepted blocks and zero refusals, no shard result in 900 s: 27f54124 does not go to the hubs; the cause from its miner log to the shipper and the node lane with the block. D02's THIRD VERSION (d799c086, 10:55 UK; the batch tv-d02-20261009-03): fee dependence in TV-04's own frame (the target one BU a year, the current schedule's year-1 paid subsidy 963,038,999.99 IGN; the multiples 0.1x to 10x; TV-04's emission.csv reconciling exactly beside TV-01's spec, 52 of 52 rows); the year fees must exceed the subsidy under A / B / C: at 1x year 5 / 1 / 3; at 4x year 9 / 13 / 11; at 10x year 11 / 17 / 16; at 0.25x and 0.1x year 1 under every schedule; the meaning: a longer same-cap schedule moves fee dependence later only when each coin buys at least 4x what it bought at launch; at 1x it moves it earlier (B and C starting with 50 and 63 percent of A's first-year subsidy); open B0, B2, B3. +THE MINERS AND THE 27f54124 CANARY (the fleet lane, 10:57 UK): the tracker's 10:54 read 42 within ten and 36 of them MINING with accepted blocks; lp-4090-04 (its pair file given the kit-2 miner sha) and lp-4090-36 (back on the fleet kit) started at 10:55; /live 184 MH/s and 120 blocks per 60 s at 10:51 against 120 MH/s at 10:45, rising as the packs export and the 30 re-rolled boxes land (about 11:30). The 27f54124 canary's run 1 FAIL on lp-4090-36 was the harness, not the kit: the sync line PASSED (genesis to within ten in 1,041 s) but the box's pack-id gate refused the canary miner (sha 727606c0, never added to the box's pair-miners.txt by the harness), so the mining and shard lines were never exercised; run 2 from 10:57 on lp-36 with the sha admitted, a fresh datadir, SEED the three hubs, the verdict by about 11:45 UK; 27f54124 nowhere near the hubs before that. THE PODS HANDED (the fleet lane, by 11:00 UK): X7's fk-x7-4090 at stock 450 W (10:38) and fk-x7-5090j (11:00, its cap named: 400 W of a 575 W default; six Vast 5090 offers in a row busy or capped at 400 to 500 W, so a stock 5090 does not exist on Vast this morning; the gate reading the cap, the row carrying it); X6's fk-x6-5090e (capped 500 W of 600, named) and fk-x6-4090c (stock 450 W) at 10:54; the first five X6 hosts refused by the gate (a 250 W 4090, a 535 driver, a busy 5090, a 400 W 5090, one unreadable), each destroyed within a minute; the day's gate refusals about USD 4. X6 AT THE SEAL (the steward, 10:56 UK): the twenty-four blind packs cut and read back on build-1 under /srv/artefacts/1p5x/x6/packs/ (twelve on the frozen tree 1a938abe4, twelve on the X1 candidate a99de07c, the sha256 files beside each, the family table identical by index on both trees, no finding); the commitment 2949e6a9, the sealed file and the kit's line on the Mac at mode 600; the run order with the fleet lane (ABBA per tuple in X1's P04 form, the rows by 12:10); the X5 sweep taking --ops 56064 --loads 256 for every pair; the AMD and Intel cells NOT RUN; R15-07 (B2, B4) landing under the lock, R15-05 recorded with B1's landing, R15-06 at B3's; the int8 cells (class:int8 on R15-03 and R15-04) and X7's negative control under R15-02 in the same batch (R15-02 citing the X7 README on master 6ba3f01b, the X8 rows and the verdict when landed); on the site: site-utc-times 7becf078 and guard-miner-bench 25d31fc2 landing on master as their gates go green; the deploy a public publish on the founder's own word in his chat, asked of main. + A SHARED-DEVNET FACT FROM THE FLEET (not this lane's, with the shipper and the infra lane): the Hetzner live seed 188.245.5.161:26611 is still on the old override object (digest eada4bda) 1 h 40 min after the 0.3.20 sweep (the fleet never touches Hetzner nodes, so it was outside the sweep); the 0.3.21 wipe canary c22-1 took five digest-mismatch rejects from it; an app with the packaged peers is refused at the seed and syncs through node1 and the hub only, a fresh joiner with only the seed cannot join, the 14 voters and the hub are unaffected; the owner puts the floor file ov16-floor-900000.json (sha 294f1f80) and the c4459193 pin on it. 0.3.21's STAGING (the node lane): the order dry-merges onto 55768f88 with nothing moving to 0.3.22; the late-join fix is 52e96c94 (70e4601e rebased onto 55768f88, exec suite 33 green with both new tests); f067f7c1, b0444f51 and 437f0438 merge clean in order; 2e32d5f6's one conflict (DST_ADDRESS beside pool-finish's DST_BINDING in consensus/core/src/finality.rs) kept both; the live-file digest eada4bda after each (every switch at never); the staging waits on the shipper's sweep-end word; the re-pin held. PC 2 DOWN AGAIN (main, 16:5x UK): the founder takes PC 2 down for cable work (PC 1 back but his desk); both PCs out of the sweep's waves, each updates on its poller on return; no PC job to PC 1; the Windows G1 completed before the outage, nothing reruns. 0.3.21's SECOND GATE LINE on 55768f88 (sha256 279b1b690e854fc9): the ten-minute mixed-version gate beside the 5899f603 pair, 13:37:40Z to 13:47:52Z, SUMMARY PASS (one digest b0afb2ee on five nodes; 223 new and 381 old blocks accepted by the old hub, 0 rejected; counts equal at 319, 486 and 604 through both clean joins and the restart step at 13:45:22Z; no panic); the node lane's two lines on 0.3.21's first candidate complete, in plan 6.9 on ca3-v4-node; the fleet's set on it (the bare-child 12 GB line, the wipe, the kept read, the cases) is the fleet's. 0.3.21's FIRST GATE LINE on 55768f88 (sha256 279b1b690e854fc9, the string read back; pairing igneum-pow 8c728ca3 at byte 5): the digest gate 13:35:41Z to 13:37:19Z SUMMARY PASS (a89be8a7 on both binaries with the peers; db9a85f9 refused, no peer; the live file's eada4bda unmoved); the ten-minute mixed-version gate from 13:37:40Z, line about 13:50Z. The 0.3.21 order as the shipper sent it: 55768f88; f067f7c1 and 70e4601e; b0444f51; 6eb21fc9; db28d331; then the re-pin from 8bdcbdd8 on the coordinator's word; suites between, the digest read after every one; the mirror's release-0.3.20-node back at the pin c4459193, release-0.3.21-node open at 55768f88. THE LATE-JOIN COMMIT (N9's second half, the node lane): 70e4601e on the box mirror as branch proof-hold-fix, from c4459193, two files (igneum/exec/src/proving.rs, protocol/flows/src/v10/proving.rs); the gap was the fetch side on the joiner (the served record ran the native check against the joiner's trailing exec state before anything was stored, the check refused it, the proof was never held, the body rule read "not held" for 20 s and failed the IBD); the fix holds the proof by hash before the checks (the pool entry still needs them) and the serve side says when it holds fewer than asked; the exec suite 32 passed at 13:26Z with the known-failed shape first, the flows check green 13:28Z, igneumd on build-1 at the 0321 worktree path built 13:32Z, sha256 17649eeb2f7d1290, string read back; with the testnet lane (the resume form, B alone); it joins the 0.3.21 staging as its own commit. THE WIPE CANARY ON c19-1, c4459193 (sha 45be9b02d1b002f5, string read back): FORM END rc 0 at 13:50:53Z. Wipe synced 13:35:50Z (57 minutes, inside the 98-minute class); mining 13:36:00Z to 13:47:07Z, 66 mined, 66 accepted, 0 rejected, isSynced true at the tip throughout; the hub holds 41 of its blocks in its last 700 with 0 rejects (13:47:09Z); the restart on its kept datadir at 13:47:15Z: the old process stopped at once (the new process's first lock line seven seconds after the marker; the watchdog held nothing, the b7cc37e7 fault closed), synced again at 13:48:39Z after 84 s, 109 templates read with max 3,432 ms and 0 timeouts; the kept read on pool-1's 0.3.17 copy on the same pod passed at 13:38Z (the rewrite line once, a clean second start). The pin's set on c4459193: the digest gate PASS, the mixed-version gate PASS, the wipe canary PASS, the kept read PASS, the restart PASS, the 12 GB line proves and verifies (paid is a race, not a gate); CASES END from c20-1 (about 14:50Z) is the last pin line. THE INTEROP FACT stands from the void run: the 5899f603 hub accepted 235 object-byte-5 blocks from the 8097d600 node with 0 rejected, one digest on all five nodes on the live sixteen-field file. The gates: the digest test and the kaspa-pow vector test (the amended devnet epoch-0 id 1a4230699a6b9c60 must equal, c120d7963abdcd96 must differ, the v3 control unchanged) on the box; the mixed-version Devnet 2 gate (the amended 0.3.20 node beside a 5899f603 node for ten minutes on the live file without the v4 fields) after the Mac build; the fresh-join canary the 0.3.20 cut's | | Main's rulings (7 October, morning) | no generator change to v4 on the live devnet; the record's null is the window model with numbers, sent by the hash lane to the attack-pass lane so AP-F8-1 re-gates against it; a fault beyond the model (a low-entropy source at site 15) stops at the coordinator with the two options priced (a 0.3.19 class amendment before the flip, or the flip held at the floor), nothing shipping without the founder's word; the tighter tail, an acceptance bound on the hot-set share, is a CLASS V5 item (sent to the v5 lane a6410f3b8abefb762 with the 64-seed census as its gate; the bound's number follows from the model) |