Sign in the cold.
Broadcast from the heat.
Your keys live on a machine that never touches the network. The hot machine issues a chain ticket with everything the cold side needs — genesis hash, runtime versions, your next nonce — you sign the transfer offline with real ML-DSA keys, and the hot side re-verifies the signature locally before anything reaches the chain.
1 Issue a chain ticket
Connects to a node, reads the chain facts a cold signer needs, and packs them into one QR. The ticket binds the signature to a specific genesis, runtime, nonce and era window.
The ticket stays saved on this hot desk — step 2 uses it to verify the signature.
2 Receive, verify & broadcast
Bring the signed package back from the cold machine — scan the chunk QRs, drop images, paste the text blocks, or load the file. The desk reassembles, decodes, and re-verifies the ML-DSA signature locally before offering broadcast.
Verification ticket
The signature is re-derived from the ticket it was built against. This hot desk remembers the ticket it issued; if the package came from another session, paste that ticket here.
🛡 What the hot desk guarantees — and what it can't
- Byte-exact payload: the signature is verified against a payload re-derived from the ticket, not from values inside the package — a package that claims a different genesis, runtime, nonce or amount fails.
- Nonce freshness: before broadcast, the desk compares the package nonce with the chain's
accountNextIndex. A stale nonce means something else was sent first — re-issue the ticket. - Era window: the mortal era (64 blocks) is checked against the current head; an expired package is refused, not retried.
- What it can't do: prove the cold machine was offline, or that the 24 words were never photographed. Cold hygiene is physical.
1 Import the chain ticket
Scan the ticket QR from the hot desk, drop its image, paste the text, or load the file. The ticket is validated strictly — wrong network, bad checksum, or malformed fields are refused.
2 Build the transfer
Everything is constructed locally — no network calls, ever, on this side.
Read these five checkphrase words back before the desk will sign — this is your last defense against a poisoned or mistyped address.
Signing key — memory only, wiped after signing
Offline, the exact fee can't be quoted — the hot desk quotes it from the node before broadcast. Byte length of the final extrinsic is shown so you know what you're carrying.
3 Signed package
Carry these chunk QRs (or the text/file) to the hot machine. Scan in any order — the hot desk reassembles them. ML-DSA signatures are kilobytes, so chunking is the practical path.
Nothing signed yet.
🔒 Signing key wiped from memory.
⚙ How the protocol works
The chain ticket
A signed-by-nobody JSON blob: sender address, next nonce, genesis hash, spec &
transaction versions, head number+hash, and the mortal-era window (birth block + hash). Serialized as
QAGT1:<base64url> — small enough for one QR. The cold side refuses tickets with a bad
SS58 checksum, a non-189 prefix, or malformed chain fields.
The signed package
A complete signed extrinsic — version byte 0x84, AccountId32 sender,
variant-tagged ML-DSA signature + pubkey, mortal era, nonce, tip, and the
Balances.transfer_keep_alive call. Transported as numbered chunks
QAGX:<session>:<i>/<n>:<base64url>; reassembly tolerates any scan
order and duplicates, and refuses mixed sessions or missing chunks.
Hot-side verification
The desk decodes the extrinsic, pulls the ticket's genesis/spec/tx-version/era-birth,
re-derives the exact signing payload (QUANTUS_EXTRINSIC context), and verifies the ML-DSA
signature locally. Only then is a node fee quoted and broadcast offered. Tamper with one byte and the
badge goes red.
Honest limits
- No page can prove its machine is offline — the airgap is your procedure.
- Fees are quoted by the node at broadcast time; the cold side only knows byte length.
- The era window is 64 blocks — dawdle and the package expires; re-issue the ticket.
- If the sender's nonce moved (another transfer went out), the ticket's nonce is stale — the hot desk checks
accountNextIndexand warns.