The quick way: open the certificate
Open the certificate link (it looks like verifiedwallet.io/cert?id=VW-XXXX-XXXX). Your browser then checks two things, on your device:
- Wallet signature. The wallet's own signature over the request message, checked against the certified address (EIP-191 for EVM, Ed25519 for Solana, BIP-137 or BIP-322 for Bitcoin, TIP-191 for Tron).
- Attester signature. VerifiedWallet's ES256 counter-signature over the certificate's data, checked against our public key at /api/attester.
Both show a tick when valid. The page also shows whether the certificate has been revoked. Revocation is kept in our register, separately from the signed data, so a revoked certificate's signatures still check out but the page says clearly that it's revoked.
Looking a wallet up
On Verify a wallet, paste an address or certificate ID to see every certificate issued for it.
Checking without trusting us
The certificate's raw data is public at https://verifiedwallet.io/api/cert/<ID>. It has a core (the signed data: address, chain, tier, the exact wallet message and signature, dates and any identity or AML results) and an attestation (our signature).
1. The wallet signature
Take core.walletSignature.message, core.walletSignature.signature and core.wallet and check them with any standard tool:
- EVM: Etherscan's Verify Signature, or
verifyMessagein ethers.js or viem. - Bitcoin: Sparrow's Sign/Verify Message, Electrum's Verify message (classic BIP-137 signatures), or any BIP-322 verifier.
- Solana: any Ed25519 library, such as
tweetnacl: the signature is base58, over the message's UTF-8 bytes, with the address as the public key. - Tron: TronWeb's
await tronWeb.trx.verifyMessageV2(message, signature)returns the signing address.
Also read the message itself: it names VerifiedWallet, the address and the tier, plus a one-time nonce and timestamp.
2. Our counter-signature
The attestation is ECDSA P-256 with SHA-256 (ES256) over the core as JSON with its keys sorted alphabetically at every level and no extra spaces. This runs in a browser console or Node 20+:
const id = "VW-XXXX-XXXX"; // the certificate to check
const cert = await (await fetch(`https://verifiedwallet.io/api/cert/${id}`)).json();
const { publicKey } = await (await fetch("https://verifiedwallet.io/api/attester")).json();
const sortKeys = (v) => Array.isArray(v) ? v.map(sortKeys)
: v && typeof v === "object" ? Object.fromEntries(Object.keys(v).sort().map((k) => [k, sortKeys(v[k])])) : v;
const key = await crypto.subtle.importKey("jwk", publicKey, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
const sig = Uint8Array.from(atob(cert.attestation.sig.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
const ok = await crypto.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, key, sig,
new TextEncoder().encode(JSON.stringify(sortKeys(cert.core))));
console.log(ok ? "Attester signature valid" : "INVALID");
If both signatures are valid, the certificate is genuine: the wallet signed that message, and we issued that exact certificate. Change a single character of the certificate and the checks fail.
Sign once with your wallet: free, no transaction. We counter-sign it and give you a link anyone can verify. From $1.
More guides
How to prove you own a Bitcoin address
Sign a message with the address's key: free, instant, nothing on the blockchain.
How to sign a message with a Bitcoin wallet
Step by step in Xverse, Electrum, Sparrow, Trezor, Ledger and Bitcoin Core.
BIP-322 vs BIP-137: Bitcoin message signing explained
Why there are two formats, which wallets use which, and why Taproot needs BIP-322.
How to prove you own an Ethereum wallet
One signed message, no gas, and it covers every EVM network at once.
Questions
What if VerifiedWallet disappeared?
The proof would still stand. The wallet signature checks against the address with any standard tool, and our counter-signature checks against our published public key. Keep a copy of the certificate data and key if you want an offline record.
Can a certificate be faked?
Not without the wallet's private key and our signing key. Editing any part of a certificate breaks both signatures.
What does revoked mean?
We've marked the certificate as no longer valid in our register (for example if it was issued in error). Its original signatures still check out, but the certificate page and register show it as revoked.