Skip to content

Commit e1878ac

Browse files
committed
Fix ECDSA signature malleability (#3610)
(cherry picked from commit d693d89)
1 parent 64e4820 commit e1878ac

File tree

3 files changed

+16
-30
lines changed

3 files changed

+16
-30
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 4.7.3
4+
5+
### Breaking changes
6+
7+
* `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`.
8+
39
## 4.7.2 (2022-07-27)
410

511
* `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578))

contracts/utils/cryptography/ECDSA.sol

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ library ECDSA {
5555
* _Available since v4.3._
5656
*/
5757
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
58-
// Check the signature length
59-
// - case 65: r,s,v signature (standard)
60-
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
6158
if (signature.length == 65) {
6259
bytes32 r;
6360
bytes32 s;
@@ -71,17 +68,6 @@ library ECDSA {
7168
v := byte(0, mload(add(signature, 0x60)))
7269
}
7370
return tryRecover(hash, v, r, s);
74-
} else if (signature.length == 64) {
75-
bytes32 r;
76-
bytes32 vs;
77-
// ecrecover takes the signature parameters, and the only way to get them
78-
// currently is to use assembly.
79-
/// @solidity memory-safe-assembly
80-
assembly {
81-
r := mload(add(signature, 0x20))
82-
vs := mload(add(signature, 0x40))
83-
}
84-
return tryRecover(hash, r, vs);
8571
} else {
8672
return (address(0), RecoverError.InvalidSignatureLength);
8773
}

test/utils/cryptography/ECDSA.test.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,6 @@ function to2098Format (signature) {
2222
return web3.utils.bytesToHex(short);
2323
}
2424

25-
function from2098Format (signature) {
26-
const short = web3.utils.hexToBytes(signature);
27-
if (short.length !== 64) {
28-
throw new Error('invalid signature length (expected short format)');
29-
}
30-
short.push((short[32] >> 7) + 27);
31-
short[32] &= (1 << 7) - 1; // zero out the first bit of 1 the 32nd byte
32-
return web3.utils.bytesToHex(short);
33-
}
34-
3525
function split (signature) {
3626
const raw = web3.utils.hexToBytes(signature);
3727
switch (raw.length) {
@@ -144,11 +134,13 @@ contract('ECDSA', function (accounts) {
144134
);
145135
});
146136

147-
it('works with short EIP2098 format', async function () {
137+
it('rejects short EIP2098 format', async function () {
148138
const version = '1b'; // 27 = 1b.
149139
const signature = signatureWithoutVersion + version;
150-
expect(await this.ecdsa.recover(TEST_MESSAGE, to2098Format(signature))).to.equal(signer);
151-
expect(await this.ecdsa.recover(TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.equal(signer);
140+
await expectRevert(
141+
this.ecdsa.recover(TEST_MESSAGE, to2098Format(signature)),
142+
'ECDSA: invalid signature length',
143+
);
152144
});
153145
});
154146

@@ -187,11 +179,13 @@ contract('ECDSA', function (accounts) {
187179
);
188180
});
189181

190-
it('works with short EIP2098 format', async function () {
182+
it('rejects short EIP2098 format', async function () {
191183
const version = '1c'; // 27 = 1b.
192184
const signature = signatureWithoutVersion + version;
193-
expect(await this.ecdsa.recover(TEST_MESSAGE, to2098Format(signature))).to.equal(signer);
194-
expect(await this.ecdsa.recover(TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.equal(signer);
185+
await expectRevert(
186+
this.ecdsa.recover(TEST_MESSAGE, to2098Format(signature)),
187+
'ECDSA: invalid signature length',
188+
);
195189
});
196190
});
197191

0 commit comments

Comments
 (0)