Skip to main content
Every Quantum Chain transaction carries a post-quantum signature that authorizes the spend. Block validators verify the signature against the sender’s registered public key on every block at or after quantumVerificationBlock. The signing primitive is different from Ethereum’s ECDSA, but the transaction envelope is unchanged: legacy, EIP-1559, and EIP-2930 transactions are all supported.

Three signing models

ModelWhere the key livesBest for
Local keystoregeth process memoryDevelopment, single-user nodes
External signer (Clef)A separate process you controlHot wallets with policy enforcement
Custody platform (Qustody)A signing service behind a network boundaryInstitutional, multi-user, audited

Local keystore signing

This is the path used by --unlock and personal_sendTransaction. geth reads the encrypted key from the keystore, decrypts it in memory using the unlock passphrase, and signs each transaction internally.
// Geth IPC console
personal.unlockAccount("0xfF81...", "strong-pass", 60)
eth.sendTransaction({
  from: "0xfF81...",
  to:   "0x1865...",
  value: web3.toWei(1, "ether")
})
Local keystore signing exposes your key inside the geth process. Anyone with read access to the host or to the RPC interface can drain the wallet. Use this only for development.

External signing with Clef

Clef is a separate process that owns the keystore. geth talks to clef over an IPC socket and never touches private keys. Start clef:
./build/bin/clef \
  --keystore ~/.quantum-chain/keystore \
  --chainid 20803 \
  --ipcpath /tmp/clef.ipc
Connect geth:
geth ... --signer /tmp/clef.ipc --nousb
Each signing request appears in clef’s terminal for approval, or you can write a JavaScript rule file (clef --rules rules.js) that auto-approves matching requests.

External signing via Qustody

For multi-user, policy-driven, auditable signing, use the Qustody platform. The flow:
  1. Your application calls Qustody’s POST /v1/transactions with {wallet_id, to, value}.
  2. Qustody runs its policy engine and AML screening, then enters PENDING_SIGNATURE.
  3. Your post-quantum signing service fetches the signing payload via GET /v1/transactions/{id}/signing-payload.
  4. The signing service produces a post-quantum signature using the wallet’s private key.
  5. The service POSTs the signature to POST /v1/transactions/{id}/signature.
  6. Qustody verifies the signature, broadcasts via JSON-RPC, and emits webhooks for each subsequent state.
See External signing for the full payload schemas.

Building a transaction by hand

The signing payload is the Keccak-256 hash of the RLP-encoded transaction without signature fields. The signature is a post-quantum signature over that 32-byte digest. Reassemble the signed transaction by appending the signature in the transaction’s signature fields and broadcasting via eth_sendRawTransaction. For library users, ethers.js v6, web3.py, and viem support custom signers — plug in a signer that produces post-quantum signatures and the rest of the transaction-building stack works unchanged.

Verifying a signature

Use the standard JSON-RPC:
curl -s -X POST $RPC \
  -H 'Content-Type: application/json' \
  --data '{
    "jsonrpc":"2.0",
    "method":"eth_getTransactionByHash",
    "params":["0x..."],
    "id":1
  }'
The response includes the post-quantum public key and signature fields. A node will reject any block containing a transaction whose signature does not verify against the sender’s public key.

Where to go next