Skip to content

perf(ecdsa-spartan2): skip R1CS loading during prove phase #80

@moven0831

Description

@moven0831

Problem

During the prove phase, Spartan2's SatisfyingAssignment::enforce() is a no-op — it ignores all constraint-enforcement calls (src/bellpepper/solver.rs:70-78):

fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, _a: LA, _b: LB, _c: LC) {
    // Do nothing: we don't care about linear-combination evaluations in this context.
}

Yet in both PrepareCircuit and ShowCircuit, the prove-phase code loads the full R1CS and iterates all constraints through circom_scotia::synthesize just to call that no-op:

// prepare_circuit.rs & show_circuit.rs — current prove-phase path
let witness = self.get_or_generate_witness()?;

match load_r1cs::<Scalar>(&self.r1cs_path()) {
    Ok(r1cs) => {
        synthesize(cs, r1cs, Some(witness))?;  // ← wasteful on native
    }
    Err(_) => {
        synthesize_witness_only(cs, &witness, num_public)?;  // ← efficient fallback
    }
}

On the native (non-WASM) path, load_r1cs succeeds, so it always takes the Ok(r1cs) branch. This wastes:

  • Memory: full R1CS struct held in RAM alongside the proving key
  • CPU: millions of LinearCombination allocations that go nowhere

Affected files

  1. wallet-unit-poc/ecdsa-spartan2/src/circuits/prepare_circuit.rs
  2. wallet-unit-poc/ecdsa-spartan2/src/circuits/show_circuit.rs

Proposed fix

The efficient synthesize_witness_only helper already exists in circuits/mod.rs — it does direct cs.alloc_input / cs.alloc calls. It's currently only used as a WASM/browser fallback. The fix is to always use it during prove:

// Replace the match block with:
let witness = self.get_or_generate_witness()?;
synthesize_witness_only(cs, &witness, num_public)?;
  • For PrepareCircuit: num_public comes from layout.num_public()
  • For ShowCircuit: num_public = 3

R1CS loading should only happen during setup (ShapeCS phase), where Spartan2 actually needs the constraint shape.

Expected impact

  • ~100–300 MB peak RSS reduction during prove (no R1CS struct in memory)
  • Significant prove-time reduction (no constraint iteration + LinearCombination allocations)
  • Setup phase unchanged — no impact on key generation

Reference

This optimization was implemented for the zkmopro/zkID fork in zkmopro/zkID#30, which applies the same pattern to Sha256RsaCircuit (RSA-SHA256 certificate verification).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions