Ogni moneta su Bitcoin sta dietro una serratura: un piccolo programma, lo scriptPubKey, che dice a quali condizioni quella moneta si può spendere. Spendere significa presentare ciò che la serratura chiede, di norma una firma che prova il possesso della chiave giusta. I tipi di serratura sono pochi, nati uno dopo l'altro lungo la storia del protocollo, e ciascuno risponde a modo suo alla stessa domanda: quanto si vede, da fuori, di ciò che chiude la moneta. Alcune serrature mettono la chiave pubblica in chiaro sull'output dal primo istante; altre ne espongono soltanto l'impronta, e la chiave si vede solo quando la moneta si muove. Qui si guarda a questo: che forma hanno le serrature, come sono cambiate, cosa distingue l'una dall'altra.
Questo testo si tiene sul piano d'insieme: la cronologia dei tipi, le tabelle che li mettono in fila, e la forma in byte di ciascuna serratura. Come si costruisce e si firma davvero un'intera transazione, il suo formato pezzo per pezzo, è materia di un secondo passaggio, più tecnico. Chi arriva dai pezzi sul quantum computing e sui suoi numeri misurati trova qui il meccanismo che quelli danno per noto.
Serratura e indirizzo non sono la stessa cosa
Conviene chiarirlo subito, perché è l'equivoco più comune. La serratura è lo scriptPubKey, lo script che sta sull'output e ne fissa le condizioni di spesa. L'indirizzo non è la serratura: è solo un modo compatto di scriverla, una codifica pensata per stare in un messaggio, con un controllo di integrità che evita di sbagliare una cifra. Da un indirizzo il portafoglio ricava la serratura da mettere sull'output; sul registro, di indirizzi non ce ne sono, ci sono script.
Tenere separate le due cose spiega diverse asimmetrie. Alcuni tipi di serratura non hanno un indirizzo proprio (i più antichi). Codifiche diverse convivono nello stesso momento, una per famiglia di serrature. E lo stesso identico indirizzo, riusato per ricevere due volte, produce due output con la stessa serratura: quando si spende il primo, la chiave diventa pubblica, e il secondo si ritrova scoperto senza che nessuno l'abbia toccato.
Il linguaggio delle serrature
Una serratura è un programma, e il linguaggio in cui è scritta si chiama Script: una sequenza di istruzioni, gli op (opcode), eseguite su una pila di dati. Chi spende presenta i propri dati di sblocco, di norma una firma e una chiave, a volte uno script intero; i nodi mettono quei dati sulla pila e poi eseguono la serratura: se alla fine sulla pila resta «vero», la spesa è valida. Tutto qui: non c'è un guardiano che decide, c'è un programma che ogni nodo del mondo riesegue e che dà a tutti lo stesso esito.
Quando a un nodo arriva un blocco, i controlli si fanno in un ordine preciso, dal più economico al più caro: prima l'intestazione e il proof-of-work, che costano un hash; poi la forma del blocco; poi, per ogni transazione, che le monete spese esistano davvero e non risultino già spese; e soltanto alla fine si eseguono le serrature, cioè si verificano le firme. È il passaggio che costa di più, ed è l'ultimo apposta: chi manda spazzatura viene fermato prima di farla pagare a tutti. Per molte transazioni, poi, quel lavoro il nodo l'ha già fatto quando le ha viste passare, e se lo ricorda. Le serrature di questa voce sono quell'ultimo anello.
Le operazioni permesse sono poche e concrete: mettere dati sulla pila,
duplicarli e confrontarli (OP_DUP, OP_EQUAL), calcolarne l'impronta
(OP_HASH160, OP_SHA256), verificare firme (OP_CHECKSIG,
OP_CHECKMULTISIG), aprire un bivio (OP_IF), vincolare la spesa al tempo
(OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY). Mancano di proposito i
cicli: uno script non può ripetersi, quindi ogni verifica termina di sicuro e
costa un tempo prevedibile. Nel 2010, dopo la scoperta di alcune falle, una
parte degli op fu disabilitata (OP_CAT e altri): da allora il linguaggio è
più stretto di com'era nato.
Le famiglie, in tabella; le serrature della cronologia stanno tutte nelle prime cinque righe.
| famiglia | op principali | a che servono |
|---|---|---|
| costanti e push | OP_0…OP_16, i push diretti |
mettere dati sulla pila (firme, chiavi, impronte) |
| pila | OP_DUP, OP_DROP, OP_SWAP |
duplicare e riordinare ciò che c'è sopra |
| confronto | OP_EQUAL, OP_EQUALVERIFY |
confrontare due elementi in cima |
| hash | OP_HASH160, OP_SHA256 |
calcolare impronte |
| firme | OP_CHECKSIG, OP_CHECKMULTISIG (in tapscript: OP_CHECKSIGADD) |
verificare firme contro chiavi |
| flusso | OP_IF / OP_ELSE / OP_ENDIF, OP_VERIFY, OP_RETURN |
bivi, arresti, output dichiaratamente inspendibili |
| tempo | OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY |
vincolare la spesa a un'altezza o a un'attesa |
| aritmetica (ridotta) | OP_ADD, OP_SUB, i confronti numerici |
piccoli conti su numeri piccoli |
| disabilitati (2010) | OP_CAT, OP_MUL, OP_LSHIFT… |
rimossi dopo le falle; qualcuno oggi si ridiscute |
Conviene vederlo su una serratura vera. Questa è la P2PKH, la serratura degli
indirizzi che iniziano per 1, presa dal più celebre dei pagamenti (i
diecimila bitcoin della pizza, 2010), byte per byte:
Ogni casella è un byte, o un gruppo di byte, col suo valore esadecimale dentro
e il conto dei byte sopra. Le caselle blu sono op, le istruzioni; quelle
gialle sono dati; quelle grigie sono un tipo speciale di byte, il push,
e vale la pena fermarcisi perché ritorna in ogni serratura. Un byte di push non
ordina nulla: dichiara «i prossimi N byte sono dati, mettili sulla pila così
come sono». Il 14 grigio, per esempio, è il numero venti, e annuncia che
seguono venti byte, l'impronta della chiave. È così che lo script separa i dati
dalle istruzioni senza ambiguità: un valore non si confonde mai con un comando,
perché a introdurlo c'è sempre il suo push.
Prima di seguire un'esecuzione conviene mettere in chiaro chi porta che cosa, perché non tutto arriva da chi spende.
La serratura il nodo ce l'ha già. Non gliela manda chi spende: sta scritta sull'output di una transazione precedente, di norma confermata tempo prima, e ogni nodo la conserva nell'UTXO set, l'insieme di tutte le monete spendibili in quel momento. La transazione di spesa si limita a puntarla, dicendo quale transazione passata e quale dei suoi output. Non potrebbe essere altrimenti: se la serratura la portasse chi spende, ciascuno porterebbe la propria.
Da fuori arriva una cosa sola, i dati di sblocco: viaggiano dentro la transazione di spesa, nello scriptSig, e da SegWit in poi in una zona separata della transazione, il witness.
E il messaggio, il testo su cui la firma viene verificata, non viaggia affatto. È la transazione di spesa ridotta a un numero secondo regole fisse, che lasciano fuori i dati di sblocco: se li comprendessero, la firma dovrebbe coprire sé stessa. Chi firma lo calcola prima di firmare, il nodo lo ricalcola per conto suo su quello che ha ricevuto, e i due numeri coincidono solo se la transazione è rimasta quella. Nessuno lo trasmette perché nessuno ha bisogno di riceverlo: la transazione ce l'hanno entrambi.
Resta fuori da questo giro una cosa sola, la chiave privata, che non compare né nella serratura, né nei dati di sblocco, né nel messaggio.
Quanto chi spende debba portare dipende poi dal tipo di serratura: dove c'è un'impronta la chiave va esibita, perché il nodo non ce l'ha; dove c'è già la chiave, basta la firma.
Gli op non si «accendono» a chiamata: si scorre lo script da sinistra a destra, un elemento alla volta, e ogni op agisce quando arriva il suo turno, su ciò che i passi precedenti hanno lasciato sulla pila. Prima però si impilano i dati di sblocco: chi spende premette la propria firma e la propria chiave, e solo dopo si esegue la serratura. Sblocco prima, serratura poi, sulla stessa pila. Nella P2PKH qui sopra l'ordine è questo:
- i dati di sblocco vanno sulla pila: la firma e la chiave pubblica;
OP_DUPduplica la chiave,OP_HASH160ne calcola l'impronta;OP_EQUALVERIFYconfronta quell'impronta con i venti byte scritti nella serratura: se non coincidono, l'esecuzione si ferma qui e la spesa è nulla;OP_CHECKSIGverifica la firma contro la chiave: se regge, lascia «vero» sulla pila e la spesa è valida.
Sono i quattro op e l'unico push che si leggono nella striscia, eseguiti in quell'ordine.
Vale la pena guardare da vicino il passo 4, perché è lì che il meccanismo si
chiude. OP_CHECKSIG non mette a confronto due valori: ricostruisce il testo
che la firma doveva coprire, cioè la transazione ridotta a un numero secondo
regole fisse, e poi verifica che fra quel numero, la chiave pubblica e i due
numeri della firma valga una certa relazione. La relazione torna solo se chi ha
firmato possedeva la chiave privata, e torna solo per quella transazione: la
stessa firma, spostata su un'altra, non tornerebbe. Quali parti della
transazione entrino nel conto lo dichiara la firma stessa, con un byte in coda.
Quello che il controllo accerta si ferma però lì: che chi ha firmato possedeva la chiave in quel momento, e che acconsentiva a quella spesa. Non chi fosse, non se la chiave fosse solo sua, non se gliel'avessero sottratta. Su Bitcoin la proprietà è definita così, come possesso della chiave, e la serratura non ha modo di guardare oltre.
C'è poi un limite dello stesso genere: OP_CHECKSIG giudica la firma che
riceve, non il modo in cui è stata prodotta. Anche quel lato ha condizioni sue,
tutte dalla parte di chi firma: la più delicata riguarda il
nonce, il numero che ogni firma consuma una volta
sola e che non deve ripetersi mai.
Resta una domanda sul linguaggio, e regge tutto il seguito: se permette combinazioni a piacere, perché i tipi di serratura sono una manciata? Perché i nodi, quando decidono se rilanciare una transazione, riconoscono poche forme fisse, gli script standard: fuori da quelle forme una serratura può essere valida per le regole del consenso ma non viaggia bene sulla rete. I tipi della tabella che segue sono precisamente queste forme, e la loro cronologia è la storia di come la lista si è allungata. Col tempo è cambiato anche dove stanno i dati di sblocco (dentro il corpo della transazione, poi in una sezione a parte: se ne parla alla voce SegWit), ma il meccanismo della pila è rimasto quello.
Una manciata di tipi
Prima della cronologia, il colpo d'occhio. Questa tabella si consulta, non si studia: conviene tornarci mentre si leggono le sezioni che seguono.
| serratura | forma (schematica) | indirizzo | quando compare la chiave |
|---|---|---|---|
| P2PK | <chiave> OP_CHECKSIG |
nessuno | subito: la chiave è già sull'output |
| P2PKH | OP_DUP OP_HASH160 <hash chiave> OP_EQUALVERIFY OP_CHECKSIG |
1… |
alla prima spesa |
| bare multisig | m <chiavi…> n OP_CHECKMULTISIG |
nessuno | subito: le chiavi sono sull'output |
| P2SH | OP_HASH160 <hash script> OP_EQUAL |
3… |
alla spesa, quando si rivela lo script |
| P2WPKH | OP_0 <hash chiave, 20 byte> (witness v0) |
bc1q… (corto) |
alla prima spesa |
| P2WSH | OP_0 <hash script, 32 byte> (witness v0) |
bc1q… (lungo) |
alla spesa, quando si rivela lo script |
| P2TR | OP_1 <chiave a 32 byte> (witness v1) |
bc1p… |
subito: la chiave (con tweak) è sull'output; l'albero di script solo se usato |
Le sigle che iniziano per P2 si leggono tutte allo stesso modo: pay to,
«paga a», e il resto dice a che cosa si paga, una chiave pubblica (PK),
l'impronta di una chiave (PKH), l'impronta di uno script (SH), con la W di
witness per le forme segwit e la TR di Taproot.
Fuori tabella restano gli script non standard e le forme che non sono
serrature da spendere (per esempio gli output OP_RETURN, che portano dati e
si sa già che nessuno riscuoterà). La distinzione utile è tra chi mette la
chiave in vista per costruzione (P2PK, bare multisig, e in parte P2TR) e
chi la tiene dietro un'impronta finché non arriva la spesa (le famiglie con
hash: P2PKH, P2SH, P2WPKH, P2WSH).
La cronologia: come sono nate, una dopo l'altra
P2PK, le origini (2009)
La prima serratura è anche la più diretta: la chiave pubblica in chiaro sullo script, seguita dall'ordine di verificare la firma. È la forma degli output di conio dei primi tempi e del primo pagamento mai fatto, da Satoshi a Hal Finney (blocco 170, gennaio 2009). Non ha un indirizzo: si maneggiava la chiave direttamente. Semplice, e per questo esposta: la chiave sta sul registro dal primo momento, senza alcuna schermatura.
P2PKH, l'indirizzo classico (2009)
Poco dopo arriva la forma che ha retto per anni come standard di fatto, quella
degli indirizzi che iniziano per 1. La serratura non porta la chiave ma la
sua impronta, un hash di venti byte; la chiave vera si mostra solo al
momento della spesa, dentro i dati che sbloccano l'output. Due vantaggi: un
indirizzo più corto da scambiare, e una chiave che resta coperta fintanto che
la moneta non si muove. Da qui in poi «indirizzo» diventa sinonimo, nell'uso
comune, di questa impronta codificata. La sua striscia di byte è quella della
sezione sul linguaggio: quattro op e un push attorno all'impronta di venti
byte.
bare multisig, la firma multipla grezza (dal principio, standard nel 2011)
L'operazione per chiedere più firme, m firme valide su n chiavi elencate,
sta nel protocollo fin dall'inizio; come forma riconosciuta dalle regole di
inoltro arriva nel 2011 (BIP 11). Nella versione «grezza» le chiavi stanno per
intero sullo script dell'output, in chiaro. Funziona, ma occupa spazio ed
espone le chiavi per costruzione; con l'arrivo di una soluzione più pulita
(sotto) cade in disuso come forma diretta, e resta soprattutto dentro altre
serrature.
Nella striscia si leggono le due chiavi intere, una dopo l'altra, ciascuna
introdotta dal suo push. A far da cornice ci sono i due numeri della regola:
OP_1 in testa, le firme che servono, e OP_2 in coda, le chiavi elencate,
prima di OP_CHECKMULTISIG. Nessuna impronta, tutto in chiaro.
P2SH, l'impegno a uno script (2012, BIP 16)
Il passo che generalizza l'idea dell'impronta. Invece di impegnare una singola
chiave, la serratura impegna l'hash di uno script intero, il redeem script,
che al momento della spesa va rivelato e soddisfatto. Nascono gli indirizzi che
iniziano per 3. Con P2SH la firma multipla diventa comoda: chi paga vede solo
un indirizzo corto, e la complessità (quante chiavi, quali condizioni) resta
nascosta dietro l'impronta finché non serve. Da qui il multisig si usa quasi
sempre così, dentro P2SH, e non più grezzo.
Ventitré byte in tutto: OP_HASH160, i venti byte dell'impronta dello
script, OP_EQUAL. Che dietro ci sia una singola chiave o un multisig
complicato, da fuori la serratura è identica.
SegWit v0, il witness separato (2017, BIP 141/143)
Un cambiamento strutturale. I dati che sbloccano l'output (firma e chiave, o
script e firme) escono dal corpo della transazione e finiscono in una sezione
a parte, il witness. Due tipi nuovi ricalcano i precedenti:
P2WPKH è il corrispettivo di P2PKH (impronta di una chiave), P2WSH
quello di P2SH (impronta di uno script), con un hash più robusto per gli
script. Cambia anche la codifica dell'indirizzo, che passa a bc1q. La
separazione del witness risolve un difetto storico (la possibilità di
alterare l'identificativo di una transazione prima della conferma) e apre la
strada ai livelli superiori come Lightning.
Le due strisce dicono la semplificazione a colpo d'occhio: OP_0 seguito da
un push e da un'impronta, e nient'altro. Venti byte per la chiave (P2WPKH),
trentadue per lo script (P2WSH): l'unica differenza visibile tra le due è la
lunghezza dell'impronta.
Per la transizione esiste una forma ibrida, il segwit annidato dentro
P2SH: mantiene un indirizzo 3 compatibile con i portafogli vecchi, ma dentro
lavora come segwit. È un ponte, non un tipo nuovo.
Taproot, la chiave e l'albero (2021, BIP 340/341/342)
L'ultima famiglia attiva. Introduce un tipo di firma diverso, più pulito da
verificare e da combinare (Schnorr), e una serratura, P2TR, che tiene
insieme due vie di spesa: una chiave interna, per il caso semplice e
comune, e un albero di script nascosto, che resta invisibile finché non
lo si usa. Chi spende per la via della chiave mostra pochissimo, e le spese
complesse diventano indistinguibili da quelle semplici. Indirizzi che iniziano
per bc1p, con una codifica rivista rispetto a segwit v0. Sul fronte
dell'esposizione, Taproot mette la chiave in vista per costruzione, come P2PK:
sull'output non c'è un'impronta ma la chiave stessa, ritoccata da un piccolo
aggiustamento (il tweak) che impegna l'albero di script. È un tratto che i
pezzi sul quantum computing pesano nei loro conti.
La striscia somiglia a quella di P2WSH, OP_1 al posto di OP_0 e trentadue
byte, ma quei trentadue byte non sono un'impronta: sono la chiave, in chiaro.
Le proposte quantum-resistant (in discussione)
La riga aperta. Di fronte alla prospettiva di una macchina in grado di ricavare la chiave privata da quella pubblica, sono allo studio serrature di nuovo tipo, basate su firme che si ritengono resistenti a quel genere di attacco (la bozza più avanti nel percorso è BIP 360, oggi Pay-to-Merkle-Root), insieme a proposte per ritirare nel tempo le firme legacy (BIP 361). Sono proposte, non parti attive del protocollo. Il perché di tutto questo, e quanto peserebbe, sta nel pezzo sul quantum computing; qui basta segnarne il posto nella fila: il prossimo gradino, se e quando arriverà.
Le codifiche degli indirizzi
Alla cronologia delle serrature corre in parallelo quella delle codifiche, il modo di scrivere un indirizzo. Sono poche e si accompagnano alle famiglie.
| codifica | serrature | indirizzi | note |
|---|---|---|---|
| Base58Check | P2PKH, P2SH | 1…, 3… |
alfabeto senza caratteri ambigui, checksum in coda |
| Bech32 | P2WPKH, P2WSH (witness v0) | bc1q… |
un solo registro di caratteri, comoda nei codici QR, rilevamento degli errori garantito dal checksum |
| Bech32m | P2TR (witness v1) | bc1p… |
variante di Bech32 corretta per le versioni di witness dalla 1 in poi |
Le coppie che si confondono
Alcune distinzioni che, tenute ferme, sciolgono gran parte della confusione:
- serratura ≠ indirizzo: lo scriptPubKey sull'output è la serratura; l'indirizzo è solo una sua codifica leggibile;
- chiave ≠ impronta della chiave: i tipi con hash (P2PKH, P2WPKH) non mostrano la chiave finché non si spende, quelli senza (P2PK, la via chiave di P2TR) la mostrano subito;
- nonce di firma ≠ nonce del blocco: la stessa parola sta in due posti che non c'entrano niente fra loro; quello del mining è pubblico e si cerca a tentativi, quello di firma è segreto e non va cercato affatto;
- nonce ripetuto ≠ chiave debole: la chiave può essere perfetta, è la firma ad averla consegnata;
- segwit annidato ≠ segwit nativo: un indirizzo
3può essere un P2SH qualunque oppure un segwit avvolto in P2SH per compatibilità; da fuori si somigliano, dentro no; - valido ≠ standard: il linguaggio accetta molte più forme di quante i nodi rilancino; i tipi di questa voce sono le forme standard, non tutto il possibile.
In breve
Le serrature di Bitcoin sono poche e si leggono in fila storica: la chiave nuda delle origini (P2PK), l'impronta di una chiave che diventa lo standard (P2PKH), le chiavi multiple messe in chiaro (bare multisig), l'impegno a uno script intero (P2SH), la separazione del witness (P2WPKH e P2WSH), l'unione di chiave e albero di script (P2TR), e la riga ancora aperta delle proposte pensate per un mondo con computer quantistici. Il movimento non è una linea sola: ciò che serve a spendere prima sta in chiaro sull'output, poi arretra dietro un'impronta e si mostra solo alla spesa, e con Taproot torna in vista, per ragioni che con la riservatezza della chiave non c'entrano. Sotto ogni tipo resta la stessa domanda pratica: se e quando la chiave pubblica finisce in chiaro sul registro.
Riferimenti
- BIP 11, M-of-N Standard Transactions: github.com/bitcoin/bips/blob/master/bip-0011.mediawiki
- BIP 16, Pay to Script Hash: github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
- BIP 141, Segregated Witness (Consensus layer): github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
- BIP 143, Transaction Signature Verification for Version 0 Witness Program: github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
- BIP 173, Base32 address format for native v0-16 witness outputs (Bech32): github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
- BIP 340, Schnorr Signatures: github.com/bitcoin/bips/blob/master/bip-0340.mediawiki; BIP 341, Taproot: github.com/bitcoin/bips/blob/master/bip-0341.mediawiki; BIP 342, Tapscript: github.com/bitcoin/bips/blob/master/bip-0342.mediawiki
- BIP 350, Bech32m format for v1+ witness addresses: github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
- BIP 360, Pay-to-Merkle-Root (P2MR) (bozza): github.com/bitcoin/bips/blob/master/bip-0360.mediawiki; BIP 361, Post Quantum Migration and Legacy Signature Sunset (bozza): github.com/bitcoin/bips/blob/master/bip-0361.mediawiki. Il contesto sta nel pezzo «Bitcoin e quantum computing».
- Il linguaggio Script e l'elenco degli op: la pagina Script del wiki di Bitcoin
e, per la semantica di esecuzione, il sorgente di Bitcoin Core,
src/script/interpreter.cpp - A. M. Antonopoulos, D. A. Harding, Mastering Bitcoin (3ª ed., O'Reilly 2023), capitoli su transazioni, Script e indirizzi; il testo è anche in un repo pubblico
- Le pagine tecniche di learn me a bitcoin (G. Walker): percorsi byte per byte su script, transazioni e codifiche
- I numeri di quante monete hanno la chiave già in vista stanno nel pezzo dei dati.