Technik › Wer hat empfangen?

Einmal-Adressen

Stealth-Adressen: Geld an eine Adresse senden, ohne sie auf die Blockchain zu schreiben

Kurz gesagt

Der Sender wählt ein zufälliges r, veröffentlicht R = r·G und sendet das Geld an den Einmalschlüssel P = Hs(8·r·A ‖ i)·G + B. Der Empfänger findet ihn, indem er dasselbe über a berechnet: Hs(8·a·R ‖ i)·G + B. Ausgeben kann er ihn mit dem privaten Schlüssel x = Hs(8·a·R ‖ i) + b.

Die Aufgabe

Wir wollen:

  1. dass weder die Adresse des Empfängers noch irgendetwas, das sich bei Zahlungen an dieselbe Person wiederholt, auf der Blockchain erscheint;
  2. dass der Empfänger seine Outputs selbst findet, ohne mit dem Sender zu sprechen;
  3. dass nur der Empfänger den Output ausgeben kann.

Die Lösung ist ein Diffie-Hellman-Schlüsselaustausch, der in jede Transaktion eingebaut ist.

Schritt für Schritt

Sender Empfänger r (zufällig) R = r·G kennt die Adresse: A, B gemeinsames Geheimnis: 8·r·A P = Hs(8rA ‖ i)·G + B auf die Chain: R und P (und sonst nichts über die Adresse) a, b (eigene Schlüssel) sieht R in der Transaktion gemeinsames Geheimnis: 8·a·R = 8·a·r·G = 8·r·A prüft: Hs(8aR ‖ i)·G + B == P ?

1. Der Sender wählt ein zufälliges r

Ein frisches zufälliges r (privater Transaktionsschlüssel) für jede Transaktion. Seine öffentliche Version R = r·G (öffentlicher Transaktionsschlüssel) wird in das Feld tx_extra der Transaktion geschrieben.

2. Das gemeinsame Geheimnis

Der Sender berechnet 8·r·A (A ist der öffentliche View Key aus der Adresse). Später berechnet der Empfänger 8·a·R. Es ist derselbe Punkt, denn a·R = a·r·G = r·a·G = r·A. Im Code von Monero heißt das Key Derivation.

Der Faktor 8 (der Kofaktor) „säubert“ den Punkt von jedem Anteil kleiner Ordnung: Selbst wenn jemand ein bösartiges R liefert, landet das Ergebnis in der richtigen Untergruppe.

3. Der Einmalschlüssel

P = Hs( 8·r·A ‖ i )·G + B i ist der Index des Outputs in der Transaktion (Varint), damit zwei Outputs einer Transaktion verschiedene Schlüssel bekommen

Das ist die Einmal-Adresse (öffentlicher Output-Schlüssel). Sie sieht aus wie ein zufälliger Punkt: Ohne a oder r gibt es nichts, womit man sie vergleichen könnte.

4. Der Empfänger sucht

Für jede neue Transaktion und jeden Output i berechnet die Wallet Hs(8·a·R ‖ i)·G + B und vergleicht es mit P. Übereinstimmung – der Output gehört uns. Dafür braucht es nur den View Key a und das öffentliche B – deshalb kann eine View-only-Wallet eingehende Zahlungen finden.

5. Der Empfänger gibt aus

Der private Schlüssel des Einmal-Outputs:

x = Hs( 8·a·R ‖ i ) + b Probe: x·G = Hs(…)·G + b·G = Hs(…)·G + B = P ✓

Dafür braucht es den Spend Key b. Mit dem Schlüssel x wird die Ausgabe signiert, und aus ihm wird das Key Image berechnet.

Auch der Betrag wird mit dem gemeinsamen Geheimnis verschlüsselt

Aus demselben gemeinsamen Geheimnis wird eine Maske für den Betrag abgeleitet. Der Betrag des Outputs (8 Bytes) wird als amount ⊕ Keccak("amount" ‖ Hs(8rA ‖ i))[0..8] gespeichert, der Blinding-Faktor des Commitments als Hs("commitment_mask" ‖ Hs(8rA ‖ i)). Der Empfänger berechnet dasselbe und entschlüsselt den Betrag. Mehr dazu unter Pedersen-Commitments.

Schwachstellen

  • Das Durchsuchen ist teuer: eine Punktmultiplikation für jeden Output jeder Transaktion. Teilweise gelöst durch View Tags.
  • Der Janus-Angriff: Ein Sender, der vermutet, dass zwei Subadressen derselben Person gehören, kann einen Output aus Teilen beider bauen und beobachten, ob der Empfänger die Zahlung „bemerkt“. Wallets haben einen teilweisen Schutz; Carrot schließt die Lücke vollständig.
  • Der Sender kennt r und kann einem Dritten beweisen, dass er an eine bestimmte Adresse gezahlt hat (manchmal nützlich – ein „Zahlungsnachweis“).