FHEordle
December 18, 2023 · View on GitHub
Our favorite game, but having state on FHE blockchain!
Play at https://kroist.github.io/encryptedWords/
Repo
Repo includes smart contracts in contracts, full game integration tests in test/fheordle and game ui in react-wordle
How it works
Original Wordle Game
The original game without FHE can be described as follows:
There is a set of valid words and a set of playable words .
- Browser chooses a secret word from .
- Player enters some word .
- Browser checks if and if it is, compares it with character by character.
- Player gets statuses for each character . e.g if and , player will get statues , where means correct, means character exists in word, means character is absent in word.
- The game finishes when player has no more tries or when player guesses the word (all the statues are )
Now let's dive into FHE implementation of the game
FHE game
For sake of simplicity, let's define as encrypted value of some .
Word generation
There are N publically available words from set . Smart contract generates $0 < [x] \leq N[w_{x}]$:
Fully-trustless solution
One might write a FHE circuit to get the word from the set of encrypted words using encrypted index as input (which would be very costly at the time of writing).
Trusted relayer
One might use a trusted relayer, which will receive reencrypted index , find , ecnrypt it and submit to blockchain.
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 https://github.com/kroist/encryptedWords/blob/4a07d9d48fdc13e37661567a7169903fdd533523/react-wordle/src/lib/blockchain.ts#L937
Word guessing
Assume that the player tries the word . And the alphabet is . We define a FHE function:
Where, $mask_{=} = \{i \in [0..4] | v(i) = w_x(i) \}$$
Where,
Player submits the word, which is compared to in FHE. Player receives . The first mask is a set of positions of word's letters equal to the . The second mask is a set of letters, which are in both of the words at the same time.
When the , the player has guessed the word. Otherwise we can deduce correct/existing/absent characters in word easily.
Validity of words
In the original game, the secret word has to be from the set . If we use relayer for word submission, we have to trust it with choosing the valid 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.
Dive into the implementation
Contracts
Factory contract
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
Game contract
The contract is contracts/FHEordle.sol
public methods:
setWord1Id- sets the secret id of wordgetWord1Id- available only to relayer - get the reencrypted word idsubmitWord1- available only to relayer - set the secret wordguessWord1- player sends the word to contractgetGuess- player gets about previous guessgetLetterGuess- util method, get the letters of previous guesses from the historyclaimWin- player has guessed the word and marks the game as wonrevealWord- the game has ended and the secret word is revealed
Methods that are available but not currently used:
submitProof- relayer submits a merkle proof of inclusion of , where is secret it in merkle tree of the setcheckProof- and are revealed and proof is checked
UI
UI signs/sends transaction using Metamask SDK.
Contract calls are written in react-wordle/src/lib/blockchain.ts
Further development considerations
Usage of real private relayer
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.
Validity of words
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.
Credits
- smart contracts were implemented using TFHE by zama https://github.com/zama-ai/fhevm
- frontend was cloned from https://github.com/cwackerfuss/react-wordle