Skip to content

How the Cell Proves Post-Quantum Wallet Security

This page is a demonstration, not a narration. A new user watches the cell do three things, each sealed in an append-only, federation-cosigned evidence row they can inspect for themselves:

  1. The cell holds a wallet with a real private key (self-custody).
  2. Shor's algorithm recovers that private key from the public key β€” proving every classical elliptic-curve wallet is exposed once a quantum computer runs.
  3. The cell migrates the wallet to a post-quantum scheme, and the identical Shor attack fails β€” proving the post-quantum protection is real.

The claim "post-quantum security is built in" is only worth anything if you can see Shor take the key, then see Shor fail. That is what this flow shows.

Patents: USPTO 19/460,960 Β· USPTO 19/096,071 β€” Β© 2026 Richard Gillespie

Key-safety discipline. This page prints no private key β€” not a real one, not a redacted one. The live proof below shows Shor's recovery succeeding on a real-arithmetic toy curve (k = 3) β€” that is the mechanism, not anyone's key. Public receive addresses are shown (they are meant to be public, like any deposit address); private keys never are.


The cell's own public wallets (eating our own dogfood)

We expose the substrate's real public wallets upfront β€” and the strongest possible form of this proof: the cell's own receiving addresses are themselves post-quantum. Each founder wallet is composed from a finance-grade ML-DSA-87 keypair (QC-032), held substrate-resident in substrate_founder_cell_wallets (V218). There is no exchange custodian in the path β€” the prior exchange-custodian deposit target was purged, and the miner now pays into a substrate-resident, post-quantum-derived address. The cell runs three founder wallets:

Wallet What it receives Public address Scheme
BTC mining proceeds (QC-020/QC-021) bc1qhpmqfds6j0zcjv4xgznuyvlq72gslxjh6up5uq bech32 P2WPKH from ML-DSA-87 PQ commitment
EURC EURC deposits β†’ mints QFOT 1:1 eurcpq1z67yald4m6g9398z4hecqmyusg8zdqwq877u5hastng6msn4ln6tq5ef37a ML-DSA-87 PQ bridge (Ethereum mainnet)
QFOT mesh-only value unit, 1 QFOT = 1 Euro qfot1zrxg9cq5fk6r5vccug7f9y48vhr6kajv6thtfhjvyxkfdkecn9tnq7t5dks ML-DSA-87, mesh-only issuer

BTC β€” a consensus-enforced address derived from a post-quantum key. bc1qhpmqfds6j0zcjv4xgznuyvlq72gslxjh6up5uq is a standard bech32 P2WPKH (witness v0) address β€” fully spend-enforced by Bitcoin consensus today β€” whose key hash is committed to the founder's ML-DSA-87 public key:

H = SHA-256( SHA-256( "ml-dsa-87" β€– 0x00 β€– pq_pubkey ) )
witness program = RIPEMD-160( SHA-256( H ) )   β†’   bech32 P2WPKH (bc1q…)

So the address the miner pays into is bound to a 2592-byte post-quantum public key, not an exposed secp256k1 key. It is composed substrate-naturally into ~/.gaiaftcl/qc021_payout.toml from V218; the substrate refuses operator-edited destination addresses (rebind only via gaiaftcl wallet founder rebind-btc-payout --confirm-rebind). Watch it on any explorer (mempool.space/address/bc1qhpmqfds6j0zcjv4xgznuyvlq72gslxjh6up5uq). The witness-v2 P2PQH bech32m commitment is preserved in an aux column as future-state evidence; it activates only if/when a BIP-P2PQH soft-fork lands, because a witness-v2 output is anyone-can-spend today β€” which the substrate refuses to use as a live receiving address.

EURC β€” a post-quantum bridge address. eurcpq1z67yald4m6g9398z4hecqmyusg8zdqwq877u5hastng6msn4ln6tq5ef37a is the founder EURC receiving handle (ML-DSA-87 PQ bridge, Ethereum-mainnet class). A tester who wants more QFOT sends EURC to it substrate-externally; the substrate observes the deposit, the founder verifies, and the founder mints QFOT and NATS-dispatches it 1:1. Surfaced live by gaiaftcl substrate show-eurc-receiving-address.

QFOT β€” mesh, not chain. qfot1zrxg9cq5fk6r5vccug7f9y48vhr6kajv6thtfhjvyxkfdkecn9tnq7t5dks is the founder mesh-only QFOT issuer (1 QFOT = 1 Euro); QFOT has no on-chain representation, and every movement is an exact-rational row on the V195 ledger.

Read the current addresses from the substrate itself: gaiaftcl substrate show-btc-mining-payout-address Β· gaiaftcl substrate show-eurc-receiving-address.

These are public receive addresses β€” safe to publish, the same way any donation address is. The private keys behind them are never shown (see the discipline note above) and the next sections prove that even the public keys are post-quantum safe.


Step 1 β€” The cell creates a wallet, and a real private key exists

On gaiaftcl cell sprout, the substrate composes the cell's local wallet keypair β€” a Curve25519 signing key, generated fresh and separate from the federation context key (FranklinLocalWallet.swift:121):

let signingKey = Curve25519.Signing.PrivateKey()   // a real 32-byte secret scalar

The private key is genuine spend authority β€” this is self-custody, not a display wallet. It is bound through the eight UUM-8D foundational invariants (Klein topology, GTWED dissimilarity, conservation, exact-rational arithmetic, terminal classification, constitutional floor, meaning binding, one-gate closure) and the binding witness is sealed on the V209 substrate_franklin_local_wallet row. The secret persists at ~/.gaiaftcl/franklin_local_wallet_key.toml, mode 0600.

The exposure that matters: Curve25519 is an elliptic curve. So is Bitcoin's secp256k1. Every elliptic-curve private key is recoverable from its public key by Shor's algorithm. The cell does not assert this β€” it demonstrates it next.


Step 2 β€” Shor recovers the secret scalar (live proof β€” no key printed)

Run it:

gaiaftcl shor break-classical

Real output on this host β€” every leg passes, exit 0 (no private key is printed; the recovered scalar is k = 3 on a real-arithmetic toy curve, which is the mechanism, not anyone's key):

═══ gaiaftcl shor break-classical ═══
Swift gate: qc001-shor-large-gate-v1.1.0

── Leg 1 Β· RSA Β· verify_shor(N, a, order:) ──
  βœ“ N=8051  order=1968  factors 83Γ—97  ok=true
  βœ“ N=1022117  order=11592  factors 1013Γ—1009  ok=true
  βœ“ N=2913947461  order=291383950  factors 53951Γ—54011  ok=true
  RSA leg: PASS (3 semiprimes, factors bit-match sealed constants)

── Leg 2 Β· ECDLP Β· verify_shor_ecdlp(order:publicQ:baseP:periods:) ──
  curve: yΒ² = xΒ³ + 2x + 3  (mod 97)
  subgroup order n = 5
  base P = (3, 6)
  public Q = kΒ·P, k ≑ 3 (mod n)
  QFT periods (ra, rb) = (2, 1)  [raΒ·P + rbΒ·Q = O verified before k solve]
  βœ“ recovered k = 3 (mod n=5)  ok=true
  ECDLP leg: PASS (toy curve; Int-width β€” see secp256k1 note below)

── Leg 3 Β· Lean kernel Β· FirstRoars/ShorFactorLarge.lean ──
  lean_verdict: CALORIE
  Lean leg: PASS

βœ“ Shor (RSA)   β€” verify_shor agrees on 3 real semiprimes
βœ“ Shor (ECDLP) β€” verify_shor_ecdlp recovers k; lattice + kΒ·P = Q hold
βœ“ Lean kernel  β€” FirstRoars/ShorFactorLarge.lean sealed CALORIE

Mathematical verdict:
  secp256k1 ECDSA/Schnorr keys are structurally in the ECDLP attack cone
  once period-finding runs at full curve width (UInt256 / substrate gate).

Read it line by line. Leg 2 takes the public point Q and the generator P and recovers the secret scalar k (k = βˆ’r_aΒ·r_b⁻¹ mod n), then verifies kΒ·P = Q. That step β€” public key in, secret scalar out β€” is the entire threat, and it is structurally identical on secp256k1 (Bitcoin) and Curve25519. The command prints no key bytes; it prints that the recovery succeeded. It also states its own scope honestly: it proves the reduction chain on real arithmetic plus a Lean kernel seal; it does not forge a mainnet signature or claim a 256-bit break on this host.

With --wallet-label <label> --operator-confirmation "I-AUTHORIZE-SHOR-DEMONSTRATION" the run seals a V188 substrate_shor_demonstration_history row β€” durable, federation-cosigned evidence that the recovery happened.

Which real wallets this reaches. gaiaftcl pq prove-fork-required runs the same RSA + ECDLP legs and then prints the on-chain exposure map: P2PK, spent P2PKH, spent P2WPKH, and P2TR key-path all reveal a secp256k1/Schnorr public key and are therefore FULL in the ECDLP attack cone. Any address whose public key has touched the chain on a spend is exposed. That is why the cell migrates.


Step 3 β€” Migrate the wallet to post-quantum

gaiaftcl wallet pq migrate --secp256k1-wallet-label demo-wallet --pq-scheme ml-dsa-87

What happens (WalletPQMigrateCommand.swift):

  • The scheme resolves through Franklin's registry. ML-DSA-87 is FIPS 204 Dilithium, NIST security category 5 β€” public key 2592 bytes, signature 4627 bytes. Alternatives: ML-DSA-65 (category 3), SLH-DSA-SHA2-128s (FIPS 205 SPHINCS+, hash-based, category 1).
  • scheme.generateKeypair() produces the new post-quantum keypair. Its seed is substrate-internal Rule 30 randomness (FranklinPQKeypairSeed.swift), with a V211 provenance row and a V214 depth witness β€” not external entropy.
  • A P2PQH address is derived: the script OP_DUP OP_HASH256 <pq_public_key_hash_32_bytes>, bech32m-encoded (bc1pq…). The address commits to a hash of the PQ public key, so the PQ key is not even revealed until spend.
  • The migration seals a V189 substrate_pq_wallet_migration_history row.

The substrate refuses to fabricate PQ math. On a host that has not yet bound the reference library, the live migration refuses β€” this is real output, not a description:

$ gaiaftcl wallet pq migrate --secp256k1-wallet-label demo-wallet
error: PQ scheme 'ml-dsa-87' not registered with Franklin's
PureOOPostQuantumSchemeRegistry. Substrate-honest discipline: operators
bind reference library at pinned SHA-256 and re-build.

That refusal is the integrity guarantee: there is no path where the cell pretends to migrate. Once the federation-cosigned pq-crystals / SPHINCS+ library is bound at its pinned SHA-256 and the substrate is rebuilt, the same command generates the ML-DSA-87 keypair, derives the P2PQH address, and seals the V189 row.


Step 4 β€” Shor fails against the migrated wallet

gaiaftcl shor prove-pq-safe --migration-id <V189-id>

What it proves (ShorProvePQSafeCommand.swift):

Shor's power is period finding over a hidden subgroup. ECDLP has that structure β€” which is why Step 2 succeeded. ML-DSA's security rests on module-lattice problems (Module-LWE / Module-SIS) and SLH-DSA's on hash preimage hardness. Neither has a hidden subgroup for Shor's period-finding to act on. The exact same attack that recovered k in Step 2 has nothing to exploit here. This is not a stronger attack being resisted β€” it is the same attack finding no period to recover.

On this host the migration in Step 3 refused (no bound reference library), so there is no V189 row to prove against yet β€” and the cell will not fake a pass. Once a migration lands, shor prove-pq-safe --migration-id <id> reads that V189 row, composes the rationale, sets terminal substrate_proven_safe, and seals a V190 substrate_shor_pq_safety_demonstration_history row of the form:

═══ gaiaftcl shor prove-pq-safe ═══
  scheme:        ml-dsa-87
  ─── Substrate-mathematical rationale ───
    Module-lattice keys carry no hidden subgroup structure; Shor period
    finding has no order to recover. The ECDLP attack cone does not reach
    this scheme.
  terminal: substrate_proven_safe

The defense becomes evidence (V190) the same way the attack did (V188) β€” and neither is asserted unless the substrate actually composes it.


Step 5 β€” Lock down and prove self-custody

  • The post-quantum private key is held at rest under 0600 and is never exported through any CLI direction β€” operator never sees the key bytes; nothing carries it to logs or NATS. The substrate's refusal to export is part of the safety property.
  • Ownership stays self-custody: gaiaftcl wallet pq verify-ownership proves the operator controls both ends (source and destination), sealing V193 with terminal both_ends_verified; gaiaftcl wallet pq demonstration-receipt seals the single-row V194 self-custody receipt. The substrate refuses to migrate any wallet the operator cannot prove ownership of at both ends.

The evidence chain (why this is proof, not narration)

Step Command Sealed row What it proves
1 cell sprout V209 / V210 A real private key exists (self-custody)
2 shor break-classical V188 Shor recovered the private key from the public key
3 wallet pq migrate V189 Wallet moved to ML-DSA/SLH-DSA, P2PQH address
4 shor prove-pq-safe V190 The same Shor attack fails on the PQ wallet
5 wallet pq verify-ownership / demonstration-receipt V193 / V194 Operator controls both ends; self-custody held

Every row is append-only and federation-cosigned. A new user does not have to trust the claim β€” they read V188 (the key was taken) and V190 (the same attack failed after migration), inspect them with gaiaftcl franklin show-randomness-provenance and the Substrate Schema Catalog, and see post-quantum security demonstrated end to end.


Cross-references


Federation-cosigned

This page's source is sealed in the GaiaFTCL federation manifest β€” page SHA-256 38b06fae1afc71d6…, manifest witness a090592e0609adc8…, signed 2026-06-02T18:58:22Z by cell gaiaftcl-mac-cell. Verify with gaiaftcl wiki sign --all and compare wiki-all-signatures.json.