Partie 1 : Comment fonctionne Bitcoin Script, et pourquoi est-ce si difficile ? Partie 2 : Qu'est-ce que Miniscript, et comment simplifie-t-il les scripts Bitcoin ? Partie 3 : Écrire un parseur et un analyseur Miniscript en Go

Dans la première partie de cette série d'articles, nous avons examiné des exemples de verrouillage de bitcoins à l'aide de conditions élaborées comme (person1 peut dépenser à tout moment) OU (person2 peut dépenser dans un an) avec Bitcoin Script, le langage de script natif de Bitcoin. Ces exemples ont montré à quel point il était difficile pour les développeurs de formuler de telles conditions et de les utiliser en pratique à cause des limites et des pièges de Bitcoin Script. Il était difficile de développer le script qui encode les conditions de dépense souhaitées, ainsi que de créer des witnesses valides permettant de dépenser les bitcoins.

Miniscript résout ces problèmes en introduisant des fragments qui encapsulent des morceaux de Bitcoin Script, ce qui facilite l'écriture de scripts Bitcoin plus complexes en composant ces fragments.

Cet article entre dans les détails du fonctionnement de Miniscript et de la manière dont il se mappe vers Bitcoin Script.

Prenez le temps de lire la première partie avant d'aller plus loin, car nous nous appuierons sur les concepts de Bitcoin Script qui y sont introduits, par exemple sur la manière dont les scripts Bitcoin sont exécutés pour déterminer si un bitcoin peut être dépensé.

Qu'est-ce que Miniscript ?

Miniscript se compose de deux éléments indépendants :

Langage de politiques

Le langage de politiques est un langage d'expressions de haut niveau, composable et facile à lire et à écrire pour les humains. Le langage de politiques peut être automatiquement compilé en un Miniscript adapté par un compilateur de politiques. Un exemple de politique est or(pk(key_1),pk(key_2)), ce qui signifie « soit key_1, soit key_2 peut dépenser ».

Miniscript

Une expression Miniscript peut par exemple ressembler à or_b(pk(key_1),s:pk(key_2)), qui a été compilée à partir de la politique ci-dessus à l'aide du compilateur de sipa. Il s'agit d'une composition de fragments tels que or_b, pk, etc.

Chaque fragment correspond à un morceau particulier de Bitcoin Script. Par exemple, pk(key) correspond à <key> OP_CHECKSIG, et or_b(X,Y) correspond à [X] [Y] BOOLOR.

Miniscript lui-même est un langage d'expressions facile à lire aussi bien pour les ordinateurs que pour les humains.

Pour les ordinateurs, c'est important afin que votre application de portefeuille puisse décoder une expression Miniscript, la transformer en adresses de réception et vous permettre de dépenser vos fonds.

Pour les humains, c'est important afin que vous puissiez sauvegarder le descripteur de votre portefeuille en l'écrivant sur papier, et utiliser ce même descripteur pour interagir avec différentes applications et différents outils. Par exemple, vous pouvez vouloir importer le descripteur de votre portefeuille dans un outil de suivi de portefeuille ou de déclaration fiscale, ou l'importer dans un portefeuille mobile watch-only. Un descripteur de portefeuille peut inclure un miniscript et peut être utilisé pour dériver des adresses.

Le langage d'expressions Miniscript ressemble beaucoup au langage de politiques, il est donc facile de confondre les deux. Il est important de comprendre qu'il s'agit de deux langages complètement indépendants :

Le langage de politiques est un outil qui aide les développeurs à formuler facilement des conditions de dépense, car il est très simple à écrire. Il ne contient qu'une poignée de primitives telles que and(X,Y), or(X,Y), older(time), etc., et elles se composent toutes parfaitement les unes avec les autres. Le langage de politiques est simplement un outil pour les développeurs et n'est pas standard. Une expression de politique n'est pas garantie de toujours produire la même expression Miniscript.

Miniscript, en revanche, est bien spécifié. Seul Miniscript est utilisé pour dériver le Bitcoin Script, les witnesses valides, et effectuer des analyses de validité. Une expression Miniscript correspondra toujours au même Bitcoin Script.

Alors pourquoi les développeurs n'écrivent-ils pas directement des expressions Miniscript ? Pourquoi s'appuie-t-on sur un compilateur de politiques ? La raison est que les expressions Miniscript ne sont pas triviales à écrire à la main, car elles héritent naturellement d'une partie de la complexité de Bitcoin Script en l'encapsulant :

  • Il y a beaucoup plus de fragments dans Miniscript que dans le langage de politiques. Par exemple, il existe au moins quatre façons différentes d'exprimer X or Y dans Miniscript : or_b(X,Y), or_c(X,Y), or_d(X,Y) et or_i(X,Y), chacune correspondant à une manière différente, dans Bitcoin Script, d'exprimer X or Y, chacune avec des caractéristiques différentes en termes de taille du script, de taille du witness et de composition avec d'autres fragments.
  • Il peut exister de nombreux miniscripts différents qui encodent les mêmes conditions. Le compilateur de politiques peut aider à optimiser, par exemple, la taille du script pour réduire les frais de transaction.
  • Toutes les expressions Miniscript ne produisent pas des scripts valides : les fragments doivent être composés de manière à respecter des propriétés de validité. Le compilateur de politiques veille à ne produire que des miniscripts valides.

En pratique : correspondance avec Bitcoin Script

Pour comprendre comment une expression Miniscript encode un Bitcoin Script, voyons-le en action en décomposant l'expression suivante :

`or_b(pk(key_1),s:pk(key_2))
`

Chaque fragment correspond à un morceau particulier de Bitcoin Script. pk(key) correspond à <key> OP_CHECKSIG, et or_b(X,Y) correspond à [X] [Y] BOOLOR.

Chaque fragment peut aussi être enveloppé dans des wrappers, indiqués par des lettres avant les deux-points :. Le wrapper s:X correspond à OP_SWAP [X]. Les wrappers sont fondamentalement la même chose que les autres fragments, mais en plus concis. D'une certaine manière, ce sont simplement du sucre syntaxique. Vous pouvez considérer, par exemple, que s:X revient à écrire s(X), ou que dv:older(144) revient à écrire d(v(older(144)).

L'expression Miniscript complète ci-dessus se traduit donc par ce Bitcoin Script :

`<key_1> OP_CHECKSIG OP_SWAP <key_2> OP_CHECKSIG OP_BOOLOR
\_________________/ \ \________________/ /
        \ X        \ X                / /
         \ \__________________/ /
          \ Y=s:X            /
\_______________________________________________/
or_b(X,Y)
`

Dans cet exemple précis, un witness pour dépenser les fonds aurait la forme <signature2> <signature1>, où au moins l'une des signatures doit être valide. OP_SWAP est nécessaire pour que la partie <key_2> OP_CHECKSIG soit appliquée non pas à l'élément au sommet de la pile, qui contient le résultat de <signature1> <key_1> OP_CHECKSIG, mais à l'élément situé juste en dessous, qui contient la signature pour la deuxième clé.

Il existe au total 22 fragments définis et 11 wrappers, chacun ayant une correspondance concrète avec Bitcoin Script. Vous pouvez consulter la liste complète ainsi que leurs correspondances dans la spécification ici.

Décomposons une expression plus complexe. Rappelons la condition de dépense que nous avons utilisée dans la première partie de cette série comme exemple motivant :

`pubkey1 OU (pubkey2 dans un an)
`

Le script que nous avons utilisé pour encoder cette condition était assez compliqué et difficile à élaborer à la main :

`<pubkey1> OP_CHECKSIG OP_IFDUP OP_NOTIF
<pubkey2> OP_CHECKSIGVERIFY <52560 (un an)> OP_CHECKSEQUENCEVERIFY
OP_ENDIF
`

Avec Miniscript, cependant, cette condition de dépense peut être exprimée par la politique suivante :

`or(10@pk(pubkey1),and(pk(pubkey2),older(52560)))
`

qui se compile en l'expression Miniscript suivante :

`or_d(pk(pubkey1),and_v(v:pk(pubkey2),older(52560)))
`

qui, à son tour, correspond au Script complexe ci-dessus en faisant correspondre les fragments à leurs équivalents Script comme suit :

  • older(52560) encapsule <52560> OP_CHECKSEQUENCEVERIFY
  • v:pk(pubkey2) encapsule <pubkey2> OP_CHECKSIGVERIFY
  • and_v(X,Y) encapsule [X] [Y], donc dans ce cas <pubkey2> OP_CHECKSIGVERIFY <52560> OP_CHECKSEQUENCEVERIFY
  • pk(pubkey1) encapsule <pubkey1> OP_CHECKSIG
  • or_d(X,Y) encapsule [X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF, ce qui donne le script final ci-dessus.

Le 10@ donne au compilateur de politiques une indication selon laquelle nous nous attendons à ce que ce chemin de dépense soit bien plus probable que l'autre. Le compilateur peut utiliser cette information pour optimiser la taille totale du script dans ce cas.

Une fois le Bitcoin Script connu, une application de portefeuille peut le convertir en adresse de réception comme bc1... et vous permettre d'y recevoir des fonds. Ces fonds seront verrouillés à l'aide des conditions de dépense exprimées dans la politique/le miniscript d'origine.

Génération des witnesses

Les witnesses correspondants pour dépenser des fonds peuvent eux aussi être générés automatiquement à partir de l'expression Miniscript, car chaque fragment définit comment construire des satisfactions et des dissatisfactions valides pour celui-ci. Une application de portefeuille basée sur Miniscript utiliserait cette méthode pour vous permettre d'effectuer des transactions.

La liste de toutes les satisfactions et dissatisfactions pour chaque fragment se trouve sous « Basic satisfactions » ici.

Par exemple, le fragment pk(key), qui correspond à <key> OP_CHECKSIG, peut être satisfait par <signature>. L'exécution finale du script serait <signature> <key> OP_CHECKSIG et laisserait un 1 sur la pile si la signature était valide, et un 0 sinon. Le même fragment peut produire une dissatisfaction via la signature vide invalide <>. Une dissatisfaction signifie que le script n'est pas interrompu et continue en laissant un 0 sur la pile.

Reportez-vous à la première partie de cette série d'articles pour comprendre comment les witnesses et les scripts sont combinés et exécutés afin de permettre la dépense des fonds.

Générons les witnesses pour la même expression que dans l'exemple ci-dessus :

`or_b(pk(key_1),s:pk(key_2))
`
  • le fragment pk(key) peut être satisfait par <signature>, et produire une dissatisfaction avec la signature vide <>.
  • le fragment or_b(X,Y) ([X] [Y] OP_BOOLOR) peut être satisfait par trois satisfactions différentes : soit X et Y sont satisfaits, soit un seul des deux l'est : [satisfaction pour Y][satisfaction pour X], ou [dissatisfaction pour Y][satisfaction pour X], ou [satisfaction pour Y][dissatisfaction pour X].
  • En combinant les deux : or_b(pk(key_1),s:pk(key_2)) possède ces trois witnesses valides :
  1. <signature2> <signature1>
  2. <> <signature1>
  3. <signature2> <>.

Conclusion

Dans cet article, nous avons vu comment Miniscript simplifie le développement de conditions de dépense complexes et comment il permet aux applications de portefeuille de recevoir et de dépenser des fonds verrouillés par de telles conditions.

Dans le prochain volet, nous écrirons un véritable parseur Miniscript complet et un analyseur de validité dans le langage de programmation Go. Il sera capable de générer des adresses de réception Bitcoin à partir d'expressions Miniscript arbitraires. À suivre !

Vous n'avez pas encore de BitBox ?

La sécurité de vos cryptos n'a pas à être compliquée. Le hardware wallet BitBox02 stocke hors ligne les clés privées de vos cryptomonnaies. Vous pouvez ainsi gérer vos fonds en toute sécurité.

La BitBox02 existe aussi en version Bitcoin-only, avec un firmware résolument ciblé : moins de code signifie moins de surface d'attaque, ce qui améliore encore votre sécurité si vous ne stockez que du Bitcoin.

Procurez-vous-en une dans notre boutique !

Foire aux questions (FAQ)

Qu'est-ce que Miniscript dans le contexte de Bitcoin ? Miniscript introduit des fragments qui encapsulent des morceaux de Bitcoin Script, ce qui simplifie la création de scripts Bitcoin complexes en composant ces fragments.

En quoi Miniscript diffère-t-il du langage de script natif de Bitcoin ? Alors que Bitcoin Script est difficile à utiliser pour les développeurs à cause de ses subtilités, Miniscript facilite l'encodage des conditions de dépense souhaitées et la création de witnesses valides pour dépenser des bitcoins.

Quels sont les deux éléments indépendants de Miniscript ? Miniscript se compose du langage de politiques, un langage d'expressions de haut niveau, et de Miniscript lui-même, un langage d'expressions qui correspond directement à Bitcoin Script.

Pourquoi le langage de politiques est-il utilisé dans Miniscript ? Le langage de politiques aide les développeurs à formuler facilement des conditions de dépense. C'est un outil destiné aux développeurs et il n'est pas standardisé, tandis que Miniscript est bien spécifié et utilisé pour dériver Bitcoin Script.

Quel est l'intérêt de Miniscript pour les applications de portefeuille ? Miniscript permet aux applications de portefeuille de décoder ses expressions, de générer des adresses de réception et de faciliter les transactions de fonds en fonction des conditions de dépense définies.

Shift Crypto est une entreprise privée basée à Zurich, en Suisse. Notre équipe de contributeurs Bitcoin, d'experts crypto et d'ingénieurs en sécurité conçoit des produits qui permettent à nos clients de progresser sereinement, du niveau débutant à la maîtrise de la gestion des cryptomonnaies. BitBox02, notre hardware wallet de deuxième génération, permet aux utilisateurs de stocker, protéger et effectuer facilement des transactions en Bitcoin et autres cryptomonnaies, avec son logiciel compagnon, BitBoxApp.

This post was translated with the help of AI