The use of long type for variable K in the sha256_round_function_gadget gadget breaks stuff when building on platforms where long is 32bit.
Specifically, in sha256_components.tcc the SHA256_K array is typed unsigned long.
However, in the sha256_round_function_gadget definition the parameter type for K is simply long.
So the constant term for the unreduced_new_e and unreduced_new_a constraints is interpreted as p-K (because it's negative...).
Example diff of constraints, where green is 64bit platform and red is 32bit platform:
<a,(1,x)> = 1
- <b,(1,x)> = 21888242871839275222246405745257275088548364400416034343698204186575137909401
+ <b,(1,x)> = 3624381080
<c,(1,x)> = 0
constraint was:
terms for a:
1 * 1
terms for b:
- 1 * 21888242871839275222246405745257275088548364400416034343698204186575137909401
+ 1 * 3624381080
x_1814 * 1
where x_1814 (module.leaf_hash.hasher input_hasher packed_W_8) was assigned value 0
i.e. negative of 0
Because of this bug the proofs on both 32bit and 64bit platforms are self-consistent, but the constraint system is different - so the same proving key doesn't work on both platforms.
Changing the definition of the K variable in sha256_round_function_gadget to unsigned long does not fix the problem, because the Fp_model constructor with default arguments thinks that the variable is signed.
There is only one constructor:
Fp_model(const long x, const bool is_unsigned=false);
Which performs implicit conversion from an unsigned long to a long then re-interprets it as a signed integer because the is_unsigned flag is never provided (e.g. via the linear combination + operator).
Changing the type of the K instance variable to FieldT constructor to the following fixes the problem:
However, I really recommend that the Fp_model doesn't take long variable with an extra unsigned parameter to do the equivalent of a static_cast - and instead handles long and unsigned long separately.
The use of
long
type for variableK
in thesha256_round_function_gadget
gadget breaks stuff when building on platforms wherelong
is 32bit.Specifically, in
sha256_components.tcc
theSHA256_K
array is typedunsigned long
.However, in the
sha256_round_function_gadget
definition the parameter type forK
is simplylong
.So the constant term for the
unreduced_new_e
andunreduced_new_a
constraints is interpreted asp-K
(because it's negative...).Example diff of constraints, where green is 64bit platform and red is 32bit platform:
Because of this bug the proofs on both 32bit and 64bit platforms are self-consistent, but the constraint system is different - so the same proving key doesn't work on both platforms.
Changing the definition of the
K
variable insha256_round_function_gadget
tounsigned long
does not fix the problem, because theFp_model
constructor with default arguments thinks that the variable is signed.There is only one constructor:
Which performs implicit conversion from an
unsigned long
to along
then re-interprets it as a signed integer because theis_unsigned
flag is never provided (e.g. via the linear combination+
operator).Changing the type of the
K
instance variable toFieldT
constructor to the following fixes the problem:However, I really recommend that the
Fp_model
doesn't takelong
variable with an extraunsigned
parameter to do the equivalent of astatic_cast
- and instead handleslong
andunsigned long
separately.