
Wir haben einen Prototyp anonymer Transaktionen implementiert , der auf zkSNARK basiert, um vertrauliche Transaktionen in der Waves-Blockchain sicherzustellen. In unserer Implementierung verwenden wir das Groth16-Evidenzsystem für die BN254-Kurve und DSL- Circom .
Wir erklären, wie es funktioniert.
zkSNARKs
zkSNARK ist ein kryptografisches Grundelement , das die Kenntnis eines speziellen Datensatzes (Evidence) bestätigt, der dem Satz der folgenden Gleichungen entspricht (Constraint-System):
⟨ai,w⟩⟨bi,w⟩+⟨ci,w⟩=0
Ein Teil der Beweise ist privat. Mit dieser Konstruktion können wir beispielsweise die Kenntnis des Hash-Invers-Bildes nachweisen, ohne das Invers-Bild preiszugeben. Sie kann auch im privaten Transaktionsmechanismus für das UTXO-Modell (Unspent Transaction (TX) Output) verwendet werden, bei dem nur UTXO-Hashes veröffentlicht werden und die Gültigkeit der Transaktion in zkSNARK nachgewiesen wird (Eigentumsnachweis, Nachweis des Speicherns des Betrags).
zkSNARK ist eine nicht interaktive Technologie ohne Offenlegung, dh es handelt sich nicht um ein Protokoll der Interaktion zwischen Teilnehmern, das zum Nachweis von Wissen implementiert wird. In der zkSNARK-Technologie erstellt der Prüfer den Beweis und sendet ihn an den Prüfer - es sind keine zusätzlichen Interaktionen erforderlich. Der Prüfer kann die Richtigkeit und Richtigkeit der Verwendung von Beweisdaten überprüfen, ohne auf zusätzliche Informationen zurückgreifen zu müssen. Ursprünglich wurden zkSNARKs als Protokoll für „vertrauliches Rechnen“ erstellt: Bei der Berechnung des Ergebnisses werden die an den Berechnungen beteiligten Daten nicht bekannt gegeben.
Mit der zkSNARK-Technologie kann ein Schema zur Festschreibung implementiert werden: Der Prüfer berechnet den Hash, gibt ihn dem Prüfer und führt einen speziellen Beweis durch, dass er das umgekehrte Bild des Hash x kennt. Durch Einsetzen der Werte von x und Hash in die Formel und Übergeben dieser Formel und des Beweises an den Prüfer kann der Prüfer sicherstellen, dass der Prüfer x kennt. Dies ist die Basis für anonyme Transaktionen: Wir kennen den privaten Schlüssel und eine bestimmte Eingabe (nicht ausgegebenes UTXO) mit einem bestimmten Betrag, den der Benutzer im Smart-Vertrag erstellt hat. Ohne Offenlegung dieser Daten kann der Nutzer mit einem Smart-Vertrag bestätigen, dass dies seine Eingabe ist, dass er darüber verfügen und sie jemandem zur Verwendung geben kann.
Jetzt wird die Technologie nicht überall verwendet, da der Proof für mehrere Minuten erstellt wird, was für den Benutzer nicht sehr praktisch ist.
Weitere Informationen zur zkSNARK-Programmierung finden Sie in Vitalik Buterins Artikel „Quadratische Arithmetikprogramme: von Null bis Held“ und in Iden3s Artikel zum Entwurf von Circom-Schaltkreisen.
Kontomodell
Für Transaktionen in Waves werden normalerweise Schlüssel und Adressen verwendet, die auf curve25519
basieren. Diese Kurve ist nicht zkSNARK-freundlich, daher verwenden wir für anonyme Transaktionen die Edwards-Untergruppe der verdrehten Kurven von BabyJubJub
. Außerdem verwenden wir öffentliche Schlüssel als Adressen, da Sie beim Senden die Daten für den Empfänger verschlüsseln müssen.
UTXO-Modell
In unserem Modell wird UTXO durch einen Satz von 3 Parametern dargestellt: Balance, öffentlicher Schlüssel des Besitzers und eindeutiges Geheimnis. Die Blockchain enthält nur Hashes ohne zusätzliche Verschlüsselung. Der Eigentümer wird durch einen öffentlichen Schlüssel dargestellt. Wie bereits erwähnt, verwenden wir öffentliche Schlüssel nicht für die Kurve curve25519
, sondern für die zkSNARK-freundliche BabyJubJub
Kurve. Die UTXO-ID sollte zufällig generiert werden, da der Benutzer, wenn er zwei identische IDs angibt, UTXO nur für eine davon abholen (ausgeben) kann. In diesem Fall wird nur UTXO mit der entsprechenden ID für den aktuellen Benutzer blockiert, nicht jedoch für den Rest. Es liegt im Interesse des Benutzers, ID mithilfe eines Zufallszahlengenerators auszuwählen (253 Bits werden ID zugewiesen, sodass es schwierig ist, eine Kollision zu erhalten).
Um UTXO auszugeben, müssen Sie einen Nullifier veröffentlichen, eine deterministische Funktion von UTXO, definiert als Hash (secret, owner_privkey). Dieser Wert ist deterministisch und für jedes UTXO eindeutig, nur der Eigentümer kennt ihn. Abgesehen vom Eigentümer kann niemand UTXO mit dem entsprechenden Nullifier verknüpfen.
UTXOs werden in der dApp-Hash-Map gespeichert, d. H. Im Vertragsstil. In der Blockchain werden UTXOs verschlüsselt. Um sein Geld zu erhalten, muss der Benutzer die Blockchain scannen und versuchen, jedes UTXO zu entschlüsseln.
Zustand dapp
Der dApp-Stil enthält Hash-Maps, die zwei Gruppen darstellen:
Auf diese Weise kann dApp die Existenz einer anonymen UTXO-Menge und die Eindeutigkeit von Nullen überprüfen. Dies reicht aus, um anonyme Überweisungen mit dem Schutz vor Fälschung neuer Vermögenswerte und doppelten Ausgaben zu verarbeiten.
DApp verfügt über drei Methoden, die den grundlegenden Arten von Transaktionen entsprechen:
- Einzahlung
- Übertragen
- Fazit
Für die Überweisung und Auszahlung von Geldern verwenden wir unsere eigenen Prüfer, die die Interaktion von dApp mit speziellen anonymen Konten auf der Grundlage der BabyJubJub-Kurve sicherstellen. Einzahlungen werden von regulären Waves-Konten verarbeitet.
Provisionen
Für die Auffüllung des Kontos wird eine Gebühr vom curve25519
Konto erhoben. Bei Überweisungen und Abhebungen wird die Provision vom anonymen Konto abgebucht. Auf der dApp-Ebene sieht es so aus:
dApp zahlt für die Transaktion selbst, dh das native Token, das für die Zahlung der Provision ausgegeben wird, wird von seinem Guthaben abgebucht
Zwischen den Ein- und Ausgängen wird ein Teil der Provision verbrannt, um die Vermögenswerte zu annullieren, die den tatsächlichen Vermögenswerten des Smart-Vertrags entsprechen
Auf UTXO-Ebene verbrennen wir bei der Abwicklung einer Transaktion einen bestimmten Betrag als Provision.
Transaktionen
Eine Einzahlung ist ein einfacher Vorgang. Jede Einzahlung fügt UTXO ein neues Element hinzu.

Übertragungen basieren auf dem 2-zu-2-Übersetzungsprimitiv.

Einige Ein- und Ausgänge können Null sein. Als Teilbeispiel einer solchen Konstruktion kann jede Art von einfacher Übersetzung dargestellt werden (Join-, Split- und andere Übertragungen mit Ausnahme von Atom-Swaps).
Schlussfolgerungen funktionieren wie andere Transaktionen, nur dass der Benutzer anstelle eines zweiten UTXOs sein UTXO aus dApp entfernen kann. Es können auch zwei UTXOs am Eingang vorhanden sein, UTXOs am Ausgang mit dem Rest der Geldmittel und Abhebungen, die in der Blockchain veröffentlicht sind.

Beim Zurückziehen oder Übertragen überprüft dApp, ob die entsprechenden Nullifier noch nicht in seinem Stack gefunden wurden.
Mit zkSNARK können wir berechnen, dass die Summe der Transaktionseingaben der Summe der Ausgaben entspricht. Wenn wir eine Transaktion ausführen, geben wir sie für UTXO und eine andere Null-UTXO aus, die sich nicht im Merkle-Baum befindet. Um UTXO ausgeben zu können, müssen Sie den privaten Schlüssel seines Besitzers nachweisen. Überprüfen Sie, ob der private Schlüssel bei Multiplikation mit dem Gruppengenerator einen öffentlichen Schlüssel ergibt. Ohne Kenntnis des privaten Schlüssels kann daher eine Transaktion nicht abgeschlossen werden.
Anonymes Set
Wir verwenden eine anonyme Menge von 8 Elementen. Das Zielelement wird privat aus der Menge ausgewählt, die in der öffentlichen zkSNARK-Eingabe dargestellt ist. Mit dieser Methode können Sie das Transaktionsdiagramm verschleiern (wenn es möglich ist, das UTXO-Interaktionsdiagramm wiederherzustellen, besteht die Möglichkeit, Transaktionen zu dekanonymisieren).
Ferner kann ein einfacher Sammler von 8 Elementen durch einen Sammler von Merkle-Bäumen ersetzt werden. Der Ansatz verbirgt das Transaktionsdiagramm.
Um eine gültige Transaktion zu erstellen, beweisen wir, dass wir etwas UTXO aus der Menge von UTXO ausgeben. Wir setzen zkSNARK-Merkle-Proofs und UTXO-Daten in private Eingaben und Root-Hash in den öffentlichen Eingang. Mit SNARK beweisen wir also, dass wir UTXO kennen.

Doppelter Ausgabenschutz
Zum Schutz vor doppelten Ausgaben verwenden wir Nullifier - deterministische Funktionen, die nicht direkt vom UTXO-Hash abhängen. Um den Nullifier zu berechnen, nehmen wir die Funktion vom privaten Schlüssel, es wird nachgewiesen, dass sie dem öffentlichen Schlüssel, der ID und dem UTXO-Hash entspricht. Für jede UTXO gibt es nur einen Nuller.
Für jede Transaktion sollte der Nuller der ausgegebenen UTXO-Ausgaben als öffentlicher Eintrag für zkSNARK dargestellt werden. Innerhalb der zkSNARK-Schaltung muss außerdem bestätigt werden, dass sie zu verbrauchtem UTXO gehört.
Wenn der dApp-Vertrag einen nicht eindeutigen Nullwert erhält, wird die Transaktion abgelehnt. Somit ist garantiert, dass jede UTXO einmal ausgegeben wird.
Nachdem sie UTXO ausgegeben haben, wird der Nullifier in der Liste der ausgegebenen Nullifier im dApp-Artikel veröffentlicht. Das heißt, in der Hash-Map gegenüber diesem Nullifier wird "true" gesetzt. Bevor wir den Nullifier im Artikel veröffentlichen, prüfen wir, ob dieser Nullifier noch nicht verwendet wurde, was bedeutet, dass UTXO mit dieser ID ausgegeben werden kann.