Documentation

CsdLean4.Mathlib.QuantumInfo.Reversible.ModReduceCtrl

Reversible modular reduction — the complete single-step reduce circuit (ECDLP Phase 2, Stage S6.3a) #

Category: 1-Mathlib (CSD-free; staged as a Mathlib-upstream candidate).

S4 (ModReduce.lean) verified the comparison-as-carry-out primitive and the x ≥ N reduce value (rippleCirc_modReduce_ge), but left the flag-controlled wrapper and the x < N branch as documented cost, not as an exhibited circuit (ResourceBounds.modReduceToffoli is a documented estimate, not derived from a reduce circuit). This module closes that residue: it exhibits and proves the complete single-step modular reduction circuit, both branches, from already-verified primitives only.

The circuit (modReduce) #

For x in register B with x < 2N (and x < 2ⁿ, N ≤ 2ⁿ):

modReduce L = rippleCirc L1 ++ [Gate.X flag] ++ cRippleCirc L2

The arithmetic (verified in modReduce_correct):

What is NEW vs S4 #

S4's rippleCirc_modReduce_ge handled only the x ≥ N branch and no control — the reduce was the bare adder, correct only when a subtract was actually needed. This module does both branches in one reversible pass, with the comparison flag controlling the conditional add-back via S2's cRippleCirc. So: comparison VERIFIED (S4), x ≥ N reduce VERIFIED (S4), and now the flag-controlled wrapper + the x < N identity branch are exhibited circuits, VERIFIED (S6.3a) — the documented residue of S4 §"Documented residue" is closed.

Honest cost #

modReduceCtrl_toffoli derives 2n + 8n = 10n Toffolis from the exhibited gate list (step-1 ripple 2n, the X flip 0, step-3 controlled ripple 8n via cRippleCirc_toffoli). This is heavier than S4's documented estimate modReduceToffoli n = 4n: the controlled add-back is 8n (the quantum×quantum overhead of S2, the 2n of an uncontrolled add), not the ~2n an idealised in-place subtract would suggest. That is the honest cost of a verified reduction (compare-and- conditional-subtract, both branches, in the 2-control DSL) versus S4's documented uncontrolled-add estimate.

Remaining residue (named, not built) #

  1. Cleanup / reversibility (S6.3b concern). The comparison flag C1 n is left holding decide (x < N), the step-1 carry chain C1 holds garbage, and C2/anc are restored clean by cRippleCirc but C1/flag are not uncomputed. The value correctness of B holds regardless (modReduce_correct), but in-place reuse inside a multiply needs the standard recompute-and-uncompute of the flag and step-1 carries. Naming, not building, that uncompute pass here.
  2. Full product reduction. A 2w-bit product (x up to ~N²) is reduced by the multi-step / interleaved schedule that keeps the accumulator < 2N and applies this primitive each step. This module is the single-step (x < 2N) primitive that schedule iterates; the full modular multiply is S6.3b.

A single-step modular-reduction layout on Fin m for n-bit registers. Bundles:

  • B — the data register (holds x, overwritten with x mod N);
  • A1 — the step-1 constant register (preset to 2ⁿ − N), with fresh carry chain C1 (whose output wire C1 n is the comparison flag);
  • A2 — the step-3 constant register (preset to N), with a second fresh carry chain C2;
  • anc — the shared clean ancilla for the controlled add-back.

The fields are pure wire geometry (pairwise disjointness + per-range bounded injectivity), mirroring the RippleLayout/CRippleLayout discipline. The injectivity fields are bounded (< n for registers, < n + 1 for carry chains) exactly as MulLayout/CMulLayout — an unbounded ℕ → Fin m injectivity field is uninhabitable and would make the theorem vacuous.

  • B : Fin m

    Data register: holds x, overwritten with x mod N.

  • A1 : Fin m

    Step-1 constant register (preset to 2ⁿ − N).

  • C1 : Fin m

    Step-1 carry chain; C1 n is the comparison flag (the control of step 3).

  • A2 : Fin m

    Step-3 constant register (preset to N).

  • C2 : Fin m

    Step-3 carry chain (distinct from C1).

  • anc : Fin m

    Shared clean ancilla for the controlled add-back.

  • hBA1 (i j : ) : self.B i self.A1 j
  • hBC1 (i j : ) : self.B i self.C1 j
  • hA1C1 (i j : ) : self.A1 i self.C1 j
  • hBinj (i j : ) : i < nj < nself.B i = self.B ji = j
  • hA1inj (i j : ) : i < nj < nself.A1 i = self.A1 ji = j
  • hC1inj (i j : ) : i < n + 1j < n + 1self.C1 i = self.C1 ji = j
  • hBA2 (i j : ) : self.B i self.A2 j
  • hBC2 (i j : ) : self.B i self.C2 j
  • hA2C2 (i j : ) : self.A2 i self.C2 j
  • hA2inj (i j : ) : i < nj < nself.A2 i = self.A2 ji = j
  • hC2inj (i j : ) : i < n + 1j < n + 1self.C2 i = self.C2 ji = j
  • hflagA2 (j : ) : self.C1 n self.A2 j
  • hflagB (j : ) : self.C1 n self.B j
  • hflagC2 (j : ) : self.C1 n self.C2 j
  • hflaganc : self.C1 n self.anc
  • hancA2 (j : ) : self.anc self.A2 j
  • hancB (j : ) : self.anc self.B j
  • hancC2 (j : ) : self.anc self.C2 j
  • hA2A1 (i j : ) : self.A2 i self.A1 j
  • hA2C1 (i j : ) : self.A2 i self.C1 j
  • hC2A1 (i j : ) : self.C2 i self.A1 j
  • hC2C1 (i j : ) : self.C2 i self.C1 j
  • hancA1 (j : ) : self.anc self.A1 j
  • hancC1 (j : ) : self.anc self.C1 j
Instances For

    Step 1 as a RippleLayout: register A1 + data B + carry chain C1.

    Equations
    • L.stepOne = { A := L.A1, B := L.B, C := L.C1, hAB := , hAC := , hBC := , hAinj := , hBinj := , hCinj := }
    Instances For

      Step 3 as a CRippleLayout: register A2 + data B + carry chain C2, controlled on the flag C1 n, with the shared ancilla.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        The single-step modular-reduction circuit. rippleCirc (add complement 2ⁿ − N, produce the comparison flag) ++ [X flag] (flip flag to x < N) ++ cRippleCirc (controlled add-back of N).

        Equations
        Instances For

          Frame: step-3 inputs survive steps 1 and 2 #

          Step 1 (rippleCirc L.stepOne) touches only {A1 k, B k, C1 k} and step 2 (X (C1 n)) only {C1 n}. The step-3 carry chain C2, constant A2, and ancilla anc are disjoint from those, so their values pass through steps 1 + 2 unchanged.

          theorem Reversible.modReduce_stepTwo_preserves_B {m n : } {L : ModReduceLayout m n} (s : State m) (j : ) :
          denoteGate (Gate.X (L.C1 n)) s (L.B j) = s (L.B j)

          The data-register window B is untouched by the flag flip (step 2): C1 n ≠ B j.

          theorem Reversible.modReduce_steps12_preserves_C2 {m n : } {L : ModReduceLayout m n} (s : State m) (j : ) :
          denoteGate (Gate.X (L.C1 n)) (denote (rippleCirc L.stepOne) s) (L.C2 j) = s (L.C2 j)

          Steps 1 + 2 leave the step-3 carry chain C2 j at its initial value.

          theorem Reversible.modReduce_steps12_preserves_A2 {m n : } {L : ModReduceLayout m n} (s : State m) (j : ) :
          denoteGate (Gate.X (L.C1 n)) (denote (rippleCirc L.stepOne) s) (L.A2 j) = s (L.A2 j)

          Steps 1 + 2 leave the step-3 constant register A2 j at its initial value.

          Steps 1 + 2 leave the shared ancilla anc at its initial value.

          Value correctness, both branches #

          theorem Reversible.modReduce_correct {m n : } (L : ModReduceLayout m n) (s : State m) (hC1 : ∀ (j : ), s (L.C1 j) = false) (hC2 : ∀ (j : ), s (L.C2 j) = false) (hanc : s L.anc = false) {N : } (hN : N 2 ^ n) (hA1 : regValRange L.A1 s n = 2 ^ n - N) (hA2 : regValRange L.A2 s n = N) (hx2N : regValRange L.B s n < 2 * N) :

          The complete single-step modular reduction — both branches, verified from the exhibited circuit. For a disjoint-wire ModReduceLayout with the step-1 carry chain C1, the step-3 carry chain C2, and the ancilla anc all initialised false, register A1 preset to 2ⁿ − N, register A2 preset to N, and data B holding x with N ≤ 2ⁿ, x < 2ⁿ, x < 2N: the circuit modReduce L leaves B holding x mod N.

          Proof. Step 1 (rippleCirc_correct) writes (x + 2ⁿ − N) mod 2ⁿ to B and sets the flag C1 n = decide (N ≤ x) (rippleCirc_carryout); step 2 flips it to decide (x < N); step 3 (cRippleCirc_correct) adds N back iff the flag is set. The two branches:

          • x ≥ N (flag clear): step-1 value (x + 2ⁿ − N) mod 2ⁿ = x − N (N ≤ x < 2ⁿ), and x − N = x mod N (mod_eq_sub_of_le_of_lt_two_mul); add-back skipped.
          • x < N (flag set): step-1 value x + 2ⁿ − N (no wrap, x < N ≤ 2ⁿ), then + N mod 2ⁿ = (x + 2ⁿ) mod 2ⁿ = x = x mod N.

          This closes S4's documented residue: comparison + conditional-subtract + both branches, derived from circuits, not documented.

          theorem Reversible.modReduce_in_range {m n : } (L : ModReduceLayout m n) (s : State m) (hC1 : ∀ (j : ), s (L.C1 j) = false) (hC2 : ∀ (j : ), s (L.C2 j) = false) (hanc : s L.anc = false) {N : } (hNpos : 0 < N) (hN : N 2 ^ n) (hA1 : regValRange L.A1 s n = 2 ^ n - N) (hA2 : regValRange L.A2 s n = N) (hx2N : regValRange L.B s n < 2 * N) :

          The reducer output is a genuine residue in [0, N). A direct corollary of modReduce_correct and Nat.mod_lt: the property a modular reducer must have.

          Derived cost #

          Derived Toffoli cost of the single-step reduce circuit: 10n Toffolis, from the exhibited gate list. Step 1 (rippleCirc) is 2n (rippleAdder_toffoli-style, here read via the same ripple count), the X flip is 0, and step 3 (cRippleCirc) is 8n (cRippleCirc_toffoli); composed through the Tranche-1 additivity cost_comp_toffoli_count. This is heavier than S4's documented modReduceToffoli n = 4n: the verified controlled add-back costs 8n (the quantum×quantum overhead of S2, an uncontrolled add), the honest price of an exhibited both-branch reduction.

          Non-vacuity witness #

          A concrete 2-bit reduce layout on Fin 13:

          This exhibits that ModReduceLayout is inhabited (the bounded-injectivity bundle is satisfiable), so the headlines are not vacuously quantified. The concrete computations below run the reducer on n = 2, N = 3 at two fully-specified input states, checking x = 3 ↦ 0 (the x ≥ N subtract branch) and x = 2 ↦ 2 (the x < N identity branch). [The spec's illustrative x = 5 ↦ 2 needs n = 3: 5 < 2³ = 8; at n = 2, x < 2² = 4, so 5 is not representable in two wires.]

          A concrete 2-bit reduce layout on Fin 13.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For

            Interface lemmas (CONVENTIONS §9.1, F1): the wire assignments of the concrete layout, one lemma per field.

            modReduceLayout2's data-register wires.

            modReduceLayout2's step-1 constant-register wires.

            modReduceLayout2's step-1 carry-chain wires.

            modReduceLayout2's step-3 constant-register wires.

            modReduceLayout2's step-3 carry-chain wires.

            Concrete input state for n = 2, N = 3: data B = x (wires 0,1), A1 = 1 = 2² − 3 (wire 2), A2 = 3 (wires 7,8), all carries / ancilla false. Parameterised by the two data bits b0, b1 of x.

            Equations
            Instances For

              The hypotheses of modReduce_correct hold at modReduceState2 b0 b1 (carries/ancilla clear, A1 = 1, A2 = 3), for any data bits. The regValRange register-value preconditions are concrete sums, discharged by decide.