Skip to content

Commit de239d7

Browse files
BashmuntaAmxx
andauthored
Optimize ERC-1271 path in isValidSignatureNowCalldata to avoid extra allocation (#6123)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
1 parent d94f150 commit de239d7

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

.changeset/fuzzy-lizards-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`SignatureChecker`: Add `isValidERC1271SignatureNowCalldata`, a variant of `isValidERC1271SignatureNow` that takes the signature from calldata.

contracts/utils/cryptography/SignatureChecker.sol

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ library SignatureChecker {
5050
(address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecoverCalldata(hash, signature);
5151
return err == ECDSA.RecoverError.NoError && recovered == signer;
5252
} else {
53-
return isValidERC1271SignatureNow(signer, hash, signature);
53+
return isValidERC1271SignatureNowCalldata(signer, hash, signature);
5454
}
5555
}
5656

@@ -73,8 +73,8 @@ library SignatureChecker {
7373
// Encoded calldata is :
7474
// [ 0x00 - 0x03 ] <selector>
7575
// [ 0x04 - 0x23 ] <hash>
76-
// [ 0x24 - 0x44 ] <signature offset> (0x40)
77-
// [ 0x44 - 0x64 ] <signature length>
76+
// [ 0x24 - 0x43 ] <signature offset> (0x40)
77+
// [ 0x44 - 0x63 ] <signature length>
7878
// [ 0x64 - ... ] <signature data>
7979
let ptr := mload(0x40)
8080
mstore(ptr, selector)
@@ -87,6 +87,33 @@ library SignatureChecker {
8787
}
8888
}
8989

90+
function isValidERC1271SignatureNowCalldata(
91+
address signer,
92+
bytes32 hash,
93+
bytes calldata signature
94+
) internal view returns (bool result) {
95+
bytes4 selector = IERC1271.isValidSignature.selector;
96+
uint256 length = signature.length;
97+
98+
assembly ("memory-safe") {
99+
// Encoded calldata is :
100+
// [ 0x00 - 0x03 ] <selector>
101+
// [ 0x04 - 0x23 ] <hash>
102+
// [ 0x24 - 0x43 ] <signature offset> (0x40)
103+
// [ 0x44 - 0x63 ] <signature length>
104+
// [ 0x64 - ... ] <signature data>
105+
let ptr := mload(0x40)
106+
mstore(ptr, selector)
107+
mstore(add(ptr, 0x04), hash)
108+
mstore(add(ptr, 0x24), 0x40)
109+
mstore(add(ptr, 0x44), length)
110+
calldatacopy(add(ptr, 0x64), signature.offset, length)
111+
112+
let success := staticcall(gas(), signer, ptr, add(length, 0x64), 0x00, 0x20)
113+
result := and(success, and(gt(returndatasize(), 0x1f), eq(mload(0x00), selector)))
114+
}
115+
}
116+
90117
/**
91118
* @dev Verifies a signature for a given ERC-7913 signer and hash.
92119
*

test/utils/cryptography/SignatureChecker.test.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ describe('SignatureChecker (ERC1271)', function () {
5858
});
5959

6060
describe('ERC1271 wallet', function () {
61-
for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow', 'isValidSignatureNowCalldata']) {
61+
for (const fn of [
62+
'isValidERC1271SignatureNow',
63+
'isValidERC1271SignatureNowCalldata',
64+
'isValidSignatureNow',
65+
'isValidSignatureNowCalldata',
66+
]) {
6267
describe(fn, function () {
6368
it('with matching signer and signature', async function () {
6469
await expect(

0 commit comments

Comments
 (0)