Skip to content

Commit

Permalink
Merge pull request #354 from zama-ai/fix/euint160_nooracleservicechange
Browse files Browse the repository at this point in the history
Fix/euint160 nooracleservicechange
  • Loading branch information
jatZama authored Apr 9, 2024
2 parents c5f5f06 + d98c02f commit 17357a9
Show file tree
Hide file tree
Showing 15 changed files with 634 additions and 12 deletions.
92 changes: 92 additions & 0 deletions codegen/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type euint8 is uint256;
type euint16 is uint256;
type euint32 is uint256;
type euint64 is uint256;
type eaddress is uint256;
library Common {
// Values used to communicate types to the runtime.
Expand All @@ -21,6 +22,8 @@ library Common {
uint8 internal constant euint16_t = 3;
uint8 internal constant euint32_t = 4;
uint8 internal constant euint64_t = 5;
uint8 internal constant euint128_t = 6;
uint8 internal constant euint160_t = 7;
}
`;
}
Expand Down Expand Up @@ -729,6 +732,8 @@ function tfheCustomMethods(ctx: CodegenContext, mocked: boolean): string {
}
}
// Returns the network public FHE key.
function fhePubKey() internal view returns (bytes memory) {
return Impl.fhePubKey();
Expand Down Expand Up @@ -782,6 +787,93 @@ function tfheCustomMethods(ctx: CodegenContext, mocked: boolean): string {
function randEuint64(uint64 upperBound) internal view returns (euint64) {
return euint64.wrap(Impl.randBounded(upperBound, Common.euint64_t));
}
// Decrypts the encrypted 'value'.
function decrypt(eaddress value) internal view returns (address) {
return address(uint160(Impl.decrypt(eaddress.unwrap(value))));
}
// Reencrypt the encrypted 'value'.
function reencrypt(eaddress value, bytes32 publicKey) internal view returns (bytes memory reencrypted) {
return Impl.reencrypt(eaddress.unwrap(value), publicKey);
}
// From bytes to eaddress
function asEaddress(bytes memory ciphertext) internal pure returns (eaddress) {
return eaddress.wrap(Impl.verify(ciphertext, Common.euint160_t));
}
// Convert a plaintext value to an encrypted asEaddress.
function asEaddress(address value) internal pure returns (eaddress) {
return eaddress.wrap(Impl.trivialEncrypt(uint160(value), Common.euint160_t));
}
// Return true if the enrypted integer is initialized and false otherwise.
function isInitialized(eaddress v) internal pure returns (bool) {
return eaddress.unwrap(v) != 0;
}
// Evaluate eq(a, b) and return the result.
function eq(eaddress a, eaddress b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
if (!isInitialized(b)) {
b = asEaddress(address(0));
}
return ebool.wrap(Impl.eq(eaddress.unwrap(a), eaddress.unwrap(b), false));
}
// Evaluate ne(a, b) and return the result.
function ne(eaddress a, eaddress b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
if (!isInitialized(b)) {
b = asEaddress(address(0));
}
return ebool.wrap(Impl.ne(eaddress.unwrap(a), eaddress.unwrap(b), false));
}
// Evaluate eq(a, b) and return the result.
function eq(eaddress a, address b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.eq(eaddress.unwrap(a), bProc, true));
}
// Evaluate eq(a, b) and return the result.
function eq(address b, eaddress a) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.eq(eaddress.unwrap(a), bProc, true));
}
// Evaluate ne(a, b) and return the result.
function ne(eaddress a, address b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.ne(eaddress.unwrap(a), bProc, true));
}
// Evaluate ne(a, b) and return the result.
function ne(address b, eaddress a) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.ne(eaddress.unwrap(a), bProc, true));
}
function select(ebool control, eaddress a, eaddress b) internal pure returns (eaddress) {
return eaddress.wrap(Impl.select(ebool.unwrap(control), eaddress.unwrap(a), eaddress.unwrap(b)));
}
`;
if (mocked) {
result += `
Expand Down
7 changes: 6 additions & 1 deletion docs/fundamentals/decrypt.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function requestDecryption(
) returns(uint256 requestID)
```

The first argument, `ct`, should be an array of ciphertexts of a single same type i.e `eXXX` stands for either `ebool`, `euint4`, `euint8`, `euint16`, `euint32` or `euint64`. `ct` is the list of ciphertexts that are requested to be decrypted. Calling `requestDecryption` will emit an `EventDecryptionEXXX` on the `OraclePredeploy` contract which will be detected by a relayer. Then, the relayer will send the corresponding ciphertexts to the KMS for decryption before fulfilling the request.
The first argument, `ct`, should be an array of ciphertexts of a single same type i.e `eXXX` stands for either `ebool`, `euint4`, `euint8`, `euint16`, `euint32`, `euint64` or `eaddress`. `ct` is the list of ciphertexts that are requested to be decrypted. Calling `requestDecryption` will emit an `EventDecryptionEXXX` on the `OraclePredeploy` contract which will be detected by a relayer. Then, the relayer will send the corresponding ciphertexts to the KMS for decryption before fulfilling the request.

`callbackSelector` is the function selector of the callback function which will be called by the `OraclePredeploy` contract once the relayer fulfils the decryption request. Notice that the callback function should always follow this convention:

Expand Down Expand Up @@ -83,6 +83,8 @@ function addParamsEUint32(uint256 requestID, euint32 _euint32) internal;
function addParamsEUint64(uint256 requestID, euint64 _euint64) internal;
function addParamsEAddress(uint256 requestID, address _eaddress) internal;
function addParamsAddress(uint256 requestID, address _address) internal;
function addParamsUint(uint256 requestID, uint256 _uint) internal;
Expand All @@ -103,6 +105,8 @@ function getParamsEUint32(uint256 requestID) internal;
function getParamsEUint64(uint256 requestID) internal;
function getParamsEAddress(uint256 requestID) internal;
function getParamsAddress(uint256 requestID) internal;
function getParamsUint(uint256 requestID) internal;
Expand Down Expand Up @@ -151,6 +155,7 @@ event ResultCallbackUint8(uint256 indexed requestID, bool success, bytes result)
event ResultCallbackUint16(uint256 indexed requestID, bool success, bytes result);
event ResultCallbackUint32(uint256 indexed requestID, bool success, bytes result);
event ResultCallbackUint64(uint256 indexed requestID, bool success, bytes result);
event ResultCallbackAddress(uint256 indexed requestID, bool success, bytes result);
```

The first argument is the `requestID` of the corresponding decryption request, `success` is a boolean assessing if the call to the callback succeeded, and `result` is the bytes array corresponding the to return data from the callback.
Expand Down
14 changes: 14 additions & 0 deletions examples/TestAsyncDecrypt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ contract TestAsyncDecrypt is OracleCaller {
euint16 xUint16;
euint32 xUint32;
euint64 xUint64;
eaddress xAddress;

bool public yBool;
uint8 public yUint4;
uint8 public yUint8;
uint16 public yUint16;
uint32 public yUint32;
uint64 public yUint64;
address public yAddress;

constructor() {
xBool = TFHE.asEbool(true);
Expand All @@ -27,6 +29,7 @@ contract TestAsyncDecrypt is OracleCaller {
xUint16 = TFHE.asEuint16(16);
xUint32 = TFHE.asEuint32(32);
xUint64 = TFHE.asEuint64(64);
xAddress = TFHE.asEaddress(0x8ba1f109551bD432803012645Ac136ddd64DBA72);
}

function requestBool() public {
Expand Down Expand Up @@ -100,4 +103,15 @@ contract TestAsyncDecrypt is OracleCaller {
yUint64 = decryptedInput;
return decryptedInput;
}

function requestAddress() public {
eaddress[] memory cts = new eaddress[](1);
cts[0] = xAddress;
Oracle.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100);
}

function callbackAddress(uint256 /*requestID*/, address decryptedInput) public onlyOracle returns (address) {
yAddress = decryptedInput;
return decryptedInput;
}
}
70 changes: 69 additions & 1 deletion examples/tests/TFHEManualTestSuite.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.20;

import "../../abstracts/Reencrypt.sol";
import "../../lib/TFHE.sol";

contract TFHEManualTestSuite {
contract TFHEManualTestSuite is Reencrypt {
function test_select(
bytes calldata control,
bytes calldata ifTrue,
Expand All @@ -15,6 +16,73 @@ contract TFHEManualTestSuite {
return TFHE.decrypt(TFHE.select(controlProc, ifTrueProc, ifFalseProc));
}

function test_select_eaddress(
bytes calldata control,
bytes calldata ifTrue,
bytes calldata ifFalse
) public view returns (address) {
ebool controlProc = TFHE.asEbool(control);
eaddress ifTrueProc = TFHE.asEaddress(ifTrue);
eaddress ifFalseProc = TFHE.asEaddress(ifFalse);
return TFHE.decrypt(TFHE.select(controlProc, ifTrueProc, ifFalseProc));
}

function test_eq_eaddress_eaddress(bytes calldata a, bytes calldata b) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
eaddress bProc = TFHE.asEaddress(b);
ebool result = TFHE.eq(aProc, bProc);
return TFHE.decrypt(result);
}

function test_ne_eaddress_eaddress(bytes calldata a, bytes calldata b) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
eaddress bProc = TFHE.asEaddress(b);
ebool result = TFHE.ne(aProc, bProc);
return TFHE.decrypt(result);
}

function test_eq_eaddress_address(bytes calldata a, address b) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
address bProc = b;
ebool result = TFHE.eq(aProc, bProc);
return TFHE.decrypt(result);
}

function test_eq_address_eaddress(address b, bytes calldata a) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
address bProc = b;
ebool result = TFHE.eq(aProc, bProc);
return TFHE.decrypt(result);
}

function test_ne_eaddress_address(bytes calldata a, address b) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
address bProc = b;
ebool result = TFHE.ne(aProc, bProc);
return TFHE.decrypt(result);
}

function test_ne_address_eaddress(address b, bytes calldata a) public view returns (bool) {
eaddress aProc = TFHE.asEaddress(a);
address bProc = b;
ebool result = TFHE.ne(aProc, bProc);
return TFHE.decrypt(result);
}

function test_eaddress_decrypt(bytes calldata addr) public view returns (address) {
eaddress addProc = TFHE.asEaddress(addr);
return TFHE.decrypt(addProc);
}

function test_reencrypt_eaddress(
bytes calldata addr,
bytes32 publicKey,
bytes calldata signature
) public view virtual onlySignedPublicKey(publicKey, signature) returns (bytes memory) {
eaddress addProc = TFHE.asEaddress(addr);
return TFHE.reencrypt(addProc, publicKey);
}

function test_ebool_to_euint4_cast(bool input) public view returns (uint16) {
return TFHE.decrypt(TFHE.asEuint4(TFHE.asEbool(input)));
}
Expand Down
90 changes: 90 additions & 0 deletions lib/TFHE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type euint8 is uint256;
type euint16 is uint256;
type euint32 is uint256;
type euint64 is uint256;
type eaddress is uint256;

library Common {
// Values used to communicate types to the runtime.
Expand All @@ -17,6 +18,8 @@ library Common {
uint8 internal constant euint16_t = 3;
uint8 internal constant euint32_t = 4;
uint8 internal constant euint64_t = 5;
uint8 internal constant euint128_t = 6;
uint8 internal constant euint160_t = 7;
}

import "./Impl.sol";
Expand Down Expand Up @@ -5742,6 +5745,93 @@ library TFHE {
return euint64.wrap(Impl.randBounded(upperBound, Common.euint64_t));
}

// Decrypts the encrypted 'value'.
function decrypt(eaddress value) internal view returns (address) {
return address(uint160(Impl.decrypt(eaddress.unwrap(value))));
}

// Reencrypt the encrypted 'value'.
function reencrypt(eaddress value, bytes32 publicKey) internal view returns (bytes memory reencrypted) {
return Impl.reencrypt(eaddress.unwrap(value), publicKey);
}

// From bytes to eaddress
function asEaddress(bytes memory ciphertext) internal pure returns (eaddress) {
return eaddress.wrap(Impl.verify(ciphertext, Common.euint160_t));
}

// Convert a plaintext value to an encrypted asEaddress.
function asEaddress(address value) internal pure returns (eaddress) {
return eaddress.wrap(Impl.trivialEncrypt(uint160(value), Common.euint160_t));
}

// Return true if the enrypted integer is initialized and false otherwise.
function isInitialized(eaddress v) internal pure returns (bool) {
return eaddress.unwrap(v) != 0;
}

// Evaluate eq(a, b) and return the result.
function eq(eaddress a, eaddress b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
if (!isInitialized(b)) {
b = asEaddress(address(0));
}
return ebool.wrap(Impl.eq(eaddress.unwrap(a), eaddress.unwrap(b), false));
}

// Evaluate ne(a, b) and return the result.
function ne(eaddress a, eaddress b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
if (!isInitialized(b)) {
b = asEaddress(address(0));
}
return ebool.wrap(Impl.ne(eaddress.unwrap(a), eaddress.unwrap(b), false));
}

// Evaluate eq(a, b) and return the result.
function eq(eaddress a, address b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.eq(eaddress.unwrap(a), bProc, true));
}

// Evaluate eq(a, b) and return the result.
function eq(address b, eaddress a) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.eq(eaddress.unwrap(a), bProc, true));
}

// Evaluate ne(a, b) and return the result.
function ne(eaddress a, address b) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.ne(eaddress.unwrap(a), bProc, true));
}

// Evaluate ne(a, b) and return the result.
function ne(address b, eaddress a) internal pure returns (ebool) {
if (!isInitialized(a)) {
a = asEaddress(address(0));
}
uint256 bProc = uint256(uint160(b));
return ebool.wrap(Impl.ne(eaddress.unwrap(a), bProc, true));
}

function select(ebool control, eaddress a, eaddress b) internal pure returns (eaddress) {
return eaddress.wrap(Impl.select(ebool.unwrap(control), eaddress.unwrap(a), eaddress.unwrap(b)));
}

// Decrypts the encrypted 'value'.
function decrypt(ebool value) internal view returns (bool) {
return (Impl.decrypt(ebool.unwrap(value)) != 0);
Expand Down
Loading

0 comments on commit 17357a9

Please sign in to comment.