Version 1.0 · Rendered from WHITEPAPER.md at commit 2882390fcb0c

Source SHA-256 f135b79cb472a85afc0259d3cf0536e6b8a705b07ada7daab03b4f900611e049

RFC-0012, the normative election specification, is published beside this paper. To save a PDF, print this page; the print layout keeps the version stamp.

Spek

A post-quantum, unbonded proof-of-stake ledger with secret, ungrindable 30-second leader election, and no energy race.

Technical white paper, November 2026. Describes the reference implementation (Rust, 20 workspace crates, MIT / Apache-2.0) and its leader election as specified in RFC-0012. Designed and directed by one developer; implemented, tested and reviewed almost entirely by Claude Code.

Two disclosures before anything else.

  1. SQIsign is not a NIST standard. It is a candidate in NIST's additional post-quantum signature process (advanced to Round 3 in May 2026, with evaluation expected to run about two years). "NIST security level 1" and "level 5" below name the security categories the parameter sets target, not approvals. NIST's finalised post-quantum signature standards (ML-DSA, SLH-DSA) and the selected FN-DSA are different schemes, and Spek uses none of them.
  2. The code has been audited only by AI models (Anthropic's Claude). No independent human security audit, and no review by a cryptographer or by the SQIsign authors, has taken place before launch. That covers the Rust implementation, the vendored SQIsign and RandomX C code, and the FFI boundary between them.

Abstract#

Spek is an unbonded proof-of-stake UTXO blockchain in which time, not work, schedules blocks. The clock is divided into fixed 30-second timeslots anchored at a genesis timestamp; block height equals timeslot number, so every block's timestamp is derived rather than declared. In each slot every eligible stake output has exactly one draw: the middle-out distance from the centre of the 256-bit hash space of a hash over the epoch's beacon, the height, the miner key and a per-height slot secret that only the key owner can compute and that was committed inside the stake output before the beacon existed. Nobody, the owner included, can rank keys for a future slot before the beacon is fixed, and nobody else can know a miner's score until its header is published. The highest score whose full block validates wins; if no candidate arrives, every node constructs the same unsigned null block so the chain never stalls. Eligibility is what the protocol prices: during a 45-day seed phase a RandomX ticket per 3-day round, recorded on chain before it can count, and afterwards one output at the miner's stake address worth at least 80% of the block reward, created at least a day before it counts.

Block headers and mining keys use SQIsign Level I (isogeny-based, targeting NIST security level 1); long-lived custody outputs can opt into SQIsign Level V, and the genesis allocation and its guardians use it. SQIsign is a Round 3 candidate, not a NIST standard. Hashing is BLAKE3 throughout. Public keys stay hidden behind a hash until an output is spent, and Taproot-style script commitments are rebuilt on hash commitments rather than curve tweaks. Consensus time comes from an authenticated Roughtime quorum projected forward on the hardware-rate monotonic clock, so neither the host's wall clock nor its NTP daemon can steer a node's slot. Forks within 4 blocks of the tip resolve by cumulative score once each branch holds two blocks above the fork point; transactions settle by confirmations sized to an assumed attacker share, and a weak-subjectivity checkpoint grid every 4,000 blocks is the hard barrier. Supply is capped at 450,000,000 coins: a 30,000,000-coin genesis allocation (founders 5%, vesting over five years; a stewardship fund 1.67%, vesting over twenty) plus a 50-coin reward halving every 4,200,000 blocks.


Contents#

  1. Introduction
  2. Design goals
  3. Timeslots and the verified clock
  4. Leader election
  5. Slot settlement and the null block
  6. Chain selection and settlement
  7. Eligibility: ticket records and stake outputs
  8. Cryptography
  9. Transactions and scripts
  10. Monetary policy
  11. Network protocol
  12. Synchronisation and checkpoints
  13. Node architecture and storage
  14. Governance and upgrades
  15. Threat model
  16. Comparison
  17. Known limitations and open items

1. Introduction#

Proof-of-work buys Sybil resistance with energy and rewards the party that burns the most. Bonded proof-of-stake buys it with locked capital and inherits a thicket of slashing, validator sets, and finality gadgets. Spek is unbonded proof of stake, mechanically simpler than either: a per-slot election over stake outputs that each hold a coin-eligibility floor, with nothing locked and nothing slashed.

Three ideas carry the design:

  1. Time is the schedule. A block exists for every 30-second slot since genesis, whether or not anyone produced one. Height, timestamp, reward, fee floor, coin requirement, and vesting are all pure functions of that slot index.
  2. One stake output, one secret draw. A miner's score for slot h depends only on values fixed before the draw's beacon existed: its key, its committed slot secret for h, and the height. There is no nonce to grind, no key to swap in after the fact, and nothing a producer can re-sign or re-order to improve its own or any descendant's chances. Until a miner publishes its header, nobody else can compute its score.
  3. Eligibility is the security parameter. Since any selection rule over independent uniform draws awards a party controlling N of N+H draws exactly N/(N+H) of slots, the only lever is what a draw costs to field. Spek prices that explicitly, and differently in two phases (§7).

The result is a network whose honest operating cost is a node and a held balance, not a power bill. The remainder of this paper describes the mechanism as built, including the parts that are deliberately plain and the parts that are still open.

Positioning note. Spek is unbonded proof of stake. Stake is a threshold met by one output, never a bond: nothing is locked, burned, or slashed, and there is no validator set and no delegation. The first 45 days price keys with RandomX tickets instead (§7.2), so the chain is not proof-of-work even then: work buys eligibility for a round, not a block. Spek has no staking product (no yield, no locking, no pools), so it should never be described with staking-product language such as "staking rewards" or "stake your coins"; the block winner earns the block reward.

2. Design goals#

3. Timeslots and the verified clock#

3.1 Slots#

Let G be the genesis timestamp. The slot currently being mined, and therefore the height of the block that does not yet exist, is

time_derived_timeslot = (now − G) / 30
settled_tip           = time_derived_timeslot − 1
derived_timestamp(h)  = G + 30·h

A slot is unsettled while it is being mined and settled once it closes. The header carries no timestamp field at all: a block at height h can only ever have timestamp G + 30h, which removes timestamp grinding, median-time-past, and the whole tolerance-window class of validation by construction. Block height is a u32 (about 4,000 years of 30-second slots); derived timestamps are 64-bit.

Slots are grouped into epochs of L = 1,440 slots (12 h), which carry the election beacon (§4.2), and segments of S = 8,640 slots (3 days), which carry each key's slot-secret hash chains (§4.1).

3.2 Two phases per slot#

Each slot is split into a headers-only phase (0–6 s) in which 743-byte candidate headers flood the mesh and the ranking settles, and a block phase (6–30 s) in which nodes pull full bodies only for the top three candidates (rank 1 from three peers, ranks 2–3 from one each) and serve the top five. Fetching bodies only after the ranking is known bounds bandwidth and removes the "premature block flood" denial-of-service vector. The 24-second body window is sized for megabyte-scale blocks crossing intercontinental links, with room for two pull-retry rounds.

0 s                6 s                                                   30 s
|--- headers only --|--- pull top-3 bodies · validate rank-1 · serve top-5 ---|
slot h opens                                        boundary: winner of h committed, or null

Header push is paced at 6 per second per peer in fixed one-second windows; current-slot block serving allows 5 requests per 3 seconds per peer, one per retained candidate.

3.3 Where time comes from#

Because a wrong clock puts a node in the wrong slot, Spek does not trust the operating system's clock for consensus. Each node maintains an in-process verified clock:

Consequence. Cross-node clock agreement is bounded by the residual after rate correction over one sync interval plus Roughtime path asymmetry, not by a "sub-second" promise. The 2-second outlier bound, the 5-second step bound, and the 30-second slot are sized around that.

4. Leader election#

The election needs a per-slot value that is (a) secret until used, (b) unique per height so it cannot be ground, and (c) committed before the randomness it is drawn against exists. A unique-signature VRF would give (a) and (b), but no deployable post-quantum VRF exists, and a randomised signature such as SQIsign is not unique. Spek gets all three from BLAKE3 alone, with a committed hash chain.

4.1 Slot secrets and horizons#

Each miner key file holds a SQIsign Level I key pair and a 32-byte slot seed drawn from the operating system's random source when the key is generated (385 bytes in all). The slot seed is independent of the signing key, so recovering a SQIsign secret key reveals nothing about future slot secrets.

σ       = BLAKE3-derive-key("spek 2026-10-20 slot-secret v1", slot_seed)
s_g     = BLAKE3("spek/slot-chain/v1" ‖ σ ‖ g)                 // one chain per 3-day segment g
T_g     = step^S(s_g)                                          // segment top, step = BLAKE3("spek/slot-step/v1" ‖ x)
r_h     = step^(S − 1 − (h mod S))(s_g(h))                     // slot reveal for height h
leaf_j  = BLAKE3("spek/slot-leaf/v1" ‖ pk ‖ T_(J0 + j))         // j = 0 … 1023, key-bound
C       = Merkle root over the 1,024 leaves                    // one horizon

Each segment's chain is revealed backwards, one value per slot, so publishing r_h exposes only values for heights already passed. A horizon is 1,024 consecutive segments starting at segment J0: about 8.4 years on mainnet. Its root C, bound to the key in every leaf, is committed in the stake output (§7.1) before any beacon it will be drawn against exists, so for every key, commitment and height exactly one r_h verifies.

A header carries the reveal, its 10-hash Merkle path and J0. A verifier walks the reveal up to its segment top (at most S hashes), hashes the key-bound leaf, climbs the path, and uses the derived root to rebuild the stake address; if the reveal is wrong, there is simply no stake at that address. The root is never carried. A mining node keeps the 1,024 segment tops (32 KB) and checkpoints in the current segment, so producing r_h takes fewer than 96 hashes; building a horizon takes 1–3 s.

A node creates its next horizon automatically about a year before the current one ends (--horizon-renewal-lead-segments, node policy, default 122 segments), with two segments of overlap so eligibility never lapses.

4.2 The epoch beacon#

B_e = BLAKE3("spek/beacon/v1" ‖ e ‖ genesis.merkle_root)                 e ∈ {0, 1}
B_e = BLAKE3("spek/beacon/v1" ‖ e ‖ election_seed@beacon_height(e))      e ≥ 2
beacon_height(e) = (e − 1)·L − 1

The beacon for epoch e is read from the election seed at the last block of epoch e−2, a full epoch before e starts. Every block of that source epoch mixes its winner's secret r_h into the seed (§4.4), so the beacon is unpredictable until the source epoch is produced. It is the same on every fork that shares that history, which covers every propagation fork (at most 5 deep against L = 1,440). The two launch epochs read the genesis merkle root, which commits to the launch ticket records and a launch nonce derived from a Bitcoin block mined after the record list was sealed (§7.2), so nobody, the organiser included, can choose it after learning the launch beacons.

The miner at a beacon height can withhold its block and let the runner-up set the beacon instead, and because it holds its own future reveals it can evaluate both choices. Simulation puts the gain at 1.9–3.0% more of its own wins per beacon it controls, 0.3–0.6% averaged over all epochs, with no compounding; it was measured and accepted.

4.3 The score#

score = middle_out( BLAKE3("spek/score/v2" ‖ B_e ‖ h ‖ pk ‖ r_h) )
x = hash as a 256-bit integer,  C = 2^255
middle_out(x) = x ≥ C ? (x − C) + 1 : C − x          // range [1, 2^255], arbitrary-precision integers

Both 0x00…00 and 0xFF…FF score the maximum; 0x7F…FF and 0x80…00 score 1. The genesis block scores the fixed 2^255; a null block scores 0.

Every input is fixed before the beacon exists: the key and its commitment sit in a stake output that had to be created below a cutoff one full epoch before the beacon height (§7.1), and r_h is the unique reveal of that commitment. The key is inside the preimage, so a copied commitment or a replayed reveal gives the copier an independent draw, never the victim's score. A genuine tie between two distinct keys has probability about 2^−255; the tie-break (highest score → lowest pubkey → lowest merkle root) is a determinism guarantee, not a grinding surface.

0x00…00                         C = 2^255                          0xFF…FF
|==================================|==================================|
score 2^255 (max)              score 1 (min)               score 2^255 (max)
            higher score = further from centre = more likely to win

At receipt a node first computes the header's claimed score (one hash) and drops it before any expensive check if it could not enter the slot's top five; a header is inserted into the ranking only after its signature, reveal and eligibility pass, so an unverified claim can never displace a verified entry. With top-5 relay a node verifies about 5·(1 + ln(N/5)) headers per slot: about 31 at a thousand miners, 66 at a million.

4.4 The election seed chain#

The header carries two hash chains with distinct jobs. prev_block is the identity chain: the BLAKE3 hash of the parent's signed fields. The signature is left out, because SQIsign signatures are not unique: anyone holding one can derive another valid one on the same bytes, so an identity that covered it could be split by any relay. The identity stays producer-malleable through the free merkle root, which is fine for an identifier. election_seed is the beacon chain:

election_seed(h) = BLAKE3("spek/election-seed/v2" ‖ election_seed(h−1) ‖ miner_pubkey ‖ r_h)
election_seed(0) = 0x00…00

The seed binds only the parent's seed, the winner's identity and its committed reveal. No signature bytes, merkle root, or header hash enter it, so re-signing or re-ordering a block cannot move any later beacon. This closed a grinding channel present in an earlier design that seeded from the parent's full hash. A later rule that scored directly from this chain (seed ‖ pubkey) was also replaced, because the winner of one slot knew the next seed and could fund, in its own block, whichever pre-generated key drew best next; the beacon, the stake cutoff and the slot secrets close that.

4.5 Mining a block#

At each slot boundary a mining node, in one chain-state read scope so that the parent, its seed, the beacon, and the stake verdict all come from a single consistent state:

  1. checks the sync condition chain_height + 1 == current_slot (a node behind the clock does not sign a block it knows is at the wrong height; this is not suppression during download, which the design forbids — see §12.2);
  2. picks its eligible horizon (in the seed phase, the one whose stake program holds the round's ticket record);
  3. computes r_h and the Merkle path from its slot-secret store, then the score and the next election seed;
  4. applies its own eligibility rule through the same function block validation uses, and forfeits the slot rather than produce a block every peer would reject;
  5. builds a template from the mempool and self-checks it (structure, locktime, genesis spend rules, size and count caps, merkle root), because the winner-commit path applies the node's own block without re-validation;
  6. signs the 543-byte header prefix with SQIsign;
  7. persists the signed attempt to disk so a crash-restart within the slot re-announces the same attempt instead of a fresh signature (which would be self-equivocation);
  8. floods the header.

4.6 Equivocation#

Only one entry per miner key per parent per slot is kept. SQIsign signatures are randomised, and anyone holding one can derive other valid signatures over the same content, so the block hash leaves the signature out and a second header with identical signed content is the same block: it is merged. A second header with different signed content over the same attempt is equivocation: the miner's entry is evicted, the attempt is negated slot-wide under its attempt-identity hash BLAKE3(prev_block ‖ miner_pubkey), and a compact proof is gossiped. Any "pick one variant" rule would be either unbounded (a miner floods variants) or arrival-order dependent (a partition); forfeiting the slot is bounded and order-independent.

5. Slot settlement and the null block#

At the boundary, nodes cascade through retained candidates in rank order (up to the top five) and commit the first whose full body is in hand and passes authoritative validation. Holding five while pulling three lets rank 3 promote after up to two same-slot disqualifications, and leaves two backup bodies for the case where a top-3 body is never served (for example a winner whose machine died after announcing). The node waits a bounded 2.5 s for the rank-1 verdict if it is in flight.

If a slot closes with no committable candidate, every node constructs the canonical null block for (height, prev_block): version 1, all-zero miner key, signature and slot fields, zero merkle root, no transactions and no coinbase, with an election seed derived by the normal rule using a fixed null identity and an all-zero reveal so the beacon chain continues unbroken. It is constructed, not mined, so no relay is needed and no bytes cross the wire. Its score is defined as 0, strictly below the minimum real score of 1, so any real block for that height outranks it and fork choice heals a null the moment a late winner surfaces, a depth-1 reorg with no ban and no negation. Nulls mint nothing and are stored and served like ordinary blocks.

Two consequences are worth stating. First, a chain whose height and hashes agree across nodes can still have an unhealthy mesh underneath, because null slots are silent and deterministic; health must be read from per-node telemetry. Second, silence is not evidence about a peer: rules that infer misbehaviour from an absence of data must first establish that data existed, and the implementation's inactivity reaper and isolation accounting are gated accordingly.

Residual. Per-boundary settlement fills exactly one missed slot. If every node simultaneously misses two or more boundaries (a coordinated restart, a network-wide freeze) no node is exactly one behind and the chain wedges. Recovery is an operator-invoked, locally-served RPC that fills deterministic nulls for settled slots, capped per call at the propagation fork window and refused whenever any peer proves a better chain exists. It cannot be automatic: a single node cannot distinguish "the whole network was down" from "I was down".

6. Chain selection and settlement#

6.1 Cumulative score#

chainwork(b) = chainwork(parent(b)) + score(b)       // score under the beacon of b's epoch on that chain

Chainwork is an arbitrary-precision sum that is never truncated or reset; truncation would enable long-range attacks. Each block is scored against the beacon of its epoch on the chain being scored, resolved from that chain's own headers; a header whose beacon cannot yet be resolved is quarantined, never scored with a guess.

6.2 Fork resolution ladder#

  1. Propagation forks (the hot path). When a competing branch forks within the propagation fork window (PROPAGATION_FORK_WINDOW = 4 blocks below the tip), both branches are compared by cumulative score once each holds at least two blocks above the fork point; the heavier wins and the loser is dropped. Waiting for both sides removes the tip thrash that per-block score variance would otherwise cause. The reorg is validated against a copy-on-write UTXO overlay before any live state changes, so a fork block that fails validation leaves the chain untouched. Rollback is bounded at 5 blocks.
  2. Divergence-triggered download. If no common ancestor lies inside the window while the peer's chain keeps pace with the clock (the equal-height lockstep that every partition heal produces, since both sides mine every slot), the node escalates to a full download, locates the true branch point, compares cumulative work, and reorgs at any depth above its restoration pin using per-block undo data or, failing that, an exact UTXO rebuild.
  3. Checkpoint barrier (weak subjectivity). A fork whose branch point lies behind the node's restoration pin or a hard checkpoint is never auto-resolved; the offering peer is banned. Checkpoints sit on a 4,000-block grid (~33 h), and the restoration pin is the newest boundary buried at least one full interval below the tip, so it trails the tip by 33–67 h. A partition must outlast a boundary by more than an interval before the two sides hold different settled checkpoints; a partition that merely straddles a boundary heals by the ordinary fork walk or weight comparison. Only that state needs operator recovery.

Coinbase outputs mature after 3,000 blocks (~25 h).

6.3 Settlement#

Spek has three settlement layers, and states each for what it is:

There is no finality gadget and no rollback cap shorter than the pin. A cap was designed and dropped: as drafted, both sides of a long partition finalized and refused each other forever, and an eclipsed node finalized the eclipser's chain.

7. Eligibility: ticket records and stake outputs#

Because the election geometry cannot be made Sybil-resistant, the cost of fielding a draw is where all of Spek's security lives. That cost has two regimes, and in both the thing that confers eligibility must exist on chain before the beacon it competes against.

7.1 Post-seed: one stake output#

min_coin_requirement(h) = max(0.8 × block_reward(h), 0.1 coin)     for h ≥ 129,600
stake_address           = hidden-key address of (pk, BLAKE3("spek/slot-commit/v1" ‖ C ‖ J0))
stake_cutoff(h)         = beacon_height(epoch(h)) − L

A header at height h is eligible only if its horizon covers h and its stake address, rebuilt from the header's key and the root its reveal derives, holds one unspent output that:

Eligibility is judged against the parent block's ledger, so spending the stake output ends eligibility from the next block, and on a fork each branch's own ledger decides. One output per draw keeps the check to a bounded walk of a value-ordered index: every output it steps over holds at least a full requirement, so stuffing a stake address with dust cannot slow anyone's check. Each stake output is one draw per slot, so a key with two funded horizons fields two draws, economically the same as two keys.

This is Spek's unbonded proof of stake. Post-seed block production is capital-proportional: a holder of X coins can fund ⌊X/requirement⌋ stake outputs and wins slots in that proportion. The requirement level (80% rather than some other ratio) sets the entry quantum and identity granularity, not the attack cost: matching the honest network costs roughly the aggregate capital it holds, whatever the per-draw price. The requirement halves with the reward, and the 0.1-coin floor only binds about nine halvings (~36 years) out.

The stake key pk is public in every header the miner publishes and lives on the mining machine, so the node keeps exposure to one stake unit. Node policy, not consensus: the coinbase pays the stake address of the first horizon not yet funded, then pays a separate hidden-key payout address (--payout-address). A winner therefore renews its next horizon for free; a key that never wins renews with one ordinary transaction, which the node makes itself from any surplus at the current stake address about a year before the horizon ends (or, with no surplus, the operator funds from a wallet). The node also merges a stake address funded in pieces into a single output.

This also breaks the classic proof-of-work death spiral. Honest operating cost is ~zero, so a falling price gives no miner a reason to unplug and the honest draw count does not collapse with price. Price exposure sits on the attacker's acquisition side: buying a large share drives the price up as it buys, and the stake it holds loses value when the attack is seen.

7.2 Seed phase: RandomX ticket records#

At launch nobody holds coins, so a coin floor would be zero and a draw would cost one SQIsign keygen (sub-second, parallel, pre-computable). The first 45 days (129,600 blocks) therefore use a different price. The seed phase is divided into 15 rounds of W = 8,640 blocks (3 days). A ticket is a nonce such that

RandomX_K( "SPEK-SEED-TICKET-V2" ‖ round ‖ round_seed ‖ A ‖ nonce ) < D,   D = 2^228
A            = the stake program (the 32-byte hidden-key program of the miner's stake address)
K            = genesis hash (fixed for the whole seed phase)
round_seed_0 = genesis hash
round_seed_1 = hash of the block at height W/2
round_seed_r = hash of the block at height (r−1)·W          for r ≥ 2

A ticket counts only once it is recorded on chain: a 48-byte record ("SKTR" ‖ round ‖ A ‖ nonce) carried as a zero-value OP_RETURN output in a seed-phase coinbase, at most 16 per block, one per (A, round). Records relay on their own gossip topic and wait in a bounded pool; every block producer includes pending ones. A record counts for an epoch only if it landed below that epoch's stake cutoff, so to cover a whole round it must land about two epochs before the round starts (a 48-hour search window per round). Because the ticket is committed before the beacon it competes against exists, a miner cannot rank free keys by their scores in an already-known epoch and buy tickets only for the best ones.

The RandomX instance is a custom-parameterised Spek variant (unique Argon2 salt plus documented-safe instruction-frequency changes), so rented marketplace hash-power cannot be pointed at it. Verification runs in light mode (15–30 ms, 256 MiB cache); searching uses the ~2 GiB dataset. D was calibrated so that a 2018-era 8-core desktop's spare cycles yield about three tickets per round; the residual blank-round probability is absorbed by the null block.

The round seed is resolved by walking the candidate chain's own ancestry, never by reading the observer's main chain at a height, so ticket validity is a pure function of the block and its chain and re-verifies identically during download. Round 1 is seeded from mid-round-0 rather than from genesis so that a single pre-launch grinding budget buys at most one round of tickets, not two.

Open launch. Epochs 0–2 (the first 36 hours) count only records written into the genesis coinbase, and anyone can win one. The search opens at a pre-announced Bitcoin block: its hash, with the network name, gives the launch key K_L, so no ticket can exist before it. Anyone then searches for a round-0 ticket under K_L (the same target D, with K_L as RandomX key and round seed) and submits the record to a public submission channel, which checks each ticket on arrival and lists every valid entry with its ticket hash so anyone can recheck the listing. After the deadline the organiser seals the list: it publishes the list with the genesis timestamp, the vout-0 message and the allocation, and a digest over all of them that independent witnesses record before a second pre-announced Bitcoin block is mined. The genesis takes up to 1,973 records, one per key, chosen by lowest ticket hash, so when more are submitted than fit, searching longer buys better odds. The launch nonce is derived from the launch key, the seal digest and that second block's hash, and the genesis builder is deterministic, so the launch beacons depend on a value nobody knew while any input could still change, and anyone can recompute the whole selection and genesis from public inputs. One record is one key, and a node mines one key, so a seat costs what every later round costs: one ticket.

The effect is that seed-phase draws are priced by sustained per-round compute rather than one-time keygen: a key bank is worthless without fresh work per key per round, and a flood decays within two rounds of its operator ceasing to pay for it. Ticket holders must fund a stake output below the cutoff of the first post-seed epoch; the node warns seven days ahead.

7.3 What the schedule does and does not do#

Both regimes award blocks in proportion to the draws held, and post-seed draws are bought with coins that (absent trading) only block rewards mint, so the coin-share distribution at the end of the seed phase is self-preserving under the post-seed lottery. Share changes afterwards come from coins changing hands, not from the protocol. One-node-one-key is client policy, not consensus: nothing ties a miner key to a machine, and the design does not rely on hardware scaling for its economics.

8. Cryptography#

8.1 Signatures: SQIsign Level I and Level V#

Every signature in the system is SQIsign (isogeny-based), produced by a vendored reference implementation behind an FFI boundary. There is no ECDSA, no Schnorr, and no elliptic-curve library linked into the signature crate; that invariant is asserted by test on the dependency graph.

Level Target Public key Signature Secret key Verify (ADX / portable) Used for
I NIST level 1 83 B 200 B 270 B 2.68 / 5.03 ms Headers, mining keys, stake outputs, everyday outputs (the default)
V NIST level 5 169 B 406 B 549 B 16.4 / 26.7 ms Opt-in custody outputs; every genesis allocation, council and guardian key

Signing a Level I header takes 25–40 ms (once per slot for a miner; the signer verifies its own signature before releasing it), with 6 ms used as the planning worst case for a verification everywhere a latency budget depends on it. Level V signing runs on a dedicated thread with its own stack.

Why headers stay at Level I. A forger who broke Level I still could not win a live slot as someone else, because it would also need that key's unrevealed r_h, which comes from an independent random seed and is protected only by BLAKE3. It could copy a just-revealed r_h into a second header and force an equivocation negation (a liveness attack, not a theft), and it could sign branches for past heights down to the restoration pin, which would hold at any level that broke. Stake outputs are capped at one stake unit per key by the payout rule (§7.1). Mining keys rotate with every horizon, so moving headers to a new level later is a hard fork that phases in as horizons expire, with no coin moves.

Standardisation and review status. SQIsign is not a NIST standard. It is one of nine candidates NIST advanced to Round 3 of its additional digital-signature process in May 2026. That round is expected to last about two years, a draft standard could not appear before about 2028, and SQIsign may be dropped. "Level I" and "Level V" refer to the security categories the parameters target (comparable to AES-128 and AES-256 key search), not to any NIST approval. Spek chose SQIsign over the standardised ML-DSA for its size: a 200-byte signature and a 83-byte key against roughly 2.4 KB and 1.3 KB. The trade-off is that SQIsign's security rests on a younger assumption (the supersingular endomorphism-ring problem) with less cryptanalytic history than lattices, and on a reference implementation that has not been built for production. Spek's copy of that implementation and its Rust FFI boundary have been audited only by AI models (Anthropic's Claude). No cryptographer, SQIsign author, or independent human auditor has reviewed them before launch.

A public key has exactly one valid encoding: every field half must be canonical (below the field prime), and the starting curve E₀, whose endomorphism ring is public, is never an acceptable key. A non-canonical encoding is a decode error, never a silently substituted value. A positive-only verification cache (262,144 entries) makes re-presented valid triples a hash lookup; it never caches failures and never changes a verdict.

8.2 Hashing: BLAKE3#

BLAKE3 is used for block hashes, election seeds, beacons, scores, slot secrets and their Merkle trees, transaction merkle trees, script and hidden-key commitments, the OP_BLAKE3 opcode, addresses, and the UTXO script index. Every consensus hash is domain-separated by a tag string, and transaction merkle trees tag leaves (0x00) and interior nodes (0x01) so no byte string can be valid as both; odd levels duplicate the last node, with the resulting duplicate-txid ambiguity closed by an explicit in-block duplicate-txid rule.

8.3 Block header#

Field Bytes Role
version 4 Integer selector for header/signature scheme; only 1 valid until an upgrade activates 2
prev_block 32 Identity chain: BLAKE3 of the parent's 743-byte header
merkle_root 32 Domain-separated BLAKE3 merkle root of transactions
election_seed 32 Beacon chain (§4.4)
block_height 4 Equals timeslot; timestamp is derived
miner_pubkey 83 SQIsign Level I key; input to score, seed, stake address and attempt identity
horizon_start 4 J0, the first segment of the horizon the reveal belongs to
slot_reveal 32 r_h (§4.1)
slot_path 320 The 10-hash Merkle path from the reveal's leaf to the horizon root
miner_signature 200 SQIsign signature over the first 543 bytes

The signature covers the whole field set, not just the score inputs: signing only the score inputs would let an attacker substitute a different transaction set under a winning header. The encoding is a hand-written fixed layout (743 bytes, length pinned, trailing bytes rejected) so canonical hashing does not depend on a serialisation library. Headers grow by about 781 MB a year, independent of the number of miners. The horizon root is derived, never carried; the seed-phase ticket lives in a coinbase record, not the header, and there is no reserved header field.

8.4 Hidden keys and script commitments instead of Taproot#

Isogeny keys cannot be tweaked on a curve, so Spek's Taproot analogue, ScriptCommit, commits to the script tree with a hash:

commitment = BLAKE3(T ‖ T ‖ pubkey ‖ script_merkle_root),  T = BLAKE3("SpekScriptCommit")
key-path-only outputs use commitment = 0x00…00

The default output hides even the key. A hashed output is 34 bytes, a witness version and a 32-byte program, the same shape as a Bitcoin P2WSH or P2TR output:

v1 (Level I):  OP_1 <32 B>   program = TH("SpekHashedCommit",   pubkey83  ‖ commitment)
v2 (Level V):  OP_2 <32 B>   program = TH("SpekHashedCommitL5", pubkey169 ‖ commitment)

A key-path spend reveals the key and commitment next to one signature; a script-path spend reveals the leaf, its merkle proof and a control block, and the validator recomputes the commitment and the program before running the leaf in the script VM (§9.3). Leaves under a v2 output verify Level V signatures. Multisig, timelocks, hash locks and atomic swaps are expressible; key aggregation is not. The plain ScriptCommit output (OP_1 <83-byte pubkey> <32-byte commitment>, 118 bytes) remains valid for outputs that want the key visible.

Addresses are Bech32m with human-readable part spek: witness version 1 carries a 32-byte hashed program or the 115-byte plain program, and version 2 a 32-byte Level V program. Decoding re-encodes and requires a byte-exact match, so each output script has exactly one lowercase address string. Wallets use the hashed form for every receive, change and coinbase address, so a public key is exposed only when its output is spent, except a stake key, which every header it signs makes public.

8.5 Crypto-agility#

There is deliberately no per-transaction algorithm menu and no runtime negotiation: at any height exactly one scheme is valid for a given output form or header version, which closes downgrade and algorithm-confusion attacks. The witness version selects the output scheme (1 = Level I, 2 = Level V; versions 3–16 are reserved), and the block version selects the header scheme, activated through the height-indexed upgrade schedule. Because the signed message commits to every spent output's locking script, a signature for a scheme-X output can never be reinterpreted under scheme Y. A hash-committed output is exactly the shape other chains are retrofitting for post-quantum migration; Spek ships with it, and with a second, larger parameter set already live for custody.

9. Transactions and scripts#

9.1 Model#

Spek is a UTXO ledger. Values are unsigned 64-bit integer bits (10⁸ bits per coin); there is no floating point anywhere in the protocol or its RPC. Exactly four output forms are admissible at creation: hashed Level I (34 bytes), hashed Level V (34 bytes), plain ScriptCommit (118 bytes), and zero-value OP_RETURN data carriers, which never enter the UTXO set. There is no pay-to-pubkey form. Everything else is rejected at both block and mempool validation, because an unspendable output is a permanent fund burn.

The transaction id is the BLAKE3 hash of every field except the witnesses, so it is fixed before signing and no relay can change it, and the block merkle tree commits to a second hash over the full wire encoding, witnesses included. The signature message (a BIP143-style preimage) commits to the chain (its genesis block hash), inputs, outputs, every spent output's value and locking script, and the version, but not to the witness. The chain binding matters for offline signers: the same committed keys produce byte-identical scripts on every chain that commits them, so without it a signature made on a test or rehearsal chain for a plan naming a mainnet output would be valid on mainnet. This pairing means a spend's txid is stable only while its satisfying witness is unique, so the validator enforces the full canonicality set: canonical witness wire, minimal numbers, clean stack, minimal conditionals, and a single signature rule under which a non-empty signature that fails verification aborts the script rather than evaluating to false. Only SIGHASH_ALL semantics exist.

9.2 Time locks#

All locks are block-height locks; there is no timestamp variant because height is time. Absolute nLockTime, relative nSequence locks (BIP68 semantics, version ≥ 2), OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY are enforced with one spending-height convention shared by block validation and mempool admission ("the height the transaction would be mined at"), and a parity test asserts the mempool is never more permissive than consensus.

9.3 Script VM#

A minimal stack machine for ScriptCommit leaves, dispatching on raw bytes: 82 executable opcodes frozen per leaf version (0xc0), with OP_BLAKE3 on Bitcoin's SHA-256 byte, OP_SHA256 at 0xbb so cross-chain atomic swaps can share one hash lock with Bitcoin-family chains, and OP_CHECKSIG/CHECKSIGVERIFY/CHECKSIGADD verifying SQIsign at the level of the output's witness version; the legacy CHECKMULTISIG opcodes are disabled. Limits: 10,000-byte scripts, 1,000-item stacks, 520-byte elements, 100-deep conditionals, 128-deep merkle proofs. Because verification is the dominant cost and an invalid signature is uncacheable, each input carries a BIP342-style signature budget (213 bytes per Level I verify, 421 per Level V verify, debited before the verify) so an attacker-authored leaf cannot amplify SQIsign work beyond roughly one verification per genuine signature's worth of witness bytes. Non-signature VM cost was measured at under 2 ms per input at the limits and needs no opcode counter.

9.4 Virtual size, fees and the mempool#

A Level V verification costs up to 6.119 times a Level I verification (the larger of the two backends' measured ratios), so each Level V input's witness bytes count ρ = 151/50 = 3.02 times in a transaction's virtual size. Blocks are limited by header + Σ vsize ≤ 2 MiB, and every fee rate and template budget is measured in vsize, so no block can take longer to verify than a full Level I block. For a transaction with no Level V input, vsize equals its wire size.

A relay fee floor decays geometrically per halving era (250,000 bits at launch), flat for transactions up to 3,000 vbytes and linear above, so permanent UTXO residency is priced while ordinary payments are not. The mempool is bounded (200 MB, 100,000 transactions by default, with hard minimums), performs admission in three phases (structural pre-check, input resolution, resolved verification), and re-judges height-coupled rules whenever the tip can move backwards. Block templates fill 85% of a block by package feerate and the rest oldest-first within a 10 KB package bound, and a miner's coinbase claims subsidy + fees, never more. One transaction shape is admitted outside the fee market: a guardian cancel of a confirmed staged covenant output cannot raise its own fee, so the mempool admits it without the capacity feerate contest, never evicts it, and lets nothing but another cancel replace it; it ages through the oldest-first share and moves to its front once its deadline is within a day, so a flood of higher-paying traffic cannot run out the veto window (section 10.2).

10. Monetary policy#

450M 50 4.2M 30M 3,000
hard cap (coins) reward at block 1 blocks per halving (~4 y) genesis allocation coinbase maturity (blocks)

10.1 Emission#

reward(0) = 30,000,000 coins                         (one-time genesis allocation)
reward(h) = max(50 coins >> ⌊(h−1)/4,200,000⌋, 1 bit)  clamped so Σ ≤ 450,000,000 coins

Halvings count from block 1, so the first occurs at height 4,200,001. The geometric series sums to ~420,000,000 coins; with the 30,000,000-coin genesis mint the cap is filled exactly, with no unallocated residual. The 1-bit tail avoids a discontinuity and only ever fills sub-coin rounding. Once cumulative issuance reaches the cap the reward is zero and miners are paid by fees alone; a fee-less zero-subsidy block uses a canonical zero-value OP_RETURN coinbase.

10.2 Genesis allocation (6.67%)#

Outputs Recipient Amount Unlock
vout 0 Genesis message ("Make Crypto Decentralized Again") 0 Permanently unspendable
vout 1–15 Founders (5.00%), 15 per-founder 2-of-3 vaults 22,500,000 Five annual tranches of 3 outputs (one per founder), years 1–5
vout 16 Stewardship fund launch slice 1,500,000 From coinbase maturity
vout 17–26 Stewardship fund tranches, 10 × 600,000 6,000,000 Years 2, 4, … 20

The open launch's ticket records follow these outputs in the genesis coinbase (§7.2).

Vesting is a UTXO-level consensus rule keyed on the output index: a spend of a locked genesis output is invalid below its unlock height regardless of the transaction's own locktime, so a leaked founder or council key cannot move a tranche early. Every allocation output is a 34-byte Level V hashed vault (witness version 2) over a provably unusable (NUMS) internal key, rejected by both the encoder and an explicit gate, so no key-path spend exists; every allocation, council and guardian key is SQIsign Level V. Each founder's outputs sit under that founder's own 2-of-3 multisig; the stewardship fund sits under one 3-of-5 council multisig, with no reserve keys and no timelocked recovery path (succession is a physical key handoff under the fund's charter). Allocation value is held by a consensus covenant: it can leave a vault only by being staged, a staged output can be released only after 86,400 blocks (~30 days), and inside that window its guardians can cancel it back to the vault (3-of-5 fund guardians for the stewardship fund, 1-of-3 per founder for that founder's vault). Consensus guarantees the public 30-day veto window; it does not constrain where a released output goes, so what guardians check before letting a staged spend through is their published policy, not a protocol rule. There is no premine beyond this allocation and no on-chain treasury voting at launch.

11. Network protocol#

11.1 Transport and topology#

Spek runs on libp2p over QUIC only (TLS 1.3 built in, stream multiplexing, 0-RTT reconnection for mobile and home users). Connection migration is disabled at the application layer so IP-keyed rate limits and bans remain meaningful; roughly 5–15% of hosts behind UDP-blocking networks are an accepted exclusion. Peers are found from a hard-coded bootstrap list and a Kademlia random walk (aggressive for ten minutes after start, then every ten minutes). Every connection, however discovered, passes diversity gates: at most one peer per IP, at most two per network group, a 34% cap on any hosting autonomous system, 20 outbound and 60 total on mainnet. Native IPv6 is rejected at launch.

11.2 Propagation#

Headers flood over FloodSub and are verified off the event loop on a priority validation pool (signature 3–6 ms plus the reveal walk, never awaited inline) with per-peer in-flight caps, after the one-hash claimed-score pre-filter has dropped any header that could not rank; bodies are pulled, never pushed. Seed-phase ticket records travel on their own topic and are checked on the mempool lane, never on the slot-critical path. Current-slot pulls go compact-first: the server sends short transaction ids keyed by a server-chosen nonce (a block-hash-only key would let an offline collision grind force the fallback on every node identically), the client reconstructs against its mempool and must reach the header's merkle root, and every failure converts to a classic full-block request. Full blocks remain the unconditional fallback and the initial-download path.

The scheduler guarantees that the current slot's rank-1 block validation gets service ahead of download, catch-up and mempool work. Starving live propagation is the one scheduling failure that costs the network mining power, and an earlier ordering that strictly demoted catch-up instead produced 11-deep self-forks under load; propagation and catch-up are co-equal above download and mempool admission, with a reserved lane for the slot-critical verdict.

11.3 Misbehaviour#

Violations are counted per canonical IP (IPv4-mapped IPv6 normalised at the type level, so evasion by address form is unrepresentable), in three classes (header, transaction, block) with their own thresholds. Bans escalate 1 day → 4 days → 90 days and persist to disk; every ban is timed, so the bounded ban table always has an eviction victim and a strike memory that survives expiry keeps a returning offender on the top rung. Expiry runs on the verified clock so a stepped host clock cannot shorten them. Divergence across a checkpoint caps at 16 days so an honest node on the wrong side of a fork can always return. Objective invalidity (a bad signature, a reveal outside its horizon, an invalid ticket record) is a strike. So is a header that builds directly on the receiving node's tip but is ineligible there or carries a seed that does not derive from the tip's: that verdict depends only on the tip's ledger, so every node on that tip reaches it, and an honest node publishes a header only after ranking it on its own tip, so no honest relayer ever delivers one. Five header strikes inside 18 hours ban the address. Drops that could be the relayer's fault rather than the producer's, or that depend on a ledger view that differs across forks (a negated attempt, no stake at the derived address for a header off the tip, a collision), are silent, never strikes.

12. Synchronisation and checkpoints#

12.1 Initial block download#

A joining node downloads headers in batches and runs signature and horizon checks in parallel, then pulls bodies in order into a staged store and applies them strictly sequentially with the same authoritative validator used at the tip, which derives each header's horizon root and checks its stake output or ticket record against the ledger it has built. Each candidate chain resolves its own beacons from its own headers. There is no "assume-valid" height: every block at every height is fully SQIsign-verified. Download starts only with at least 8 sync peers, or 1 if a hard-coded bootstrap seed is connected; the bar cannot be lowered by any flag or RPC, by design, so an eclipse cannot relax it. The node keeps mining and relaying while deferred.

12.2 Mining is never suppressed by download#

If a candidate chain could pause mining, an attacker could advertise a fake heavy chain to halt honest block production and exploit the weakened window. Mining on the main chain continues unconditionally; if the download selects a better chain, the reorg orphans the node's blocks naturally.

12.3 Checkpoints#

Checkpoints sit on a 4,000-block grid shared by the checkpoint-handshake identity, the served checkpoint chain, the durability fsync, and the self-produced UTXO snapshot. Hard checkpoints pin settled history for nodes that have none of their own (a new joiner, a resync, a node offline for days): exchanged work claims are unauthenticated and could otherwise lock such a node onto a fabricated heavier chain. They are permanent weak subjectivity, not a seed-phase measure. Unbonded stake cannot bound signing after the fact: a key that held stake at a fork point can sign a branch from that point at any later time, even after its owner sold the coins, and a private branch knows its own future beacons. Pins are therefore never retired. Each release compiles in boundaries the running network already holds as restoration pins, and between releases a pin file extends them. The node authenticates that file itself: it must name the network and genesis and carry signatures from a threshold of the checkpoint signers compiled into the binary, and it may add to the compiled-in table but never contradict it. The mitigations are threshold signing by signers who each confirm the hash on their own fully validated node, reproducible builds, and independent reproduction of every published pin.

13. Node architecture and storage#

The reference implementation is a Rust workspace of 20 crates: config, util, crypto (with a separate wallet-only seeded-keygen crate so the node binary never links a DRBG, and a build crate for the vendored SQIsign stacks), RandomX, core types and chain state, consensus, script, mempool, FloodSub, network, storage, RPC, node, wallet, covenant and guardian tooling, a test client and an operator GUI. Production code contains no unwrap; errors are typed. Tests favour end-to-end harnesses over unit tests.

State lives in RocksDB (headers, blocks with undo data, UTXO set, main-chain index, chainwork, seed-phase ticket records, metadata, bans, snapshots), written as atomic batches without per-block fsync (a disk stall on the commit path would delay honest propagation; durability is recovered at checkpoint boundaries). The UTXO set is fully resident with a 20-byte script index for O(log N) lookups and a value-ordered stake index for the eligibility walk. Three operating modes exist: archive, pruned (default, 100 GB target, 20,000-block floor; pruned nodes can mine), and assume-UTXO from a snapshot. An archive year is roughly 2 TB at full 2 MiB blocks; a pruned node around 15–20 GB plus about 0.7 GB of headers per year.

One authenticated RPC surface is served: JSON-RPC (port 4521), with one 128-permit admission semaphore and integer-only values. The API is intentionally not Bitcoin-compatible: there is no difficulty, nonce, bits, or median time; headers expose miner_pubkey, miner_signature, election_seed, horizon_start, slot_reveal and slot_path, and getstakeaddress reports each horizon's stake address, eligibility window and counted output.

14. Governance and upgrades#

Spek has one upgrade mechanism: a monotonically increasing block version activated at a fixed flag height in a compile-time-checked schedule, empty at launch. A signature-scheme or header-format change is always a hard fork and uses this path; rule tightenings use it too, relying on off-chain coordination. There is no BIP-9-style version-bit signalling: it coordinates soft forks, and a slot-winner signal is a weak, grindable readiness proxy. If a soft fork later needs on-chain coordination it will be designed against Spek's actual consensus, preferably with guaranteed eventual activation. Process governance is off-chain and social; every full node enforces every rule; each operator independently opts into or declines an update.

15. Threat model#

Threat Mechanism Residual
Score grinding Score inputs (key, commitment, reveal) all fixed before the beacon; seed binds only parent seed + key + reveal; no producer-malleable bytes Withholding at a beacon height: 0.3–0.6% of an attacker's own wins over all epochs, no compounding
Stake shifting into a pre-chosen key Stake counts only below a cutoff a full epoch before the beacon height Closed
Commitment copying / reveal replay Key bound into the score preimage and every commitment leaf Closed
Predicted winners (targeted DoS, bribery) Scores unknown until each header is published None for live slots
Sybil (post-seed) One output ≥ 80% of reward per draw, aged 24–36 h Attack share = capital share; concentration risk is economic, not protocol
Sybil (seed phase) RandomX ticket per stake address per 3-day round, recorded on chain before it counts; Spek-variant VM Launch seats: the search opens at a Bitcoin block, so every searcher starts together and no record exists before it; the organiser could leave a listed entry out of the sealed list, which the public listings and the witnessed seal digest expose. No party has an informed abort: the launch beacons depend on a Bitcoin block mined after the seal
Private-branch rewrite Fixed draws; pins bound running nodes; checkpoints bound fresh nodes A private branch chooses its own beacons: break-even attacker share 0.45–0.47 within the pin; about 0.42 for a fresh node without checkpoints
Bought or dormant keys signing old branches Restoration pins and compiled checkpoints Unbonded stake cannot bound this; such keys add to an attacker's share at no cost to the seller
Clock steering Authenticated Roughtime quorum, operator diversity, RAW-clock projection, 5 s step bound, mining hold A quorate colluding cohort can walk the clock 5 s per sync; pool composition is the security parameter (§17)
Equivocation One entry per key per attempt; different content → slot negated, proof gossiped None beyond forfeited slot
Header / body flood Claimed-score pre-filter, structural gates before signature; per-peer verify caps; pull-only bodies; rate limits; escalating IP bans Griefing bounded; winning power unaffected by flood rate
Stake-address dust One counted output per draw, value-ordered index Each extra step costs a full stake unit
Validation-cost amplification Per-input signature budget debited before verify; Level V witness bytes weighted by ρ; positive-only cache; rank-1-only full validation Adversarial leaf ≈ 1.27× honest signature density
Deep reorg / long range Depth-4 comparison, bounded rollback, untruncated chainwork, restoration pins, checkpoint barrier Partitions longer than the pin lag need operator recovery
Fake-chain mining halt Mining never suppressed by download None
Eclipse during sync 8-peer minimum (1 with hard-coded seed), diversity caps, no relaxing flag Small deployments depend on seed reachability for deep-fork resolution
Fund burn Output-form whitelist; canonical keys and addresses Leaf authors remain responsible for witness-injective scripts
Witness malleability Identities exclude witness bytes: txids and block hashes do not cover signatures, the merkle root commits to the exact witnesses; canonical wire, minimal numbers, clean stack, minimal-if, one signature rule SQIsign signatures themselves stay malleable (no strong unforgeability, by design): a mempool copy may differ from the one mined, which costs a re-verify, never an identity
Harvest-now quantum attack Keys hidden behind hashes until spent; Level V for long-lived custody Stake keys are public in headers; the payout rule keeps one stake unit per key
Quantum or classical break of SQIsign SQIsign everywhere; independent slot secrets; reserved version selectors Depends on SQIsign holding (a NIST Round 3 candidate, not a NIST standard; implementation audited only by AI models); a Level I break allows equivocation negations and history rewrites down to the pin, not live-slot theft; migration is a scheduled hard fork

16. Comparison#

Bitcoin (PoW) Typical bonded PoS Spek
Category Proof of work Bonded proof of stake Unbonded proof of stake (RandomX tickets for the first 45 days)
Block schedule Poisson, ~10 min Slots, often 12 s with committees Fixed 30 s slots; a block (or null) exists for every slot
Producer selection First valid nonce VRF / committee rotation over bonded stake Max hash distance over a beacon, the key and a committed per-height secret; one draw per stake output
Leader schedule known in advance No Often an epoch ahead No: each score is unknown until its header is published
Cost of a ticket Energy per attempt, perpetual Bonded, slashable capital One aged output at the stake address (a threshold, never locked); RandomX compute in seed phase
Penalty for attacking Hardware and energy spent Slashing No slashing; the attacker's purchases raise the price it pays, and its held stake loses value when the attack is seen
Honest opex Dominant Low ~Zero beyond a node
Settlement Probabilistic, ~60 min convention Finality gadget, minutes Confirmations sized to an attacker share (68 min against one third); restoration pin at 33–67 h; checkpoint barrier
Timestamp Declared, MTP rule Slot-derived Derived; no header field
Signatures ECDSA / Schnorr BLS / Ed25519 SQIsign Level I, Level V for custody (post-quantum)
Public keys on chain Exposed by many output types Exposed Hidden until spent (stake keys excepted)
Empty-network liveness Chain halts Skipped slots Deterministic null block, score 0
Upgrades BIP-9 / BIP-8 signalling Varies, often on-chain Block version + flag height only

Where Spek is genuinely strong. None of the chains above has all of these at once:

17. Known limitations and open items#

A white paper that omits its own open problems is marketing. As of this draft:

Appendix A. Parameter reference#

Parameter Value Notes
TIMESLOT_DURATION 30 s Block time; height = slot
PHASE2_START_MS 6,000 Headers-only before; bodies after
MAX_BLOCK_SIZE 2,097,152 B Header plus the sum of transaction vsizes
MAX_TRANSACTIONS_PER_BLOCK 8,000
PROPAGATION_FORK_WINDOW 4 Deepest fork resolved on the propagation path; deeper forks go to download
PROPAGATION_FORK_MAX_ROLLBACK 5 Hot-path reorg bound
CHECKPOINT_GRID_INTERVAL 4,000 blocks ~33.3 h; restoration pin trails the tip by 33–67 h
election_epoch_blocks (L) 1,440 12 h; beacon epoch
slot_segment_blocks (S) 8,640 3 days; one slot-secret hash chain
SLOT_HORIZON_DEPTH (d) 10 1,024 segments per horizon, ~8.4 years
Stake age 2L+2 to 3L+1 blocks About 24–36 h from creation to first counted height
Horizon renewal lead 122 segments ~1 year; node policy, operator-configurable
coinbase_maturity 3,000 blocks ~25 h
initial_block_reward 50 coins Block 1
halving_interval 4,200,000 Counted from block 1
tail_reward 1 bit Floor until cap
max_supply 450,000,000 coins Exactly filled
genesis_reward 30,000,000 coins Founders 22.5M + stewardship 7.5M
vesting_interval_blocks 1,051,200 ~1 year
seed_phase_blocks 129,600 45 days
seed_ticket_round_blocks (W) 8,640 3 days; 15 rounds
SEED_TICKET_TARGET_D 2^228 ~3 tickets/round on a 2018-era 8-core desktop
ticket_records_per_block_max 16 Seed-phase coinbase records per block
Coin requirement max(80% reward, 0.1 coin) Post-seed; one output at the stake address, aged
FEE_FLOOR (era 0) 250,000 bits Flat ≤ 3,000 vB, linear above
ρ (Level V witness weight) 151/50 = 3.02 vsize multiplier for Level V input witness bytes
SQIsign Level I pk / sig / sk 83 / 200 / 270 B Headers, mining keys, default outputs
SQIsign Level V pk / sig / sk 169 / 406 / 549 B Opt-in custody; allocation, council, guardians
Miner key file 385 B Level I secret key, public key, 32-byte slot seed
Header / signed prefix 743 / 543 B
Hashed output / plain ScriptCommit 34 / 118 B
Roughtime sync interval 1 h learning, 4 h once the rate is confirmed (≤ 5 ppm) Rate correction clamped at 250 ppm, at most 50 ppm per sync
Roughtime quorum / outlier / step 3 operators (floor 3) / 2 s / 5 s One vote per operator
Peers: per IP / per netgroup / ASN cap / outbound / total 1 / 2 / 34% / 20 / 60 Mainnet
IBD minimum peers 8 (1 with bootstrap seed) Not overridable
Ban ladder 1 d → 4 d → 90 d Checkpoint divergence capped 16 d
Ports (mainnet) 4520 p2p / 4521 JSON-RPC Testnet 14500s, regtest 24500s
Script limits 10,000 B / 1,000 items / 520 B / depth 100 / proof 128

Appendix B. Confirmations against an attacker share#

Probability that a transaction at k confirmations is ever reversible, for an attacker holding share q of the draws who may choose its fork point in hindsight (RFC-0012, Appendix B):

q k = 6 10 30 60 120 240
0.10 3.6e-4 4.8e-6 3.8e-15 1.3e-28 2.3e-55 ~0
0.20 1.8e-2 2.4e-3 2.0e-7 2.2e-13 3.7e-25 1.4e-48
0.33 2.4e-1 1.3e-1 7.3e-3 1.4e-4 6.4e-8 1.8e-14
0.40 5.5e-1 4.3e-1 1.5e-1 3.5e-2 2.3e-3 1.3e-5

Confirmations for under one reversible slot per century (1,051,200 slots a year):

q 10% 20% 25% 30% 33% 40% 45%
k 16 (8 min) 37 (18 min) 58 (29 min) 95 (48 min) 136 (68 min) 412 (3.4 h) 1,686 (14 h)

Parameters marked as placeholders are substituted at launch. This document describes the implementation as it exists and is not an offer of any kind.

Versions