@cofhe/mock-contracts 0.7.1 → 1.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +10 -0
- package/contracts/ACPShareRegistry.sol +227 -114
- package/contracts/ACPTimestampRevoker.sol +36 -34
- package/contracts/MockACL.sol +35 -16
- package/contracts/MockCoFHE.sol +201 -86
- package/contracts/MockCoFHEAddressBook.sol +64 -0
- package/contracts/MockERC1967Proxy.sol +13 -0
- package/contracts/MockPermissioned.sol +16 -0
- package/contracts/MockTaskManager.sol +143 -28
- package/contracts/MockThresholdNetwork.sol +5 -5
- package/contracts/MockZkVerifier.sol +2 -2
- package/contracts/Permissioned.sol +240 -143
- package/contracts/cofhe-contracts.json +10 -0
- package/dist/index.d.mts +980 -101
- package/dist/index.d.ts +980 -101
- package/dist/index.js +817 -118
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +816 -119
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -6
- package/remappings.txt +1 -0
- package/src/ACPShareRegistry.ts +469 -56
- package/src/MockACL.ts +56 -25
- package/src/MockCoFHEAddressBook.ts +114 -0
- package/src/MockERC1967Proxy.ts +74 -0
- package/src/MockTaskManager.ts +73 -6
- package/src/index.ts +4 -0
- package/src/typechain-types/ACPShareRegistry.ts +309 -12
- package/src/typechain-types/MockACL.ts +65 -6
- package/src/typechain-types/MockCoFHEAddressBook.ts +124 -0
- package/src/typechain-types/MockERC1967Proxy.ts +85 -0
- package/src/typechain-types/MockTaskManager.ts +66 -1
- package/src/typechain-types/index.ts +2 -0
package/contracts/MockACL.sol
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
pragma solidity >=0.8.19 <0.9.0;
|
|
3
3
|
|
|
4
4
|
import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { ACP, SCOPE_GLOBAL, SCOPE_CONTRACT, SCOPE_HANDLES } from './Permissioned.sol';
|
|
6
|
+
import { MockPermissioned } from './MockPermissioned.sol';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @title ACL
|
|
@@ -32,6 +32,9 @@ contract MockACL is MockPermissioned {
|
|
|
32
32
|
/// @param receiver Address the share would have been directed at.
|
|
33
33
|
error NotShared(uint256 handle, address receiver);
|
|
34
34
|
|
|
35
|
+
/// @notice Returned when the TaskManager address being set is zero.
|
|
36
|
+
error InvalidTaskManagerAddress();
|
|
37
|
+
|
|
35
38
|
/// @notice Returned when a share is pending but was written by a different party.
|
|
36
39
|
/// @param expected Sharer the receiver named.
|
|
37
40
|
/// @param actual Sharer recorded in the slot.
|
|
@@ -53,6 +56,9 @@ contract MockACL is MockPermissioned {
|
|
|
53
56
|
/// @notice Emitted when the share registry address is updated (zero = unset).
|
|
54
57
|
event ShareRegistryUpdated(address oldAddress, address newAddress);
|
|
55
58
|
|
|
59
|
+
/// @notice Emitted when the TaskManager address is updated.
|
|
60
|
+
event TaskManagerUpdated(address oldAddress, address newAddress);
|
|
61
|
+
|
|
56
62
|
/// @custom:storage-location erc7201:cofhe.storage.ACL
|
|
57
63
|
struct ACLStorage {
|
|
58
64
|
mapping(uint256 handle => bool isGlobal) globalHandles;
|
|
@@ -62,6 +68,7 @@ contract MockACL is MockPermissioned {
|
|
|
62
68
|
/// @dev ACP infrastructure addresses served to SDKs (appended fields — do not reorder)
|
|
63
69
|
address defaultRevokerContract;
|
|
64
70
|
address shareRegistry;
|
|
71
|
+
address taskManager;
|
|
65
72
|
}
|
|
66
73
|
|
|
67
74
|
/// @notice Name of the contract.
|
|
@@ -76,9 +83,6 @@ contract MockACL is MockPermissioned {
|
|
|
76
83
|
/// @notice Patch version of the contract.
|
|
77
84
|
uint256 private constant PATCH_VERSION = 0;
|
|
78
85
|
|
|
79
|
-
/// @notice TaskManagerAddress address.
|
|
80
|
-
address public constant TASK_MANAGER_ADDRESS_ = TASK_MANAGER_ADDRESS;
|
|
81
|
-
|
|
82
86
|
/// @dev keccak256(abi.encode(uint256(keccak256("cofhe.storage.ACL")) - 1)) & ~bytes32(uint256(0xff))
|
|
83
87
|
bytes32 private constant ACL_SLOT =
|
|
84
88
|
keccak256(abi.encode(uint256(keccak256('cofhe.storage.ACL')) - 1)) & ~bytes32(uint256(0xff));
|
|
@@ -103,7 +107,7 @@ contract MockACL is MockPermissioned {
|
|
|
103
107
|
* @param requester Address of the account giving the permissions.
|
|
104
108
|
*/
|
|
105
109
|
function allow(uint256 handle, address account, address requester) public virtual {
|
|
106
|
-
if (msg.sender !=
|
|
110
|
+
if (msg.sender != _taskManager()) {
|
|
107
111
|
revert DirectAllowForbidden(msg.sender);
|
|
108
112
|
}
|
|
109
113
|
|
|
@@ -122,7 +126,7 @@ contract MockACL is MockPermissioned {
|
|
|
122
126
|
* @param requester Address of the account giving the permissions.
|
|
123
127
|
*/
|
|
124
128
|
function allowGlobal(uint256 handle, address requester) public virtual {
|
|
125
|
-
if (msg.sender !=
|
|
129
|
+
if (msg.sender != _taskManager()) {
|
|
126
130
|
revert DirectAllowForbidden(msg.sender);
|
|
127
131
|
}
|
|
128
132
|
|
|
@@ -140,7 +144,7 @@ contract MockACL is MockPermissioned {
|
|
|
140
144
|
* @param handlesList List of handles.
|
|
141
145
|
*/
|
|
142
146
|
function allowForDecryption(uint256[] memory handlesList, address requester) public virtual {
|
|
143
|
-
if (msg.sender !=
|
|
147
|
+
if (msg.sender != _taskManager()) {
|
|
144
148
|
revert DirectAllowForbidden(msg.sender);
|
|
145
149
|
}
|
|
146
150
|
|
|
@@ -167,11 +171,11 @@ contract MockACL is MockPermissioned {
|
|
|
167
171
|
* @param requester Address of the requester.
|
|
168
172
|
*/
|
|
169
173
|
function allowTransient(uint256 handle, address account, address requester) public virtual {
|
|
170
|
-
if (msg.sender !=
|
|
174
|
+
if (msg.sender != _taskManager()) {
|
|
171
175
|
revert DirectAllowForbidden(msg.sender);
|
|
172
176
|
}
|
|
173
177
|
|
|
174
|
-
if (!isAllowed(handle, requester) && requester !=
|
|
178
|
+
if (!isAllowed(handle, requester) && requester != _taskManager()) {
|
|
175
179
|
revert SenderNotAllowed(requester);
|
|
176
180
|
}
|
|
177
181
|
|
|
@@ -217,14 +221,14 @@ contract MockACL is MockPermissioned {
|
|
|
217
221
|
* @notice Grants `receiver` transient access to `handle` and records `sharer` as the
|
|
218
222
|
* party that handed it over, for the duration of this transaction.
|
|
219
223
|
* @dev The caller must be the Task Manager contract.
|
|
220
|
-
* @dev Stricter than allowTransient: there is no
|
|
224
|
+
* @dev Stricter than allowTransient: there is no TaskManager bypass, since
|
|
221
225
|
* nothing shares on the Task Manager's own behalf.
|
|
222
226
|
* @param handle Handle.
|
|
223
227
|
* @param sharer Address handing the handle over.
|
|
224
228
|
* @param receiver Address the handle is being handed to.
|
|
225
229
|
*/
|
|
226
230
|
function shareCtHash(uint256 handle, address sharer, address receiver) public virtual {
|
|
227
|
-
if (msg.sender !=
|
|
231
|
+
if (msg.sender != _taskManager()) {
|
|
228
232
|
revert DirectAllowForbidden(msg.sender);
|
|
229
233
|
}
|
|
230
234
|
|
|
@@ -247,7 +251,7 @@ contract MockACL is MockPermissioned {
|
|
|
247
251
|
* @param receiver Address consuming the share.
|
|
248
252
|
*/
|
|
249
253
|
function receiveCtHash(uint256 handle, address expectedSharer, address receiver) public virtual {
|
|
250
|
-
if (msg.sender !=
|
|
254
|
+
if (msg.sender != _taskManager()) {
|
|
251
255
|
revert DirectAllowForbidden(msg.sender);
|
|
252
256
|
}
|
|
253
257
|
|
|
@@ -270,7 +274,7 @@ contract MockACL is MockPermissioned {
|
|
|
270
274
|
* @param delegateeContract Delegatee contract.
|
|
271
275
|
*/
|
|
272
276
|
function delegateAccount(address delegatee, address delegateeContract) public virtual {
|
|
273
|
-
if (msg.sender !=
|
|
277
|
+
if (msg.sender != _taskManager()) {
|
|
274
278
|
revert DirectAllowForbidden(msg.sender);
|
|
275
279
|
}
|
|
276
280
|
if (delegateeContract == msg.sender) {
|
|
@@ -328,7 +332,7 @@ contract MockACL is MockPermissioned {
|
|
|
328
332
|
* @return taskManagerAddress Address of the TaskManager.
|
|
329
333
|
*/
|
|
330
334
|
function getTaskManagerAddress() public view virtual returns (address) {
|
|
331
|
-
return
|
|
335
|
+
return _taskManager();
|
|
332
336
|
}
|
|
333
337
|
|
|
334
338
|
/**
|
|
@@ -378,7 +382,7 @@ contract MockACL is MockPermissioned {
|
|
|
378
382
|
* Account Abstraction when bundling several UserOps calling the TaskManagerCoprocessor.
|
|
379
383
|
*/
|
|
380
384
|
function cleanTransientStorage() external virtual {
|
|
381
|
-
if (msg.sender !=
|
|
385
|
+
if (msg.sender != _taskManager()) {
|
|
382
386
|
revert DirectAllowForbidden(msg.sender);
|
|
383
387
|
}
|
|
384
388
|
|
|
@@ -458,6 +462,21 @@ contract MockACL is MockPermissioned {
|
|
|
458
462
|
$.shareRegistry = newAddress;
|
|
459
463
|
}
|
|
460
464
|
|
|
465
|
+
/// @notice Sets the TaskManager allowed to drive this ACL (unrestricted in the mock;
|
|
466
|
+
/// the production setter is onlyRole(DEFAULT_ADMIN_ROLE)).
|
|
467
|
+
function setTaskManager(address newAddress) external {
|
|
468
|
+
if (newAddress == address(0)) {
|
|
469
|
+
revert InvalidTaskManagerAddress();
|
|
470
|
+
}
|
|
471
|
+
ACLStorage storage $ = _getACLStorage();
|
|
472
|
+
emit TaskManagerUpdated($.taskManager, newAddress);
|
|
473
|
+
$.taskManager = newAddress;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function _taskManager() private view returns (address) {
|
|
477
|
+
return _getACLStorage().taskManager;
|
|
478
|
+
}
|
|
479
|
+
|
|
461
480
|
/// @notice V3 (ACP) access check — the scope table.
|
|
462
481
|
///
|
|
463
482
|
/// | condition | result |
|
package/contracts/MockCoFHE.sol
CHANGED
|
@@ -6,6 +6,11 @@ import { FHE } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
|
|
|
6
6
|
import { FunctionId, Utils } from '@fhenixprotocol/cofhe-contracts/ICofhe.sol';
|
|
7
7
|
import { console } from 'hardhat/console.sol';
|
|
8
8
|
|
|
9
|
+
/// @dev Foundry/hevm cheatcode address: address(uint160(uint256(keccak256('hevm cheat code')))).
|
|
10
|
+
/// Only reachable when running under forge with cheatcode access granted (vm.allowCheatcodes);
|
|
11
|
+
/// on Hardhat this address has no code and the shim is never enabled.
|
|
12
|
+
address constant CHEATCODE_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;
|
|
13
|
+
|
|
9
14
|
address constant ZK_VERIFIER_SIGNER_ADDRESS = 0x6E12D8C87503D4287c294f2Fdef96ACd9DFf6bd2;
|
|
10
15
|
uint256 constant ZK_VERIFIER_SIGNER_PRIVATE_KEY = 49099792800763675079532137679706322989817545357788440619111868498148356080914;
|
|
11
16
|
|
|
@@ -33,9 +38,27 @@ abstract contract MockCoFHE {
|
|
|
33
38
|
|
|
34
39
|
bool public logOps = true;
|
|
35
40
|
|
|
41
|
+
/// @dev When true, mock-only work (plaintext replication + logging) runs between
|
|
42
|
+
/// pauseGasMetering/resumeGasMetering cheatcodes so it is excluded from forge's
|
|
43
|
+
/// gas accounting, giving gas numbers closer to the real CoFHE task manager.
|
|
44
|
+
/// Only enable under forge AFTER granting this contract cheatcode access
|
|
45
|
+
/// (vm.allowCheatcodes(address(taskManager))); must stay false on Hardhat.
|
|
46
|
+
bool public mockGasExcluded = false;
|
|
47
|
+
|
|
36
48
|
mapping(uint256 => uint256) public mockStorage;
|
|
37
49
|
mapping(uint256 => bool) public inMockStorage;
|
|
38
50
|
|
|
51
|
+
/// @dev Emitted for each block of mock-only work (op replication, decrypt-task storage,
|
|
52
|
+
/// log building) with the gas it consumed, whenever that work runs metered (i.e. not
|
|
53
|
+
/// under forge's paused gas metering). Tooling sums these per transaction to compute
|
|
54
|
+
/// gas usage excluding mock overhead - see the hardhat plugin's getAdjustedGasUsed.
|
|
55
|
+
event MockGasConsumed(uint256 gas);
|
|
56
|
+
|
|
57
|
+
/// @dev Gas spent emitting MockGasConsumed itself (LOG1 + 32 data bytes + bookkeeping).
|
|
58
|
+
/// It lands after the closing gasleft() read, so it is added back as a constant to
|
|
59
|
+
/// keep the reported figure covering the full mock-only cost.
|
|
60
|
+
uint256 internal constant MOCK_GAS_EVENT_COST = 1030;
|
|
61
|
+
|
|
39
62
|
error InputNotInMockStorage(uint256 ctHash);
|
|
40
63
|
|
|
41
64
|
// Used internally to check if we missed any operations in the mocks
|
|
@@ -49,6 +72,59 @@ abstract contract MockCoFHE {
|
|
|
49
72
|
logOps = _logOps;
|
|
50
73
|
}
|
|
51
74
|
|
|
75
|
+
function setMockGasExcluded(bool _mockGasExcluded) public {
|
|
76
|
+
mockGasExcluded = _mockGasExcluded;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// @dev How a mock-only block is being accounted for.
|
|
80
|
+
/// MEASURE - metering is live: measure with gasleft() and emit MockGasConsumed.
|
|
81
|
+
/// PAUSED_BY_MOCK - we paused forge's metering and must resume it afterwards.
|
|
82
|
+
/// ALREADY_UNMETERED - metering was already paused by the caller's own test; leave it
|
|
83
|
+
/// untouched (the mock work is unmetered either way) and emit nothing.
|
|
84
|
+
enum MockGasMode {
|
|
85
|
+
MEASURE,
|
|
86
|
+
PAUSED_BY_MOCK,
|
|
87
|
+
ALREADY_UNMETERED
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// @dev True while forge's gas metering is paused: gasleft() is frozen, so two consecutive
|
|
91
|
+
/// reads are equal. While metered they differ by the cost of the second GAS opcode.
|
|
92
|
+
/// (Foundry has no query cheatcode for this state.)
|
|
93
|
+
function _isGasMeteringPaused() internal view returns (bool) {
|
|
94
|
+
uint256 a = gasleft();
|
|
95
|
+
uint256 b = gasleft();
|
|
96
|
+
return a == b;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// @dev Opens a mock-only block. Under forge (detected by code at the cheatcode address -
|
|
100
|
+
/// forge plants a marker byte there, other environments have none) with exclusion
|
|
101
|
+
/// enabled, pauses gas metering unless the caller's test already paused it - never
|
|
102
|
+
/// steal a pause we don't own, or `_mockGasTrackEnd` would resume metering out from
|
|
103
|
+
/// under the user's own measurement region. Everywhere else, records gasleft() so the
|
|
104
|
+
/// block's cost can be reported via MockGasConsumed.
|
|
105
|
+
/// Only wrap code that cannot revert - a revert inside the block would skip
|
|
106
|
+
/// `_mockGasTrackEnd` and leak paused metering (see sendEventCreated's trampoline
|
|
107
|
+
/// for the revert-safe variant).
|
|
108
|
+
function _mockGasTrackStart() internal returns (MockGasMode mode, uint256 startGas) {
|
|
109
|
+
if (mockGasExcluded && CHEATCODE_ADDRESS.code.length > 0) {
|
|
110
|
+
if (_isGasMeteringPaused()) return (MockGasMode.ALREADY_UNMETERED, 0);
|
|
111
|
+
(bool ok, ) = CHEATCODE_ADDRESS.call(abi.encodeWithSignature('pauseGasMetering()'));
|
|
112
|
+
if (ok) return (MockGasMode.PAUSED_BY_MOCK, 0);
|
|
113
|
+
}
|
|
114
|
+
return (MockGasMode.MEASURE, gasleft());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// @dev Closes a mock-only block: resumes metering (if we paused it) or emits the
|
|
118
|
+
/// measured cost. A caller-owned pause is left exactly as we found it.
|
|
119
|
+
function _mockGasTrackEnd(MockGasMode mode, uint256 startGas) internal {
|
|
120
|
+
if (mode == MockGasMode.PAUSED_BY_MOCK) {
|
|
121
|
+
(bool ok, ) = CHEATCODE_ADDRESS.call(abi.encodeWithSignature('resumeGasMetering()'));
|
|
122
|
+
ok;
|
|
123
|
+
} else if (mode == MockGasMode.MEASURE) {
|
|
124
|
+
emit MockGasConsumed(startGas - gasleft() + MOCK_GAS_EVENT_COST);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
52
128
|
// Utils
|
|
53
129
|
|
|
54
130
|
function getUintTypeFromHash(uint256 hash) internal pure returns (uint8) {
|
|
@@ -224,76 +300,92 @@ abstract contract MockCoFHE {
|
|
|
224
300
|
logAllow(operation, ctHash, account);
|
|
225
301
|
}
|
|
226
302
|
|
|
303
|
+
/// @dev Same as MOCK_logAllow, but the log-string building runs excluded from forge gas
|
|
304
|
+
/// metering / reported via MockGasConsumed, like the rest of the mock-only work.
|
|
305
|
+
/// With logging disabled the whole thing is skipped - the residual cost is negligible.
|
|
306
|
+
/// Safe without the revert trampoline: logAllow only formats bounded strings.
|
|
307
|
+
function MOCK_trackedLogAllow(string memory operation, uint256 ctHash, address account) internal {
|
|
308
|
+
if (!logOps) return;
|
|
309
|
+
(MockGasMode mode, uint256 startGas) = _mockGasTrackStart();
|
|
310
|
+
logAllow(operation, ctHash, account);
|
|
311
|
+
_mockGasTrackEnd(mode, startGas);
|
|
312
|
+
}
|
|
313
|
+
|
|
227
314
|
// Mock functions
|
|
228
315
|
|
|
229
316
|
function MOCK_verifyKeyInStorage(uint256 ctHash) internal view {
|
|
230
317
|
if (!inMockStorage[ctHash]) revert InputNotInMockStorage(ctHash);
|
|
231
318
|
}
|
|
232
319
|
|
|
233
|
-
function MOCK_unaryOperation(uint256 ctHash,
|
|
234
|
-
if (
|
|
320
|
+
function MOCK_unaryOperation(uint256 ctHash, FunctionId funcId, uint256 input) internal {
|
|
321
|
+
if (funcId == FunctionId.random) {
|
|
235
322
|
_set(ctHash, uint256(blockhash(block.number - 1)));
|
|
236
|
-
logOperation('FHE.random', '', logCtHash(ctHash));
|
|
323
|
+
if (logOps) logOperation('FHE.random', '', logCtHash(ctHash));
|
|
237
324
|
return;
|
|
238
325
|
}
|
|
239
|
-
if (
|
|
326
|
+
if (funcId == FunctionId.cast) {
|
|
240
327
|
_set(ctHash, _get(input));
|
|
241
|
-
logOperation('FHE.cast', logCtHash(input), logCtHash(ctHash));
|
|
328
|
+
if (logOps) logOperation('FHE.cast', logCtHash(input), logCtHash(ctHash));
|
|
242
329
|
return;
|
|
243
330
|
}
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
331
|
+
if (funcId == FunctionId.not) {
|
|
332
|
+
if (getIsBoolTypeFromHash(ctHash)) {
|
|
333
|
+
bool inputIsTruthy = _get(input) == 1;
|
|
334
|
+
_set(ctHash, !inputIsTruthy);
|
|
335
|
+
} else {
|
|
336
|
+
// bitwise NOT, masked to the type width by _set
|
|
337
|
+
_set(ctHash, ~_get(input));
|
|
338
|
+
}
|
|
339
|
+
if (logOps) logOperation('FHE.not', logCtHash(input), logCtHash(ctHash));
|
|
248
340
|
return;
|
|
249
341
|
}
|
|
250
|
-
if (
|
|
342
|
+
if (funcId == FunctionId.square) {
|
|
251
343
|
unchecked {
|
|
252
344
|
_set(ctHash, _get(input) * _get(input));
|
|
253
345
|
}
|
|
254
|
-
logOperation('FHE.square', string.concat(logCtHash(input), ' * ', logCtHash(input)), logCtHash(ctHash));
|
|
346
|
+
if (logOps) logOperation('FHE.square', string.concat(logCtHash(input), ' * ', logCtHash(input)), logCtHash(ctHash));
|
|
255
347
|
return;
|
|
256
348
|
}
|
|
257
|
-
revert InvalidUnaryOperation(
|
|
349
|
+
revert InvalidUnaryOperation(Utils.functionIdToString(funcId));
|
|
258
350
|
}
|
|
259
351
|
|
|
260
|
-
function MOCK_twoInputOperation(uint256 ctHash,
|
|
261
|
-
if (
|
|
352
|
+
function MOCK_twoInputOperation(uint256 ctHash, FunctionId funcId, uint256 input1, uint256 input2) internal {
|
|
353
|
+
if (funcId == FunctionId.sub) {
|
|
262
354
|
unchecked {
|
|
263
355
|
_set(ctHash, _get(input1) - _get(input2));
|
|
264
356
|
}
|
|
265
|
-
logOperation('FHE.sub', string.concat(logCtHash(input1), ' - ', logCtHash(input2)), logCtHash(ctHash));
|
|
357
|
+
if (logOps) logOperation('FHE.sub', string.concat(logCtHash(input1), ' - ', logCtHash(input2)), logCtHash(ctHash));
|
|
266
358
|
return;
|
|
267
359
|
}
|
|
268
|
-
if (
|
|
360
|
+
if (funcId == FunctionId.add) {
|
|
269
361
|
unchecked {
|
|
270
362
|
_set(ctHash, _get(input1) + _get(input2));
|
|
271
363
|
}
|
|
272
|
-
logOperation('FHE.add', string.concat(logCtHash(input1), ' + ', logCtHash(input2)), logCtHash(ctHash));
|
|
364
|
+
if (logOps) logOperation('FHE.add', string.concat(logCtHash(input1), ' + ', logCtHash(input2)), logCtHash(ctHash));
|
|
273
365
|
return;
|
|
274
366
|
}
|
|
275
|
-
if (
|
|
367
|
+
if (funcId == FunctionId.xor) {
|
|
276
368
|
unchecked {
|
|
277
369
|
_set(ctHash, _get(input1) ^ _get(input2));
|
|
278
370
|
}
|
|
279
|
-
logOperation('FHE.xor', string.concat(logCtHash(input1), ' ^ ', logCtHash(input2)), logCtHash(ctHash));
|
|
371
|
+
if (logOps) logOperation('FHE.xor', string.concat(logCtHash(input1), ' ^ ', logCtHash(input2)), logCtHash(ctHash));
|
|
280
372
|
return;
|
|
281
373
|
}
|
|
282
|
-
if (
|
|
374
|
+
if (funcId == FunctionId.and) {
|
|
283
375
|
unchecked {
|
|
284
376
|
_set(ctHash, _get(input1) & _get(input2));
|
|
285
377
|
}
|
|
286
|
-
logOperation('FHE.and', string.concat(logCtHash(input1), ' & ', logCtHash(input2)), logCtHash(ctHash));
|
|
378
|
+
if (logOps) logOperation('FHE.and', string.concat(logCtHash(input1), ' & ', logCtHash(input2)), logCtHash(ctHash));
|
|
287
379
|
return;
|
|
288
380
|
}
|
|
289
|
-
if (
|
|
381
|
+
if (funcId == FunctionId.or) {
|
|
290
382
|
unchecked {
|
|
291
383
|
_set(ctHash, _get(input1) | _get(input2));
|
|
292
384
|
}
|
|
293
|
-
logOperation('FHE.or', string.concat(logCtHash(input1), ' | ', logCtHash(input2)), logCtHash(ctHash));
|
|
385
|
+
if (logOps) logOperation('FHE.or', string.concat(logCtHash(input1), ' | ', logCtHash(input2)), logCtHash(ctHash));
|
|
294
386
|
return;
|
|
295
387
|
}
|
|
296
|
-
if (
|
|
388
|
+
if (funcId == FunctionId.div) {
|
|
297
389
|
uint256 cleartext2 = _get(input2);
|
|
298
390
|
if (cleartext2 == 0) {
|
|
299
391
|
_set(ctHash, type(uint256).max);
|
|
@@ -302,143 +394,166 @@ abstract contract MockCoFHE {
|
|
|
302
394
|
_set(ctHash, _get(input1) / cleartext2);
|
|
303
395
|
}
|
|
304
396
|
}
|
|
305
|
-
logOperation('FHE.div', string.concat(logCtHash(input1), ' / ', logCtHash(input2)), logCtHash(ctHash));
|
|
397
|
+
if (logOps) logOperation('FHE.div', string.concat(logCtHash(input1), ' / ', logCtHash(input2)), logCtHash(ctHash));
|
|
306
398
|
return;
|
|
307
399
|
}
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
|
|
400
|
+
if (funcId == FunctionId.rem) {
|
|
401
|
+
// Like TFHE-rs, the remainder by zero returns the first input unchanged
|
|
402
|
+
uint256 cleartext2 = _get(input2);
|
|
403
|
+
if (cleartext2 == 0) {
|
|
404
|
+
_set(ctHash, _get(input1));
|
|
405
|
+
} else {
|
|
406
|
+
unchecked {
|
|
407
|
+
_set(ctHash, _get(input1) % cleartext2);
|
|
408
|
+
}
|
|
311
409
|
}
|
|
312
|
-
logOperation('FHE.rem', string.concat(logCtHash(input1), ' % ', logCtHash(input2)), logCtHash(ctHash));
|
|
410
|
+
if (logOps) logOperation('FHE.rem', string.concat(logCtHash(input1), ' % ', logCtHash(input2)), logCtHash(ctHash));
|
|
313
411
|
return;
|
|
314
412
|
}
|
|
315
|
-
if (
|
|
413
|
+
if (funcId == FunctionId.mul) {
|
|
316
414
|
unchecked {
|
|
317
415
|
_set(ctHash, _get(input1) * _get(input2));
|
|
318
416
|
}
|
|
319
|
-
logOperation('FHE.mul', string.concat(logCtHash(input1), ' * ', logCtHash(input2)), logCtHash(ctHash));
|
|
417
|
+
if (logOps) logOperation('FHE.mul', string.concat(logCtHash(input1), ' * ', logCtHash(input2)), logCtHash(ctHash));
|
|
320
418
|
return;
|
|
321
419
|
}
|
|
322
|
-
if (
|
|
420
|
+
if (funcId == FunctionId.shl) {
|
|
323
421
|
unchecked {
|
|
324
422
|
_set(ctHash, _get(input1) << _get(input2));
|
|
325
423
|
}
|
|
326
|
-
logOperation('FHE.shl', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
424
|
+
if (logOps) logOperation('FHE.shl', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
327
425
|
return;
|
|
328
426
|
}
|
|
329
|
-
if (
|
|
427
|
+
if (funcId == FunctionId.shr) {
|
|
330
428
|
unchecked {
|
|
331
429
|
_set(ctHash, _get(input1) >> _get(input2));
|
|
332
430
|
}
|
|
333
|
-
logOperation('FHE.shr', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
431
|
+
if (logOps) logOperation('FHE.shr', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
334
432
|
return;
|
|
335
433
|
}
|
|
336
|
-
if (
|
|
434
|
+
if (funcId == FunctionId.gte) {
|
|
337
435
|
_set(ctHash, _get(input1) >= _get(input2));
|
|
338
|
-
logOperation('FHE.gte', string.concat(logCtHash(input1), ' >= ', logCtHash(input2)), logCtHash(ctHash));
|
|
436
|
+
if (logOps) logOperation('FHE.gte', string.concat(logCtHash(input1), ' >= ', logCtHash(input2)), logCtHash(ctHash));
|
|
339
437
|
return;
|
|
340
438
|
}
|
|
341
|
-
if (
|
|
439
|
+
if (funcId == FunctionId.lte) {
|
|
342
440
|
_set(ctHash, _get(input1) <= _get(input2));
|
|
343
|
-
logOperation('FHE.lte', string.concat(logCtHash(input1), ' <= ', logCtHash(input2)), logCtHash(ctHash));
|
|
441
|
+
if (logOps) logOperation('FHE.lte', string.concat(logCtHash(input1), ' <= ', logCtHash(input2)), logCtHash(ctHash));
|
|
344
442
|
return;
|
|
345
443
|
}
|
|
346
|
-
if (
|
|
444
|
+
if (funcId == FunctionId.lt) {
|
|
347
445
|
_set(ctHash, _get(input1) < _get(input2));
|
|
348
|
-
logOperation('FHE.lt', string.concat(logCtHash(input1), ' < ', logCtHash(input2)), logCtHash(ctHash));
|
|
446
|
+
if (logOps) logOperation('FHE.lt', string.concat(logCtHash(input1), ' < ', logCtHash(input2)), logCtHash(ctHash));
|
|
349
447
|
return;
|
|
350
448
|
}
|
|
351
|
-
if (
|
|
449
|
+
if (funcId == FunctionId.gt) {
|
|
352
450
|
_set(ctHash, _get(input1) > _get(input2));
|
|
353
|
-
logOperation('FHE.gt', string.concat(logCtHash(input1), ' > ', logCtHash(input2)), logCtHash(ctHash));
|
|
451
|
+
if (logOps) logOperation('FHE.gt', string.concat(logCtHash(input1), ' > ', logCtHash(input2)), logCtHash(ctHash));
|
|
354
452
|
return;
|
|
355
453
|
}
|
|
356
|
-
if (
|
|
454
|
+
if (funcId == FunctionId.min) {
|
|
357
455
|
uint256 min;
|
|
358
456
|
unchecked {
|
|
359
457
|
min = _get(input1) < _get(input2) ? _get(input1) : _get(input2);
|
|
360
458
|
}
|
|
361
459
|
_set(ctHash, min);
|
|
362
460
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
461
|
+
if (logOps)
|
|
462
|
+
logOperation(
|
|
463
|
+
'FHE.min',
|
|
464
|
+
string.concat('min(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
465
|
+
logCtHash(ctHash)
|
|
466
|
+
);
|
|
368
467
|
return;
|
|
369
468
|
}
|
|
370
|
-
if (
|
|
469
|
+
if (funcId == FunctionId.max) {
|
|
371
470
|
uint256 max;
|
|
372
471
|
unchecked {
|
|
373
472
|
max = _get(input1) > _get(input2) ? _get(input1) : _get(input2);
|
|
374
473
|
}
|
|
375
474
|
_set(ctHash, max);
|
|
376
475
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
476
|
+
if (logOps)
|
|
477
|
+
logOperation(
|
|
478
|
+
'FHE.max',
|
|
479
|
+
string.concat('max(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
480
|
+
logCtHash(ctHash)
|
|
481
|
+
);
|
|
382
482
|
return;
|
|
383
483
|
}
|
|
384
|
-
if (
|
|
484
|
+
if (funcId == FunctionId.eq) {
|
|
385
485
|
_set(ctHash, _get(input1) == _get(input2));
|
|
386
486
|
|
|
387
|
-
logOperation('FHE.eq', string.concat(logCtHash(input1), ' == ', logCtHash(input2)), logCtHash(ctHash));
|
|
487
|
+
if (logOps) logOperation('FHE.eq', string.concat(logCtHash(input1), ' == ', logCtHash(input2)), logCtHash(ctHash));
|
|
388
488
|
return;
|
|
389
489
|
}
|
|
390
|
-
if (
|
|
490
|
+
if (funcId == FunctionId.ne) {
|
|
391
491
|
_set(ctHash, _get(input1) != _get(input2));
|
|
392
492
|
|
|
393
|
-
logOperation('FHE.ne', string.concat(logCtHash(input1), ' != ', logCtHash(input2)), logCtHash(ctHash));
|
|
493
|
+
if (logOps) logOperation('FHE.ne', string.concat(logCtHash(input1), ' != ', logCtHash(input2)), logCtHash(ctHash));
|
|
394
494
|
return;
|
|
395
495
|
}
|
|
396
|
-
if (
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
496
|
+
if (funcId == FunctionId.rol) {
|
|
497
|
+
// rotation within the type width, amount modulo the width (TFHE-rs semantics); _set masks the result
|
|
498
|
+
uint256 bits = getUtypeBits(ctHash);
|
|
499
|
+
uint256 shift = _get(input2) % bits;
|
|
500
|
+
uint256 value = _get(input1);
|
|
501
|
+
_set(ctHash, shift == 0 ? value : (value << shift) | (value >> (bits - shift)));
|
|
502
|
+
|
|
503
|
+
if (logOps)
|
|
504
|
+
logOperation(
|
|
505
|
+
'FHE.rol',
|
|
506
|
+
string.concat('rol(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
507
|
+
logCtHash(ctHash)
|
|
508
|
+
);
|
|
402
509
|
return;
|
|
403
510
|
}
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
511
|
+
if (funcId == FunctionId.ror) {
|
|
512
|
+
uint256 bits = getUtypeBits(ctHash);
|
|
513
|
+
uint256 shift = _get(input2) % bits;
|
|
514
|
+
uint256 value = _get(input1);
|
|
515
|
+
_set(ctHash, shift == 0 ? value : (value >> shift) | (value << (bits - shift)));
|
|
516
|
+
|
|
517
|
+
if (logOps)
|
|
518
|
+
logOperation(
|
|
519
|
+
'FHE.ror',
|
|
520
|
+
string.concat('ror(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
521
|
+
logCtHash(ctHash)
|
|
522
|
+
);
|
|
410
523
|
return;
|
|
411
524
|
}
|
|
412
|
-
revert InvalidTwoInputOperation(
|
|
525
|
+
revert InvalidTwoInputOperation(Utils.functionIdToString(funcId));
|
|
413
526
|
}
|
|
414
527
|
|
|
415
528
|
function MOCK_threeInputOperation(
|
|
416
529
|
uint256 ctHash,
|
|
417
|
-
|
|
530
|
+
FunctionId funcId,
|
|
418
531
|
uint256 input1,
|
|
419
532
|
uint256 input2,
|
|
420
533
|
uint256 input3
|
|
421
534
|
) internal {
|
|
422
|
-
if (
|
|
535
|
+
if (funcId == FunctionId.trivialEncrypt) {
|
|
423
536
|
_set(ctHash, input1);
|
|
424
537
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
538
|
+
if (logOps)
|
|
539
|
+
logOperation(
|
|
540
|
+
string.concat('FHE.asE', removeFirstLetter(getUtypeStringFromHash(ctHash))),
|
|
541
|
+
string.concat(removeFirstLetter(getUtypeStringFromHash(ctHash)), '(', Strings.toString(input1), ')'),
|
|
542
|
+
logCtHash(ctHash)
|
|
543
|
+
);
|
|
430
544
|
return;
|
|
431
545
|
}
|
|
432
|
-
if (
|
|
546
|
+
if (funcId == FunctionId.select) {
|
|
433
547
|
_set(ctHash, _get(input1) == 1 ? _get(input2) : _get(input3));
|
|
434
548
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
549
|
+
if (logOps)
|
|
550
|
+
logOperation(
|
|
551
|
+
'FHE.select',
|
|
552
|
+
string.concat(logCtHash(input1), ' ? ', logCtHash(input2), ' : ', logCtHash(input3)),
|
|
553
|
+
logCtHash(ctHash)
|
|
554
|
+
);
|
|
440
555
|
return;
|
|
441
556
|
}
|
|
442
|
-
revert InvalidThreeInputOperation(
|
|
557
|
+
revert InvalidThreeInputOperation(Utils.functionIdToString(funcId));
|
|
443
558
|
}
|
|
444
559
|
}
|