Era

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

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

Summary

Incorrect logic inside ecpairing will lead to reject valid proof

Vulnerability Details

Whenever verifier verifies proof he will eventually calls ecpairing -> calls g2ScalarMul

as you can see zr1is not being used when condition case 0x02 triggers, but yp1 used passed twice to g2JacobianDouble.

function g2ScalarMul(xp0, xp1, yp0, yp1, zp0, zp1, scalar) -> xr0, xr1, yr0, yr1, zr0, zr1 {
let scalarBitIndex := bitLen(scalar)
switch scalar
case 0x02 {
xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianDouble(xp0, xp1, yp0, yp1, zp0, yp1) // @audit zp1 where?
}
default {
xr0 := 0
xr1 := 0
yr0 := MONTGOMERY_ONE()
yr1 := 0
zr0 := 0
zr1 := 0
for {} scalarBitIndex {} {
scalarBitIndex := sub(scalarBitIndex, 1)
xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianDouble(xr0, xr1, yr0, yr1, zr0, zr1) // @audit correct passing params
let bitindex := checkBit(scalarBitIndex, scalar)
if bitindex {
xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianAdd(xp0, xp1, yp0, yp1, zp0, zp1, xr0, xr1, yr0, yr1, zr0, zr1)
}
}
}
}

precompiles/EcPairing.yul#L683

Incorrect g2ScalarMul leads to g2IsInSubGroup being incorrect -> iszero(g2IsInSubGroup(g2_x0,g2_x1, g2_y0, g2_y1, MONTGOMERY_ONE(), 0)) false
-> rejecting valid proof

Impact

Flase proof will be accepted when condition case 0x02 triggers. For now scalar can only be TWISTED_SUBGROUP_ORDER or X - 4965661367192848881, but later it might become dynamic, it will reject valid proofs

Tools Used

Recommendations

function g2ScalarMul(xp0, xp1, yp0, yp1, zp0, zp1, scalar) -> xr0, xr1, yr0, yr1, zr0, zr1 {
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
xr1 := 0
yr0 := MONTGOMERY_ONE()
yr1 := 0
zr0 := 0
zr1 := 0
for {} scalarBitIndex {} {
scalarBitIndex := sub(scalarBitIndex, 1)
xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianDouble(xr0, xr1, yr0, yr1, zr0, zr1)
let bitindex := checkBit(scalarBitIndex, scalar)
if bitindex {
xr0, xr1, yr0, yr1, zr0, zr1 := g2JacobianAdd(xp0, xp1, yp0, yp1, zp0, zp1, xr0, xr1, yr0, yr1, zr0, zr1)
}
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 5 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.