Closed code423n4 closed 1 year ago
The malleability checks are on the client side on Ethereum (and are done by the DefaultAсcount.sol). https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L187
miladpiri marked the issue as sponsor disputed
@miladpiri to confirm: Are you saying that MM will reject the signature or is the check going to be performed by the zkSync node (I believe it should be Core)?
@GalloDaSballo I believe that Milad meant the ecrecover precompile on EVM accepts the malleable signature, but specifically, the transaction signature is accepted as not malleable.
On zkSync Era, we also accept the malleable signature on ecrecover. But the default account (analog to the Ethereum EOA) will reject signature malleavility. So all good
I must agree with the sponsor:
ecRecover on the Node will revert
The Precompile ecrecover
will not revert if the value is above half the curve, see below fuzzed test:
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;
import {Test} from "forge-std/Test.sol";
contract TestDirty is Test {
function setUp() public {
}
function testEC(uint8 v, uint256 r, uint256 s) external view {
s = s % 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1;
s += 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1;
ecrecover(bytes32(0), v, bytes32(r), bytes32(s));
}
}
This test passes on mainnet meaning that the behaviour is consistent between the two implementations
The AA is safe from malleability per the check shown by the Sponsor
GalloDaSballo marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/precompiles/Ecrecover.yul#L62
Vulnerability details
Impact
The
Ecrecover.yul
file meant to simulate theecrecover
mechanism as executed by traditional ETH 1.0 consensus mechanisms is incorrect. In detail, it does not conform to the "Homestead" update which introduced an upper-bound check fors
values of an(r, s, v)
ECDSA payload to prohibit malleable signatures.All major ETH 1.0 clients (i.e.
go-ethereum
,nethermind
) prevents
values as input inecrecover
instructions if the value lies in the upper half of thesecp256k1
curve order. To illustrate:go-ethereum
: https://github.com/ethereum/go-ethereum/blob/b628d72/crypto/crypto.go#L266-L270nethermind
: https://github.com/NethermindEth/nethermind/blob/fd34651/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs#L22-L24The consensus discrepancy at hand illustrates a security feature present in ETH 1.0 clients and absent in the
zkEVM
. As such, a contract that would be secure when deployed in ETH 1.0 will not be so when deployed in the zkEVM. This vulnerability allows malleable signatures to be consumed thus opening up potential replay-attack vectors that would otherwise be impossible in ETH 1.0.The
ecrecover
function lies at the heart of multiple authorization systems in use by smart contracts, meaning that a significant amount of funds would be affected by this discrepancy.Proof of Concept
An
ecrecover
call with ans
value that is greater than or equal to0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1
should fail execution, however, the operation properly succeeds in the zkEVM. A minimalistic contract that illustrates the issue:Tools Used
Manual review, ETH 1.0 clients, Ethereum Foundation release guidelines.
Recommended Mitigation Steps
We advise the upper bound evaluation to be performed similarly to the
SECP256K1_GROUP_SIZE
bound check already applied to the codebase, utilizing thenethermind
coding style which divides the group size by2
.