QSDM Wallet
Generate a quantum-secure (ML-DSA-87, NIST FIPS 204) wallet entirely
inside this browser tab. The private key is created locally, encrypted with
AES-256-GCM under a passphrase you choose, and offered as a
downloadable JSON keystore. Nothing about the keypair touches the QSDM
validators, this site's web server, or any third party. Compatible
byte-for-byte with qsdmcli wallet.
Read this before clicking anything
1) The QSDM wallet is the only thing standing between you and your coins. If you lose the JSON keystore file or forget the passphrase, the address is permanently unrecoverable — no support team, no reset email, no validator override. Back up the file. Pick a passphrase you will not forget.
2) Verify you are on qsdm.tech (look at the address bar) before
generating. A phishing clone of this page could replace the WASM binary and
exfiltrate the private key the moment it's generated. Even with HTTPS, treat
the wallet page like a hardware-wallet recovery screen.
3) The same keystore format is produced by the offline CLI: qsdmcli
wallet new. If you'd rather not trust a webpage, use the CLI on a
machine you control — the keystore opens here either way.
Generate a fresh wallet
Choose a strong passphrase (12+ characters, mix of types). The wallet
page never sees the passphrase in network traffic: it is fed to
PBKDF2-HMAC-SHA-256 (600 000 iterations) inside this browser
tab, the derived key encrypts the private key under AES-256-GCM,
and the resulting JSON keystore is yours to download.
Open an existing keystore
Drop in a wallet.json file (produced here, or by
qsdmcli wallet new). The browser will decrypt it locally to
confirm the passphrase is correct and the file isn't tampered with.
Nothing is uploaded.
Sign a message
Decrypt the keystore and produce a ML-DSA-87 signature over
an arbitrary message. The decrypted private key is held only inside the
WASM call; the browser zeros the JS reference as soon as the signature
is returned.
Check an address balance
Unlike the other three tabs, this one talks to the network.
It sends a single GET https://api.qsdm.tech/api/v1/wallet/balance?address=<addr>
and renders the response. An address is public information — it's already on
chain — so the request leaks no private material, but it does correlate
this browser with this address at the validator's HTTP log
layer. If you want to avoid that correlation, ask a friend's node, run your own
validator, or skip this tab entirely.
How this works
- Keypair generation: a
~3 MBGo WebAssembly module (wallet.wasm) runs the same cloudflare/circlML-DSA-87implementation that QSDM validators use to verify your transactions. It calls the browser'scrypto.getRandomValuesfor the keygen entropy. - Encryption: the browser's
WebCryptoAPI (crypto.subtle) derives the AES-256 key withPBKDF2-SHA256(600 000 iterations, 16-byte salt), then encrypts the private key underAES-256-GCMwith a fresh 12-byte nonce. The on-disk format is identical topkg/keystore(Go) so the CLI and browser can swap keystores freely. - Address derivation: the QSDM address is
hex(sha256(public_key)). Same shape as the validator-sidepkg/walletderivation. - Bounded network surface: the Generate / Open / Sign
tabs only fetch the three static files
(
wallet.wasm,wasm_exec.js,wallet.js). They never POST the passphrase, the private key, the public key, or even the address. The Check balance tab is the one exception — it sends a single read-onlyGETtoapi.qsdm.techwith the address in the query string, and only after you click the button. Confirm in DevTools → Network. - WASM build version: loading…
Or do it from the CLI
Identical keystore format, but offline. Useful for cold-storage flows where
you don't want even a static webpage in the trust chain. The mining step
uses qsdmminer-console --protocol=v2 against the live
NVIDIA-locked mainnet; the legacy CPU qsdmminer binary is no
longer a public release artefact (mainnet rejects its v1 proofs at
consensus — see
MINER_QUICKSTART).
# Build once
git clone https://github.com/blackbeardONE/QSDM
cd QSDM/QSDM/source
go build -o qsdmcli ./cmd/qsdmcli
go build -o qsdmminer-console ./cmd/qsdmminer-console
# Wallet: generate (passphrase prompted, address printed to stdout)
./qsdmcli wallet new --out ~/.qsdm/wallet.json
ADDR=$(./qsdmcli wallet show | awk '/^address/{print $2}')
# Mining (v2): generate the HMAC key, enroll on-chain (10 CELL bond),
# then start the live miner against the mainnet validator.
./qsdmminer-console --gen-hmac-key=$HOME/.qsdm/hmac.key
./qsdmcli enroll --sender=$ADDR \
--node-id=rig-77 \
--gpu-uuid=$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -1) \
--hmac-key=$(cat $HOME/.qsdm/hmac.key) \
--nonce=<your-account-nonce>
./qsdmminer-console --protocol=v2 \
--validator=https://api.qsdm.tech \
--address=$ADDR \
--hmac-key-path=$HOME/.qsdm/hmac.key \
--node-id=rig-77 \
--gpu-uuid=$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -1) \
--gpu-arch=ada