Was sind effektive und sichere Möglichkeiten, ein Kartenspiel in einem Vertrag zu mischen?

Wir wollen ein Kartenspiel in Ethereum schreiben. Was sind effektive und sichere Methoden, um ein Kartenspiel in einem Vertrag zu mischen und an die Spieler zu verteilen? Es muss so geschehen, dass niemand die Karten des anderen und das gemischte Deck bestimmen kann, indem der Open-Source-Vertragscode untersucht und Transaktionen gemischt werden, die sich alle auf der öffentlichen Ethereum-Blockchain befinden.

Wenn dies vertraglich nicht möglich ist, welche Vorgehensweisen sind möglich?

Bitte lesen Sie diese Frage zum Erstellen einer Zufallszahl ethereum.stackexchange.com/questions/191/…
Ich denke, dies ist erheblich unterschiedlich genug, um eine separate Frage zu rechtfertigen. Das Mischen von Karten ist viel schwieriger als einfaches RNG. Siehe mentales Poker
Der Kommentar, der Sie auf den Wikipedia-Artikel über Mental Poker verweist, beantwortet Ihre Frage wirklich. Ich wollte einen kurzen Überblick darüber geben, wie wir mischen, aber um ehrlich zu sein, ist es genau das, was in diesem Artikel beschrieben wird - und meine Beschreibung war weniger klar geschrieben.
@jimkberry, Es wäre immer noch hilfreich, eine gute Antwort auf diese Frage zu haben, auch wenn es sich nur um eine Zusammenfassung von Wikipedia handelt. Fügen Sie vielleicht einige Dinge hinzu, die Sie aus Erfahrung gelernt haben, oder einen soliden Code.
Ja, ich hoffe auf das, was @TjadenHess vorschlägt
Ist es für Ihren Anwendungsfall in Ordnung, wenn jeder weiß, welche Karten an welche Spieler ausgeteilt werden?
Nein, aber zögern Sie nicht, eine gute Frage zu formulieren und zu beantworten, was Sie in Betracht ziehen ... Ich kann diesen Titel auch aktualisieren, um die Unterschiede in unseren Fragen klarer zu machen, wenn Sie eine erstellen.
Das Ergebnis ist, dass das Mischen/Handhaben der Karte Peer-to-Peer mit kommutativer Verschlüsselung und überhaupt nicht per Vertragscode erfolgt. Mir ist keine Möglichkeit bekannt, wie Sie einen vertrauenswürdigen Einzelserver (sogar einen Ethereum-Vertrag) haben könnten, der mischt und die Geheimhaltung der Hände wahrt. Angesichts dessen bin ich mir nicht sicher, ob das, was ich zu sagen habe, tatsächlich die Frage von @eth beantwortet.
Es klingt wie eine Zusammenfassung der Kommentare von @jimkberry und Piper, dass "Dies kann nicht auf Ethereum getan werden", was auf Ethereum getan werden kann und was außerhalb getan werden muss, wäre die Antwort ...
Es kann auf Ethereum erledigt werden, aber die meiste Arbeit wird von den Spielern selbst erledigt. Der Vertrag kann im Streitfall nur den Gewinner verifizieren und Auszahlungen verwalten.

Antworten (3)

Ein Deck mischen


Kommutative Verschlüsselung:

Alice und Bob wollen ein Kartenspiel so mischen, dass keiner weiß, was die Hand des anderen enthält, aber die Hände disjunkt sind (dh nur einer darf eine bestimmte Karte haben).

Protokoll:

Alice und Bob entscheiden sich für ein Verschlüsselungsprotokoll mit folgenden Merkmalen

  1. E K (X) ist X -verschlüsselt mit Schlüssel K
  2. D K [ E K (X) ] = X für alle K und X
  3. E. K. [ E. J. (X) ] = E. J. [ E. K. (X) ]
    • dh E(X) ist kommutativ
  4. Bei gegebenen X und E K (X) ist es rechnerisch unmöglich, K abzuleiten
  5. Gegeben X und Y , J und K , so dass E J (X) = E K (Y) nicht gefunden werden kann
    • dh E(x) ist stoßfest

Nun, da Alice und Bob ein Verschlüsselungsschema haben:

  1. Bob nimmt die zweiundfünfzig Karten ( "2C","3C",...,"AS" ) und verschlüsselt jede mit Schlüssel B
  2. Bob mischt die verschlüsselten Karten in zufälliger Reihenfolge und schickt den Stapel an Alice
    • Alice kann die Karten nicht sehen, da sie B nicht kennt
  3. Alice wählt fünf Karten aus und schickt sie an Bob zurück
    • Das ist Bobs Hand. Bob kann diese Karten sehen, da er B kennt
  4. Alice schickt fünf weitere Karten an Bob zurück, aber zuerst verschlüsselt sie sie mit Schlüssel A
    • Jede Karte wird nun als E A [ E B (X) ] verschlüsselt , was E B [ E A (X) ] durch Eigenschaft Nr. 4 entspricht.
  5. Bob entschlüsselt diese Karten und schickt sie zurück
    • Bob kann die Karten nicht sehen, da er A nicht kennt . Alice hingegen kann sie sehen und das sind ihre Hände.

Weitere Karten können mit einem ähnlichen Verfahren gezogen werden. Nach dem Spiel zeigen Alice und Bob A und B , damit sie überprüfen können, dass keiner der Spieler geschummelt hat.

Tatsächlich existieren Verschlüsselungsverfahren mit den aufgeführten Eigenschaften, darunter auch ein RSA-ähnliches Verfahren. Siehe meine Quelle für weitere Details.


Verwendung in Verträgen:

Verträge können verwendet werden, um die Nachrichten zwischen Spielern zu verwalten und Belohnungen zu verteilen. Der Vertrag muss keine Logik ausführen, es sei denn, die Spieler sind sich über die Ergebnisse nicht einig. Im Falle einer Meinungsverschiedenheit muss der Herausforderer genügend Ether aufbringen, um die Gaskosten für die Verifizierung des Spiels zu decken. Dann muss der andere Spieler den Anruf ausführen, um das Spielergebnis zu überprüfen. Das Gas wird dem wahrheitsgemäßen Spieler zurückerstattet und die Runde wird vom Betrüger abgebrochen oder verwirkt.

Dies wird mentales Poker genannt

Da der Quellcode von Ethereum-Verträgen verifiziert werden kann, sollte dies so einfach sein wie die Verwendung eines RNG, um zufällig Karten aus einem Stapel auszuwählen. Jeder, der überprüfen möchte, ob das Deck angemessen gemischt ist, kann den Vertragsquellcode überprüfen.

Da die Erzeugung einer guten Zufälligkeit an anderer Stelle angesprochen wird , geht diese Antwort davon aus, dass der Kartenmischvertrag Zugriff auf gute Zufallszahlen hat.

Verwenden von On-Demand-Zufälligkeit

Die Herstellung eines gut gemischten Decks kann durch zufälliges Auswählen von Karten aus einem nicht gemischten Deck und das Erstellen eines neuen Decks erfolgen, bis das nicht gemischte Deck aufgebraucht ist.

contract Deck {
   uint8[52] deck;

   function getRandomNumber() returns (uint) {
       ...;
   }

   function shuffle() {
      uint8[52] memory unshuffled;

      for (uint8 i=0; i < 52; i++) {
          unshuffled[i] = i;
      }

      uint cardIndex;

      for (i=0; i < 52; i++) {
          cardIndex = getRandomNumber() % (52 - i);
          deck[i] = unshuffled[cardIndex];
          unshuffled[cardIndex] = unshuffled[52 - i - 1]
      }
   }
}

Dieser Kontrakt repräsentiert jede der 52 Karten als ganze Zahl zwischen 0 und 51 einschließlich. Ein Aufruf der shuffleFunktion füllt die deckSpeichervariable mit einem Kartenspiel mit 52 Karten in zufälliger Reihenfolge.

Reagieren auf zufällige Eingaben.

Dies setzt voraus, dass die Zufälligkeit sicher angefordert werden kann, was nicht unbedingt möglich ist. Wenn dies nicht der Fall ist und stattdessen Zufälligkeit in den Vertrag geschickt werden muss, sollte das folgende allgemeine Konzept genauso gut funktionieren.

contract Deck {
   uint8[52] deck;

   function shuffle(bytes randomBytes) {
      if (randomBytes.length < 52) throw;

      uint8[52] memory unshuffled;

      for (uint8 i=0; i < 52; i++) {
          unshuffled[i] = i;
      }

      uint8 cardIndex;

      for (i=0; i < 52; i++) {
          cardIndex = uint8(randomBytes[i]) % (52 - i);
          deck[i] = unshuffled[cardIndex];
          unshuffled[cardIndex] = unshuffled[52 - i - 1];
      }
   }
}

Diese Version des Vertrags erfordert mindestens 52 Zufallsbytes, die in den Aufruf von aufgenommen werden müssen shuffle.

Dies beantwortet die Frage wie angegeben, aber ich denke, die Implikation war, dass die Karten heimlich gemischt und ausgeteilt würden, sodass die Spieler die Hände der anderen Spieler nicht sehen können. Ich finde die Frage schlecht formuliert.
Danke für das Feedback @TjadenHess. Ich hoffe, ich habe die Frage mit Kursivschrift besser verdeutlicht.
@eth: Ich glaube nicht, dass deine aktuelle Kursivschrift etwas verdeutlicht, es ist nicht klar, ob Leute in der Lage sein müssen, heimlich Karten zu ziehen, ohne dass die anderen Spieler es wissen.
"muss so gemacht werden, dass niemand [die Karten des anderen und] bestimmen kann, was das gemischte Deck ist" ok, ich habe den Teil in [] hinzugefügt (es verdeutlicht, ist aber nicht sicher, ob es wirklich benötigt wird)
Angesichts der neuen Anforderungen neige ich dazu, meine Antwort auf „Dies ist auf Ethereum nicht möglich, da es für Verträge unmöglich ist, Geheimnisse zu bewahren.“ zu ändern. Diese Art von App ist so komplex, dass ich bezweifle, dass es sich um eine nützliche Frage handelt, da die Lösung wahrscheinlich eine Koordination durch andere Netzwerke wie Flüstern erfordert. Möchte sich noch jemand dazu äußern?
In Fällen, in denen jeder weiß, wie das Deck gemischt wird, stellt dies kein Problem dar, und in Fällen, in denen das gespielte Spiel nicht das gesamte Deck erfordert, halte ich es für sehr verschwenderisch, die 52 Karten vorher zu mischen (so wie die typische richtige Art des Mischens vor sich geht ). Karten sollten nach Bedarf gemischt werden, wobei so wenige Vorgänge wie möglich durchgeführt werden müssen, um genügend gemischte Karten zu produzieren.
Klingt so, als hätten Sie Recht @PiperMerriam: "Die Lösung erfordert wahrscheinlich eine Koordination durch andere Netzwerke". Ich stimme Ihrer Antwort zu.
Für maximale Effizienz sollte das Spiel wahrscheinlich auf einem Seitenkanal wie Whisper gespielt werden, aber es ist definitiv möglich, es on-chain zu spielen. Der Vertrag sieht die Karten nicht bis zum Schluss, er vertraut einfach darauf, dass die Spieler ehrlich sind. Nur wenn die Spieler einen Streit haben, werden die Karten aufgedeckt und der Vertrag bestätigt die Zughistorie

Wenn Sie wollen, dass sich Karten nicht wiederholen, dann ist das eigentlich ein ziemlich schwieriges Problem. Ein einfacheres Problem ist, wenn es uns egal ist, ob dieselbe Karte mehrmals ausgeteilt wird (z. B. Sie haben ein Pik-Ass und ich ein Pik-Ass).

Betrachten wir ein einfaches Spiel mit 2 Spielern. Jeder Spieler erhält 1 Karte und es ist in Ordnung, dass beide Spieler die gleiche Karte bekommen. Man kann sich das so vorstellen, als würden die beiden Karten von zwei verschiedenen Decks ausgeteilt. Um dies zu implementieren, können wir uns jede Karte als einen Index zwischen 0 und 51 (einschließlich) vorstellen. Hier erfahren Sie, wie Sie die Karte von Spieler 1 fair generieren, sodass nur er weiß, was es ist.

  1. Spieler 2 generiert eine Zufallszahl im Bereich 0..51 namens p2_offset. Als nächstes generiert er eine zufällige Zeichenfolge namens p2_secret (zum Beispiel "pcjshjfgn"). Als nächstes übermittelt er sha3(p2_offset, p2_secret) an die Blockchain.
  2. Spieler 1 generiert eine Zufallszahl im Bereich 0..51 namens p1_offset und eine zufällige Zeichenfolge p1_secret und übermittelt sha3(p1_offset, p1_secret) an die Blockchain.
  3. Spieler 2 gibt p2_offset und p2_secret an den Ethereum-Vertrag weiter, der bestätigt, dass sha3 dieser Werte mit dem übereinstimmt, was er zuvor eingereicht hat.
  4. Spieler 1 kann jetzt herausfinden, was seine Karte ist, indem er (p2_offset + p1_offset) mod 52 ausführt. Beachten Sie, dass Spieler 2 nicht weiß, was die Karten sind, weil ihm p1_offset unbekannt ist.
  5. Spieler 1 kann seine Karte aufdecken, indem er p1_offset und p1_secret an den Vertrag übermittelt. Auch hier bestätigt der Vertrag, dass sha3 dieser Werte mit dem übereinstimmt, was Spieler 1 zuvor übermittelt hat.

Derselbe Ansatz kann zum Erzeugen der Karte von Spieler 2 verwendet werden.

Sicherzustellen, dass jede Karte nur einmal erscheint, finde ich ziemlich herausfordernd. Das könnten wir einmal sagen