← All posts

How to verify your hardware wallet’s addresses — ColdCard, Ledger, Trezor — without trusting the vendor’s code

Every hardware wallet vendor gives the same advice, and in our opinion it is excellent. Before you receive coins, confirm the address on the device's own screen. Keep following it.

However, notice what it checks. The device defends against malware on your online computer, particularly against swapping the address from your wallet app. Few consider that the device itself might have an issue at generation time. It may be introduced during a routine update, a new derivation standard implementation, or in a number of other, well-meaning ways. We have a page that walks through the failure modes a self-custody setup can have, the derivation path among them, and it is well worth any bitcoiner's time. See the verification layer page.

DEVICE 1 APPLIES THE STANDARDS

its own way

DERIVES OUTPUTS

its own math

CHECKS ITS WORK

same code

REPORTS GREEN

self-verified

RESTORE DAY

Will it?

SAME CODE

START TO FINISH

THE REPORTS VOUCH FOR THEMSELVES

In other words, if the derivation logic is wrong or outdated, the screen will render the wrong address as confidently as the correct one. Checking the device against the vendor's companion app wouldn't help either: two programs from the same source agreeing is the proverbial witness vouching for itself.

Luckily, there is a check that can help. Export the extended public key, together with the derivation path and script type (the account's public data). Then re-derive the addresses with software that shares zero code with the original device, and compare the two lists. If your wallet exports a full output descriptor, even better, use that. It has the key, the path and the policy in one string, and it is the better thing to keep. If the lists agree, then the derivation has been confirmed by an independent implementation, not just the vendor's. Clean.

One should be aware of a privacy detail, though. The extended public key is privacy-sensitive. Anyone who obtains it can compute every address in the account, past and future, and watch them on-chain. So handle the exported file accordingly. It's generally better to delete it from any online machine when the check is done, and run the re-derivation offline if possible.

Step one: get the public data out of the device.

Coldcard writes it to a microSD card, so nothing needs to be plugged into a computer. This is a good thing.

Trezor would hand it over through its desktop app, as text and as a QR code.

In case of a Ledger device you will be retrieving it from an advanced panel. Also its app expects a network connection. So export once, move the file to your offline machine, and do everything after that step off the network.

Look at the first four characters of what you exported. The most common are xpub. A native SegWit account key usually begins zpub, and a nested SegWit key ypub. All three are ok. Some tools accept a zpub directly, others want it converted to plain xpub form with the path supplied separately. The conversion changes only the version bytes. Depth, parent fingerprint, child number, chain code and public key all survive it. In any case, keep the verified path and policy beside the key.

The standard account paths are m/44'/0'/0' for legacy addresses beginning with 1, m/49'/0'/0' for nested SegWit beginning with 3, m/84'/0'/0' for native SegWit beginning with bc1q, and m/86'/0'/0' for Taproot beginning with bc1p. Receive addresses extend the account path with /0/0, /0/1, /0/2 and so on. Change addresses extend it with /1/0, /1/1. An account-level key plus its policy and path is everything the independent side needs. A descriptor is that same information in one long string.

Step two: re-derive. The tool must share no code with the original device and none with the vendor's companion app. Otherwise the comparison collapses back into the device agreeing with itself.

xpubverify, the free MIT-licensed script on the Bitcoin Witness GitHub, was written for this check. It is plain Python, standard library only, short enough to read in full before you run it. Give it the exported public key and it prints receive and change addresses. Ten and five by default, more if you ask. On the Bitcoin Witness station (see the demo in the preview section), the same check is Extended Public Key Verification. Import the key and the air-gapped machine derives the addresses and writes a timestamped Confidence Report. Since the verification tools don't touch the network, they won't show you a balance. They tell you which addresses belong to the key, not what those addresses hold.

You can rehearse the whole procedure with public test vectors. xpubverify will do this via its --self-test flag. It runs its embedded test vectors and exits.

Step three: compare, properly. Put the derived list next to the device, then read the full string. A partial visual match is not an identity check. Compare every character.

Don't stop at index 0. Confirm the first receive address, and a few more further down the list. We know it may be boring, but especially if you plan to use these addresses long term, it is well worth your time. Where your device offers an address explorer or another safe way to display one, verify at least one change address from the /1/ branch. Change addresses are where a derivation bug hides longest, since coins flow to them without you necessarily reading one. If the same key and policy produce the same full addresses at several receive and change indices, the derivation has been cross-checked by independent code. Note the fingerprint, the account path, the policy, the indices you tested and the date beside your backup records, and treat them as privacy-sensitive.

The agreement between the two confirms that the public key the device handed you derives, under standard BIP32 math and the policy you named, the addresses you tested.

THE USER

Creates the wallet, descriptors and stores private keys on device 1

THE USER’S
VERIFICATION LAYER

Re-derives on device 2. Different code, offline

HEIRS OR THIRD PARTIES

Receive a secret-free and signed Confidence Report or a Package.

SUCCESSFUL RESTORE

On day X

DIFFERENT CODE

INDEPENDENT VERIFICATION

COMPLETE REPORTS

It does not opine, nor should it, on how well the seed inside the device was generated, how safely the device stores it, or whether the signatures leak anything when you spend. Those are separate questions. Some have verification procedures of their own. Others, like the randomness behind a seed that was generated elsewhere, cannot be verified after the fact. We compiled and visualized some examples on the verification layer page. What it does help address though is one specific issue. That your receive addresses were independently verified, and ideally on an offline computer.

Bitcoin Witness. Verify your self-custody setup.