@cofhe/mock-contracts 0.7.1 → 0.8.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/MockACL.sol +33 -15
- package/contracts/MockCoFHE.sol +165 -74
- package/contracts/MockCoFHEAddressBook.sol +64 -0
- package/contracts/MockTaskManager.sol +74 -24
- package/contracts/MockZkVerifier.sol +2 -2
- package/dist/index.d.mts +291 -20
- package/dist/index.d.ts +291 -20
- package/dist/index.js +224 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +224 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/MockACL.ts +37 -13
- package/src/MockCoFHEAddressBook.ts +114 -0
- package/src/MockTaskManager.ts +73 -1
- package/src/index.ts +2 -0
- package/src/typechain-types/MockACL.ts +38 -6
- package/src/typechain-types/MockCoFHEAddressBook.ts +124 -0
- package/src/typechain-types/MockTaskManager.ts +66 -1
- package/src/typechain-types/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @cofhe/mock-contracts Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6f7a4c5: Resolve the Task Manager through the `CoFHEAddressBook` (`@fhenixprotocol/cofhe-contracts@1.0.0`). **Breaking:** `TASK_MANAGER_ADDRESS` is removed from `@cofhe/sdk`. Use `getTaskManagerAddress(publicClient)`, which reads `getTm(TASK_MANAGER_ID)` from the book at `COFHE_ADDRESS_BOOK_ADDRESS` (both exported) and caches the result per chain. If the chain has no book, or the id is unset, it throws `TASK_MANAGER_UNRESOLVED`. `verifyDecryptResult`, the ACL/ACP lookups and `useCofheEnabled` / `useCofheReadDecryptionResults` now resolve the Task Manager this way. `@cofhe/react` adds `useCofheTaskManagerAddress()`.
|
|
8
|
+
|
|
9
|
+
Mocks: a new `MockCoFHEAddressBook` is deployed at FHE.sol's `COFHE_ADDRESS_BOOK`, and `MockTaskManager` moves to `MOCKS_TASK_MANAGER_ADDRESS` (`0x…5000`) and is registered in the book. `MockACL` now stores its Task Manager (`setTaskManager` / `getTaskManagerAddress`) instead of reading a constant, so its `TASK_MANAGER_ADDRESS_()` getter is gone. All three plugins deploy and wire the book. Hardhat 2 exposes `hre.cofhe.mocks.getMockCoFHEAddressBook()`, Hardhat 3 exposes `conn.cofhe.mocks.MockCoFHEAddressBook`, and Foundry exposes `CofheTest.mockAddressBook`. Contracts must be built against `@fhenixprotocol/cofhe-contracts@1.0.0` or later (the hardhat plugin's peer range is now `>=1.0.0`). Each FHE op now makes one extra `getTm` call on the book, as it does on real networks, so expect slightly higher gas numbers.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- ccb7b68: Realistic gas reporting for mocks. Under Foundry, mock-only work is now excluded from gas metering by default (opt out with `mockTaskManager.setMockGasExcluded(false)`), so expect `forge snapshot` numbers to drop. Under Hardhat, mock transactions emit `MockGasConsumed` events (extra receipt logs), and the plugins add `getAdjustedGasUsed(receipt)` / `getAdjustedGasBreakdown(receipt)` plus an opt-in `cofhe.gasSummary` report.
|
|
14
|
+
|
|
3
15
|
## 0.7.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A mock smart contract library for testing CoFHE (Confidential Computing Framewor
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
12
|
- Mock implementations of core CoFHE contracts:
|
|
13
|
+
- MockCoFHEAddressBook (deployed at FHE.sol's `COFHE_ADDRESS_BOOK`, resolves the TaskManager)
|
|
13
14
|
- MockTaskManager
|
|
14
15
|
- MockThresholdNetwork
|
|
15
16
|
- MockZkVerifier
|
|
@@ -137,6 +138,15 @@ When interacting with CoFHE this request is routed to the Threshold Network, whi
|
|
|
137
138
|
|
|
138
139
|
When working with the mocks, the `cofheClient` instead queries the `MockThresholdNetwork` contract, which verifies the request `acp` and returns the decrypted result.
|
|
139
140
|
|
|
141
|
+
### Gas
|
|
142
|
+
|
|
143
|
+
Because the mocks replicate the off-chain FHE computation on-chain (plaintext math, mock storage writes, logging), transactions consume more gas than they would on a real CoFHE network. The mocks account for this in two ways:
|
|
144
|
+
|
|
145
|
+
- **Foundry**: when gas exclusion is enabled (`setMockGasExcluded(true)` — the foundry plugin's `deployMocks()` does this automatically), the mock-only work runs between `pauseGasMetering` / `resumeGasMetering` cheatcodes, so forge's reported gas approximates real-network cost. Requires cheatcode access (`vm.allowCheatcodes(taskManagerAddress)`) and forge ≥ 1.0; without either, execution silently stays metered.
|
|
146
|
+
- **Everywhere else** (Hardhat, anvil): `MockTaskManager` measures each block of mock-only work with `gasleft()` and emits a `MockGasConsumed(uint256)` event. Summing these events from a receipt and subtracting from `gasUsed` yields the adjusted cost — the hardhat plugins expose this as `getAdjustedGasUsed(receipt)` / `getAdjustedGasBreakdown(receipt)` and an opt-in `gasSummary` table.
|
|
147
|
+
|
|
148
|
+
`eth_estimateGas` is never adjusted: the mock work really executes, so transactions still need the raw gas limit.
|
|
149
|
+
|
|
140
150
|
### Using Foundry
|
|
141
151
|
|
|
142
152
|
Use [`@cofhe/foundry-plugin`](../foundry-plugin/README.md), which builds on these mocks. Inherit its
|
package/contracts/MockACL.sol
CHANGED
|
@@ -3,7 +3,6 @@ pragma solidity >=0.8.19 <0.9.0;
|
|
|
3
3
|
|
|
4
4
|
import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';
|
|
5
5
|
import { MockPermissioned, ACP, SCOPE_GLOBAL, SCOPE_CONTRACT, SCOPE_HANDLES } from './Permissioned.sol';
|
|
6
|
-
import { TASK_MANAGER_ADDRESS } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @title ACL
|
|
@@ -32,6 +31,9 @@ contract MockACL is MockPermissioned {
|
|
|
32
31
|
/// @param receiver Address the share would have been directed at.
|
|
33
32
|
error NotShared(uint256 handle, address receiver);
|
|
34
33
|
|
|
34
|
+
/// @notice Returned when the TaskManager address being set is zero.
|
|
35
|
+
error InvalidTaskManagerAddress();
|
|
36
|
+
|
|
35
37
|
/// @notice Returned when a share is pending but was written by a different party.
|
|
36
38
|
/// @param expected Sharer the receiver named.
|
|
37
39
|
/// @param actual Sharer recorded in the slot.
|
|
@@ -53,6 +55,9 @@ contract MockACL is MockPermissioned {
|
|
|
53
55
|
/// @notice Emitted when the share registry address is updated (zero = unset).
|
|
54
56
|
event ShareRegistryUpdated(address oldAddress, address newAddress);
|
|
55
57
|
|
|
58
|
+
/// @notice Emitted when the TaskManager address is updated.
|
|
59
|
+
event TaskManagerUpdated(address oldAddress, address newAddress);
|
|
60
|
+
|
|
56
61
|
/// @custom:storage-location erc7201:cofhe.storage.ACL
|
|
57
62
|
struct ACLStorage {
|
|
58
63
|
mapping(uint256 handle => bool isGlobal) globalHandles;
|
|
@@ -62,6 +67,7 @@ contract MockACL is MockPermissioned {
|
|
|
62
67
|
/// @dev ACP infrastructure addresses served to SDKs (appended fields — do not reorder)
|
|
63
68
|
address defaultRevokerContract;
|
|
64
69
|
address shareRegistry;
|
|
70
|
+
address taskManager;
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
/// @notice Name of the contract.
|
|
@@ -76,9 +82,6 @@ contract MockACL is MockPermissioned {
|
|
|
76
82
|
/// @notice Patch version of the contract.
|
|
77
83
|
uint256 private constant PATCH_VERSION = 0;
|
|
78
84
|
|
|
79
|
-
/// @notice TaskManagerAddress address.
|
|
80
|
-
address public constant TASK_MANAGER_ADDRESS_ = TASK_MANAGER_ADDRESS;
|
|
81
|
-
|
|
82
85
|
/// @dev keccak256(abi.encode(uint256(keccak256("cofhe.storage.ACL")) - 1)) & ~bytes32(uint256(0xff))
|
|
83
86
|
bytes32 private constant ACL_SLOT =
|
|
84
87
|
keccak256(abi.encode(uint256(keccak256('cofhe.storage.ACL')) - 1)) & ~bytes32(uint256(0xff));
|
|
@@ -103,7 +106,7 @@ contract MockACL is MockPermissioned {
|
|
|
103
106
|
* @param requester Address of the account giving the permissions.
|
|
104
107
|
*/
|
|
105
108
|
function allow(uint256 handle, address account, address requester) public virtual {
|
|
106
|
-
if (msg.sender !=
|
|
109
|
+
if (msg.sender != _taskManager()) {
|
|
107
110
|
revert DirectAllowForbidden(msg.sender);
|
|
108
111
|
}
|
|
109
112
|
|
|
@@ -122,7 +125,7 @@ contract MockACL is MockPermissioned {
|
|
|
122
125
|
* @param requester Address of the account giving the permissions.
|
|
123
126
|
*/
|
|
124
127
|
function allowGlobal(uint256 handle, address requester) public virtual {
|
|
125
|
-
if (msg.sender !=
|
|
128
|
+
if (msg.sender != _taskManager()) {
|
|
126
129
|
revert DirectAllowForbidden(msg.sender);
|
|
127
130
|
}
|
|
128
131
|
|
|
@@ -140,7 +143,7 @@ contract MockACL is MockPermissioned {
|
|
|
140
143
|
* @param handlesList List of handles.
|
|
141
144
|
*/
|
|
142
145
|
function allowForDecryption(uint256[] memory handlesList, address requester) public virtual {
|
|
143
|
-
if (msg.sender !=
|
|
146
|
+
if (msg.sender != _taskManager()) {
|
|
144
147
|
revert DirectAllowForbidden(msg.sender);
|
|
145
148
|
}
|
|
146
149
|
|
|
@@ -167,11 +170,11 @@ contract MockACL is MockPermissioned {
|
|
|
167
170
|
* @param requester Address of the requester.
|
|
168
171
|
*/
|
|
169
172
|
function allowTransient(uint256 handle, address account, address requester) public virtual {
|
|
170
|
-
if (msg.sender !=
|
|
173
|
+
if (msg.sender != _taskManager()) {
|
|
171
174
|
revert DirectAllowForbidden(msg.sender);
|
|
172
175
|
}
|
|
173
176
|
|
|
174
|
-
if (!isAllowed(handle, requester) && requester !=
|
|
177
|
+
if (!isAllowed(handle, requester) && requester != _taskManager()) {
|
|
175
178
|
revert SenderNotAllowed(requester);
|
|
176
179
|
}
|
|
177
180
|
|
|
@@ -217,14 +220,14 @@ contract MockACL is MockPermissioned {
|
|
|
217
220
|
* @notice Grants `receiver` transient access to `handle` and records `sharer` as the
|
|
218
221
|
* party that handed it over, for the duration of this transaction.
|
|
219
222
|
* @dev The caller must be the Task Manager contract.
|
|
220
|
-
* @dev Stricter than allowTransient: there is no
|
|
223
|
+
* @dev Stricter than allowTransient: there is no TaskManager bypass, since
|
|
221
224
|
* nothing shares on the Task Manager's own behalf.
|
|
222
225
|
* @param handle Handle.
|
|
223
226
|
* @param sharer Address handing the handle over.
|
|
224
227
|
* @param receiver Address the handle is being handed to.
|
|
225
228
|
*/
|
|
226
229
|
function shareCtHash(uint256 handle, address sharer, address receiver) public virtual {
|
|
227
|
-
if (msg.sender !=
|
|
230
|
+
if (msg.sender != _taskManager()) {
|
|
228
231
|
revert DirectAllowForbidden(msg.sender);
|
|
229
232
|
}
|
|
230
233
|
|
|
@@ -247,7 +250,7 @@ contract MockACL is MockPermissioned {
|
|
|
247
250
|
* @param receiver Address consuming the share.
|
|
248
251
|
*/
|
|
249
252
|
function receiveCtHash(uint256 handle, address expectedSharer, address receiver) public virtual {
|
|
250
|
-
if (msg.sender !=
|
|
253
|
+
if (msg.sender != _taskManager()) {
|
|
251
254
|
revert DirectAllowForbidden(msg.sender);
|
|
252
255
|
}
|
|
253
256
|
|
|
@@ -270,7 +273,7 @@ contract MockACL is MockPermissioned {
|
|
|
270
273
|
* @param delegateeContract Delegatee contract.
|
|
271
274
|
*/
|
|
272
275
|
function delegateAccount(address delegatee, address delegateeContract) public virtual {
|
|
273
|
-
if (msg.sender !=
|
|
276
|
+
if (msg.sender != _taskManager()) {
|
|
274
277
|
revert DirectAllowForbidden(msg.sender);
|
|
275
278
|
}
|
|
276
279
|
if (delegateeContract == msg.sender) {
|
|
@@ -328,7 +331,7 @@ contract MockACL is MockPermissioned {
|
|
|
328
331
|
* @return taskManagerAddress Address of the TaskManager.
|
|
329
332
|
*/
|
|
330
333
|
function getTaskManagerAddress() public view virtual returns (address) {
|
|
331
|
-
return
|
|
334
|
+
return _taskManager();
|
|
332
335
|
}
|
|
333
336
|
|
|
334
337
|
/**
|
|
@@ -378,7 +381,7 @@ contract MockACL is MockPermissioned {
|
|
|
378
381
|
* Account Abstraction when bundling several UserOps calling the TaskManagerCoprocessor.
|
|
379
382
|
*/
|
|
380
383
|
function cleanTransientStorage() external virtual {
|
|
381
|
-
if (msg.sender !=
|
|
384
|
+
if (msg.sender != _taskManager()) {
|
|
382
385
|
revert DirectAllowForbidden(msg.sender);
|
|
383
386
|
}
|
|
384
387
|
|
|
@@ -458,6 +461,21 @@ contract MockACL is MockPermissioned {
|
|
|
458
461
|
$.shareRegistry = newAddress;
|
|
459
462
|
}
|
|
460
463
|
|
|
464
|
+
/// @notice Sets the TaskManager allowed to drive this ACL (unrestricted in the mock;
|
|
465
|
+
/// the production setter is onlyRole(DEFAULT_ADMIN_ROLE)).
|
|
466
|
+
function setTaskManager(address newAddress) external {
|
|
467
|
+
if (newAddress == address(0)) {
|
|
468
|
+
revert InvalidTaskManagerAddress();
|
|
469
|
+
}
|
|
470
|
+
ACLStorage storage $ = _getACLStorage();
|
|
471
|
+
emit TaskManagerUpdated($.taskManager, newAddress);
|
|
472
|
+
$.taskManager = newAddress;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function _taskManager() private view returns (address) {
|
|
476
|
+
return _getACLStorage().taskManager;
|
|
477
|
+
}
|
|
478
|
+
|
|
461
479
|
/// @notice V3 (ACP) access check — the scope table.
|
|
462
480
|
///
|
|
463
481
|
/// | 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,87 @@ 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 (
|
|
331
|
+
if (funcId == FunctionId.not) {
|
|
245
332
|
bool inputIsTruthy = _get(input) == 1;
|
|
246
333
|
_set(ctHash, !inputIsTruthy);
|
|
247
|
-
logOperation('FHE.not', logCtHash(input), logCtHash(ctHash));
|
|
334
|
+
if (logOps) logOperation('FHE.not', logCtHash(input), logCtHash(ctHash));
|
|
248
335
|
return;
|
|
249
336
|
}
|
|
250
|
-
if (
|
|
337
|
+
if (funcId == FunctionId.square) {
|
|
251
338
|
unchecked {
|
|
252
339
|
_set(ctHash, _get(input) * _get(input));
|
|
253
340
|
}
|
|
254
|
-
logOperation('FHE.square', string.concat(logCtHash(input), ' * ', logCtHash(input)), logCtHash(ctHash));
|
|
341
|
+
if (logOps) logOperation('FHE.square', string.concat(logCtHash(input), ' * ', logCtHash(input)), logCtHash(ctHash));
|
|
255
342
|
return;
|
|
256
343
|
}
|
|
257
|
-
revert InvalidUnaryOperation(
|
|
344
|
+
revert InvalidUnaryOperation(Utils.functionIdToString(funcId));
|
|
258
345
|
}
|
|
259
346
|
|
|
260
|
-
function MOCK_twoInputOperation(uint256 ctHash,
|
|
261
|
-
if (
|
|
347
|
+
function MOCK_twoInputOperation(uint256 ctHash, FunctionId funcId, uint256 input1, uint256 input2) internal {
|
|
348
|
+
if (funcId == FunctionId.sub) {
|
|
262
349
|
unchecked {
|
|
263
350
|
_set(ctHash, _get(input1) - _get(input2));
|
|
264
351
|
}
|
|
265
|
-
logOperation('FHE.sub', string.concat(logCtHash(input1), ' - ', logCtHash(input2)), logCtHash(ctHash));
|
|
352
|
+
if (logOps) logOperation('FHE.sub', string.concat(logCtHash(input1), ' - ', logCtHash(input2)), logCtHash(ctHash));
|
|
266
353
|
return;
|
|
267
354
|
}
|
|
268
|
-
if (
|
|
355
|
+
if (funcId == FunctionId.add) {
|
|
269
356
|
unchecked {
|
|
270
357
|
_set(ctHash, _get(input1) + _get(input2));
|
|
271
358
|
}
|
|
272
|
-
logOperation('FHE.add', string.concat(logCtHash(input1), ' + ', logCtHash(input2)), logCtHash(ctHash));
|
|
359
|
+
if (logOps) logOperation('FHE.add', string.concat(logCtHash(input1), ' + ', logCtHash(input2)), logCtHash(ctHash));
|
|
273
360
|
return;
|
|
274
361
|
}
|
|
275
|
-
if (
|
|
362
|
+
if (funcId == FunctionId.xor) {
|
|
276
363
|
unchecked {
|
|
277
364
|
_set(ctHash, _get(input1) ^ _get(input2));
|
|
278
365
|
}
|
|
279
|
-
logOperation('FHE.xor', string.concat(logCtHash(input1), ' ^ ', logCtHash(input2)), logCtHash(ctHash));
|
|
366
|
+
if (logOps) logOperation('FHE.xor', string.concat(logCtHash(input1), ' ^ ', logCtHash(input2)), logCtHash(ctHash));
|
|
280
367
|
return;
|
|
281
368
|
}
|
|
282
|
-
if (
|
|
369
|
+
if (funcId == FunctionId.and) {
|
|
283
370
|
unchecked {
|
|
284
371
|
_set(ctHash, _get(input1) & _get(input2));
|
|
285
372
|
}
|
|
286
|
-
logOperation('FHE.and', string.concat(logCtHash(input1), ' & ', logCtHash(input2)), logCtHash(ctHash));
|
|
373
|
+
if (logOps) logOperation('FHE.and', string.concat(logCtHash(input1), ' & ', logCtHash(input2)), logCtHash(ctHash));
|
|
287
374
|
return;
|
|
288
375
|
}
|
|
289
|
-
if (
|
|
376
|
+
if (funcId == FunctionId.or) {
|
|
290
377
|
unchecked {
|
|
291
378
|
_set(ctHash, _get(input1) | _get(input2));
|
|
292
379
|
}
|
|
293
|
-
logOperation('FHE.or', string.concat(logCtHash(input1), ' | ', logCtHash(input2)), logCtHash(ctHash));
|
|
380
|
+
if (logOps) logOperation('FHE.or', string.concat(logCtHash(input1), ' | ', logCtHash(input2)), logCtHash(ctHash));
|
|
294
381
|
return;
|
|
295
382
|
}
|
|
296
|
-
if (
|
|
383
|
+
if (funcId == FunctionId.div) {
|
|
297
384
|
uint256 cleartext2 = _get(input2);
|
|
298
385
|
if (cleartext2 == 0) {
|
|
299
386
|
_set(ctHash, type(uint256).max);
|
|
@@ -302,143 +389,147 @@ abstract contract MockCoFHE {
|
|
|
302
389
|
_set(ctHash, _get(input1) / cleartext2);
|
|
303
390
|
}
|
|
304
391
|
}
|
|
305
|
-
logOperation('FHE.div', string.concat(logCtHash(input1), ' / ', logCtHash(input2)), logCtHash(ctHash));
|
|
392
|
+
if (logOps) logOperation('FHE.div', string.concat(logCtHash(input1), ' / ', logCtHash(input2)), logCtHash(ctHash));
|
|
306
393
|
return;
|
|
307
394
|
}
|
|
308
|
-
if (
|
|
395
|
+
if (funcId == FunctionId.rem) {
|
|
309
396
|
unchecked {
|
|
310
397
|
_set(ctHash, _get(input1) % _get(input2));
|
|
311
398
|
}
|
|
312
|
-
logOperation('FHE.rem', string.concat(logCtHash(input1), ' % ', logCtHash(input2)), logCtHash(ctHash));
|
|
399
|
+
if (logOps) logOperation('FHE.rem', string.concat(logCtHash(input1), ' % ', logCtHash(input2)), logCtHash(ctHash));
|
|
313
400
|
return;
|
|
314
401
|
}
|
|
315
|
-
if (
|
|
402
|
+
if (funcId == FunctionId.mul) {
|
|
316
403
|
unchecked {
|
|
317
404
|
_set(ctHash, _get(input1) * _get(input2));
|
|
318
405
|
}
|
|
319
|
-
logOperation('FHE.mul', string.concat(logCtHash(input1), ' * ', logCtHash(input2)), logCtHash(ctHash));
|
|
406
|
+
if (logOps) logOperation('FHE.mul', string.concat(logCtHash(input1), ' * ', logCtHash(input2)), logCtHash(ctHash));
|
|
320
407
|
return;
|
|
321
408
|
}
|
|
322
|
-
if (
|
|
409
|
+
if (funcId == FunctionId.shl) {
|
|
323
410
|
unchecked {
|
|
324
411
|
_set(ctHash, _get(input1) << _get(input2));
|
|
325
412
|
}
|
|
326
|
-
logOperation('FHE.shl', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
413
|
+
if (logOps) logOperation('FHE.shl', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
327
414
|
return;
|
|
328
415
|
}
|
|
329
|
-
if (
|
|
416
|
+
if (funcId == FunctionId.shr) {
|
|
330
417
|
unchecked {
|
|
331
418
|
_set(ctHash, _get(input1) >> _get(input2));
|
|
332
419
|
}
|
|
333
|
-
logOperation('FHE.shr', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
420
|
+
if (logOps) logOperation('FHE.shr', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
334
421
|
return;
|
|
335
422
|
}
|
|
336
|
-
if (
|
|
423
|
+
if (funcId == FunctionId.gte) {
|
|
337
424
|
_set(ctHash, _get(input1) >= _get(input2));
|
|
338
|
-
logOperation('FHE.gte', string.concat(logCtHash(input1), ' >= ', logCtHash(input2)), logCtHash(ctHash));
|
|
425
|
+
if (logOps) logOperation('FHE.gte', string.concat(logCtHash(input1), ' >= ', logCtHash(input2)), logCtHash(ctHash));
|
|
339
426
|
return;
|
|
340
427
|
}
|
|
341
|
-
if (
|
|
428
|
+
if (funcId == FunctionId.lte) {
|
|
342
429
|
_set(ctHash, _get(input1) <= _get(input2));
|
|
343
|
-
logOperation('FHE.lte', string.concat(logCtHash(input1), ' <= ', logCtHash(input2)), logCtHash(ctHash));
|
|
430
|
+
if (logOps) logOperation('FHE.lte', string.concat(logCtHash(input1), ' <= ', logCtHash(input2)), logCtHash(ctHash));
|
|
344
431
|
return;
|
|
345
432
|
}
|
|
346
|
-
if (
|
|
433
|
+
if (funcId == FunctionId.lt) {
|
|
347
434
|
_set(ctHash, _get(input1) < _get(input2));
|
|
348
|
-
logOperation('FHE.lt', string.concat(logCtHash(input1), ' < ', logCtHash(input2)), logCtHash(ctHash));
|
|
435
|
+
if (logOps) logOperation('FHE.lt', string.concat(logCtHash(input1), ' < ', logCtHash(input2)), logCtHash(ctHash));
|
|
349
436
|
return;
|
|
350
437
|
}
|
|
351
|
-
if (
|
|
438
|
+
if (funcId == FunctionId.gt) {
|
|
352
439
|
_set(ctHash, _get(input1) > _get(input2));
|
|
353
|
-
logOperation('FHE.gt', string.concat(logCtHash(input1), ' > ', logCtHash(input2)), logCtHash(ctHash));
|
|
440
|
+
if (logOps) logOperation('FHE.gt', string.concat(logCtHash(input1), ' > ', logCtHash(input2)), logCtHash(ctHash));
|
|
354
441
|
return;
|
|
355
442
|
}
|
|
356
|
-
if (
|
|
443
|
+
if (funcId == FunctionId.min) {
|
|
357
444
|
uint256 min;
|
|
358
445
|
unchecked {
|
|
359
446
|
min = _get(input1) < _get(input2) ? _get(input1) : _get(input2);
|
|
360
447
|
}
|
|
361
448
|
_set(ctHash, min);
|
|
362
449
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
450
|
+
if (logOps)
|
|
451
|
+
logOperation(
|
|
452
|
+
'FHE.min',
|
|
453
|
+
string.concat('min(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
454
|
+
logCtHash(ctHash)
|
|
455
|
+
);
|
|
368
456
|
return;
|
|
369
457
|
}
|
|
370
|
-
if (
|
|
458
|
+
if (funcId == FunctionId.max) {
|
|
371
459
|
uint256 max;
|
|
372
460
|
unchecked {
|
|
373
461
|
max = _get(input1) > _get(input2) ? _get(input1) : _get(input2);
|
|
374
462
|
}
|
|
375
463
|
_set(ctHash, max);
|
|
376
464
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
465
|
+
if (logOps)
|
|
466
|
+
logOperation(
|
|
467
|
+
'FHE.max',
|
|
468
|
+
string.concat('max(', logCtHash(input1), ', ', logCtHash(input2), ')'),
|
|
469
|
+
logCtHash(ctHash)
|
|
470
|
+
);
|
|
382
471
|
return;
|
|
383
472
|
}
|
|
384
|
-
if (
|
|
473
|
+
if (funcId == FunctionId.eq) {
|
|
385
474
|
_set(ctHash, _get(input1) == _get(input2));
|
|
386
475
|
|
|
387
|
-
logOperation('FHE.eq', string.concat(logCtHash(input1), ' == ', logCtHash(input2)), logCtHash(ctHash));
|
|
476
|
+
if (logOps) logOperation('FHE.eq', string.concat(logCtHash(input1), ' == ', logCtHash(input2)), logCtHash(ctHash));
|
|
388
477
|
return;
|
|
389
478
|
}
|
|
390
|
-
if (
|
|
479
|
+
if (funcId == FunctionId.ne) {
|
|
391
480
|
_set(ctHash, _get(input1) != _get(input2));
|
|
392
481
|
|
|
393
|
-
logOperation('FHE.ne', string.concat(logCtHash(input1), ' != ', logCtHash(input2)), logCtHash(ctHash));
|
|
482
|
+
if (logOps) logOperation('FHE.ne', string.concat(logCtHash(input1), ' != ', logCtHash(input2)), logCtHash(ctHash));
|
|
394
483
|
return;
|
|
395
484
|
}
|
|
396
|
-
if (
|
|
485
|
+
if (funcId == FunctionId.rol) {
|
|
397
486
|
unchecked {
|
|
398
487
|
_set(ctHash, _get(input1) << _get(input2));
|
|
399
488
|
}
|
|
400
489
|
|
|
401
|
-
logOperation('FHE.rol', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
490
|
+
if (logOps) logOperation('FHE.rol', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
|
|
402
491
|
return;
|
|
403
492
|
}
|
|
404
|
-
if (
|
|
493
|
+
if (funcId == FunctionId.ror) {
|
|
405
494
|
unchecked {
|
|
406
495
|
_set(ctHash, _get(input1) >> _get(input2));
|
|
407
496
|
}
|
|
408
497
|
|
|
409
|
-
logOperation('FHE.ror', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
498
|
+
if (logOps) logOperation('FHE.ror', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
|
|
410
499
|
return;
|
|
411
500
|
}
|
|
412
|
-
revert InvalidTwoInputOperation(
|
|
501
|
+
revert InvalidTwoInputOperation(Utils.functionIdToString(funcId));
|
|
413
502
|
}
|
|
414
503
|
|
|
415
504
|
function MOCK_threeInputOperation(
|
|
416
505
|
uint256 ctHash,
|
|
417
|
-
|
|
506
|
+
FunctionId funcId,
|
|
418
507
|
uint256 input1,
|
|
419
508
|
uint256 input2,
|
|
420
509
|
uint256 input3
|
|
421
510
|
) internal {
|
|
422
|
-
if (
|
|
511
|
+
if (funcId == FunctionId.trivialEncrypt) {
|
|
423
512
|
_set(ctHash, input1);
|
|
424
513
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
514
|
+
if (logOps)
|
|
515
|
+
logOperation(
|
|
516
|
+
string.concat('FHE.asE', removeFirstLetter(getUtypeStringFromHash(ctHash))),
|
|
517
|
+
string.concat(removeFirstLetter(getUtypeStringFromHash(ctHash)), '(', Strings.toString(input1), ')'),
|
|
518
|
+
logCtHash(ctHash)
|
|
519
|
+
);
|
|
430
520
|
return;
|
|
431
521
|
}
|
|
432
|
-
if (
|
|
522
|
+
if (funcId == FunctionId.select) {
|
|
433
523
|
_set(ctHash, _get(input1) == 1 ? _get(input2) : _get(input3));
|
|
434
524
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
525
|
+
if (logOps)
|
|
526
|
+
logOperation(
|
|
527
|
+
'FHE.select',
|
|
528
|
+
string.concat(logCtHash(input1), ' ? ', logCtHash(input2), ' : ', logCtHash(input3)),
|
|
529
|
+
logCtHash(ctHash)
|
|
530
|
+
);
|
|
440
531
|
return;
|
|
441
532
|
}
|
|
442
|
-
revert InvalidThreeInputOperation(
|
|
533
|
+
revert InvalidThreeInputOperation(Utils.functionIdToString(funcId));
|
|
443
534
|
}
|
|
444
535
|
}
|