Documentation

CsdLean4.Mathlib.QuantumInfo.Reversible.ModularMulLoop

Reversible interleaved modular multiply β€” the general-n Horner LOOP (ECDLP Phase 2, Stage S6.3d-2b) #

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

This module delivers the verified general-n interleaved MSB-first modular multiply over 𝔽_p, folding the verified Horner loop body (hornerStep, S6.3d-2a) over all n bits of the multiplier X to leave the accumulator holding X Β· Y mod N. It is the capstone of the modular-arithmetic chain: the verified field-multiply atom ⟦c⟧ = (Β· * Yval) mod N an exhibited EC point op would call.

mulLoop L = ((List.range n).map (fun j => hornerStep (L.bank j))).flatMap id

processing bits MSB-first: loop index j = 0, …, n-1 runs hornerStep on bank j, whose control is bound to X (n-1-j) β€” the (n-1-j)-th bit of the multiplier. Each body is one verified Horner step acc ← (2Β·acc + [X_{n-1-j}]Β·Y) mod N (hornerStep_correct). The banks share the accumulator B and the multiplicand Y; every other wire of each bank is FRESH and disjoint (the Θ(nΒ²)-ancilla fresh-wire model inherited from S6.3d-1 / S6.3c).

The invariant (induction over the processed-bank prefix) #

After processing banks [0, …, k-1] from acc = 0, the accumulator holds hornerVal k Β· Yval mod N, where hornerVal k is the top-k-bits-of-X MSB-first reconstruction (hornerVal 0 = 0, hornerVal (k+1) = 2Β·hornerVal k + bit (n-1-k)). The step k β†’ k+1 is exactly the per-step reasoning of mulStep2_correct: hornerStep_correct on bank k maps (hornerVal k Β· Yval) mod N to ((2Β·hornerVal k + bit)Β·Yval) mod N = (hornerVal (k+1) Β· Yval) mod N; hornerStep_preserves_Y keeps Y; hornerStep_preserves_external keeps the later banks' wires clean and the not-yet-read X bits intact. The bridge hornerVal n = Xval (hornerVal_full) closes it.

Carve line (what this is, and is NOT) #

This is the VERIFIED modular field-multiply X Β· Y mod N β€” the ⟦c⟧ = op payoff of the S6.3 Option-1 route β€” composing the verified Horner step (S6.3d-2a) over all n bits.

Named residue:

  1. Fresh per-iteration wires ⟹ Θ(n²) qubits + Θ(n²) Toffoli. Each of the n Horner steps is supplied its OWN doubling scratch / carries / ancilla and controlled-add carries / ancilla, disjoint from every other step's. This is the honest fresh-ancilla cost. In-place reuse (Θ(n) qubits) needs the carry-clean / ancilla-restoring adder the corpus does NOT yet provide (Cuccaro-style inline carry-uncompute, or the self-cleaning high-bit modular adder). That carry-clean adder is the genuine orthogonal residue.
  2. This is NOT the EC point operation. It is the verified modular MULTIPLY over registers (X Β· Y mod N), β„• / mod N bit arithmetic β€” no field / group semantics. Assembling these field-multiplies into the full elliptic-curve point op (point add / double) is S6.3e+, NOT built here. And this is the Θ(nΒ²)-qubit version, not the optimised in-place one.

Honest cost #

mulLoop_toffoli derives 30 * nΒ² Toffolis: n Horner steps, each 30n (hornerStep_toffoli), composed through cost_comp_toffoli_count over the fold (multiplier_toffoli).

The Horner reconstruction value (pure β„•) #

hornerVal bits n k is the top-k-bits MSB-first reconstruction of the n-bit number whose bits are bits 0, …, bits (n-1) (each bits i ∈ {0,1} for the intended use, but the lemmas hold for any bits). The bridge hornerVal_full (hornerVal bits n n = βˆ‘_{i<n} bits i Β· 2^i) lets the loop's per-step recurrence land on the full multiplier value.

def Reversible.hornerVal (bits : β„• β†’ β„•) (n : β„•) :
β„• β†’ β„•

Top-k-bits MSB-first reconstruction: hornerVal bits n 0 = 0, hornerVal bits n (k+1) = 2 Β· hornerVal bits n k + bits (n-1-k).

Equations
Instances For
    @[simp]
    theorem Reversible.hornerVal_zero (bits : β„• β†’ β„•) (n : β„•) :
    hornerVal bits n 0 = 0
    theorem Reversible.hornerVal_succ (bits : β„• β†’ β„•) (n k : β„•) :
    hornerVal bits n (k + 1) = 2 * hornerVal bits n k + bits (n - 1 - k)
    theorem Reversible.hornerVal_aux (bits : β„• β†’ β„•) (n k : β„•) :
    k ≀ n β†’ hornerVal bits n k * 2 ^ (n - k) + βˆ‘ i ∈ Finset.range (n - k), bits i * 2 ^ i = βˆ‘ i ∈ Finset.range n, bits i * 2 ^ i

    The Horner-reconstruction bridge (auxiliary, all prefixes). For k ≀ n, the top-k-bits reconstruction times 2^(n-k), plus the bottom n-k bits in place value, is the full value.

    theorem Reversible.hornerVal_full (bits : β„• β†’ β„•) (n : β„•) :
    hornerVal bits n n = βˆ‘ i ∈ Finset.range n, bits i * 2 ^ i

    The Horner-reconstruction bridge. The full n-bit MSB-first reconstruction equals the place-value sum βˆ‘_{i<n} bits i Β· 2^i. Specialised from hornerVal_aux at k = n.

    theorem Reversible.regValRange_eq_hornerVal_bits {m : β„•} (X : β„• β†’ Fin m) (s : State m) (n : β„•) :
    regValRange X s n = hornerVal (fun (i : β„•) => if s (X i) = true then 1 else 0) n n

    The control-bit indicator bit i = if s (X i) then 1 else 0, as a β„•. The place-value sum of these indicators over [0, n) is exactly regValRange X s n.

    The n-bank multiply-loop layout #

    A MulLoopLayout bundles n per-bit HornerStepLayout banks (bank j, S6.3d-2a), all sharing the accumulator B ((bank j).B = B) and the multiplicand Y ((bank j).Y = Y), with bank j's control bound to X (n-1-j) (MSB-first). The inter-bank geometry needed to fold the steps β€” bank j's circuit must not touch any of bank k's clean / preset wires (k β‰  k), nor the not-yet-read control bits β€” is carried by the membership-based footprints Touches / Clean and the single disjointness field hInter. This is bounded and inhabitable for every n (no unbounded β„• β†’ Fin m injectivity field): the witness assigns each bank a disjoint contiguous block of fresh wires and discharges hInter / hCtrl* by omega, and Touches/Clean are decidable finite disjunctions over the 18/14 families.

    Touches L j w holds iff w is one of bank j's 18 touched wire families; Clean L k w iff w is one of bank k's 14 clean/preset families (the ones whose initial value bank k's hornerStep_correct reads). The field hInter says: for j β‰  k, a clean wire of bank k is not touched by bank j β€” which is exactly what hornerStep_preserves_external needs to transport bank k's preconditions through bank j's step.

    def Reversible.Touches {m n : β„•} (L : β„• β†’ HornerStepLayout m n) (j : β„•) (w : Fin m) :

    The 18 wire families bank j's hornerStep circuit touches (writes or reads), as a membership predicate over wires. (The doubling block's B is the shared accumulator, listed once via add.B.)

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For
      def Reversible.Clean {m n : β„•} (L : β„• β†’ HornerStepLayout m n) (k : β„•) (w : Fin m) :

      The 14 wire families bank k's hornerStep_correct reads as a clean / preset precondition: the doubling scratch / carries / ancilla / presets and the controlled-add carries / ancilla / presets. (The shared B, Y and the control bit are handled separately.)

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

        An n-bank modular-multiply loop layout on Fin m. The n banks share B and Y; bank j's control is X (n-1-j); bank j does not touch bank k's clean wires for k β‰  j (hInter), nor any control bit X i other than its own (hCtrlTouch), and X/B/Y registers are injective on [0,n). All hypotheses are bounded (< n), so the schema is inhabitable for every n.

        • bank : β„• β†’ HornerStepLayout m n

          The n per-bit Horner-step banks (bank j processes bit n-1-j).

        • X : β„• β†’ Fin m

          Shared multiplier (control) register X; bank j reads bit X (n-1-j).

        • hBshare (j j' : β„•) : (self.bank j).B = (self.bank j').B

          Sharing: every bank acts on the same accumulator B.

        • hYshare (j j' : β„•) : (self.bank j).Y = (self.bank j').Y

          Sharing: every bank reads the same multiplicand Y.

        • hctrl (j : β„•) : (self.bank j).ctrl = self.X (n - 1 - j)

          Bank j's control bit is X (n-1-j).

        • hInter (j k : β„•) (w : Fin m) : j < n β†’ k < n β†’ j β‰  k β†’ Clean self.bank k w β†’ Β¬Touches self.bank j w

          Inter-bank disjointness: for j β‰  k, bank j's circuit does not touch bank k's clean wires.

        • hCtrlTouch (j i : β„•) : j < n β†’ i < n β†’ i β‰  n - 1 - j β†’ Β¬Touches self.bank j (self.X i)

          Bank j's circuit does not touch the control bit X i unless i = n-1-j (its own).

        • hXinj (i i' : β„•) : i < n β†’ i' < n β†’ self.X i = self.X i' β†’ i = i'

          The control register is injective on [0, n).

        Instances For
          def Reversible.MulLoopLayout.B {m n : β„•} (L : MulLoopLayout m n) :
          β„• β†’ Fin m

          The shared accumulator register (B of bank 0).

          Equations
          Instances For
            def Reversible.MulLoopLayout.Y {m n : β„•} (L : MulLoopLayout m n) :
            β„• β†’ Fin m

            The shared multiplicand register (Y of bank 0).

            Equations
            Instances For
              theorem Reversible.notTouches_preserved {m n : β„•} (L : MulLoopLayout m n) (j : β„•) (s : State m) (w : Fin m) (hw : Β¬Touches L.bank j w) :
              denote (hornerStep (L.bank j)) s w = s w

              A wire not touched by bank j survives bank j's Horner step. (The Touches predicate lists exactly the 18 families hornerStep_preserves_external requires disjointness from.)

              theorem Reversible.bank_step_preserves_clean {m n : β„•} (L : MulLoopLayout m n) (j k : β„•) (hj : j < n) (hk : k < n) (hjk : j β‰  k) (s : State m) (w : Fin m) (hw : Clean L.bank k w) :
              denote (hornerStep (L.bank j)) s w = s w

              A clean wire of bank k survives bank j's Horner step (j β‰  k, both < n): by hInter it is not touched, so notTouches_preserved applies. The 14 Clean-membership constructors are unfolded at each call site (the mulLoop_invariant step transports bank k's preconditions through bank j).

              theorem Reversible.horner_mod_step (H Yval N : β„•) (b : Bool) :
              (2 * (H * Yval % N) + if b = true then Yval else 0) % N = (2 * H + if b = true then 1 else 0) * Yval % N

              The Horner arithmetic step. Folding one MSB-first Horner digit through the running residue: (2Β·((HΒ·Y) mod N) + [bit]Β·Y) mod N = ((2Β·H + [bit])Β·Y) mod N, i.e. the value hornerStep_correct produces from c = (HΒ·Y) mod N is (hornerVal-next Β· Y) mod N. (Nat.add_mod / Nat.mul_mod absorb the inner reduction; the if is the 0/1 digit.)

              The general-n multiply loop and its correctness #

              The general-n modular-multiply loop. Process the multiplier bits MSB-first: bank j (j = 0, …, n-1) runs one verified Horner step acc ← (2Β·acc + [X_{n-1-j}]Β·Y) mod N. The banks share the accumulator B and the multiplicand Y; every other wire is fresh.

              Equations
              Instances For

                The first k banks of the loop (prefix [0, …, k-1]), the induction handle for mulLoop.

                Equations
                Instances For
                  @[simp]

                  Split the prefix at its last bank: mulLoopUpto L (k+1) = mulLoopUpto L k ++ hornerStep (bank k) (bank k runs LAST). From List.range_succ.

                  theorem Reversible.mulLoopUpto_preserves {m n : β„•} (L : MulLoopLayout m n) (k : β„•) (s : State m) (w : Fin m) (hw : βˆ€ j < k, Β¬Touches L.bank j w) :
                  denote (mulLoopUpto L k) s w = s w

                  Prefix frame. A wire not touched by any bank j < k survives the whole prefix mulLoopUpto L k (fold of notTouches_preserved).

                  Preservation of bank k's preconditions through the prefix #

                  Every clean / preset wire of bank k lies in Clean L.bank k, so (for k ≀ n and the prefix length ≀ k) it is untouched by every earlier bank j < k (hInter) and survives mulLoopUpto. The control bit X (n-1-k) survives via hCtrlTouch. These are the lemmas the invariant's step consumes.

                  theorem Reversible.clean_pres {m n : β„•} (L : MulLoopLayout m n) {k p : β„•} (hk : k < n) (hpk : p ≀ k) (s : State m) (w : Fin m) (hw : Clean L.bank k w) :
                  denote (mulLoopUpto L p) s w = s w
                  theorem Reversible.clean_pres_reg {m n : β„•} (L : MulLoopLayout m n) {k p : β„•} (hk : k < n) (hpk : p ≀ k) (s : State m) (f : β„• β†’ Fin m) (hf : βˆ€ (i : β„•), Clean L.bank k (f i)) (q : β„•) :
                  theorem Reversible.mulLoop_invariant {m n : β„•} (L : MulLoopLayout m n) (s : State m) {N Yval : β„•} (h2N : 2 * N ≀ 2 ^ n) (hNpos : 0 < N) (hYN : Yval < N) (hB0 : regValRange L.B s n = 0) (hYv : regValRange L.Y s n = Yval) (hcleanAop : βˆ€ (j i : β„•), j < n β†’ i < n β†’ s ((L.bank j).dbl.Aop i) = false) (hcleanCadd : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.Cadd i) = false) (hcleandC1 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.C1 i) = false) (hcleandC2 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.C2 i) = false) (hcleandanc : βˆ€ j < n, s (L.bank j).dbl.addLayout.anc = false) (hcleanCcadd : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.Ccadd i) = false) (hcleanancC : βˆ€ j < n, s (L.bank j).add.ancC = false) (hcleanC1 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.C1 i) = false) (hcleanC2 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.C2 i) = false) (hcleananc : βˆ€ j < n, s (L.bank j).add.anc = false) (hA1dbl : βˆ€ j < n, regValRange (L.bank j).dbl.addLayout.A1 s n = 2 ^ n - N) (hA2dbl : βˆ€ j < n, regValRange (L.bank j).dbl.addLayout.A2 s n = N) (hA1add : βˆ€ j < n, regValRange (L.bank j).add.A1 s n = 2 ^ n - N) (hA2add : βˆ€ j < n, regValRange (L.bank j).add.A2 s n = N) (k : β„•) :
                  k ≀ n β†’ regValRange L.B (denote (mulLoopUpto L k) s) n = hornerVal (fun (i : β„•) => if s (L.X i) = true then 1 else 0) n k * Yval % N ∧ regValRange L.Y (denote (mulLoopUpto L k) s) n = Yval

                  The multiply-loop invariant. After the first k banks (k ≀ n), the accumulator holds (hornerVal bits n k Β· Yval) mod N (bits i = [X i]) and the multiplicand still holds Yval. By induction on k, splitting the last bank (mulLoopUpto_succ): the prefix preserves bank k's clean / preset wires (clean_pres) and its control bit (hCtrlTouch); hornerStep_correct then advances the residue (horner_mod_step), hornerStep_preserves_Y keeps Yval.

                  theorem Reversible.mulLoop_correct {m n : β„•} (L : MulLoopLayout m n) (s : State m) {N Yval : β„•} (h2N : 2 * N ≀ 2 ^ n) (hNpos : 0 < N) (hYN : Yval < N) (hB0 : regValRange L.B s n = 0) (hYv : regValRange L.Y s n = Yval) (hcleanAop : βˆ€ (j i : β„•), j < n β†’ i < n β†’ s ((L.bank j).dbl.Aop i) = false) (hcleanCadd : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.Cadd i) = false) (hcleandC1 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.C1 i) = false) (hcleandC2 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).dbl.addLayout.C2 i) = false) (hcleandanc : βˆ€ j < n, s (L.bank j).dbl.addLayout.anc = false) (hcleanCcadd : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.Ccadd i) = false) (hcleanancC : βˆ€ j < n, s (L.bank j).add.ancC = false) (hcleanC1 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.C1 i) = false) (hcleanC2 : βˆ€ (j i : β„•), j < n β†’ s ((L.bank j).add.C2 i) = false) (hcleananc : βˆ€ j < n, s (L.bank j).add.anc = false) (hA1dbl : βˆ€ j < n, regValRange (L.bank j).dbl.addLayout.A1 s n = 2 ^ n - N) (hA2dbl : βˆ€ j < n, regValRange (L.bank j).dbl.addLayout.A2 s n = N) (hA1add : βˆ€ j < n, regValRange (L.bank j).add.A1 s n = 2 ^ n - N) (hA2add : βˆ€ j < n, regValRange (L.bank j).add.A2 s n = N) :
                  regValRange L.B (denote (mulLoop L) s) n = regValRange L.X s n * Yval % N

                  The verified general-n modular field multiply (the S6.3d-2b headline). Under the accumulator initialised 0, the multiplicand Y holding Yval < N, 2N ≀ 2ⁿ, 0 < N, and every bank's clean / preset wires set (carries / ancilla false, presets A1 = 2ⁿ βˆ’ N, A2 = N), the loop leaves the accumulator holding (X Β· Yval) mod N, with the multiplier X arbitrary: regValRange B (denote (mulLoop L) s) n = (regValRange X s n Β· Yval) % N.

                  Proof: mulLoop_invariant at k = n gives (hornerVal bits n n Β· Yval) % N; hornerVal_full / regValRange_eq_hornerVal_bits bridges hornerVal bits n n = regValRange X s n (top n bits of an n-bit number is itself).

                  Derived cost #

                  Derived Toffoli cost of the general-n modular multiply: 30 Β· nΒ² Toffolis. The loop is n Horner steps (hornerStep_toffoli, 30n each), composed through the fold; multiplier_toffoli turns the concatenation cost into the sum of the per-step counts, which is n Β· 30n = 30nΒ².

                  Honest reading: this is the Θ(nΒ²)-Toffoli, Θ(nΒ²)-qubit fresh-ancilla figure β€” each of the n steps uses its own fresh scratch / carries / ancilla. The optimised in-place (Θ(n)-qubit) version needs the carry-clean / ancilla-restoring adder the corpus does not yet provide.

                  Concrete witness: a 3-bank (n = 3) modular multiply on Fin 135 #

                  A genuine MulLoopLayout 135 3, exhibiting MulLoopLayout is inhabited and mulLoop_correct applies. Shared accumulator B β†’ {0,1,2}, multiplicand Y β†’ {3,4,5}, 3-bit multiplier X β†’ {6,7,8} (bit j on wire 6+j, so bank j reads X (2-j) = wire 6+(2-j) = the high-to-low MSB-first order). Each bank j owns the disjoint fresh block [9 + 42Β·j, 9 + 42Β·(j+1)) of Fin 135. All disjointness / injectivity is linear-arithmetic on the wire indices (omega), so the schema is manifestly inhabitable; the same stride formula inhabits every n (only the ambient Fin m grows).

                  def Reversible.wDbl (base : β„•) (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) :

                  Bank j's doubling sub-layout on Fin 135: private block [base, base+22) with base = 9+42·j. All wire families are ⟨base + offset + min i width, _⟩, so every geometry field is omega.

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

                    Interface lemmas (CONVENTIONS Β§9.1, F1): the doubling sub-layout's wire assignments at the value level, one lemma per bundled field.

                    theorem Reversible.wDbl_Aop_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.Aop i) = base + 0 + min i 2

                    wDbl's operand wires, value level.

                    theorem Reversible.wDbl_B_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.B i) = min i 2

                    wDbl's accumulator wires, value level.

                    theorem Reversible.wDbl_Cadd_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.Cadd i) = base + 3 + min i 3

                    wDbl's add-step carry wires, value level.

                    theorem Reversible.wDbl_A1_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.A1 i) = base + 7 + min i 2

                    wDbl's step-1 constant-register wires, value level.

                    theorem Reversible.wDbl_C1_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.C1 i) = base + 10 + min i 3

                    wDbl's step-1 carry wires, value level.

                    theorem Reversible.wDbl_A2_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.A2 i) = base + 14 + min i 2

                    wDbl's step-3 constant-register wires, value level.

                    theorem Reversible.wDbl_C2_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) (i : β„•) :
                    ↑((wDbl base hlo hb).addLayout.C2 i) = base + 17 + min i 3

                    wDbl's step-3 carry wires, value level.

                    theorem Reversible.wDbl_anc_val {base : β„•} (hlo : 9 ≀ base) (hb : base + 22 ≀ 135) :
                    ↑(wDbl base hlo hb).addLayout.anc = base + 21

                    wDbl's ancilla wire, value level.

                    def Reversible.wAdd (base ctrl : β„•) (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) :

                    Bank j's controlled-add sub-layout on Fin 135: operand Y β†’ {3,4,5}, control X (2-j) = wire 6 + (2-j), private block [base+22, base+42) with base = 9+42Β·j.

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

                      Interface lemmas (CONVENTIONS Β§9.1, F1): the controlled-add sub-layout's wire assignments at the value level, one lemma per field.

                      theorem Reversible.wAdd_Aop_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).Aop i) = 3 + min i 2

                      wAdd's operand wires, value level.

                      theorem Reversible.wAdd_B_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).B i) = min i 2

                      wAdd's accumulator wires, value level.

                      theorem Reversible.wAdd_Ccadd_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).Ccadd i) = base + 22 + min i 3

                      wAdd's controlled-add carry wires, value level.

                      theorem Reversible.wAdd_ctrl_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) :
                      ↑(wAdd base ctrl hlo hb hc1 hc2).ctrl = ctrl

                      wAdd's control wire, value level.

                      theorem Reversible.wAdd_ancC_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) :
                      ↑(wAdd base ctrl hlo hb hc1 hc2).ancC = base + 26

                      wAdd's clean-ancilla wire, value level.

                      theorem Reversible.wAdd_A1_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).A1 i) = base + 27 + min i 2

                      wAdd's step-1 constant-register wires, value level.

                      theorem Reversible.wAdd_C1_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).C1 i) = base + 30 + min i 3

                      wAdd's step-1 carry wires, value level.

                      theorem Reversible.wAdd_A2_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).A2 i) = base + 34 + min i 2

                      wAdd's step-3 constant-register wires, value level.

                      theorem Reversible.wAdd_C2_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) (i : β„•) :
                      ↑((wAdd base ctrl hlo hb hc1 hc2).C2 i) = base + 37 + min i 3

                      wAdd's step-3 carry wires, value level.

                      theorem Reversible.wAdd_anc_val {base ctrl : β„•} (hlo : 9 ≀ base) (hb : base + 42 ≀ 135) (hc1 : 6 ≀ ctrl) (hc2 : ctrl < 9) :
                      ↑(wAdd base ctrl hlo hb hc1 hc2).anc = base + 41

                      wAdd's reduce-step ancilla wire, value level.

                      Bank j (j < 3) as a HornerStepLayout 135 3: doubling block wDbl, controlled-add block wAdd (control X (2-j) = wire 6 + (2-j)), sharing B β†’ {0,1,2}. The 70 cross-disjointness fields are all linear-arithmetic on the block offsets (omega).

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        theorem Reversible.wBank_clean_range (k : β„•) (hk : k < 3) (w : Fin 135) (hw : Clean wBank k w) :
                        9 + 42 * k ≀ ↑w ∧ ↑w < 9 + 42 * k + 42

                        Every Clean (wBank Β·) k w wire (k < 3) lies in bank k's private block [9 + 42Β·k, 9 + 42Β·k + 42). (All 14 clean / preset families are private; none is B, Y or X.)

                        theorem Reversible.wBank_touch_range (j : β„•) (hj : j < 3) (w : Fin 135) (hw : Touches wBank j w) :
                        ↑w < 6 ∨ ↑w = 6 + (2 - j) ∨ 9 + 42 * j ≀ ↑w ∧ ↑w < 9 + 42 * j + 42

                        Every Touches (wBank Β·) j w wire (j < 3) lies in {0,…,5} βˆͺ {6 + (2 - j)} βˆͺ [9 + 42Β·j, 9 + 42Β·j + 42) β€” bank j's shared B/Y, its own control bit, and its private block.

                        The concrete 3-bank (n = 3) modular-multiply loop layout on Fin 135. B β†’ {0,1,2}, Y β†’ {3,4,5}, X β†’ {6,7,8} (bit i on wire 6 + i), bank j on the fresh block [9 + 42Β·j, 9 + 42Β·(j+1)). The geometry fields reduce to the block-range lemmas wBank_clean_range / wBank_touch_range and omega.

                        Equations
                        Instances For

                          Every bank of the loop is the standard wBank (interface lemma, Β§9.1).

                          theorem Reversible.wMulLoop_X_val (i : β„•) :
                          ↑(wMulLoop.X i) = 6 + min i 2

                          The loop's multiplier wires, value level (interface lemma, Β§9.1).

                          Concrete #eval cross-check: the verified n = 3, N = 3 modular multiply on Fin 135 #

                          wState sets the shared B β†’ {0,1,2} to 0, the multiplicand Y β†’ {3,4,5} and the multiplier X β†’ {6,7,8} to the given bits, and presets every bank's reduce constants A1 = 2Β³ βˆ’ 3 = 5 and A2 = 3 (the 24 preset wires); every scratch / carry / ancilla is false. (N = 3 is forced by the modular reducer's 2N ≀ 2ⁿ, i.e. N ≀ 4 at n = 3; the multiplicand satisfies Y < N = 3.) Reading register B (low 3 bits) off the strict Array Bool evaluator (runArr, via the proven bridge regValRangeArr_eq) gives the value mulLoop_correct constrains, computed instantly. The three witnesses below realise X Β· Y mod 3 for Y = 2: X = 3 ↦ 6 mod 3 = 0; X = 4 ↦ 8 mod 3 = 2; X = 5 ↦ 10 mod 3 = 1.

                          def Reversible.wState (y0 y1 y2 x0 x1 x2 : Bool) :
                          State 135

                          Concrete input state on Fin 135: B = 0, Y = (y0,y1,y2) (wires {3,4,5}), X = (x0,x1,x2) (wires {6,7,8}), every bank's presets A1 = 5 (bits 0,2), A2 = 3 (bits 0,1), all scratch / carries / ancilla false.

                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For
                            theorem Reversible.min3_cases (i : β„•) :
                            min i 3 = 0 ∨ min i 3 = 1 ∨ min i 3 = 2 ∨ min i 3 = 3

                            min i 3 (and min i 2) ranges over {0,1,2,3}; this turns an βˆ€ i clean-wire goal whose wire depends on i only through min i 3 into the four concrete decide-able cases.