@cofhe/mock-contracts 0.8.0 → 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.
@@ -31,7 +31,6 @@ error OnlyAggregatorAllowed(address caller);
31
31
 
32
32
  // Operation-specific errors
33
33
  error RandomFunctionNotSupported();
34
- error NotImplemented();
35
34
 
36
35
  library TMCommon {
37
36
  uint256 private constant HASH_MASK_FOR_METADATA = type(uint256).max - type(uint16).max; // 2 bytes reserved for metadata
@@ -249,6 +248,9 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
249
248
  // Signer address for decrypt result verification (threshold network's signing key)
250
249
  address public decryptResultSigner;
251
250
 
251
+ // Counter mixed into generated random seeds, as in the real task manager
252
+ uint256 private randomCounter;
253
+
252
254
  // Storage contract for plaintext results of decrypt operations
253
255
  // PlaintextsStorage public plaintextsStorage;
254
256
 
@@ -481,6 +483,32 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
481
483
  validateFunctionInputTypes(funcId, functionName, encryptedHashes);
482
484
  }
483
485
 
486
+ /// @dev Same checks as the real task manager: the plaintext must fit the target type and the
487
+ /// security zone must be in range. Without them `FHE.asEuint8(256)` would be stored masked
488
+ /// to 0 here while the real task manager reverts.
489
+ function validateTrivialEncryptInputs(uint256[] memory extraInputs) internal view {
490
+ uint256 securityZone = extraInputs[2];
491
+ if (securityZone > uint256(int256(type(int32).max)) || !isValidSecurityZone(int32(int256(securityZone)))) {
492
+ revert InvalidSecurityZone(int32(int256(securityZone)), securityZoneMin, securityZoneMax);
493
+ }
494
+
495
+ uint256 value = extraInputs[0];
496
+ uint256 toType = extraInputs[1];
497
+ uint256 max;
498
+ if (toType == Utils.EUINT8_TFHE) max = type(uint8).max;
499
+ else if (toType == Utils.EUINT16_TFHE) max = type(uint16).max;
500
+ else if (toType == Utils.EUINT32_TFHE) max = type(uint32).max;
501
+ else if (toType == Utils.EUINT64_TFHE) max = type(uint64).max;
502
+ else if (toType == Utils.EUINT128_TFHE) max = type(uint128).max;
503
+ else if (toType == Utils.EADDRESS_TFHE) max = type(uint160).max;
504
+ else if (toType == Utils.EBOOL_TFHE) max = 1;
505
+ else return;
506
+
507
+ if (value > max) {
508
+ revert InvalidInputForFunction('trivialEncrypt', uint8(toType));
509
+ }
510
+ }
511
+
484
512
  function validateSelectInputs(uint256[] memory encryptedHashes) internal pure {
485
513
  if (encryptedHashes.length != 3) {
486
514
  revert InvalidInputsAmount('select', encryptedHashes.length, 3);
@@ -511,6 +539,9 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
511
539
  }
512
540
 
513
541
  validateInputs(encryptedHashes, funcId, operation);
542
+ if (funcId == FunctionId.trivialEncrypt) {
543
+ validateTrivialEncryptInputs(extraInputs);
544
+ }
514
545
  uint256[] memory inputs = TMCommon.combineInputs(encryptedHashes, extraInputs);
515
546
 
516
547
  int32 securityZone = getSecurityZone(funcId, encryptedHashes, extraInputs);
@@ -813,12 +844,46 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
813
844
  // Stub implementations for new ITaskManager interface methods (inc PR #48)
814
845
 
815
846
  function createRandomTask(uint8 returnType, uint256 seed, int32 securityZone) external returns (uint256) {
816
- // Mock implementation: just return a pseudo-random hash based on seed
817
- return uint256(keccak256(abi.encode(returnType, seed, securityZone, block.timestamp)));
847
+ if (!isValidSecurityZone(securityZone)) {
848
+ revert InvalidSecurityZone(securityZone, securityZoneMin, securityZoneMax);
849
+ }
850
+
851
+ if (seed == 0) {
852
+ seed = uint256(
853
+ keccak256(
854
+ abi.encodePacked(blockhash(block.number - 1), block.timestamp, randomCounter, block.chainid, securityZone)
855
+ )
856
+ );
857
+ unchecked {
858
+ randomCounter++;
859
+ }
860
+ }
861
+
862
+ // Same handle derivation as the real task manager: msg.sender is part of the preimage.
863
+ uint256[] memory inputs = new uint256[](2);
864
+ inputs[0] = seed;
865
+ inputs[1] = uint256(uint160(msg.sender));
866
+
867
+ uint256 ctHash = TMCommon.calcPlaceholderKey(returnType, securityZone, inputs, FunctionId.random);
868
+ acl.allowTransient(ctHash, msg.sender, address(this));
869
+ emit TaskCreated(
870
+ ctHash,
871
+ Utils.functionIdToString(FunctionId.random),
872
+ seed,
873
+ uint256(uint32(securityZone)),
874
+ inputs[1]
875
+ );
876
+
877
+ // NOTE: MOCK - the real task manager leaves the value to the coprocessor; store one here.
878
+ (MockGasMode mode, uint256 startGas) = _mockGasTrackStart();
879
+ _set(ctHash, uint256(keccak256(abi.encode(ctHash))));
880
+ _mockGasTrackEnd(mode, startGas);
881
+
882
+ return ctHash;
818
883
  }
819
884
 
820
885
  function isPubliclyAllowed(uint256 ctHash) external view returns (bool) {
821
- revert NotImplemented();
886
+ return acl.globalAllowed(ctHash);
822
887
  }
823
888
 
824
889
  function verifyDecryptResultBatch(
@@ -9,7 +9,7 @@ pragma solidity >=0.8.19 <0.9.0;
9
9
 
10
10
  import { MockACL } from './MockACL.sol';
11
11
  import { MockTaskManager } from './MockTaskManager.sol';
12
- import { MockPermissioned, ACP } from './Permissioned.sol';
12
+ import { ACP, PermissionedUpgradeable } from './Permissioned.sol';
13
13
 
14
14
  contract MockThresholdNetwork {
15
15
  MockTaskManager public mockTaskManager;
@@ -181,16 +181,16 @@ contract MockThresholdNetwork {
181
181
 
182
182
  function decodeLowLevelReversion(bytes memory data) public pure returns (string memory error) {
183
183
  bytes4 selector = bytes4(data);
184
- if (selector == MockPermissioned.PermissionInvalid_Expired.selector) {
184
+ if (selector == PermissionedUpgradeable.PermissionInvalid_Expired.selector) {
185
185
  return 'PermissionInvalid_Expired';
186
186
  }
187
- if (selector == MockPermissioned.PermissionInvalid_IssuerSignature.selector) {
187
+ if (selector == PermissionedUpgradeable.PermissionInvalid_IssuerSignature.selector) {
188
188
  return 'PermissionInvalid_IssuerSignature';
189
189
  }
190
- if (selector == MockPermissioned.PermissionInvalid_RecipientSignature.selector) {
190
+ if (selector == PermissionedUpgradeable.PermissionInvalid_RecipientSignature.selector) {
191
191
  return 'PermissionInvalid_RecipientSignature';
192
192
  }
193
- if (selector == MockPermissioned.PermissionInvalid_Disabled.selector) {
193
+ if (selector == PermissionedUpgradeable.PermissionInvalid_Disabled.selector) {
194
194
  return 'PermissionInvalid_Disabled';
195
195
  }
196
196
  // Handle other errors
@@ -3,7 +3,8 @@
3
3
  pragma solidity >=0.8.19 <0.9.0;
4
4
 
5
5
  import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
6
- import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
6
+ import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
7
+ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7
8
 
8
9
  /// @dev ACP scope discriminator (uint8 on the wire). Exactly one scope mode per ACP:
9
10
  /// SCOPE_GLOBAL — access to ALL of `issuer`s encrypted values; `contracts`/`handles` must be empty
@@ -15,160 +16,256 @@ uint8 constant SCOPE_CONTRACT = 1;
15
16
  uint8 constant SCOPE_HANDLES = 2;
16
17
 
17
18
  /**
18
- * @dev ACP (Access Control Permission) — the V3 permission struct.
19
+ * @dev ACP (Access Control Permission) — the permission body that must be passed to a
20
+ * contract to allow access to sensitive data.
19
21
  *
20
- * Signing flows are identical to V2 (self / two-step sharing) with the
21
- * `ACPIssuerSelf` / `ACPIssuerShared` / `ACPRecipient` EIP-712 types under
22
- * domain version "2".
22
+ * The minimum permission to access a user's own data requires the fields
23
+ * < issuer, expiration, scope, sealingKey, issuerSignature >
23
24
  *
24
- * Revocation: `revokerData` is an opaque uint256 interpreted by
25
- * `revokerContract` (creation timestamp in the default ACPTimestampRevoker).
26
- * `revokerData = 0` or `revokerContract = address(0)` disables the check
27
- * (permission not revocable).
25
+ * ---
26
+ *
27
+ * If not sharing the permission, `issuer` signs a signature using the fields:
28
+ * < issuer, expiration, recipient, revokerData, revokerContract, scope, contracts, handles, sealingKey >
29
+ * This signature can now be used by `issuer` to access their own encrypted data.
30
+ *
31
+ * ---
32
+ *
33
+ * Sharing a permission is a two step process: `issuer` completes step 1, and `recipient` completes step 2.
34
+ *
35
+ * 1:
36
+ * `issuer` creates a permission with `recipient` populated with the address of the user to give access to.
37
+ * `issuer` does not include a `sealingKey` in the permission, it will be populated by the `recipient`.
38
+ * `issuer` signs a signature including the fields: (note: `sealingKey` is absent in this signature)
39
+ * < issuer, expiration, recipient, revokerData, revokerContract, scope, contracts, handles >
40
+ * `issuer` packages the permission data and `issuerSignature` and shares it with `recipient`
41
+ * ** None of this data is sensitive, and can be shared as cleartext **
42
+ *
43
+ * 2:
44
+ * `recipient` adds their `sealingKey` to the data received from `issuer`
45
+ * `recipient` signs a signature including the fields:
46
+ * < sealingKey, issuerSignature >
47
+ * `recipient` can now use the completed permission to access `issuer`s encrypted data.
48
+ *
49
+ * ---
50
+ *
51
+ * Scope: `scope` selects exactly one access mode (see SCOPE_* above). Scopes narrow the
52
+ * issuer's existing ACL access, they never widen it. Scope semantics are enforced by the
53
+ * ACL (`isAllowedWithPermission`); this contract checks structure only.
54
+ *
55
+ * ---
56
+ *
57
+ * Revocation: `revokerData` and `revokerContract` are optional and can be used together to
58
+ * increase security and control by disabling a permission after it has been created.
59
+ * `revokerData` is an opaque uint256 interpreted by `revokerContract` (the creation
60
+ * timestamp in the default ACPTimestampRevoker). `revokerData = 0` or
61
+ * `revokerContract = address(0)` disables the check (permission not revocable).
28
62
  */
29
63
  struct ACP {
30
- address issuer;
31
- uint64 expiration;
32
- address recipient;
33
- uint256 revokerData;
34
- address revokerContract;
35
- uint8 scope;
36
- address[] contracts;
37
- bytes32[] handles;
38
- bytes32 sealingKey;
39
- bytes issuerSignature;
40
- bytes recipientSignature;
64
+ // (base) User that initially created the permission, target of data fetching
65
+ address issuer;
66
+ // (base) Expiration timestamp
67
+ uint64 expiration;
68
+ // (sharing) The user that this permission will be shared with
69
+ // ** optional, use `address(0)` to disable **
70
+ address recipient;
71
+ // (issuer defined revocation) Opaque data passed to `revokerContract` to check this permission's validity
72
+ // ** optional, use `0` to disable **
73
+ uint256 revokerData;
74
+ // (issuer defined revocation) The contract to query to determine permission validity
75
+ // ** optional, use `address(0)` to disable **
76
+ address revokerContract;
77
+ // (scope) Which access mode this permission grants — one of SCOPE_GLOBAL / SCOPE_CONTRACT / SCOPE_HANDLES
78
+ uint8 scope;
79
+ // (scope) Contracts whose readable values this permission grants access to (SCOPE_CONTRACT only)
80
+ address[] contracts;
81
+ // (scope) Ciphertext handles this permission grants access to (SCOPE_HANDLES only)
82
+ bytes32[] handles;
83
+ // (base) The publicKey of a sealingPair used to re-encrypt `issuer`s confidential data
84
+ // (non-sharing) Populated by `issuer`
85
+ // (sharing) Populated by `recipient`
86
+ bytes32 sealingKey;
87
+ // (base) `signTypedData` signature created by `issuer`.
88
+ // (base) Shared- and Self- permissions differ in signature format: (`sealingKey` absent in shared signature)
89
+ bytes issuerSignature;
90
+ // (sharing) `signTypedData` signature created by `recipient` with format:
91
+ // (sharing) < sealingKey, issuerSignature >
92
+ // ** required for shared permissions **
93
+ bytes recipientSignature;
41
94
  }
42
95
 
43
96
  /// @dev Minimum required interface to create a custom permission revoker.
44
- /// Revokers are optional and provide control to disable a permission after creation.
97
+ /// Revokers are optional, and provide extra security and control when sharing permissions.
45
98
  interface IPermissionCustomIdValidator {
46
- /// @dev Returning `true` disables the permission.
47
- function disabled(address issuer, uint256 id) external view returns (bool);
99
+ /// @dev Checks whether a permission has been revoked, returning `true` disables the permission.
100
+ function disabled(address issuer, uint256 id) external view returns (bool);
48
101
  }
49
102
 
50
- contract MockPermissioned is EIP712 {
51
- using ACPUtils for ACP;
52
-
53
- /// @dev Same verifying-contract identity as V2 ("ACL"), domain version bumped for V3 types.
54
- constructor() EIP712("ACL", "2") {}
55
-
56
- error PermissionInvalid_Expired();
57
- error PermissionInvalid_IssuerSignature();
58
- error PermissionInvalid_RecipientSignature();
59
- error PermissionInvalid_Disabled();
60
-
61
- /// @dev Validates an ACP's structure: expiration, signatures, revocation.
62
- /// Identical check order and semantics to V2 `withPermission`.
63
- ///
64
- /// NOTE: Functions protected by `withPermission` should return ONLY the sensitive data of `acp.issuer`.
65
- /// !! Returning data of `msg.sender` will leak sensitive values - `msg.sender` cannot be trusted in view functions !!
66
- modifier withPermission(ACP memory acp) {
67
- // Expiration
68
- if (acp.expiration < block.timestamp)
69
- revert PermissionInvalid_Expired();
70
-
71
- // Issuer signature
72
- if (
73
- !SignatureChecker.isValidSignatureNow(
74
- acp.issuer,
75
- _hashTypedDataV4(acp.issuerHash()),
76
- acp.issuerSignature
77
- )
78
- ) revert PermissionInvalid_IssuerSignature();
79
-
80
- // (if applicable) Recipient signature
81
- if (
82
- acp.recipient != address(0) &&
83
- !SignatureChecker.isValidSignatureNow(
84
- acp.recipient,
85
- _hashTypedDataV4(acp.recipientHash()),
86
- acp.recipientSignature
87
- )
88
- ) revert PermissionInvalid_RecipientSignature();
89
-
90
- // (if applicable) Externally disabled (revoked)
91
- if (
92
- acp.revokerData != 0 &&
93
- acp.revokerContract != address(0) &&
94
- IPermissionCustomIdValidator(acp.revokerContract).disabled(
95
- acp.issuer,
96
- acp.revokerData
97
- )
98
- ) revert PermissionInvalid_Disabled();
99
-
100
- _;
101
- }
102
-
103
- /// @dev Structure-validity probe (expiration / signatures / revocation).
104
- function checkPermissionValidity(
105
- ACP memory acp
106
- ) public view withPermission(acp) returns (bool) {
107
- return true;
108
- }
109
-
110
- function hashTypedDataV4(
111
- bytes32 structHash
112
- ) public view virtual returns (bytes32) {
113
- return _hashTypedDataV4(structHash);
114
- }
103
+ contract PermissionedUpgradeable is Initializable, EIP712Upgradeable {
104
+ using ACPUtils for ACP;
105
+
106
+ /// @dev Same verifying-contract identity as V2 ("ACL"), domain version bumped for the ACP types.
107
+ function __PermissionedUpgradeable_init() internal onlyInitializing {
108
+ __EIP712_init_unchained("ACL", "2");
109
+ }
110
+
111
+ function __PermissionedUpgradeable_init_unchained()
112
+ internal
113
+ onlyInitializing
114
+ {
115
+ __EIP712_init_unchained("ACL", "2");
116
+ }
117
+
118
+ /// @dev The EIP-712 domain is defined by code, not by storage.
119
+ ///
120
+ /// `EIP712Upgradeable` persists name/version at initialization time and only
121
+ /// then — an implementation-only upgrade would leave an already-initialized
122
+ /// proxy reporting the V2 domain ("ACL", "1") while hashing the V3 types,
123
+ /// and every signature would fail to verify. Overriding the accessors (which
124
+ /// OZ marks `virtual` for exactly this case) makes the upgrade a pure
125
+ /// implementation swap: no reinitializer, no migration transaction.
126
+ function _EIP712Name() internal view virtual override returns (string memory) {
127
+ return "ACL";
128
+ }
129
+
130
+ function _EIP712Version()
131
+ internal
132
+ view
133
+ virtual
134
+ override
135
+ returns (string memory)
136
+ {
137
+ return "2";
138
+ }
139
+
140
+ /// @dev Emitted when `acp.expiration` is in the past (< block.timestamp)
141
+ error PermissionInvalid_Expired();
142
+
143
+ /// @dev Emitted when `issuerSignature` is malformed or was not signed by `acp.issuer`
144
+ error PermissionInvalid_IssuerSignature();
145
+
146
+ /// @dev Emitted when `recipientSignature` is malformed or was not signed by `acp.recipient`
147
+ error PermissionInvalid_RecipientSignature();
148
+
149
+ /// @dev Emitted when `revokerContract` returned `true` indicating that this permission has been externally disabled
150
+ error PermissionInvalid_Disabled();
151
+
152
+ /// @dev Validates an `acp`s access of sensitive data.
153
+ /// `acp` may be invalid or unauthorized for the following reasons:
154
+ /// - Expired: `acp.expiration` is in the past (< block.timestamp)
155
+ /// - Issuer signature: `issuerSignature` is malformed or was not signed by `acp.issuer`
156
+ /// - Recipient signature: `recipientSignature` is malformed or was not signed by `acp.recipient`
157
+ /// - Disabled: `revokerContract` returned `true` indicating that this permission has been externally disabled
158
+ /// @param acp ACP struct containing data necessary to validate data access and seal for return.
159
+ ///
160
+ /// NOTE: Functions protected by `withPermission` should return ONLY the sensitive data of `acp.issuer`.
161
+ /// !! Returning data of `msg.sender` will leak sensitive values - `msg.sender` cannot be trusted in view functions !!
162
+ modifier withPermission(ACP memory acp) {
163
+ // Expiration
164
+ if (acp.expiration < block.timestamp)
165
+ revert PermissionInvalid_Expired();
166
+
167
+ // Issuer signature
168
+ if (
169
+ !SignatureChecker.isValidSignatureNow(
170
+ acp.issuer,
171
+ _hashTypedDataV4(acp.issuerHash()),
172
+ acp.issuerSignature
173
+ )
174
+ ) revert PermissionInvalid_IssuerSignature();
175
+
176
+ // (if applicable) Recipient signature
177
+ if (
178
+ acp.recipient != address(0) &&
179
+ !SignatureChecker.isValidSignatureNow(
180
+ acp.recipient,
181
+ _hashTypedDataV4(acp.recipientHash()),
182
+ acp.recipientSignature
183
+ )
184
+ ) revert PermissionInvalid_RecipientSignature();
185
+
186
+ // (if applicable) Externally disabled (revoked)
187
+ if (
188
+ acp.revokerData != 0 &&
189
+ acp.revokerContract != address(0) &&
190
+ IPermissionCustomIdValidator(acp.revokerContract).disabled(
191
+ acp.issuer,
192
+ acp.revokerData
193
+ )
194
+ ) revert PermissionInvalid_Disabled();
195
+
196
+ _;
197
+ }
198
+
199
+ /// @dev Structure-validity probe (expiration / signatures / revocation).
200
+ function checkPermissionValidity(
201
+ ACP memory acp
202
+ ) public view withPermission(acp) returns (bool) {
203
+ return true;
204
+ }
115
205
  }
116
206
 
117
- /// @dev Signature type hashes for ACP. Field order must match the struct and the
207
+ /// @dev Internal utility library to improve the readability of PermissionedUpgradeable.
208
+ /// Primarily focused on signature type hashes. Field order must match the struct and the
118
209
  /// SDK's SignatureTypes exactly — pinned by tests on both sides.
119
210
  library ACPUtils {
120
- function issuerHash(ACP memory acp) internal pure returns (bytes32) {
121
- if (acp.recipient == address(0)) return issuerSelfHash(acp);
122
- return issuerSharedHash(acp);
123
- }
124
-
125
- function issuerSelfHash(ACP memory acp) internal pure returns (bytes32) {
126
- return
127
- keccak256(
128
- abi.encode(
129
- keccak256(
130
- "ACPIssuerSelf(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles,bytes32 sealingKey)"
131
- ),
132
- acp.issuer,
133
- acp.expiration,
134
- acp.recipient,
135
- acp.revokerData,
136
- acp.revokerContract,
137
- acp.scope,
138
- keccak256(abi.encodePacked(acp.contracts)),
139
- keccak256(abi.encodePacked(acp.handles)),
140
- acp.sealingKey
141
- )
142
- );
143
- }
144
-
145
- function issuerSharedHash(ACP memory acp) internal pure returns (bytes32) {
146
- return
147
- keccak256(
148
- abi.encode(
149
- keccak256(
150
- "ACPIssuerShared(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles)"
151
- ),
152
- acp.issuer,
153
- acp.expiration,
154
- acp.recipient,
155
- acp.revokerData,
156
- acp.revokerContract,
157
- acp.scope,
158
- keccak256(abi.encodePacked(acp.contracts)),
159
- keccak256(abi.encodePacked(acp.handles))
160
- )
161
- );
162
- }
163
-
164
- function recipientHash(ACP memory acp) internal pure returns (bytes32) {
165
- return
166
- keccak256(
167
- abi.encode(
168
- keccak256("ACPRecipient(bytes32 sealingKey,bytes issuerSignature)"),
169
- acp.sealingKey,
170
- keccak256(acp.issuerSignature)
171
- )
172
- );
173
- }
211
+ function issuerHash(ACP memory acp) internal pure returns (bytes32) {
212
+ if (acp.recipient == address(0)) return issuerSelfHash(acp);
213
+ return issuerSharedHash(acp);
214
+ }
215
+
216
+ function issuerSelfHash(
217
+ ACP memory acp
218
+ ) internal pure returns (bytes32) {
219
+ return
220
+ keccak256(
221
+ abi.encode(
222
+ keccak256(
223
+ "ACPIssuerSelf(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles,bytes32 sealingKey)"
224
+ ),
225
+ acp.issuer,
226
+ acp.expiration,
227
+ acp.recipient,
228
+ acp.revokerData,
229
+ acp.revokerContract,
230
+ acp.scope,
231
+ keccak256(abi.encodePacked(acp.contracts)),
232
+ keccak256(abi.encodePacked(acp.handles)),
233
+ acp.sealingKey
234
+ )
235
+ );
236
+ }
237
+
238
+ function issuerSharedHash(
239
+ ACP memory acp
240
+ ) internal pure returns (bytes32) {
241
+ return
242
+ keccak256(
243
+ abi.encode(
244
+ keccak256(
245
+ "ACPIssuerShared(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles)"
246
+ ),
247
+ acp.issuer,
248
+ acp.expiration,
249
+ acp.recipient,
250
+ acp.revokerData,
251
+ acp.revokerContract,
252
+ acp.scope,
253
+ keccak256(abi.encodePacked(acp.contracts)),
254
+ keccak256(abi.encodePacked(acp.handles))
255
+ )
256
+ );
257
+ }
258
+
259
+ function recipientHash(
260
+ ACP memory acp
261
+ ) internal pure returns (bytes32) {
262
+ return
263
+ keccak256(
264
+ abi.encode(
265
+ keccak256("ACPRecipient(bytes32 sealingKey,bytes issuerSignature)"),
266
+ acp.sealingKey,
267
+ keccak256(acp.issuerSignature)
268
+ )
269
+ );
270
+ }
174
271
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "repo": "FhenixProtocol/cofhe-contracts",
3
+ "commit": "0afc699c29e64c16e602845d95b2e85d5ca159c4",
4
+ "sourceDir": "contracts/internal/host-chain/contracts",
5
+ "files": {
6
+ "ACPShareRegistry.sol": "27cfcadd82922ca56151ae4bde04fff8129aa1c26d4631a2e16a56d6a96a9971",
7
+ "ACPTimestampRevoker.sol": "be40add6302b68cff8c15fb5bcc54e7ef74db63df59cf350e8ccfbb06a7a74fc",
8
+ "Permissioned.sol": "34d8d2f4a41c9a5ffbd69e32e4e3d718a7d4fcde6289fbe132fa3c4a74de9c0d"
9
+ }
10
+ }