mirror of
https://github.com/luxfhe/example-blind-auction.git
synced 2026-10-30 18:13:37 +00:00
- Update to unified FHE decryption API - Update dependencies to @luxfi/contracts
113 lines
4.9 KiB
Solidity
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;
|
|
}
|
|
}
|