-
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 Uint8Arrays. The verification functions do not enforce they actually receive BigInts, 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.