Cada transacció de Bitcoin conté una o més signatures digitals. Aquestes signatures autoritzen la despesa de fons, però també poden revelar indirectament informació sobre com o “qui” les ha generat.
Comencem amb una breu descripció 😉
El wallet fingerprinting és la pràctica d’identificar quin moneder ha creat una transacció concreta. Les software wallets ja han estat relativament estudiats en aquest àmbit: es diferencien en com seleccionen UTXOs, ordenen inputs i outputs, estimen comissions, etc. D’altra banda, els hardware wallets han rebut gairebé cap atenció, principalment perquè es considera que tots són iguals: dispositius aïllats de signatura que simplement produeixen una signatura determinista i res més.
Doncs bé, aquesta suposició resulta ser només parcialment certa.
Què hi ha realment dins d’una signatura?
Per entendre el fingerprinting en aquests dispositius, cal entendre què conté una signatura de Bitcoin i com es codifica.
ECDSA (Legacy i SegWit)
Les signatures ECDSA produeixen un parell de valors . El valor es deriva d’un nonce aleatori : concretament, .
El valor $s$ codifica l’autorització real utilitzant la clau privada: .
Aquests valors es codifiquen en format DER, que té una peculiaritat: si o comença amb un byte 0x80 o superior, cal afegir un byte de padding 0x00 per evitar que el valor s’interpreti com a negatiu (DER utilitza complement a dos). Això fa que una signatura pugui tenir una mida d’entre 70 i 73 bytes.
Després de BIP-62, el valor sempre es normalitza a la meitat inferior de la corba, limitant les signatures a 72 bytes. Però continua sent variable: aproximadament el 50% de les vegades, comença amb un byte alt i necessita aquest 0x00 extra.
Schnorr (Taproot)
Les signatures Schnorr sempre ocupen exactament 64 bytes, 32 per a la coordenada del punt nonce , i 32 per a . Sense codificació DER, sense longitud variable, sense mal·leabilitat.
Els vectors de fingerprinting
Tenint en compte l’anterior, què es pot utilitzar realment per fer fingerprinting d’un hardware wallet?
1. Low-r grinding
Alguns moneders iteren sobre nonces candidats fins que cau dins del rang baix de la corba (és a dir, que no necessita el byte 0x00 inicial). Aquest “low-r grinding” produeix signatures que sempre tenen 71 bytes en lloc dels habituals 71–72.
{% include figure.liquid path=”/assets/img/posts/hww-fp/ecdsa_len.png” alt=”Distribució de longitud de signatures ECDSA al llarg del temps” caption=”Longitud de signatures ECDSA al llarg del temps. El canvi cap a signatures de 71 bytes al voltant d’octubre de 2018 marca l’adopció del low-r grinding a Bitcoin Core v0.17.0. Font: mainnet.observer” class=”img-fluid w-75 d-block mx-auto rounded z-depth-1″ zoomable=true loading=”lazy” %}
La lògica de fingerprinting aquí és asimètrica:
- Una signatura de 72 bytes implica que el moneder no implementa low-r grinding.
- Una signatura de 71 bytes no ho prova — podria ser simplement un nonce afortunat.
Per tant… és un fingerprint probabilístic.
2. Tipus de SIGHASH
Cada signatura ECDSA acaba amb un byte que indica el tipus de SIGHASH, que defineix quines parts de la transacció cobreix la signatura.
Si una transacció utilitza qualsevol tipus de SIGHASH diferent de ALL, es redueix immediatament el conjunt de moneders possibles, ja que la majoria de hardware wallets només suporten SIGHASH_ALL.
3. Determinisme del nonce (RFC 6979)
RFC 6979 defineix una manera de generar el nonce de forma determinista a partir de la clau privada i el missatge, en lloc de fer-ho aleatòriament. Això significa que signar el mateix PSBT dues vegades amb la mateixa clau hauria de produir signatures idèntiques.
En teoria, això es podria utilitzar per fingerprinting: només cal signar la mateixa transacció dues vegades i comparar. Si les signatures són iguals, el moneder utilitza RFC 6979. Però a la pràctica, això només es pot detectar en un entorn de laboratori, ja que no es poden emetre dues transaccions conflictives a la xarxa.
Durant els nostres experiments, vam observar que alguns moneders que implementaven RFC 6979 produïen signatures diferents. Vam concloure que això estava relacionat amb la tècnica de low-R grinding i el nombre d’iteracions de RFC 6979 que realitzaven per obtenir un valor baix de .
Construint un entorn de proves
Un dels problemes pràctics d’aquesta recerca va ser que alguns dels moneders que volíem provar només funcionen a la mainnet de Bitcoin. Així que vam construir la nostra pròpia mainnet: una mainnet paral·lela que comparteix el mateix bloc gènesi que la xarxa real, però que s’executa de manera completament aïllada. Pots veure com replicar-la aquí 🙂
Tot i que aquest entorn no és necessari per a la creació i observació de signatures, el necessitàvem per verificar que signatures generades amb diferents sighashes eren vàlides a mainnet.
En qualsevol cas, tens tot el setup disponible a BTC-Labnet.
Resultats
Vam provar deu dispositius, tots inicialitzats amb la mateixa llavor BIP-39, tots connectats a Sparrow Wallet (o a la seva aplicació oficial quan no era compatible amb Sparrow). Per a cada moneder, vam signar el mateix PSBT múltiples vegades i vam observar les signatures.
Els resultats es van agrupar en tres categories:
| Grup | Comportament |
|---|---|
| RFC 6979, sense low-r | Signatures deterministes, 71–72 bytes |
| RFC 6979 + low-r grinding | Deterministes, sempre 71 bytes |
| Anti-exfil, sense low-r | No deterministes per disseny, 71–72 bytes |
Per si no coneixes l’anti-exfil.
Moneders com BitBox02 i Jade introdueixen deliberadament aleatorietat externa en la generació del nonce per prevenir atacs de canal encobert (com Dark Skippy, del qual ja n’he parlat abans). Això fa que les seves signatures siguin no deterministes i, per tant, distingibles de la resta.
Pel que fa al suport de SIGHASH, el panorama és clar. La majoria de moneders rebutgen signar qualsevol cosa que no sigui SIGHASH_ALL. Només Ledger Nano S+ i Keystone 3 Pro accepten tota la gamma de tipus SIGHASH, cosa que els fa immediatament identificables quan aquests apareixen a la pràctica.
Aquí tens el resum:
| Wallet | Low-r | NONE | SINGLE | ANYONECANPAY variants | Cluster |
|---|---|---|---|---|---|
| Ledger Nano S Plus (Bitcoin App 2.3.0) | ✗ | ✓ | ✓ | ✓ | A |
| BitBox02 (Multi 9.21.0) | ✗ | ✗ | ✗ | ✗ | B |
| Foundation Passport (2.3.5) | ✗ | ✗ | ✗ | ✗ | B |
| Trezor Model T Safe 3 (2.8.7) | ✗ | ✗ | ✗ | ✗ | B |
| Trezor Model T Safe 5 (2.8.7) | ✗ | ✗ | ✗ | ✗ | B |
| Coldcard Mk4 (5.2.0) | ✓ | ✗ | ✗ | ✗ | C |
| Blockstream Jade (1.0.35) | ✓ | ✗ | ✗ | ✗ | C |
| KeepKey (7.9.1) | ✗ | ✗ | ✗ | ✗ | B |
| Keystone 3 Pro (BTC 1.1.4) | ✗ | ✓ | ✓ | ✓ | A |
| SeedSigner (0.7.0) | ✓ | ✗ | ✗ | ✗ | C |
Aleshores, són fingerprintables o no?
Els hardware wallets són, en general, molt més difícils de fingerprintar que els software wallets.
La principal dificultat és determinar si una signatura ha estat produïda per un hardware wallet o per un de software, cosa que és pràcticament impossible sense informació addicional. Fins i tot si saps que una transacció ha estat signada amb un hardware wallet, potser pots assignar-la a un dels tres grups identificats. Tanmateix, no hi ha cap manera fiable de distingir entre dispositius individuals dins del mateix grup.
Per tant, podem concloure que identificar individualment un hardware wallet a partir d’una signatura és essencialment inviable.