Bitcoin est un systĂšme de monnaie programmable et constitue la premiĂšre implĂ©mentation de ce quâon appelle les smart contracts ou contrats autonomes. Ă chaque transaction, des scripts sont exĂ©cutĂ©s pour vĂ©rifier que les fonds dĂ©pensĂ©s remplissent les conditions voulues par lâutilisateur prĂ©cĂ©dent. De nombreuses conditions sont peuvent ĂȘtre mises en place (divulgation dâun secret, verrou temporel, multisignature), mĂȘme si le plus souvent les fonds sont simplement dĂ©pensĂ©s grĂące Ă la signature dâun utilisateur unique.
Bitcoin repose sur un modĂšle de piĂšces (UTXO), oĂč chaque piĂšce est verrouillĂ©e par un script incomplet Ă©crit sur la chaĂźne. Lors dâune transaction, les piĂšces de bitcoin en entrĂ©e sont dĂ©verrouillĂ©es par un script complĂ©mentaire. Puis, de nouvelles piĂšces sont crĂ©Ă©es Ă partir des anciennes grĂące Ă de naouveaux scripts de verrouillage, ce qui perpĂ©tue le caractĂšre programmable du systĂšme.
Lorsque jâai dĂ©couvert comment les transactions fonctionnaient et ce quâelles permettaient, jâai Ă©tĂ© fascinĂ© par lâĂ©lĂ©gance de cette solution. NĂ©anmoins, en approfondissant ma recherche, jâai Ă©tĂ© perturbĂ© par lâexistence dâune chose qui diffĂ©rait des autres, une exception : le schĂ©ma Pay to Script Hash, quâon abrĂšge couramment en P2SH.
Â
Les différents schémas : P2PK, P2PKH, P2MS et P2SH
Des scripts sont impliquĂ©s dans chaque transaction du rĂ©seau Bitcoin. Le langage de script est constituĂ© de plus dâune centaine de codes opĂ©ration, de sorte quâun large Ă©ventail de possibilitĂ©s sâoffre Ă nous vis-Ă -vis des conditions quâon souhaite imposer.
Cependant, dans le but dâamĂ©liorer la communication entre les diffĂ©rentes applications et de limiter le risque de perte, certains standards de scripts, ou schĂ©mas, ont Ă©mergĂ©.
Â
P2PK : Pay to Public Key
Le premier schĂ©ma sâappelle Pay to Public Key (P2PK), quâon peut traduire littĂ©ralement en français par « payer Ă la clĂ© publique ». Il sâagit dâenvoyer des fonds vers la clĂ© publique (public key) dâun utilisateur, que lui seul pourrait dĂ©penser en signant avec sa clĂ© privĂ©e. Le script de verrouillage (parfois appelĂ© scriptPubKey) permettant ce type dâenvoi est :
<clé publique> CHECKSIG
Au moment de la dĂ©pense, lâutilisateur doit utiliser un script de dĂ©verrouillage (parfois appelĂ© scriptSig) contenant simplement sa signature :
<signature>
Pour lâexpliquer en français, lâexĂ©cution successive de ces deux scripts permet de vĂ©rifier que la signature fournie par lâutilisateur correspond Ă sa clĂ© publique, auquel cas elle est valide.
Si le schĂ©ma P2PK Ă©tait utilisĂ© dans les premiers jours de Bitcoin, notamment pour recevoir les gains de minage, il est aujourdâhui tombĂ© en dĂ©suĂ©tude au profit dâun schĂ©ma rival : P2PKH.
Â
P2PKH : Pay to Public Key Hash
Pay to Public Key Hash (P2PKH), littĂ©ralement « payer Ă lâempreinte de la clĂ© publique », est le deuxiĂšme type de schĂ©ma apparu dans Bitcoin dĂšs le dĂ©but, grĂące Ă la conception de Satoshi Nakamoto. Ce schĂ©ma permet non pas de rĂ©aliser un paiement vers une clĂ© publique, mais vers lâempreinte dâune clĂ© publique, et de faire en sorte que le systĂšme de script de Bitcoin vĂ©rifie quand mĂȘme que la signature correspond Ă la clĂ© publique lors de la dĂ©pense des fonds. Lâempreinte de la clĂ© publique est alors considĂ©rĂ©e comme la donnĂ©e essentielle de lâadresse, qui dans ce cas commence toujours par un 1, comme par exemple 1DzxhUphLFq8FZPGbFgLF8Ssz3hMX9EuMp
.
Le script de verrouillage ici est :
DUP HASH160 <empreinte de la clé publique> EQUALVERIFY CHECKSIG
Et le script de déverrouillage est :
<signature> <clé publique>
Pour le dire en français, lâexĂ©cution des deux scripts permet de :
- Vérifier que le passage de la clé publique fournie par la fonction de hachage
HASH160
(lâempreinte) est Ă©gale Ă lâempreinte qui est spĂ©cifiĂ©e dans le script ;
- Vérifier la signature fournie correspond à la clé publique fournie.
Lâavantage de ce schĂ©ma est quâil permet dâavoir des adresses plus courtes (lâinformation Ă encoder nâest que de 20 octets au lieu de 65 octets pour une clĂ© publique), chose pour laquelle Satoshi Nakamoto lâa implĂ©mentĂ©. De plus, en ne rĂ©vĂ©lant la clĂ© publique quâau moment de la dĂ©pense, ce schĂ©ma accroĂźt aussi la sĂ©curitĂ© contre la menace (trĂšs hypothĂ©tique) de lâordinateur quantique.
Â
P2MS : Pay To MultiSig
Le schĂ©ma Pay To MultiSig (P2SH), littĂ©ralement « payer Ă la multisignature », sâest popularisĂ© dĂ©but 2012. Il sâagit essentiellement dâun schĂ©ma qui permet dâexiger la signature de M personnes faisant partie dâun groupe de N participants, via le script de verrouillage :
M <clé publique 1> ... <clé publique N> N CHECKMULTISIG
Le script de déverrouillage correspondant est :
<leurre (0)> <signature 1> ... <signature M>
Pour plus dâinformations sur la multisignature, je vous invite Ă lire mon article sur les adresses multisignatures.
Câest ce schĂ©ma, particuliĂšrement exigeant au niveau de la mise en place, qui a motivĂ© la crĂ©ation du schĂ©ma P2SH.
Â
P2SH
Pay to Script Hash (P2SH), littĂ©ralement « payer Ă lâempreinte du script ». Ce schĂ©ma reprend lâidĂ©e derriĂšre P2PKH, Ă la seule diffĂ©rence que la donnĂ©e hachĂ©e ici nâest pas une clĂ© publique, mais le script lui-mĂȘme ! Le script en question est alors appelĂ© script de rĂšglement (redeem script) et son empreinte est la donnĂ©e constituante de lâadresse, cette derniĂšre commençant toujours par un 3 Ă lâinstar de 3DyDCGSC59yYY46dnRH7Vw1iKbV8zeW36q
.
Ce type de schĂ©ma a pour avantage de permettre Ă un utilisateur dây inclure nâimporte quel script et de pouvoir recevoir des fonds de la quasi-totalitĂ© des portefeuilles existants. Le fardeau de la construction et du dĂ©verrouillage du script revient donc au dĂ©tenteur de lâadresse, non Ă celui qui envoie les fonds, ce qui simplifie grandement la communication.
Le script de verrouillage pour le schéma P2SH est :
HASH160 <empreinte du script de rĂšglement> EQUAL
Et le script de déverrouillage est un script de la forme :
[éléments de déverrouillage] <script de rÚglement>
En français, cela veut dire que le systĂšme de script originel de Bitcoin va vĂ©rifier que le hachage du script de rĂšglement est Ă©gal Ă lâempreinte inscrite dans le script. Et câest tout.
Comment ça, « câest tout » ? Le script de rĂšglement nâest pas exĂ©cutĂ© ? Nâimporte qui connaissant le script pourrait dĂ©penser les bitcoins ?
Comme on va le voir, ce nâest pas le cas et le script de rĂšglement est bien exĂ©cutĂ©, bien que ce ne soit pas indiquĂ© explicitement.
Â
RĂšgles et exceptions : OP_EVAL et P2SH
Dans la vie, il y a souvent une maniĂšre Ă©lĂ©gante de faire les choses, qui demande parfois plus dâefforts initiaux mais qui prĂ©serve lâordre et la simplicitĂ©, et une maniĂšre grossiĂšre, plus facile Ă implĂ©menter mais qui complique les choses et crĂ©e le dĂ©sordre.
Ainsi, dans le systĂšme lĂ©gislatif dâun pays, il est plus facile de crĂ©er et de faire voter de nouvelles lois execeptionnelles que de rĂ©former en profondeur le systĂšme. Cette tendance Ă lâinflation lĂ©gislative fait quâon se retrouve avec des pays comme la France, qui cumule 73 codes juridiques en vigueur et qui vit de 214 taxes et impĂŽts ainsi que dâune myriade de cotisations sociales.
En informatique comme en droit, lâajout de nouvelles exceptions crĂ©e de la dette technique, rendant le systĂšme plus complexe Ă apprĂ©hender, plus difficile Ă maintenir et plus susceptible de ne pas fonctionner comme attendu. P2SH fait partie de ces exceptions.
Â
Le code opération mort-né : OP_EVAL
LâidĂ©e dâimplĂ©menter un schĂ©ma de script qui utilise lâempreinte dâun autre script comme identifiant est nĂ©e en 2011, afin de reproduire ce qui est rĂ©alisĂ© dans la schĂ©ma P2PKH. Toutefois, cette idĂ©e nâa pas Ă©tĂ© dĂ©veloppĂ©e initialement comme P2SH, mais Ă travers OP_EVAL, un nouveau code opĂ©ration permettant lâexĂ©cution rĂ©cursive dâun script Ă lâintĂ©rieur dâun autre script.
Lâajout de ce code opĂ©ration, proposĂ© le 18 octobre 2011 par Gavin Andresen, devait ĂȘtre implĂ©mentĂ© comme un soft fork, via le remplacement de lâinstruction nulle OP_NOP1.
Un schéma standard aurait également été ajouté. Le script de verrouillage imaginé pour ce schéma était :
DUP HASH160 <empreinte du script de rĂšglement> EQUALVERIFY EVAL
Le script de déverrouillage correspondant était :
[éléments de déverrouillage] <script de rÚglement>
Pour le dire en français, lâexĂ©cution des deux scripts cĂŽte Ă cĂŽte aurait permis de :
- VĂ©rifier que le hachage du script de rĂšglement soit Ă©gal Ă lâempreinte spĂ©cifiĂ©e dans le script de verrouillage ;
- VĂ©rifier que lâexĂ©cution du script de rĂšglement combinĂ© aux Ă©lĂ©ments de dĂ©verrouillage soit bien valide.
NĂ©anmoins cette solution nâa pas Ă©tĂ© acceptĂ©e, celle-ci ayant Ă©tĂ© jugĂ©e trop dangereuse au niveau du pouvoir de rĂ©cursion. Ă la place câest un autre modĂšle, plus restrictif, qui a prĂ©valu : le schĂ©ma P2SH.
Â
Comment fonctionne P2SH ?
P2SH a Ă©tĂ© proposĂ© le 3 janvier 2012 comme alternative Ă OP_EVAL et Ă dâautres propositions. Il a Ă©tĂ© intĂ©grĂ© au protocole Bitcoin le 1er avril sous la forme dâun soft fork activĂ© par les mineurs.
LâexĂ©cution de ce type de script fonctionne exactement comme le schĂ©ma liĂ© Ă OP_EVAL, Ă lâexception quâune partie du script nâest pas explicitement indiquĂ©e. Dâune part, la vĂ©rification de la correspondance entre lâempreinte indiquĂ©e et le script de rĂšglement est bien rĂ©alisĂ©e par le script de verrouillage. En effet, celui-ci devient (comme on lâa vu) :
DUP HASH160 <empreinte du script de rĂšglement> EQUALVERIFY EVAL
Dâautre part, lâĂ©valuation du script de rĂšglement est effectuĂ©e implicitement grĂące Ă une exception ajoutĂ©e au code source. DĂšs que les nĆuds du rĂ©seau reconnaissent le schĂ©ma, ils lâinterprĂštent diffĂ©remment. Ainsi dans Bitcoin Core, on peut observer la condition suivante au sein de la fonction VerifyScript
de lâinterprĂ©teur :
// Additional validation for spend-to-script-hash transactions:
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
{
...
}
Cette exception permet lâexĂ©cution du script de rĂšglement aprĂšs lâexĂ©cution des deux scripts (dĂ©verrouillage et verrouillage). DâoĂč le fait quâon indique les Ă©lĂ©ments de dĂ©verrouillage avant de pousser le script de rĂšglement dans le script de dĂ©verrouillage :
[éléments de déverrouillage] <script de rÚglement>
Si cette solution est pratique, elle crĂ©e une complexitĂ© et nâest pas trĂšs Ă©lĂ©gante. Comme lâa dit Gavin Andresen dans lâexplication du BIP-16 :
ReconnaĂźtre une forme « spĂ©ciale » de scriptPubKey et rĂ©aliser une validation supplĂ©mentaire quand elle est dĂ©tectĂ©e, câest laid. Cependant, lâavis gĂ©nĂ©ral est que les alternatives sont soit encore plus laides, soit plus complexes Ă implĂ©menter, et/ou Ă©tendent le pouvoir du langage dâexpression de maniĂšre dangereuse.
LâimplĂ©mentation initiale de P2SH a donc compliquĂ© les choses. Mais cela ne sâest pas arrĂȘtĂ© pas lĂ , car lâactivation de SegWit en 2017 a ajoutĂ© de la complexitĂ© au modĂšle.
Â
SegWit, P2SH-P2WPKH et P2SH-P2WSH
En aoĂ»t 2017, la mise Ă niveau SegWit a Ă©tĂ© intĂ©grĂ©e Ă Bitcoin (BTC) sous la forme dâun soft fork. Celle-ci avait pour objectif de corriger la mallĂ©abilitĂ© des transactions, dâaugmenter la capacitĂ© transactionnelle, dâamĂ©liorer la vĂ©rification des signatures et de faciliter les modifications futures du protocole.
Pour ce faire, SegWit implĂ©mentait un nouveau modĂšle de transaction, oĂč les signatures sont situĂ©es dans une partie sĂ©parĂ©e de la transaction appelĂ©e le tĂ©moin (dâoĂč le nom de Segregated Witness). Afin dâimplĂ©menter ce changement comme un soft fork, il a Ă©tĂ© nĂ©cessaire dâintroduire un moyen dâaccĂ©der au nouveau type de transaction sans briser la compatibilitĂ© avec les anciennes adresses.
Câest ainsi que 4 nouveaux types dâadresse ont vu le jour : deux nouveaux types « natifs », P2WPKH (Pay to Witness Public Key Hash) et P2WSH (Pay to Witness Script Hash), incompatibles avec portefeuilles ne supportant pas SegWit ; et deux types « imbriquĂ©s » associĂ©s, P2SH-P2WPKH et P2SH-P2WSH, qui permettent la transition grĂące Ă lâemploi de P2SH.
Pour ces deux derniers types dâadresse, le schĂ©ma utilisĂ© est P2SH avec un script de rĂšglement de la forme :
<version SegWit> <empreinte>
Dans la version 0 de SegWit (la seule qui existe pour le moment), lâempreinte est affectĂ©e Ă une clĂ© publique ou Ă un script selon sa longueur : si elle est de 20 octets, elle est interprĂ©tĂ©e comme une empreinte de clĂ© publique ; si elle est de 32 octets, elle est interprĂ©tĂ©e comme une empreinte de script. Cette empreinte est aussi appelĂ©e « programme ».
Ce script est anyone-can-spend puisque le script de rÚglement suffit à déverrouiller la piÚce :
<script de rĂšglement>
Comme pour P2SH, la connaissance du script de rÚglement ne suffit pourtant pas à dépenser les fonds, car une nouvelle exception est ajoutée au code de façon à ce que les éléments de déverrouillage soient transférées dans le témoin. Dans Bitcoin Core, cette exception se traduit par :
// P2SH witness program
if (flags & SCRIPT_VERIFY_WITNESS) {
...
}
SegWit a ainsi apportĂ© un nouveau lot de complexitĂ©, et notamment un deuxiĂšme niveau de rĂ©cursion. Dans le cas du schĂ©ma P2SH-P2WSH, on a en effet une sĂ©rie de 3 scripts imbriquĂ©s. Le premier script est le script de dĂ©verrouillage que lâon a prĂ©sentĂ© au dĂ©but de cet article :
HASH160 <empreinte du script de rĂšglement> EQUAL
Le deuxiÚme script est le script de rÚglement spécifique à P2SH :
<version SegWit> <empreinte du script SegWit>
Le troisiĂšme est le script SegWit, indiquĂ© dans le tĂ©moin avec les Ă©lĂ©ments de dĂ©verrouillage au moment de la dĂ©pense des fonds. Par exemple, il peut sâagir dâun script de multisignature comme vu prĂ©cĂ©demment :
2 <clé publique 1> <clé publique 2> 2 CHECKMULTISIG
quâon complĂšte avec les Ă©lĂ©ments :
0 <signature 1> <signature 2>
Â
Conclusion
Pay to Script Hash (P2SH) est donc une maniĂšre imparfaite mais trĂšs pratique de permettre aux utilisateurs de payer Ă lâempreinte dâun script, câest-Ă -dire Ă une adresse simple qui correspond Ă un script. La rĂ©cursion qui intervient dans lâexĂ©cution du script aurait pu ĂȘtre implĂ©mentĂ©e de maniĂšre plus Ă©lĂ©gante grĂące au code opĂ©ration OP_EVAL, mais ce dernier a Ă©tĂ© jugĂ© trop dangereux par la communautĂ© pour voir le jour.
En ajoutant une nouvelle exception au protocole pour ĂȘtre exĂ©cutĂ©, le schĂ©ma P2SH reprĂ©sente un vecteur de complexitĂ©. De plus, cette complexitĂ© est dĂ©multipliĂ©e par lâincorporation de SegWit, qui ajoute de nouvelles exceptions rigides Ă P2SH et qui finit de dĂ©tourner complĂštement le fonctionnement originel du systĂšme de script de Bitcoin.
NĂ©anmoins, ce qui est fait est fait, et aujourdâhui ces changements commencent Ă ĂȘtre connus dans lâĂ©cosystĂšme, et on peut donc espĂ©rer que cette complexitĂ© nâimpacte pas trop les nouveaux dĂ©veloppeurs. En particulier, le schĂ©ma P2SH est rĂ©pandu dans tout lâĂ©cosystĂšme, par les protocoles associĂ©s Ă Bitcoin tel que Bitcoin Cash, Litecoin ou Dash. Seuls les dĂ©veloppeurs de Bitcoin SV ont se sont opposĂ©s Ă cette particularitĂ© de maniĂšre catĂ©gorique et ont choisi de dĂ©sactiver P2SH en fĂ©vrier 2020.
Ce quâil faut retenir de tout ceci, câest que Bitcoin, au-delĂ de son aspect technique, est un systĂšme Ă©conomique et social. Il Ă©volue selon les exigences de ses utilisateurs, si bien quâil est impossible de le comprendre sans apprĂ©hender les dynamiques sous-jacentes qui ont Ă©tĂ© Ă lâĆuvre dans le passĂ©.
Â
Sources
Gavin Andresen, BIP-11 (M-of-N Standard Transactions), 18 octobre 2011.
Gavin Andresen, BIP-12 (OP_EVAL), 18 octobre 2011.
Gavin Andresen, BIP-16 (Pay to Script Hash), 3 janvier 2012.
Mike Hearn, On consensus and forks, 12 août 2015.
Eric Lombrozo, Johnson Lau et Pieter Wuille, BIP-141 (Segregated Witness), 21 décembre 2015.