@cofhe/mock-contracts 0.1.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.
@@ -0,0 +1,140 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
2
+ // solhint-disable one-contract-per-file
3
+
4
+ pragma solidity >=0.8.19 <0.9.0;
5
+
6
+ import { TASK_MANAGER_ADDRESS } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
7
+ import { EncryptedInput } from '@fhenixprotocol/cofhe-contracts/ICofhe.sol';
8
+ import { MockTaskManager } from './MockTaskManager.sol';
9
+
10
+ contract MockZkVerifier {
11
+ // TMCommon
12
+ uint256 constant hashMaskForMetadata = type(uint256).max - type(uint16).max; // 2 bytes reserved for metadata
13
+ uint256 constant uintTypeMask = (type(uint8).max >> 1); // 0x7f - 7 bits reserved for uint type in the one before last byte
14
+ uint256 constant triviallyEncryptedMask = type(uint8).max - uintTypeMask; //0x80 1 bit reserved for isTriviallyEncrypted
15
+
16
+ // Specific
17
+ uint256 salt = 0;
18
+ error InvalidInputs();
19
+
20
+ // EXISTENCE
21
+
22
+ function exists() public pure returns (bool) {
23
+ return true;
24
+ }
25
+
26
+ // HASHING
27
+
28
+ function getByteForTrivialAndType(bool isTrivial, uint8 uintType) internal pure returns (uint256) {
29
+ /// @dev first bit for isTriviallyEncrypted
30
+ /// @dev last 7 bits for uintType
31
+
32
+ return uint256(((isTrivial ? triviallyEncryptedMask : 0x00) | (uintType & uintTypeMask)));
33
+ }
34
+
35
+ function _appendMetadata(
36
+ uint256 preCtHash,
37
+ uint8 securityZone,
38
+ uint8 uintType,
39
+ bool isTrivial
40
+ ) internal pure returns (uint256 result) {
41
+ result = preCtHash & hashMaskForMetadata;
42
+ uint256 metadata = (getByteForTrivialAndType(isTrivial, uintType) << 8) | (uint256(uint8(int8(securityZone)))); /// @dev 8 bits for type, 8 bits for securityZone
43
+ result = result | metadata;
44
+ }
45
+
46
+ function uint256ToBytes32(uint256 value) internal pure returns (bytes memory) {
47
+ bytes memory result = new bytes(32);
48
+ assembly {
49
+ mstore(add(result, 32), value)
50
+ }
51
+ return result;
52
+ }
53
+
54
+ function _calcPlaceholderKey(
55
+ address user,
56
+ uint8 utype,
57
+ uint8 securityZone,
58
+ uint256 input
59
+ ) internal view returns (uint256) {
60
+ bytes memory combined = bytes.concat(uint256ToBytes32(input));
61
+ combined = bytes.concat(combined, uint256ToBytes32(uint256(uint160(user))));
62
+ combined = bytes.concat(combined, keccak256(abi.encodePacked(salt)));
63
+
64
+ // Calculate Keccak256 hash
65
+ bytes32 ctHash = keccak256(combined);
66
+
67
+ return _appendMetadata(uint256(ctHash), securityZone, utype, false);
68
+ }
69
+
70
+ // CORE
71
+
72
+ function zkVerifyCalcCtHashesPacked(
73
+ uint256[] memory values,
74
+ uint8[] memory utypes,
75
+ address user,
76
+ uint8 securityZone,
77
+ uint256 chainId
78
+ ) public view returns (uint256[] memory ctHashes) {
79
+ if (utypes.length != values.length) {
80
+ revert InvalidInputs();
81
+ }
82
+
83
+ ctHashes = new uint256[](utypes.length);
84
+
85
+ for (uint256 i = 0; i < utypes.length; i++) {
86
+ ctHashes[i] = zkVerifyCalcCtHash(values[i], utypes[i], user, securityZone, chainId);
87
+ }
88
+ }
89
+
90
+ function zkVerifyCalcCtHash(
91
+ uint256 value,
92
+ uint8 utype,
93
+ address user,
94
+ uint8 securityZone,
95
+ uint256
96
+ ) public view returns (uint256 ctHash) {
97
+ ctHash = _calcPlaceholderKey(user, utype, securityZone, value);
98
+ }
99
+
100
+ function insertPackedCtHashes(uint256[] memory ctHashes, uint256[] memory values) public {
101
+ for (uint256 i = 0; i < ctHashes.length; i++) {
102
+ insertCtHash(ctHashes[i], values[i]);
103
+ }
104
+ }
105
+
106
+ function insertCtHash(uint256 ctHash, uint256 value) public {
107
+ MockTaskManager(TASK_MANAGER_ADDRESS).MOCK_setInEuintKey(ctHash, value);
108
+ salt += 1;
109
+ }
110
+
111
+ function zkVerifyPacked(
112
+ uint256[] memory values,
113
+ uint8[] memory utypes,
114
+ address user,
115
+ uint8 securityZone,
116
+ uint256 chainId
117
+ ) public returns (EncryptedInput[] memory inputs) {
118
+ if (utypes.length != values.length) {
119
+ revert InvalidInputs();
120
+ }
121
+
122
+ inputs = new EncryptedInput[](utypes.length);
123
+
124
+ for (uint256 i = 0; i < utypes.length; i++) {
125
+ inputs[i] = zkVerify(values[i], utypes[i], user, securityZone, chainId);
126
+ }
127
+ }
128
+
129
+ function zkVerify(
130
+ uint256 value,
131
+ uint8 utype,
132
+ address user,
133
+ uint8 securityZone,
134
+ uint256
135
+ ) public returns (EncryptedInput memory) {
136
+ uint256 ctHash = _calcPlaceholderKey(user, utype, securityZone, value);
137
+ insertCtHash(ctHash, value);
138
+ return EncryptedInput({ ctHash: ctHash, securityZone: securityZone, utype: utype, signature: hex'' });
139
+ }
140
+ }
@@ -0,0 +1,213 @@
1
+ // solhint-disable func-name-mixedcase
2
+ // SPDX-License-Identifier: MIT
3
+ pragma solidity >=0.8.19 <0.9.0;
4
+
5
+ import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
6
+ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
7
+
8
+ /**
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.
37
+ *
38
+ * ---
39
+ *
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).
43
+ */
44
+ struct Permission {
45
+ // (base) User that initially created the permission, target of data fetching
46
+ address issuer;
47
+ // (base) Expiration timestamp
48
+ uint64 expiration;
49
+ // (sharing) The user that this permission will be shared with
50
+ // ** optional, use `address(0)` to disable **
51
+ 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`
61
+ 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
+ bytes issuerSignature;
67
+ // (sharing) `signTypedData` signature created by `recipient` with format:
68
+ // (sharing) < sealingKey, issuerSignature>
69
+ // ** required for shared permits **
70
+ bytes recipientSignature;
71
+ }
72
+
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.
75
+ interface IPermissionCustomIdValidator {
76
+ /// @dev Checks whether a permission is valid, returning `false` disables the permission.
77
+ function disabled(address issuer, uint256 id) external view returns (bool);
78
+ }
79
+
80
+ contract MockPermissioned is EIP712 {
81
+ using PermissionUtils for Permission;
82
+
83
+ constructor() EIP712("ACL", "1") {}
84
+
85
+ /// @dev Emitted when `permission.expiration` is in the past (< block.timestamp)
86
+ error PermissionInvalid_Expired();
87
+
88
+ /// @dev Emitted when `issuerSignature` is malformed or was not signed by `permission.issuer`
89
+ error PermissionInvalid_IssuerSignature();
90
+
91
+ /// @dev Emitted when `recipientSignature` is malformed or was not signed by `permission.recipient`
92
+ error PermissionInvalid_RecipientSignature();
93
+
94
+ /// @dev Emitted when `validatorContract` returned `false` indicating that this permission has been externally disabled
95
+ error PermissionInvalid_Disabled();
96
+
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.
104
+ ///
105
+ /// NOTE: Functions protected by `withPermission` should return ONLY the sensitive data of `permission.issuer`.
106
+ /// !! Returning data of `msg.sender` will leak sensitive values - `msg.sender` cannot be trusted in view functions !!
107
+ modifier withPermission(Permission memory permission) {
108
+ // Expiration
109
+ if (permission.expiration < block.timestamp)
110
+ revert PermissionInvalid_Expired();
111
+
112
+ // Issuer signature
113
+ if (
114
+ !SignatureChecker.isValidSignatureNow(
115
+ permission.issuer,
116
+ _hashTypedDataV4(permission.issuerHash()),
117
+ permission.issuerSignature
118
+ )
119
+ ) revert PermissionInvalid_IssuerSignature();
120
+
121
+ // (if applicable) Recipient signature
122
+ if (
123
+ permission.recipient != address(0) &&
124
+ !SignatureChecker.isValidSignatureNow(
125
+ permission.recipient,
126
+ _hashTypedDataV4(permission.recipientHash()),
127
+ permission.recipientSignature
128
+ )
129
+ ) revert PermissionInvalid_RecipientSignature();
130
+
131
+ // (if applicable) Externally disabled
132
+ if (
133
+ permission.validatorId != 0 &&
134
+ permission.validatorContract != address(0) &&
135
+ IPermissionCustomIdValidator(permission.validatorContract).disabled(
136
+ permission.issuer,
137
+ permission.validatorId
138
+ )
139
+ ) revert PermissionInvalid_Disabled();
140
+
141
+ _;
142
+ }
143
+
144
+ function hashTypedDataV4(
145
+ bytes32 structHash
146
+ ) public view virtual returns (bytes32) {
147
+ return _hashTypedDataV4(structHash);
148
+ }
149
+ }
150
+
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);
160
+ }
161
+
162
+ function issuerSelfHash(
163
+ Permission memory permission
164
+ ) internal pure returns (bytes32) {
165
+ return
166
+ keccak256(
167
+ abi.encode(
168
+ keccak256(
169
+ "PermissionedV2IssuerSelf(address issuer,uint64 expiration,address recipient,uint256 validatorId,address validatorContract,bytes32 sealingKey)"
170
+ ),
171
+ permission.issuer,
172
+ permission.expiration,
173
+ permission.recipient,
174
+ permission.validatorId,
175
+ permission.validatorContract,
176
+ permission.sealingKey
177
+ )
178
+ );
179
+ }
180
+
181
+ function issuerSharedHash(
182
+ Permission memory permission
183
+ ) internal pure returns (bytes32) {
184
+ return
185
+ keccak256(
186
+ abi.encode(
187
+ keccak256(
188
+ "PermissionedV2IssuerShared(address issuer,uint64 expiration,address recipient,uint256 validatorId,address validatorContract)"
189
+ ),
190
+ permission.issuer,
191
+ permission.expiration,
192
+ permission.recipient,
193
+ permission.validatorId,
194
+ permission.validatorContract
195
+ )
196
+ );
197
+ }
198
+
199
+ function recipientHash(
200
+ Permission memory permission
201
+ ) internal pure returns (bytes32) {
202
+ return
203
+ keccak256(
204
+ abi.encode(
205
+ keccak256(
206
+ "PermissionedV2Recipient(bytes32 sealingKey,bytes issuerSignature)"
207
+ ),
208
+ permission.sealingKey,
209
+ keccak256(permission.issuerSignature)
210
+ )
211
+ );
212
+ }
213
+ }
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.13;
3
+
4
+ import '@fhenixprotocol/cofhe-contracts/FHE.sol';
5
+
6
+ contract TestBed {
7
+ euint32 public eNumber;
8
+ uint256 public numberHash;
9
+
10
+ function exists() public pure returns (bool) {
11
+ return true;
12
+ }
13
+
14
+ function setNumber(InEuint32 memory inNumber) public {
15
+ eNumber = FHE.asEuint32(inNumber);
16
+ numberHash = euint32.unwrap(eNumber);
17
+ FHE.allowThis(eNumber);
18
+ FHE.allowSender(eNumber);
19
+ }
20
+
21
+ function setNumberTrivial(uint256 inNumber) public {
22
+ eNumber = FHE.asEuint32(inNumber);
23
+ numberHash = euint32.unwrap(eNumber);
24
+ FHE.allowThis(eNumber);
25
+ FHE.allowSender(eNumber);
26
+ }
27
+
28
+ function increment() public {
29
+ eNumber = FHE.add(eNumber, FHE.asEuint32(1));
30
+ FHE.allowThis(eNumber);
31
+ FHE.allowSender(eNumber);
32
+ }
33
+
34
+ function add(InEuint32 memory inNumber) public {
35
+ eNumber = FHE.add(eNumber, FHE.asEuint32(inNumber));
36
+
37
+ FHE.allowThis(eNumber);
38
+ FHE.allowSender(eNumber);
39
+ }
40
+
41
+ function sub(InEuint32 memory inNumber) public {
42
+ euint32 inAsEuint32 = FHE.asEuint32(inNumber);
43
+ euint32 eSubOrZero = FHE.select(FHE.lte(inAsEuint32, eNumber), inAsEuint32, FHE.asEuint32(0));
44
+ eNumber = FHE.sub(eNumber, eSubOrZero);
45
+ FHE.allowThis(eNumber);
46
+ FHE.allowSender(eNumber);
47
+ }
48
+
49
+ function mul(InEuint32 memory inNumber) public {
50
+ eNumber = FHE.mul(eNumber, FHE.asEuint32(inNumber));
51
+ FHE.allowThis(eNumber);
52
+ FHE.allowSender(eNumber);
53
+ }
54
+
55
+ function decrypt() public {
56
+ FHE.decrypt(eNumber);
57
+ }
58
+
59
+ function getDecryptResult(euint32 input1) public view returns (uint32) {
60
+ return FHE.getDecryptResult(input1);
61
+ }
62
+
63
+ function getDecryptResultSafe(euint32 input1) public view returns (uint32 value, bool decrypted) {
64
+ return FHE.getDecryptResultSafe(input1);
65
+ }
66
+ }