Alice and Bob wants to deal one card to each other in a trustless way.
52 integers are fixed in the contract that represent 52 cards in the deck. Call this
uint[52] deck
A large number.
Pair of secret numbers K and L are generated in the front-end such that GCD(K, phi(N)) =
1
and L.K = 1 (mod N)
Note: All arithmetic from now are modulo N
.
Alice sends the numbers deck[0]**K_Alice, ..., deck[51]**K_Alice
in a random order and stores it in
uint[52] cards
Bob picks two indices from cards
, call it, alice_index
and bob_index
Bob sends cards[bob_index]**K_Bob
, call it bob_card
Alice sends bob_card**L_Alice
, call it bob_card
Alice reveals keys K_Alice
and L_Alice
Bob reveals keys K_Bob
and L_Bob
- Check if
cards[alice_index]**L_Alice
is indeck
. - Check if
bob_card**L_Bob
is indeck
. - Optionally check if
cards[0]**L_Alice, ... cards[52]**L_Alice
is same asdeck
.
// SPDX-License-Identifier: GPL v3
pragma solidity >= 0.7.0;
pragma experimental ABIEncoderV2;
enum State {
Commit_Alice,
Commit_Bob,
Play_Bob,
Play_Alice,
Reveal_Alice,
Reveal_Bob,
Done
}
struct Secret{
uint K;
uint L;
}
struct Instance {
address alice;
address bob;
uint[52] cards;
uint8 alice_index;
uint8 bob_index;
uint bob_card;
State state;
Secret alice_secret;
Secret bob_secret;
}
contract Game {
// The encoding of 2♠, ..., A♠, 2♥, ..., A♥, 2♦, ..., A♦, 2♣, ..., A♣
uint[52] deck;
/* TODO Fix value of N */
uint constant N = type(uint).max;
mapping (uint => Instance) data;
uint index = 0;
constructor() {
/* TODO store an encoding of deck */
}
function commit_alice(uint[52] memory cards) public returns (uint _index) {
Instance memory instance;
instance.alice = msg.sender;
instance.cards = cards;
instance.state = State.Commit_Alice;
_index = index;
data[index] = instance;
++index;
}
function commit_bob(uint _index, uint8 alice_index, uint8 bob_index) public returns (uint) {
/* TODO verify state */
data[_index].state = State.Commit_Bob;
data[_index].bob = msg.sender;
data[_index].alice_index = alice_index;
data[_index].bob_index = bob_index;
return index;
}
function play_bob(uint _index, uint card) public {
/* TODO verify state and sender */
data[_index].state = State.Play_Bob;
data[_index].bob_card = card;
}
function play_alice(uint _index, uint card) public {
/* TODO verify state and sender */
data[_index].state = State.Play_Alice;
data[_index].bob_card = card;
}
function reveal_alice(uint _index, Secret memory alice_secret) public {
/* TODO verify state and sender */
data[_index].alice_secret = alice_secret;
}
function reveal_bob(uint _index, Secret memory bob_secret) public {
/* TODO verify state and sender */
data[_index].bob_secret = bob_secret;
}
function verify(uint _index) public returns (bool) {
/* TODO Compute correctness */
data[_index].state = State.Done;
}
}