SOLANA MAINNETSLOT ...SIG WOTS-KECCAK n=192 w=256VAULT PROGRAM Shor…fuHZ
How it works, v1

How QSAFU keeps it SAFU

The short version: your fees go to a vault with no private key, and only a one-time hash signature can move them. The long version is below, with every parameter. It's the same primitive behind XMSS and LMS (NIST SP 800-208).

Summary

A QSAFU vault is a program-derived account on Solana. It has no private key, so nothing signed with Ed25519 can move its funds. The vault program releases SOL or tokens only for a valid Winternitz one-time signature (WOTS) over the exact withdrawal, then rotates the vault to the next key in the same instruction. The address never changes; each key signs once.

Coins launched here name the launcher's vault as the pump.fun creator. pump.fun pays creator fees to that address, collection needs no signature, and from then on only the vault's hash-based key can withdraw.

Threat model

A large quantum computer running Shor's algorithm derives an Ed25519 private key from its public key. On Solana every address is a public key, so every wallet is exposed the day such a machine exists. Hash functions lose much less: Grover's algorithm gives at most a square-root speed-up on preimage search and parallelises poorly.

QSAFU protects funds at rest in vaults. It does not change how Solana signs transactions: the wallet that pays network fees is still Ed25519. That wallet never holds vault funds, and a forged fee-payer signature cannot produce a valid Winternitz signature.

Signature scheme

ParameterValue
n24 bytes per chain element (192-bit), the length SLH-DSA (FIPS 205) uses at security category 3
w256: each chain has 255 steps, one per byte value
chains34: 32 message-digest bytes plus a 2-byte checksum
hashkeccak-256 (Solana syscall), truncated to n where noted
signature816 bytes (34 × 24)
F(ps, i, j, x)  = keccak256(ps ‖ 0x00 ‖ i ‖ j ‖ x)[0..24]     chain step j → j+1 of chain i
pk_i            = F applied 255 times to sk_i
root            = keccak256(ps ‖ 0x01 ‖ pk_0 ‖ … ‖ pk_33)
d               = keccak256(message)                           32 digest chunks d_0..d_31
C               = Σ (255 − d_k), encoded as 2 big-endian bytes   chunks 32, 33
sig_i           = F^(c_i)(sk_i)
verify          : walk each sig_i from c_i to 255, rebuild root, compare with the vault

The checksum is what makes a revealed signature useless to an attacker: moving any digest chunk forward requires moving a checksum chunk backward, which means inverting the hash. The public seed ps and the chain and position tweaks (i, j) make every hash call in every vault distinct, which blocks multi-target attacks across vaults.

Key derivation

One 32-byte seed, shown to the user as 24 BIP39 words, generates every key of every vault. Derivation is local to the browser.

ps(v)        = keccak256(TAG_PS ‖ seed ‖ u32le(v))
sk_i(v, k)   = keccak256(TAG_SK ‖ seed ‖ u32le(v) ‖ u32le(k) ‖ u8(i))[0..24]
vault v      : key index k = the vault's on-chain nonce
address      = PDA(["vault", ps(v), root(v, 0)], program)

On the device the seed is encrypted with AES-256-GCM under a PBKDF2-SHA256 key (600,000 iterations) from the user's password. Symmetric 256-bit encryption keeps a comfortable margin against Grover.

Vault account

OffsetFieldNotes
0tag0x5a
1bumpPDA bump
2version1
4..12nonceu64, index of the current key; +1 per spend
12..44pspublic seed
44..76idroot of key 0 (fixed, part of the address)
76..108rootroot of the current key

The address commits to both ps and id, so nobody can open a look-alike vault at someone else's address. SOL is the account's lamports above rent. Tokens sit in associated token accounts owned by the vault PDA.

Instructions

#NameAccountsData
0Openpayer (signer), vault, systemps, id, bump
1WithdrawSolvault, destinationsig, amount, next_root
2WithdrawTokenvault, source, destination, token programsig, amount, next_root
3Unwrapvault, vault WSOL account, token programnone (permissionless)

Open is idempotent and keeps any lamports already sent to the address. Withdrawals reject a zero amount, a repeated or zero next root, and anything that would leave the vault below rent. Token withdrawals support SPL Token and Token-2022 (mints without transfer fees or hooks).

Signed messages

SOL    TAG_SOL ‖ vault ‖ u64le(nonce) ‖ u64le(amount) ‖ destination ‖ next_root
TOKEN  TAG_TOK ‖ vault ‖ u64le(nonce) ‖ mint ‖ u64le(amount) ‖ destination ‖ next_root

The signature binds the vault, the key index, the amount, the destination and the next key. It can't be replayed (the nonce moves), redirected (the destination is signed) or used to install an attacker's key (the next root is signed). The mint is read from the source token account on chain.

Fee flow

At launch, pump.fun's create_v2 receives the vault address as creator. Bonding-curve fees accumulate in pump.fun's creator-vault PDA; collect_creator_fee pays them to the creator and does not require the creator to sign. After graduation, PumpSwap pays creator fees in WSOL to the vault's WSOL account; the vault program's Unwrap turns them into SOL in place. A keeper calls both on a schedule. Anyone else can too, and the funds can only land in the vault.

Costs

OperationCompute unitsTransaction size
Open≈3,300356 bytes
WithdrawSol≈550k-700k (≈144 CU per hash)1,147 bytes
WithdrawToken≈600k-750k1,213 bytes
Unwrap≈1,800323 bytes

Verification hashes between roughly 3,800 and 5,000 times for a typical message, inside the 1.4M CU limit even in the worst case. Withdrawals fit Solana's 1,232-byte packet without lookup tables.

Limitations

  • Each key must sign only one message. The program enforces rotation on chain; the app stores the pending message so a failed send can only be retried, never re-signed differently.
  • Fees waiting in pump.fun's creator vault are held by pump.fun's program until collected. They can only be paid to your vault.
  • Wallet balances outside the vault remain Ed25519 until Solana adopts post-quantum accounts. SIMD-0416 (a Falcon verification syscall) is the first step.
  • The program has not had an external audit. Treat large balances accordingly.

Deployment

Read live from Solana. While the upgrade authority is an Ed25519 key, whoever holds it could change the program, so it will be removed once the program has run in production.

Deployed on mainnet
Upgrade authority