I found an undefined behavior in an edge case when unpacking fields into bool arrays. More concretely, when you are trying to unpack a field into a bit array of length > 254 bits. I think the compiler assumes that the bit size of a field is 254 bits, and that is the case for the curve bn128, but the bls12_381 has 255 bits. So if you are writting a circuit for the latter curve you can run into the following error.
Environment
Compiler version: zokrates:0.8.7 (but this should still occur in 0.8.8)
Operating system: macos Sonoma (M1)
Steps to Reproduce
the way unpack is implemented unpack(a) will return a bool array of length <= 254 if a < $2^{254}$ and only a larger array of length n if $2^{n-1} \le a < 2^{n}$. This leads to obscure consequences..
Lets assume I want to write a circuit on bls12_381, the following curve should pass.
However, the compiler throws an assertion error on the third assert.
Note that the arrays used in the 2nd and 3rd assert are exactly the same but for the additional false at the beginning of the 3rd array representing the trailing zero.
This is the root cause, that in order for the jubjub implementation to work atm, the stdlib has to make the case distinction between values that are <$2^{254) and when values are <$2{255}
Proposal
The proposal would be to modify this threshold either to bitsize of the bigger curve, 255 bit, or to the arbitrary length of 256 bits.
This will not have a negative impact on circuits on smaller curves as the affected values at the moment would be wrapped by the modulo.
The other case, when p is larger than the boolean array, is handled by ZoKrates with an exception (#955) .which I see no objection:
Undefined behavior of EMBED's unpack
I found an undefined behavior in an edge case when unpacking fields into bool arrays. More concretely, when you are trying to unpack a field into a bit array of length > 254 bits. I think the compiler assumes that the bit size of a field is 254 bits, and that is the case for the curve
bn128
, but thebls12_381
has 255 bits. So if you are writting a circuit for the latter curve you can run into the following error.Environment
Steps to Reproduce
the way unpack is implemented unpack(a) will return a bool array of length <= 254 if a < $2^{254}$ and only a larger array of length n if $2^{n-1} \le a < 2^{n}$. This leads to obscure consequences..
Take the following code.
Lets assume I want to write a circuit on
bls12_381
, the following curve should pass. However, the compiler throws an assertion error on the third assert. Note that the arrays used in the 2nd and 3rd assert are exactly the same but for the additionalfalse
at the beginning of the 3rd array representing the trailing zero.This is the root cause, that in order for the jubjub implementation to work atm, the stdlib has to make the case distinction between values that are <$2^{254) and when values are <$2{255}
Proposal
The proposal would be to modify this threshold either to bitsize of the bigger curve, 255 bit, or to the arbitrary length of 256 bits.
This will not have a negative impact on circuits on smaller curves as the affected values at the moment would be wrapped by the modulo.
The other case, when
p
is larger than the boolean array, is handled by ZoKrates with an exception (#955) .which I see no objection:error message: