Our favorite game, but having state on FHE blockchain!
Play at https://kroist.github.io/encryptedWords/
Repo includes smart contracts in contracts
, full game integration tests in test/fheordle
and game ui in react-wordle
The original game without FHE can be described as follows:
There is a set of valid words
- Browser chooses a secret word
$w$ from$S_{playable}$ . - Player enters some word
$v = c_1 c_2 c_3 c_4 c_5$ . - Browser checks if
$v \in S_{valid}$ and if it is, compares it with$w$ character by character. - Player gets statuses for each character
$c_i$ . e.g if$w = rebus$ and$v = rules$ , player will get statues${\color{green}\textsf{c}}$ ${\color{orange}\textsf{e}}$ ${\color{grey}\textsf{a}}$ ${\color{orange}\textsf{e}}$ ${\color{green}\textsf{c}}$ , where${\color{green}\textsf{c}}$ means correct,${\color{orange}\textsf{e}}$ means character exists in word,${\color{grey}\textsf{a}}$ means character is absent in word. - The game finishes when player has no more tries or when player guesses the word
$w$ (all the statues are${\color{green}\textsf{c}}$ )
Now let's dive into FHE implementation of the game
For sake of simplicity, let's define
There are N publically available words
One might write a FHE circuit to get the word
One might use a trusted relayer, which will receive reencrypted index
The implementation in this repo uses trusted relayer option and "mocks" the call to such relayer because the main goal is to show proof-of-concept of the game
Assume that the player tries the word
Where,
Where,
Player submits the word, which is compared to
When the
In the original game, the secret word
However, it is easy to make the word submission trustless by requiring relayer to submit Merkle proof of inclusion of word into the set. Such functionality is implemented, by default turned off for better UX in frontend.
Because of the nature of the game, proof can be checked only in the end of the game, when the word is revealed.
The contract which needs to be deployed is contracts/FHEordleFactory.sol
It provides public methods
createGame
- creates a new game contractmint
- increments the number of won games if the player winsgamesWon
- mapping returning number of won games for a player
The contract is contracts/FHEordle.sol
public methods:
-
setWord1Id
- sets the secret id of word$[x]$ -
getWord1Id
- available only to relayer - get the reencrypted word id$x$ -
submitWord1
- available only to relayer - set the secret word$[w_x]$ -
guessWord1
- player sends the word$v$ to contract -
getGuess
- player gets$mask_{=}, mask_{\Sigma}$ about previous guess -
getLetterGuess
- util method, get the letters of previous guesses from the history -
claimWin
- player has guessed the word and marks the game as won -
revealWord
- the game has ended and the secret word$w_{x}$ is revealed
Methods that are available but not currently used:
-
submitProof
- relayer submits a merkle proof of inclusion of$w_{x}$ , where$x$ is secret it in merkle tree of the set$S_{playable}$ -
checkProof
-$x$ and$w_{x}$ are revealed and proof is checked
UI signs/sends transaction using Metamask SDK.
Contract calls are written in react-wordle/src/lib/blockchain.ts
As mentioned earlier, for the sake of simplicity and PoC nature of the project, relayer program was not implemented and UI client acts like a relayer itself, therefore leaking the encrypted word.
Private relayer implementation could be as simple as an API calling a two smart contract functions getWord1Id
,submitWord1
.
Or it can have more secure design.
With further development of FHE SNARK's, it would be easy to verify computation on FHE public inputs, making merkle tree proofs be available to check immediately, not at the end of the game.
- smart contracts were implemented using TFHE by zama https://github.com/zama-ai/fhevm
- frontend was cloned from https://github.com/cwackerfuss/react-wordle