Bitcoin e blockchain collegate, come Liquid di Blockstream, utilizzano l’algoritmo di firma ECDSA per verificare il possesso dei coin e per il loro trasferimento. Con questa decisione tecnica apparentemente presa nel 2008, è stato scelto uno schema di firma che in quel momento fosse ampiamente utilizzato e non sotto brevetto. Tuttavia, ECDSA ha alcune serie limitazioni tecniche. In particolare, multifirma e firme con soglia – firme effettuate da un quorum di parti indipendenti piuttosto che da una singola parte – sono estremamente difficili da riprodurre con ECDSA. Le firme ECDSA hanno una struttura algebrica complessa che le rende inflessibili e complica il loro utilizzo, costringendo gli sviluppatori ad utilizzare gli script Bitcoin per applicazioni come cross-chain atomic swap o Lightning, i quali potrebbero essere implementati in maniera più compatta e privata utilizzando uno schema di firma più flessibile.
Tuttavia, mentre lo stato dell’arte delle firme digitali è avanzato significativamente dal 2008, gli schemi di firma alternativi descritti in letteratura hanno sottovalutato numerosi requisiti per l’utilizzo nel mondo reale. In particolare, spesso assumono che i firmatari abbiano completo controllo su come e quando le loro chiavi sono generate, che dispongano di fonti di casualità perfetta e che abbiano accesso a memoria persistente, affidabile e sicura. Nella pratica, gli utenti di Bitcoin hanno spesso accesso limitato alle proprie chiavi, poco controllo sul meccanismo di generazione delle stesse e nessun controllo su come parti esterne utilizzino gli indirizzi da loro generati. Per affrontare tali problematiche, abbiamo cominciato un percorso per progettare un nuovo schema di firma ed abbiamo messo in atto uno sforzo ingegneristico per implementarlo in modo robusto ed antifragile.
Introduzione
Nella prima metà dello scorso anno, in collaborazione con Yannick Seurin e Gregory Maxwell, il crittografo di Blockstream Pieter Wuille ed io abbiamo pubblicato MuSig, un nuovo schema multifirma. Questo schema multifirma offre sicurezza dimostrabile, persino nei confronti di sottoinsiemi di firmatari collusi e malevoli, e produce firme indistinguibili da firme Schnorr effettuate da un singolo firmatario. Da quel momento in poi, abbiamo trasformato MuSig da un articolo accademico in codice utilizzabile e questa settimana abbiamo incluso tale codice in secp256k1-zkp, un fork di secp256k1, la libreria crittografica ad alta sicurezza utilizzata da Bitcoin Core, che è stata estesa per aggiungere il supporto a Confidential Transactions per Elements e Liquid.
Dal momento che la comunità Bitcoin sta esplorando l’uso delle firme Schnorr, speriamo che il nostro codice verrà eventualmente incluso nella libreria a monte secp256k1 impiegata da Bitcoin Core e molti altri progetti.
Il nostro codice genera firme conformi a BIP-schnorr, e può inoltre produrre adaptor signatures, che possono rendere possibile Lightning con scriptless script.
Perché MuSig?
Come abbiamo discusso lo scorso hanno, la letteratura crittografica annovera numerosi schemi multifirma e una domanda ragionevole è chiedersi perché abbiamo bisogno sviluppare il nostro. La risposta, in breve, è che abbiamo due requisiti che non sono ancora soddisfatti dagli schemi esistenti:
- Firme compatte, a dimensione costante, che sembrano uguali a verificatori indipendentemente dall’insieme dei firmatari. In un sistema blockchain, l’efficienza della verifica è l’aspetto più importante e non ha alcun senso indicare ai verificatori i dettagli della composizione del firmatario se non quelli necessari per prevenire furti. Come beneficio aggiuntivo, le firme MuSig migliorano la privacy in quanto nascondono l’esatta politica di firma.
- Sicurezza dimostrabile nel modello a chiave pubblica nota (“plain public-key model”). Questo significa che i firmatari hanno piena flessibilità nel contribuire ad una multifirma utilizzando chiavi ordinarie, senza fornire ulteriori informazioni riguardo il modo specifico in cui queste chiavi sono state prodotte o sono controllate. Le informazioni su come le chiavi sono state generate potrebbero essere difficili da fornire in un contesto come Bitcoin siccome i singoli firmatari hanno politiche di gestione delle chiavi variegate e restrittive. Inoltre una dipendenza sulla generazione dell’algoritmo di firma potrebbe interagire male con Taproot, un’estensione proposta per Bitcoin con la quale le chiavi pubbliche utilizzate nelle firme possono avere un significato aggiuntivo ed invisibile codificato in esse.
In aggiunta, dall’annuncio di MuSig, abbiamo imparato che molti schemi di firma pubblicati, tra cui una precedente versione non pubblicata di MuSig, sono in realtà insicuri! Esploreremo questo ulteriormente in un blog post futuro, ma per ora è sufficiente dire che il nostro lavoro è il risultato dello sviluppo di uno schema multifirma per Bitcoin e Liquid.
Insidie e sviluppo di una API sicura
Come tutte le descrizioni matematiche di schemi multifirma, MuSig, come pubblicato, assume che i partecipanti abbiano accesso a memoria persistente durante il protocollo di firma, facilmente aggiornabile, e che può essere resettata a stati precedenti da attaccanti. Assume inoltre che i firmatari abbiano accesso a fonti di casualità indistinguibili da una distribuzione uniforme. Sfortunatamente il mondo reale non è così semplice e abbiamo speso uno sforzo considerevole nel progettare una API che potesse essere utilizzata in numerosi scenari senza la possibilità che hardware limitato o assunzioni non dichiarate portino alla perdita delle chiavi segrete.
Le firme MuSig, proprio come le firme Schnorr e ECDSA, utilizzano nella loro costruzione un segreto “nonce” che deve essere prodotto in maniera uniformemente casuale. Qualsiasi deviazione dalla distribuzione uniforme, anche di un singolo bit, può condurre alla perdita della chiave privata e al furto dei fondi.
Il nostro obbiettivo primario era di creare una API che fosse resistente ad un uso non corretto, semplice da utilizzare e che non incoraggi schemi di utilizzo pericolosi in ambienti vincolati.
Casualità Uniforme
Con firme singole, l’approccio standard per ottenere “nonce” uniformemente casuali è semplice: prendi un dato segreto e il messaggio da firmare e passa questi ad una funzione crittografica di hash per ottenere un valore uniformemente casuale che sarà indipendente dal messaggio firmato.
Tuttavia, in una multifirma, questa soluzione ovvia e robusta diventa un ostacolo. Un firmatario malevolo potrebbe richiedere due multifirme per il medesimo messaggio, aggiustando opportunamente il proprio contributo alla firma nella seconda iterazione. Se il primo firmatario sceglie il suo “nonce” facendo l’hash di un segreto e del messaggio, finirà per usare lo stesso “nonce” in due firme differenti – essenzialmente lo stesso errore che ha causato un attacco informatico alla PS3. Sfortunatamente a differenza del caso con una singola firma, non vi è una soluzione semplice poiché firmatari devono scegliere i loro “nonce” prima di conoscere tutti i dettagli della firma che vogliono generare.
Una soluzione tradizionale a questo problema, utilizzata prima che l’uso dell’hash divenisse popolare, è utilizzare un generatore di numeri casuali hardware. Purtroppo, questi dispositivi sono costosi, soggetti a distorsioni ambientali o altre forme di influenza esterna e, soprattutto, non vi è modo di verificarne il corretto funzionamento.
L’ultimo punto, sulla verifica, ha alcune soluzioni creative che esploreremo in un prossimo articolo. Per ora, la nostra scelta è stata di richiedere agli utilizzatori dell’API di fornire un unico “session ID” per ogni sessione di firma. I “nonce” sono prodotti facendo l’hash del segreto del firmatario, l’insieme dei firmatari, il messaggio da firmare ed infine l’input per la specifica sessione. Utenti che hanno accesso ad un generatore di numeri casuali potranno utilizzarlo per produrre “session ID”; coloro che che hanno accesso a memoria persistente potrebbero utilizzare un semplice contatore.
Non siamo soddisfatti di richiedere numeri casuali o memoria persistente e ci aspettiamo che la nostra continua ricerca sarà presto in grado di trovare una soluzione realmente robusta.
Attacchi Ripetuti
Anche con una solida fonte di casualità, è ancora possibile estrarre le chiavi segrete da un partecipante in uno schema multifirma, se è possibile ripetere un protocollo di firma da un punto a metà del processo. Questo tipo di attacco è detto attacco ripetuto (“replay attack”) e può essere portato a termine nei confronti di un firmatario che funziona all’interno di una macchina virtuale che possa essere riavviata, oppure una che supporti l’interruzione del processo di firma e il ripristino da un qualche stato serializzabile. Potrebbe anche accadere fortuitamente senza un attaccante attivo, ad esempio eseguendo due macchine virtuali clonate da uno stesso stato, oppure eseguendo codice su un database distribuito che non è più sincronizzato.
Precisamente, se un firmatario contribuisce ad una multifirma e il processo di firma e ricominciato ad un punto successivo alla scelta del suo “nonce”, è possibile modificare i contributi degli altri firmatari per eseguire un attacco analogo a quello descritto sopra.
Questo tipo di attacco non è presente nel caso di firme singole in quanto queste sono prodotte in un unico step, senza stati intermedi dai quali ripristinare. Queste sfide supplementari sono uniche dei protocolli crittografici multi-round.
Senza nuovi meccanismi, che sono un argomento che stiamo attivamente studiando, non vi è nulla che possiamo fare per proteggere utenti che firmano in macchine virtuali. Possiamo però osservare che utilizzare macchine virtuali implica di per sé una sicurezza inferiore, in quanto un macchina che può essere riavviata da un attaccante è verosimilmente una macchina da cui l’attaccante stesso può direttamente estrarre i segreti.
Per proteggere i firmatari che potrebbero serializzare stati obsoleti e ricominciare da essi, la nostra API non supporta la serializzazione delle sessioni di firma.
Ciò, in pratica, significa che gli utilizzatori del nostro codice che vogliono supportare sessioni di firma in grado di sopravvivere a ripristini o interruzioni di alimentazione – che è un obbiettivo ragionevole per un hardware wallet – devono mantenere memoria sicura e persistente. Se tali wallet vogliono supportare molteplici sessioni di firma in parallelo, richiederanno memoria persistente addizionale per ogni sessione parallela.
Ancora, crediamo che saremo in grado di eliminare questa limitazione utilizzando approcci oggetto della nostra ricerca.
Conclusione e Lavoro Futuro
L’osservazione implicita in tutta la discussione precedente è che i protocolli tra più parti presentano sfide nuove e notevolmente più difficili rispetto ai protocolli con una singola parte. In termini di complessità matematica, MuSig è più semplice di, per esempio, Bulletproofs. Ma in termini di implementazione, MuSig ha richiesto maggiori sforzi e trade-off tra antifragilità e flessibilità delle API.
Questo articolo descrive solamente multifirma – le firme nelle quali n firmatari collaborano per produrre una singola firma. In un prossimo post discuteremo le firme con soglia (“threshold signatures”), un’idea simile nella quale un qualunque sottoinsieme degli n firmatari, purché siano in numero sufficiente, è in grado di produrre firme senza il contributo dell’intero gruppo.
Nei prossimi articoli discuteremo inoltre alcune tecniche per rendere la generazione di casualità del “nonce” più sicura e verificabile. In particolare, utilizzando una tecnica detta sign-to-contract è possibile per un host eliminare ogni possibile distorsione da un generatore di numeri casuali hardware inaffidabile.
Procedendo ulteriormente, sfruttando le zero knowledge proofs dovrebbe essere possibile eliminare i rischi indotti da fonti di casualità distorta e attacchi ripetuti, rimuovere i requisiti di memoria persistente e ridurre il protocollo MuSig da tre a due round. Siamo entusiasti di questa nuova possibilità e non vediamo l’ora di condividere i nostri risultati mentre continuano a svilupparsi.
Il nostro codice è disponibile pubblicamente su GitHub e vi incoraggiamo a giocarci e ad inviarci i vostri feedback!