This PR avoids ejecting the scalar value when loading and storing a circuit.
Failing Case
This issue was found in a deployed program.
Suppose that we have a program cast operation from a field to a scalar.
Suppose that r0 is a field element that is larger than the scalar modulus.
function foo:
input r0 as field.private;
cast r0 into r1 as scalar;
When the cast instruction is executed, constraints are added to check that the casted scalar value is correct.
During deployment, these constraints are not checked for satisfaction (by design), and an invalid scalar element is stored into the registers.
store_circuit ejects the stored value and checks for type equality.
However, the implementation of Eject for Scalar requires that the element is a valid a scalar and panics otherwise.
Solution
The eject is done to check that the type of the stored value is correct.
To avoid this failing case, we directly check for type equality against the circuit value.
Testing
This PR includes an integration test that enumerates all LiteralType combinations of cast and cast.lossy and tests them in a program context.
This PR avoids ejecting the scalar value when loading and storing a circuit.
Failing Case
This issue was found in a deployed program.
Suppose that we have a program
cast
operation from afield
to ascalar
. Suppose thatr0
is a field element that is larger than the scalar modulus.When the
cast
instruction is executed, constraints are added to check that the casted scalar value is correct. During deployment, these constraints are not checked for satisfaction (by design), and an invalid scalar element is stored into the registers.store_circuit
ejects the stored value and checks for type equality. However, the implementation ofEject
forScalar
requires that the element is a valid a scalar and panics otherwise.Solution
The eject is done to check that the type of the stored value is correct. To avoid this failing case, we directly check for type equality against the circuit value.
Testing
This PR includes an integration test that enumerates all
LiteralType
combinations ofcast
andcast.lossy
and tests them in a program context.CI is running in this branch.
Considerations
We considered alternate solutions including:
cast
operation onscalar
sScalar::eject
does not fail however, these solutions would either require a migration or impact a large portion of the codebase.