Era

ZKsync
FoundryLayer 2
500,000 USDC
View results
Submission Details
Severity: low
Valid

`EcPairing.g2ScalarMul`'s `g2JacobianDouble` final parameter should be `zp1` for scalar 2

Summary

The function g2JacobianDouble is called with an incorrect final parameter in the EcPairing.yul file at the function g2ScalarMul when the scalar is 0x02. The final parameter should be zp1 instead of yp1, as the NatSpec specifies.

Vulnerability Details

In the EcPairing.yul file, the function g2JacobianDouble is called with the parameters xp0, xp1, yp0, yp1, zp0, and yp1. The final parameter should be zp1 instead of yp1 when doubling the g2 point. This incorrect parameter may lead to incorrect calculations and results.

Passing yp1 instead of zp1 as the final parameter to g2JacobianDouble when the scalar is 2 results in incorrect point doubling on the elliptic curve. Specifically, the function uses the y-coordinate part (yp1) as the z-coordinate, which is mathematically invalid.

As you can see on Ethereum's py_pairing reference implementation from EIP-197: Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128, the jacobian_multiply function should not change the Z coordinate of the G2 point when doubling. You can also confirm that on go-ethereum (geth)'s implementation of ecpairing: (references: 1, 2, 3, 4), where the Double function does not change the coordinates of the a *curvePoint G2 point.

Impact

This issue can affect the overall functionality and correctness of the cryptographic operations in the EcPairing contract. Potential Consequences:

  • Invalid Cryptographic Proofs: In ZKSync, incorrect scalar multiplication can lead to the generation of invalid proofs. This may cause the system to accept false statements or reject valid ones, undermining the integrity of the protocol.

  • Attackers could exploit the incorrect calculations to forge proofs or signatures

  • Smart contracts relying on EcPairing may experience unexpected behavior or enter invalid states, which could lead to loss of funds

Tools Used

Code review

Recommendations

Update the call to g2JacobianDouble to use zp1 as the final parameter instead of yp1:

diff --git a/era-contracts/system-contracts/contracts/precompiles/EcPairing.yul b/era-contracts/system-contracts/contracts/precompiles/EcPairing.yul
index 5e8011b..1cac224 100644
--- a/era-contracts/system-contracts/contracts/precompiles/EcPairing.yul
+++ b/era-contracts/system-contracts/contracts/precompiles/EcPairing.yul
@@ -680,7 +680,7 @@ object "EcPairing" {
let scalarBitIndex := bitLen(scalar)
switch scalar
case 0x02 {
- xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianDouble(xp0, xp1, yp0, yp1, zp0, yp1)
+ xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianDouble(xp0, xp1, yp0, yp1, zp0, zp1)
}
default {
xr0 := 0
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Valid proof will be rejected once `case 0x02` code is triggered

Appeal created

malfurionwhitehat Submitter
6 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Valid proof will be rejected once `case 0x02` code is triggered

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.