Home
Articoli
Migliorare la trasparenza crypto con le prove a conoscenza zero

Migliorare la trasparenza crypto con le prove a conoscenza zero

Intermedio
Pubblicato Feb 10, 2023Aggiornato Aug 9, 2023
10m

TL;DR

Una dimostrazione a conoscenza zero consente a una parte (un verifier) di determinare la validità di un'affermazione data da un'altra parte (il prover) senza alcuna conoscenza sul contenuto dell'affermazione. Ad esempio, Binance potrebbe voler dimostrare di avere le riserve necessarie per garantire interamente i fondi dei suoi utenti senza rivelare tutti i saldi dei singoli utenti.

Una "Prova delle Riserve" potrebbe essere costruita con un Merkle tree che protegge dalla falsificazione dei dati interni, in questo caso i saldi netti totali dei clienti, che rappresentano le passività dell'exchange nei confronti dei suoi utenti. Questo può essere combinato con uno zk-SNARK (un protocollo di dimostrazione a conoscenza zero) che assicura che gli utenti possano verificare che il loro saldo faccia parte del saldo netto totale degli utenti senza conoscere i saldi individuali.

Introduzione

In seguito ai recenti eventi di mercato, la sicurezza dei crypto asset in custodia presso una terza parte è diventata un argomento critico. Gli utenti blockchain apprezzano molto la trasparenza e l'apertura di questo ecosistema, ma vogliono anche privacy e riservatezza. Questo crea un dilemma quando si tratta di dimostrare le riserve dei fondi detenute dai custodian (la terza parte che ha in custodia i fondi). Spesso si arriva ad un compromesso tra trasparenza, fiducia e riservatezza dei dati.

Tuttavia, non è necessario che sia così. Combinando protocolli di dimostrazioni a conoscenza zero come gli zk-SNARK con i Merkle tree, possiamo trovare una soluzione efficace per tutte le parti.

Cos'è la dimostrazione a conoscenza zero?

Una dimostrazione a conoscenza zero consente a una parte (un verifier) di determinare la validità di un'affermazione data da un'altra parte (il prover) senza conoscere il contenuto dell'affermazione. Vediamo un esempio semplice.

Hai una cassaforte chiusa di cui solo tu conosci la soluzione. La cassaforte, in questo esempio, non può essere scassinata, forzata o aperta in nessun altro modo se non conoscendo la combinazione. Tale caratteristica è stabilita, verificata e conosciuta anche dal tuo amico che partecipa all'esperimento.

Dici al tuo amico di conoscere la combinazione, ma non vuoi rivelarla o aprire la cassaforte davanti a lui. In cima alla cassaforte c'è un foro dove il tuo amico può inserire un biglietto. Affinché questa sia una dimostrazione a conoscenza zero, il tuo amico non deve avere altre informazioni sul processo oltre alla dichiarazione data.

Puoi dimostrare al tuo amico che conosci la combinazione aprendo la scatola, dicendogli cosa c'era scritto sul biglietto e richiudendola. Tuttavia, in nessun momento, hai rivelato la combinazione.

Per un esempio più avanzato, leggi il nostro articolo Cos'è la dimostrazione a conoscenza zero e che impatto ha sulla blockchain? .

Perché usiamo la dimostrazione a conoscenza zero?

Le dimostrazioni a conoscenza zero sono adatte per dimostrare qualcosa senza rivelare informazioni o dettagli sensibili. Questo potrebbe essere il caso se non vuoi consegnare le tue informazioni finanziarie o personali che potrebbero essere utilizzate in modo inappropriato.

Nel mondo crypto, si può dimostrare di possedere una chiave privata senza rivelarla o firmare digitalmente qualcosa. Un exchange di criptovalute potrebbe anche voler dimostrare lo stato delle sue riserve senza rivelare informazioni riservate sui suoi utenti, compresi i saldi dei loro conti individuali. 

Per questi esempi (e per molti altri), una dimostrazione a conoscenza zero utilizzerebbe algoritmi che prendono un dato come input e restituiscono "vero" o "falso" come output. 

Definizione delle dimostrazioni a conoscenza zero in termini tecnici

Una dimostrazione a conoscenza zero, in termini tecnici, segue una struttura specifica con determinati criteri. Abbiamo già parlato dei ruoli di prover e verifier, ma ci sono anche tre criteri che una dimostrazione a conoscenza zero dovrebbe soddisfare:

  1. Completezza. Se l'affermazione è vera, un verifier sarà convinto dalla prova fornita, senza bisogno di altre informazioni o verifiche.

  2. Solidità. Se l'affermazione è falsa, un verifier non sarà convinto della verità dell'affermazione tramite la prova fornita.

  3. Conoscenza zero. Se l'affermazione è vera, il verifier non apprende alcuna informazione oltre al fatto che l'affermazione è vera.

Cos'è uno zk-SNARK?

Uno zk-SNARK (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) è un protocollo di prova che segue i principi di conoscenza zero precedentemente illustrati. Con uno zk-SNARK, puoi dimostrare di conoscere il valore originale sottoposto ad hashing (discusso più avanti) senza rivelare quale sia. È inoltre possibile dimostrare la validità di una transazione senza rivelare alcuna informazione su importi, valori o indirizzi specifici.

Gli zk-SNARK sono comunemente usati e discussi nel mondo della blockchain e delle criptovalute . Forse ti stai chiedendo perché qualcuno dovrebbe preoccuparsi di usare uno zk-SNARK quando potrebbe usare un semplice metodo che sfrutta una coppia di chiavi pubbliche e private per proteggere le informazioni. In questo modo, non potremmo implementare una prova matematica che garantisca che non vengano inclusi saldi negativi nella somma del Merkle tree. 

Nel caso delle riserve di un exchange, vogliamo dimostrare la copertura 1:1 dei saldi dei clienti senza che gli identificatori e i saldi di ogni conto siano resi pubblici. Inoltre, la tecnologia zk-SNARK rende ancora più improbabile la falsificazione dei dati.

Cos'è un Merkle tree?

Presentare i fondi sommati dei conti degli utenti di Binance richiede di lavorare con un grande insieme di dati. Un modo per mostrare questa grande quantità di dati in modo crittografico è quello di utilizzare un Merkle tree. Al suo interno è possibile memorizzare in modo efficiente una grande quantità di informazioni e la sua natura crittografica ne rende facilmente verificabile l'integrità.

Funzioni di hash

Per codificare sinteticamente un input, un Merkle tree dipende dall'utilizzo delle funzioni di hash. In breve, con hashing si intende il processo che genera un output di dimensione fissa partendo da un input di dimensioni variabili. In altre parole, quando un input di qualsiasi lunghezza viene sottoposto ad hashing tramite un algoritmo, produrrà un output criptato di lunghezza fissa.

Finché l'input rimane lo stesso, lo sarà anche l'output. Questo significa che possiamo prendere enormi quantità di dati transazionali e trasformarli in un output gestibile. L'output sarà radicalmente diverso se una qualsiasi informazione viene modificata nell'input.

Ad esempio, possiamo prendere il contenuto di 100 libri e inserirli nella funzione di hash SHA-256. Il risultato sarà qualcosa di simile a questo:

801a9be154c78caa032a37b4a4f0747f1e1addb397b64fa8581d749d704c12ea

Se poi cambiassimo un singolo carattere dell'input (quei 100 libri), l'hash sarebbe completamente diverso, risulterebbe qualcosa del tipo:

abc5d230121d93a93a25bf7cf54ab71e8617114ccb57385a87ff12872bfda410

Si tratta di una proprietà importante delle funzioni di hash, perché consente di verificare facilmente l'accuratezza dei dati. Se qualcuno replica il processo di hashing degli stessi 100 libri utilizzando l'algoritmo SHA-256, otterrà lo stesso identico hash come output. Se l'output è diverso, possiamo affermare con certezza che l'input è stato modificato. Ciò significa che non è necessario verificare individualmente o manualmente le differenze tra gli input, cosa che può richiedere molto lavoro.

I Merkle tree nel mondo delle criptovalute

Nell'archiviazione dei dati delle transazioni su una blockchain, ogni nuova transazione viene sottoposta a una funzione di hash, che genera valori di hash unici. Immaginiamo di avere otto transazioni (da A a H), ciascuna sottoposta individualmente ad hashing per ottenere i relativi output. Questi sono i cosiddetti nodi foglia Merkle. Nell'immagine sottostante, puoi vedere il valore di hash univoco di ciascuna lettera: hA per A, hB per B, hC per C, ecc.

Possiamo quindi prendere coppie di output sottoposti ad hashing, combinarle e ottenere un nuovo hash output. Gli hash di hA e hB combinati insieme, ad esempio, ci daranno un nuovo hash output hAB, noto come ramo Merkle. Nota che ogni volta che viene generato un nuovo risultato, questo ha una lunghezza e una dimensione fissa, a seconda della funzione di hash utilizzata.

Ora abbiamo i dati di due transazioni (ad esempio, A e B) combinati in un unico hash (hAB). Nota che se cambiamo una qualsiasi informazione di A o B e ripetiamo il processo, il nostro hash output hAB sarà completamente diverso.

Il processo continua con la combinazione di nuove coppie di hash per ottenere un nuovo hash (vedi l'immagine seguente). Effettuiamo l'hashing di hAB con hCD per ottenere un hash unico hABCD e facciamo lo stesso con hEF e hGH per ottenere hEFGH. Alla fine, otteniamo un unico hash che rappresenta l'hash output di tutti gli hash delle transazioni precedenti. In altre parole, l'hash output hABCDEFGH rappresenta tutte le informazioni che lo hanno preceduto.

Il grafico mostrato sopra è chiamato Merkle tree e l'hash output hABCDEFGH è la Merkle root. Utilizziamo le Merkle root negli header dei blocchi, in quanto riassumono crittograficamente tutti i dati delle transazioni in un blocco in modo conciso. Possiamo anche verificare rapidamente se i dati sono stati manomessi o modificati all'interno del blocco.

I limiti dei Merkle Tree

Torniamo al nostro esempio delle riserve su un CEX. Un CEX vuole dimostrare la copertura 1:1 di tutti gli asset dei suoi clienti e costruisce un Merkle tree che mette insieme gli UID dei suoi clienti con il loro patrimonio netto (compensando asset e passività) a livello di token. Una volta rilasciato (e firmato per dimostrare la proprietà della Merkle root fornita), un singolo utente non avrebbe modo di verificare se il Merkle tree è valido senza accedere a tutti i suoi input.

Un exchange potrebbe non aver incluso alcuni input. Potrebbe anche aver creato dei conti falsi con saldi negativi per alterare la passività totale. Ad esempio, sebbene gli asset dei clienti possano ammontare a 1.000.000$, potrebbe aggiungere un conto falso con un saldo di -500.000$. In questo modo creerebbe un target delle riserve pari a soli 500.000$

Il contesto della prova delle riserve è diverso dalla Merkle root di un blocco, poiché gli utenti possono vedere tutte le transazioni contenute in un blocco su un blockchain explorer. Un CEX, tuttavia, non vorrà rivelare il saldo di ogni conto per ragioni di sicurezza e riservatezza dei dati. Anche i clienti non sarebbero contenti di rendere pubblici i saldi dei loro conti. In questo caso, il CEX non può dimostrare che i saldi degli utenti raggiungono il totale corretto senza rendere visibili i saldi degli altri utenti.

Una soluzione che gli exchange possono prendere in considerazione è l'utilizzo di un revisore di terze parti fidato. Il revisore può controllare i singoli conti e le riserve prima di attestare la validità della Merkle root fornita. Tuttavia, per gli utenti questo metodo richiede fiducia nel revisore e nei dati utilizzati per la verifica. Non serve affidarsi a una terza parte quando puoi fidarti dei dati.

Combinare zk-SNARK e Merkle tree

Il problema descritto sopra è un caso perfetto per l'utilizzo degli zk-SNARK. Vogliamo dimostrare che le riserve coprono completamente le passività degli utenti e non sono state falsificate. Tuttavia, per motivi di privacy e sicurezza, non vogliamo mostrare al verifier l'esatta composizione dei saldi e delle riserve degli utenti. 

Utilizzando uno zk-SNARK, un exchange di criptovalute può dimostrare che l'elenco di tutti i bilanci dei nodi foglia del Merkle tree (cioè i saldi dei conti degli utenti) contribuiscono al bilancio totale degli utenti dichiarato dall'exchange. Ogni utente può facilmente accedere al proprio nodo foglia come se fosse stato incluso nel processo. Lo zk-SNARK garantisce inoltre che il Merkle tree generato non contenga utenti con un saldo netto totale negativo (il che implicherebbe la falsificazione dei dati, poiché tutti i prestiti sono sovracollateralizzati). Inoltre, viene calcolato lo stato globale di Binance, ovvero l'elenco del saldo netto totale di ogni asset detenuto da ciascun cliente di Binance.

Vediamo come Binance gestisce la situazione. Per cominciare, Binance definisce i vincoli della computazione che vuole dimostrare e li definisce sotto forma di circuito programmabile. Di seguito è riportato l'insieme dei tre vincoli che Binance utilizza nel suo modello 

Per l'insieme dei bilanci di ogni utente (nodo foglia del Merkle tree), il nostro circuito garantisce che:

  1. I saldi degli asset di un utente sono inclusi nel calcolo della somma dei saldi netti totali degli utenti su Binance.

  2. Il saldo netto totale dell'utente è maggiore o uguale a zero.

  3. La variazione della Merkle tree root è valida (cioè non utilizza informazioni falsificate) dopo l'aggiornamento delle informazioni di un utente al livello dell'hash del nodo foglia.

Binance può quindi generare una prova zk-SNARK per la costruzione del Merkle tree in base al circuito. Questo comporta che l'exchange esegua pesanti calcoli di hashing degli ID e dei saldi degli utenti, assicurandosi che la prova soddisfi i vincoli.

Un verifier esaminerà la prova (e il suo codice open-source rilasciato pubblicamente) per convincersi che la computazione è stata eseguita rispettando tutti i vincoli. La computazione della verifica richiede un tempo estremamente ridotto rispetto al tempo di dimostrazione.

Ad ogni rilascio di una Prova delle Riserve, l'exchange pubblicherà:

1. La Merkle proof per ogni utente.

2. La prova zk-SNARK e l'input pubblico (un hash dell'elenco del saldo netto totale di ogni asset e della Merkle root) del circuito per tutti gli utenti.

Le parti interessate possono verificare la Merkle proof, assicurandosi che i loro saldi individuali abbiano contribuito alla Merkle tree root. Possono anche verificare la prova zk-SNARK per assicurarsi che la costruzione del Merkle tree soddisfi i vincoli definiti nel circuito. Per una spiegazione più dettagliata della soluzione zk-SNARK e delle sue performance, leggi l'articolo del nostro blog Come gli zk-SNARK migliorano il sistema di Prova delle Riserve di Binance.

In chiusura

Gli zk-SNARK forniscono la tecnologia necessaria per garantire l'integrità dei dati e allo stesso tempo la privacy. La sua applicazione per dimostrare le riserve e aumentare la trasparenza dei CEX dovrebbe contribuire a creare fiducia nel settore blockchain. Per molti, uno sviluppo come questo era atteso da tempo e arriva in un momento cruciale per i CEX.

Questa è la prima versione del nostro zk-SNARK e siamo ansiosi di ricevere i feedback della community in modo da poter continuare a migliorare il sistema.

Letture consigliate