Skip to main content

Underconstrained Outputs (uc-outputs)

Summary and Usage

The Underconstrained Output (UCO) detector finds underconstrained output vulnerabilities in ZK circuit code. The UCO detector looks to see if a used output from a component is constrained either by an input value or a single constant value; if neither is true, then the output is not constrained and can result in a vulnerability, as a malicious actor may be able to create valid proofs for bogus statements when outputs are underconstrained.

Usage

The UCO detector is invoked by selecting "Underconstrained outputs" (uc-outputs) in the Detector selection during the tool configuration step.

Example and Explanation

The following toy example is designed to determine if the lowest bit of the input signal inp is 1. If (inp & 1) = 1, then outp should be 1, and otherwise, outp should be 0.

uc_outputs_bug.circom
pragma circom 2.1.8;

template LowestBitIsOne() {
signal input inp;
signal output outp;

outp <-- inp & 1;
outp * (outp - 1) === 0;
}

component main = LowestBitIsOne();

In this example, outp is assigned to inp & 1, but is not constrained by the input inp, which is flagged as a UCO bug. While the outp * (outp - 1) === 0 constraint does constrain the outp signal to a boolean value per the overall design of the circuit, the constraint may be satisfied by the assignment outp = 0 or outp = 1 regardless of the value of inp, allowing the attacker to forge arbtrary proofs of the form {inp = <any value>, outp = <0 or 1>}.

Usage Example

Running the UCO detector yields the following text output log:

ZK Vanguard Output
----Running Vanguard with uc-outputs detector----
Running detector: uc-outputs
[Critical] Underconstrained output signal in component LowestBitIsOne @ uc_outputs_bug.circom:3
Reported By: vanguard:uc-outputs
Location: LowestBitIsOne @ uc_outputs_bug.circom:3
Confidence: 0.99
More Info: placeholder
Details:
In template LowestBitIsOne @ uc_outputs_bug.circom:3
* Signal outp

Line 3 of the above log tells us there is an underconstrained output signal in the LowestBitIsOne template (defined in uc_outputs_bug.circom starting on line 3). Lines 9–10 of the log tell us that outp is the underconstrained output signal.

Limitations

  • This detector may incur false positives if the output signal is designed to be constant constrained, but that constant is computed within the circuit (e.g., the output signal is a hash of a constant value).
  • This detector will fail to detect issues where, e.g., an output signal is constrained by an input, but should be constrained by multiple inputs.

Assessing Severity

It is generally rare for output signals to not be a function of input signals or constants, so findings from this detector often indicate severe issues where key computations and constraints have been accidentally omitted. These findings are therefore