Number of limbs of Uint521
not enforced
Description
The sdk's Uint521
type uses gnark's standard library implementation for emulated fields, in a configuration in which elements are stored in six limbs of 96 bits each:
var u521Field *emulated.Field[Uint521Field]
type Uint521Field struct{}
func (f Uint521Field) NbLimbs() uint { return 6 }
func (f Uint521Field) BitsPerLimb() uint { return 96 }
type Uint521 struct {
*emulated.Element[Uint521Field]
}
However, the Values
and FromValues
implementations do not verify the number of limbs. Thus, FromValues
accepts arbitrary numbers of arguments, using them as limbs, even less or more than six, and Values
similarly does not check how many limbs it is returning:
func (v Uint521) Values() []frontend.Variable {
u521Field.Reduce(v.Element)
return v.Limbs
}
func (v Uint521) FromValues(vs ...frontend.Variable) CircuitVariable {
n := emulated.ValueOf[Uint521Field](0)
n.Limbs = vs
return newU521(&n)
}
Based on a cursory look into gnark's emulated.Field
implementation as used by Uint521
, it appears that a variable number of limbs generally seems to be supported.
However, lack of limb-number checks means that Values
does not always return a list of the same length. This can cause problems for example when attempting to use Uint521
as components of List
or TupleN
types; see Discussion point ref↗.
Impact
As a constant length of the return value of Values
is not ensured, using Uint521
within the SDK's list or tuple types may cause crashes or panics or lead to unintended behavior (e.g., limbs of three Uint521
s being split up among two Uint521
s instead).
While it appears as though emulated.Field
can handle elements with nonstandard numbers of limbs, we have not fully checked emulated.Field
to make sure this is the case. As usage with nonstandard number of limbs is not explicitly documented as being supported, it may thus be safer to ensure a standard number of limbs for Uint521
.
Recommendations
We recommend to check that len(vs)
is equal to NumVars()
in FromValues
and that len(v.Limbs)
is equal to NumVars()
just before the return in Values
.
Remediation
This issue has been acknowledged by Brevis, and fixes were implemented in the following commits: