Introduction
zkSecurity was contracted by Aztec to audit their Bigfield implementation in the Barretenberg library.
The audit was conducted between June 10th and June 28th.
The specific commit that was audited is 4ba553ba31
.
Methodology
zkSecurity did line-by-line review of the Barretenberg bigfield
and field
modules.
We used a SageMath script to symbolically simplify the custom gate expressions used throughout the Barretenberg bigfield
implementation to ease the subsequent manual review of the simplified expressions.
Overview of Barretenberg Bigfield
The Barretenberg bigfield
module implements arithmetic of a prime field different from the native field of the circuit, i.e. it implements arithmetic using a (UltraPlonK) circuit over .
In particular, it can be used to emulate a prime field which is (somewhat) larger than the native field.
Within Barretenberg, bigfield
is primarily used inside the biggroup
module,
which implements constraints for elliptic curve operations over the emulated base field.
Applications of this includes verifying a Bn254-based SNARK inside a BN254-based SNARK, or checking secp256k1-based ECDSA signatures inside a Bn254-based SNARK.
How to Embed a Field
For context, let’s briefly outline the high-level strategy employed by the bigfield
module to emulate a foreign field .
Motivation. Because the foreign field is larger than the native field , it is not possible to “embed” an element of into ; representing it as an integer encoded in the native field. Furthermore, when we embed into another ring, we must ensure that all arithmetic operations can be executed without overflow: the ring is “large enough” to contain the result. As long as this is achieved, the prover can then non-deterministically reduce the representative modulo to enable further computation in the foreign field.
A Bigger Ring. To obtain a ring sufficiently large that this embedding is possible and to allow for executing all arithmetic operations without overflow, the Barretenberg bigfield
module lifts elements of the field into the ring , where is the modulus of the native field and is sufficiently large i.e. .
This ring enables emulation of integer arithmetic ()
as long as the elements involved are smaller than ; such that to reduction modulo occurs.
Emulation of is done by emulating arithmetic (on bounded integers) inside and non-deterministically reducing the result modulo (the prover witnesses the reduction and proves it correct).
CRT Decomposition. Since and are coprime, the integer ring above is isomorphic to the product
and the isomorphism is given by the Chinese Remainder Theorem (CRT).
Barretenberg bigfield
uses this to represent an element of using its CRT decomposition:
as a pair of elements in and .
This enables operating independently on the two components for much better performance.
Representing and computing on the -component is trivially achieved by using the native field arithmetic,
while the computation on the -component is achieved by decomposing into a set of small limbs such that limb-wise intermediate results never overflow the native field.
Bounds and Range Checks.
It might be immediate to the reader,
but a potential source of vulnerabilities in any such emulated field is “overflows”:
since the arithmetic is really done by emulating inside which itself is emulated inside using limb decomposition.
Issue could arise in which the arithmetic is satisfied in but not in and thus not in , or in which the emulation of is incorrect because a limb overflows the native field during emulated operations in .
To avoid such issues, Barretenberg bigfield
keeps track of the maximum sizes of all involved operands and intermediate results when generating constraints.
This approach allows Barretenberg to be “lazy” about enforcing reductions modulo ,
for instance allowing multiple additions to be performed before reducing the result modulo .