@cofhe/mock-contracts 0.6.0 → 0.7.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.
@@ -5,142 +5,108 @@ pragma solidity >=0.8.19 <0.9.0;
5
5
  import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
6
6
  import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
7
7
 
8
+ /// @dev ACP scope discriminator (uint8 on the wire). Exactly one scope mode per ACP:
9
+ /// SCOPE_GLOBAL — access to ALL of `issuer`s encrypted values; `contracts`/`handles` must be empty
10
+ /// SCOPE_CONTRACT — access to values readable by any of `contracts`; `handles` must be empty
11
+ /// SCOPE_HANDLES — access to the listed ciphertext `handles` only; `contracts` must be empty
12
+ /// Array/scope consistency is validated client-side at creation (no contract-side enforcement).
13
+ uint8 constant SCOPE_GLOBAL = 0;
14
+ uint8 constant SCOPE_CONTRACT = 1;
15
+ uint8 constant SCOPE_HANDLES = 2;
16
+
8
17
  /**
9
- * @dev Permission body that must be passed to a contract to allow access to sensitive data.
10
- *
11
- * The minimum permission to access a user's own data requires the fields
12
- * < issuer, expiration, sealingKey, issuerSignature >
13
- *
14
- * ---
15
- *
16
- * If not sharing the permission, `issuer` signs a signature using the fields:
17
- * < issuer, expiration, sealingKey, issuerSignature >
18
- * This signature can now be used by `issuer` to access their own encrypted data.
19
- *
20
- * ---
21
- *
22
- * Sharing a permission is a two step process: `issuer` completes step 1, and `recipient` completes step 2.
23
- *
24
- * 1:
25
- * `issuer` creates a permission with `recipient` populated with the address of the user to give access to.
26
- * `issuer` does not include a `sealingKey` in the permission, it will be populated by the `recipient`.
27
- * `issuer` signs a signature including the fields: (note: `sealingKey` is absent in this signature)
28
- * < issuer, expiration, sealingKey, issuerSignature >
29
- * `issuer` packages the permission data and `issuerSignature` and shares it with `recipient`
30
- * ** None of this data is sensitive, and can be shared as cleartext **
31
- *
32
- * 2:
33
- * `recipient` adds their `sealingKey` to the data received from `issuer`
34
- * `recipient` signs a signature including the fields:
35
- * < sealingKey, issuerSignature >
36
- * `recipient` can now use the completed Permission to access `issuer`s encrypted data.
18
+ * @dev ACP (Access Control Permission) — the V3 permission struct.
37
19
  *
38
- * ---
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".
39
23
  *
40
- * `validatorId` and `validatorContract` are optional and can be used together to
41
- * increase security and control by disabling a permission after it has been created.
42
- * Useful when sharing permits to provide external access to sensitive data (eg auditors).
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).
43
28
  */
44
- struct Permission {
45
- // (base) User that initially created the permission, target of data fetching
29
+ struct ACP {
46
30
  address issuer;
47
- // (base) Expiration timestamp
48
31
  uint64 expiration;
49
- // (sharing) The user that this permission will be shared with
50
- // ** optional, use `address(0)` to disable **
51
32
  address recipient;
52
- // (issuer defined validation) An id used to query a contract to check this permissions validity
53
- // ** optional, use `0` to disable **
54
- uint256 validatorId;
55
- // (issuer defined validation) The contract to query to determine permission validity
56
- // ** optional, user `address(0)` to disable **
57
- address validatorContract;
58
- // (base) The publicKey of a sealingPair used to re-encrypt `issuer`s confidential data
59
- // (non-sharing) Populated by `issuer`
60
- // (sharing) Populated by `recipient`
33
+ uint256 revokerData;
34
+ address revokerContract;
35
+ uint8 scope;
36
+ address[] contracts;
37
+ bytes32[] handles;
61
38
  bytes32 sealingKey;
62
- // (base) `signTypedData` signature created by `issuer`.
63
- // (base) Shared- and Self- permissions differ in signature format: (`sealingKey` absent in shared signature)
64
- // (non-sharing) < issuer, expiration, recipient, validatorId, validatorContract, sealingKey >
65
- // (sharing) < issuer, expiration, recipient, validatorId, validatorContract >
66
39
  bytes issuerSignature;
67
- // (sharing) `signTypedData` signature created by `recipient` with format:
68
- // (sharing) < sealingKey, issuerSignature>
69
- // ** required for shared permits **
70
40
  bytes recipientSignature;
71
41
  }
72
42
 
73
- /// @dev Minimum required interface to create a custom permission validator.
74
- /// Permission validators are optional, and provide extra security and control when sharing permits.
43
+ /// @dev Minimum required interface to create a custom permission revoker.
44
+ /// Revokers are optional and provide control to disable a permission after creation.
75
45
  interface IPermissionCustomIdValidator {
76
- /// @dev Checks whether a permission is valid, returning `false` disables the permission.
46
+ /// @dev Returning `true` disables the permission.
77
47
  function disabled(address issuer, uint256 id) external view returns (bool);
78
48
  }
79
49
 
80
50
  contract MockPermissioned is EIP712 {
81
- using PermissionUtils for Permission;
51
+ using ACPUtils for ACP;
82
52
 
83
- constructor() EIP712("ACL", "1") {}
53
+ /// @dev Same verifying-contract identity as V2 ("ACL"), domain version bumped for V3 types.
54
+ constructor() EIP712("ACL", "2") {}
84
55
 
85
- /// @dev Emitted when `permission.expiration` is in the past (< block.timestamp)
86
56
  error PermissionInvalid_Expired();
87
-
88
- /// @dev Emitted when `issuerSignature` is malformed or was not signed by `permission.issuer`
89
57
  error PermissionInvalid_IssuerSignature();
90
-
91
- /// @dev Emitted when `recipientSignature` is malformed or was not signed by `permission.recipient`
92
58
  error PermissionInvalid_RecipientSignature();
93
-
94
- /// @dev Emitted when `validatorContract` returned `false` indicating that this permission has been externally disabled
95
59
  error PermissionInvalid_Disabled();
96
60
 
97
- /// @dev Validate's a `permissions` access of sensitive data.
98
- /// `permission` may be invalid or unauthorized for the following reasons:
99
- /// - Expired: `permission.expiration` is in the past (< block.timestamp)
100
- /// - Issuer signature: `issuerSignature` is malformed or was not signed by `permission.issuer`
101
- /// - Recipient signature: `recipientSignature` is malformed or was not signed by `permission.recipient`
102
- /// - Disabled: `validatorContract` returned `false` indicating that this permission has been externally disabled
103
- /// @param permission Permission struct containing data necessary to validate data access and seal for return.
61
+ /// @dev Validates an ACP's structure: expiration, signatures, revocation.
62
+ /// Identical check order and semantics to V2 `withPermission`.
104
63
  ///
105
- /// NOTE: Functions protected by `withPermission` should return ONLY the sensitive data of `permission.issuer`.
64
+ /// NOTE: Functions protected by `withPermission` should return ONLY the sensitive data of `acp.issuer`.
106
65
  /// !! Returning data of `msg.sender` will leak sensitive values - `msg.sender` cannot be trusted in view functions !!
107
- modifier withPermission(Permission memory permission) {
66
+ modifier withPermission(ACP memory acp) {
108
67
  // Expiration
109
- if (permission.expiration < block.timestamp)
68
+ if (acp.expiration < block.timestamp)
110
69
  revert PermissionInvalid_Expired();
111
70
 
112
71
  // Issuer signature
113
72
  if (
114
73
  !SignatureChecker.isValidSignatureNow(
115
- permission.issuer,
116
- _hashTypedDataV4(permission.issuerHash()),
117
- permission.issuerSignature
74
+ acp.issuer,
75
+ _hashTypedDataV4(acp.issuerHash()),
76
+ acp.issuerSignature
118
77
  )
119
78
  ) revert PermissionInvalid_IssuerSignature();
120
79
 
121
80
  // (if applicable) Recipient signature
122
81
  if (
123
- permission.recipient != address(0) &&
82
+ acp.recipient != address(0) &&
124
83
  !SignatureChecker.isValidSignatureNow(
125
- permission.recipient,
126
- _hashTypedDataV4(permission.recipientHash()),
127
- permission.recipientSignature
84
+ acp.recipient,
85
+ _hashTypedDataV4(acp.recipientHash()),
86
+ acp.recipientSignature
128
87
  )
129
88
  ) revert PermissionInvalid_RecipientSignature();
130
89
 
131
- // (if applicable) Externally disabled
90
+ // (if applicable) Externally disabled (revoked)
132
91
  if (
133
- permission.validatorId != 0 &&
134
- permission.validatorContract != address(0) &&
135
- IPermissionCustomIdValidator(permission.validatorContract).disabled(
136
- permission.issuer,
137
- permission.validatorId
92
+ acp.revokerData != 0 &&
93
+ acp.revokerContract != address(0) &&
94
+ IPermissionCustomIdValidator(acp.revokerContract).disabled(
95
+ acp.issuer,
96
+ acp.revokerData
138
97
  )
139
98
  ) revert PermissionInvalid_Disabled();
140
99
 
141
100
  _;
142
101
  }
143
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
+
144
110
  function hashTypedDataV4(
145
111
  bytes32 structHash
146
112
  ) public view virtual returns (bytes32) {
@@ -148,65 +114,60 @@ contract MockPermissioned is EIP712 {
148
114
  }
149
115
  }
150
116
 
151
- /// @dev Internal utility library to improve the readability of PermissionedV2
152
- /// Primarily focused on signature type hashes
153
- library PermissionUtils {
154
- function issuerHash(
155
- Permission memory permission
156
- ) internal pure returns (bytes32) {
157
- if (permission.recipient == address(0))
158
- return issuerSelfHash(permission);
159
- return issuerSharedHash(permission);
117
+ /// @dev Signature type hashes for ACP. Field order must match the struct and the
118
+ /// SDK's SignatureTypes exactly — pinned by tests on both sides.
119
+ 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);
160
123
  }
161
124
 
162
- function issuerSelfHash(
163
- Permission memory permission
164
- ) internal pure returns (bytes32) {
125
+ function issuerSelfHash(ACP memory acp) internal pure returns (bytes32) {
165
126
  return
166
127
  keccak256(
167
128
  abi.encode(
168
129
  keccak256(
169
- "PermissionedV2IssuerSelf(address issuer,uint64 expiration,address recipient,uint256 validatorId,address validatorContract,bytes32 sealingKey)"
130
+ "ACPIssuerSelf(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles,bytes32 sealingKey)"
170
131
  ),
171
- permission.issuer,
172
- permission.expiration,
173
- permission.recipient,
174
- permission.validatorId,
175
- permission.validatorContract,
176
- permission.sealingKey
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
177
141
  )
178
142
  );
179
143
  }
180
144
 
181
- function issuerSharedHash(
182
- Permission memory permission
183
- ) internal pure returns (bytes32) {
145
+ function issuerSharedHash(ACP memory acp) internal pure returns (bytes32) {
184
146
  return
185
147
  keccak256(
186
148
  abi.encode(
187
149
  keccak256(
188
- "PermissionedV2IssuerShared(address issuer,uint64 expiration,address recipient,uint256 validatorId,address validatorContract)"
150
+ "ACPIssuerShared(address issuer,uint64 expiration,address recipient,uint256 revokerData,address revokerContract,uint8 scope,address[] contracts,bytes32[] handles)"
189
151
  ),
190
- permission.issuer,
191
- permission.expiration,
192
- permission.recipient,
193
- permission.validatorId,
194
- permission.validatorContract
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))
195
160
  )
196
161
  );
197
162
  }
198
163
 
199
- function recipientHash(
200
- Permission memory permission
201
- ) internal pure returns (bytes32) {
164
+ function recipientHash(ACP memory acp) internal pure returns (bytes32) {
202
165
  return
203
166
  keccak256(
204
167
  abi.encode(
205
- keccak256(
206
- "PermissionedV2Recipient(bytes32 sealingKey,bytes issuerSignature)"
207
- ),
208
- permission.sealingKey,
209
- keccak256(permission.issuerSignature)
168
+ keccak256("ACPRecipient(bytes32 sealingKey,bytes issuerSignature)"),
169
+ acp.sealingKey,
170
+ keccak256(acp.issuerSignature)
210
171
  )
211
172
  );
212
173
  }