# Discrepancy in ECRECOVER Precompile when Using Delegatecall

zkSync Era's ECRECOVER precompile returns bytes32(0) instead of the recovered address when invoked via delegatecall, breaking EVM compatibility and signature validation.

- Payout: Contest reward
- Severity: medium
- Program: zkSync
- Credited: anon
- Disclosed: 2024-02-29
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-10-zksync-findings/issues/175
- Library page: https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-17
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:crypto vuln:signature-replay

**Target:** EVM precompile at 0x01 (Ecrecover.yul) / EfficientCall library
**Root cause:** The ECRECOVER precompile at 0x01 is implemented as a Yul contract; when reached via delegatecall it executes in the caller's context rather than behaving as a precompileCall, returning bytes32(0) instead of the recovered address.
**Steps:**
1. Deploy PoC contract with ecrecoverStaticcall/ecrecoverCall/ecrecoverDelegatecall functions using assembly call/staticcall/delegatecall to 0x01 with abi.encode(h,v,r,s).
2. Call ecrecoverStaticcall and ecrecoverCall: both return the expected recovered address (0x759389e8e5c1aa1f511e9ea98b6caedd262bff0b).
3. Call ecrecoverDelegatecall: on zkSync Era it returns bytes32(0), diverging from EVM behavior.
4. Compare against standard EVM where all three return the same address.
**How found:** Researcher compared precompile behavior across call/staticcall/delegatecall on zkSync Era versus standard EVM and noticed the delegatecall path returned bytes32(0) instead of the recovered address, tracing it to the Yul Ecrecover precompile implementation.
**Insight:** When auditing EVM-equivalent L2s, differential-test every precompile across call, staticcall, and delegatecall — precompiles implemented as contracts (not native) can behave differently under delegatecall context.
