From e05eb0c43a6a37bb1f26c5d66fa1f2fbdb783200 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Tue, 6 Oct 2026 16:24:02 +0000 Subject: [PATCH] Counter ASIC 3.0 gates (node): the program id carries the class. A class v4 program is generator 4 wherever it is made: the CLI's --era path stamps the generator from the class (era_generator_of: 4 on V4_CLASS, 3 otherwise; ProgramClass::of_load_class), show honours --program-class and --era-hex; the shadow block marks class v4 in packcheck, packfile.h and the Metal worker (a generator 3 pack with IGNEUM_SHADOW_INSTRS is refused as a v4 program stamped v3, a generator 4 pack without it is refused; generator 2 ladder packs unchanged); the seven gate packs re-exported (generator 4, id c120d7963abdcd96 against the v3 control's 73bcbfe8ccf988f1, every other line byte-identical); class-v4.mjs asserts every v4 epoch's id against the CLI's same-seed v3 and v4 ids (--id-check-against v4 is the assertion's failed case); v2 and v3 ids byte-identical (60 + 7 + 4 + 19 + 7, the pinned packs) Co-Authored-By: Claude Fable 5.1 --- igneum-pow/src/generator.rs | 38 ++++++++++++++++++- igneum-pow/src/main.rs | 15 ++++++-- igneum-pow/src/packcheck.rs | 23 +++++++++++ infra/fast-time/class-v4.mjs | 34 +++++++++++++++-- proto-cuda/nvrtc/emu/packfile-test.c | 18 ++++++++- proto-cuda/nvrtc/packfile.h | 12 ++++++ .../packs-ca3-v4/v4-devnet-epoch0/program.h | 11 +++--- .../v4-devnet-epoch0/program.json | 6 +-- .../packs-ca3-v4/v4-devnet-epoch0/vectors.h | 2 +- .../v4-devnet-epoch0/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-0/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-0/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-0/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-0/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-1/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-1/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-1/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-1/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-2/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-2/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-2/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-2/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-3/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-3/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-3/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-3/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-4/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-4/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-4/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-4/vectors.json | 2 +- proto-cuda/packs-ca3-v4/v4-era-5/program.h | 11 +++--- proto-cuda/packs-ca3-v4/v4-era-5/program.json | 6 +-- proto-cuda/packs-ca3-v4/v4-era-5/vectors.h | 2 +- proto-cuda/packs-ca3-v4/v4-era-5/vectors.json | 2 +- proto-metal/main.swift | 5 +++ 35 files changed, 211 insertions(+), 81 deletions(-) diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 7cbffc106..b55e2c954 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -814,7 +814,15 @@ pub const V3_ALLOWED: [u8; 1] = [1]; /// over the width set `allowed`, generator 3 stamped and the era bytes recorded (`docs/plans/era-layout.md`). /// The chain's path is this with `base = V3_CLASS` and `allowed = V3_ALLOWED`. pub fn generate_era(seed_string: &str, seed_bytes: &[u8], base: LoadClass, era_bytes: &[u8], allowed: &[u8]) -> Program { - generate_era_generator(seed_string, seed_bytes, base, era_bytes, allowed, GENERATOR_VERSION_V3) + generate_era_generator(seed_string, seed_bytes, base, era_bytes, allowed, era_generator_of(&base)) +} + +/// The generator version an era program over `base` is stamped with: 4 when the base (minus any era) is +/// [`V4_CLASS`], else 3. Counter ASIC 3.0, 6 October 2026: the seven gate packs exported through the CLI's `--era` +/// path on `mx8+sh256x27` were stamped generator 3 and so carried the v3 control's program id (`program_id(3, seed, +/// attempt)` is class-independent inside a generator version); a class v4 program is generator 4 wherever it is made. +pub fn era_generator_of(base: &LoadClass) -> u32 { + if ProgramClass::of_load_class(base) == Some(ProgramClass::V4) { GENERATOR_VERSION_V4 } else { GENERATOR_VERSION_V3 } } /// [`generate_era`] with the generator version stamped by the caller: 3 for class v3 over [`V3_CLASS`], 4 for @@ -878,6 +886,21 @@ impl ProgramClass { *self != ProgramClass::V2 } + /// The program class whose load class `class` is, the era draw set aside: [`LoadClass::V2`] is v2, [`V3_CLASS`] + /// is v3, [`V4_CLASS`] is v4; a measurement class (a width, a derivation length, another shadow size) is none. + pub fn of_load_class(class: &LoadClass) -> Option { + let base = LoadClass { era: None, ..*class }; + if base == LoadClass::V2 { + Some(ProgramClass::V2) + } else if base == V3_CLASS { + Some(ProgramClass::V3) + } else if base == V4_CLASS { + Some(ProgramClass::V4) + } else { + None + } + } + /// The generator version as a byte, for wire formats that carry the class as a number. pub fn as_u8(&self) -> u8 { self.generator_version() as u8 @@ -1727,6 +1750,19 @@ mod tests { assert_eq!(v4.program_id(), program_id(GENERATOR_VERSION_V4, &v4.seed, v4.attempt)); assert_ne!(v4.program_id(), v3.program_id()); assert_ne!(v4.program_id(), program_id(GENERATOR_VERSION, &v4.seed, v4.attempt)); + // the CLI's `--era` path (generate_era over a base class) stamps 4 on V4_CLASS and 3 on anything else, so a + // pack exported with `--class mx8+sh256x27 --era` is a class v4 pack with the v4 id (the 6 October trap: + // the seven gate packs stamped 3 carried the v3 control's id) + let via_era = generate_era("igneum-genesis", b"igneum-genesis", V4_CLASS, &era, &V3_ALLOWED); + assert_eq!(via_era, v4, "the --era path and the chain path make the same v4 program"); + assert_eq!(via_era.generator, GENERATOR_VERSION_V4); + assert_eq!(generate_era("igneum-genesis", b"igneum-genesis", V3_CLASS, &era, &V3_ALLOWED), v3); + assert_eq!(generate_era("igneum-genesis", b"igneum-genesis", LoadClass::MX8.with_shadow(256, 13), &era, &V3_ALLOWED).generator, GENERATOR_VERSION_V3, "a measurement class stays generator 3"); + assert_eq!(ProgramClass::of_load_class(&v4.class), Some(ProgramClass::V4)); + assert_eq!(ProgramClass::of_load_class(&v3.class), Some(ProgramClass::V3)); + assert_eq!(ProgramClass::of_load_class(&LoadClass::V2), Some(ProgramClass::V2)); + assert_eq!(ProgramClass::of_load_class(&LoadClass::MX8.with_shadow(256, 13)), None); + assert_eq!(ProgramClass::of_load_class(&LoadClass::MX4), None); // without an era (a template before the era is known) the bare V4_CLASS stands, generator 4 let bare = generate_from_seed_bytes_program_class("igneum-genesis", b"igneum-genesis", ProgramClass::V4, None); assert_eq!(bare.class, V4_CLASS); diff --git a/igneum-pow/src/main.rs b/igneum-pow/src/main.rs index be1db5e0e..3d32504ee 100644 --- a/igneum-pow/src/main.rs +++ b/igneum-pow/src/main.rs @@ -161,7 +161,8 @@ fn parse() -> Args { /// `Epoch::from_chain_seeds` does); the pack then carries IGNEUM_PROGRAM_CLASS "v3" and IGNEUM_ERA_SEED_HEX. fn stamp_era(e: &mut Epoch, a: &Args) { if let Some((_, bytes, _)) = &a.era { - e.program.generator = GENERATOR_VERSION_V3; + // generator 4 on V4_CLASS (class v4, Counter ASIC 3.0), 3 on every other era program + e.program.generator = igneum_pow::generator::era_generator_of(&e.program.class); e.program.era_bytes = Some(bytes.clone()); } } @@ -405,9 +406,15 @@ fn accept(a: &Args) { fn show(a: &Args) { let (label, bytes) = seed_bytes_of(a); - let mut p = igneum_pow::generator::generate_from_seed_bytes_class(&label, &bytes, a.class); - if let Some((_, eb, _)) = &a.era { - p.generator = GENERATOR_VERSION_V3; + // --program-class: the chain's own derivation (the era from --era-hex), as the node and the miner draw it; else + // the load class of --class, the era of --era composed over it + let era_hex_bytes = a.era_hex.as_deref().map(|h| igneum_pow::bind::unhex(h).unwrap_or_else(|| usage())); + let mut p = match a.program_class { + Some(pc) => igneum_pow::generator::generate_from_seed_bytes_program_class(&label, &bytes, pc, era_hex_bytes.as_deref()), + None => igneum_pow::generator::generate_from_seed_bytes_class(&label, &bytes, a.class), + }; + if let (None, Some((_, eb, _))) = (a.program_class, &a.era) { + p.generator = igneum_pow::generator::era_generator_of(&p.class); p.era_bytes = Some(eb.clone()); } println!( diff --git a/igneum-pow/src/packcheck.rs b/igneum-pow/src/packcheck.rs index e8df4c84a..177d74b3a 100644 --- a/igneum-pow/src/packcheck.rs +++ b/igneum-pow/src/packcheck.rs @@ -186,6 +186,20 @@ pub fn verify_pack_texts_chain( } } let era_hex = define_str(program_h, "IGNEUM_ERA_SEED_HEX").map(|h| h.to_ascii_lowercase()); + // Counter ASIC 3.0 (6 October 2026): the shadow block is the mark of class v4, so a generator 4 pack carries + // IGNEUM_SHADOW_INSTRS and a generator 3 pack does not; a pack exported as class v4 but stamped generator 3 (the + // seven gate packs of 6 October, which carried the v3 control's program id because `program_id(3, ..)` is + // class-independent) is refused here instead of mining as class v3 under the wrong id, and a generator 4 pack + // without the block is no v4 pack. A generator 2 pack with a shadow (the measurement ladder of + // proto-cuda/packs-ca3-shadow) carries a class-bearing id and stays loadable. + let shadow = define_u32(program_h, "IGNEUM_SHADOW_INSTRS").unwrap_or(0); + match (class, shadow > 0) { + (ProgramClass::V4, false) => return Err(PackFault::Disagree("IGNEUM_GENERATOR 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack".into())), + (ProgramClass::V3, true) => { + return Err(PackFault::Disagree(format!("IGNEUM_GENERATOR 3 (class v3) with a shadow block (IGNEUM_SHADOW_INSTRS {shadow}): a class v4 program is generator 4 (export the pack as class v4)"))) + } + _ => {} + } if let Some(want) = want_class { if want != class { return Err(PackFault::WrongClass(format!("the pack is program class {} (generator {generator}), the chain is on class {}", class.name(), want.name()))); @@ -416,5 +430,14 @@ mod tests { assert!(err.to_string().contains("class v4 pack without IGNEUM_ERA_SEED_HEX"), "{err}"); // the v3 pack of the same seeds is unchanged by the v4 class existing assert_eq!(program_header(&v3.program, "test day", &v3.dataset), h3); + // the 6 October trap: a v4 program stamped generator 3 (the CLI's old --era path) is refused for its shadow + // block, whatever class is wanted; and a generator 4 header without the block is refused too + let stamped3 = h4.replace("#define IGNEUM_GENERATOR 4\n", "#define IGNEUM_GENERATOR 3\n").replace("#define IGNEUM_PROGRAM_CLASS \"v4\"\n", "#define IGNEUM_PROGRAM_CLASS \"v3\"\n"); + let err = verify_pack_texts(&stamped3, None, &e, &d).unwrap_err(); + assert!(matches!(err, PackFault::Disagree(_)) && err.to_string().contains("shadow block"), "{err}"); + assert!(verify_pack_texts_chain(&stamped3, None, &e, &d, Some(ProgramClass::V3), Some(&era)).is_err()); + let no_shadow = h4.replace("#define IGNEUM_SHADOW_INSTRS 256\n", ""); + let err = verify_pack_texts(&no_shadow, None, &e, &d).unwrap_err(); + assert!(matches!(err, PackFault::Disagree(_)) && err.to_string().contains("without IGNEUM_SHADOW_INSTRS"), "{err}"); } } diff --git a/infra/fast-time/class-v4.mjs b/infra/fast-time/class-v4.mjs index 6fda03ad0..af1a309f8 100644 --- a/infra/fast-time/class-v4.mjs +++ b/infra/fast-time/class-v4.mjs @@ -30,7 +30,7 @@ // (0x1e010000 = 2^24 hashes per block: under a second on an M5 Max; the CPU miners on nodes 1 and 2 then verify // and rarely find). -import { spawn } from 'node:child_process'; +import { spawn, spawnSync } from 'node:child_process'; import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync } from 'node:fs'; import { connectRpc } from '../../tools/finality-attacks/lib/rpc.mjs'; import { devAddress } from '../../tools/harness/lib/address.mjs'; @@ -40,6 +40,8 @@ const FILE = `${ROOT}infra/fast-time/override-60x.json`; const BIN = process.env.IGNEUM_CA3_BIN || `${ROOT}vendor/igneum-node-ca3v4/target-ca3v4/release`; const IGNEUMD = process.env.IGNEUMD || `${BIN}/igneumd`; const CPU_MINER = process.env.IGNEUM_MINER || `${BIN}/igneum-miner`; +// the igneum-pow CLI, for the program-id assertion (the same-seed v3 and v4 ids of every v4 epoch) +const IGNEUM_POW = process.env.IGNEUM_POW || `${ROOT}igneum-pow/target/release/igneum-pow`; const TMP = '/tmp/igneum-fast-time-v4'; const BASE = 29660, SUFFIX = 966; const NEVER = '18446744073709551615'; @@ -54,6 +56,12 @@ const SECS = flag('secs', 420); const ACTIVATION = actflag('activation', 150); // class v4 (N5); null = never const V3_ACTIVATION = actflag('v3-activation', 60); // class v3 (N4); null = never const EPOCHS_AFTER = flag('epochs-after', 2); +// The program-id assertion (6 October 2026, the hash lane's finding: program_id(3, seed, attempt) is class-independent, so +// a v4 pack stamped generator 3 carried the v3 id and no id check could fire): every v4 epoch's id, as the three miners +// print it, must equal the CLI's class v4 id of that seed and era and DIFFER from the CLI's class v3 id of the same seed +// and era. `--id-check-against v4` is the assertion's own known-failed case: the "must differ" side is then the v4 id +// itself, so the check must read false. +const ID_AGAINST = sflag('id-check-against') || 'v3'; const THREADS = flag('threads', 1); const started = []; const log = (...a) => console.log(new Date().toISOString().slice(11, 23), ...a); @@ -151,7 +159,7 @@ nodes.forEach((n, i) => { }); const pay = devAddress('fast-time-v4'); -const epochs = new Map(); // epoch index -> { class, firstSeenDaa, at } +const epochs = new Map(); // epoch index -> { class, firstSeenDaa, at, eraSeed } let firstV4 = null, firstV3 = null, lastEpoch = -1, lastReport = 0, lastDaa = 0, switchEnd = null; const samples = []; while (Date.now() - t0 < SECS * 1000) { @@ -164,7 +172,7 @@ while (Date.now() - t0 < SECS * 1000) { era = pe.eraIndex; eraSeed = pe.eraSeed; act3 = pe.programClassV3ActivationDaa; act4 = pe.programClassV4ActivationDaa; } catch (e) { log(`template: ${e.message}`); } if (epoch != null && epoch !== lastEpoch) { - epochs.set(epoch, { class: cls, firstSeenDaa: daa, at: +since() }); + epochs.set(epoch, { class: cls, firstSeenDaa: daa, at: +since(), eraSeed: eraSeed == null ? null : String(eraSeed) }); log(`epoch ${lastEpoch} -> ${epoch} at daa ${daa}, ${since()} s: template class ${cls} (generator), next epoch class ${nextCls}, era ${era} seed ${String(eraSeed).slice(0, 16)}, activation v3 ${act3} v4 ${act4}`); if (firstV3 == null && cls === 3) { firstV3 = { epoch, daa, at: +since() }; log(`CLASS SWITCH: the template is class v3 from epoch ${epoch} (daa ${daa}) at ${since()} s wall`); } if (firstV4 == null && cls === 4) { firstV4 = { epoch, daa, at: +since() }; log(`CLASS SWITCH: the template is class v4 from epoch ${epoch} (daa ${daa}) at ${since()} s wall`); } @@ -215,6 +223,21 @@ for (const i of [0, 1, 2]) for (const l of minerLog(i)) { // pays the cache; a v4 epoch after a v3 one reuses the v3 day cache, so its number is the program alone) const programRows = [...programs.values()].sort((a, b) => a.epoch - b.epoch).map(p => ({ epoch: p.epoch, class: p.class, program_id: p.id, seed: p.seed, miners: p.miners.size, disagree: !!p.disagree, ready_ms: p.ready_ms })); const idsOf = (c) => programRows.filter(p => p.class === c).map(p => p.program_id); +// the CLI's ids for the same seed and era: `igneum-pow show --epoch-hex --program-class v3|v4 --era-hex ` +function cliId(seedHex, eraHex, cls) { + if (!existsSync(IGNEUM_POW)) return null; + const r = spawnSync(IGNEUM_POW, ['show', '--epoch-hex', seedHex, '--program-class', cls, '--era-hex', eraHex], { encoding: 'utf8' }); + const m = /program id ([0-9a-f]{16})/.exec(r.stdout || ''); + return m ? m[1] : null; +} +const idRows = []; +for (const [k, e] of programs) { + if (e.class !== 'v4') continue; + const era = epochs.get(e.epoch)?.eraSeed; + if (!era) { idRows.push({ epoch: e.epoch, seed: e.seed, era: null, miners_id: e.id, cli_v3: null, cli_v4: null }); continue; } + idRows.push({ epoch: e.epoch, seed: e.seed, era: era.slice(0, 16), miners_id: e.id, miners: e.miners.size, cli_v3: cliId(k, era, 'v3'), cli_v4: cliId(k, era, 'v4') }); +} +const idAgainst = (r) => ID_AGAINST === 'v4' ? r.cli_v4 : r.cli_v3; const v2Ids = idsOf('v2'), v3Ids = idsOf('v3'), v4Ids = idsOf('v4'); const olderIds = [...v2Ids, ...v3Ids]; @@ -268,6 +291,8 @@ const checks = { v2_programs_seen_when_v3_starts_later: FIRST_V3_EPOCH == null || FIRST_V3_EPOCH === 0 || v2Ids.length > 0, program_ids_differ_across_the_switch: v4Ids.length > 0 && !olderIds.some(id => v4Ids.includes(id)), miners_agree_on_every_program: programRows.every(p => !p.disagree), + v4_ids_equal_the_cli_v4_id_of_the_seed_and_era: idRows.length > 0 && idRows.every(r => r.cli_v4 != null && r.cli_v4 === r.miners_id && r.miners === 3), + v4_ids_differ_from_the_same_seed_v3_id: idRows.length > 0 && idRows.every(r => idAgainst(r) != null && idAgainst(r) !== r.miners_id), zero_rejected_by_miners: rejectedMiner.every(r => r.length === 0), zero_rejected_by_nodes: rejectedNode.every(r => r.length === 0), sinks_agree: new Set(sinks).size === 1, @@ -287,7 +312,7 @@ const summary = { node: IGNEUMD, miner: CPU_MINER, metal_worker: METAL, genesis_bits: `0x${GENESIS_BITS.toString(16)}`, template_switch_v3: firstV3, template_switch: firstV4, run_ended_at_s: switchEnd, final_daa: lastDaa, blocks: { total: blocks.length, before_boundary: before.length, after_boundary: after.length, chain_before: chainBefore, chain_after: chainAfter }, - programs: programRows, accepted_per_miner: accepted, + programs: programRows, program_id_rows: idRows, id_check_against: ID_AGAINST, igneum_pow: IGNEUM_POW, accepted_per_miner: accepted, rejected_by_miners: rejectedMiner.map(r => r.length), rejected_by_nodes: rejectedNode.map(r => r.length), rejected_lines: [...rejectedMiner.flat(), ...rejectedNode.flat()].slice(0, 20), sinks, block_counts: counts, tips_per_node: tips, switch_lines: switchLines, v3_switch_lines: v3SwitchLines, samples, metal, @@ -299,6 +324,7 @@ if (metal) { for (const l of [...metal.prepares, ...metal.prepared, ...metal.swaps]) log(` ${l.slice(0, 260)}`); for (const l of [...metal.mismatch_lines, ...metal.refused].slice(0, 10)) log(` BAD ${l.slice(0, 260)}`); } +for (const r of idRows) log(`PROGRAM ID epoch ${r.epoch} seed ${r.seed} era ${r.era}: miners ${r.miners_id} (${r.miners ?? '?'} of 3) cli v4 ${r.cli_v4} cli v3 ${r.cli_v3} ${r.cli_v4 === r.miners_id && r.cli_v3 !== r.miners_id ? 'OK' : 'MISMATCH'}`); for (const [k, v] of Object.entries(checks)) if (!v) log(`FAILED CHECK ${k}`); log(`summary: ${TMP}/summary.json`); await stopAll(); diff --git a/proto-cuda/nvrtc/emu/packfile-test.c b/proto-cuda/nvrtc/emu/packfile-test.c index eea550e70..dca59a8a8 100644 --- a/proto-cuda/nvrtc/emu/packfile-test.c +++ b/proto-cuda/nvrtc/emu/packfile-test.c @@ -132,10 +132,24 @@ int main(int argc, char** argv) { CHECK(pf_pack_class_ok("v2", "", "v2", EPOCH_33, why, sizeof(why)) == 1, "an era named on a v2 job is ignored"); // Counter ASIC 3.0 (6 October 2026): a generator 4 pack is class v4 with its era seed; a job naming class v3 // refuses it and a job naming class v4 refuses a v3 pack; the era rule applies to v4 as to v3 - snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v4\"\n#define IGNEUM_ERA_SEED_HEX \"%s\"\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, EPOCH_33, sw, kw); + snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v4\"\n#define IGNEUM_ERA_SEED_HEX \"%s\"\n#define IGNEUM_SHADOW_INSTRS 256\n#define IGNEUM_SHADOW_REPS 27\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, EPOCH_33, sw, kw); write_file(dir, "program.h", text); err[0] = 0; CHECK(pf_load(dir, &pk, err, sizeof(err)) == 1 && strcmp(pk.programClass, "v4") == 0 && strcmp(pk.eraHex, EPOCH_33) == 0, "a generator 4 pack loads as class v4 with its era seed"); + // the 6 October trap: the same text stamped generator 3 (a v4 program exported as v3, the v3 control's id) is refused; generator 4 without the block too + snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 3\n#define IGNEUM_PROGRAM_CLASS \"v3\"\n#define IGNEUM_ERA_SEED_HEX \"%s\"\n#define IGNEUM_SHADOW_INSTRS 256\n#define IGNEUM_SHADOW_REPS 27\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, EPOCH_33, sw, kw); + write_file(dir, "program.h", text); + err[0] = 0; + CHECK(pf_load(dir, &pk, err, sizeof(err)) == 0 && strstr(err, "with a shadow block") != NULL, "a generator 3 pack with a shadow block (a v4 program stamped v3) is refused"); + snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v4\"\n#define IGNEUM_ERA_SEED_HEX \"%s\"\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, EPOCH_33, sw, kw); + write_file(dir, "program.h", text); + err[0] = 0; + CHECK(pf_load(dir, &pk, err, sizeof(err)) == 0 && strstr(err, "without IGNEUM_SHADOW_INSTRS") != NULL, "a generator 4 pack without the shadow block is refused"); + // back to the good v4 pack for the class-token checks below + snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v4\"\n#define IGNEUM_ERA_SEED_HEX \"%s\"\n#define IGNEUM_SHADOW_INSTRS 256\n#define IGNEUM_SHADOW_REPS 27\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, EPOCH_33, sw, kw); + write_file(dir, "program.h", text); + err[0] = 0; + CHECK(pf_load(dir, &pk, err, sizeof(err)) == 1, "the v4 pack with its block loads again"); CHECK(pf_pack_class_ok(pk.programClass, pk.eraHex, "v4", EPOCH_33, why, sizeof(why)) == 1, "the v4 pack matches a job naming class v4 and its era"); CHECK(pf_pack_class_ok(pk.programClass, pk.eraHex, "v3", EPOCH_33, why, sizeof(why)) == 0 && strstr(why, "program class mismatch") == why, "a job naming class v3 refuses the v4 pack"); CHECK(pf_pack_class_ok(pk.programClass, pk.eraHex, "v4", EPOCH_34, why, sizeof(why)) == 0 && strstr(why, "era seed mismatch") == why, "a job naming another era refuses the v4 pack"); @@ -144,7 +158,7 @@ int main(int argc, char** argv) { char c[8] = {0}, e[65] = {0}; CHECK(pf_class_token("class=v4", c, sizeof(c), e, sizeof(e)) == 1 && strcmp(c, "v4") == 0, "the class=v4 token is read"); } - snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v3\"\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, sw, kw); + snprintf(text, sizeof(text), "#define IGNEUM_SEED_BYTES_HEX \"%s\"\n#define IGNEUM_DAY_BYTES_HEX \"%s\"\n#define IGNEUM_GENERATOR 4\n#define IGNEUM_PROGRAM_CLASS \"v3\"\n#define IGNEUM_SHADOW_INSTRS 256\n#define IGNEUM_DATASET_LOG2 28\n#define IGNEUM_DATASET_MODE 1\n#define IGNEUM_SEEDW_INIT { %s }\n#define IGNEUM_KEY_INIT { %s }\n#define IGNEUM_CACHE_LOG2_WORDS 26\n#define IGNEUM_CACHE_SEGMENTS 4096u\n", EPOCH_34, DAY_20731, sw, kw); write_file(dir, "program.h", text); err[0] = 0; CHECK(pf_load(dir, &pk, err, sizeof(err)) == 0 && strstr(err, "does not match IGNEUM_GENERATOR 4") != NULL, "a v3 class line on a generator 4 pack is refused"); diff --git a/proto-cuda/nvrtc/packfile.h b/proto-cuda/nvrtc/packfile.h index 77318617e..48c09fab5 100644 --- a/proto-cuda/nvrtc/packfile.h +++ b/proto-cuda/nvrtc/packfile.h @@ -292,6 +292,18 @@ static int pf_load(const char* dir, PfPack* pk, char* err, size_t cap) { free(prog); return pf_fail(err, cap, m); } strcpy(pk->programClass, pk->generator == 4 ? "v4" : pk->generator == 3 ? "v3" : "v2"); + { + /* Counter ASIC 3.0 (6 October 2026): the shadow block marks class v4. A generator 3 pack with IGNEUM_SHADOW_INSTRS + * is a v4 program stamped as v3 (the old export path; it carried the v3 control's program id) and is refused; + * a generator 4 pack without the block is no v4 pack. */ + uint32_t shadow = 0; + if (!pf_define_u32(prog, "IGNEUM_SHADOW_INSTRS", &shadow)) shadow = 0; + if (pk->generator == 4 && shadow == 0) { free(prog); return pf_fail(err, cap, "program pack generator 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack"); } + if (pk->generator == 3 && shadow != 0) { /* a generator 2 pack with a shadow is the measurement ladder (a class-bearing id) and loads */ + char m[220]; snprintf(m, sizeof(m), "program pack generator %u with a shadow block (IGNEUM_SHADOW_INSTRS %u): a class v4 program is generator 4 (export the pack as class v4)", (unsigned)pk->generator, (unsigned)shadow); + free(prog); return pf_fail(err, cap, m); + } + } { char named[8] = {0}; if (pf_define_str(prog, "IGNEUM_PROGRAM_CLASS", named, sizeof(named)) && strcmp(named, pk->programClass) != 0) { diff --git a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.h b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.h index 603cd74cd..797566612 100644 --- a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.h +++ b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.json b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.json index c60deb85e..0df7ca434 100644 --- a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.json +++ b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07", "load_class": "mx8-erad810f22d+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.h b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.h index dcb7685bf..15de69d34 100644 --- a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.json b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.json index f45be8278..91635da08 100644 --- a/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-devnet-epoch0/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0xcefc114b62c2013b", "0x82df54bee88f1fa9", "0x94ed24d32cecf436", "0x8a9bd67e3fed0c5b", "0x7c1a21514ebe42b7", "0x0edd5b084c5815ed", "0x077927721192da87", "0x28e26e3eb72cd8c4", diff --git a/proto-cuda/packs-ca3-v4/v4-era-0/program.h b/proto-cuda/packs-ca3-v4/v4-era-0/program.h index d818fc48e..12e272815 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-0/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-0/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "8bffdd3366b9c3ffe89c1231e91538d531cfa717307df5c48ccba43096e17212" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-0/program.json b/proto-cuda/packs-ca3-v4/v4-era-0/program.json index f0399738b..0f1becba3 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-0/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-0/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "8bffdd3366b9c3ffe89c1231e91538d531cfa717307df5c48ccba43096e17212", "load_class": "mx8-erab2ed8a89+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-0/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-0/vectors.h index 5ad619153..84254f8d6 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-0/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-0/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-0/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-0/vectors.json index 226840642..832538fa7 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-0/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-0/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0xc6ac65d8c667c94b", "0x423ba68373b366fb", "0x21eb7c55ad8be449", "0x241e717cf2ab882a", "0xa615906f3f9be2ce", "0xce309393aa36b7ef", "0x6243ddb51a337304", "0xe0495ce514ee4267", diff --git a/proto-cuda/packs-ca3-v4/v4-era-1/program.h b/proto-cuda/packs-ca3-v4/v4-era-1/program.h index d6f11642b..9e205a43b 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-1/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-1/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "ff87ad96a1b53f367a95d5ca123bab64211bd9aa57fc7ad3c5e2d496c20138d4" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-1/program.json b/proto-cuda/packs-ca3-v4/v4-era-1/program.json index f6e7015c1..8c26983fd 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-1/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-1/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "ff87ad96a1b53f367a95d5ca123bab64211bd9aa57fc7ad3c5e2d496c20138d4", "load_class": "mx8-era676a17fc+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-1/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-1/vectors.h index b17b8c1b4..5a0861fe4 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-1/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-1/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-1/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-1/vectors.json index 2ba98770e..d3d40ed6a 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-1/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-1/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0xbd25be585e9f483a", "0x42415dc1008bc167", "0x808b481a2ba0ee31", "0x9482f0d11a102aac", "0xc8782e4fbd38f71d", "0xbef02f6193c78dfe", "0xf790061d0baf0ee2", "0x8df707bfebbb5266", diff --git a/proto-cuda/packs-ca3-v4/v4-era-2/program.h b/proto-cuda/packs-ca3-v4/v4-era-2/program.h index 3fef632bd..8a962d87e 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-2/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-2/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "df57136f2ad5f410e6145023090eea148c1342ccef5a5f541afa590be7e44745" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-2/program.json b/proto-cuda/packs-ca3-v4/v4-era-2/program.json index 625d18b4a..554430aa9 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-2/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-2/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "df57136f2ad5f410e6145023090eea148c1342ccef5a5f541afa590be7e44745", "load_class": "mx8-era843155d7+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-2/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-2/vectors.h index c6c40eb8e..78a83a960 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-2/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-2/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-2/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-2/vectors.json index 8d5f84b65..731647a9d 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-2/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-2/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0xd15f7638ecab0638", "0xf71dc04ca33f9049", "0xdda27e825b83045f", "0x0babd54b6eb42cb6", "0x22b4cafe1d3a82d7", "0x1ded091e583999c8", "0x9445769b44b82cbd", "0xbd850d3ec7937586", diff --git a/proto-cuda/packs-ca3-v4/v4-era-3/program.h b/proto-cuda/packs-ca3-v4/v4-era-3/program.h index 8f20e2a35..8481a9f52 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-3/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-3/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "e593fc1d48475c88e456632f6aa0a752a5fdbca3c33022afe37680e44b7dfd11" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-3/program.json b/proto-cuda/packs-ca3-v4/v4-era-3/program.json index de459b864..09cc22767 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-3/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-3/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "e593fc1d48475c88e456632f6aa0a752a5fdbca3c33022afe37680e44b7dfd11", "load_class": "mx8-erad6367bfe+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-3/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-3/vectors.h index cc4e31e1d..a2557ab32 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-3/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-3/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-3/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-3/vectors.json index 25d5d144a..7ef3fb872 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-3/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-3/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0x40b750d1c8a8070f", "0x0eabee774c28ab59", "0xcc13c43e53c39432", "0x6a9c15036cd8ea3e", "0x33632873969d8ede", "0x598d17a33791fdc9", "0x2eff1230b4254f1e", "0xe94dd51fbd984bce", diff --git a/proto-cuda/packs-ca3-v4/v4-era-4/program.h b/proto-cuda/packs-ca3-v4/v4-era-4/program.h index d6c011769..0d279daaa 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-4/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-4/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "5e0587f455a86e91e4990f5c481a34cca0044d3f3ae519adcae58ddc82885d31" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-4/program.json b/proto-cuda/packs-ca3-v4/v4-era-4/program.json index 7c473c6f8..b3eec7bbf 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-4/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-4/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "5e0587f455a86e91e4990f5c481a34cca0044d3f3ae519adcae58ddc82885d31", "load_class": "mx8-era4488f3ed+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-4/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-4/vectors.h index 0de90ccdc..f11d1b8cd 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-4/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-4/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-4/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-4/vectors.json index b08eb76e8..cc5539d3f 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-4/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-4/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0x32d75a818461b0fe", "0xfb58b5a9a0749f1a", "0x7f1ef1c14a39acb7", "0x241bbf0d64ef82da", "0xa91a888a98e1a327", "0x85236aa911aee1cc", "0x2b621fc52bd4de06", "0xccb36c7b29b9f7ee", diff --git a/proto-cuda/packs-ca3-v4/v4-era-5/program.h b/proto-cuda/packs-ca3-v4/v4-era-5/program.h index 8b11b5689..11c7c9895 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-5/program.h +++ b/proto-cuda/packs-ca3-v4/v4-era-5/program.h @@ -13,9 +13,9 @@ #define IGNEUM_SEED_STRING "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000" #define IGNEUM_SEED_BYTES_HEX "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07" -#define IGNEUM_GENERATOR 3 +#define IGNEUM_GENERATOR 4 #define IGNEUM_PROGRAM_ATTEMPT 0 -#define IGNEUM_PROGRAM_ID 0x73bcbfe8ccf988f1ull +#define IGNEUM_PROGRAM_ID 0xc120d7963abdcd96ull #define IGNEUM_DAY_STRING "bytes:69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY_BYTES_HEX "69676e65756d2d6461792ffa50000000000000" #define IGNEUM_DAY0 0xceed56d7u @@ -28,9 +28,10 @@ #define IGNEUM_LOADS_PER_HASH 128 #define IGNEUM_WIDE_LOADS_PER_HASH 0 #define IGNEUM_OP_MIX "load=16 add=15 shfl=6 mad=4 or=4 rotl=4 rotr=4 xor=4 mulhi=3 mul=2 sub=2" -// Program class v3 (Counter ASIC 2.0, docs/plans/counter-asic-2-rollout.md): generator version 3; a worker that -// runs another class refuses this pack, and a job line names the class it wants (class=v3 era=). -#define IGNEUM_PROGRAM_CLASS "v3" +// Program class v4 (Counter ASIC 3.0, docs/plans/counter-asic-3-node.md): generator version 4, class v3 plus the +// latency-shadow block (IGNEUM_SHADOW_INSTRS x IGNEUM_SHADOW_REPS per iteration); a worker that runs another class +// refuses this pack, and a job line names the class it wants (class=v4 era=). +#define IGNEUM_PROGRAM_CLASS "v4" #define IGNEUM_ERA_SEED_HEX "7f450623297a954f493ca08abcdfe7142bb753900abcee38256266007b4b48b7" // Class v3 construction (Counter ASIC 2.0, 5 October 2026, docs/plans/mixer-x4.md): version 2 loads; the dataset item // derivation applies the mixer IGNEUM_MIXER_MULT times per round (memhard.h), and the cache follows the growth rule. diff --git a/proto-cuda/packs-ca3-v4/v4-era-5/program.json b/proto-cuda/packs-ca3-v4/v4-era-5/program.json index fa77a8abe..8dae1d59a 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-5/program.json +++ b/proto-cuda/packs-ca3-v4/v4-era-5/program.json @@ -1,8 +1,8 @@ { "format": "igneum-program-pack-3", - "generator": 3, + "generator": 4, "attempt": 0, - "program_id": "0x73bcbfe8ccf988f1", + "program_id": "0xc120d7963abdcd96", "program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32", "dataset_mode": "memory-hard", "seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000", @@ -15,7 +15,7 @@ "iterations": 8, "instruction_count": 64, "loads_per_hash": 128, - "program_class": "v3", + "program_class": "v4", "era_seed_bytes": "7f450623297a954f493ca08abcdfe7142bb753900abcee38256266007b4b48b7", "load_class": "mx8-eraf897c84e+sh256x27", "mixer_mult": 8, diff --git a/proto-cuda/packs-ca3-v4/v4-era-5/vectors.h b/proto-cuda/packs-ca3-v4/v4-era-5/vectors.h index 0563d5609..58dfa5e27 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-5/vectors.h +++ b/proto-cuda/packs-ca3-v4/v4-era-5/vectors.h @@ -1,5 +1,5 @@ // Generated by igneum-pow export (generator v2) for seed "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000". Do not edit by hand. -// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset +// Expected outputs: igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset #pragma once #ifdef __cplusplus #include diff --git a/proto-cuda/packs-ca3-v4/v4-era-5/vectors.json b/proto-cuda/packs-ca3-v4/v4-era-5/vectors.json index 05263f229..197245d50 100644 --- a/proto-cuda/packs-ca3-v4/v4-era-5/vectors.json +++ b/proto-cuda/packs-ca3-v4/v4-era-5/vectors.json @@ -5,7 +5,7 @@ "dataset_log2_words": 28, "mask": "0x0fffffff", "lanes": 32, - "source": "igneum-pow (Rust) CPU interpreter, generator v3, memory-hard dataset", + "source": "igneum-pow (Rust) CPU interpreter, generator v4, memory-hard dataset", "warps": [ {"base_nonce": 0, "expected": [ "0xbf945be0cc8d3f41", "0x34be8a9b058957ef", "0xa790f250cb3f84c2", "0xf348a3adcb120fee", "0x84ffe7a18320fce6", "0xc3ca0cd342a7b5a0", "0xc661be2913cc0a16", "0x42a2613074355476", diff --git a/proto-metal/main.swift b/proto-metal/main.swift index 07b1ddb38..eff385acd 100644 --- a/proto-metal/main.swift +++ b/proto-metal/main.swift @@ -3088,6 +3088,11 @@ func servePackProgram(_ gpu: GPU, _ store: ServeStore, seedHex: String, seed: [U guard generator == 2 || generator == 3 || generator == 4 else { throw refuse("program pack generator \(generator) is not a generator version this worker runs (2, 3 or 4)") } let packClass = packClassOf(generator: generator) if let named = defineStr("IGNEUM_PROGRAM_CLASS"), named != packClass { throw refuse("program pack IGNEUM_PROGRAM_CLASS \"\(named)\" does not match IGNEUM_GENERATOR \(generator)") } + // Counter ASIC 3.0 (6 October 2026): the shadow block marks class v4 (packfile.h's rule): a generator 3 pack with + // IGNEUM_SHADOW_INSTRS is a v4 program stamped v3 (the v3 control's program id) and a generator 4 pack without it is no v4 pack + let shadow = defineU32("IGNEUM_SHADOW_INSTRS") ?? 0 + if generator == 4 && shadow == 0 { throw refuse("program pack generator 4 (class v4) without IGNEUM_SHADOW_INSTRS: not a class v4 pack") } + if generator == 3 && shadow != 0 { throw refuse("program pack generator \(generator) with a shadow block (IGNEUM_SHADOW_INSTRS \(shadow)): a class v4 program is generator 4 (export the pack as class v4)") } let eraHex = defineStr("IGNEUM_ERA_SEED_HEX") ?? "" if wantClass != "" && wantClass != packClass { throw refuse("program class mismatch: this pack is class \(packClass), the line names class \(wantClass) (export the pack again)") } if wantEra != "" && isPackClass(packClass) && wantEra.lowercased() != eraHex.lowercased() { throw refuse("era seed mismatch: this pack was drawn under era \(eraHex.isEmpty ? "(none)" : String(eraHex.prefix(16))), the line names era \(wantEra.prefix(16)) (export the pack again)") }