Skip to main content
Sigvex

Template Misuse Remediation

How to fix incorrect template instantiation patterns including parameter mismatches and unconstrained wiring.

Template Misuse Remediation

Overview

Related Detector: Template Misuse

Template misuse covers three patterns: parameter mismatches (e.g., LessThan(8) used on 256-bit values), unused template outputs, and unconstrained template inputs. Each pattern silently degrades security without causing compilation errors. The fix depends on the specific misuse pattern.

Parameter Mismatch (Before / After)

// Before: LessThan(8) only valid for values < 256
template UnsafePriceCheck() {
    signal input price;     // Could be up to 2^64
    signal input maxPrice;

    component lt = LessThan(8);  // WRONG: 8 bits, max value 255
    lt.in[0] <== price;
    lt.in[1] <== maxPrice;
    lt.out === 1;
}

// After: Match parameter to actual data size
template SafePriceCheck() {
    signal input price;
    signal input maxPrice;

    component lt = LessThan(64);  // CORRECT: 64 bits for price values
    lt.in[0] <== price;
    lt.in[1] <== maxPrice;
    lt.out === 1;
}

Unused Template Output (Before / After)

// Before: Hash output is never used
template UnsafeVerifier() {
    signal input a, b;
    component hash = Poseidon(2);
    hash.inputs[0] <== a;
    hash.inputs[1] <== b;
    // hash.out is never read -- wasted computation, possible logic error
}

// After: Use or remove the component
template SafeVerifier() {
    signal input a, b;
    signal output commitment;

    component hash = Poseidon(2);
    hash.inputs[0] <== a;
    hash.inputs[1] <== b;
    commitment <== hash.out;  // Output is used
}

Unconstrained Template Input (Before / After)

// Before: Input wired via <--
component rangeCheck = Num2Bits(64);
rangeCheck.in <-- amount;  // BROKEN: unconstrained wiring

// After: Input wired via <==
component rangeCheck = Num2Bits(64);
rangeCheck.in <== amount;  // CORRECT: constrained wiring

Alternative Mitigations

1. Wrapper Templates with Parameter Validation

Create wrapper templates that document and enforce parameter requirements:

// Wrapper that makes the bit width requirement explicit
template SafeLessThan(nBits) {
    signal input in[2];
    signal output out;

    // Range check inputs to nBits before comparison
    component check0 = Num2Bits(nBits);
    check0.in <== in[0];
    component check1 = Num2Bits(nBits);
    check1.in <== in[1];

    component lt = LessThan(nBits);
    lt.in[0] <== in[0];
    lt.in[1] <== in[1];
    out <== lt.out;
}

2. Assertion Comments for Parameter Choices

Document why specific parameters are chosen, so reviewers can verify correctness:

// Price values are at most 2^64 - 1 (validated by input range check above)
component lt = LessThan(64);

Common Mistakes

Using a small bit width for “efficiency”: Smaller bit widths produce fewer constraints, but using a bit width smaller than the actual data size produces incorrect results for large values. Correctness must take priority.

Assuming unused outputs are harmless: An unused component output may indicate a logic error – the developer may have intended to use it in a constraint. Review whether the component is necessary.

Wiring inputs with <-- “because the value is correct”: The value may be correct during honest witness generation, but the constraint is what prevents a malicious prover from substituting a different value.

References