-
Notifications
You must be signed in to change notification settings - Fork 473
Description
In the JavaScript verifiers, the type/shape of public signals is not checked consistently.
length
and arrays
In fflonk and plonk, there is a check for the length
property.
Lines 45 to 48 in e0c7219
if (publicSignals.length !== vk.nPublic) { | |
logger.error("Number of public signals does not match with vk"); | |
return false; | |
} |
Lines 49 to 52 in e0c7219
if (publicSignals.length != vk_verifier.nPublic) { | |
if (logger) logger.error("Invalid number of public inputs"); | |
return false; | |
} |
but in groth16 there is none. An attacker might submit a shorter array, which has the same effect as sending
0
in the missing elements (for groth16), but the calling code might have different expectations.
Moreover (for all schemes), if verify
receives publicSignals
from decoded, user-provided JSON, they might not be an array at all and instead a weird object like {"length": 3, 0: "0", 1: "1", 2 "0"}
. Again, implications depend heavily on the calling code's interpretation of such objects but I feel like they should not verify successfully.
toRprBE
, toRprLE
and non-BigInts
These functions encode public signals into Uint8Array
s. The verification functions do not enforce they actually receive BigInt
s, there is just an implicit assumption from unstringifyBigInts
. However, that function is not quite consistent with the BigInt
constructor.
For example, publicSignals = ["0b0"]
will be the same after unstringifyBigInts
. While BigInt
and thus the range checks and possibly callers might interpret it as 0
, toRprLE
treats it identically to 176
, because 176 === 0xb0
. Similar issues arise with leading and trailing whitespace.