GameState:
- seed
- tiles[]
- players: { name: string, score: int,
}
gameState_n+1 = next(gameState_n, turn_n)
- Enters password
- Generates P1.sk = hash(password)
- Could be anything, provided that P1 can remember it next turn
- Sends:
- P1.pk = hash(P1.sk)
- Enters password
- Stores:
- P1.pk
- Sends:
- P2.pk = hash(password)
- Enters password
- Stores:
- P1.pk
- P2.pk
- Sends:
- P2.pk
- P3.pk = hash(password)
- Re-computes (P1.sk, P1.pk)
- Generates seed based on (P2.pk * P1.sk)
- Generates gameState_0 = GameState(seed)
- Plays turn_0
- Generates gameState_1 = next(gameState_0, turn_0)
- Stores:
- hash(gameState_1) (after turn)
- Sends:
- P1.sk
- seed (or gameState_0)
- [turn_0]
- Verifies that hash(P1.sk) = P1.pk
- Verifies that seed = (P2.pk * P1.sk)
- Re-computes gameState_1 = next(gameState_0, turn_0)
- Plays turn_1
- Generates gameState_2 = next(gameState_0, turn_1)
- Stores:
- hash(gameState_2)
- Sends:
- [turn_0, turn_1]
- Verifies hash(gameState_1) against storage
- Re-computes gameState_2 = next(gameState_1, turn_1)
- Plays turn_2
- Generates gameState_3 = next(gameState_2, turn_2)
- Stores:
- hash(gameState_3)
- Sends:
- [turn_0, turn_1, turn_2]
- Verifies hash(gameState_n-1) against storage
- Re-computes gameState_n = next(gameState_n-1, turn_n-1)
- Plays turn_n
- Generates gameState_n+1 = next(gameState_n, turn_n)
- Stores:
- hash(gameState_n+1)
- Sends:
- [turn_0, ..., turn_n]
Each turn is:
- Direction: 1 bit
- Start tile: 15*15 => 8 bits
- Length: 4 bits
- Letters: 3-8 bytes
Note: The opponent's tiles are public with this scheme.
- Verify that commit(received_open) == Store[received_commitment]
- Verify that seed_{n-1} = hash(received_open, commit(Store[r_n])) // commit(Store[r_n]) equals received_commitment from the previous player.
- Re-compute gameState_n from initial seed and turns
- Verify Store[checksum] == hash(gameState_n-1, Store[r_n], Store[received_commitment])
- If hash matches and everything is legal, then we're all good
- Compute seed_n = hash(Store[r_n], received_commitment) // Could replace received_commitment with anything we can't predict.
- Compute new tiles from last turn (can't be in current turn, otherwise they would be predictable)
- new_tiles = rand(seed_n)
- Play turn_n
- Compute gameState_n+1 = next(gameState_n, turn_n, seed_n)
- This does not include the new tiles
- Generate r_n = random() // Should this be deterministic?
- Store (encrypt with password):
- r_n
- received_commitment (can optionally be public)
- checksum = hash(gameState_n+1, r_n, received_commitment)
- Send:
- open (from last commitment) = Store[r_n]
- commitment = commit(r_n) // Also include gameState to force variation?
- all turns as
{ placements: List (letter, x, y), seed: Int }