COURS DE LECTURE · 10 MINUTES

Apprenez à lire votre contrat.

Tout votre coffre tient dans une ligne de texte — celle qui est imprimée dans votre kit de récupération. Le jour où vous savez la lire, vous ne dépendez plus de PLUG, ni d'aucun logiciel, ni de personne. Ce cours vous apprend à la comprendre parfaitement — puis à la vérifier vous-même avec des outils indépendants.

1 · LE CONTRAT

Le voici en entier.

C'est un « descripteur » — la carte d'identité complète de votre coffre. Celui-ci dit : « verrou n°4, ouvrable par la clé n°4 du trousseau, pas avant le bloc 908 640 » :

wsh(and_v(v:pk(xpub6CUGRUo…Vpgp/2/4),after(908640)))

Une ligne, sept morceaux. On les lit un par un, de l'extérieur vers l'intérieur — comme des poupées russes.

wsh( … )
Le type de coffre. « Witness Script Hash » : l'adresse de dépôt est l'empreinte (le hash) du contrat, pas le contrat. Le réseau garde l'empreinte ; vous gardez le texte. Analogie : le notaire n'archive que l'empreinte digitale du testament. Sans votre photocopie, personne ne peut le reconstituer — pas même lui.

Une empreinte, ça s'écrit comment ?

Un hash (SHA-256, celui de Bitcoin) prend n'importe quelle entrée — un mot, tout le script du verrou, un film entier — et recrache toujours une sortie de taille fixe : 256 bits, écrits en hexadécimal (0-9, a-f) — soit 64 caractères, sans exception :

SHA-256("hello") =
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Changez une seule lettre — « hello » → « Hello » — et le résultat devient totalement différent, sans aucun rapport visuel avec le précédent : c'est l'effet avalanche. Exactement pour ça qu'un caractère mal recopié dans votre descripteur donne une adresse complètement autre, pas « presque la bonne » — et pour ça que le checksum (section 2) peut détecter la moindre faute.

Votre adresse bc1q… n'est pas littéralement ce hex — elle passe par un habillage supplémentaire (Bech32, qui ajoute le préfixe bc1 et son propre checksum), mais le principe est le même : SHA-256(votre script) → 32 octets → encodés en Bech32 → votre adresse de dépôt. Le hash est la vraie empreinte ; l'adresse n'en est qu'un habillage plus facile à recopier.

and_v( A , B )
« A ET B, obligatoirement. » Les deux conditions qui suivent doivent être vraies en même temps. Pas de « ou », pas d'exception, pas de procédure d'urgence. Analogie : une porte blindée à deux serrures. Une seule clé ne sert à rien.
v:pk( … )
Serrure n°1 : prouver que c'est vous. Il faut une signature valide de la clé indiquée entre parenthèses. La seule machine au monde capable de produire cette signature est votre hardware wallet. Analogie : le chèque n'est encaissable qu'avec VOTRE signature — et votre main, c'est le Ledger.
xpub6CUGRUo…Vpgp
Votre trousseau public. Une « xpub » est fabriquée à partir de votre seed, mais ne contient aucun pouvoir de signer : elle permet seulement de fabriquer des adresses et de regarder les soldes. Analogie : le catalogue de toutes vos serrures — utile pour les reconnaître dans la rue, incapable d'en ouvrir une seule. Les clés, elles, ne sortent jamais du Ledger.
/2/
L'allée n°2 du trousseau. Votre trousseau est rangé en allées : les allées 0 et 1 servent aux portefeuilles classiques (réception et monnaie rendue) ; l'allée 2 est réservée aux verrous du coffre. Aucune collision possible avec vos autres wallets. Analogie : dans le garage, l'étagère du haut c'est uniquement les cadenas du coffre.
/4
Le numéro du verrou. Chaque cycle de re-lock utilise la clé suivante : verrou n°0 → clé /2/0, n°1 → /2/1… Ici c'est le 5ᵉ verrou (on compte depuis 0). Clé neuve = adresse neuve à chaque cycle, jamais réutilisée. Analogie : un cadenas neuf à chaque fois — personne ne peut suivre la série.
after( 908640 )
Serrure n°2 : pas avant le bloc 908 640. La blockchain compte les blocs comme une horloge compte les secondes : un bloc ≈ 10 minutes, 144 par jour, 4320 ≈ 30 jours. Tant que le bloc 908 640 n'existe pas, aucun mineur au monde n'acceptera la dépense. Analogie : le coffre de banque à horlogerie — même le directeur ne peut pas ouvrir avant l'heure. L'horloge, ici, c'est la blockchain entière. 🗝 H est un simple entier, sans marqueur : H < 500 000 000 → hauteur de bloc (notre cas, toujours) ; H ≥ 500 000 000 → timestamp Unix (secondes depuis 1970). Le seuil n'est pas arbitraire — à ce rythme de blocs, on ne l'atteindra que dans des millénaires. Ce coffre n'utilise jamais le mode timestamp — mélanger les deux types dans un même script n'a aucun sens (l'un compte des blocs, l'autre des secondes).

Convertir un bloc en date (calcul de coin de table)

Regardez la hauteur actuelle sur votre dashboard ou mempool.space, puis :

(bloc_cible − bloc_actuel) × 10 min  →  ex. (908 640 − 906 480) × 10 min = 2160 blocs ≈ 15 jours

C'est approximatif (le réseau respire), mais jamais de plus de quelques heures sur un mois. Le dashboard fait ce calcul pour vous — maintenant vous savez le refaire sans lui.

2 · VÉRIFIER — NE NOUS CROYEZ PAS SUR PAROLE

Le même contrat, relu par trois témoins indépendants.

Un contrat qu'on ne peut pas contre-vérifier ne vaut rien. Le vôtre est du miniscript standard : n'importe quel outil Bitcoin sérieux sait le relire et doit retomber sur exactement la même adresse. Si trois logiciels écrits par trois équipes différentes affichent la même adresse que votre Ledger — vous pouvez dormir tranquille.

Témoin n°1 — Bitcoin Core (le juge de paix)

getdescriptorinfo ne devine rien : il faut lui donner le descripteur déjà complet — celui de votre kit de récupération, xpub + index + hauteur inclus. Il ne fait que vérifier la syntaxe et calculer une somme de contrôle : 8 caractères qui ne prouvent rien sur l'authenticité, mais qui détectent une faute de frappe — comme le dernier chiffre d'un IBAN. Recopiez le descripteur du kit à la main et changez UN seul caractère : le checksum ne colle plus, et Bitcoin Core refuse net au lieu de vous laisser déposer sur une adresse que vous ne contrôlez pas. Sur n'importe quelle machine avec Bitcoin Core :

# 1. Valider le contrat déjà en main et lui ajouter sa somme de contrôle
$ bitcoin-cli getdescriptorinfo "wsh(and_v(v:pk(votre_xpub/2/4),after(908640)))"
→ renvoie le MÊME descripteur, suivi de #checksum (8 caractères)

# 2. Recalculer l'adresse depuis ce contrat — sans PLUG
$ bitcoin-cli deriveaddresses "wsh(and_v(v:pk(votre_xpub/2/4),after(908640)))#checksum"
["bc1q…"] ← doit être IDENTIQUE à l'adresse du dashboard ET du Ledger

Ne sautez pas le #checksum à l'étape 2. deriveaddresses accepte techniquement un descripteur sans lui — il dérive alors l'adresse sans rien vérifier, même si vous avez mal recopié un caractère. C'est la présence du checksum qui déclenche le contrôle et vous fait échouer bruyamment plutôt que dériver une fausse adresse en silence.

Si l'adresse recalculée diffère d'un seul caractère, ne déposez rien.

Pourquoi le kit reste indispensable si vous le perdez : votre xpub se ré-exporte toujours du Ledger — c'est une formule mathématique fixe (BIP32), aucune information externe requise. Mais l'index et la hauteur n'ont, eux, aucun lien mathématique avec votre clé : l'index a simplement été incrémenté à chaque cycle, la hauteur a été choisie sur le moment (« bloc actuel + 4320 ») au jour du dépôt. Pire : l'adresse dépend des deux à la fois (le script contient la clé ET la hauteur ensemble) — impossible de retrouver l'un sans l'autre en scannant juste des index. Seul un brute-force conjoint (chaque index plausible × chaque hauteur dans une fenêtre de dates) pourrait un jour la reconstituer, et seulement si vous vous souvenez d'une fenêtre de dépôt assez précise, avec un nœud indexé sous la main. Sans ça, rien ne la retrouve en pratique : c'est la seule vraie raison d'être du kit imprimé.

« Mais la date du dépôt est visible sur la blockchain, non ? » La date de confirmation du dépôt, oui. La hauteur écrite dans le script, non — comme le tampon postal d'une enveloppe qui ne révèle rien de la date écrite à l'intérieur de la lettre. Pire : l'adresse est créée avant que vous y déposiez quoi que ce soit, donc même la bonne date de dépôt ne donne qu'un ordre de grandeur, pas la valeur exacte. Et personne — pas même le réseau — ne détient le script en clair tant qu'il n'a pas été révélé par une dépense : il n'y a littéralement personne à qui le demander.

« Et si je connais MA date, moi — mon propre calendrier ? » Là, c'est un vrai chemin de secours, pas une impasse — voir la procédure complète juste en dessous ↓.

Cas particulier — vous connaissez vos dates, pas le kit

Si vous avez un souvenir précis (agenda, relevé de retrait d'exchange, mémoire fiable) de quand un verrou a été créé — pas déposé, créé — vous pouvez reconstruire sa hauteur exacte avec votre propre nœud, sans le kit. Voici comment, étape par étape.

1 — Convertir la date en fenêtre de hauteurs. Cherchez sur mempool.space (ou tout explorateur) quel bloc a été miné à peu près à votre date. Prenez une marge large autour — l'étape 3 ne coûte quasiment rien de plus si la fenêtre est généreuse, alors ne lésinez pas :

# Exemple : verrou créé "vers le 3 mars 2026", marge de ±3 jours
DEBUT=904200 # hauteur estimée, 3 jours avant
FIN=904650 # hauteur estimée, 3 jours après (~432 blocs d'écart)

2 — Construire le balayage. Impossible de « sauter » des hauteurs : un seul bloc d'écart change tout le hash, donc chaque valeur de la fenêtre doit être testée. En revanche l'index, lui, accepte la vraie syntaxe de plage BIP389 (/2/* + range) — Bitcoin Core balaie les index pour vous à l'intérieur de chaque hauteur candidate :

SCAN='['
for H in $(seq $DEBUT $FIN); do
  SCAN+="{\"desc\":\"wsh(and_v(v:pk(votre_xpub/2/*),after($H)))\",\"range\":[0,20]},"
done
SCAN="${SCAN%,}]"

3 — Lancer le scan. scantxoutset parcourt l'ensemble des UTXO existants une seule fois, quel que soit le nombre de candidats fournis — c'est ce passage unique qui prend du temps (plusieurs minutes sur mainnet), pas la taille de votre fenêtre. D'où l'intérêt d'être large à l'étape 1 :

$ bitcoin-cli scantxoutset start "$SCAN"

4 — Lire le résultat. Si un candidat correspond à un vrai verrou financé, il apparaît dans unspents avec son desc complet — la hauteur et l'index exacts sont dedans. Vous venez de reconstruire votre descripteur sans le kit. Rien dans unspents ? Élargissez la fenêtre et recommencez.

Pourquoi ça reste un plan B, pas un plan A : tout repose sur la justesse de votre souvenir de date — une cadence supposée (« tous les 30 jours ») dérive dès qu'un cycle a traîné, et vous devez vous en souvenir précisément au moment où, par définition, vous avez déjà perdu vos autres repères (kit et state.json). Le kit imprimé ne rend pas cette reconstruction possible — elle l'est déjà. Il la rend certaine, sans dépendre de votre mémoire un jour de stress.

Témoin n°2 — Sparrow Wallet (l'interface graphique)

  1. Sparrow → File → New Wallet → onglet Script Policy.
  2. Collez le descripteur du kit → Sparrow affiche la liste des adresses.
  3. Comparez avec le dashboard : mêmes adresses, mêmes soldes.

Bonus : branchez le Ledger dans Sparrow — il doit reconnaître le wallet et pouvoir signer. C'est votre preuve de sortie de secours : PLUG n'est pas un passage obligé.

Témoin n°3 — un explorateur public (lecture seule)

Collez l'adresse du verrou sur mempool.space : vous voyez vos dépôts arriver et se consolider, comme tout le monde. La blockchain est publique — votre contrat s'exécute au vu de tous, sans révéler qui vous êtes (l'adresse ne porte pas votre nom, et le script reste caché jusqu'à la dépense).

3 · VÉRIFIER UNE PSBT — PAS SEULEMENT UNE ADRESSE

La checklist du dashboard, relue par un logiciel qui ne l'a pas écrite.

Les descripteurs et les adresses, c'est de la statique — le contrat au repos. Le jour du re-lock, ce qu'il faut vérifier, c'est une PSBT : la transaction concrète que le Ledger va signer. La checklist du dashboard est produite par le même code qui a construit cette PSBT — si PLUG était un jour compromis, les deux pourraient mentir ensemble. Voici comment la relire avec un logiciel qui n'a jamais vu PLUG.

Décoder — sans faire confiance au dashboard

Les fichiers .psbt de hodl-lock sont du texte base64 brut : ouvrez-les tels quels, aucune conversion nécessaire.

$ cat psbt/relock-4-20260716.psbt
$ bitcoin-cli decodepsbt "<collez le contenu base64>"
→ entrées, sorties, locktime, scripts — lu par un programme qui ne sait pas ce qu'est PLUG

$ bitcoin-cli analyzepsbt "<même contenu>"
→ calcule les frais lui-même, dit si la PSBT est prête à signer

Re-vérifier les 4 points — mais vous-même, pas PLUG

Montant
witness_utxo.amount de chaque entrée — comparez au solde réellement on-chain de cette adresse (explorateur ou gettxout).
Destination
La seule adresse dans tx.vout — re-dérivez-la vous-même avec deriveaddresses depuis votre descripteur (témoin n°1 plus haut) et comparez caractère par caractère.
Échéance
tx.locktime — reconvertissez en date avec le calcul de coin de table : un futur proche et raisonnable, jamais une valeur absurde.
Frais
entrées − sorties, ou directement le champ fee d'analyzepsbt — sous le plafond (0,5 %).

Le champ que la checklist ne montre même pas

Dans tx.vin[0].sequence : vérifiez qu'il est inférieur à 0xffffffff. Comme vu plus haut, s'il vaut exactement cette valeur, tout le mécanisme CLTV est silencieusement désactivé — une PSBT pourrait afficher la bonne échéance sur la checklist tout en étant réellement dépensable immédiatement. Ce n'est pas un des 4 points affichés par le dashboard ; c'est exactement le genre de détail qu'un outil indépendant révèle et qu'un dashboard compromis pourrait omettre.

Le plus simple pour un non-développeur : Sparrow

Glissez le fichier .psbt dans Sparrow, avec le wallet watch-only (descripteur déjà importé — témoin n°2). Il reconnaît automatiquement les entrées comme appartenant à votre coffre, affiche destination/montant/frais clairement, et surtout : s'il ne reconnaît pas une entrée ou une sortie comme vôtre, il vous avertit. La vérification indépendante la plus accessible sans taper une commande.

Au bout de la chaîne, une dernière protection que rien de logiciel ne peut compromettre : l'écran du Ledger, un composant matériel séparé qui réaffiche montant, destination et échéance au moment de signer. Logiciel indépendant + vos yeux + écran matériel — trois couches, aucune ne fait confiance aux autres.

4 · LES SIGNAUX D'ALERTE

À quoi ressemble un contrat sain — et un contrat piégé.

✓ Contrat sain

  • La xpub est la vôtre — les 6 premiers et 6 derniers caractères correspondent à celle exportée de VOTRE Ledger.
  • Le chemin est /2/N, où N suit la série de vos verrous (0, 1, 2…).
  • after() est à ~4320 blocs du bloc courant (≈ 30 jours) — faites le calcul de coin de table.
  • L'adresse recalculée par Bitcoin Core/Sparrow est identique à celle du dashboard et de l'écran du Ledger.

✗ Ne signez pas si…

  • La xpub n'est pas la vôtre → la machine est peut-être compromise : un malware qui remplace la destination par la sienne.
  • after() est absurdement loin (des années) → erreur ou piège : vos fonds seraient gelés bien plus longtemps que prévu.
  • La transaction a plusieurs sorties alors que le rituel n'en prévoit qu'une seule → une partie des fonds partirait ailleurs.
  • L'écran du Ledger affiche autre chose que la checklist → c'est l'écran du Ledger qui a raison, toujours. Annulez sur l'appareil.

Règle d'or : en cas de doute, ne signez pas. Un re-lock peut attendre une heure ou un jour — vos fonds mûrs restent à vous, simplement dépensables. Rien ne presse jamais assez pour signer un contrat qu'on n'a pas relu.

5 · LE SCÉNARIO CATASTROPHE

PLUG a disparu. Récupérez tout, sans nous.

Le test ultime de votre autonomie. Il vous faut deux choses, et seulement deux : votre seed (les 24 mots, restaurés sur n'importe quel hardware wallet compatible) et le kit de récupération (la photocopie des contrats). Ensuite :

  1. Ouvrez Sparrow (ou Bitcoin Core) sur une machine propre.
  2. Importez le descripteur de chaque verrou depuis le kit → vos fonds apparaissent, avec leurs échéances.
  3. Attendez la maturité du verrou (le calcul de coin de table vous dit quand).
  4. Construisez la dépense vers l'adresse de votre choix, signez avec le hardware wallet, diffusez. C'est tout — le détail juste en dessous.

Aucune étape ne mentionne PLUG : le logiciel est un confort, jamais une dépendance. Répétez ce scénario une fois sur signet (des faux fonds) — le jour où vous l'avez fait en entier, ce coffre est vraiment le vôtre.

Construire la dépense — ce que Sparrow fait pour vous, en détail

Une transaction Bitcoin est une fiche à remplir avec des champs précis. La moindre case fausse invalide tout, ou rend la signature caduque après coup. Quatre choses comptent :

1 — L'entrée : quel dépôt on vide. Vous désignez précisément le verrou concerné (txid + vout — l'identifiant de la transaction de dépôt et sa position). Sans ambiguïté : « je vide CE compte, pas un autre ».

2 — La sortie : où l'argent va. Une adresse de destination, un montant = entrée − frais. Le coffre impose une sortie unique en garde-fou : tout part au même endroit, rien ne se disperse ailleurs discrètement.

3 — nLockTime : la clé de la seconde serrure. Le script contient <H> OP_CHECKLOCKTIMEVERIFY. Cet opcode ne fait qu'une chose : comparer H au champ nLockTime de votre transaction, et exiger nLockTime ≥ H. Vous devez l'écrire vous-même — ce n'est pas automatique si vous bricolez à la main. Oubliez-le ou mettez une valeur trop basse, et chaque nœud du réseau refuse le document, pas seulement le vôtre.

4 — sequence : le détail qui piège tout le monde. Subtilité BIP65 peu connue : CLTV n'a aucun effet si le sequence de l'entrée vaut la valeur « finale » par défaut (0xffffffff). Il faut explicitement une valeur inférieure — le coffre utilise 0xfffffffd, qui a un bonus : elle signale aussi le RBF (remplaçable par une version à frais plus élevés en cas de blocage). Oubliez ce détail, et le nLockTime de l'étape 3 est silencieusement ignoré par les règles de consensus — la transaction passe alors qu'elle n'aurait pas dû.

# Les mêmes 4 champs, en commande (Bitcoin Core) :
$ bitcoin-cli createpsbt \
  '[{"txid":"...","vout":0,"sequence":4294967293}]' \ # 0xfffffffd
  '[{"adresse_destination":montant}]' \
  908640 # nLockTime ≥ H — ici =H, mais la hauteur courante marche aussi

Deux hauteurs, pas une. Celle du script (after(H)) est gravée dans l'adresse — la changer produit un script différent qui hash vers une adresse différente, aucune substitution possible. Celle du nLockTime ci-dessus, en revanche, accepte n'importe quelle valeur ≥ H déjà atteinte par le réseau — mettre la hauteur courante plutôt que H pile est même la pratique recommandée (protection anti-fee-sniping, ch. 9 de Mastering Bitcoin).

La signature scelle tout à la fois. Le Ledger signe montant, destination, nLockTime et sequence ensemble — la signature est une empreinte cryptographique de l'ensemble. Changez un seul champ après coup, même une virgule, et elle devient invalide. Tout doit être exact avant d'appuyer sur le bouton, pas après.

Le witness : le script apparaît enfin au grand jour. Une fois signée, la preuve de dépense s'assemble : [signature, script_complet]. C'est le tout premier moment où votre script (clé + CLTV) devient visible publiquement — jusque-là, seul son hash (l'adresse) existait on-chain. L'enveloppe de l'analogie précédente vient de s'ouvrir.

En pratique, Sparrow fait les étapes 3 et 4 pour vous automatiquement dès qu'il reconnaît le descripteur CLTV importé — mais vous savez maintenant pourquoi il les fait, et vous pouvez vérifier qu'il les a bien faites avant de signer.

6 · TESTEZ-VOUS

Quatre questions, et vous savez lire.

Dans wsh(and_v(v:pk(xpub…/2/7),after(910000))), quel est le numéro du verrou ?

Le verrou n°7 — le 8ᵉ de la série (on compte depuis 0), rangé dans l'allée n°2 du trousseau, celle des verrous. Sa clé est la n°7, son adresse n'a jamais servi avant.

Le bloc actuel est 906 480 et le contrat dit after(910000). On ouvre quand ?

910 000 − 906 480 = 3520 blocs × 10 min ≈ 587 h ≈ 24-25 jours. Avant ça, la transaction de dépense sera refusée par chaque nœud du réseau — il n'existe personne à supplier pour aller plus vite.

La checklist affiche une xpub dont les premiers caractères ne correspondent pas à celle de votre Ledger. Vous faites quoi ?

Vous ne signez pas. Point. La destination doit être dérivée de VOTRE trousseau — une xpub inconnue signifie que les fonds repartiraient vers la serrure de quelqu'un d'autre. Machine peut-être compromise : vérifiez sur une machine saine, et fiez-vous uniquement à ce qu'affiche l'écran du Ledger.

PLUG n'existe plus, vous avez la seed et le kit. Vos fonds sont-ils perdus ?

Non — rien n'est perdu. Seed + descripteurs = récupération complète avec Sparrow ou Bitcoin Core (section 4 ci-dessus). C'est le sens de « rien de propriétaire » : le contrat est écrit dans la langue de Bitcoin, pas dans la nôtre. Mais seed sans kit = fonds introuvables : imprimez le kit, rangez-le avec la seed.

Vous savez maintenant lire votre contrat.
Prochaine étape : le voir fonctionner en vrai, avec des faux fonds.

Installer le coffre sur signet →  ·  le guide complet