@inco/lightning 0.11.0-testnet-3 → 1.0.0-devnet-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.
@@ -0,0 +1,211 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {inco} from "../Lib.sol";
5
+ import {euint256, ALLOWANCE_GRANTED_MAGIC_VALUE} from "../Types.sol";
6
+ import {IncoTest} from "./IncoTest.sol";
7
+ import {IIncoVerifier} from "../interfaces/IIncoVerifier.sol";
8
+ import {IncoVerifier} from "../IncoVerifier.sol";
9
+ import {AdvancedAccessControl} from "../lightning-parts/AccessControl/AdvancedAccessControl.sol";
10
+ import {AllowanceVoucher, AllowanceProof} from "../lightning-parts/AccessControl/AdvancedAccessControl.sol";
11
+ import {REQUIRED_ALLOWANCE_VOUCHER_WARNING} from "../lightning-parts/AccessControl/AdvancedAccessControl.types.sol";
12
+ import {DecryptionAttester} from "../lightning-parts/DecryptionAttester.sol";
13
+ import {
14
+ DecryptionAttestation,
15
+ ElementAttestationWithProof,
16
+ ReencryptionAttestation
17
+ } from "../lightning-parts/DecryptionAttester.types.sol";
18
+
19
+ /// @dev Approves any caller — simplest possible voucher verifier so the proof flow doesn't
20
+ /// shadow the property under test (which is the pause gate, not voucher logic).
21
+ contract AlwaysApprove {
22
+
23
+ function check(bytes32, address, bytes memory, bytes memory) public pure returns (bytes32) {
24
+ return ALLOWANCE_GRANTED_MAGIC_VALUE;
25
+ }
26
+
27
+ }
28
+
29
+ /// @dev Minimal test contract — reverts if the verifier reports the attestation invalid.
30
+ contract TestContract {
31
+
32
+ error InvalidAttestation();
33
+
34
+ IIncoVerifier verifier;
35
+
36
+ constructor(IIncoVerifier _verifier) {
37
+ verifier = _verifier;
38
+ }
39
+
40
+ function verify(DecryptionAttestation memory att, bytes[] calldata signatures) external view {
41
+ if (!verifier.isValidDecryptionAttestation(att, signatures)) {
42
+ revert InvalidAttestation();
43
+ }
44
+ }
45
+
46
+ }
47
+
48
+ contract TestVerifierPause is IncoTest {
49
+
50
+ function testValidAttestationsBecomeInvalidWhenVerifierIsPaused() public {
51
+ IIncoVerifier verifier = inco.incoVerifier();
52
+
53
+ // Set up a valid decryption attestation for a handle alice owns
54
+ vm.startPrank(alice);
55
+ euint256 secret = inco.asEuint256(42);
56
+ inco.allow(euint256.unwrap(secret), alice);
57
+ vm.stopPrank();
58
+ bytes32 handle = euint256.unwrap(secret);
59
+
60
+ AllowanceProof memory emptyProof; // sharer == address(0) → no voucher needed
61
+ (DecryptionAttestation memory att, bytes[] memory sigs) =
62
+ getDecryptionAttestation(alice, HandleWithProof({handle: handle, proof: emptyProof}));
63
+
64
+ // Set up a valid voucher-based AllowanceProof so isAllowedWithProof returns true
65
+ AlwaysApprove approver = new AlwaysApprove();
66
+ AllowanceVoucher memory voucher = AllowanceVoucher({
67
+ sessionNonce: bytes32(0),
68
+ verifyingContract: address(approver),
69
+ callFunction: approver.check.selector,
70
+ sharerArgData: "",
71
+ warning: REQUIRED_ALLOWANCE_VOUCHER_WARNING
72
+ });
73
+ AllowanceProof memory proof = AllowanceProof({
74
+ sharer: alice,
75
+ voucher: voucher,
76
+ voucherSignature: getSignatureForDigest(verifier.allowanceVoucherDigest(voucher), alicePrivKey),
77
+ requesterArgData: ""
78
+ });
79
+
80
+ // Set up valid reencryption + elist attestations (helpers scope away locals
81
+ // that would otherwise blow the 16-slot stack limit in this function)
82
+ (ReencryptionAttestation[] memory reAtts, bytes[] memory reSigs) = _buildValidReencryption(verifier, handle);
83
+ (ElementAttestationWithProof[] memory proofElements, bytes32 elistProof, bytes[] memory elistSigs) =
84
+ _buildValidElistAttestation(verifier, handle);
85
+
86
+ TestContract testContract = new TestContract(verifier);
87
+
88
+ // Sanity: every attestation is valid before pause
89
+ assertTrue(verifier.isValidDecryptionAttestation(att, sigs), "decryption attestation should be valid");
90
+ assertTrue(verifier.isAllowedWithProof(handle, bob, proof), "voucher proof should grant access");
91
+ assertTrue(verifier.isValidReencryptionAttestation(reAtts, reSigs), "reencryption attestation should be valid");
92
+ assertTrue(
93
+ verifier.isValidEListDecryptionAttestation(handle, proofElements, elistProof, elistSigs),
94
+ "elist decryption attestation should be valid"
95
+ );
96
+ testContract.verify(att, sigs); // shouldn't revert
97
+
98
+ // Pause the verifier
99
+ vm.prank(owner);
100
+ IncoVerifier(address(verifier)).pause();
101
+
102
+ // Pause flips every verifier check to false for the same inputs
103
+ assertFalse(
104
+ verifier.isValidDecryptionAttestation(att, sigs), "decryption attestation should be invalid when paused"
105
+ );
106
+ assertFalse(verifier.isAllowedWithProof(handle, bob, proof), "voucher proof should be rejected when paused");
107
+ assertFalse(
108
+ verifier.isValidReencryptionAttestation(reAtts, reSigs),
109
+ "reencryption attestation should be invalid when paused"
110
+ );
111
+ assertFalse(
112
+ verifier.isValidEListDecryptionAttestation(handle, proofElements, elistProof, elistSigs),
113
+ "elist decryption attestation should be invalid when paused"
114
+ );
115
+
116
+ // Downstream test contract that trusts the verifier reverts
117
+ vm.expectRevert(TestContract.InvalidAttestation.selector);
118
+ testContract.verify(att, sigs);
119
+
120
+ // Unpause restores validity (the attestation/proof bytes are unchanged)
121
+ vm.prank(owner);
122
+ IncoVerifier(address(verifier)).unpause();
123
+ assertTrue(verifier.isValidDecryptionAttestation(att, sigs), "decryption attestation should be valid again");
124
+ assertTrue(verifier.isAllowedWithProof(handle, bob, proof), "voucher proof should grant access again");
125
+ assertTrue(
126
+ verifier.isValidReencryptionAttestation(reAtts, reSigs), "reencryption attestation should be valid again"
127
+ );
128
+ assertTrue(
129
+ verifier.isValidEListDecryptionAttestation(handle, proofElements, elistProof, elistSigs),
130
+ "elist decryption attestation should be valid again"
131
+ );
132
+ testContract.verify(att, sigs); // shouldn't revert
133
+ }
134
+
135
+ /// @dev helper to build a valid ReencryptionAttestation + signatures that pass the verifier checks when not paused.
136
+ function _buildValidReencryption(IIncoVerifier verifier, bytes32 handle)
137
+ private
138
+ view
139
+ returns (ReencryptionAttestation[] memory atts, bytes[] memory sigs)
140
+ {
141
+ atts = new ReencryptionAttestation[](1);
142
+ atts[0] =
143
+ ReencryptionAttestation({handle: handle, userCiphertext: hex"deadbeef", encryptedSignature: hex"cafebabe"});
144
+ sigs = new bytes[](1);
145
+ sigs[0] = getSignatureForDigest(verifier.reencryptionAttestationDigest(atts[0]), teePrivKey);
146
+ }
147
+
148
+ /// @dev helper to build a valid EListAttestation + signatures that pass the verifier checks when not paused.
149
+ function _buildValidElistAttestation(IIncoVerifier verifier, bytes32 handle)
150
+ private
151
+ view
152
+ returns (ElementAttestationWithProof[] memory elements, bytes32 proof, bytes[] memory sigs)
153
+ {
154
+ elements = new ElementAttestationWithProof[](1);
155
+ elements[0] =
156
+ ElementAttestationWithProof({pairHash: keccak256("elem"), commitment: bytes32(0), value: bytes32(0)});
157
+ bytes32[] memory hashes = new bytes32[](1);
158
+ hashes[0] = elements[0].pairHash;
159
+ proof = keccak256(abi.encodePacked(hashes));
160
+ sigs = new bytes[](1);
161
+ sigs[0] = getSignatureForDigest(
162
+ verifier.decryptionAttestationDigest(DecryptionAttestation({handle: handle, value: proof})), teePrivKey
163
+ );
164
+ }
165
+
166
+ /// @dev Security-critical: when paused, the four verifier checks must short-circuit to
167
+ /// false BEFORE running any input validation.
168
+ function testPausedVerifierShortCircuitsBeforeInputValidation() public {
169
+ IIncoVerifier verifier = inco.incoVerifier();
170
+
171
+ // Inputs designed to exercise the unpaused revert paths in two of the four checks.
172
+ // (`isValidDecryptionAttestation` and `isValidEListDecryptionAttestation` use
173
+ // tryRecover + length-based early returns, so they don't have a clean malformed-revert
174
+ // path — for them we just assert the pause gate cleanly returns false.)
175
+ AllowanceProof memory garbageProof; // voucher.warning == "" → InvalidVoucherWarning
176
+ ReencryptionAttestation[] memory atts = new ReencryptionAttestation[](2);
177
+ bytes[] memory sigsLenOne = new bytes[](1); // mismatched → AttestationsSignaturesLengthMismatch
178
+ bytes[] memory sigsEmpty = new bytes[](0);
179
+ DecryptionAttestation memory garbageAtt;
180
+ ElementAttestationWithProof[] memory emptyElements = new ElementAttestationWithProof[](0);
181
+
182
+ // Sanity: the malformed inputs DO revert when not paused
183
+ vm.expectRevert(AdvancedAccessControl.InvalidVoucherWarning.selector);
184
+ verifier.isAllowedWithProof(bytes32(0), address(0), garbageProof);
185
+
186
+ vm.expectRevert(abi.encodeWithSelector(DecryptionAttester.AttestationsSignaturesLengthMismatch.selector, 2, 1));
187
+ verifier.isValidReencryptionAttestation(atts, sigsLenOne);
188
+
189
+ // Pause; the same calls must return false WITHOUT reverting
190
+ vm.prank(owner);
191
+ IncoVerifier(address(verifier)).pause();
192
+
193
+ assertFalse(
194
+ verifier.isAllowedWithProof(bytes32(0), address(0), garbageProof),
195
+ "isAllowedWithProof must return false (not revert) when paused with garbage proof"
196
+ );
197
+ assertFalse(
198
+ verifier.isValidReencryptionAttestation(atts, sigsLenOne),
199
+ "isValidReencryptionAttestation must return false (not revert) when paused with mismatched arrays"
200
+ );
201
+ assertFalse(
202
+ verifier.isValidDecryptionAttestation(garbageAtt, sigsEmpty),
203
+ "isValidDecryptionAttestation must return false when paused"
204
+ );
205
+ assertFalse(
206
+ verifier.isValidEListDecryptionAttestation(bytes32(0), emptyElements, bytes32(0), sigsEmpty),
207
+ "isValidEListDecryptionAttestation must return false when paused"
208
+ );
209
+ }
210
+
211
+ }
@@ -7,7 +7,7 @@ pragma solidity ^0.8;
7
7
  // UPDATE the CHANGELOG on new versions
8
8
 
9
9
  string constant CONTRACT_NAME = "incoLightning";
10
- uint8 constant MAJOR_VERSION = 11;
10
+ uint8 constant MAJOR_VERSION = 12;
11
11
  uint8 constant MINOR_VERSION = 0;
12
12
  // whenever a new version is deployed, we need to pump this up
13
13
  // otherwise make test_upgrade will fail