Unconnected Component Inputs Remediation
How to fix unconnected component inputs by wiring all sub-circuit inputs to parent signals using constraining assignments.
Unconnected Component Inputs Remediation
Overview
Related Detector: Unconnected Component Inputs
When a component is instantiated and its outputs are read but its inputs are not wired, the sub-circuit’s constraints are satisfied independently of the parent circuit. The prover controls the component’s outputs. The fix is to wire all component inputs using <==.
Recommended Fix
Before (Vulnerable)
template Broken() {
signal input data;
signal output hash;
component h = Poseidon(1);
// BUG: h.inputs[0] is never assigned
// The prover can set h.out to any valid Poseidon output
hash <== h.out;
}
After (Fixed)
template Fixed() {
signal input data;
signal output hash;
component h = Poseidon(1);
h.inputs[0] <== data; // input wired -- data is now bound to the hash
hash <== h.out; // output is determined by data
}
The constraining assignment h.inputs[0] <== data generates an R1CS equation that connects the parent signal data to the component’s input. Now Poseidon’s internal constraints bind h.out to data, and the prover cannot forge the hash.
Alternative Mitigations
1. Wire to a Constant
If the component input should be a fixed value:
component h = Poseidon(1);
h.inputs[0] <== 0; // constant input, constrained
hash <== h.out;
2. Wire to an Intermediate Signal
If the input is the result of a computation:
signal intermediate;
intermediate <== a + b;
component h = Poseidon(1);
h.inputs[0] <== intermediate; // wired via constrained intermediate
hash <== h.out;
3. Remove Unused Components
If the component is not needed, remove the instantiation entirely rather than leaving it disconnected:
// Before: unused component (wastes constraints in the R1CS)
component unused = Poseidon(1);
result <== input_signal;
// After: clean -- no wasted constraints
result <== input_signal;
Common Mistakes
Wiring inputs via <-- instead of <==: using h.inputs[0] <-- data assigns the value during witness generation but creates no constraint. The component will compute the correct output during proving, but the verifier has no guarantee that h.inputs[0] equals data. A malicious prover can substitute a different input. Always use <== for component wiring.
Partial wiring: if a component has multiple inputs and you wire only some of them, the unwired inputs are free variables. The prover can set them to any value. Wire all inputs, not just some.
// WRONG: only one of two inputs wired
component h = Poseidon(2);
h.inputs[0] <== data1;
// h.inputs[1] is never assigned -- prover controls it
hash <== h.out;
// CORRECT: all inputs wired
component h = Poseidon(2);
h.inputs[0] <== data1;
h.inputs[1] <== data2;
hash <== h.out;
Assuming default values: Circom does not initialize component inputs to zero. An unwired input is not zero — it is unconstrained. The prover provides whatever value satisfies the component’s constraints.
Leaving dead components in the circuit: even if a component’s outputs are never read, its constraints are still included in the R1CS. This wastes proving time and constraint rows. If you do not use a component, remove it.