zk-SNARKs sind ein leistungsstarkes kryptografisches Tool, das zu einem immer wichtigeren Bestandteil sowohl von Blockchain- als auch von Nicht-Blockchain-basierten Anwendungen geworden ist. Ihre Komplexität zeigt sich sowohl im Verständnis ihrer Funktionsweise als auch darin, wie sie effektiv genutzt werden können. In diesem Artikel wird untersucht, wie sich zk-SNARKs an aktuelle Anwendungen anpassen, es werden Beispiele dafür gegeben, was sie leisten können und was nicht, und es werden allgemeine Richtlinien dazu gegeben, wann zk-SNARKs für bestimmte Anwendungen geeignet sind. Ein besonderer Schwerpunkt wird auf ihrer Rolle bei der Gewährleistung der Privatsphäre liegen.
Stellen Sie sich vor, Sie hätten eine öffentliche Eingabe x, eine private Eingabe w und eine (öffentliche) Funktion f(x,w) → {True,False}, die die Eingaben validiert. Mit zk-SNARKs kann man beweisen, dass sie aw kennen, sodass für ein gegebenes f und x f(x,w) = True ist, ohne preiszugeben, was w tatsächlich ist. Darüber hinaus können Prüfer den Beweis viel schneller authentifizieren, als sie f(x,w) berechnen könnten, selbst wenn sie w wüssten.
Dies verleiht zk-SNARKs zwei Eigenschaften: Datenschutz und Skalierbarkeit. Wie bereits erwähnt, konzentrieren sich unsere Beispiele in diesem Artikel hauptsächlich auf den Datenschutzaspekt.
Angenommen, Sie besitzen ein Ethereum-Wallet und möchten nachweisen, dass dieses Wallet im Rahmen eines Proof-of-Humanity-Systems registriert ist, ohne offenzulegen, wer die registrierte Person tatsächlich ist. Diese Funktion kann mathematisch beschrieben werden als:
Private Eingabe (w): Ihre Adresse A, Ihr privater Adressschlüssel k
Öffentliche Eingabe (x): Adresssatz aller verifizierten Proof-of-Humanity-Profile {H1…Hn}
Verifizierungsfunktion f(x,w):
Interpretieren Sie w als Paar (A, σ) und x als gültige Profilliste {H1…Hn}
Stellen Sie sicher, dass A eine der Adressen in {H1…Hn}ist.
Bestätigen Sie privtoaddr(k) = A
Wenn beide Überprüfungen bestanden sind, geben Sie „True“ zurück. Wenn einer von ihnen fehlschlägt, geben Sie „False“ zurück.
Der Prüfer generiert seine Adresse A und den zugehörigen Schlüssel k und stellt w=(A,k) als private Eingabe für f bereit. Sie erhalten den öffentlichen Input, den aktuellen Satz verifizierter Proof-of-Humanity-Profile {H1…Hn}, aus der Kette. Anschließend führen sie den zk-SNARK-Beweisalgorithmus aus, der (vorausgesetzt, die Eingabe ist korrekt) einen Beweis erstellt. Dieser Nachweis wird zusammen mit der Blockhöhe, aus der die verifizierte Profilliste abgerufen wurde, an den Verifizierer gesendet.
Der Verifizierer liest auch die Kette, ruft die Liste {H1…Hn} ab der vom Prüfer angegebenen Höhe ab und prüft den Beweis. Wenn die Verifizierung erfolgreich ist, geht der Verifizierer davon aus, dass der Prüfer über ein verifiziertes Proof-of-Humanity-Profil verfügt.
Bevor ich mich mit komplexeren Beispielen befasse, empfehle ich dringend, das obige Beispiel vollständig zu verstehen.
Ein Nachteil des oben genannten Beweissystems besteht darin, dass der Verifizierer den gesamten Profilsatz {H1…Hn} kennen muss, was O(n) Zeit benötigt, um diesen Satz in den zk-SNARK-Mechanismus „einzugeben“. Dieses Problem kann gelöst werden, indem die On-Chain-Merkle-Wurzel, die alle Profile umfasst, als öffentliche Eingabe verwendet wird (möglicherweise nur die Staatswurzel). Wir fügen eine weitere private Eingabe hinzu, einen Merkle-Beweis M, der bestätigt, dass sich das Konto A des Prüfers im relevanten Teil des Baums befindet.
Eine sehr neue und effizientere Alternative zu Merkle-Beweisen für ZK-Mitgliedschaftsnachweise ist Caulk. In Zukunft könnten einige dieser Anwendungsfälle auf ähnliche Lösungen wie Caulk umgestellt werden.
Projekte wie Zcash und Tornado.cash ermöglichen es uns, datenschutzfreundliche Währungen zu besitzen. Nun könnte man meinen, sie könnten die erwähnten „ZK-Menschenbeweise“ nutzen, aber es geht nicht darum, den Zugang zu menschlichen Profilbeweisen zu beweisen; es geht darum, den Zugang zu Münzen nachzuweisen. Hier liegt ein Problem: Wir müssen uns gleichzeitig mit Datenschutz und Doppelausgaben befassen. Das heißt, wir sollten nicht zweimal dieselbe Münze ausgeben.
So lösen wir es: Wer eine Münze besitzt, hat ein privates Geheimnis „s“. Sie berechnen lokal ein „Blatt“ L=hash(s,1), das in der Kette veröffentlicht wird und Teil des Zustands N=hash(s,2) wird, den wir Nullifier nennen. Der Zustand wird in einem Merkle-Baum gespeichert.
Um eine Münze auszugeben, muss der Absender ein ZK-SNARK vorlegen, wobei:
Zu den öffentlichen Eingaben gehören ein Nullifier N, die aktuelle oder aktuelle Merkle-Wurzel R und ein neues Blatt L' (für den Empfänger gedacht, der ein geheimes s' als L'=hash(s',1) an den Absender übergeben hat).
Private Eingaben umfassen ein Geheimnis s, ein Blatt L und einen Merkle-Zweig M.
Die Verifizierungsfunktion prüft:
M ist ein gültiger Merkle-Zweig, was beweist, dass L ein Blatt des Baums ist, dessen Wurzel bei R liegt, wobei R die Merkle-Wurzel des aktuellen Zustands ist.
Hash(s,1)=L und Hash(s,2)=N.
Die Transaktion enthält den Nullifier N und das neue Blatt L'. Wir beweisen eigentlich nichts über L', aber es wird in den Beweis „eingemischt“, um eine Änderung durch Dritte während der Transaktion zu verhindern. Um die Transaktion zu validieren, verifiziert die Kette das ZK-SNARK und prüft, ob N in früheren Transaktionen verwendet wurde. Bei Erfolg wird N zum Satz verbrauchter Nullifizierer hinzugefügt, wodurch dieser wieder unbrauchbar wird. L' wird zum Merkle-Baum hinzugefügt.
Mithilfe von ZK-SNARKs verknüpfen wir zwei Werte: L (erscheint auf der Kette, wenn die Münze geprägt wird) und N (erscheint, wenn sie ausgegeben wird), ohne offenzulegen, welches L mit welchem N verbunden ist. Die Verbindung zwischen L und N ist nur erkennbar, wenn Sie Kennen Sie die Geheimnisse, die sie erzeugen. Jede geprägte Münze kann einmal verwendet werden (da es für jedes L nur ein gültiges N gibt), die jeweils verwendete konkrete Münze bleibt jedoch verborgen.
Dies ist ein entscheidendes Grundelement, das es zu begreifen gilt. Darauf basieren viele Mechanismen, die wir im Folgenden beschreiben, allerdings mit unterschiedlichen Zwecken.
Das oben Gesagte lässt sich leicht auf Münzen mit beliebigem Guthaben erweitern. Wir behalten das Konzept einer „Münze“ bei, aber jede Münze trägt ein (privates) Guthaben. Eine einfache Möglichkeit, dies zu erreichen, besteht darin, dass jede Münze über eine Kettenspeicherung verfügt, nicht nur mit Blatt L, sondern auch mit einem verschlüsselten Guthaben. Jede Transaktion würde zwei Münzen verbrauchen und zwei neue erstellen, wodurch zwei Paare (Blatt, verschlüsseltes Guthaben) zum Zustand hinzugefügt würden. Das ZK-SNARK überprüft außerdem, ob die Summe der Eingangssalden der Summe der Ausgangssalden entspricht und beide Ausgangssalden nicht negativ sind.
Ein faszinierendes Anti-DOS-Tool: Stellen Sie sich vor, Sie haben eine On-Chain-Identität, die nicht einfach zu erstellen ist; Es könnte sich um ein menschensicheres Profil oder 32 ETH-Validatoren oder einfach um ein Konto mit einem ETH-Guthaben ungleich Null handeln. Wir könnten ein DOS-resistenteres Peer-to-Peer-Netzwerk schaffen, indem wir nur Nachrichten akzeptieren, die beweisen, dass der Absender über ein Profil verfügt. Für jedes Profil wären bis zu 1000 Nachrichten pro Stunde zulässig. Wenn ein Absender betrügt, wird sein Profil aus der Liste entfernt. Aber wie stellen wir die Privatsphäre sicher?
Zuerst das Setup: Sei k der private Schlüssel des Benutzers und A=privtoaddr(k) die entsprechende Adresse. Eine Liste gültiger Adressen ist öffentlich (z. B. ein On-Chain-Register). Bisher spiegelt dies das Beispiel des Menschenbeweises wider: Sie müssen nachweisen, dass Sie den privaten Schlüssel zu einer Adresse besitzen, ohne preiszugeben, welche. Aber wir wollen nicht nur den Beweis, dass Sie auf der Liste stehen. Wir benötigen ein Protokoll, mit dem Sie beweisen können, dass Sie auf der Liste stehen, das Ihre Beweise jedoch einschränkt.
Wir teilen die Zeit in Perioden auf, die jeweils 3,6 Sekunden dauern (also 1000 Perioden pro Stunde). Unser Ziel ist es, dass jeder Benutzer pro Zeitraum nur eine Nachricht senden kann. Wenn sie zwei im gleichen Zeitraum senden, werden sie erwischt. Um gelegentliche Ausbrüche zu ermöglichen, können sie aktuelle Zeiträume verwenden. Wenn ein Benutzer also 500 ungenutzte Zeiträume hat, kann er 500 Nachrichten auf einmal senden.
Beginnen wir mit einer Basisversion, die Nullifier verwendet. Ein Benutzer generiert einen Nullifier mit (N = \text{hash}(k, e)), wobei (k) sein Schlüssel und (e) eine Epochennummer ist, und veröffentlicht ihn dann mit der Nachricht (m). ZK-SNARK verschleiert dann (\text{hash}(m)). In diesem Prozess wird nichts über (m) verifiziert, sodass der Beweis an eine einzelne Nachricht gebunden ist. Wenn ein Benutzer zwei Beweise mit demselben Nullifier an zwei unterschiedliche Nachrichten bindet, besteht die Gefahr, dass er erwischt wird.
Jetzt wechseln wir zu einer komplexeren Version. In diesem Szenario gibt das nachfolgende Protokoll seinen privaten Schlüssel preis und bestätigt nicht nur, ob jemand dieselbe Epoche zweimal verwendet hat. Unsere zentrale Technik basiert auf dem Prinzip, dass „zwei Punkte eine Linie bestimmen“. Das Aufdecken eines Punktes auf einer Linie verrät wenig, aber das Aufdecken von zwei Punkten enthüllt die gesamte Linie.
Für jede Epoche (e) wählen wir eine Linie (L_e(x) = \text{hash}(k, e) \times x + k). Die Steigung der Linie ist (\text{hash}(k, e)) und der y-Achsenabschnitt ist (k), beide sind der Öffentlichkeit unbekannt. Um ein Zertifikat für die Nachricht (m) zu erstellen, stellt der Absender (y = L_e(\text{hash}(m)) = \text{hash}(k, e) \times \text{hash}(m) + k bereit ), zusammen mit einem ZK-SNARK-Beweis, dass die Berechnung von (y) korrekt ist.
Zusammenfassend lautet ZK-SNARK wie folgt:
({A_1…A_n}): Eine Liste gültiger Konten
(M): Die Nachricht, die durch das Zertifikat validiert wird
(E): Die Epochennummer für das Zertifikat
(Y): Auswertung der Linienfunktion
Überprüfen Sie, ob (\text{privtoaddr}(k)) in ({A_1…A_n}) existiert.
Bestätige (y = \text{hash}(k, e) \times \text{hash}(m) + k)
Was aber, wenn jemand eine Epoche zweimal verwendet? Sie würden zwei Werte (m_1) und (m_2) zusammen mit ihren Zertifikatswerten (y_1 = \text{hash}(k, e) \times \text{hash}(m_1) + k) und (y_2 = \text{hash}(k, e) \times \text{hash}(m_2) + k). Wir können diese beiden Punkte dann nutzen, um die Linie und anschließend den Y-Achsenabschnitt, der den privaten Schlüssel darstellt, wiederherzustellen.
Wenn also jemand eine Epoche wiederverwendet, gibt er versehentlich seinen privaten Schlüssel an alle weiter. Je nach Kontext kann dies zum Diebstahl von Geldern oder zur bloßen Verbreitung des privaten Schlüssels und seiner Integration in einen Smart Contract führen, was zur Entfernung der zugehörigen Adresse führt.
Ein funktionsfähiges anonymes Anti-Denial-of-Service-System außerhalb der Kette, das für Blockchain-Peer-to-Peer-Netzwerke, Chat-Apps und ähnliche Systeme geeignet ist, erfordert keinen Arbeitsnachweis. Das RLN-Projekt konzentriert sich im Wesentlichen auf dieses Konzept, allerdings mit geringfügigen Änderungen (nämlich werden sowohl Nullifikatoren als auch die Zweipunktlinientechnik verwendet, wodurch es einfacher wird, Fälle zu erkennen, in denen eine Epoche wiederverwendet wird).
Stellen Sie sich vor, Sie gründen 0chan, ein Online-Forum wie 4chan, das vollständige Anonymität bietet (Sie haben nicht einmal feste Namen), aber mit einem Reputationssystem zur Förderung qualitativ hochwertigerer Inhalte. Ein solches System könnte über ein Governance-DAO verfügen, um Beiträge zu kennzeichnen, die gegen die Systemregeln verstoßen, und einen Three-Strike-Mechanismus einzuführen.
Das Reputationssystem kann auf positive oder negative Reputationen eingehen; Allerdings erfordert die Bewältigung negativer Reputationen zusätzliche Infrastruktur. Dies erfordert, dass Benutzer alle Reputationsdaten in ihre Beweise einbeziehen, auch wenn diese negativ sind. Wir werden uns in erster Linie auf diesen anspruchsvollen Anwendungsfall konzentrieren, ähnlich dem, was Unirep Social implementieren möchte.
Jeder kann posten, indem er eine Nachricht in der Kette, die den Post enthält, zusammen mit einem ZK-SNARK sendet. Dieses ZK-SNARK dient als Beweis dafür, dass (i) Sie über eine eindeutige externe Identität verfügen, die Ihnen die Erlaubnis zur Erstellung eines Kontos gewährt, oder (ii) dass Sie zuvor bestimmte Beiträge veröffentlicht haben. Konkret funktioniert ZK-SNARK wie folgt:
Nullifier, N
Neuester Blockchain-Staatsstamm, R
Beitragsinhalt (in den Beweis „eingemischt“, um ihn an den Beitrag zu binden, ohne dass Berechnungen dazu erforderlich sind)
Ihr privater Schlüssel, k
Eine externe Identität (Adresse A) oder der im vorherigen Beitrag verwendete Nullifier Nprev
Ein Merkle-Beweis, M, dass die Kette A oder Nprev enthält
Der i-te Beitrag, den Sie mit diesem Konto veröffentlicht haben
Bestätigen Sie, dass M ein gültiger Merkle-Zweig ist, und beweisen Sie, dass (A oder Nprev, je nachdem, was angegeben wird) ein Blatt eines Baums mit der Wurzel R ist.
Überprüfen Sie N = enc(i, k), wobei enc eine Verschlüsselungsfunktion (z. B. AES) ist.
Wenn i=0, überprüfen Sie A=privtoaddr(k), andernfalls überprüfen Sie Nprev=enc(i−1,k).
Neben der Beweisvalidierung prüft die Kette auch, (i) ob R tatsächlich eine aktuelle Zustandswurzel ist und (ii) ob der Nullifier N noch nie verwendet wurde. Bis zu diesem Punkt ähnelt es den zuvor beschriebenen Münzen zum Schutz der Privatsphäre, wir haben jedoch einen Prozess zum „Mint“ neuer Konten hinzugefügt und die Möglichkeit entfernt, Ihr Konto an andere Schlüssel zu „senden“. Stattdessen werden alle Nullifier mit dem Originalschlüssel generiert. Wir verwenden hier enc, um den Nullifikator umkehrbar zu machen. Wenn Sie den Schlüssel k haben, können Sie jeden bestimmten Nullifier in der Kette entschlüsseln; Wenn das Ergebnis ein gültiger Index und kein zufälliges Kauderwelsch ist (z. B. können wir einfach prüfen, ob dec(N) < 2^64 ist), wissen Sie, dass der Nullifier mit dem Schlüssel k generiert wurde.
In diesem Schema ist die Reputation in der Kette verankert und eindeutig. Einige Smart Contracts verfügen über eine Methode namens addReputation, die den mit einem Beitrag veröffentlichten Nullifier und die Anzahl der Reputationseinheiten, die hinzugefügt oder subtrahiert werden sollen, als Eingabe verwendet.
Wir haben die in der Kette gespeicherten Daten für jeden Beitrag erweitert. Anstatt nur den Nullifier N zu speichern, speichern wir {N, h¯, u¯} , wobei:
h¯ = hash(h, r) wobei h die Blockhöhe der Zustandswurzel darstellt, auf die im Beweis verwiesen wird.
u¯ = hash(u, r) wobei u der Reputationswert des Kontos ist (beginnend bei 0 für neue Konten).
R ist hier ein zufälliger Wert, der hinzugefügt wird, um zu verhindern, dass h und u durch Brute-Force-Suche gefunden werden. Aus kryptografischer Sicht macht das Hinzufügen von R den Hash zu einer verborgenen Verpflichtung.
Angenommen, ein Beitrag verwendet Root R und speichert {N, h¯, u¯}. In seinem Beweis wird auf einen früheren Beitrag verwiesen, in dem die Daten {Nprev, h¯prev, u¯prev} gespeichert waren. Der Beweis des Beitrags muss auch alle Reputationseinträge durchlaufen, die zwischen hprev und h gepostet werden. Für jeden Nullifier N entschlüsselt die Verifizierungsfunktion N mithilfe des Benutzerschlüssels k. Wenn die Entschlüsselung einen gültigen Index ausgibt, wendet sie die Reputationsaktualisierung an. Wenn die Summe aller Reputationsaktualisierungen gleich δ ist, dann ist u = uprev + δ.
Wenn wir eine „Drei Schläge und du bist raus“-Regel implementieren möchten, würde ZK-SNARK auch sicherstellen, dass u > -3 ist. Wenn wir eine Regel wollen, nach der ein Beitrag mit Reputationen ≥ 100 ein spezielles „Beitrag mit hoher Reputation“ erhält, ist das auch möglich.
Um die Skalierbarkeit dieses Systems zu verbessern, können wir es in zwei Arten von Nachrichten unterteilen: Posts und RCAs. Ein Beitrag wäre außerhalb der Kette, erfordert jedoch einen Verweis auf einen RCA, der in der letzten Woche erstellt wurde. RCAs wären in der Kette und würden alle Reputationsaktualisierungen seit dem vorherigen RCA des Herausgebers durchlaufen. Auf diese Weise wird die Belastung der Kette auf eine Transaktion pro Post und Woche sowie eine Transaktion für jede Reputationsnachricht reduziert.
Manchmal besteht die Notwendigkeit, ein System mit einem zentralen „Betreiber“ zu entwerfen. Die Gründe dafür können unterschiedlich sein: Mal liegt es an der Skalierbarkeit, mal an der Privatsphäre, insbesondere an der Vertraulichkeit der vom Betreiber gespeicherten Daten. Das zwangsresistente Wahlsystem MACI erfordert beispielsweise, dass Wähler ihre Stimmen in der Kette abgeben, verschlüsselt mit einem Schlüssel, der von einem zentralen Betreiber gehalten wird. Dieser Operator entschlüsselt alle Abstimmungen in der Kette, zählt sie und zeigt das Endergebnis an. Sie verwenden ZK-SNARK, um zu beweisen, dass alles, was sie getan haben, korrekt war. Diese zusätzliche Komplexität ist entscheidend, um einen robusten Datenschutz zu gewährleisten (bekannt als Zwangswiderstand): Benutzer können niemandem beweisen, wie sie abgestimmt haben, selbst wenn sie es wollten. Dank Blockchain und ZK-SNARK bleibt unser Vertrauen in den Betreiber minimal. Böswillige Betreiber können den Zwangswiderstand durchbrechen, aber da die Stimmen auf der Blockchain veröffentlicht werden, können sie nicht durch Zensur der Stimmen betrügen. Und da sie einen ZK-SNARK bereitstellen müssen, können sie nicht durch falsche Berechnungen der Ergebnisse schummeln.
Eine fortgeschrittenere Verwendung von ZK-SNARKs sind Berechnungen, bei denen Beweise erforderlich sind, wobei die Eingabe auf zwei oder mehr Parteien verteilt wird und wir nicht möchten, dass eine Partei etwas über die Eingaben der anderen erfährt. In einem Zwei-Parteien-Szenario können verstümmelte Leitungen Datenschutzanforderungen erfüllen; Für N Parteien können komplexere Mehrparteien-Berechnungsprotokolle verwendet werden. ZK-SNARKs können für überprüfbare Mehrparteienberechnungen in diese Protokolle integriert werden. Dies ermöglicht fortschrittliche Reputationssysteme, die es mehreren Teilnehmern ermöglichen, gemeinsame Berechnungen für ihre privaten Eingaben durchzuführen. Die Berechnungen, um dies effektiv zu erreichen, stecken noch in den Kinderschuhen.
ZK-SNARKs ist äußerst effektiv bei der Erstellung von Systemen, in denen Benutzer private Zustände haben. Es kann jedoch keinen so privaten Zustand aufrechterhalten, den niemand kennt. Damit Informationen bewiesen werden können, muss der Prüfer sie im Klartext kennen. Uniswap ist ein Beispiel, das schwer zu privatisieren ist. In Uniswap gibt es eine zentrale logische „Entität“ – das Konto des Liquiditätsanbieters, das niemandem gehört, und alle Uniswap-Transaktionen finden über dieses Konto statt. Sie können den Status dieses Kontos nicht verbergen, da jemand diesen Status im Klartext speichern muss, um dies zu beweisen, und jede Transaktion seine aktive Beteiligung erfordern würde. Sie könnten die verstümmelten Schaltkreise von ZK-SNARK nutzen, um eine zentralisierte, sichere, private Version von Uniswap zu erstellen, aber es ist unklar, ob die Vorteile die Kosten überwiegen würden. Es bietet möglicherweise nicht einmal wirkliche Vorteile: Verträge müssen Benutzer über Vermögenspreise informieren, und Preisverschiebungen pro Block können Transaktionsaktivitäten aufdecken. Blockchains können staatliche Informationen globalisieren und ZK-SNARKs können sie privatisieren, aber es gibt keine solide Methode, staatliche Informationen gleichzeitig zu globalisieren und zu privatisieren.
In den obigen Abschnitten haben wir Beispiele für Tools gesehen, die für sich genommen leistungsstark sind, aber auch als Bausteine für andere Anwendungen dienen können. Nullifizierer, die für Währungen von entscheidender Bedeutung sind, tauchen jetzt in anderen Anwendungsfällen wieder auf. Die im Abschnitt „Negative Reputation“ verwendete Technik der „erzwungenen Verlinkung“ hat eine breite Anwendung. Dies ist für viele Apps äußerst effektiv, bei denen sich das „Profil“ eines Benutzers im Laufe der Zeit auf komplexe Weise ändert und Sie Benutzer dazu zwingen möchten, Systemregeln zu befolgen und gleichzeitig die Privatsphäre zu wahren. Benutzer könnten sogar damit beauftragt werden, ihren internen „Zustand“ mithilfe eines vollständigen privaten Merkle-Baums darzustellen. Das erwähnte „Commitment Pool“-Tool kann mit ZK-SNARK aufgebaut werden. Wenn bestimmte Apps nicht vollständig in der Kette funktionieren und einen zentralen Betreiber erfordern, können dieselben Techniken dafür sorgen, dass der Betreiber ehrlich bleibt. ZK-SNARK ist ein leistungsstarkes Tool, das Verantwortlichkeits- und Datenschutzvorteile vereint. Obwohl sie ihre Grenzen haben, können diese Einschränkungen in einigen Fällen durch clevere Anwendungsdesigns umgangen werden. Ich hoffe, dass in den kommenden Jahren mehr Anwendungen ZK-SNARK übernehmen und schließlich Anwendungen entwickeln, die ZK-SNARK mit anderen Formen der Verschlüsselung verbinden.
Teilen
Nội dung
zk-SNARKs sind ein leistungsstarkes kryptografisches Tool, das zu einem immer wichtigeren Bestandteil sowohl von Blockchain- als auch von Nicht-Blockchain-basierten Anwendungen geworden ist. Ihre Komplexität zeigt sich sowohl im Verständnis ihrer Funktionsweise als auch darin, wie sie effektiv genutzt werden können. In diesem Artikel wird untersucht, wie sich zk-SNARKs an aktuelle Anwendungen anpassen, es werden Beispiele dafür gegeben, was sie leisten können und was nicht, und es werden allgemeine Richtlinien dazu gegeben, wann zk-SNARKs für bestimmte Anwendungen geeignet sind. Ein besonderer Schwerpunkt wird auf ihrer Rolle bei der Gewährleistung der Privatsphäre liegen.
Stellen Sie sich vor, Sie hätten eine öffentliche Eingabe x, eine private Eingabe w und eine (öffentliche) Funktion f(x,w) → {True,False}, die die Eingaben validiert. Mit zk-SNARKs kann man beweisen, dass sie aw kennen, sodass für ein gegebenes f und x f(x,w) = True ist, ohne preiszugeben, was w tatsächlich ist. Darüber hinaus können Prüfer den Beweis viel schneller authentifizieren, als sie f(x,w) berechnen könnten, selbst wenn sie w wüssten.
Dies verleiht zk-SNARKs zwei Eigenschaften: Datenschutz und Skalierbarkeit. Wie bereits erwähnt, konzentrieren sich unsere Beispiele in diesem Artikel hauptsächlich auf den Datenschutzaspekt.
Angenommen, Sie besitzen ein Ethereum-Wallet und möchten nachweisen, dass dieses Wallet im Rahmen eines Proof-of-Humanity-Systems registriert ist, ohne offenzulegen, wer die registrierte Person tatsächlich ist. Diese Funktion kann mathematisch beschrieben werden als:
Private Eingabe (w): Ihre Adresse A, Ihr privater Adressschlüssel k
Öffentliche Eingabe (x): Adresssatz aller verifizierten Proof-of-Humanity-Profile {H1…Hn}
Verifizierungsfunktion f(x,w):
Interpretieren Sie w als Paar (A, σ) und x als gültige Profilliste {H1…Hn}
Stellen Sie sicher, dass A eine der Adressen in {H1…Hn}ist.
Bestätigen Sie privtoaddr(k) = A
Wenn beide Überprüfungen bestanden sind, geben Sie „True“ zurück. Wenn einer von ihnen fehlschlägt, geben Sie „False“ zurück.
Der Prüfer generiert seine Adresse A und den zugehörigen Schlüssel k und stellt w=(A,k) als private Eingabe für f bereit. Sie erhalten den öffentlichen Input, den aktuellen Satz verifizierter Proof-of-Humanity-Profile {H1…Hn}, aus der Kette. Anschließend führen sie den zk-SNARK-Beweisalgorithmus aus, der (vorausgesetzt, die Eingabe ist korrekt) einen Beweis erstellt. Dieser Nachweis wird zusammen mit der Blockhöhe, aus der die verifizierte Profilliste abgerufen wurde, an den Verifizierer gesendet.
Der Verifizierer liest auch die Kette, ruft die Liste {H1…Hn} ab der vom Prüfer angegebenen Höhe ab und prüft den Beweis. Wenn die Verifizierung erfolgreich ist, geht der Verifizierer davon aus, dass der Prüfer über ein verifiziertes Proof-of-Humanity-Profil verfügt.
Bevor ich mich mit komplexeren Beispielen befasse, empfehle ich dringend, das obige Beispiel vollständig zu verstehen.
Ein Nachteil des oben genannten Beweissystems besteht darin, dass der Verifizierer den gesamten Profilsatz {H1…Hn} kennen muss, was O(n) Zeit benötigt, um diesen Satz in den zk-SNARK-Mechanismus „einzugeben“. Dieses Problem kann gelöst werden, indem die On-Chain-Merkle-Wurzel, die alle Profile umfasst, als öffentliche Eingabe verwendet wird (möglicherweise nur die Staatswurzel). Wir fügen eine weitere private Eingabe hinzu, einen Merkle-Beweis M, der bestätigt, dass sich das Konto A des Prüfers im relevanten Teil des Baums befindet.
Eine sehr neue und effizientere Alternative zu Merkle-Beweisen für ZK-Mitgliedschaftsnachweise ist Caulk. In Zukunft könnten einige dieser Anwendungsfälle auf ähnliche Lösungen wie Caulk umgestellt werden.
Projekte wie Zcash und Tornado.cash ermöglichen es uns, datenschutzfreundliche Währungen zu besitzen. Nun könnte man meinen, sie könnten die erwähnten „ZK-Menschenbeweise“ nutzen, aber es geht nicht darum, den Zugang zu menschlichen Profilbeweisen zu beweisen; es geht darum, den Zugang zu Münzen nachzuweisen. Hier liegt ein Problem: Wir müssen uns gleichzeitig mit Datenschutz und Doppelausgaben befassen. Das heißt, wir sollten nicht zweimal dieselbe Münze ausgeben.
So lösen wir es: Wer eine Münze besitzt, hat ein privates Geheimnis „s“. Sie berechnen lokal ein „Blatt“ L=hash(s,1), das in der Kette veröffentlicht wird und Teil des Zustands N=hash(s,2) wird, den wir Nullifier nennen. Der Zustand wird in einem Merkle-Baum gespeichert.
Um eine Münze auszugeben, muss der Absender ein ZK-SNARK vorlegen, wobei:
Zu den öffentlichen Eingaben gehören ein Nullifier N, die aktuelle oder aktuelle Merkle-Wurzel R und ein neues Blatt L' (für den Empfänger gedacht, der ein geheimes s' als L'=hash(s',1) an den Absender übergeben hat).
Private Eingaben umfassen ein Geheimnis s, ein Blatt L und einen Merkle-Zweig M.
Die Verifizierungsfunktion prüft:
M ist ein gültiger Merkle-Zweig, was beweist, dass L ein Blatt des Baums ist, dessen Wurzel bei R liegt, wobei R die Merkle-Wurzel des aktuellen Zustands ist.
Hash(s,1)=L und Hash(s,2)=N.
Die Transaktion enthält den Nullifier N und das neue Blatt L'. Wir beweisen eigentlich nichts über L', aber es wird in den Beweis „eingemischt“, um eine Änderung durch Dritte während der Transaktion zu verhindern. Um die Transaktion zu validieren, verifiziert die Kette das ZK-SNARK und prüft, ob N in früheren Transaktionen verwendet wurde. Bei Erfolg wird N zum Satz verbrauchter Nullifizierer hinzugefügt, wodurch dieser wieder unbrauchbar wird. L' wird zum Merkle-Baum hinzugefügt.
Mithilfe von ZK-SNARKs verknüpfen wir zwei Werte: L (erscheint auf der Kette, wenn die Münze geprägt wird) und N (erscheint, wenn sie ausgegeben wird), ohne offenzulegen, welches L mit welchem N verbunden ist. Die Verbindung zwischen L und N ist nur erkennbar, wenn Sie Kennen Sie die Geheimnisse, die sie erzeugen. Jede geprägte Münze kann einmal verwendet werden (da es für jedes L nur ein gültiges N gibt), die jeweils verwendete konkrete Münze bleibt jedoch verborgen.
Dies ist ein entscheidendes Grundelement, das es zu begreifen gilt. Darauf basieren viele Mechanismen, die wir im Folgenden beschreiben, allerdings mit unterschiedlichen Zwecken.
Das oben Gesagte lässt sich leicht auf Münzen mit beliebigem Guthaben erweitern. Wir behalten das Konzept einer „Münze“ bei, aber jede Münze trägt ein (privates) Guthaben. Eine einfache Möglichkeit, dies zu erreichen, besteht darin, dass jede Münze über eine Kettenspeicherung verfügt, nicht nur mit Blatt L, sondern auch mit einem verschlüsselten Guthaben. Jede Transaktion würde zwei Münzen verbrauchen und zwei neue erstellen, wodurch zwei Paare (Blatt, verschlüsseltes Guthaben) zum Zustand hinzugefügt würden. Das ZK-SNARK überprüft außerdem, ob die Summe der Eingangssalden der Summe der Ausgangssalden entspricht und beide Ausgangssalden nicht negativ sind.
Ein faszinierendes Anti-DOS-Tool: Stellen Sie sich vor, Sie haben eine On-Chain-Identität, die nicht einfach zu erstellen ist; Es könnte sich um ein menschensicheres Profil oder 32 ETH-Validatoren oder einfach um ein Konto mit einem ETH-Guthaben ungleich Null handeln. Wir könnten ein DOS-resistenteres Peer-to-Peer-Netzwerk schaffen, indem wir nur Nachrichten akzeptieren, die beweisen, dass der Absender über ein Profil verfügt. Für jedes Profil wären bis zu 1000 Nachrichten pro Stunde zulässig. Wenn ein Absender betrügt, wird sein Profil aus der Liste entfernt. Aber wie stellen wir die Privatsphäre sicher?
Zuerst das Setup: Sei k der private Schlüssel des Benutzers und A=privtoaddr(k) die entsprechende Adresse. Eine Liste gültiger Adressen ist öffentlich (z. B. ein On-Chain-Register). Bisher spiegelt dies das Beispiel des Menschenbeweises wider: Sie müssen nachweisen, dass Sie den privaten Schlüssel zu einer Adresse besitzen, ohne preiszugeben, welche. Aber wir wollen nicht nur den Beweis, dass Sie auf der Liste stehen. Wir benötigen ein Protokoll, mit dem Sie beweisen können, dass Sie auf der Liste stehen, das Ihre Beweise jedoch einschränkt.
Wir teilen die Zeit in Perioden auf, die jeweils 3,6 Sekunden dauern (also 1000 Perioden pro Stunde). Unser Ziel ist es, dass jeder Benutzer pro Zeitraum nur eine Nachricht senden kann. Wenn sie zwei im gleichen Zeitraum senden, werden sie erwischt. Um gelegentliche Ausbrüche zu ermöglichen, können sie aktuelle Zeiträume verwenden. Wenn ein Benutzer also 500 ungenutzte Zeiträume hat, kann er 500 Nachrichten auf einmal senden.
Beginnen wir mit einer Basisversion, die Nullifier verwendet. Ein Benutzer generiert einen Nullifier mit (N = \text{hash}(k, e)), wobei (k) sein Schlüssel und (e) eine Epochennummer ist, und veröffentlicht ihn dann mit der Nachricht (m). ZK-SNARK verschleiert dann (\text{hash}(m)). In diesem Prozess wird nichts über (m) verifiziert, sodass der Beweis an eine einzelne Nachricht gebunden ist. Wenn ein Benutzer zwei Beweise mit demselben Nullifier an zwei unterschiedliche Nachrichten bindet, besteht die Gefahr, dass er erwischt wird.
Jetzt wechseln wir zu einer komplexeren Version. In diesem Szenario gibt das nachfolgende Protokoll seinen privaten Schlüssel preis und bestätigt nicht nur, ob jemand dieselbe Epoche zweimal verwendet hat. Unsere zentrale Technik basiert auf dem Prinzip, dass „zwei Punkte eine Linie bestimmen“. Das Aufdecken eines Punktes auf einer Linie verrät wenig, aber das Aufdecken von zwei Punkten enthüllt die gesamte Linie.
Für jede Epoche (e) wählen wir eine Linie (L_e(x) = \text{hash}(k, e) \times x + k). Die Steigung der Linie ist (\text{hash}(k, e)) und der y-Achsenabschnitt ist (k), beide sind der Öffentlichkeit unbekannt. Um ein Zertifikat für die Nachricht (m) zu erstellen, stellt der Absender (y = L_e(\text{hash}(m)) = \text{hash}(k, e) \times \text{hash}(m) + k bereit ), zusammen mit einem ZK-SNARK-Beweis, dass die Berechnung von (y) korrekt ist.
Zusammenfassend lautet ZK-SNARK wie folgt:
({A_1…A_n}): Eine Liste gültiger Konten
(M): Die Nachricht, die durch das Zertifikat validiert wird
(E): Die Epochennummer für das Zertifikat
(Y): Auswertung der Linienfunktion
Überprüfen Sie, ob (\text{privtoaddr}(k)) in ({A_1…A_n}) existiert.
Bestätige (y = \text{hash}(k, e) \times \text{hash}(m) + k)
Was aber, wenn jemand eine Epoche zweimal verwendet? Sie würden zwei Werte (m_1) und (m_2) zusammen mit ihren Zertifikatswerten (y_1 = \text{hash}(k, e) \times \text{hash}(m_1) + k) und (y_2 = \text{hash}(k, e) \times \text{hash}(m_2) + k). Wir können diese beiden Punkte dann nutzen, um die Linie und anschließend den Y-Achsenabschnitt, der den privaten Schlüssel darstellt, wiederherzustellen.
Wenn also jemand eine Epoche wiederverwendet, gibt er versehentlich seinen privaten Schlüssel an alle weiter. Je nach Kontext kann dies zum Diebstahl von Geldern oder zur bloßen Verbreitung des privaten Schlüssels und seiner Integration in einen Smart Contract führen, was zur Entfernung der zugehörigen Adresse führt.
Ein funktionsfähiges anonymes Anti-Denial-of-Service-System außerhalb der Kette, das für Blockchain-Peer-to-Peer-Netzwerke, Chat-Apps und ähnliche Systeme geeignet ist, erfordert keinen Arbeitsnachweis. Das RLN-Projekt konzentriert sich im Wesentlichen auf dieses Konzept, allerdings mit geringfügigen Änderungen (nämlich werden sowohl Nullifikatoren als auch die Zweipunktlinientechnik verwendet, wodurch es einfacher wird, Fälle zu erkennen, in denen eine Epoche wiederverwendet wird).
Stellen Sie sich vor, Sie gründen 0chan, ein Online-Forum wie 4chan, das vollständige Anonymität bietet (Sie haben nicht einmal feste Namen), aber mit einem Reputationssystem zur Förderung qualitativ hochwertigerer Inhalte. Ein solches System könnte über ein Governance-DAO verfügen, um Beiträge zu kennzeichnen, die gegen die Systemregeln verstoßen, und einen Three-Strike-Mechanismus einzuführen.
Das Reputationssystem kann auf positive oder negative Reputationen eingehen; Allerdings erfordert die Bewältigung negativer Reputationen zusätzliche Infrastruktur. Dies erfordert, dass Benutzer alle Reputationsdaten in ihre Beweise einbeziehen, auch wenn diese negativ sind. Wir werden uns in erster Linie auf diesen anspruchsvollen Anwendungsfall konzentrieren, ähnlich dem, was Unirep Social implementieren möchte.
Jeder kann posten, indem er eine Nachricht in der Kette, die den Post enthält, zusammen mit einem ZK-SNARK sendet. Dieses ZK-SNARK dient als Beweis dafür, dass (i) Sie über eine eindeutige externe Identität verfügen, die Ihnen die Erlaubnis zur Erstellung eines Kontos gewährt, oder (ii) dass Sie zuvor bestimmte Beiträge veröffentlicht haben. Konkret funktioniert ZK-SNARK wie folgt:
Nullifier, N
Neuester Blockchain-Staatsstamm, R
Beitragsinhalt (in den Beweis „eingemischt“, um ihn an den Beitrag zu binden, ohne dass Berechnungen dazu erforderlich sind)
Ihr privater Schlüssel, k
Eine externe Identität (Adresse A) oder der im vorherigen Beitrag verwendete Nullifier Nprev
Ein Merkle-Beweis, M, dass die Kette A oder Nprev enthält
Der i-te Beitrag, den Sie mit diesem Konto veröffentlicht haben
Bestätigen Sie, dass M ein gültiger Merkle-Zweig ist, und beweisen Sie, dass (A oder Nprev, je nachdem, was angegeben wird) ein Blatt eines Baums mit der Wurzel R ist.
Überprüfen Sie N = enc(i, k), wobei enc eine Verschlüsselungsfunktion (z. B. AES) ist.
Wenn i=0, überprüfen Sie A=privtoaddr(k), andernfalls überprüfen Sie Nprev=enc(i−1,k).
Neben der Beweisvalidierung prüft die Kette auch, (i) ob R tatsächlich eine aktuelle Zustandswurzel ist und (ii) ob der Nullifier N noch nie verwendet wurde. Bis zu diesem Punkt ähnelt es den zuvor beschriebenen Münzen zum Schutz der Privatsphäre, wir haben jedoch einen Prozess zum „Mint“ neuer Konten hinzugefügt und die Möglichkeit entfernt, Ihr Konto an andere Schlüssel zu „senden“. Stattdessen werden alle Nullifier mit dem Originalschlüssel generiert. Wir verwenden hier enc, um den Nullifikator umkehrbar zu machen. Wenn Sie den Schlüssel k haben, können Sie jeden bestimmten Nullifier in der Kette entschlüsseln; Wenn das Ergebnis ein gültiger Index und kein zufälliges Kauderwelsch ist (z. B. können wir einfach prüfen, ob dec(N) < 2^64 ist), wissen Sie, dass der Nullifier mit dem Schlüssel k generiert wurde.
In diesem Schema ist die Reputation in der Kette verankert und eindeutig. Einige Smart Contracts verfügen über eine Methode namens addReputation, die den mit einem Beitrag veröffentlichten Nullifier und die Anzahl der Reputationseinheiten, die hinzugefügt oder subtrahiert werden sollen, als Eingabe verwendet.
Wir haben die in der Kette gespeicherten Daten für jeden Beitrag erweitert. Anstatt nur den Nullifier N zu speichern, speichern wir {N, h¯, u¯} , wobei:
h¯ = hash(h, r) wobei h die Blockhöhe der Zustandswurzel darstellt, auf die im Beweis verwiesen wird.
u¯ = hash(u, r) wobei u der Reputationswert des Kontos ist (beginnend bei 0 für neue Konten).
R ist hier ein zufälliger Wert, der hinzugefügt wird, um zu verhindern, dass h und u durch Brute-Force-Suche gefunden werden. Aus kryptografischer Sicht macht das Hinzufügen von R den Hash zu einer verborgenen Verpflichtung.
Angenommen, ein Beitrag verwendet Root R und speichert {N, h¯, u¯}. In seinem Beweis wird auf einen früheren Beitrag verwiesen, in dem die Daten {Nprev, h¯prev, u¯prev} gespeichert waren. Der Beweis des Beitrags muss auch alle Reputationseinträge durchlaufen, die zwischen hprev und h gepostet werden. Für jeden Nullifier N entschlüsselt die Verifizierungsfunktion N mithilfe des Benutzerschlüssels k. Wenn die Entschlüsselung einen gültigen Index ausgibt, wendet sie die Reputationsaktualisierung an. Wenn die Summe aller Reputationsaktualisierungen gleich δ ist, dann ist u = uprev + δ.
Wenn wir eine „Drei Schläge und du bist raus“-Regel implementieren möchten, würde ZK-SNARK auch sicherstellen, dass u > -3 ist. Wenn wir eine Regel wollen, nach der ein Beitrag mit Reputationen ≥ 100 ein spezielles „Beitrag mit hoher Reputation“ erhält, ist das auch möglich.
Um die Skalierbarkeit dieses Systems zu verbessern, können wir es in zwei Arten von Nachrichten unterteilen: Posts und RCAs. Ein Beitrag wäre außerhalb der Kette, erfordert jedoch einen Verweis auf einen RCA, der in der letzten Woche erstellt wurde. RCAs wären in der Kette und würden alle Reputationsaktualisierungen seit dem vorherigen RCA des Herausgebers durchlaufen. Auf diese Weise wird die Belastung der Kette auf eine Transaktion pro Post und Woche sowie eine Transaktion für jede Reputationsnachricht reduziert.
Manchmal besteht die Notwendigkeit, ein System mit einem zentralen „Betreiber“ zu entwerfen. Die Gründe dafür können unterschiedlich sein: Mal liegt es an der Skalierbarkeit, mal an der Privatsphäre, insbesondere an der Vertraulichkeit der vom Betreiber gespeicherten Daten. Das zwangsresistente Wahlsystem MACI erfordert beispielsweise, dass Wähler ihre Stimmen in der Kette abgeben, verschlüsselt mit einem Schlüssel, der von einem zentralen Betreiber gehalten wird. Dieser Operator entschlüsselt alle Abstimmungen in der Kette, zählt sie und zeigt das Endergebnis an. Sie verwenden ZK-SNARK, um zu beweisen, dass alles, was sie getan haben, korrekt war. Diese zusätzliche Komplexität ist entscheidend, um einen robusten Datenschutz zu gewährleisten (bekannt als Zwangswiderstand): Benutzer können niemandem beweisen, wie sie abgestimmt haben, selbst wenn sie es wollten. Dank Blockchain und ZK-SNARK bleibt unser Vertrauen in den Betreiber minimal. Böswillige Betreiber können den Zwangswiderstand durchbrechen, aber da die Stimmen auf der Blockchain veröffentlicht werden, können sie nicht durch Zensur der Stimmen betrügen. Und da sie einen ZK-SNARK bereitstellen müssen, können sie nicht durch falsche Berechnungen der Ergebnisse schummeln.
Eine fortgeschrittenere Verwendung von ZK-SNARKs sind Berechnungen, bei denen Beweise erforderlich sind, wobei die Eingabe auf zwei oder mehr Parteien verteilt wird und wir nicht möchten, dass eine Partei etwas über die Eingaben der anderen erfährt. In einem Zwei-Parteien-Szenario können verstümmelte Leitungen Datenschutzanforderungen erfüllen; Für N Parteien können komplexere Mehrparteien-Berechnungsprotokolle verwendet werden. ZK-SNARKs können für überprüfbare Mehrparteienberechnungen in diese Protokolle integriert werden. Dies ermöglicht fortschrittliche Reputationssysteme, die es mehreren Teilnehmern ermöglichen, gemeinsame Berechnungen für ihre privaten Eingaben durchzuführen. Die Berechnungen, um dies effektiv zu erreichen, stecken noch in den Kinderschuhen.
ZK-SNARKs ist äußerst effektiv bei der Erstellung von Systemen, in denen Benutzer private Zustände haben. Es kann jedoch keinen so privaten Zustand aufrechterhalten, den niemand kennt. Damit Informationen bewiesen werden können, muss der Prüfer sie im Klartext kennen. Uniswap ist ein Beispiel, das schwer zu privatisieren ist. In Uniswap gibt es eine zentrale logische „Entität“ – das Konto des Liquiditätsanbieters, das niemandem gehört, und alle Uniswap-Transaktionen finden über dieses Konto statt. Sie können den Status dieses Kontos nicht verbergen, da jemand diesen Status im Klartext speichern muss, um dies zu beweisen, und jede Transaktion seine aktive Beteiligung erfordern würde. Sie könnten die verstümmelten Schaltkreise von ZK-SNARK nutzen, um eine zentralisierte, sichere, private Version von Uniswap zu erstellen, aber es ist unklar, ob die Vorteile die Kosten überwiegen würden. Es bietet möglicherweise nicht einmal wirkliche Vorteile: Verträge müssen Benutzer über Vermögenspreise informieren, und Preisverschiebungen pro Block können Transaktionsaktivitäten aufdecken. Blockchains können staatliche Informationen globalisieren und ZK-SNARKs können sie privatisieren, aber es gibt keine solide Methode, staatliche Informationen gleichzeitig zu globalisieren und zu privatisieren.
In den obigen Abschnitten haben wir Beispiele für Tools gesehen, die für sich genommen leistungsstark sind, aber auch als Bausteine für andere Anwendungen dienen können. Nullifizierer, die für Währungen von entscheidender Bedeutung sind, tauchen jetzt in anderen Anwendungsfällen wieder auf. Die im Abschnitt „Negative Reputation“ verwendete Technik der „erzwungenen Verlinkung“ hat eine breite Anwendung. Dies ist für viele Apps äußerst effektiv, bei denen sich das „Profil“ eines Benutzers im Laufe der Zeit auf komplexe Weise ändert und Sie Benutzer dazu zwingen möchten, Systemregeln zu befolgen und gleichzeitig die Privatsphäre zu wahren. Benutzer könnten sogar damit beauftragt werden, ihren internen „Zustand“ mithilfe eines vollständigen privaten Merkle-Baums darzustellen. Das erwähnte „Commitment Pool“-Tool kann mit ZK-SNARK aufgebaut werden. Wenn bestimmte Apps nicht vollständig in der Kette funktionieren und einen zentralen Betreiber erfordern, können dieselben Techniken dafür sorgen, dass der Betreiber ehrlich bleibt. ZK-SNARK ist ein leistungsstarkes Tool, das Verantwortlichkeits- und Datenschutzvorteile vereint. Obwohl sie ihre Grenzen haben, können diese Einschränkungen in einigen Fällen durch clevere Anwendungsdesigns umgangen werden. Ich hoffe, dass in den kommenden Jahren mehr Anwendungen ZK-SNARK übernehmen und schließlich Anwendungen entwickeln, die ZK-SNARK mit anderen Formen der Verschlüsselung verbinden.