Files
Fuma Nama d6738a228e refactor(fhe): unify API - reveal() replaces getDecryptResult()
- Update to unified FHE decryption API
- Update dependencies to @luxfi/contracts
2025-12-31 21:11:39 -08:00

113 lines
4.9 KiB
Solidity

// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity >=0.8.13 <0.9.0;
import { euint32, ebool, FHE } from "@luxfi/contracts/fhe/FHE.sol";
import "./BytesLib.sol";
/// @title Encrypted Address Library
/// @notice Provides methods for creating and managing addresses encrypted with FHE (Fully Homomorphic Encryption)
/// @dev Assumes the existence of an FHE library that implements fully homomorphic encryption functions
/// @dev A representation of an encrypted address using Fully Homomorphic Encryption.
/// It consists of 5 encrypted 32-bit unsigned integers (`euint32`).
struct Eaddress {
euint32[5] values;
}
library ConfAddress {
/// @notice Encrypts a plaintext Ethereum address into its encrypted representation (`eaddress`).
/// @dev Iterates over 5 chunks of the address, applying a bitmask to each, then encrypting with `FHE`.
/// @param addr The plain Ethereum address to encrypt
/// @return eaddr The encrypted representation of the address
function toEaddress(address addr) internal returns (Eaddress memory) {
uint160 addrValue = uint160(address(addr));
/// @dev A bitmask constant for selecting specific 32-bit chunks from a 160-bit Ethereum address.
/// It has the first 32 bits set to 1, and the remaining bits set to 0.
uint160 MASK = uint160(uint256(0x000000000000000000000000FFFFFFFF00000000000000000000000000000000));
Eaddress memory eaddr;
for (uint i = 0; i < 5; i++) {
uint160 currentChunkOffset = uint160(i * 32);
uint160 mask = MASK >> currentChunkOffset; // Mask the correct chunk based on i
uint32 chunk = uint32((addrValue & mask) >> (128 - currentChunkOffset));
eaddr.values[i] = FHE.asEuint32(chunk);
}
return eaddr;
}
/// @notice Decrypts an `eaddress` to retrieve the original plaintext Ethereum address.
/// @dev This operation should be used with caution as it exposes the encrypted address.
/// @dev Uses async decrypt pattern - caller must wait for decrypt results
/// @param eaddr The encrypted address to decrypt
/// @return The decrypted plaintext Ethereum address
function unsafeToAddress(Eaddress memory eaddr) internal returns (address) {
uint160 addrValue;
// Request decryption for all values
for (uint i = 0; i < 5; i++) {
FHE.decrypt(eaddr.values[i]);
}
// Get decryption results
for (uint i = 0; i < 5; i++) {
uint32 currentChunkOffset = uint32((4 - i) * 32);
(uint256 val, bool ready) = FHE.revealSafe(eaddr.values[i]);
require(ready, "Decrypt not ready");
uint160 currentValue = uint160(uint32(val)) << currentChunkOffset;
addrValue += currentValue;
}
bytes memory addrBz = new bytes(32);
assembly {
mstore(add(addrBz, 32), addrValue)
}
return BytesLib.toAddress(addrBz, 12);
}
/// @notice Re-encrypts the encrypted values within an `eaddress`.
/// @dev The re-encryption is done to change the encrypted representation without
/// altering the underlying plaintext address, which can be useful for obfuscation purposes in storage.
/// @param eaddr The encrypted address to re-encrypt
/// @param ezero An encrypted zero value that triggers the re-encryption
function resestEaddress(Eaddress memory eaddr, euint32 ezero) internal {
for (uint i = 0; i < 5; i++) {
// Adding zero will practiaclly reencrypt the value without it being changed
eaddr.values[i] = FHE.add(eaddr.values[i], ezero);
}
}
/// @notice Determines if an encrypted address is equal to a given plaintext Ethereum address.
/// @dev This operation encrypts the plaintext address and compares the encrypted representations.
/// @param lhs The encrypted address to compare
/// @param addr The plaintext Ethereum address to compare against
/// @return res A boolean indicating if the encrypted and plaintext addresses are equal
function equals(Eaddress storage lhs, address payable addr) internal returns (ebool) {
Eaddress memory rhs = toEaddress(addr);
ebool res = FHE.eq(lhs.values[0], rhs.values[0]);
for (uint i = 1; i < 5; i++) {
res = FHE.and(res, FHE.eq(lhs.values[i], rhs.values[i]));
}
return res;
}
function conditionalUpdate(
ebool condition,
Eaddress memory eaddr,
Eaddress memory newEaddr
) internal returns (Eaddress memory) {
for (uint i = 0; i < 5; i++) {
// Even if condition is false the ENCRYPTED value of eaddr.values[i] will be changed
// because the encryption is not deterministic
// so no one will know whether the highest bidder was changed or not
eaddr.values[i] = FHE.select(condition, newEaddr.values[i], eaddr.values[i]);
}
return eaddr;
}
}