@inco/lightning 0.6.7 → 0.6.9
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.
- package/README.md +29 -2
- package/manifest.yaml +0 -42
- package/package.json +5 -2
- package/src/CreateXHelper.sol +3 -1
- package/src/DeployUtils.sol +36 -71
- package/src/Errors.sol +1 -1
- package/src/IIncoLightning.sol +2 -0
- package/src/IncoLightning.sol +5 -17
- package/src/IncoVerifier.sol +12 -18
- package/src/Lib.template.sol +40 -159
- package/src/Types.sol +233 -97
- package/src/interfaces/IIncoLightning.sol +2 -0
- package/src/interfaces/IIncoVerifier.sol +7 -12
- package/src/interfaces/automata-interfaces/BELE.sol +2 -0
- package/src/interfaces/automata-interfaces/IAutomataEnclaveIdentityDao.sol +9 -11
- package/src/interfaces/automata-interfaces/IFmspcTcbDao.sol +3 -3
- package/src/interfaces/automata-interfaces/IPCCSRouter.sol +13 -47
- package/src/interfaces/automata-interfaces/IPCCSRouterExtended.sol +2 -0
- package/src/interfaces/automata-interfaces/IPcsDao.sol +6 -11
- package/src/interfaces/automata-interfaces/IQuoteVerifier.sol +4 -7
- package/src/interfaces/automata-interfaces/Types.sol +7 -6
- package/src/libs/incoLightning_devnet_v1_887305889.sol +5 -3
- package/src/libs/incoLightning_testnet_v1_938327937.sol +5 -3
- package/src/lightning-parts/AccessControl/AdvancedAccessControl.sol +41 -75
- package/src/lightning-parts/AccessControl/BaseAccessControlList.sol +31 -62
- package/src/lightning-parts/AccessControl/interfaces/IAdvancedAccessControl.sol +8 -15
- package/src/lightning-parts/AccessControl/interfaces/IBaseAccessControlList.sol +5 -12
- package/src/lightning-parts/AccessControl/test/TestAdvancedAccessControl.t.sol +42 -83
- package/src/lightning-parts/AccessControl/test/TestBaseAccessControl.t.sol +2 -0
- package/src/lightning-parts/DecryptionAttester.sol +14 -28
- package/src/lightning-parts/EncryptedInput.sol +23 -52
- package/src/lightning-parts/EncryptedOperations.sol +93 -440
- package/src/lightning-parts/Fee.sol +3 -1
- package/src/lightning-parts/TEELifecycle.sol +95 -225
- package/src/lightning-parts/TEELifecycle.types.sol +4 -3
- package/src/lightning-parts/TrivialEncryption.sol +6 -20
- package/src/lightning-parts/interfaces/IDecryptionAttester.sol +7 -2
- package/src/lightning-parts/interfaces/IEncryptedInput.sol +5 -12
- package/src/lightning-parts/interfaces/IEncryptedOperations.sol +17 -61
- package/src/lightning-parts/interfaces/ITEELifecycle.sol +7 -11
- package/src/lightning-parts/interfaces/ITrivialEncryption.sol +2 -0
- package/src/lightning-parts/primitives/EventCounter.sol +7 -8
- package/src/lightning-parts/primitives/HandleGeneration.sol +20 -32
- package/src/lightning-parts/primitives/HandleMetadata.sol +7 -17
- package/src/lightning-parts/primitives/LightningAddressGetter.sol +3 -0
- package/src/lightning-parts/primitives/SignatureVerifier.sol +91 -27
- package/src/lightning-parts/primitives/VerifierAddressGetter.sol +3 -0
- package/src/lightning-parts/primitives/interfaces/IEventCounter.sol +2 -0
- package/src/lightning-parts/primitives/interfaces/IHandleGeneration.sol +10 -2
- package/src/lightning-parts/primitives/interfaces/ISignatureVerifier.sol +4 -2
- package/src/lightning-parts/primitives/interfaces/IVerifierAddressGetter.sol +2 -0
- package/src/lightning-parts/primitives/test/SignatureVerifier.t.sol +838 -0
- package/src/lightning-parts/test/Fee.t.sol +6 -6
- package/src/lightning-parts/test/HandleMetadata.t.sol +21 -76
- package/src/lightning-parts/test/InputsFee.t.sol +7 -28
- package/src/lightning-parts/test/TestDecryptionAttestationInSynchronousFlow.t.sol +16 -48
- package/src/pasted-dependencies/CreateX.sol +146 -419
- package/src/pasted-dependencies/ICreateX.sol +58 -102
- package/src/periphery/SessionVerifier.sol +5 -7
- package/src/shared/IOwnable.sol +3 -0
- package/src/shared/IUUPSUpgradable.sol +5 -1
- package/src/shared/JsonUtils.sol +3 -5
- package/src/shared/TestUtils.sol +14 -13
- package/src/test/AddTwo.sol +9 -7
- package/src/test/FakeIncoInfra/FakeComputeServer.sol +11 -53
- package/src/test/FakeIncoInfra/FakeDecryptionAttester.sol +35 -118
- package/src/test/FakeIncoInfra/FakeIncoInfraBase.sol +31 -48
- package/src/test/FakeIncoInfra/FakeQuoteVerifier.sol +4 -7
- package/src/test/FakeIncoInfra/KVStore.sol +2 -0
- package/src/test/FakeIncoInfra/MockOpHandler.sol +9 -31
- package/src/test/FakeIncoInfra/MockRemoteAttestation.sol +44 -21
- package/src/test/IncoTest.sol +15 -9
- package/src/test/OpsTest.sol +429 -0
- package/src/test/TEELifecycle/TEELifecycleMockTest.t.sol +58 -104
- package/src/test/TestAddTwo.t.sol +4 -3
- package/src/test/TestDeploy.t.sol +5 -6
- package/src/test/TestExtractDataOfEventTooLarge.t.sol +7 -14
- package/src/test/TestFakeInfra.t.sol +15 -38
- package/src/test/TestUpgrade.t.sol +40 -135
- package/src/test/TestVersion.t.sol +6 -5
- package/src/version/IncoLightningConfig.sol +1 -1
- package/src/version/Version.sol +48 -51
- package/src/version/interfaces/IVersion.sol +6 -0
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
// SPDX-License-Identifier: No License
|
|
2
|
+
pragma solidity ^0.8;
|
|
3
|
+
|
|
4
|
+
import {TestUtils} from "../../../shared/TestUtils.sol";
|
|
5
|
+
import {SignatureVerifier} from "../SignatureVerifier.sol";
|
|
6
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
7
|
+
|
|
8
|
+
contract TestSignatureVerifier is TestUtils, SignatureVerifier {
|
|
9
|
+
|
|
10
|
+
using ECDSA for bytes32;
|
|
11
|
+
|
|
12
|
+
function setUp() public initializer {
|
|
13
|
+
// Initialize the contract
|
|
14
|
+
__Ownable_init(address(this));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Helper function to create sorted signatures
|
|
18
|
+
// Takes a digest and an array of private keys, generates signatures,
|
|
19
|
+
// and returns them sorted by signer address in ascending order
|
|
20
|
+
function getSortedSignatures(bytes32 digest, uint256[] memory privKeys) internal returns (bytes[] memory) {
|
|
21
|
+
bytes[] memory signatures = new bytes[](privKeys.length);
|
|
22
|
+
address[] memory signers = new address[](privKeys.length);
|
|
23
|
+
|
|
24
|
+
// Generate signatures and recover signer addresses
|
|
25
|
+
for (uint256 i = 0; i < privKeys.length; i++) {
|
|
26
|
+
signatures[i] = getSignatureForDigest(digest, privKeys[i]);
|
|
27
|
+
signers[i] = digest.recover(signatures[i]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Bubble sort signatures by signer address (ascending)
|
|
31
|
+
for (uint256 i = 0; i < signatures.length; i++) {
|
|
32
|
+
for (uint256 j = i + 1; j < signatures.length; j++) {
|
|
33
|
+
if (signers[i] > signers[j]) {
|
|
34
|
+
// Swap signers
|
|
35
|
+
address tempSigner = signers[i];
|
|
36
|
+
signers[i] = signers[j];
|
|
37
|
+
signers[j] = tempSigner;
|
|
38
|
+
|
|
39
|
+
// Swap signatures
|
|
40
|
+
bytes memory tempSig = signatures[i];
|
|
41
|
+
signatures[i] = signatures[j];
|
|
42
|
+
signatures[j] = tempSig;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return signatures;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Helper functions to expose internal/external functions for testing
|
|
51
|
+
function exposedAddSigner(address signerAddress) public {
|
|
52
|
+
addSigner(signerAddress);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function exposedRemoveSigner(address signerAddress) public {
|
|
56
|
+
this.removeSigner(signerAddress);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function exposedSetThreshold(uint256 newThreshold) public {
|
|
60
|
+
this.setThreshold(newThreshold);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ============ Tests for Adding Signers ============
|
|
64
|
+
|
|
65
|
+
function testAddSingleSigner() public {
|
|
66
|
+
exposedAddSigner(alice);
|
|
67
|
+
assertTrue(isSigner(alice));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function testAddMultipleSigners() public {
|
|
71
|
+
exposedAddSigner(alice);
|
|
72
|
+
exposedAddSigner(bob);
|
|
73
|
+
exposedAddSigner(carol);
|
|
74
|
+
|
|
75
|
+
assertTrue(isSigner(alice));
|
|
76
|
+
assertTrue(isSigner(bob));
|
|
77
|
+
assertTrue(isSigner(carol));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function testRevertWhenAddingDuplicateSigner() public {
|
|
81
|
+
exposedAddSigner(alice);
|
|
82
|
+
|
|
83
|
+
// Test that adding the same signer again reverts
|
|
84
|
+
// Using try-catch since the revert happens in an internal function
|
|
85
|
+
try this.exposedAddSigner(alice) {
|
|
86
|
+
fail("Expected revert when adding duplicate signer");
|
|
87
|
+
} catch (bytes memory reason) {
|
|
88
|
+
// Verify it's the correct error
|
|
89
|
+
bytes4 expectedSelector = SignatureVerifier.SignerAlreadyAdded.selector;
|
|
90
|
+
bytes4 receivedSelector = bytes4(reason);
|
|
91
|
+
assertEq(receivedSelector, expectedSelector, "Wrong error selector");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ============ Tests for Setting Threshold ============
|
|
96
|
+
|
|
97
|
+
function testSetThreshold() public {
|
|
98
|
+
exposedAddSigner(alice);
|
|
99
|
+
exposedAddSigner(bob);
|
|
100
|
+
exposedAddSigner(carol);
|
|
101
|
+
|
|
102
|
+
exposedSetThreshold(2);
|
|
103
|
+
assertEq(getThreshold(), 2);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function testRevertWhenThresholdExceedsSigners() public {
|
|
107
|
+
exposedAddSigner(alice);
|
|
108
|
+
exposedAddSigner(bob);
|
|
109
|
+
|
|
110
|
+
vm.expectRevert(abi.encodeWithSelector(SignatureVerifier.InvalidThreshold.selector, 3, 2));
|
|
111
|
+
exposedSetThreshold(3);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function testRevertWhenThresholdIsZero() public {
|
|
115
|
+
exposedAddSigner(alice);
|
|
116
|
+
|
|
117
|
+
vm.expectRevert(abi.encodeWithSelector(SignatureVerifier.InvalidThreshold.selector, 0, 1));
|
|
118
|
+
exposedSetThreshold(0);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function testThresholdChangedEvent() public {
|
|
122
|
+
exposedAddSigner(alice);
|
|
123
|
+
exposedAddSigner(bob);
|
|
124
|
+
exposedSetThreshold(1);
|
|
125
|
+
|
|
126
|
+
vm.expectEmit(true, true, true, true);
|
|
127
|
+
emit ThresholdChanged(1, 2);
|
|
128
|
+
exposedSetThreshold(2);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============ Tests for Signature Validation ============
|
|
132
|
+
|
|
133
|
+
function testValidSignatureSingleSignerThresholdOne() public {
|
|
134
|
+
exposedAddSigner(alice);
|
|
135
|
+
exposedSetThreshold(1);
|
|
136
|
+
|
|
137
|
+
bytes32 digest = keccak256("test message");
|
|
138
|
+
bytes[] memory signatures = new bytes[](1);
|
|
139
|
+
signatures[0] = getSignatureForDigest(digest, alicePrivKey);
|
|
140
|
+
|
|
141
|
+
assertTrue(isValidSignature(digest, signatures));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function testValidSignatureMultipleSignersThresholdMet() public {
|
|
145
|
+
exposedAddSigner(alice);
|
|
146
|
+
exposedAddSigner(bob);
|
|
147
|
+
exposedAddSigner(carol);
|
|
148
|
+
exposedSetThreshold(2);
|
|
149
|
+
|
|
150
|
+
bytes32 digest = keccak256("test message");
|
|
151
|
+
uint256[] memory privKeys = new uint256[](2);
|
|
152
|
+
privKeys[0] = alicePrivKey;
|
|
153
|
+
privKeys[1] = bobPrivKey;
|
|
154
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
155
|
+
|
|
156
|
+
assertTrue(isValidSignature(digest, signatures));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function testValidSignatureMoreSignaturesThanThreshold() public {
|
|
160
|
+
exposedAddSigner(alice);
|
|
161
|
+
exposedAddSigner(bob);
|
|
162
|
+
exposedAddSigner(carol);
|
|
163
|
+
exposedSetThreshold(2);
|
|
164
|
+
|
|
165
|
+
bytes32 digest = keccak256("test message");
|
|
166
|
+
uint256[] memory privKeys = new uint256[](3);
|
|
167
|
+
privKeys[0] = alicePrivKey;
|
|
168
|
+
privKeys[1] = bobPrivKey;
|
|
169
|
+
privKeys[2] = carolPrivKey;
|
|
170
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
171
|
+
|
|
172
|
+
assertTrue(isValidSignature(digest, signatures));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function testInvalidSignatureThresholdNotMet() public {
|
|
176
|
+
exposedAddSigner(alice);
|
|
177
|
+
exposedAddSigner(bob);
|
|
178
|
+
exposedAddSigner(carol);
|
|
179
|
+
exposedSetThreshold(3);
|
|
180
|
+
|
|
181
|
+
bytes32 digest = keccak256("test message");
|
|
182
|
+
uint256[] memory privKeys = new uint256[](2);
|
|
183
|
+
privKeys[0] = alicePrivKey;
|
|
184
|
+
privKeys[1] = bobPrivKey;
|
|
185
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
186
|
+
|
|
187
|
+
assertFalse(isValidSignature(digest, signatures));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function testInvalidSignatureThresholdZero() public {
|
|
191
|
+
exposedAddSigner(alice);
|
|
192
|
+
// Don't set threshold, it defaults to 0
|
|
193
|
+
|
|
194
|
+
bytes32 digest = keccak256("test message");
|
|
195
|
+
bytes[] memory signatures = new bytes[](1);
|
|
196
|
+
signatures[0] = getSignatureForDigest(digest, alicePrivKey);
|
|
197
|
+
|
|
198
|
+
assertFalse(isValidSignature(digest, signatures));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function testInvalidSignatureNonSigner() public {
|
|
202
|
+
exposedAddSigner(alice);
|
|
203
|
+
exposedAddSigner(bob);
|
|
204
|
+
exposedSetThreshold(2);
|
|
205
|
+
|
|
206
|
+
bytes32 digest = keccak256("test message");
|
|
207
|
+
uint256[] memory privKeys = new uint256[](2);
|
|
208
|
+
privKeys[0] = alicePrivKey;
|
|
209
|
+
privKeys[1] = davePrivKey; // Dave is not a signer
|
|
210
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
211
|
+
|
|
212
|
+
assertFalse(isValidSignature(digest, signatures));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function testInvalidSignatureDuplicateSigner() public {
|
|
216
|
+
exposedAddSigner(alice);
|
|
217
|
+
exposedAddSigner(bob);
|
|
218
|
+
exposedSetThreshold(2);
|
|
219
|
+
|
|
220
|
+
bytes32 digest = keccak256("test message");
|
|
221
|
+
uint256[] memory privKeys = new uint256[](2);
|
|
222
|
+
privKeys[0] = alicePrivKey;
|
|
223
|
+
privKeys[1] = alicePrivKey; // Duplicate
|
|
224
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
225
|
+
|
|
226
|
+
// Should revert because duplicate signers violate the ascending order requirement
|
|
227
|
+
// Using try-catch to handle the revert from a view function
|
|
228
|
+
try this.isValidSignature(digest, signatures) returns (bool result) {
|
|
229
|
+
assertFalse(result, "Expected signature validation to fail with duplicates");
|
|
230
|
+
} catch (bytes memory reason) {
|
|
231
|
+
// Verify it's the correct error
|
|
232
|
+
bytes4 expectedSelector = SignatureVerifier.SignersNotInAscendingOrder.selector;
|
|
233
|
+
bytes4 receivedSelector = bytes4(reason);
|
|
234
|
+
assertEq(receivedSelector, expectedSelector, "Wrong error selector");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function testRevertWhenSignaturesNotInAscendingOrder() public {
|
|
239
|
+
exposedAddSigner(alice);
|
|
240
|
+
exposedAddSigner(bob);
|
|
241
|
+
exposedAddSigner(carol);
|
|
242
|
+
exposedSetThreshold(2);
|
|
243
|
+
|
|
244
|
+
bytes32 digest = keccak256("test message");
|
|
245
|
+
|
|
246
|
+
// Create signatures in wrong order (descending instead of ascending)
|
|
247
|
+
bytes[] memory signatures = new bytes[](2);
|
|
248
|
+
address aliceAddr = vm.addr(alicePrivKey);
|
|
249
|
+
address bobAddr = vm.addr(bobPrivKey);
|
|
250
|
+
|
|
251
|
+
// Intentionally put them in wrong order based on addresses
|
|
252
|
+
if (aliceAddr < bobAddr) {
|
|
253
|
+
// Bob's signature first (wrong order)
|
|
254
|
+
signatures[0] = getSignatureForDigest(digest, bobPrivKey);
|
|
255
|
+
signatures[1] = getSignatureForDigest(digest, alicePrivKey);
|
|
256
|
+
} else {
|
|
257
|
+
// Alice's signature first (wrong order)
|
|
258
|
+
signatures[0] = getSignatureForDigest(digest, alicePrivKey);
|
|
259
|
+
signatures[1] = getSignatureForDigest(digest, bobPrivKey);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Should revert with SignersNotInAscendingOrder
|
|
263
|
+
try this.isValidSignature(digest, signatures) returns (bool result) {
|
|
264
|
+
fail("Expected revert for signatures not in ascending order");
|
|
265
|
+
} catch (bytes memory reason) {
|
|
266
|
+
bytes4 expectedSelector = SignatureVerifier.SignersNotInAscendingOrder.selector;
|
|
267
|
+
bytes4 receivedSelector = bytes4(reason);
|
|
268
|
+
assertEq(receivedSelector, expectedSelector, "Wrong error selector");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function testRevertWhenThreeSignaturesOutOfOrder() public {
|
|
273
|
+
exposedAddSigner(alice);
|
|
274
|
+
exposedAddSigner(bob);
|
|
275
|
+
exposedAddSigner(carol);
|
|
276
|
+
exposedSetThreshold(3);
|
|
277
|
+
|
|
278
|
+
bytes32 digest = keccak256("test message");
|
|
279
|
+
|
|
280
|
+
// Get all three signatures
|
|
281
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
282
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
283
|
+
bytes memory carolSig = getSignatureForDigest(digest, carolPrivKey);
|
|
284
|
+
|
|
285
|
+
// Recover addresses to determine correct order
|
|
286
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
287
|
+
address bobAddr = digest.recover(bobSig);
|
|
288
|
+
address carolAddr = digest.recover(carolSig);
|
|
289
|
+
|
|
290
|
+
// Create an array with middle and last swapped (intentionally wrong order)
|
|
291
|
+
bytes[] memory signatures = new bytes[](3);
|
|
292
|
+
|
|
293
|
+
// Sort addresses to find middle one
|
|
294
|
+
address[] memory addrs = new address[](3);
|
|
295
|
+
addrs[0] = aliceAddr;
|
|
296
|
+
addrs[1] = bobAddr;
|
|
297
|
+
addrs[2] = carolAddr;
|
|
298
|
+
|
|
299
|
+
// Simple sort
|
|
300
|
+
for (uint256 i = 0; i < 3; i++) {
|
|
301
|
+
for (uint256 j = i + 1; j < 3; j++) {
|
|
302
|
+
if (addrs[i] > addrs[j]) {
|
|
303
|
+
address temp = addrs[i];
|
|
304
|
+
addrs[i] = addrs[j];
|
|
305
|
+
addrs[j] = temp;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Put in wrong order: smallest, largest, middle
|
|
311
|
+
if (addrs[0] == aliceAddr) {
|
|
312
|
+
signatures[0] = aliceSig;
|
|
313
|
+
if (addrs[1] == bobAddr) {
|
|
314
|
+
signatures[1] = carolSig; // Wrong: should be bob
|
|
315
|
+
signatures[2] = bobSig;
|
|
316
|
+
} else {
|
|
317
|
+
signatures[1] = bobSig; // Wrong: should be carol
|
|
318
|
+
signatures[2] = carolSig;
|
|
319
|
+
}
|
|
320
|
+
} else if (addrs[0] == bobAddr) {
|
|
321
|
+
signatures[0] = bobSig;
|
|
322
|
+
if (addrs[1] == aliceAddr) {
|
|
323
|
+
signatures[1] = carolSig; // Wrong: should be alice
|
|
324
|
+
signatures[2] = aliceSig;
|
|
325
|
+
} else {
|
|
326
|
+
signatures[1] = aliceSig; // Wrong: should be carol
|
|
327
|
+
signatures[2] = carolSig;
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
signatures[0] = carolSig;
|
|
331
|
+
if (addrs[1] == aliceAddr) {
|
|
332
|
+
signatures[1] = bobSig; // Wrong: should be alice
|
|
333
|
+
signatures[2] = aliceSig;
|
|
334
|
+
} else {
|
|
335
|
+
signatures[1] = aliceSig; // Wrong: should be bob
|
|
336
|
+
signatures[2] = bobSig;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Should revert with SignersNotInAscendingOrder
|
|
341
|
+
try this.isValidSignature(digest, signatures) returns (bool result) {
|
|
342
|
+
fail("Expected revert for signatures not in ascending order");
|
|
343
|
+
} catch (bytes memory reason) {
|
|
344
|
+
bytes4 expectedSelector = SignatureVerifier.SignersNotInAscendingOrder.selector;
|
|
345
|
+
bytes4 receivedSelector = bytes4(reason);
|
|
346
|
+
assertEq(receivedSelector, expectedSelector, "Wrong error selector");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function testSignaturesInCorrectAscendingOrderPasses() public {
|
|
351
|
+
exposedAddSigner(alice);
|
|
352
|
+
exposedAddSigner(bob);
|
|
353
|
+
exposedAddSigner(carol);
|
|
354
|
+
exposedSetThreshold(3);
|
|
355
|
+
|
|
356
|
+
bytes32 digest = keccak256("test message");
|
|
357
|
+
|
|
358
|
+
// Use the helper that sorts signatures correctly
|
|
359
|
+
uint256[] memory privKeys = new uint256[](3);
|
|
360
|
+
privKeys[0] = alicePrivKey;
|
|
361
|
+
privKeys[1] = bobPrivKey;
|
|
362
|
+
privKeys[2] = carolPrivKey;
|
|
363
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
364
|
+
|
|
365
|
+
// Should pass because signatures are in ascending order
|
|
366
|
+
assertTrue(isValidSignature(digest, signatures));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function testInvalidSignaturesIgnoredBeyondThreshold() public {
|
|
370
|
+
exposedAddSigner(alice);
|
|
371
|
+
exposedAddSigner(bob);
|
|
372
|
+
exposedAddSigner(carol);
|
|
373
|
+
exposedSetThreshold(2);
|
|
374
|
+
|
|
375
|
+
bytes32 digest = keccak256("test message");
|
|
376
|
+
|
|
377
|
+
// Create 3 signatures: Alice, Bob (both valid), and Dave (invalid)
|
|
378
|
+
// After sorting, Dave's signature will be placed according to his address
|
|
379
|
+
// As long as the first 2 signatures checked are from valid signers, it should pass
|
|
380
|
+
bytes[] memory signatures = new bytes[](3);
|
|
381
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
382
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
383
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey);
|
|
384
|
+
|
|
385
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
386
|
+
address bobAddr = digest.recover(bobSig);
|
|
387
|
+
address daveAddr = digest.recover(daveSig);
|
|
388
|
+
|
|
389
|
+
// Sort them manually so Dave's signature is at the end (position 2, beyond threshold)
|
|
390
|
+
address[] memory addrs = new address[](3);
|
|
391
|
+
bytes[] memory sigs = new bytes[](3);
|
|
392
|
+
addrs[0] = aliceAddr;
|
|
393
|
+
addrs[1] = bobAddr;
|
|
394
|
+
addrs[2] = daveAddr;
|
|
395
|
+
sigs[0] = aliceSig;
|
|
396
|
+
sigs[1] = bobSig;
|
|
397
|
+
sigs[2] = daveSig;
|
|
398
|
+
|
|
399
|
+
// Bubble sort
|
|
400
|
+
for (uint256 i = 0; i < 3; i++) {
|
|
401
|
+
for (uint256 j = i + 1; j < 3; j++) {
|
|
402
|
+
if (addrs[i] > addrs[j]) {
|
|
403
|
+
address tempAddr = addrs[i];
|
|
404
|
+
addrs[i] = addrs[j];
|
|
405
|
+
addrs[j] = tempAddr;
|
|
406
|
+
|
|
407
|
+
bytes memory tempSig = sigs[i];
|
|
408
|
+
sigs[i] = sigs[j];
|
|
409
|
+
sigs[j] = tempSig;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// If Dave's address is in the first 2 positions, this test won't work as intended
|
|
415
|
+
// So we skip the test if Dave ends up in the first 2 positions
|
|
416
|
+
bool daveInFirstTwo = (addrs[0] == daveAddr || addrs[1] == daveAddr);
|
|
417
|
+
|
|
418
|
+
if (!daveInFirstTwo) {
|
|
419
|
+
// Dave is in position 2 (beyond threshold), so validation should pass
|
|
420
|
+
assertTrue(isValidSignature(digest, sigs));
|
|
421
|
+
} else {
|
|
422
|
+
// Dave is in first 2 positions, so validation should fail
|
|
423
|
+
assertFalse(isValidSignature(digest, sigs));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function testInvalidSignatureWithInvalidSignerInFirstThreshold() public {
|
|
428
|
+
exposedAddSigner(alice);
|
|
429
|
+
exposedAddSigner(bob);
|
|
430
|
+
exposedAddSigner(carol);
|
|
431
|
+
exposedSetThreshold(2);
|
|
432
|
+
|
|
433
|
+
bytes32 digest = keccak256("test message");
|
|
434
|
+
|
|
435
|
+
// Create signatures where an invalid signer (Dave) will be in the first threshold
|
|
436
|
+
bytes[] memory signatures = new bytes[](3);
|
|
437
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
438
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
439
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey);
|
|
440
|
+
|
|
441
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
442
|
+
address bobAddr = digest.recover(bobSig);
|
|
443
|
+
address daveAddr = digest.recover(daveSig);
|
|
444
|
+
|
|
445
|
+
// Sort them
|
|
446
|
+
address[] memory addrs = new address[](3);
|
|
447
|
+
bytes[] memory sigs = new bytes[](3);
|
|
448
|
+
addrs[0] = aliceAddr;
|
|
449
|
+
addrs[1] = bobAddr;
|
|
450
|
+
addrs[2] = daveAddr;
|
|
451
|
+
sigs[0] = aliceSig;
|
|
452
|
+
sigs[1] = bobSig;
|
|
453
|
+
sigs[2] = daveSig;
|
|
454
|
+
|
|
455
|
+
for (uint256 i = 0; i < 3; i++) {
|
|
456
|
+
for (uint256 j = i + 1; j < 3; j++) {
|
|
457
|
+
if (addrs[i] > addrs[j]) {
|
|
458
|
+
address tempAddr = addrs[i];
|
|
459
|
+
addrs[i] = addrs[j];
|
|
460
|
+
addrs[j] = tempAddr;
|
|
461
|
+
|
|
462
|
+
bytes memory tempSig = sigs[i];
|
|
463
|
+
sigs[i] = sigs[j];
|
|
464
|
+
sigs[j] = tempSig;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// If Dave is in the first 2 positions, validation should fail
|
|
470
|
+
bool daveInFirstTwo = (addrs[0] == daveAddr || addrs[1] == daveAddr);
|
|
471
|
+
|
|
472
|
+
if (daveInFirstTwo) {
|
|
473
|
+
assertFalse(isValidSignature(digest, sigs));
|
|
474
|
+
} else {
|
|
475
|
+
// If Dave is beyond threshold, it should pass
|
|
476
|
+
assertTrue(isValidSignature(digest, sigs));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ============ Tests for Removing Signers ============
|
|
481
|
+
|
|
482
|
+
function testRemoveSigner() public {
|
|
483
|
+
exposedAddSigner(alice);
|
|
484
|
+
exposedAddSigner(bob);
|
|
485
|
+
exposedAddSigner(carol);
|
|
486
|
+
exposedSetThreshold(2);
|
|
487
|
+
|
|
488
|
+
exposedRemoveSigner(alice);
|
|
489
|
+
assertFalse(isSigner(alice));
|
|
490
|
+
assertTrue(isSigner(bob));
|
|
491
|
+
assertTrue(isSigner(carol));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function testRevertWhenRemovingNonExistentSigner() public {
|
|
495
|
+
exposedAddSigner(alice);
|
|
496
|
+
|
|
497
|
+
vm.expectRevert(abi.encodeWithSelector(SignatureVerifier.SignerNotFound.selector, bob));
|
|
498
|
+
exposedRemoveSigner(bob);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function testRevertWhenRemovingSignerBelowThreshold() public {
|
|
502
|
+
exposedAddSigner(alice);
|
|
503
|
+
exposedAddSigner(bob);
|
|
504
|
+
exposedSetThreshold(2);
|
|
505
|
+
|
|
506
|
+
vm.expectRevert(abi.encodeWithSelector(SignatureVerifier.InvalidThreshold.selector, 2, 1));
|
|
507
|
+
exposedRemoveSigner(alice);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function testRemoveSignerThenValidateSignatures() public {
|
|
511
|
+
exposedAddSigner(alice);
|
|
512
|
+
exposedAddSigner(bob);
|
|
513
|
+
exposedAddSigner(carol);
|
|
514
|
+
exposedSetThreshold(2);
|
|
515
|
+
|
|
516
|
+
bytes32 digest = keccak256("test message");
|
|
517
|
+
|
|
518
|
+
// Before removal - Alice's signature should work
|
|
519
|
+
uint256[] memory privKeysBefore = new uint256[](2);
|
|
520
|
+
privKeysBefore[0] = alicePrivKey;
|
|
521
|
+
privKeysBefore[1] = bobPrivKey;
|
|
522
|
+
bytes[] memory sigsBefore = getSortedSignatures(digest, privKeysBefore);
|
|
523
|
+
assertTrue(isValidSignature(digest, sigsBefore));
|
|
524
|
+
|
|
525
|
+
// Remove Alice
|
|
526
|
+
exposedRemoveSigner(alice);
|
|
527
|
+
|
|
528
|
+
// After removal - Alice's signature should not work
|
|
529
|
+
uint256[] memory privKeysAfter = new uint256[](2);
|
|
530
|
+
privKeysAfter[0] = alicePrivKey;
|
|
531
|
+
privKeysAfter[1] = bobPrivKey;
|
|
532
|
+
bytes[] memory sigsAfter = getSortedSignatures(digest, privKeysAfter);
|
|
533
|
+
assertFalse(isValidSignature(digest, sigsAfter));
|
|
534
|
+
|
|
535
|
+
// But Bob and Carol should still work
|
|
536
|
+
uint256[] memory privKeysValid = new uint256[](2);
|
|
537
|
+
privKeysValid[0] = bobPrivKey;
|
|
538
|
+
privKeysValid[1] = carolPrivKey;
|
|
539
|
+
bytes[] memory sigsValid = getSortedSignatures(digest, privKeysValid);
|
|
540
|
+
assertTrue(isValidSignature(digest, sigsValid));
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// ============ Tests for Complex Scenarios ============
|
|
544
|
+
|
|
545
|
+
function testFullWorkflowFiveSigners() public {
|
|
546
|
+
// Add all five signers
|
|
547
|
+
exposedAddSigner(alice);
|
|
548
|
+
exposedAddSigner(bob);
|
|
549
|
+
exposedAddSigner(carol);
|
|
550
|
+
exposedAddSigner(dave);
|
|
551
|
+
exposedAddSigner(eve);
|
|
552
|
+
|
|
553
|
+
// Set threshold to 3
|
|
554
|
+
exposedSetThreshold(3);
|
|
555
|
+
|
|
556
|
+
bytes32 digest = keccak256("important message");
|
|
557
|
+
|
|
558
|
+
// Test with exactly 3 signatures
|
|
559
|
+
uint256[] memory privKeys3 = new uint256[](3);
|
|
560
|
+
privKeys3[0] = alicePrivKey;
|
|
561
|
+
privKeys3[1] = bobPrivKey;
|
|
562
|
+
privKeys3[2] = carolPrivKey;
|
|
563
|
+
bytes[] memory sigs3 = getSortedSignatures(digest, privKeys3);
|
|
564
|
+
assertTrue(isValidSignature(digest, sigs3));
|
|
565
|
+
|
|
566
|
+
// Test with 2 signatures (should fail)
|
|
567
|
+
uint256[] memory privKeys2 = new uint256[](2);
|
|
568
|
+
privKeys2[0] = alicePrivKey;
|
|
569
|
+
privKeys2[1] = bobPrivKey;
|
|
570
|
+
bytes[] memory sigs2 = getSortedSignatures(digest, privKeys2);
|
|
571
|
+
assertFalse(isValidSignature(digest, sigs2));
|
|
572
|
+
|
|
573
|
+
// Test with all 5 signatures
|
|
574
|
+
uint256[] memory privKeys5 = new uint256[](5);
|
|
575
|
+
privKeys5[0] = alicePrivKey;
|
|
576
|
+
privKeys5[1] = bobPrivKey;
|
|
577
|
+
privKeys5[2] = carolPrivKey;
|
|
578
|
+
privKeys5[3] = davePrivKey;
|
|
579
|
+
privKeys5[4] = evePrivKey;
|
|
580
|
+
bytes[] memory sigs5 = getSortedSignatures(digest, privKeys5);
|
|
581
|
+
assertTrue(isValidSignature(digest, sigs5));
|
|
582
|
+
|
|
583
|
+
// Update threshold to 4
|
|
584
|
+
exposedSetThreshold(4);
|
|
585
|
+
|
|
586
|
+
// Now 3 signatures should fail
|
|
587
|
+
assertFalse(isValidSignature(digest, sigs3));
|
|
588
|
+
|
|
589
|
+
// But 5 should still work
|
|
590
|
+
assertTrue(isValidSignature(digest, sigs5));
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function testOnlyOwnerCanRemoveSigner() public {
|
|
594
|
+
exposedAddSigner(alice);
|
|
595
|
+
exposedAddSigner(bob);
|
|
596
|
+
exposedSetThreshold(1);
|
|
597
|
+
|
|
598
|
+
vm.prank(alice);
|
|
599
|
+
vm.expectRevert();
|
|
600
|
+
exposedRemoveSigner(bob);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function testOnlyOwnerCanSetThreshold() public {
|
|
604
|
+
exposedAddSigner(alice);
|
|
605
|
+
exposedAddSigner(bob);
|
|
606
|
+
|
|
607
|
+
vm.prank(alice);
|
|
608
|
+
vm.expectRevert();
|
|
609
|
+
exposedSetThreshold(1);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// ============ Tests for Mixed Valid/Invalid Signatures ============
|
|
613
|
+
|
|
614
|
+
function testIncorrectSignaturesAllowedWithEnoughCorrectOnes() public {
|
|
615
|
+
// Add 3 valid signers
|
|
616
|
+
exposedAddSigner(alice);
|
|
617
|
+
exposedAddSigner(bob);
|
|
618
|
+
exposedAddSigner(carol);
|
|
619
|
+
exposedSetThreshold(2);
|
|
620
|
+
|
|
621
|
+
bytes32 digest = keccak256("test message");
|
|
622
|
+
|
|
623
|
+
// Create a mix: Alice (valid), Dave (invalid), Bob (valid)
|
|
624
|
+
// We need to sort them by signer address
|
|
625
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
626
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey); // Dave is not a signer
|
|
627
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
628
|
+
|
|
629
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
630
|
+
address daveAddr = digest.recover(daveSig);
|
|
631
|
+
address bobAddr = digest.recover(bobSig);
|
|
632
|
+
|
|
633
|
+
// Sort the signatures by address
|
|
634
|
+
address[] memory addrs = new address[](3);
|
|
635
|
+
bytes[] memory sigs = new bytes[](3);
|
|
636
|
+
addrs[0] = aliceAddr;
|
|
637
|
+
addrs[1] = daveAddr;
|
|
638
|
+
addrs[2] = bobAddr;
|
|
639
|
+
sigs[0] = aliceSig;
|
|
640
|
+
sigs[1] = daveSig;
|
|
641
|
+
sigs[2] = bobSig;
|
|
642
|
+
|
|
643
|
+
// Bubble sort
|
|
644
|
+
for (uint256 i = 0; i < 3; i++) {
|
|
645
|
+
for (uint256 j = i + 1; j < 3; j++) {
|
|
646
|
+
if (addrs[i] > addrs[j]) {
|
|
647
|
+
address tempAddr = addrs[i];
|
|
648
|
+
addrs[i] = addrs[j];
|
|
649
|
+
addrs[j] = tempAddr;
|
|
650
|
+
|
|
651
|
+
bytes memory tempSig = sigs[i];
|
|
652
|
+
sigs[i] = sigs[j];
|
|
653
|
+
sigs[j] = tempSig;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Should pass because we have Alice and Bob (2 valid signatures >= threshold of 2)
|
|
659
|
+
// Dave's invalid signature is simply ignored in the count
|
|
660
|
+
assertTrue(isValidSignature(digest, sigs));
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function testMultipleIncorrectSignaturesWithEnoughCorrectOnes() public {
|
|
664
|
+
// Add 3 valid signers
|
|
665
|
+
exposedAddSigner(alice);
|
|
666
|
+
exposedAddSigner(bob);
|
|
667
|
+
exposedAddSigner(carol);
|
|
668
|
+
exposedSetThreshold(2);
|
|
669
|
+
|
|
670
|
+
bytes32 digest = keccak256("test message");
|
|
671
|
+
|
|
672
|
+
// Create a mix: Alice (valid), Dave (invalid), Bob (valid), Eve (invalid)
|
|
673
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
674
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey); // Invalid
|
|
675
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
676
|
+
bytes memory eveSig = getSignatureForDigest(digest, evePrivKey); // Invalid
|
|
677
|
+
|
|
678
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
679
|
+
address daveAddr = digest.recover(daveSig);
|
|
680
|
+
address bobAddr = digest.recover(bobSig);
|
|
681
|
+
address eveAddr = digest.recover(eveSig);
|
|
682
|
+
|
|
683
|
+
// Sort all signatures
|
|
684
|
+
address[] memory addrs = new address[](4);
|
|
685
|
+
bytes[] memory sigs = new bytes[](4);
|
|
686
|
+
addrs[0] = aliceAddr;
|
|
687
|
+
addrs[1] = daveAddr;
|
|
688
|
+
addrs[2] = bobAddr;
|
|
689
|
+
addrs[3] = eveAddr;
|
|
690
|
+
sigs[0] = aliceSig;
|
|
691
|
+
sigs[1] = daveSig;
|
|
692
|
+
sigs[2] = bobSig;
|
|
693
|
+
sigs[3] = eveSig;
|
|
694
|
+
|
|
695
|
+
// Bubble sort
|
|
696
|
+
for (uint256 i = 0; i < 4; i++) {
|
|
697
|
+
for (uint256 j = i + 1; j < 4; j++) {
|
|
698
|
+
if (addrs[i] > addrs[j]) {
|
|
699
|
+
address tempAddr = addrs[i];
|
|
700
|
+
addrs[i] = addrs[j];
|
|
701
|
+
addrs[j] = tempAddr;
|
|
702
|
+
|
|
703
|
+
bytes memory tempSig = sigs[i];
|
|
704
|
+
sigs[i] = sigs[j];
|
|
705
|
+
sigs[j] = tempSig;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Should pass: we have Alice and Bob (2 valid) even with Dave and Eve (2 invalid)
|
|
711
|
+
assertTrue(isValidSignature(digest, sigs));
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function testMoreSignaturesThanThresholdIsAllowed() public {
|
|
715
|
+
exposedAddSigner(alice);
|
|
716
|
+
exposedAddSigner(bob);
|
|
717
|
+
exposedAddSigner(carol);
|
|
718
|
+
exposedSetThreshold(1);
|
|
719
|
+
|
|
720
|
+
bytes32 digest = keccak256("test message");
|
|
721
|
+
|
|
722
|
+
// Provide all 3 signatures even though threshold is only 1
|
|
723
|
+
uint256[] memory privKeys = new uint256[](3);
|
|
724
|
+
privKeys[0] = alicePrivKey;
|
|
725
|
+
privKeys[1] = bobPrivKey;
|
|
726
|
+
privKeys[2] = carolPrivKey;
|
|
727
|
+
bytes[] memory signatures = getSortedSignatures(digest, privKeys);
|
|
728
|
+
|
|
729
|
+
// Should pass because we have way more than threshold
|
|
730
|
+
assertTrue(isValidSignature(digest, signatures));
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function testExcessSignaturesWithMixedValidityPassesWithEnoughValid() public {
|
|
734
|
+
exposedAddSigner(alice);
|
|
735
|
+
exposedAddSigner(bob);
|
|
736
|
+
exposedSetThreshold(2);
|
|
737
|
+
|
|
738
|
+
bytes32 digest = keccak256("test message");
|
|
739
|
+
|
|
740
|
+
// Provide 5 signatures: Alice (valid), Bob (valid), Carol (invalid), Dave (invalid), Eve (invalid)
|
|
741
|
+
// Threshold is 2, so Alice + Bob should be enough
|
|
742
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
743
|
+
bytes memory bobSig = getSignatureForDigest(digest, bobPrivKey);
|
|
744
|
+
bytes memory carolSig = getSignatureForDigest(digest, carolPrivKey); // Invalid - not a signer
|
|
745
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey); // Invalid
|
|
746
|
+
bytes memory eveSig = getSignatureForDigest(digest, evePrivKey); // Invalid
|
|
747
|
+
|
|
748
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
749
|
+
address bobAddr = digest.recover(bobSig);
|
|
750
|
+
address carolAddr = digest.recover(carolSig);
|
|
751
|
+
address daveAddr = digest.recover(daveSig);
|
|
752
|
+
address eveAddr = digest.recover(eveSig);
|
|
753
|
+
|
|
754
|
+
// Sort all signatures
|
|
755
|
+
address[] memory addrs = new address[](5);
|
|
756
|
+
bytes[] memory sigs = new bytes[](5);
|
|
757
|
+
addrs[0] = aliceAddr;
|
|
758
|
+
addrs[1] = bobAddr;
|
|
759
|
+
addrs[2] = carolAddr;
|
|
760
|
+
addrs[3] = daveAddr;
|
|
761
|
+
addrs[4] = eveAddr;
|
|
762
|
+
sigs[0] = aliceSig;
|
|
763
|
+
sigs[1] = bobSig;
|
|
764
|
+
sigs[2] = carolSig;
|
|
765
|
+
sigs[3] = daveSig;
|
|
766
|
+
sigs[4] = eveSig;
|
|
767
|
+
|
|
768
|
+
// Bubble sort
|
|
769
|
+
for (uint256 i = 0; i < 5; i++) {
|
|
770
|
+
for (uint256 j = i + 1; j < 5; j++) {
|
|
771
|
+
if (addrs[i] > addrs[j]) {
|
|
772
|
+
address tempAddr = addrs[i];
|
|
773
|
+
addrs[i] = addrs[j];
|
|
774
|
+
addrs[j] = tempAddr;
|
|
775
|
+
|
|
776
|
+
bytes memory tempSig = sigs[i];
|
|
777
|
+
sigs[i] = sigs[j];
|
|
778
|
+
sigs[j] = tempSig;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Should pass: Alice and Bob are valid (meets threshold of 2)
|
|
784
|
+
// Extra signatures (3 invalid ones) don't cause failure
|
|
785
|
+
assertTrue(isValidSignature(digest, sigs));
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function testInsufficientValidSignaturesFailsDespiteExtraInvalidOnes() public {
|
|
789
|
+
exposedAddSigner(alice);
|
|
790
|
+
exposedAddSigner(bob);
|
|
791
|
+
exposedSetThreshold(2);
|
|
792
|
+
|
|
793
|
+
bytes32 digest = keccak256("test message");
|
|
794
|
+
|
|
795
|
+
// Provide 5 signatures but only 1 valid: Alice (valid), Carol (invalid), Dave (invalid), Eve (invalid)
|
|
796
|
+
bytes memory aliceSig = getSignatureForDigest(digest, alicePrivKey);
|
|
797
|
+
bytes memory carolSig = getSignatureForDigest(digest, carolPrivKey); // Invalid
|
|
798
|
+
bytes memory daveSig = getSignatureForDigest(digest, davePrivKey); // Invalid
|
|
799
|
+
bytes memory eveSig = getSignatureForDigest(digest, evePrivKey); // Invalid
|
|
800
|
+
|
|
801
|
+
address aliceAddr = digest.recover(aliceSig);
|
|
802
|
+
address carolAddr = digest.recover(carolSig);
|
|
803
|
+
address daveAddr = digest.recover(daveSig);
|
|
804
|
+
address eveAddr = digest.recover(eveSig);
|
|
805
|
+
|
|
806
|
+
// Sort signatures
|
|
807
|
+
address[] memory addrs = new address[](4);
|
|
808
|
+
bytes[] memory sigs = new bytes[](4);
|
|
809
|
+
addrs[0] = aliceAddr;
|
|
810
|
+
addrs[1] = carolAddr;
|
|
811
|
+
addrs[2] = daveAddr;
|
|
812
|
+
addrs[3] = eveAddr;
|
|
813
|
+
sigs[0] = aliceSig;
|
|
814
|
+
sigs[1] = carolSig;
|
|
815
|
+
sigs[2] = daveSig;
|
|
816
|
+
sigs[3] = eveSig;
|
|
817
|
+
|
|
818
|
+
// Bubble sort
|
|
819
|
+
for (uint256 i = 0; i < 4; i++) {
|
|
820
|
+
for (uint256 j = i + 1; j < 4; j++) {
|
|
821
|
+
if (addrs[i] > addrs[j]) {
|
|
822
|
+
address tempAddr = addrs[i];
|
|
823
|
+
addrs[i] = addrs[j];
|
|
824
|
+
addrs[j] = tempAddr;
|
|
825
|
+
|
|
826
|
+
bytes memory tempSig = sigs[i];
|
|
827
|
+
sigs[i] = sigs[j];
|
|
828
|
+
sigs[j] = tempSig;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Should fail: only 1 valid signature (Alice), but threshold is 2
|
|
834
|
+
// Having 4 total signatures doesn't help if only 1 is valid
|
|
835
|
+
assertFalse(isValidSignature(digest, sigs));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
}
|