Add Calldata variants of ECDSA.recover, ECDSA.tryRecover and SignatureChecker.isValidSignatureNow (#5788)

This commit is contained in:
Hadrien Croubois
2025-07-11 16:57:04 +02:00
committed by GitHub
parent 667bb9b5c3
commit bc8f775df2
6 changed files with 114 additions and 8 deletions

View File

@ -44,6 +44,7 @@ describe('ECDSA', function () {
// Recover the signer address from the generated message and signature.
expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer);
expect(await this.mock.$recoverCalldata(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer);
});
it('returns signer address with correct signature for arbitrary length message', async function () {
@ -52,11 +53,13 @@ describe('ECDSA', function () {
// Recover the signer address from the generated message and signature.
expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer);
expect(await this.mock.$recoverCalldata(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer);
});
it('returns a different address', async function () {
const signature = await this.signer.signMessage(TEST_MESSAGE);
expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer);
expect(await this.mock.$recoverCalldata(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer);
});
it('reverts with invalid signature', async function () {
@ -66,6 +69,10 @@ describe('ECDSA', function () {
this.mock,
'ECDSAInvalidSignature',
);
await expect(this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
);
});
});
@ -79,6 +86,7 @@ describe('ECDSA', function () {
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(await this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.equal(signer);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
@ -92,6 +100,7 @@ describe('ECDSA', function () {
const v = '0x1c'; // 28 = 1c.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
expect(await this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(
@ -110,6 +119,10 @@ describe('ECDSA', function () {
this.mock,
'ECDSAInvalidSignature',
);
await expect(this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
);
const { r, s } = ethers.Signature.from(signature);
await expect(
@ -126,6 +139,9 @@ describe('ECDSA', function () {
await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
await expect(this.mock.$recoverCalldata(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
});
@ -139,6 +155,7 @@ describe('ECDSA', function () {
const v = '0x1c'; // 28 = 1c.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(await this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.equal(signer);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
@ -152,6 +169,7 @@ describe('ECDSA', function () {
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
expect(await this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = ethers.Signature.from(signature);
expect(
@ -170,6 +188,10 @@ describe('ECDSA', function () {
this.mock,
'ECDSAInvalidSignature',
);
await expect(this.mock.$recoverCalldata(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
);
const { r, s } = ethers.Signature.from(signature);
await expect(
@ -186,6 +208,9 @@ describe('ECDSA', function () {
await expect(this.mock.$recover(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
await expect(this.mock.$recoverCalldata(TEST_MESSAGE, compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
});
@ -202,6 +227,9 @@ describe('ECDSA', function () {
await expect(this.mock.$recover(message, highSSignature))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);
await expect(this.mock.$recoverCalldata(message, highSSignature))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);
await expect(this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);

View File

@ -36,23 +36,29 @@ describe('SignatureChecker (ERC1271)', function () {
await expect(
this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), TEST_MESSAGE_HASH, this.signature),
).to.eventually.be.true;
await expect(this.mock.$isValidSignatureNowCalldata(this.signer.address, TEST_MESSAGE_HASH, this.signature)).to
.eventually.be.true;
});
it('with invalid signer', async function () {
await expect(
this.mock.$isValidSignatureNow(ethers.Typed.address(this.other.address), TEST_MESSAGE_HASH, this.signature),
).to.eventually.be.false;
await expect(this.mock.$isValidSignatureNowCalldata(this.other.address, TEST_MESSAGE_HASH, this.signature)).to
.eventually.be.false;
});
it('with invalid signature', async function () {
await expect(
this.mock.$isValidSignatureNow(ethers.Typed.address(this.signer.address), WRONG_MESSAGE_HASH, this.signature),
).to.eventually.be.false;
await expect(this.mock.$isValidSignatureNowCalldata(this.signer.address, WRONG_MESSAGE_HASH, this.signature)).to
.eventually.be.false;
});
});
describe('ERC1271 wallet', function () {
for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) {
for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow', 'isValidSignatureNowCalldata']) {
describe(fn, function () {
it('with matching signer and signature', async function () {
await expect(