2023-09-06 08:24:00 -07:00
|
|
|
// test/Messages.sol
|
|
|
|
// SPDX-License-Identifier: Apache 2
|
|
|
|
|
|
|
|
pragma solidity ^0.8.0;
|
|
|
|
|
|
|
|
import "../contracts/Messages.sol";
|
|
|
|
import "../contracts/Setters.sol";
|
|
|
|
import "../contracts/Structs.sol";
|
|
|
|
import "forge-test/rv-helpers/TestUtils.sol";
|
|
|
|
|
|
|
|
contract TestMessagesRV is TestUtils {
|
|
|
|
using BytesLib for bytes;
|
|
|
|
|
|
|
|
Messages messages;
|
|
|
|
|
|
|
|
struct GuardianSetParams {
|
|
|
|
uint256[] privateKeys;
|
|
|
|
uint8 guardianCount;
|
|
|
|
uint32 expirationTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setUp() public {
|
|
|
|
messages = new Messages();
|
|
|
|
}
|
|
|
|
|
|
|
|
function paramsAreWellFormed(GuardianSetParams memory params)
|
|
|
|
internal
|
|
|
|
pure
|
|
|
|
returns (bool)
|
|
|
|
{
|
|
|
|
return params.guardianCount <= 19 &&
|
|
|
|
params.guardianCount <= params.privateKeys.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateGuardianSet(GuardianSetParams memory params)
|
2023-09-07 20:26:43 -07:00
|
|
|
internal pure
|
2023-09-06 08:24:00 -07:00
|
|
|
returns (Structs.GuardianSet memory)
|
|
|
|
{
|
|
|
|
for (uint8 i = 0; i < params.guardianCount; ++i)
|
|
|
|
vm.assume(0 < params.privateKeys[i] &&
|
|
|
|
params.privateKeys[i] < SECP256K1_CURVE_ORDER);
|
|
|
|
|
|
|
|
address[] memory guardians = new address[](params.guardianCount);
|
|
|
|
|
|
|
|
for (uint8 i = 0; i < params.guardianCount; ++i) {
|
|
|
|
guardians[i] = vm.addr(params.privateKeys[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Structs.GuardianSet(guardians, params.expirationTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateSignature(
|
|
|
|
uint8 index,
|
|
|
|
uint256 privateKey,
|
|
|
|
address guardian,
|
|
|
|
bytes32 message
|
|
|
|
)
|
|
|
|
internal
|
|
|
|
returns (Structs.Signature memory)
|
|
|
|
{
|
|
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, message);
|
|
|
|
assertEq(ecrecover(message, v, r, s), guardian);
|
|
|
|
|
|
|
|
return Structs.Signature(r, s, v, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateSignatures(
|
|
|
|
uint256[] memory privateKeys,
|
|
|
|
address[] memory guardians,
|
|
|
|
bytes32 message
|
|
|
|
)
|
|
|
|
internal
|
|
|
|
returns (Structs.Signature[] memory)
|
|
|
|
{
|
|
|
|
Structs.Signature[] memory sigs =
|
|
|
|
new Structs.Signature[](guardians.length);
|
|
|
|
|
|
|
|
for (uint8 i = 0; i < guardians.length; ++i) {
|
|
|
|
sigs[i] = generateSignature(
|
|
|
|
i,
|
|
|
|
privateKeys[i],
|
|
|
|
guardians[i],
|
|
|
|
message
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sigs;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isProperSignature(Structs.Signature memory sig, bytes32 message)
|
|
|
|
internal
|
|
|
|
pure
|
|
|
|
returns (bool)
|
|
|
|
{
|
|
|
|
address signer = ecrecover(message, sig.v, sig.r, sig.s);
|
|
|
|
|
|
|
|
return signer != address(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function testCannotVerifySignaturesWithOutOfBoundsSignature(
|
|
|
|
bytes memory encoded,
|
|
|
|
GuardianSetParams memory params,
|
|
|
|
uint8 outOfBoundsGuardian,
|
|
|
|
uint8 outOfBoundsAmount
|
|
|
|
) public {
|
|
|
|
vm.assume(encoded.length > 0);
|
|
|
|
vm.assume(paramsAreWellFormed(params));
|
|
|
|
vm.assume(params.guardianCount > 0);
|
|
|
|
outOfBoundsGuardian = uint8(bound(outOfBoundsGuardian, 0, params.guardianCount - 1));
|
|
|
|
outOfBoundsAmount = uint8(bound(outOfBoundsAmount, 0, MAX_UINT8 - params.guardianCount));
|
|
|
|
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
Structs.GuardianSet memory guardianSet = generateGuardianSet(params);
|
|
|
|
Structs.Signature[] memory sigs = generateSignatures(
|
|
|
|
params.privateKeys,
|
|
|
|
guardianSet.keys,
|
|
|
|
keccak256(encoded)
|
|
|
|
);
|
|
|
|
|
|
|
|
sigs[outOfBoundsGuardian].guardianIndex =
|
|
|
|
params.guardianCount + outOfBoundsAmount;
|
|
|
|
|
|
|
|
vm.expectRevert("guardian index out of bounds");
|
|
|
|
messages.verifySignatures(message, sigs, guardianSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
function testCannotVerifySignaturesWithInvalidSignature1(
|
|
|
|
bytes memory encoded,
|
|
|
|
GuardianSetParams memory params,
|
|
|
|
Structs.Signature memory fakeSignature
|
|
|
|
) public {
|
|
|
|
vm.assume(encoded.length > 0);
|
|
|
|
vm.assume(paramsAreWellFormed(params));
|
|
|
|
vm.assume(fakeSignature.guardianIndex < params.guardianCount);
|
|
|
|
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
Structs.GuardianSet memory guardianSet = generateGuardianSet(params);
|
|
|
|
Structs.Signature[] memory sigs = generateSignatures(
|
|
|
|
params.privateKeys,
|
|
|
|
guardianSet.keys,
|
|
|
|
message
|
|
|
|
);
|
|
|
|
|
|
|
|
sigs[fakeSignature.guardianIndex] = fakeSignature;
|
|
|
|
|
|
|
|
// It is very unlikely that the arbitrary fakeSignature will be the
|
|
|
|
// correct signature for the guardian at that index, so the below
|
|
|
|
// should be the only reasonable outcomes
|
|
|
|
if (isProperSignature(fakeSignature, message)) {
|
|
|
|
(bool valid, string memory reason) =
|
|
|
|
messages.verifySignatures(message, sigs, guardianSet);
|
|
|
|
|
|
|
|
assertEq(valid, false);
|
|
|
|
assertEq(reason, "VM signature invalid");
|
|
|
|
} else {
|
|
|
|
vm.expectRevert("ecrecover failed with signature");
|
|
|
|
messages.verifySignatures(message, sigs, guardianSet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function testCannotVerifySignaturesWithInvalidSignature2(
|
|
|
|
bytes memory encoded,
|
|
|
|
GuardianSetParams memory params,
|
|
|
|
uint8 fakeGuardianIndex,
|
|
|
|
uint256 fakeGuardianPrivateKey
|
|
|
|
) public {
|
|
|
|
vm.assume(encoded.length > 0);
|
|
|
|
vm.assume(paramsAreWellFormed(params));
|
|
|
|
vm.assume(fakeGuardianIndex < params.guardianCount);
|
|
|
|
vm.assume(0 < fakeGuardianPrivateKey &&
|
|
|
|
fakeGuardianPrivateKey < SECP256K1_CURVE_ORDER);
|
|
|
|
vm.assume(fakeGuardianPrivateKey != params.privateKeys[fakeGuardianIndex]);
|
|
|
|
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
Structs.GuardianSet memory guardianSet = generateGuardianSet(params);
|
|
|
|
Structs.Signature[] memory sigs = generateSignatures(
|
|
|
|
params.privateKeys,
|
|
|
|
guardianSet.keys,
|
|
|
|
message
|
|
|
|
);
|
|
|
|
|
|
|
|
address fakeGuardian = vm.addr(fakeGuardianPrivateKey);
|
|
|
|
sigs[fakeGuardianIndex] = generateSignature(
|
|
|
|
fakeGuardianIndex,
|
|
|
|
fakeGuardianPrivateKey,
|
|
|
|
fakeGuardian,
|
|
|
|
message
|
|
|
|
);
|
|
|
|
|
|
|
|
(bool valid, string memory reason) = messages.verifySignatures(message, sigs, guardianSet);
|
|
|
|
assertEq(valid, false);
|
|
|
|
assertEq(reason, "VM signature invalid");
|
|
|
|
}
|
|
|
|
|
|
|
|
function testVerifySignatures(
|
|
|
|
bytes memory encoded,
|
|
|
|
GuardianSetParams memory params
|
|
|
|
) public {
|
|
|
|
vm.assume(encoded.length > 0);
|
|
|
|
vm.assume(paramsAreWellFormed(params));
|
|
|
|
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
Structs.GuardianSet memory guardianSet = generateGuardianSet(params);
|
|
|
|
Structs.Signature[] memory sigs = generateSignatures(
|
|
|
|
params.privateKeys,
|
|
|
|
guardianSet.keys,
|
|
|
|
message
|
|
|
|
);
|
|
|
|
|
|
|
|
(bool valid, string memory reason) = messages.verifySignatures(message, sigs, guardianSet);
|
|
|
|
assertEq(valid, true);
|
|
|
|
assertEq(bytes(reason).length, 0);
|
|
|
|
}
|
|
|
|
}
|