Comparison Operations

Encrypted comparisons (eq, ne, gt, lt, ge, le) and conditional selection. Demonstrates FHE.select for branching without information leakage, essential for "find maximum" or threshold logic.

circle-info

To run this example correctly, make sure the files are placed in the following directories:

  • .sol file → <your-project-root-dir>/contracts/

  • .ts file → <your-project-root-dir>/test/

This ensures Hardhat can compile and test your contracts as expected.

chevron-right🔐 FHE API Reference (13 items)hashtag

Types: ebool · euint32 · externalEuint32

Functions:

  • FHE.allow() - Grants PERMANENT permission for address to decrypt/use value

  • FHE.allowThis() - Grants contract permission to operate on ciphertext

  • FHE.eq() - Encrypted equality: returns ebool(a == b)

  • FHE.fromExternal() - Validates and converts external encrypted input using inputProof

  • FHE.ge() - Encrypted greater-or-equal: returns ebool(a >= b)

  • FHE.gt() - Encrypted greater-than: returns ebool(a > b)

  • FHE.le() - Encrypted less-or-equal: returns ebool(a <= b)

  • FHE.lt() - Encrypted less-than: returns ebool(a < b)

  • FHE.ne() - Encrypted inequality: returns ebool(a != b)

  • FHE.select() - Encrypted if-then-else: select(cond, a, b) → returns a if true, b if false

// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;

import {
    FHE,
    ebool,
    euint32,
    externalEuint32
} from "@fhevm/solidity/lib/FHE.sol";
import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";

/**
 * @notice Encrypted comparisons (eq, ne, gt, lt, ge, le) and conditional selection.
 *         Demonstrates FHE.select for branching without information leakage,
 *         essential for "find maximum" or threshold logic.
 *
 * @dev Comparisons return ebool; select avoids revealing values during branching.
 */
contract FHEComparison is ZamaEthereumConfig {
    euint32 private _a;
    euint32 private _b;
    ebool private _boolResult;
    euint32 private _selectedResult;

    function setA(externalEuint32 inputA, bytes calldata inputProof) external {
        _a = FHE.fromExternal(inputA, inputProof);
        FHE.allowThis(_a);
    }

    function setB(externalEuint32 inputB, bytes calldata inputProof) external {
        _b = FHE.fromExternal(inputB, inputProof);
        FHE.allowThis(_b);
    }

    function computeEq() external {
        _boolResult = FHE.eq(_a, _b);
        _grantBoolPermissions();
    }

    function computeNe() external {
        _boolResult = FHE.ne(_a, _b);
        _grantBoolPermissions();
    }

    function computeGt() external {
        _boolResult = FHE.gt(_a, _b);
        _grantBoolPermissions();
    }

    function computeLt() external {
        _boolResult = FHE.lt(_a, _b);
        _grantBoolPermissions();
    }

    function computeGe() external {
        _boolResult = FHE.ge(_a, _b);
        _grantBoolPermissions();
    }

    function computeLe() external {
        _boolResult = FHE.le(_a, _b);
        _grantBoolPermissions();
    }

    /// @notice Encrypted maximum using select: (a > b) ? a : b
    /// @dev 🔀 Why select? Using if(aGtB) would decrypt and leak the comparison!
    function computeMaxViaSelect() external {
        ebool aGtB = FHE.gt(_a, _b);
        // select evaluates both branches, picks one without revealing which
        _selectedResult = FHE.select(aGtB, _a, _b);
        FHE.allowThis(_selectedResult);
        FHE.allow(_selectedResult, msg.sender);
    }

    /// @notice Encrypted minimum using select: (a < b) ? a : b
    function computeMinViaSelect() external {
        ebool aLtB = FHE.lt(_a, _b);
        _selectedResult = FHE.select(aLtB, _a, _b);
        FHE.allowThis(_selectedResult);
        FHE.allow(_selectedResult, msg.sender);
    }

    function getBoolResult() public view returns (ebool) {
        return _boolResult;
    }

    function getSelectedResult() public view returns (euint32) {
        return _selectedResult;
    }

    function _grantBoolPermissions() internal {
        FHE.allowThis(_boolResult);
        FHE.allow(_boolResult, msg.sender);
    }
}

Last updated