Questo articolo è l’ottavo (parte B) – stavolta dedicato a Segwit– di una serie di approfondimenti sulla parte più tecnica di Bitcoin, accessibile anche a coloro a digiuno di codice.
Il testo continua una sorta di guida pensata per entrare gradualmente in quella che molti definiscono “la tana del bianconiglio”.
A livello bibliografico è d’obbligo citare il testo “Mastering Bitcoin” di Andreas Antonopoulos, riferimento costante, dal quale sono state tratte le immagini. Chi fosse interessato ad approfondire questi temi, con o senza integrazione delle dinamiche legate al codice, può trovare supporto nei corsi formativi e nella attività consulenziali erogate da Bcademy.
Segregated Witness (segwit)
Si tratta di un upgrade del protocollo e delle regole di consenso, proposto e implementato come soft-fork (BIP-9) attivato sulla main-net il primo agosto 2017. In crittografia il termine Witness (testimone) è utilizzato per descrivere una soluzione ad un puzzle crittografico: in Bitcoin il testimone soddisfa le condizioni poste su un UTXO.
Una firma digitale è una tipologia di testimone ma il termine testimone è più ampiamente utilizzato per ciò che soddisfa le condizioni poste su un UTXO, ergo generalmente per uno script di sblocco o scriptSig. Prima di segwit ogni input di transazione era seguito dal testimone che lo sbloccava: i dati del testimone erano incorporati nella transazione come parte di ciascun input. Il termine segregate witness semplicemente significa separare le firme o gli script di sblocco di uno specifico output, spostandoli dal campo di scriptSig ad una struttura dati separata di witness che accompagna la transazione. I client possono richiedere i dati della transazioni con o senza l’accompagnamento dei dati del testimone.
Segwit è un cambio strutturale che modifica diversi aspetti di scalabilità, sicurezza, incentivi economici e performance di Bitcoin.
- Transaction malleability. L’hash della transazione non include più il testimone (unica parte della transazione che poteva essere modificata da una terza parte), ergo viene rimossa la possibilità di attacchi di malleability (solo il creatore della transazione può modificarne i dati), migliorando notevolmente l’implementazione di altri protocolli che si basano sulla struttura delle transazioni bitcoin avanzate (payment channel, chained transaction, LN…)
- Script versioning. Con gli script di segwit ogni script di blocco è preceduto da un numero di script version, ciò permette un upgrade del linguaggio di script in modo retro-compatibile (ad esempio utilizzando fork) per introdurre nuovi operandi, sintassi o semantica. La capacità di migliorare il linguaggio di script in modo non-disruptive accelererà molto il tasso di innovazione di Bitcoin.
- Network and social scaling. I dati del testimone sono un deciso contributo alla grandezza di una transazione, in alcuni casi (multisig o payment channel) oltre il 75%. I nodi possono “sfoltire” (prune) i dati dei testimoni dopo aver validato le firme, o ignorarli del tutto nelle SPV (simplified payment verification): non è necessario che i dati testimone vengano trasmessi a tutti i nodi (e “storati”).
- Signature Verification Optimization. Migliora le funzioni di firma (CHECKSIG, CHECKMULTISIG, etc) riducendo la complessità dell’algoritmo. Prima di segwit, l’algoritmo usato per produrre una firma richiedeva un numero di operazioni di hash proporzionale alla grandezza della transazione: gli hashing aumentavano di O(n2)rispetto al numero di operazioni di firma, con un notevole fardello di computazione da parte di tutti i nodi che verificavano le firme (con segwit l’algortimo è cambiato riducendo la complessità a O(n)).
- Offline Signing Improvement. Le firme segwit incorporano il valore (ammontare) riferito ad ogni input nell’hash firmato. Prima, un dispositivo offline (hardware wallet) avrebbe dovuto verificare l’ammontare di ogni singolo input prima di firmare la transazione (ciò avveniva tramite lo streaming di una grande quantità di dati sulle transazioni precedenti a cui si faceva riferimento come input). Da quando l’ammontare è parte dell’hash (commitment, impegnato) firmato, un dispositivo offline non ha bisogno delle transazioni precedenti. Se l’ammontare non matcha la firma sarà non valida.
Segregate witness è un cambiamento di come gli UTXO sono spesi e dunque una caratteristica per-output. Una transazione può spendere output segwit, tradizionali o entrambi (non ha senso parlare di transazioni segwit, ma di output segwit), quando una transazione spende un UTXO deve fornire il testimone. In una tradizionale UTXO, lo script di blocco richiede che i dati del testimone siano stati forniti inline, nella parte dell’input della transazione che spende l’UTXO. Un UTXO segwit invece specifica uno script di blocco che può essere soddisfatto con dati di del testimone esterni all’input (“segregati”).
E’ un cambio significativo nel modo in cui vengono costruiti output e transazioni. Un tale cambiamento richiede normalmente un simultaneo cambio in ogni nodo Bitcoin, wallet etc, per cambiare le regole del consenso (hard fork). Segwit è stato introdotto in maniera molto più leggera, retro-compatibile (soft-fork): questo genere di upgrade permette ai software non upgradati di ignorare i cambiamenti e continuare ad operare senza “disruption”. Gli output segwit sono costruiti in modo che anche i “vecchi sistemi” (non segwit-aware) possano ancora validarli. Questi output possono essere spesi con una firma vuota, quindi il fatto che non ci sia firma all’interno della transazione (è segregata) non invalida la transazione. I nuovi wallet e miner, comunque, vedono gli output segwit e aspettano di trovare un valido testimone per essi all’interno dei dati testimone della transazione.
Esempio di uno script di output P2PKH:
DUP HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 EQUALVERIFY CHECKSIG
Con Segregated Witness verrebbe creato uno script di output Pay-to-Witness-Public-Key-Hash (P2WPKH):
0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
Più semplice di uno script di output tradizionale, consiste in due valori che sono spinti nella pila dello script di validazione. Ad un vecchio (non-segwit) client Bitcoin, i due valori spinti sembrano un output che chiunque può spendere e che non richiede firma (o meglio, che può essere speso con una firma vuota). Dai nuovi client (segwit), il primo numero (0) è interpretato come la “versione” (the witness version) e la seconda parte (20 byte) come equivalente di uno script di blocco conosciuto come “witness program” (l’hash della chiave pubblica, come negli script P2PKH).
Per spendere l’output segwit, la transazione non ha una firma sull’input, ma ha uno scriptSig vuoto e include un Segregated Witness, fuori dalla transazione stessa.
È importante notare che P2WPKH dovrebbero essere create solo dal ricevente, poiché il mandante non ha modo di sapere se il wallet del ricevente ha la capacità di costruire transazioni segwit e spendere output P2WPKH. In aggiunta, questi output devono essere costruiti dall’hash di una chiave pubblica compressa (compressed), le non-compresse non sono standard in segwit e possono essere disabilitate da un futuro soft-fork.
Il secondo tipo di witness program corrisponde agli script Pay-to-Script-Hash (P2SH). Questi script fanno riferimento agli hash di un redeem script che definisce le molteplici firme (M-su-N) richieste per spendere i fondi. Un wallet compatibile segwit potrebbe creare uno script di output Pay-to-Witness-Script-Hash (P2WSH):
0 a9b7b38d972cabc7961dbfbcb841ad4508d133c47ba87457b4a0e8aae86dbb89
Come in P2WPKH lo script è più semplice rispetto al tradizionale, e consiste di due valori pushati sulla pila (stack): una versione del testimone (0) e un 32-byte hash SHA256 dello script di redeem.
Entrambe le forme di script testimone, P2WPKH e P2WSH possono essere inserite in un indirizzo P2SH: P2SH(P2WPKH) e P2SH(P2WSH). Anche dopo l’attivazione di segwit, ci vorrà tempo finché la maggior parte dei wallet sarà upgradata (segwit può essere appunto incorporato in P2SH che lo rende agilmente compatibile anche con wallet non segwit-aware). Una volta che segwit sarà ampiamente supportato, ha senso codificare script testimone in indirizzi segwit nativi, piuttosto che incorporarli in P2SH: tale formato di indirizzi segwit nativi è definito in BIP-173.