igneum/igneum-pow
igneum-labs a09e81d51e igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters)
Standard-library Rust port of the Swift prototype for the rusty-kaspa fork. 23 tests
tie it to proto-cuda/packs: program.json instruction by instruction for three packs,
cache FNV 48c4f5bf24166b2e, dataset head/last/64 samples, 96/96 hash vectors per pack,
and kernel.cu, program.metal, kernel.cl, program.h, memhard.h, memhard.metal byte-identical.
CPU verify 0.41 to 0.58 ms per warp (Swift 0.63 to 1.21), cache fill 175 to 181 ms one core.
CLI: bench, export, hash. program.json is written as valid JSON (the Swift quotes the
cache line mask inside the "item" string; fix pending in main.swift).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:53:18 +00:00
..
src igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
tests igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
.gitignore igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
Cargo.lock igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
Cargo.toml igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
README.md igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00
rustfmt.toml igneum-pow: Rust crate bit-exact with proto-metal (seed, generator, memhard, verifier, emitters) 2026-10-03 16:53:18 +00:00

igneum-pow

The Igneum lottery hash in Rust, bit-exact with the Swift prototype in proto-metal/main.swift. This is the crate the rusty-kaspa fork will call (docs/fork-map.md, rows a1 to a3) so a node written in Rust can verify any block and hand miners the kernel source for the epoch. No dependency outside the standard library; serde_json is a dev-dependency for reading the packs in the tests.

Date: 3 October 2026. Toolchain: rustc 1.99.0 via rustup (the Homebrew 1.69 on PATH is too old; use ~/.cargo/bin/cargo).

Modules

Module What it is Swift namesake
seed 32-byte seed words from a string (FNV-1a 64, four salts, finalised); seed_words_from_bytes is the boundary where the chain will feed the VDF output; SplitMix64 seedWords, SplitMix64
generator the 64-instruction program for a seed (op, dst, src, src2, imm, imm2, rot, bit, mask); levers load_weight and wide_frac generateProgram, GeneratorConfig
memhard 256 MiB cache (2^16 chains of 64 ChaCha12 blocks), mixer parameters, 8-round item derivation with the 32 lanes interleaved, MemhardCpu::fetch cpuFillCache, MixParams, deriveItems, MemhardCPU
verify the 32-lane warp interpreter, DatasetMode::{ClosedForm, MemoryHard}, Epoch, hash_warp, verify_block cpuWarp, DatasetSource
emit Metal, CUDA and OpenCL source, program.h, memhard.h, vectors.h, program.json, vectors.json, export_pack generateMSL, memhardMSL, emitMemhardCore, generateCUDA, generateOpenCL, exportPack

The API the fork calls

use igneum_pow::{Epoch, DatasetMode};

// Once per epoch and day: generates the program and fills the 256 MiB cache (about 0.18 s on one core).
let epoch = Epoch::memory_hard("igneum-genesis", "2026-10-03");

let h: u64 = epoch.hash(nonce);                 // one nonce (computes its aligned 32-nonce warp)
let w: [u64; 32] = epoch.hash_warp(base_nonce); // one warp
let ok: bool = epoch.verify_block(nonce, target_u64);

// Miner programs for the epoch, byte-identical to the Swift exporter.
let pack = igneum_pow::emit::export_pack(&epoch, "2026-10-03", "igneum node");
pack.write_to(std::path::Path::new("out"))?;   // kernel.cu, kernel.cl, program.metal, memhard.h, ...

Epoch is Send + Sync; build one and share it. DatasetMode::ClosedForm reproduces the two old packs (igneum-genesis, igneum-hourly) and is not memory-hard. The hash is 64 bits; the fork maps it into its 256-bit target space in consensus/pow/src/lib.rs.

CLI

cargo build --release
./target/release/igneum-pow bench  --seed igneum-genesis [--warps 20] [--closed-form] [--day 2026-10-03]
./target/release/igneum-pow export --seed igneum-genesis --out <dir> [--closed-form]
./target/release/igneum-pow hash   --seed igneum-genesis --nonce 4103

Tests

cargo test (23 tests, 0.7 s after compile; the dev profile is optimised so the cache fill is quick):

Check Pack Result
program.json instruction by instruction, op mix, loads per hash igneum-genesis, igneum-genesis-mh, igneum-hourly 3 x 64 match
Mixer parameters (key, rot, mul, rc) igneum-genesis-mh match
Cache head, last line, FNV-1a 64 48c4f5bf24166b2e igneum-genesis-mh match
Dataset head (16), [MASK], 64 sampled words all three match
96 hash vectors (3 warps x 32 lanes) igneum-genesis-mh 96/96
96 hash vectors igneum-genesis, igneum-hourly 96/96 each
kernel.cu, program.metal, kernel.cl, program.h byte-identical all three identical
memhard.h, memhard.metal byte-identical igneum-genesis-mh identical
program.json byte-identical (after the fix below) all three identical
vectors.json, vectors.h byte-identical apart from the provenance string all three identical

An independent diff -r of igneum-pow export output against the checked-in packs shows the same two lines only: the provenance string and the "item" line.

One deliberate difference: proto-cuda/packs/igneum-genesis-mh/program.json as written by the Swift is not valid JSON (main.swift line 1291 uses jhex inside the "item" string, so the cache line mask is quoted inside a quoted string). The Rust emitter writes 0x003fffff bare; the test normalises that one line before comparing. A node must hand miners valid JSON, so the Rust side does not reproduce the defect.

Measured, 3 October 2026, Apple M5 Max, one core, release build

Step Rust Swift (MEMHARD.md)
Cache fill, 256 MiB, 65,536 chains x 64 ChaCha12 blocks 175 to 181 ms (5 quiet runs; 200 ms once with another build running) 184.5 to 190.6 ms (C++ host reference 161.5)
CPU verify per warp, igneum-genesis, 104 loads, 3,328 items, avg of 20 0.441 ms 0.649 ms
igneum-genesis/epoch1, 104 loads 0.411 ms 0.631 ms
igneum-genesis/epoch2, 112 loads 0.488 ms 0.701 ms
igneum-second-seed, 104 loads 0.482 ms 0.801 ms
igneum-second-seed/epoch1, 144 loads, 4,608 items 0.579 ms 1.205 ms
Cold single warps across the five seeds 0.41 to 0.87 ms 1.16 to 2.11 ms
Closed form, igneum-genesis 0.002 ms 0.017 ms

The Rust verifier is 1.4x to 2.1x faster than the Swift one per warp; the registers are kept register-major (r[reg][lane]) so the lane loops vectorise, and the item derivation interleaves the 32 lanes round by round as the Swift does. The 10 ms gate holds with a margin of about 17x on the steady figure and 11x on the worst cold warp.

Not done here

  • No GPU. The vectors tie this crate to the Metal and CUDA results through the packs; nothing here runs a kernel.
  • The epoch seed is still a string. seed::seed_words_from_bytes is where the VDF output will enter.
  • The 256-bit target mapping and the kaspa_pow::State shape belong to the fork, not to this crate.