BabyPbk()
versionNOTE: used in this document is the same as used in https://eips.ethereum.org/EIPS/eip-2494, and same as used in Geometry's bug report.
The theoretical fix is to ensure . In circom, it'll look like this:
Readers may know that just using LessThan template doesn't protect against all cases. For example, run this in zkrepl.dev: https://gist.github.com/0xbok/3f87b9c79fde41759f31fc62de218b80. It shows that LessThan
passes when . is the maximum value in circom and hence it's greater than , but LessThan
returns 1
interpreting it as .
We show that enforcing LessThan(251)[secret, l].out === 1
and then using BabyPbk()
(as defined in current master branch of circomlib) on is enough to enforce that .
We do this by proof of contradiction. We try to find such that LessThan(251)[secret, l].out === 1
and BabyPbk()
check also passes.
We can shorten our search for such a in range since BabyPbk constrains secret to 253 bits here: https://github.com/iden3/circomlib/blob/cff5ab6288b55ef23602221694a6a38a0239dcc0/circuits/babyjub.circom#L96-L97.
Now, here is LessThan
template:
LessThan(251)([secret, l])
computes: 1<<251 - l + secret
. We know , so 1<<251 - l
is also known. Let's call it .
is constrained to 252 bits by LessThan
. This expression is always < SNARK_FIELD
because of 's range (confirmed by line 11 and 12 in the code below). So we can ignore mod SNARK_FIELD
for the rest of the discussion.
We've already established that LessThan
enforces that is of 252 bits. If we want LessThan.out = 1
, n2b.out[251]
has to be 0. This implies the most significant bit of has to be 0.
is of 252 bits with the most significant bit as 0. This means is of 251 bits. So:
Since (line 14 in code below), we get:
But our initial range of is . Hence, there is no such secret.
Code to verify some claims in the proof:
reach out at twitter.com/blockdeveth