docs/spec/01 to 06 and the README index, alongside the existing overview. Section 1 is the normative definition of the lottery hash with test vectors copied from the igneum-genesis-mh pack (cache fingerprint 48c4f5bf24166b2e, 96 hashes, mixer constants) and every prototype value marked with the measurement that fixes it at gate 1. Sections 2 to 5 are the design as decided on 3 October 2026, labelled Designed. Section 6 lists 60 open items with the experiment or decision that closes each and its gate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
12 KiB
Igneum protocol specification, section 4: epoch and era seeds through the class-group VDF
Spec version 0.1, 3 October 2026. Status of this section: Measured for the VDF primitive on one machine (proto-vdf/, docs/bench-log.md entry "proto-vdf, Wesolowski VDF"); Designed for the pipeline; Open where marked. The class-group code has not been reviewed by a second cryptographer (proto-vdf/README.md, open item 1).
4.1 Why a delay
The hourly program is generated from a seed, the seed comes from a checkpoint, and the checkpoint commits to the blocks before it. The miner who finds the last block before a checkpoint can compute the program that block implies, benchmark it on its own fleet, and withhold the block if the program is bad for it. The review priced this at roughly 130 to 1 for a 30% miner; the prototype's own model gives 6 to 15 to 1 on the burned block for 10% to 40% miners (proto-vdf/README.md, grinding table, Measured by Monte Carlo over 2,000,000 epochs against the analytic model, agreement 0.03 blocks). Either way the sign is positive: with no delay, grinding pays and favours the largest miner.
A miner has about 2 s to decide whether to publish a block under a 1 block/s DAG (approximate, from the block rate). The delay only has to exceed that by a margin no hardware advantage can close. With the delay, withholding has the same expected program as publishing and only burns the block: gain 0 in every row of the grinding table.
4.2 The primitive
Wesolowski VDF (Efficient Verifiable Delay Functions, EUROCRYPT 2019) in the class group of an imaginary quadratic field with a prime discriminant derived from the input. Chia's construction (vendor/chiavdf, commit 7e62ce14, 29 Sep 2026): no trusted setup, group order unknown to everyone, a fresh discriminant per input so nothing can be precomputed. NUDUPL and NUCOMP ported from chiavdf's qfb_nudupl and qfb_nucomp with the Lehmer partial xgcd; the textbook Cohen 5.4.7 composition and plain duplication are kept as oracles and agree on 15,000 random cases (Measured, proto-vdf/README.md).
input (32 bytes)
D = -HashPrime(tag_D || input), 1024 bits, |D| prime, D = 1 mod 8
x = (2, 1, (1 - D) / 8), the generator form of Cl(D)
y = x^(2^T) T sequential squarings
l = HashPrime(tag_l || x || y || T), 256 bits Fiat-Shamir challenge
pi = x^floor(2^T / l)
output = SHA-256(tag_out || input || T || y)
proof = (T, y, pi)
verify: rederive D and x, recompute l, check pi^l * x^(2^T mod l) == y, recompute output
Tags (Implemented in proto-vdf/src/seed.rs for the epoch path): tag_D = "igneum-epoch-discriminant", tag_l = "igneum-vdf-challenge", tag_out = "igneum-program-seed". The era path uses "igneum-era-discriminant" and "igneum-era-seed" (Designed, not yet in code). Prime |D| kills the 2-torsion, the low-order element Wesolowski must exclude. Whether to mirror chiavdf's byte layout for HashPrime exactly, and whether the proof should carry D (the verifier otherwise pays a 17 ms average prime search), are Open (O-4.5).
| Parameter | Value | Label |
|---|---|---|
| Group | Class group, 1024-bit prime discriminant from the input | Designed (production choice) |
| Fiat-Shamir prime | 256 bits | Designed (Chia uses 264; 2x the 128-bit level) |
| Proof | (T, y, pi), 516 bytes with the prototype serialisation (sign byte plus fixed-width a and b) | Measured. The serialisation should become chiavdf's compact encoding before any wire format is frozen (Open, O-4.5) |
| Proof plan | 12-bit digits, at most 65,536 checkpoints (17 MB) during evaluation | Implemented; proving costs 12 to 13% of evaluation single-threaded and parallelises over residue classes |
Measured on the Apple M5 Max, one core, rustc 1.69.0, GMP 6.3.0, 3 October 2026 (docs/bench-log.md, proto-vdf entry):
| Group | Squarings/s | T for 600 s | T for 3,600 s | Verify | Proof bytes |
|---|---|---|---|---|---|
| Class group, 1024-bit D | 163,000 | 98.0 million | 588 million | 4.5 ms (12.6 ms including deriving D) | 516 |
| Class group, 2048-bit D | 83,500 | 50.1 million | 301 million | 8.0 ms | 1,028 |
| RSA-2048 (trusted-setup stand-in, timing only, never for production) | 1,257,000 | 754 million | 4.53 billion | 1.4 ms | 512 |
Full-length run, class 1024: T = 97,126,043, evaluation 585.4 s at 165,900 sq/s, proof 9.1 s on 12 threads (56.8 s on one), verify 4.47 ms. Determinism: the same checkpoint hash gave the same seed and identical proof bytes in two processes at T = 1,000,000; a wrong checkpoint, a flipped seed bit and T + 1 are all rejected.
4.3 The epoch seed pipeline
Designed. Epoch e is the DAA-score interval [3,600 e, 3,600 (e + 1)) (section 1.12).
- Seed checkpoint.
C(e)is the highest-index checkpoint (section 3, C1) whose checkpoint block has DAA score at most3,600 e - 1,200: the latest checkpoint at least 20 minutes of DAA time before the epoch starts. The checkpoint block hash is Kaspa's full header hash, which covers the nonce, as the grinding defence requires (proto-vdf/README.md: a hash that covers only the body would let a miner start the VDF while still searching nonces). - Evaluation.
input = hash(C(e)),T = T_epoch, run 4.2.program_seed_eis the 32-byte output;proof_eis (T, y, pi). - Program.
S_e = seed_words_from_bytes(program_seed_e)(section 1.3.1), program =generate_from_words(S_e)(section 1.4). The 1,200-s lead is 2x the reference evaluation time, so a core half as fast as the reference still finishes before the epoch (4.6). - Header. Every header carries
seed_source = hash(C(e))for its own epoch (section 2.4). A header is valid under the lottery only if itsseed_sourceis a block on its own selected chain at the blue score of checkpoint indexi(C(e)), and its PoW verifies under the program derived from that block. The proof is not in the header: a node verifiesproof_eonce per epoch (4.5 ms) and cachesS_e.
Determinism of step 1 is the point of the rule: which block is "the checkpoint at blue score 30 i" is a function of the header's own past, so two nodes validating the same header derive the same program, and a header mined under a reorged-away checkpoint names a block that is not on its chain and is invalid. Whether C(e) must be certified (section 3) or merely be the selected-chain block at that blue score in the header's past is Open (O-4.3): requiring certification couples mining to finality liveness (a stall longer than the lead would stop the program from being derivable), which the design document accepts ("an epoch cannot start without a valid proof") and this specification argues against, because the chain is meant to keep running on plain GHOSTDAG through a finality pause (section 3.7 item 2). The proposal: the selected-chain block at that blue score, certified or not, deep enough (1,200 DAA s plus d) that a reorg across it is a merge-depth-scale event.
4.4 The era seed pipeline
Designed (design document: "The era draw applies a one-hour delay function to the hash of all blue blocks in the day ending at the last certified checkpoint one epoch before the boundary"). Era n is the DAA-score interval [15,552,000 n, 15,552,000 (n + 1)) (section 1.12).
C_era(n)is the highest-index checkpoint whose block has DAA score at most15,552,000 n - 7,200(2 hours of lead, 2x the 1-hour evaluation).input = Hash(chain_id || n_le64 || h_1 || h_2 || ... || h_m)whereh_1..h_mare the hashes of the blue blocks inC_era(n)'s past with DAA score in(daa(C_era(n)) - 86,400, daa(C_era(n))], in ascending (blue score, hash) order, andHashis the chain's BLAKE2b-based hash. This is a function ofC_era(n)'s past, so it is as deterministic as 4.3 step 1.- Run 4.2 with
T = T_era = 6 x T_epochand the era tags.E_nis the output. - The era draw of section 1.13.1 consumes
E_nas its only randomness (proto-vdf/README.mdopen item 6: check that nothing else enters the draw).
4.5 Who evaluates, who verifies
Every mining node evaluates both VDFs itself: one CPU core for 10 minutes each hour (17% of one core) and once for an hour each era, plus 17 MB of RAM if it also proves. The GPU is untouched. The proof exists for nodes that did not evaluate (light clients, syncing nodes, late starters): 516 bytes and 4.5 ms per epoch. Proofs gossip as their own message type and are also retrievable by seed_source from any peer.
There is no timelord role and no race: unlike Chia, the chain does not wait for the VDF; it uses a VDF output that was fixed 20 minutes (epoch) or 2 hours (era) earlier. "No node evaluates" means no miner is running a CPU, which means nobody is mining.
4.6 T from a reference core rate, fixed at genesis
Designed (proto-vdf/README.md, parameter recommendation). Before genesis, run vdf bench (or chiavdf's vdf_bench) on every devnet node type that will mine, take the fastest honest single-core NUDUPL rate observed as r_ref (squarings per second), and fix at genesis:
| Constant | Definition | On the M5 Max core (r_ref = 163,000) |
|---|---|---|
T_epoch |
600 x r_ref | 98.0 million |
T_era |
3,600 x r_ref | 588 million |
Choosing the fastest honest core, not the median, keeps the stated 10 minutes an upper bound for honest nodes and leaves the attacker margin intact. T MUST NOT be derived from on-chain timing, which is manipulable. T is a genesis constant; hardware will get faster over the years and the margin will erode slowly from 300x, which a fixed T covers for decades, and the upgrade path of section 5.7 exists if it is ever needed.
| Attacker evaluator speed vs reference | Epoch delay | Era delay | Beats the 2-s window |
|---|---|---|---|
| 1x | 600 s | 3,600 s | no, margin 300x |
| 2x | 300 s | 1,800 s | no, 150x |
| 10x | 60 s | 360 s | no, 30x |
| 100x | 6 s | 36 s | no, 3x |
| 300x | 2 s | 12 s | epoch yes, era no |
Chia's and the Ethereum Foundation's VDF hardware efforts targeted single to low double-digit speedups over CPUs (approximate, from memory, proto-vdf/README.md). chiavdf's AVX-512 IFMA assembly path is faster than the prototype's 163,000 sq/s and the x86 devnet nodes will set r_ref higher than this Mac (open item 2 there).
4.7 Fallback for a node without the seed at an epoch boundary
Open (O-4.4). A node that has not finished evaluating program_seed_e when epoch e starts cannot build the program, so it cannot mine the new program or validate new blocks' PoW until it has y. It can still receive and relay. Two options:
| Option | Rule | For | Against |
|---|---|---|---|
A (proposed by proto-vdf/README.md) |
The previous epoch's program stays valid for the first N blocks of epoch e, and each header names the program seed it mined under | A slow node keeps mining through the boundary | Two programs are valid at once for N blocks; a miner may pick the better of the two, which reintroduces a small choice the VDF was meant to remove; N is a new parameter |
| B (this specification's preference) | No consensus fallback. The 1,200-s lead is 2x the reference evaluation; a node slower than that takes (y, pi) from any peer and verifies in 4.5 ms; seed_source in every header tells it which proof to ask for |
No second valid program, no new parameter; the proof is 516 bytes | A node isolated from all peers and slower than 2x the reference loses up to the remainder of its own evaluation. Honest nodes evaluate at r_ref or take the proof from peers, so the case is a slow node that is also isolated |
Decision at gate 3 with the devnet, where the time to first block after an epoch boundary is measured on the slowest node type.
4.8 Open items from the prototype
Carried into section 6: external review of classgroup.rs against chiavdf (O-4.1); reference core choice (O-4.2); whether C(e) must be certified and the header field (O-4.3); the fallback (O-4.4); HashPrime layout, carrying D in the proof, compact form encoding (O-4.5); reduction only when a exceeds 8 limbs as chiavdf does, a further speedup to port (O-4.6); no fuzzing of deserialize on hostile bytes beyond validity checks, no measurement on NVIDIA or AMD hosts' CPUs (O-4.7).