You do not need to own a hardware wallet to do this. Every check below runs on your ordinary computer, and each one mirrors a decision you will face during a real setup: is this download genuine, did this device really generate my phrase, and what exactly does a passphrase change? Doing them first means the real setup holds no surprises.
You need Python 3 and one library. macOS and Linux already have Python;
on Windows install it from python.org with “Add python.exe to
PATH” ticked. Then run pip install cryptography once and check with
python3 -c "import cryptography; print(cryptography.__version__)". The practice
phrase used throughout is the BIP-39 standard’s public test phrase, so your output will
match this page — never type a real recovery phrase into a computer.
What is a Hardware Wallet?
A hardware wallet is a small, dedicated device designed for one purpose: securely storing your cryptocurrency private keys offline. When you need to sign a transaction, the hardware wallet does the cryptographic signing internally and sends only the signed transaction out — your private key never leaves the device.
Popular hardware wallet brands include Ledger and Trezor. This guide covers the general setup process common to most devices without endorsing any specific brand.
Before You Start: Safety Checks
Never buy a hardware wallet from a third-party marketplace, eBay, or unknown reseller. Tampered devices with pre-generated seed phrases have been used to steal funds. Buy directly from the manufacturer's website or authorized retailers only.
- Verify the packaging is sealed and has not been tampered with
- Check the manufacturer's website for instructions on verifying device authenticity
- The device should arrive with NO pre-configured seed phrase. If it comes with a seed phrase card already filled in, the device has been compromised — do not use it
Step 1: Install the Companion Software
Hardware wallets require companion software on your computer or phone to manage accounts and initiate transactions. Download this software only from the manufacturer's official website.
- Verify the download URL carefully — phishing sites mimicking official download pages are common
- Check the software's cryptographic signature if the manufacturer provides one
- Keep the companion software updated to receive security patches
Step 2: Initialize the Device
When you connect and power on a new hardware wallet for the first time:
- The device will prompt you to create a new wallet (or restore from an existing seed phrase)
- Choose "Create new wallet" for a fresh setup
- Set a PIN code — this protects the device from unauthorized physical access. Choose something that is not easily guessed. Most devices lock or wipe after several failed PIN attempts.
Step 3: Record Your Seed Phrase
The device will generate and display a seed phrase (typically 12 or 24 words). This is the master backup of all your keys.
Write down every word, in exact order, on the paper card that came with your device. Double-check each word. A single wrong word can make your backup useless.
- Write it on paper or stamp it on metal — never type it into a computer, phone, or any digital device
- Never photograph it — photos sync to cloud services and can be accessed by malware
- Never store it in a password manager, email draft, or note-taking app
- Store it in a secure physical location — a safe, lockbox, or bank safety deposit box
- Consider making a second copy stored in a different physical location for disaster recovery
Step 4: Verify the Seed Phrase
Most hardware wallets will ask you to confirm your seed phrase by selecting words in order on the device screen. This is not optional — it verifies you recorded it correctly.
Take this step seriously. If your device is ever lost, stolen, or damaged, this seed phrase is the only way to recover your funds.
Step 5: Firmware Updates
After initial setup, check for firmware updates in the companion software. Firmware updates patch security vulnerabilities and add features. Always update from the official companion app — never from a link in an email or message.
Step 6: Verify Addresses on Device
When receiving funds, your hardware wallet can display the receiving address on its own screen. Always verify that the address shown on the device matches what is shown on your computer. Malware can alter displayed addresses on your computer screen, but it cannot alter what the hardware wallet shows.
Common Setup Mistakes
- Storing the seed phrase digitally — screenshots, notes apps, and cloud storage are all vulnerable to compromise
- Skipping the verification step — an incorrectly recorded seed phrase is worthless when you need it
- Using a simple PIN — 1234, 0000, or your birthdate are trivially guessable
- Buying from unofficial sellers — tampered devices are a real and documented attack vector
- Not updating firmware — known vulnerabilities remain exploitable until patched
- Trusting only the computer screen — always confirm transaction details on the hardware wallet's own display
Now Rehearse the Four Decisions That Actually Protect You
A hardware wallet is only as good as the four judgements made around it: whether the software you install is genuine, whether the device generated your phrase or somebody else did, what a passphrase really creates, and what a PIN is worth. Each one below is a small program you run on your own computer, so you meet the failure now, with nothing at stake, instead of during a real setup. Every figure printed came from running these files.
Go: open a terminal in a folder you can write to, for example
cd ~/Desktop (Windows: cd %USERPROFILE%\Desktop).
Do: save this as checksum.py and run
python3 checksum.py. It builds a stand-in installer, records the checksum a
vendor would publish, then alters exactly one byte of it — the signature of a hostile
mirror or a modified download.
import hashlib
def sha256_of(path):
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
h.update(chunk)
return h.hexdigest()
genuine = b"OFFICIAL WALLET INSTALLER v2.4\n" + bytes(4096)
open("wallet-setup.bin", "wb").write(genuine)
published = sha256_of("wallet-setup.bin")
print("checksum published by the vendor :", published)
tampered = bytearray(genuine)
tampered[2000] = 1
open("wallet-setup.bin", "wb").write(tampered)
downloaded = sha256_of("wallet-setup.bin")
print("checksum of the file you got :", downloaded)
print("bytes different out of 4127 :", sum(a != b for a, b in zip(genuine, tampered)))
print("safe to run :", downloaded == published)
You should see: two checksums with nothing in common, from files that differ by a single byte:
checksum published by the vendor : 5aec94a2313fc8825545d7efd4b831e95fc8f2cf54a1f46841c91c8ad4d92402
checksum of the file you got : db0f36469b28e4d1f8b9df94f9b9ffd18cd986da7eca09ffec1e90170f334791
bytes different out of 4127 : 1
safe to run : False
That total change from one altered byte is what makes checksums useful: a tampered installer cannot be made to keep the published number. On a real download you compare against the checksum on the vendor’s own site — typed in by hand from your own bookmark, never followed from the same page that offered the file, because an attacker who controls the download page also controls the checksum printed on it.
If not: PermissionError means the folder is not writable
— move to your Desktop or home folder. If bytes different prints something
other than 1, the index 2000 was changed; any position inside the file works,
but the count should be one.
Go: same folder. This is the single most common way people lose money on a hardware wallet, and it happens before the device is even plugged in.
Do: save this as preseeded.py and run it. Imagine a card in
the packaging with a recovery phrase helpfully pre-printed on it, and a seller who
photographed that card before shipping.
import hashlib, unicodedata
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
def first_address(phrase, passphrase=""):
seed = hashlib.pbkdf2_hmac("sha512",
unicodedata.normalize("NFKD", phrase).encode(),
("mnemonic" + passphrase).encode(), 2048)
pub = Ed25519PrivateKey.from_private_bytes(seed[:32]).public_key().public_bytes(
serialization.Encoding.Raw, serialization.PublicFormat.Raw)
return hashlib.sha256(pub).hexdigest()[:40]
card = " ".join(["abandon"] * 11 + ["about"])
print("you set the device up with the card in the box:")
print(" your first receiving address :", first_address(card))
print("the seller photographed that card before shipping:")
print(" their computed address :", first_address(card))
print()
print("same address, so the same coins:", first_address(card) == first_address(card))
You should see: one address, reached twice, by two different people:
you set the device up with the card in the box:
your first receiving address : ed0f8784166e0abfff51a9aff9ba259d8c028ed3
the seller photographed that card before shipping:
their computed address : ed0f8784166e0abfff51a9aff9ba259d8c028ed3
same address, so the same coins: True
No hacking took place. The phrase is the wallet, so whoever else has read it is a joint owner who can empty the account at a time of their choosing — often months later, once you have moved in serious funds. A genuine device never gives you a phrase: it makes you write down words it generates on its own screen, in front of you. A pre-printed card, a phrase in an email, or a setup site asking you to type words in means the device is compromised. Buy from the manufacturer directly, and if a phrase arrives with the hardware, do not use it — not even “just to test”.
If not: ModuleNotFoundError: No module named 'cryptography'
means the library is missing — run pip install cryptography. A different
address than the one above means the phrase string differs; it is eleven
abandons and then about, single-spaced.
Go: same folder. A passphrase is often called the “25th word”, which undersells what it does.
Do: save this as passphrase.py and run it. Same twelve
words every time; only the passphrase changes.
import hashlib, unicodedata
def wallet_id(phrase, passphrase=""):
seed = hashlib.pbkdf2_hmac("sha512",
unicodedata.normalize("NFKD", phrase).encode(),
("mnemonic" + passphrase).encode(), 2048)
return hashlib.sha256(seed).hexdigest()[:8].upper()
phrase = " ".join(["abandon"] * 11 + ["about"])
print("no passphrase :", wallet_id(phrase))
print("passphrase 'holiday' :", wallet_id(phrase, "holiday"))
print("passphrase 'Holiday' :", wallet_id(phrase, "Holiday"))
print("passphrase 'holiday ':", wallet_id(phrase, "holiday "))
You should see: four completely unrelated wallets from one recovery phrase:
no passphrase : 62A772F8
passphrase 'holiday' : 8C650F1D
passphrase 'Holiday' : 2AB35E62
passphrase 'holiday ': 11C59A92
This is the real feature: your twelve words open the wallet everyone expects, while the words plus a passphrase open a different one that leaves no trace on the device. Someone who forces you to unlock the wallet sees a genuine, working, modestly funded account. Nothing on the device reveals that another exists.
If not: if any two lines match, the passphrase argument is not reaching
the salt — check the ("mnemonic" + passphrase) line. If every line is
identical, you are calling wallet_id(phrase) four times.
Go: same folder, same output as step 3 — read it again before you continue.
Do: compare the last three lines. holiday,
Holiday and holiday with a trailing space produced three unrelated
wallets. To feel it, change your own copy to a passphrase you might genuinely pick, then run
it once more with one character altered.
python3 passphrase.py
You should see: that no line in that output is ever an error. A wrong passphrase does not fail — it silently opens a different, empty wallet, exactly as a mistyped recovery phrase does.
So the passphrase is a second secret with none of the recovery phrase’s safety net: no word list, no checksum, no wallet warning you that it is wrong. Capital letters, spaces and accents all count. If you use one, back it up as carefully as the phrase and in a different place, and prove it works by restoring on a spare device before you fund it. People have lost everything to a passphrase they were certain they would remember.
If not: if you change the passphrase and the wallet id does not change, the edit was made to the wrong string — the passphrase is the second argument, and the phrase itself must stay untouched.
Go: same folder. The PIN protects the device if it is physically stolen — and only then.
Do: save this as pin.py and run it. It assumes a machine
pressing the buttons at five guesses per second.
def seconds_to_words(s):
for unit, n in (("years", 31557600), ("days", 86400), ("hours", 3600), ("minutes", 60)):
if s >= n:
return f"{s / n:,.1f} {unit}"
return f"{s:.0f} seconds"
RATE = 5 # guesses per second by a machine pressing the buttons
for digits in (4, 6, 8):
combos = 10 ** digits
print(f"{digits}-digit PIN: {combos:>9,} combinations, "
f"average crack time {seconds_to_words(combos / 2 / RATE)}")
print()
print("with a device that wipes itself after 3 wrong PINs:")
print(f" 4-digit PIN: attacker gets 3 of 10,000 guesses = "
f"{3 / 10000:.2%} chance before the secret is erased")
You should see: the case for both a longer PIN and an attempt limit:
4-digit PIN: 10,000 combinations, average crack time 16.7 minutes
6-digit PIN: 1,000,000 combinations, average crack time 1.2 days
8-digit PIN: 100,000,000 combinations, average crack time 115.7 days
with a device that wipes itself after 3 wrong PINs:
4-digit PIN: attacker gets 3 of 10,000 guesses = 0.03% chance before the secret is erased
Sixteen minutes is how long a four-digit PIN survives a patient thief with a cheap button pusher — if nothing stops them trying. The wipe-after-N-attempts rule, which every reputable device implements, is what converts that into a 0.03% chance. Both matter: set the longest PIN you will reliably remember, and never disable the attempt limit. And note what the PIN does not do — it protects the device, not the phrase. Anyone who reads your written phrase does not need the device at all.
If not: ValueError: Invalid format specifier means the
:>9, inside the f-string was mistyped — it is a colon, a greater-than
sign, a nine and a comma. If the times look wildly different, check that RATE
is 5 and that the division is combos / 2 / RATE.
Without scrolling up: your hardware wallet is stolen from your home. You had a 6-digit PIN and a passphrase, and your recovery phrase is in a bank box across town. How exposed are you, and what is the first thing you should do? Answer: barely exposed. The thief faces the PIN with an attempt limit behind it, and even a device that somehow unlocked would show only the passphrase-less wallet — the funds behind the passphrase are not on the device at all. The first thing to do is not to panic but to move the funds: restore your phrase and passphrase onto a new device and send everything to freshly derived addresses, because you can no longer be certain nobody has watched you enter that PIN. Ordering a replacement comes second.
Now do it without the page: take the wallet_id function and
work out how many distinct wallets your single recovery phrase can open if you allow yourself
passphrases of up to four lower-case letters. Then ask the harder question the number raises:
if you cannot recall exactly which of those you used, which wallet do you own? That
arithmetic is the strongest argument there is for writing the passphrase down.
Summary
- Buy only from official sources and verify the device is untampered
- Set a strong PIN and generate a new seed phrase on the device
- Record the seed phrase on paper or metal — never digitally
- Verify the seed phrase when prompted and store it securely offline
- Keep firmware updated and always verify addresses on the device screen
With your device set up, learn more about seed phrases and private key management in the next tutorial.