There are two primary ways to use the encrypted boolean (ebool), generated from TFHE comparisons, within design logic.
TFHE.select
TFHE.isInitialized
TFHE.select
The TFHE.select multiplexer function allows you to pass in the ebool as the first argument and returns the second argument if the ebool is true, and the third argument if it'sfalse. This is particularly useful for avoiding information leakage, as TFHE.select provides conditional logic without exposing data through traditional if/else statements.
// hiddenValue will be 1 if eboolValue is true and 0 if falseeuint8 hiddenValue = TFHE.select(eboolValue, TFHE.asEuint8(1), TFHE.asEuint8(0));
In the private voting example, we first compare whether or not the encryptedChoice matches 1 or 0, which gives us an ebool. If the encrypted boolean is a true value, then inFavorCountToCast will take on the value of encryptedVoteCount. If it’s false, inFavorCountToCast will be assigned an encrypted value of 0. Therefore, from an outside perspective, you wouldn't know if inFavorCountToCast was assigned the actual vote count or 0. The same logic is applied to againstCountToCast but in reverse. And finally, both inFavorCountToCast and againstCountToCast are added to the encrypted tallies, inFavorCountEncrypted, and againstCountEncrypted, but only one of them would have incremented.
// Private state variableseuint64 private againstCountEncrypted;euint64 private inFavorCountEncrypted;/** * @notice Casts a vote with a given encrypted vote count and choice * @param encryptedVoteCount The encrypted voting power of the user * @param encryptedChoice Encrypted choice where 0 = against, 1 = in favor * @param inputProof Proof for decrypting inputs */functioncastEncryptedVote(einput encryptedVoteCount, einput encryptedChoice,bytescalldata inputProof) public {// Form the encrypted choice (0 or 1) for vote type euint8 userChoice = TFHE.asEuint8(encryptedChoice, inputProof);// Determine the vote type as a boolean: true = in favor, false = against ebool voteChoice = TFHE.eq(TFHE.asEuint8(1), userChoice);// Form the vote power euint64 votePower = TFHE.asEuint64(encryptedVoteCount, inputProof);// Update vote count for the sender encryptedVoteCounts[msg.sender] = votePower;// Update vote choice for the sender encryptedVoteChoices[msg.sender] = voteChoice;// Initialize local variables to avoid issues with uninitialized handles euint64 inFavorCountToCast = TFHE.asEuint64(0); euint64 againstCountToCast = TFHE.asEuint64(0);// Conditional assignment based on vote choice inFavorCountToCast = TFHE.select( voteChoice, votePower,// Set vote power for in-favor count if vote choice is true TFHE.asEuint64(0) // Otherwise, set to 0 ); againstCountToCast = TFHE.select( voteChoice, TFHE.asEuint64(0),// Set to 0 if vote choice is true votePower // Set vote power for against count if vote choice is false );// Add the computed vote powers to the encrypted tallies againstCountEncrypted = TFHE.add(againstCountEncrypted, againstCountToCast); inFavorCountEncrypted = TFHE.add(inFavorCountEncrypted, inFavorCountToCast);// Allow both the contract and owner to access these encrypted tallies in the future TFHE.allow(againstCountEncrypted,address(this)); TFHE.allow(againstCountEncrypted, owner); TFHE.allow(inFavorCountEncrypted,address(this)); TFHE.allow(inFavorCountEncrypted, owner);// Allow the user/contract to view their vote choice and vote count in the future TFHE.allow(encryptedVoteCounts[msg.sender], msg.sender); TFHE.allow(encryptedVoteChoices[msg.sender], msg.sender); TFHE.allow(encryptedVoteCounts[msg.sender],address(this)); TFHE.allow(encryptedVoteChoices[msg.sender],address(this)); }
TFHE.isInitialized
TFHE.isInitialized returns a boolean that specifies whether or not an encrypted handle has been initialized.
euint32 userBalance = erc20Balance[msg.sender];if (TFHE.isInitialized(userBalance)) {// Some logic } else {// Some logic }