@inco/lightning 0.10.0-devnet-3 → 0.11.0-demonet-2

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.
Files changed (45) hide show
  1. package/manifest.yaml +46 -0
  2. package/package.json +1 -1
  3. package/src/IncoLightning.sol +1 -3
  4. package/src/IncoVerifier.sol +1 -3
  5. package/src/Lib.alphanet.sol +19 -0
  6. package/src/Lib.demonet.sol +20 -1
  7. package/src/Lib.devnet.sol +19 -0
  8. package/src/Lib.sol +20 -1
  9. package/src/Lib.template.sol +19 -0
  10. package/src/Lib.testnet.sol +20 -1
  11. package/src/Types.sol +0 -1
  12. package/src/interfaces/automata-interfaces/IPCCSRouterExtended.sol +2 -0
  13. package/src/libs/incoLightning_alphanet_v0_297966649.sol +19 -0
  14. package/src/libs/incoLightning_alphanet_v1_725458969.sol +19 -0
  15. package/src/libs/incoLightning_alphanet_v2_976644394.sol +19 -0
  16. package/src/libs/incoLightning_demonet_v0_863421733.sol +19 -0
  17. package/src/libs/incoLightning_demonet_v11_473256067.sol +1242 -0
  18. package/src/libs/incoLightning_demonet_v2_467437523.sol +19 -0
  19. package/src/libs/incoLightning_devnet_v0_340846814.sol +19 -0
  20. package/src/libs/incoLightning_devnet_v10_266391127.sol +19 -0
  21. package/src/libs/incoLightning_devnet_v1_904635675.sol +19 -0
  22. package/src/libs/incoLightning_devnet_v2_295237520.sol +19 -0
  23. package/src/libs/incoLightning_devnet_v3_976859633.sol +19 -0
  24. package/src/libs/incoLightning_devnet_v4_409204766.sol +19 -0
  25. package/src/libs/incoLightning_devnet_v5_203964628.sol +19 -0
  26. package/src/libs/incoLightning_devnet_v6_281949651.sol +19 -0
  27. package/src/libs/incoLightning_devnet_v7_24560427.sol +19 -0
  28. package/src/libs/incoLightning_devnet_v8_985328058.sol +19 -0
  29. package/src/libs/incoLightning_devnet_v9_269218568.sol +19 -0
  30. package/src/libs/incoLightning_testnet_v0_183408998.sol +19 -0
  31. package/src/libs/incoLightning_testnet_v11_340321378.sol +1242 -0
  32. package/src/libs/incoLightning_testnet_v2_889158349.sol +19 -0
  33. package/src/lightning-parts/AccessControl/AdvancedAccessControl.sol +13 -2
  34. package/src/lightning-parts/AccessControl/AdvancedAccessControl.types.sol +12 -0
  35. package/src/lightning-parts/AccessControl/test/TestAdvancedAccessControl.t.sol +36 -9
  36. package/src/lightning-parts/EncryptedOperations.sol +2 -9
  37. package/src/lightning-parts/primitives/EListHandleMetadata.sol +6 -6
  38. package/src/lightning-parts/primitives/HandleGeneration.sol +3 -10
  39. package/src/lightning-parts/primitives/HandleMetadata.sol +10 -10
  40. package/src/lightning-parts/test/HandleMetadata.t.sol +22 -40
  41. package/src/periphery/SessionVerifier.sol +16 -14
  42. package/src/test/IncoTest.sol +19 -3
  43. package/src/test/TestLib.t.sol +65 -13
  44. package/src/test/TestUpgrade.t.sol +1 -1
  45. package/src/version/IncoLightningConfig.sol +2 -2
@@ -801,6 +801,13 @@ library e {
801
801
  inco.allow(eaddress.unwrap(a), to);
802
802
  }
803
803
 
804
+ /// @notice Allows an address to access an elist
805
+ /// @param a The elist
806
+ /// @param to The address to allow
807
+ function allow(elist a, address to) internal {
808
+ inco.allow(elist.unwrap(a), to);
809
+ }
810
+
804
811
  /// @notice Reveals an encrypted uint256
805
812
  /// @param a The encrypted uint256
806
813
  function reveal(euint256 a) internal {
@@ -819,6 +826,12 @@ library e {
819
826
  inco.reveal(eaddress.unwrap(a));
820
827
  }
821
828
 
829
+ /// @notice Reveals an elist (makes all elements publicly readable without wallet authentication)
830
+ /// @param a The elist
831
+ function reveal(elist a) internal {
832
+ inco.reveal(elist.unwrap(a));
833
+ }
834
+
822
835
  /// @notice Verifies a decryption attestation for a euint256
823
836
  /// @param handle The encrypted handle
824
837
  /// @param value The claimed decrypted value
@@ -857,6 +870,12 @@ library e {
857
870
  allow(a, address(this));
858
871
  }
859
872
 
873
+ /// @notice Allows this contract to access an elist
874
+ /// @param a The elist
875
+ function allowThis(elist a) internal {
876
+ allow(a, address(this));
877
+ }
878
+
860
879
  /// @notice Checks if a user is allowed to access an encrypted uint256
861
880
  /// @param user The address to check
862
881
  /// @param a The encrypted uint256
@@ -1,7 +1,11 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8;
3
3
 
4
- import {AllowanceVoucher, AllowanceProof} from "./AdvancedAccessControl.types.sol";
4
+ import {
5
+ AllowanceVoucher,
6
+ AllowanceProof,
7
+ REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH
8
+ } from "./AdvancedAccessControl.types.sol";
5
9
  import {ALLOWANCE_GRANTED_MAGIC_VALUE} from "../../Types.sol";
6
10
  import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
7
11
  import {IAdvancedAccessControl, IVoucherEip712Checker} from "./interfaces/IAdvancedAccessControl.sol";
@@ -47,7 +51,7 @@ abstract contract VoucherEip712Checker is IVoucherEip712Checker, EIP712Upgradeab
47
51
  /// @notice EIP-712 type hash for the AllowanceVoucher struct
48
52
  /// @dev Computed once at compile time for gas efficiency
49
53
  bytes32 constant ALLOWANCE_VOUCHER_STRUCT_HASH = keccak256(
50
- "AllowanceVoucher(bytes32 sessionNonce,address verifyingContract,bytes4 callFunction,bytes sharerArgData)"
54
+ "AllowanceVoucher(string warning,bytes32 sessionNonce,address verifyingContract,bytes4 callFunction,bytes sharerArgData)"
51
55
  );
52
56
 
53
57
  /// @notice Computes the EIP-712 digest for an allowance voucher
@@ -60,6 +64,7 @@ abstract contract VoucherEip712Checker is IVoucherEip712Checker, EIP712Upgradeab
60
64
  keccak256(
61
65
  abi.encode(
62
66
  ALLOWANCE_VOUCHER_STRUCT_HASH,
67
+ keccak256(bytes(voucher.warning)),
63
68
  voucher.sessionNonce,
64
69
  voucher.verifyingContract,
65
70
  voucher.callFunction,
@@ -95,6 +100,9 @@ abstract contract AdvancedAccessControl is
95
100
 
96
101
  using SignatureChecker for address;
97
102
 
103
+ /// @notice Thrown when a voucher's warning field does not match the required warning text
104
+ error InvalidVoucherWarning();
105
+
98
106
  /// @notice Thrown when a voucher signature is invalid for the claimed signer
99
107
  /// @param signer The address that allegedly signed the voucher
100
108
  /// @param digest The EIP-712 digest that should have been signed
@@ -121,6 +129,9 @@ abstract contract AdvancedAccessControl is
121
129
  /// @param proof The allowance proof containing voucher, signature, and requester data
122
130
  /// @return True if access is allowed, false or reverts otherwise
123
131
  function isAllowedWithProof(bytes32 handle, address account, AllowanceProof memory proof) public returns (bool) {
132
+ require(
133
+ keccak256(bytes(proof.voucher.warning)) == REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH, InvalidVoucherWarning()
134
+ );
124
135
  require(proof.voucher.verifyingContract != address(0), InvalidVerifyingContract());
125
136
  require(
126
137
  IBaseAccessControlList(incoLightningAddress).isAllowed(handle, proof.sharer),
@@ -1,9 +1,21 @@
1
1
  // SPDX-License-Identifier: No License
2
2
  pragma solidity ^0.8;
3
3
 
4
+ // Required warning that must be present in every AllowanceVoucher.
5
+ // Must match SESSION_KEY_WARNING in js/src/advancedacl/session-key.ts.
6
+ string constant REQUIRED_ALLOWANCE_VOUCHER_WARNING =
7
+ "Inco Warning: signing this message may leak your private data, including from unrelated apps. Sign only if you fully trust this app.";
8
+
9
+ // Precomputed hash of REQUIRED_ALLOWANCE_VOUCHER_WARNING for cheap runtime comparison.
10
+ // Evaluated at compile time — no storage slot used, no runtime keccak256 of the full string.
11
+ bytes32 constant REQUIRED_ALLOWANCE_VOUCHER_WARNING_HASH = keccak256(bytes(REQUIRED_ALLOWANCE_VOUCHER_WARNING));
12
+
4
13
  // can be for arbitrary handles to arbitrary accounts
5
14
  // signed by the account sharing its read access
6
15
  struct AllowanceVoucher {
16
+ // Human-readable warning displayed by wallets at signing time.
17
+ // Must be first so wallets show it before the opaque byte fields below.
18
+ string warning;
7
19
  bytes32 sessionNonce;
8
20
  address verifyingContract;
9
21
  bytes4 callFunction;
@@ -4,6 +4,7 @@ pragma solidity ^0.8;
4
4
  import {IncoTest} from "../../../test/IncoTest.sol";
5
5
  import {SessionVerifier, Session} from "../../../periphery/SessionVerifier.sol";
6
6
  import {AllowanceVoucher, AllowanceProof} from "../AdvancedAccessControl.sol";
7
+ import {REQUIRED_ALLOWANCE_VOUCHER_WARNING} from "../AdvancedAccessControl.types.sol";
7
8
  import {euint256, SharerNotAllowedForHandle} from "../../../Types.sol";
8
9
  import {e, inco} from "../../../Lib.sol";
9
10
  import {AdvancedAccessControl} from "../AdvancedAccessControl.sol";
@@ -93,7 +94,8 @@ contract TestAdvancedAccessControl is IncoTest {
93
94
  sessionNonce: bytes32(0),
94
95
  verifyingContract: address(0),
95
96
  callFunction: SessionVerifier.canUseSession.selector,
96
- sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days}))
97
+ sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days})),
98
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
97
99
  });
98
100
  AllowanceProof memory bobsProof = getBobsProof(invalidSessionVoucher);
99
101
  vm.expectRevert(abi.encodeWithSelector(AdvancedAccessControl.InvalidVerifyingContract.selector));
@@ -111,7 +113,8 @@ contract TestAdvancedAccessControl is IncoTest {
111
113
  sessionNonce: bytes32(0),
112
114
  verifyingContract: address(sessionVerifier),
113
115
  callFunction: SessionVerifier.canUseSession.selector,
114
- sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days}))
116
+ sharerArgData: abi.encode(Session({decrypter: bob, expiresAt: block.timestamp + 1 days})),
117
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
115
118
  });
116
119
  AllowanceProof memory bobsProof = getBobsProof(aliceSessionVoucherForBob);
117
120
  assertTrue(
@@ -128,7 +131,8 @@ contract TestAdvancedAccessControl is IncoTest {
128
131
  sessionNonce: bytes32(0),
129
132
  verifyingContract: address(verifier),
130
133
  callFunction: verifier.someCheck.selector,
131
- sharerArgData: ""
134
+ sharerArgData: "",
135
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
132
136
  });
133
137
  AllowanceProof memory bobsFirstProof = getBobsProof(voucher);
134
138
  assertTrue(
@@ -140,7 +144,8 @@ contract TestAdvancedAccessControl is IncoTest {
140
144
  sessionNonce: madeUpNonce,
141
145
  verifyingContract: address(verifier),
142
146
  callFunction: verifier.someCheck.selector,
143
- sharerArgData: ""
147
+ sharerArgData: "",
148
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
144
149
  });
145
150
  AllowanceProof memory invalidBobProof = getBobsProof(voucher);
146
151
  // the session nonce should be checked by inco
@@ -164,7 +169,8 @@ contract TestAdvancedAccessControl is IncoTest {
164
169
  sessionNonce: alicesNewNonce,
165
170
  verifyingContract: address(verifier),
166
171
  callFunction: verifier.someCheck.selector,
167
- sharerArgData: ""
172
+ sharerArgData: "",
173
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
168
174
  });
169
175
  AllowanceProof memory bobsSecondProof = getBobsProof(voucher);
170
176
  assertTrue(
@@ -179,7 +185,8 @@ contract TestAdvancedAccessControl is IncoTest {
179
185
  sessionNonce: bytes32(0),
180
186
  verifyingContract: address(verifier),
181
187
  callFunction: verifier.someCheck.selector,
182
- sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob}))
188
+ sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob})),
189
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
183
190
  });
184
191
  AllowanceProof memory bobsProof = AllowanceProof({
185
192
  sharer: alice,
@@ -217,7 +224,8 @@ contract TestAdvancedAccessControl is IncoTest {
217
224
  sessionNonce: bytes32(0),
218
225
  verifyingContract: address(verifier),
219
226
  callFunction: verifier.someCheck.selector,
220
- sharerArgData: ""
227
+ sharerArgData: "",
228
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
221
229
  });
222
230
  // Use bob as sharer, but bob is NOT allowed on the secret (only alice is)
223
231
  AllowanceProof memory proof = AllowanceProof({
@@ -237,7 +245,8 @@ contract TestAdvancedAccessControl is IncoTest {
237
245
  sessionNonce: bytes32(0),
238
246
  verifyingContract: address(verifier),
239
247
  callFunction: verifier.someCheck.selector,
240
- sharerArgData: ""
248
+ sharerArgData: "",
249
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
241
250
  });
242
251
  // Alice is the sharer (and is allowed), but we sign with Bob's key
243
252
  bytes memory wrongSignature = getSignatureForDigest(incoVerifier.allowanceVoucherDigest(voucher), bobPrivKey);
@@ -252,6 +261,23 @@ contract TestAdvancedAccessControl is IncoTest {
252
261
  incoVerifier.isAllowedWithProof(secretHandle, bob, proof);
253
262
  }
254
263
 
264
+ /// @notice Test InvalidVoucherWarning error when voucher warning does not match required text
265
+ function testIsAllowedWithProofInvalidVoucherWarning() public {
266
+ DoesNotVerifyAnything verifier = new DoesNotVerifyAnything();
267
+ AllowanceVoucher memory voucher = AllowanceVoucher({
268
+ sessionNonce: bytes32(0),
269
+ verifyingContract: address(verifier),
270
+ callFunction: verifier.someCheck.selector,
271
+ sharerArgData: "",
272
+ warning: "wrong warning"
273
+ });
274
+ AllowanceProof memory proof = AllowanceProof({
275
+ sharer: alice, voucher: voucher, voucherSignature: getAliceSig(voucher), requesterArgData: ""
276
+ });
277
+ vm.expectRevert(abi.encodeWithSelector(AdvancedAccessControl.InvalidVoucherWarning.selector));
278
+ incoVerifier.isAllowedWithProof(secretHandle, bob, proof);
279
+ }
280
+
255
281
  /// @notice Test claimHandle fails when proof verification fails (line 107)
256
282
  function testClaimHandleProofVerificationFailed() public {
257
283
  SomeVerifier verifier = new SomeVerifier();
@@ -261,7 +287,8 @@ contract TestAdvancedAccessControl is IncoTest {
261
287
  sessionNonce: bytes32(0),
262
288
  verifyingContract: address(verifier),
263
289
  callFunction: verifier.someCheck.selector,
264
- sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob}))
290
+ sharerArgData: abi.encode(SomeVerifier.SharerArg({handleShared: secretHandle, allowedAccount: bob})),
291
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
265
292
  });
266
293
  AllowanceProof memory proof = AllowanceProof({
267
294
  sharer: alice, // alice IS allowed on the secret
@@ -7,6 +7,8 @@ import {
7
7
  EOps,
8
8
  SenderNotAllowedForHandle,
9
9
  ETypes,
10
+ UnexpectedType,
11
+ UnsupportedType,
10
12
  isTypeSupported,
11
13
  canCastTo,
12
14
  typeToBitMask
@@ -24,15 +26,6 @@ import {Fee} from "./Fee.sol";
24
26
  /// from the operation and inputs, enabling consistent state across chains.
25
27
  abstract contract EncryptedOperations is IEncryptedOperations, BaseAccessControlList, HandleGeneration, Fee {
26
28
 
27
- /// @notice Thrown when an operation receives a handle of an unexpected type.
28
- /// @param actual The actual type of the handle.
29
- /// @param expectedTypes A bitmask of the expected types.
30
- error UnexpectedType(ETypes actual, bytes32 expectedTypes);
31
-
32
- /// @notice Thrown when an operation receives an unsupported type.
33
- /// @param actual The unsupported type.
34
- error UnsupportedType(ETypes actual);
35
-
36
29
  /// @notice Thrown when a cast is attempted to the same type.
37
30
  /// @param t The type that was both source and target.
38
31
  error SameTypeCast(ETypes t);
@@ -24,12 +24,12 @@ contract EListHandleMetadata is IEListHandleMetadata {
24
24
  /// @notice Embeds the list length into a list handle
25
25
  /// @dev Sets bytes 27-28 of the handle to the list length.
26
26
  /// Clears existing length bits before setting new value.
27
- /// @param prehandle The 32-byte handle before length embedding
27
+ /// @param handle The 32-byte handle before length embedding
28
28
  /// @param len The number of elements in the list (max 65535)
29
29
  /// @return result The handle with embedded list length
30
- function embedListLength(bytes32 prehandle, uint16 len) internal pure returns (bytes32 result) {
30
+ function embedListLength(bytes32 handle, uint16 len) internal pure returns (bytes32 result) {
31
31
  // 27 and 28 bits are used for the list length
32
- result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff;
32
+ result = handle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff;
33
33
  result = bytes32(uint256(result) | (uint256(len) << 24)); // append length
34
34
  }
35
35
 
@@ -44,11 +44,11 @@ contract EListHandleMetadata is IEListHandleMetadata {
44
44
  /// @notice Embeds the element type into a list handle
45
45
  /// @dev Sets byte 29 of the handle to the element type.
46
46
  /// This indicates the encrypted type of individual elements (euint8, euint64, etc.).
47
- /// @param prehandle The 32-byte handle before type embedding
47
+ /// @param handle The 32-byte handle before type embedding
48
48
  /// @param listType The encrypted type of list elements
49
49
  /// @return result The handle with embedded element type
50
- function embedListType(bytes32 prehandle, ETypes listType) internal pure returns (bytes32 result) {
51
- result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff;
50
+ function embedListType(bytes32 handle, ETypes listType) internal pure returns (bytes32 result) {
51
+ result = handle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff;
52
52
  result = bytes32(uint256(result) | (uint256(listType) << 16)); // append element type
53
53
  }
54
54
 
@@ -7,7 +7,6 @@ import {
7
7
  EVM_HOST_CHAIN_PREFIX,
8
8
  HANDLE_INDEX,
9
9
  HANDLE_VERSION,
10
- SEP_INPUT_PREHANDLE,
11
10
  SEP_INPUT_HANDLE,
12
11
  SEP_OP_RESULT
13
12
  } from "../../Types.sol";
@@ -78,14 +77,6 @@ contract HandleGeneration is IHandleGeneration, HandleMetadata {
78
77
  uint16 version,
79
78
  ETypes inputType
80
79
  ) internal view returns (bytes32 generatedHandle) {
81
- // Prehandle is a legacy concept inherited by an earlier design where we had a preflight system for uploading ciphertexts to an L1 before they could be used.
82
- // This is no longer the case and prehandle was mainly kept for compatibility and consistency with the intrernal design docs.
83
- // To avoid calling keccak256 twice and save gas the prehandle concept will be dropped in a future PR.
84
- bytes32 ctIndexHash = keccak256(
85
- // We don't encode the length of the ciphertext because it's the only variable length field which should prevent collisions.
86
- abi.encodePacked(SEP_INPUT_PREHANDLE, keccak256(ciphertext), HANDLE_INDEX)
87
- );
88
- bytes32 prehandle = embedIndexTypeVersion(ctIndexHash, inputType);
89
80
  // We must also propagate the handle metadata to the final handle
90
81
  generatedHandle = embedIndexTypeVersion(
91
82
  keccak256(
@@ -93,7 +84,9 @@ contract HandleGeneration is IHandleGeneration, HandleMetadata {
93
84
  SEP_INPUT_HANDLE,
94
85
  HANDLE_VERSION,
95
86
  inputType,
96
- prehandle,
87
+ uint32(ciphertext.length),
88
+ ciphertext,
89
+ HANDLE_INDEX,
97
90
  EVM_HOST_CHAIN_PREFIX,
98
91
  block.chainid, // todo cache this
99
92
  executorAddress,
@@ -16,35 +16,35 @@ contract HandleMetadata {
16
16
  /// @param raw The raw uint8 value extracted from the handle.
17
17
  error InvalidTypeValue(uint8 raw);
18
18
 
19
- /// @notice Embeds the handle index, encrypted type, and protocol version into a prehandle
19
+ /// @notice Embeds the handle index, encrypted type, and protocol version into a handle
20
20
  /// @dev Used for input handles where the index distinguishes the source.
21
- /// Clears bytes 29-31 of the prehandle, then sets:
21
+ /// Clears bytes 29-31 of the handle, then sets:
22
22
  /// - Byte 29: HANDLE_INDEX constant
23
23
  /// - Byte 30: inputType enum value
24
24
  /// - Byte 31: HANDLE_VERSION constant
25
- /// @param prehandle The 32-byte hash before metadata embedding
25
+ /// @param handle The 32-byte hash before metadata embedding
26
26
  /// @param inputType The encrypted type to embed (ebool, euint8, etc.)
27
27
  /// @return result The complete handle with embedded metadata
28
- function embedIndexTypeVersion(bytes32 prehandle, ETypes inputType) internal pure returns (bytes32 result) {
28
+ function embedIndexTypeVersion(bytes32 handle, ETypes inputType) internal pure returns (bytes32 result) {
29
29
  // Create a mask to clear the last three bytes
30
30
  bytes32 mask = bytes32(uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFF));
31
31
  // Clear the last three bytes of the original value
32
- bytes32 clearedOriginal = prehandle & mask;
32
+ bytes32 clearedOriginal = handle & mask;
33
33
  // Combine the cleared original value with the new last three bytes
34
34
  result = clearedOriginal | bytes32((uint256(HANDLE_INDEX) << 16));
35
35
  result = embedTypeVersion(result, inputType);
36
36
  }
37
37
 
38
- /// @notice Embeds the encrypted type and protocol version into a prehandle
38
+ /// @notice Embeds the encrypted type and protocol version into a handle
39
39
  /// @dev Used for operation result handles and trivial encryptions.
40
- /// Clears bytes 30-31 of the prehandle, then sets:
40
+ /// Clears bytes 30-31 of the handle, then sets:
41
41
  /// - Byte 30: handleType enum value
42
42
  /// - Byte 31: HANDLE_VERSION constant
43
- /// @param prehandle The 32-byte hash before metadata embedding
43
+ /// @param handle The 32-byte hash before metadata embedding
44
44
  /// @param handleType The encrypted type to embed (ebool, euint8, etc.)
45
45
  /// @return result The handle with type and version embedded
46
- function embedTypeVersion(bytes32 prehandle, ETypes handleType) internal pure returns (bytes32 result) {
47
- result = prehandle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000;
46
+ function embedTypeVersion(bytes32 handle, ETypes handleType) internal pure returns (bytes32 result) {
47
+ result = handle & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000;
48
48
  result = bytes32(uint256(result) | (uint256(handleType) << 8)); // append type
49
49
  result = bytes32(uint256(result) | HANDLE_VERSION);
50
50
  }
@@ -16,7 +16,9 @@ import {
16
16
  typeToBitMask,
17
17
  EOps,
18
18
  isTypeSupported,
19
- SenderNotAllowedForHandle
19
+ SenderNotAllowedForHandle,
20
+ UnexpectedType,
21
+ UnsupportedType
20
22
  } from "../../Types.sol";
21
23
  import {VerifierAddressGetter} from "../primitives/VerifierAddressGetter.sol";
22
24
  import {FEE} from "../Fee.sol";
@@ -77,11 +79,7 @@ contract TestHandleMetadata is
77
79
  ebool control = this.asEbool(false);
78
80
  euint256 a = this.asEuint256(42);
79
81
  ebool b = this.asEbool(true);
80
- vm.expectRevert(
81
- abi.encodeWithSelector(
82
- EncryptedOperations.UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)
83
- )
84
- );
82
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)));
85
83
  this.eIfThenElse(control, euint256.unwrap(a), ebool.unwrap(b));
86
84
  }
87
85
 
@@ -286,11 +284,7 @@ contract TestHandleMetadata is
286
284
  ebool b = this.asEbool(true);
287
285
  // Error: UnexpectedType(typeOf(rhs), typeToBitMask(lhsType))
288
286
  // With lhs=Uint256, rhs=Bool: UnexpectedType(Bool, typeToBitMask(Uint256))
289
- vm.expectRevert(
290
- abi.encodeWithSelector(
291
- EncryptedOperations.UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)
292
- )
293
- );
287
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)));
294
288
  this.eBitAnd(euint256.unwrap(a), ebool.unwrap(b));
295
289
  }
296
290
 
@@ -298,11 +292,7 @@ contract TestHandleMetadata is
298
292
  function testEBitOrTypeMismatch() public {
299
293
  euint256 a = this.asEuint256(42);
300
294
  ebool b = this.asEbool(true);
301
- vm.expectRevert(
302
- abi.encodeWithSelector(
303
- EncryptedOperations.UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)
304
- )
305
- );
295
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)));
306
296
  this.eBitOr(euint256.unwrap(a), ebool.unwrap(b));
307
297
  }
308
298
 
@@ -310,11 +300,7 @@ contract TestHandleMetadata is
310
300
  function testEBitXorTypeMismatch() public {
311
301
  euint256 a = this.asEuint256(42);
312
302
  ebool b = this.asEbool(true);
313
- vm.expectRevert(
314
- abi.encodeWithSelector(
315
- EncryptedOperations.UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)
316
- )
317
- );
303
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)));
318
304
  this.eBitXor(euint256.unwrap(a), ebool.unwrap(b));
319
305
  }
320
306
 
@@ -322,7 +308,7 @@ contract TestHandleMetadata is
322
308
  function testECastUnsupportedType() public {
323
309
  euint256 a = this.asEuint256(42);
324
310
  ETypes unsupportedType = ETypes.Uint4UNSUPPORTED;
325
- vm.expectRevert(abi.encodeWithSelector(EncryptedOperations.UnsupportedType.selector, unsupportedType));
311
+ vm.expectRevert(abi.encodeWithSelector(UnsupportedType.selector, unsupportedType));
326
312
  this.eCast(euint256.unwrap(a), unsupportedType);
327
313
  }
328
314
 
@@ -330,7 +316,7 @@ contract TestHandleMetadata is
330
316
  function testERandBoundedUnsupportedType() public {
331
317
  euint256 bound = this.asEuint256(100);
332
318
  ETypes unsupportedType = ETypes.Uint4UNSUPPORTED;
333
- vm.expectRevert(abi.encodeWithSelector(EncryptedOperations.UnsupportedType.selector, unsupportedType));
319
+ vm.expectRevert(abi.encodeWithSelector(UnsupportedType.selector, unsupportedType));
334
320
  this.eRandBounded{value: FEE}(euint256.unwrap(bound), unsupportedType);
335
321
  }
336
322
 
@@ -340,7 +326,7 @@ contract TestHandleMetadata is
340
326
  // Create a handle with unsupported type by manually crafting one
341
327
  bytes32 unsupportedHandle = embedIndexTypeVersion(bytes32(uint256(1)), ETypes.Uint4UNSUPPORTED);
342
328
  ebool ifFalse = this.asEbool(false);
343
- vm.expectRevert(abi.encodeWithSelector(EncryptedOperations.UnsupportedType.selector, ETypes.Uint4UNSUPPORTED));
329
+ vm.expectRevert(abi.encodeWithSelector(UnsupportedType.selector, ETypes.Uint4UNSUPPORTED));
344
330
  this.eIfThenElse(control, unsupportedHandle, ebool.unwrap(ifFalse));
345
331
  }
346
332
 
@@ -351,11 +337,7 @@ contract TestHandleMetadata is
351
337
  ebool ifFalse = this.asEbool(false);
352
338
  // ifTrue is Uint256, ifFalse is Bool - type mismatch should trigger checkInput failure
353
339
  // Error is UnexpectedType(ifFalse type=Bool, required type mask for Uint256)
354
- vm.expectRevert(
355
- abi.encodeWithSelector(
356
- EncryptedOperations.UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)
357
- )
358
- );
340
+ vm.expectRevert(abi.encodeWithSelector(UnexpectedType.selector, ETypes.Bool, typeToBitMask(ETypes.Uint256)));
359
341
  this.eIfThenElse(control, euint256.unwrap(ifTrue), ebool.unwrap(ifFalse));
360
342
  }
361
343
 
@@ -379,7 +361,7 @@ contract TestHandleMetadata is
379
361
  // ============ Fuzz Tests for HandleMetadata ============
380
362
 
381
363
  /// @dev Fuzz test for type embedding round-trip: typeOf(embedTypeVersion(h, t)) == t
382
- function testFuzzTypeEmbeddingRoundTrip(bytes32 prehandle, uint8 typeIndex) public pure {
364
+ function testFuzzTypeEmbeddingRoundTrip(bytes32 handle, uint8 typeIndex) public pure {
383
365
  // Constrain to supported types (0=Bool, 7=AddressOrUint160OrBytes20, 8=Uint256)
384
366
  ETypes inputType;
385
367
  uint8 typeSelector = typeIndex % 3;
@@ -391,14 +373,14 @@ contract TestHandleMetadata is
391
373
  inputType = ETypes.Uint256;
392
374
  }
393
375
 
394
- bytes32 embeddedHandle = embedTypeVersion(prehandle, inputType);
376
+ bytes32 embeddedHandle = embedTypeVersion(handle, inputType);
395
377
  ETypes extractedType = typeOf(embeddedHandle);
396
378
 
397
379
  assert(extractedType == inputType);
398
380
  }
399
381
 
400
382
  /// @dev Fuzz test for embedIndexTypeVersion round-trip
401
- function testFuzzEmbedIndexTypeVersionRoundTrip(bytes32 prehandle, uint8 typeIndex) public pure {
383
+ function testFuzzEmbedIndexTypeVersionRoundTrip(bytes32 handle, uint8 typeIndex) public pure {
402
384
  // Constrain to supported types
403
385
  ETypes inputType;
404
386
  uint8 typeSelector = typeIndex % 3;
@@ -410,14 +392,14 @@ contract TestHandleMetadata is
410
392
  inputType = ETypes.Uint256;
411
393
  }
412
394
 
413
- bytes32 embeddedHandle = embedIndexTypeVersion(prehandle, inputType);
395
+ bytes32 embeddedHandle = embedIndexTypeVersion(handle, inputType);
414
396
  ETypes extractedType = typeOf(embeddedHandle);
415
397
 
416
398
  assert(extractedType == inputType);
417
399
  }
418
400
 
419
401
  /// @dev Fuzz test that typeOf correctly extracts type from handles with valid embedded types
420
- function testFuzzTypeOfExtraction(bytes32 prehandle, uint8 typeIndex) public pure {
402
+ function testFuzzTypeOfExtraction(bytes32 handle, uint8 typeIndex) public pure {
421
403
  // First embed a valid type, then verify extraction
422
404
  ETypes inputType;
423
405
  uint8 typeSelector = typeIndex % 3;
@@ -429,7 +411,7 @@ contract TestHandleMetadata is
429
411
  inputType = ETypes.Uint256;
430
412
  }
431
413
 
432
- bytes32 handle = embedTypeVersion(prehandle, inputType);
414
+ bytes32 handle = embedTypeVersion(handle, inputType);
433
415
 
434
416
  // Extract the type from the handle
435
417
  ETypes extractedType = typeOf(handle);
@@ -444,7 +426,7 @@ contract TestHandleMetadata is
444
426
  }
445
427
 
446
428
  /// @dev Fuzz test that embedding preserves upper bits of handle
447
- function testFuzzEmbeddingPreservesUpperBits(bytes32 prehandle, uint8 typeIndex) public pure {
429
+ function testFuzzEmbeddingPreservesUpperBits(bytes32 handle, uint8 typeIndex) public pure {
448
430
  ETypes inputType;
449
431
  uint8 typeSelector = typeIndex % 3;
450
432
  if (typeSelector == 0) {
@@ -455,16 +437,16 @@ contract TestHandleMetadata is
455
437
  inputType = ETypes.Uint256;
456
438
  }
457
439
 
458
- bytes32 embeddedHandle = embedTypeVersion(prehandle, inputType);
440
+ bytes32 embeddedHandle = embedTypeVersion(handle, inputType);
459
441
 
460
442
  // Verify upper 30 bytes (240 bits) are preserved
461
443
  // Mask out the lower 2 bytes (16 bits) for comparison
462
444
  bytes32 upperMask = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000;
463
- assert((prehandle & upperMask) == (embeddedHandle & upperMask));
445
+ assert((handle & upperMask) == (embeddedHandle & upperMask));
464
446
  }
465
447
 
466
448
  /// @dev Fuzz test that embedIndexTypeVersion clears index byte correctly
467
- function testFuzzEmbedIndexClearsCorrectly(bytes32 prehandle, uint8 typeIndex) public pure {
449
+ function testFuzzEmbedIndexClearsCorrectly(bytes32 handle, uint8 typeIndex) public pure {
468
450
  ETypes inputType;
469
451
  uint8 typeSelector = typeIndex % 3;
470
452
  if (typeSelector == 0) {
@@ -475,7 +457,7 @@ contract TestHandleMetadata is
475
457
  inputType = ETypes.Uint256;
476
458
  }
477
459
 
478
- bytes32 embeddedHandle = embedIndexTypeVersion(prehandle, inputType);
460
+ bytes32 embeddedHandle = embedIndexTypeVersion(handle, inputType);
479
461
 
480
462
  // Extract index byte (bits 16-23) - should be HANDLE_INDEX (0)
481
463
  uint8 indexByte = uint8(uint256(embeddedHandle) >> 16);
@@ -26,18 +26,21 @@ struct Session {
26
26
 
27
27
  /// @title SessionVerifier
28
28
  /// @notice Inco access sharing verifier for browser dApp sessions
29
- /// @dev Grants access to all encrypted data held by the sharer to one decrypter for a limited time.
30
- /// This is the recommended pattern for dApps that need to decrypt user data during a browsing session.
29
+ /// @dev Grants a single decrypter address temporary access to all of the sharer's
30
+ /// encrypted handles. The session is valid as long as block.timestamp < expiresAt
31
+ /// and the requesting account matches the authorized decrypter.
31
32
  ///
32
33
  /// Usage:
33
- /// 1. User signs a voucher containing a Session struct with their chosen decrypter and expiration
34
- /// 2. The voucher specifies canUseSession.selector as the callFunction
35
- /// 3. When the decrypter requests access, this contract verifies the session is still valid
34
+ /// 1. User signs a voucher containing a Session struct with their chosen decrypter
35
+ /// and expiration time.
36
+ /// 2. The voucher specifies canUseSession.selector as the callFunction.
37
+ /// 3. When the decrypter requests access, this contract verifies the session is still
38
+ /// valid and the caller matches the authorized decrypter.
36
39
  ///
37
40
  /// To use this verifier, set the voucher's callFunction to SessionVerifier.canUseSession.selector
38
41
  contract SessionVerifier is UUPSUpgradeable, OwnableUpgradeable, Version {
39
42
 
40
- /// @notice Initializes the SessionVerifier with version information
43
+ /// @notice Initializes the SessionVerifier with version information.
41
44
  /// @param _salt Unique salt used for deterministic deployment via CreateX
42
45
  constructor(bytes32 _salt)
43
46
  Version(
@@ -49,29 +52,28 @@ contract SessionVerifier is UUPSUpgradeable, OwnableUpgradeable, Version {
49
52
  )
50
53
  {}
51
54
 
52
- /// @notice Verifies if an account can use a session to access encrypted data
55
+ /// @notice Verifies if an account can use a session to access an encrypted handle.
53
56
  /// @dev This function is called by the ACL system when validating access permissions.
54
- /// The session grants blanket access to all handles owned by the sharer - the handle
55
- /// parameter is intentionally ignored.
57
+ /// Access is granted if the session has not expired and the caller is the authorized decrypter.
56
58
  /// @param account The address requesting access (must match session.decrypter)
57
- /// @param sharerArgData ABI-encoded Session struct containing decrypter address and expiration
58
- /// @return ALLOWANCE_GRANTED_MAGIC_VALUE if session is valid, bytes32(0) otherwise
59
+ /// @param sharerArgData ABI-encoded Session struct containing decrypter and expiration
60
+ /// @return ALLOWANCE_GRANTED_MAGIC_VALUE if access is granted, bytes32(0) otherwise
59
61
  function canUseSession(
60
62
  bytes32, /* handle */
61
63
  address account,
62
64
  bytes memory sharerArgData,
63
- bytes memory requesterArgData
65
+ bytes memory /* requesterArgData */
64
66
  )
65
67
  external
66
68
  view
67
69
  returns (bytes32)
68
70
  {
69
- // unused variable just here to bypass linter
70
- (requesterArgData);
71
71
  Session memory session = abi.decode(sharerArgData, (Session));
72
+
72
73
  if (session.expiresAt >= block.timestamp && session.decrypter == account) {
73
74
  return ALLOWANCE_GRANTED_MAGIC_VALUE;
74
75
  }
76
+
75
77
  return bytes32(0);
76
78
  }
77
79