You like Circom but you find it confusing? Introducing Circomscribe


If you’ve been working in the field of zero-knowledge in the last few years you must have heard of Circom, a tool to write zero-knowledge applications in the form of circuits. Many projects have used Circom, that is the least one could say, as perhaps most ZK projects that have been built as smart contracts directly on Ethereum have been built using Circom; the most infamous project probably being TornadoCash.

While Circom has been great for developers wishing to explore usecases brought by zero-knowledge proofs, it is an extremely low-level tool, and it has proven to be quite hard to use correctly. One could almost say that if you don’t understand how circuits (or proof systems) work at a low-level, you’re going to run into trouble.

circom program example

As part of auditing ZK applications, zkSecurity has gone through its fair share of Circom circuits audits, and has realized that one of the biggest source of bugs (besides human error) is that developers have little idea of how their code eventually gets transcribed into “constraints” by the Circom compiler. In a way, it is similar to not being able to see the assembly your code compiles to, and as such making wrong assumptions sometimes.

While many more user-friendly and secure zk platforms and tools are making their way in (including our own in-house noname), the ecosystem of today is still very much based on Circom. So what can we do about this?

I say: let’s improve everyone’s understanding of how their Circom code gets compiled down to constraints! The more we educate developers, the less bugs they will write. To achieve this, we’d like to introduce Circomscribe.

Circomscribe is a tool that shows you what Circom does with your code. Simple as that. Paste your complete circuit in the tool, press a button, and quickly get an idea of what lines of code produce what constraints (if any).

For example, here’s the analysis of the Num2Bits template (which converts a value to a list of bits) taken directly from circomlib, the standard library of Circom:


As you can see, only the lines of code that are highlighted on the left produce constraints. These constraints are “pure” constraints, which is what the compiler produces before actually unrolling the circuit (for example, if a template is used several times) and before any optimizations are performed. So in a sense, this is purely useful to understand the first pass of the compiler, but not useful to see what the actual compiled circuit looks like.

Underneath, Circomscribe is essentially a modified version of the Circom compiler to run in WASM and emit information in a JSON format when compiling. As of now, the Circomscribe tool provides simple features that we hope will be useful to developers and other security engineers. We hope to add more features in the future. If you have any ideas, please let us know!