npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

circomspect

v0.0.8

Published

A static analyzer and linter for the Circom zero-knowledge DSL

Downloads

5

Readme

Circomspect 🔎

This is a version of Circomspect by Trail Of Bits, compiled to WebAssembly by @antimatter15 and published as an NPM package. This is only an experiment and has not been adequately tested! This package is not officially endorsed or affiliated with Trail of Bits.

Circomspect is a static analyzer and linter for the Circom programming language. The codebase borrows heavily from the Rust Circom compiler built by iden3.

Circomspect currently implements a number of analysis passes which can identify potential issues in Circom circuits. It is our goal to continue to add new analysis passes to be able to detect more issues in the future.

Circomspect example image

NPM Package Changelog

  • 0.0.8 - Upgrading to (dev/version-0.8.0)
  • 0.0.7 - Upgrading to (dev/version-0.8.0)
  • 0.0.6 - Upgrading to (dev/version-0.8.0)
  • 0.0.3 - Initial package

Running Circomspect

To run Circomspect on a file or directory, simply run

  npx circomspect path/to/circuit

By default, Circomspect outputs warnings and errors to stdout. To see informational results as well you can set the output level using the --level option. To ignore certain types of results, you can use the --allow option together with the corresponding result ID. (The result ID can be obtained by passing the --verbose flag to Circomspect.)

To output the results to a Sarif file (which can be read by the VSCode Sarif Viewer), use the option --sarif-file.

VSCode example image

Circomspect supports the same curves that Circom does: BN128, BLS12-381, and Ed448-Goldilocks. If you are using a different curve than the default (BN128) you can set the curve using the command line option --curve.

Analysis Passes

The project currently implements analysis passes for the following types of issues.

Side-effect free assignments (Warning)

An assigned value which does not contribute either directly or indirectly to a constraint, or a function return value, typically indicates a mistake in the implementation of the circuit. For example, consider the following BinSum template from circomlib where we've changed the final constraint to introduce a bug.

  template BinSum(n, ops) {
      var nout = nbits((2 ** n - 1) * ops);
      var lin = 0;
      var lout = 0;

      signal input in[ops][n];
      signal output out[nout];

      var e2 = 1;
      for (var k = 0; k < n; k++) {
          for (var j = 0; j < ops; j++) {
              lin += in[j][k] * e2;
          }
          e2 = e2 + e2;
      }

      e2 = 1;
      for (var k = 0; k < nout; k++) {
          out[k] <-- (lin >> k) & 1;
          out[k] * (out[k] - 1) === 0;

          lout += out[k] * e2;  // The value assigned here is not used.
          e2 = e2 + e2;
      }

      lin === nout;  // Should use `lout`, but uses `nout` by mistake.
  }

Here, lout no longer influences the generated circuit, which is detected by Circomspect.

Shadowing variable declarations (Warning)

A shadowing variable declaration is a declaration of a variable with the same name as a previously declared variable. This does not have to be a problem, but if a variable declared in an outer scope is shadowed by mistake, this could change the semantics of the program which would be an issue.

For example, consider this function which is supposed to compute the number of bits needed to represent a.

  function numberOfBits(a) {
      var n = 1;
      var r = 0;  // Shadowed variable is declared here.
      while (n - 1 < a) {
          var r = r + 1;  // Shadowing declaration here.
          n *= 2;
      }
      return r;
  }

Since a new variable r is declared in the while-statement body, the outer variable is never updated and the return value is always 0.

Signal assignments using the signal assignment operator (Warning)

Signals should typically be assigned using the constraint assignment operator <==. This ensures that the circuit and witness generation stay in sync. If <-- is used it is up to the developer to ensure that the signal is properly constrained. Circomspect will try to detect if the right-hand side of the assignment is a quadratic expression. If it is, the signal assignment can be rewritten using the constraint assignment operator <==.

However, sometimes it is not possible to express the assignment using a quadratic expression. In this case Circomspect will try to list all constraints containing the assigned signal to make it easier for the developer (or reviewer) to ensure that the variable is properly constrained.

The Tornado Cash codebase was originally affected by an issue of this type. For details see the Tornado Cash disclosure here.

Branching statement conditions that evaluate to a constant value (Warning)

If a branching statement condition always evaluates to either true or false, this means that the branch is either always taken, or never taken. This typically indicates a mistake in the code which should be fixed.

Use of the non-strict versions of Num2Bits and Bits2Num from Circomlib (Warning)

Using Num2Bits and Bits2Num from Circomlib to convert a field element to and from binary form is only safe if the input size is smaller than the size of the prime. If not, there may be multiple correct representations of the input which could cause issues, since we typically expect the circuit output to be uniquely determined by the input.

For example, Suppose that we create a component n2b given by Num2Bits(254) and set the input to 1. Now, both the binary representation of 1 and the representation of p + 1 will satisfy the circuit over BN128, since both are 254-bit numbers. If you cannot restrict the input size below the prime size you should use the strict versions Num2Bits_strict and Bits2Num_strict to convert to and from binary representation. Circomspect will generate a warning if it cannot prove (using constant propagation) that the input size passed to Num2Bits or Bits2Num is less than the size of the prime in bits.

Overly complex functions or templates (Warning)

As functions and templates grow in complexity they become more difficult to review and maintain. This typically indicates that the code should be refactored into smaller, more easily understandable, components. Circomspect uses cyclomatic complexity to estimate the complexity of each function and template, and will generate a warning if the code is considered too complex. Circomspect will also generate a warning if a function or template takes too many arguments, as this also impacts the readability of the code.

Bitwise complement of field elements (Informational)

Circom supports taking the 256-bit complement ~x of a field element x. Since the result is reduced modulo p, it will typically not satisfy the expected relations (~x)ᵢ == ~(xᵢ) for each bit i, which could lead to surprising results.

Field element arithmetic (Informational)

Circom supports a large number of arithmetic expressions. Since arithmetic expressions can overflow or underflow in Circom it is worth paying extra attention to field arithmetic to ensure that elements are constrained to the correct range.

Field element comparisons (Informational)

Field elements are normalized to the interval (-p/2, p/2] before they are compared, by first reducing them modulo p and then mapping them to the correct interval by subtracting p from the value x, if x is greater than p/2. In particular, this means that p/2 + 1 < 0 < p/2 - 1. This can be surprising if you are used to thinking of elements in GF(p) as unsigned integers.