---
# System prepended metadata

title: Identifying if secret has to be explicitly constrained to 251 bits

---

# Fix for Geometry's bug for projects that want to continue using unfixed `BabyPbk()` version

NOTE: $l$ used in this document is the same as $l$ used in https://eips.ethereum.org/EIPS/eip-2494, and same as $r$ used in Geometry's bug report.

The theoretical fix is to ensure $secret < l$. In circom, it'll look like this:
```js
LessThan(251)([secret, l]) === 1;
```

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 $secret = SNARK\_FIELD-1$. $SNARK\_FIELD-1$ is the maximum value in circom and hence it's greater than $l$, but `LessThan` returns `1` interpreting it as $p-1 < l$.

We show that enforcing `LessThan(251)[secret, l].out === 1` and then using [`BabyPbk()`](https://github.com/iden3/circomlib/blob/cff5ab6288b55ef23602221694a6a38a0239dcc0/circuits/babyjub.circom#L96-L97) (as defined in current master branch of circomlib) on $secret$ is enough to enforce that $secret < l$.

## Proof

We do this by proof of contradiction. We try to find $secret \in [l, SNARK\_FIELD-1]$ such that `LessThan(251)[secret, l].out === 1` and `BabyPbk()` check also passes.

We can shorten our search for such a $secret$ in range $[l, 2^{253}-1]$ 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:
```js
template LessThan(n) {
    assert(n <= 252);
    signal input in[2];
    signal output out;

    component n2b = Num2Bits(n+1);

    n2b.in <== in[0]+ (1<<n) - in[1];

    out <== 1-n2b.out[n];
}
```

`LessThan(251)([secret, l])` computes: `1<<251 - l + secret`. We know $l$, so `1<<251 - l` is also known. Let's call it $y$.

$y+secret$ is constrained to 252 bits by `LessThan`. This expression is always < `SNARK_FIELD` because of $secret$'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 $y+secret$ is of 252 bits. If we want `LessThan.out = 1`, `n2b.out[251]` has to be 0. This implies the most significant bit of $y+secret$ has to be 0.

$y+secret$ is of 252 bits with the most significant bit as 0. This means $y+secret$ is of 251 bits. So:
$$
y+secret < 2^{251}-1 \implies
secret < 2^{251} - 1 - y
$$

Since $2^{251} - 1 - y < l$ (line 14 in code below), we get:
$$
secret < l
$$

But our initial range of $secret$ is $[l,2^{253}-1]$. Hence, there is no such secret.

---

Code to verify some claims in the proof:
```js=
var SNARK_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495616n; // 254 bits
var l = 2736030358979909402780800718157159386076813972158567259200215660948447373041n; 
2736030358979909402780800718157159386076813972158567259200215660948447373039n// 251 bits
var one251 = 1n << 251n; // 252 bits
var y = one251 - l; // 249 bits

var secret_min = l;
var secret_max = 2n**253n-1n;

// ensure that y+secret never overflows p (SNARK_FIELD)
console.log("y+l < SNARK_FIELD-1", y+l < SNARK_FIELD-1n);
console.log("y+2^253-1 < SNARK_FIELD-1", y+(2n**253n-1n) < SNARK_FIELD-1n);

console.log("2**251-1 - y < l", 2n**251n-1n - y < l);
```

reach out at twitter.com/blockdeveth