Skip to content

Commit

Permalink
test(evm): create test for signature malleability
Browse files Browse the repository at this point in the history
We are not cutting of the upper half of the curve, so it's technically
feasible to submit a modified signature that will pass validation with
`ecrecover`. However, other measures and validations ensure that this
doesn't amount to a security risk. First, eip-712 ensures that the
signature cannot be replayed across chains. Second, we are not storing
signatures as keys anywhere and instead use the hash payloads, rendering
signature replay on the same chain impossible.

The _only_ risk involving signautures entails approving a boost claim
with multiple incentives before the claimant is eligible to claim all
incentives, since we sign off on incentive quantity instead of individual
incentives. However, this would be an issue regardless of whether or not
the signature was malleable.
  • Loading branch information
topocount committed Oct 29, 2024
1 parent f1f7baf commit 1a08c86
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions packages/evm/test/validators/SignerValidator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,38 @@ contract SignerValidatorTest is Test {
assertTrue(validator.validate(boostId, incentiveId, claimant, claimData));
}

function testValidate_MalleableSignature() public {
uint256 boostId = 5;
uint256 incentiveId = 1;
uint8 incentiveQuantity = 2;
address claimant = makeAddr("claimant");
bytes memory incentiveData = hex"def456232173821931823712381232131391321934";
bytes32 msgHash = validator.hashSignerData(boostId, incentiveQuantity, claimant, incentiveData);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(testSignerKey, msgHash);

bytes memory originalSignature = _packSignature(v, r, s);

s = bytes32(uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) - uint256(s));

if (v == 27) {
v = 28;
} else {
v = 27;
}

ASignerValidator.SignerValidatorInputParams memory validatorData =
ASignerValidator.SignerValidatorInputParams(testSigner, _packSignature(v, r, s), incentiveQuantity);
bytes memory claimData = abi.encode(IBoostClaim.BoostClaimData(abi.encode(validatorData), incentiveData));
assertTrue(validator.validate(boostId, incentiveId, claimant, claimData));

// attempt to replay the signature
validatorData = ASignerValidator.SignerValidatorInputParams(testSigner, originalSignature, incentiveQuantity);
claimData = abi.encode(IBoostClaim.BoostClaimData(abi.encode(validatorData), incentiveData));

vm.expectRevert(abi.encodeWithSelector(BoostError.IncentiveClaimed.selector, incentiveId));
validator.validate(boostId, incentiveId, claimant, claimData);
}

function testValidate_UnauthorizerCaller() public {
address badCaller = makeAddr("badValidatorCaller");

Expand Down

0 comments on commit 1a08c86

Please sign in to comment.