Control Structures

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 false
euint8 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 variables
euint64 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
     */
    function castEncryptedVote(einput encryptedVoteCount, einput encryptedChoice, bytes calldata 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
 }

Last updated