Rust · post-quantum PoW blockchain
Ironchain is a from-scratch proof-of-work blockchain in pure Rust with zero dependencies. The only primitive is SHA-256, implemented in the repo, and signatures are hash-based Lamport keys arranged under a Merkle tree, so it is a post-quantum, hash-only chain. This page runs the whole thing live in JavaScript, SHA-256 and all: mine real blocks, edit any field to tamper, watch the break cascade downstream, then fork the chain and watch a reorg rewrite the balances.
Every control on this page is wired to a working blockchain engine. Here is what each one does.
Expected work ≈ 212 = 4096 hashes per block. Above ~18 bits the browser may pause noticeably.
Balances recompute from the active chain after every mine and reorg.
| Name | Address | Balance | Nonce |
|---|
Pending transactions. Cleared into the next mined block.
Newest block on the right. Green = valid, red = invalid. Edit any field to tamper; the break cascades downstream. Fields are recomputed and re-validated on change.
A block commits to its transactions with a Merkle root. Pick a block and a transaction to see the proof path that links a single leaf to the root. Odd levels duplicate the last node.
The point of Ironchain is that its safety is machine-checked, not asserted. The tamper oracle in tests/tamper_oracle.rs builds a valid multi-block chain, confirms full-chain validation accepts it, then mutates one copy of every mutable field in turn and confirms validation rejects each one. Six gates plus an adversarial suite and a soak back it up.
# the correctness gates (cargo test) 1 tamper oracle valid accepts; mutate any amount, fee, signature, sender, receiver, nonce, merkle root, parent hash, PoW nonce, timestamp, difficulty, or miner, and it rejects 2 signatures one flipped bit in the message or signature fails, with pinned SHA-256 and derived-address known-answer vectors 3 merkle inclusion proofs verify for included leaves, fail otherwise, across non-power-of-two trees and side-swapped proofs 4 fork choice the most-work chain is picked, and the resulting account state matches an independent recomputation on the winner 5 retarget the incremental and full-chain validators recompute the same difficulty at every retarget boundary 6 malleability every reveal, complement, and auth-path bit is flipped and must fail; wrong leaf indices and truncated paths too
The signatures are the different angle: instead of elliptic-curve keys, Ironchain signs with Lamport one-time keys under a Merkle tree, so security rests only on the hardness of reversing or colliding SHA-256. The chain stays secure even against a quantum adversary. The adversarial suite in tests/adversarial.rs states one rule per test, and tests/soak.rs mines hundreds of blocks while a rival miner forks and overtakes.
Ironchain is not a new consensus idea. It is the readable, zero-dependency version of ideas that already secure real chains, with one deliberate change at the signature layer.
Ironchain echoes the same core: proof-of-work over a block header, a transaction Merkle tree with inclusion proofs, difficulty retargeting, and fork choice by most cumulative work. The difference is scale and intent. Bitcoin is a hardened production network; Ironchain is a single crate you can read in an afternoon.
Nearly every chain signs with elliptic-curve keys, which a large quantum computer could break. Ironchain signs with Lamport one-time keys under a Merkle tree, an XMSS-style scheme, so security rests only on the hardness of reversing or colliding SHA-256. It stays secure even against a quantum adversary.
Most from-scratch blockchains skip the parts that make a chain safe: real signatures, inclusion proofs, retarget consistency, reorg. Ironchain keeps all of them and proves each with a machine-checkable test rather than prose.
The only cryptographic primitive is SHA-256, implemented in the repository. No curves, no external crates, standard library only.
The building blocks
Each one is implemented in the repository behind no dependency, and each is covered by the correctness gates.
The miner searches for a header nonce whose double SHA-256 hash meets a difficulty target measured in leading zero bits. block::mine and meets_target.
The target recomputes on a schedule. Gate five confirms the incremental and full-chain validators agree at every retarget boundary, for chains that speed up and slow down.
Each block commits to its transactions with a Merkle root. merkle::prove and verify produce and check inclusion proofs across non-power-of-two trees.
Hash-based one-time keys arranged under a Merkle key tree, an XMSS-style scheme. Post-quantum, SHA-256 only. Signatures serialize and reparse strictly.
Pending transactions wait in the mempool with projected balances and nonces until a miner includes them in the next block. chain::submit_tx.
The node selects the branch with the most cumulative work and reorganizes onto it, recomputing account state to match an independent recomputation on the winner.
Prove a payment is in a block from just the header and a Merkle path, no chain storage required. spv::prove_tx and verify_spv, with a compact serialization that round trips.
A library crate plus a binary, standard library only. The same engine backs the demo, the light client, and the gates.
./target/release/ironchain mines a short chain with random valid transactions, prints the blocks and balances, then tampers with a transaction and shows validation rejecting it.
Modules sha256, sig, merkle, tx, block, state, chain, and spv. Build a Blockchain, submit_tx, mine_next, read state, or check a whole history with validate_chain.
spv::prove_tx builds a proof from a block and a transaction index; spv::verify_spv checks a payment with no chain present. Every truncation and non-canonical flag is rejected.
cargo test runs the tamper oracle, six gates, the adversarial suite, and the SPV tests. Env knobs scale the oracle and a soak mines hundreds of blocks under a forking rival.
# build, run the gates, and run the demo binary cargo build --release cargo test ./target/release/ironchain # mines a chain, then tampers and shows rejection # scale the tamper oracle and gates with env knobs IRONCHAIN_FUZZ_OPS=12 IRONCHAIN_SEED=7 cargo test # the long-horizon reorg soak IRONCHAIN_SOAK=1 cargo test --release --test soak