Skip to main content


From a user perspective, a circuit is like a program, which can be written in a programming language like Go. However, internally a circuit is a constraint system; that is, a list of constraints which have an algebraic form.

For Groth16, a constraint looks like (iaixi)(ibiyi)=icizi(\sum_ia_ix_i)(\sum_ib_iy_i)=\sum_ic_iz_i where a,b,ca,b,c are constants and x,y,zx,y,z are variables which depend on the secret inputs known by a prover.

Translating a circuit, written with gnark API to such a constraint system is called the "arithmetization" of a circuit.

An important point is that every component of a constraint (variables, inputs and constants) live in Fp\mathbb{F}_p, a finite field of characteristic pp. To write a circuit which contains a reasonable number of constraints, it is important to work on the field Fp\mathbb{F}_p, so that the field in which the circuits variables live is the same as the field on which the constraint system reasons.

On the other hand, a circuit reasoning on variables which live in Fr\mathbb{F}_r where rpr\neq p, has a high number of constraints because of the algebraic constraints needed to emulate the arithmetic modulo rr on a field of characteristic pp.

Finally, the number of constraints in a circuit is limited; you cannot write arbitrarily large circuits. For example, using Groth16 on BN254, you cannot exceed ~250M250M constraints.