Trezor: Guia Prático de Scripts para Recuperação de Acesso (BIP39)
Aviso legal e ético: este artigo trata exclusivamente da recuperação de acesso a uma carteira sua, cuja seed, PIN ou passphrase você perdeu ou esqueceu parcialmente. Executar qualquer script contra credenciais de terceiros é crime na maioria das jurisdições. Se os fundos não são seus, pare aqui.
1. Antes do código: o que exatamente se perdeu?
Um usuário de Trezor pode perder três coisas diferentes, e cada uma exige uma abordagem distinta:
| O que se perdeu | Onde é validado | Recuperação por script? |
| --- | --- | --- |
| PIN | No próprio dispositivo | Sim, mas apenas via reset com a seed |
| Passphrase (BIP39) | Off-chain, deriva uma carteira oculta | Sim, com ataque de dicionário |
| Seed (12/24 palavras) | Off-chain, define a carteira raiz | Parcialmente, se faltarem poucas palavras |
O ponto central é entender que a seed e a passphrase nunca passam pelo servidor da Trezor. Toda a matemática acontece localmente, o que significa que um script em Python pode validar hipóteses sem nunca tocar no dispositivo.
2. Fundamentos técnicos que o script precisa respeitar
2.1 BIP39 e o checksum
A seed é uma frase de 12, 18 ou 24 palavras retiradas de uma lista fixa de 2048 palavras (wordlist inglesa, na maioria dos casos). A última palavra carrega um checksum derivado de SHA-256, o que permite descartar imediatamente qualquer combinação inválida. Em uma frase de 12 palavras, o checksum ocupa 4 bits; em 24 palavras, 8 bits.
2.2 Da frase à chave mestra
O padrão usa PBKDF2-HMAC-SHA512 com 2048 iterações:
- Salt: a string
"mnemonic"concatenada com a passphrase do usuário - Saída: 64 bytes de seed mestra
Esse custo de 2048 iterações é o que torna ataques de dicionário lentos — e é exatamente por isso que a passphrase é uma camada de segurança tão eficaz quanto a própria seed.
2.3 Derivação de endereços
Da seed mestra, o BIP32 gera chaves filhas seguindo caminhos hierárquicos (BIP44, BIP49, BIP84 ou BIP86). O script precisa comparar o endereço resultante com um endereço conhecido da carteira original — por exemplo, o primeiro endereço de recebimento em m/84'/0'/0'/0/0.
3. Preparando o ambiente
Trabalhe em uma máquina offline, idealmente com um live USB (Tails ou similar) e sem rede. Instale as dependências:
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate

pip install mnemonic bip_utils trezorlib
mnemonic— validação de frases e wordlist oficialbip_utils— derivação BIP32/44/49/84/86 e geração de endereçostrezorlib— comunicação opcional com o dispositivo para conferência final
4. Etapa 1 — Validando a frase semente
Antes de qualquer força bruta, confirme se a frase que você lembra é, ao menos, estruturalmente válida:
from mnemonic import Mnemonic
mnemo = Mnemonic("english")
frase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
print(mnemo.check(frase)) # True se o checksum bater
print(mnemo.to_seed(frase)) # bytes da seed mestra
Se o checksum falhar e você tem certeza de todas as palavras, o problema está na ordem ou no idioma da wordlist (existem wordlists em português, espanhol, francês e outras).
5. Etapa 2 — Uma única palavra desconhecida
Esse é o cenário mais comum e o mais trivial: 2048 combinações, resolvido em menos de um segundo.
from mnemonic import Mnemonic
from bip_utils import Bip39SeedGenerator, Bip84, Bip84Coins, Bip44Changes
mnemo = Mnemonic("english")
modelo = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon {p} about"
alvo = "bc1q..." # primeiro endereço conhecido da sua carteira
for palavra in mnemo.wordlist:
frase = modelo.format(p=palavra)
if not mnemo.check(frase):
continue
seed = Bip39SeedGenerator(frase).Generate("")
conta = Bip84.FromSeed(seed, Bip84Coins.BITCOIN).Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(0)

if conta.PublicKey().ToAddress() == alvo:
print("Encontrado:", frase)
break
6. Etapa 3 — Duas ou três palavras desconhecidas
A complexidade cresce de forma quadrática:
| Palavras desconhecidas | Combinações |
| --- | --- |
| 1 | 2.048 |
| 2 | ~4,2 milhões |
| 3 | ~8,6 bilhões |
Com duas palavras o problema ainda é tratável, desde que você use o checksum como filtro (ele elimina cerca de 90% a 97% dos candidatos antes de qualquer derivação cara) e paralelize com multiprocessing. Evite derivar endereços para cada candidato válido: primeiro filtre pelo checksum, depois teste apenas o primeiro endereço de recebimento.
Com três ou mais palavras desconhecidas em posições arbitrárias, a recuperação deixa de ser um problema de software e passa a ser um problema de orçamento energético — na prática, inviável para qualquer pessoa física.
7. Etapa 4 — Passphrase esquecida (ataque de dicionário)
Aqui o gargalo é o PBKDF2. Cada tentativa custa, em Python puro, entre 30 e 200 ms por conta do multiprocessing e do email/hashlib. Multiplique por 100 mil candidatos e você terá dias de execução.
Estratégia recomendada:
- Monte uma wordlist pequena e cirúrgica (variações de senhas que você realmente usaria).
- Implemente variações algorítmicas: maiúsculas iniciais, sufixos numéricos, substituições previsíveis.
- Use
concurrent.futures.ProcessPoolExecutorpara distribuir os núcleos. - Lembre-se: a passphrase diferencia maiúsculas de minúsculas e espaços contam.
"minha frase"é diferente de"MinhaFrase".
from concurrent.futures import ProcessPoolExecutor
def testa(passphrase):
seed = Bip39SeedGenerator(frase_base).Generate(passphrase)
# ... derivar e comparar com o endereço alvo
return passphrase if match else None
with ProcessPoolExecutor() as ex:
for resultado in ex.map(testa, candidatos):
if resultado:

print("Passphrase encontrada:", resultado)
break
8. Etapa 5 — Conferindo no dispositivo, sem expor a seed
Nunca digite uma seed candidata em um site. Use o próprio Trezor:
- O Trezor Suite permite fazer uma recuperação de teste (dry-run) e comparar o primeiro endereço exibido com o endereço conhecido.
- Via
trezorlib, você pode abrir uma sessão e usarRecoveryDeviceno modo avançado, inserindo as palavras diretamente no dispositivo — elas nunca tocam o teclado do computador.
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
# Exemplo conceitual: sempre valide no hardware antes de mover fundos
transporte = get_transport()
cliente = TrezorClient(transporte)
Depois de recuperar o acesso, mova os fundos para uma nova seed gerada do zero. Se a seed antiga foi exposta a um computador, considere-a comprometida.
9. Segurança operacional
- Rode tudo em máquina offline e descartável.
- Nunca salve a seed, a passphrase ou os resultados em arquivos sincronizados com a nuvem.
- Desconecte impressoras, câmeras e serviços de indexação antes de exibir qualquer frase na tela.
- Destrua o ambiente (live USB) ao final.
- Desconfie de qualquer "serviço de recuperação" que peça sua seed — é golpe em 100% dos casos.
10. Limites e alternativas
Se o script não for suficiente:
- btcrecover — ferramenta madura e de código aberto para recuperação de seeds e senhas, com suporte a múltiplas moedas.
- Suporte oficial da Trezor — não recupera seeds, mas orienta sobre Shamir Backup (SLIP-39) e recuperação avançada.
- Backup Shamir — se você usou o Model T com SLIP-39, a recuperação exige um número mínimo de shares, e a matemática é diferente do BIP39 padrão.
Conclusão
Escrever um script de recuperação para Trezor é, no fundo, um exercício de entender BIP39, PBKDF2 e BIP32. O código em si é curto; o que consome tempo é a organização correta dos candidatos e a disciplina de segurança durante a execução. Use esse conhecimento apenas na sua própria carteira — e, principalmente, use-o para perceber por que um backup bem feito vale mais do que qualquer script de resgate.