Documentation

CsdLean4.Mathlib.QuantumInfo.Reversible.ModularMul

Reversible interleaved modular multiply โ€” the verified Horner LOOP BODY (ECDLP Phase 2, Stage S6.3d-2a) #

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

This module verifies the loop body of the interleaved MSB-first modular multiply over ๐”ฝ_p, acc โ† (2ยทacc + [X_i]ยทY) mod N, by chaining the two already-verified blocks one tranche below:

hornerStep L = modDouble L.dbl ++ cModAdd L.add

Composition (the loop-body identity, absorbing the inner mod N via Nat.add_mod / Nat.mod_add_mod):

So hornerStep_correct gives B โ† (2*c + (if X_i then Yval else 0)) mod N.

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

This is the verified LOOP BODY of the interleaved MSB-first modular multiply, acc โ† (2ยทacc + [X_i]ยทY) mod N, composing the verified modDouble (S6.3d-1) and cModAdd (S6.3c). The 2-step composition is delivered two ways: (i) the proven mulStep2_correct, which chains hornerStep_correct twice over two banks sharing B and Y with fresh per-bank wires, concluding acc = (X ยท Yval) mod N for the 2-bit multiplier X = 2ยทXโ‚ + Xโ‚€; and (ii) a concrete Fin 92 instance (mulCircuit2 / mulState2) whose three #eval / decide witnesses realise X = 3 โ†ฆ 0, X = 2 โ†ฆ 1, X = 1 โ†ฆ 2 at Y = 2, N = 3 (the verified n = 2 modular multiply).

This is NOT the general-n multiply. The general-n Horner loop โ€” the induction folding hornerStep over all n bits of X with the invariant acc = (X โ‰ซ i)ยทY mod N โ€” is the subsequent tranche S6.3d-2b, NOT built here โ€” it lives in ModularMulLoop.lean (mulLoop_correct).

The fresh-ancilla / dirty-carry model (inherited from S6.3d-1 and S6.3c):

  1. Fresh per-iteration wires (O(nยฒ) qubits). Each Horner step is supplied its OWN doubling scratch / carries / ancilla and its OWN controlled-add carries / ancilla, disjoint from the previous step's. The 2-step demo exhibits exactly this: two banks, fresh wires each. Across n steps this is ฮ˜(nยฒ) ancilla. In-place reuse (ฮ˜(n) qubits) needs a carry-clean / ancilla-restoring adder โ€” supplied by CuccaroModAdd.lean (cuccaroModAdd_clean) and folded into the ฮ˜(n)-qubit multiply in CuccaroModMul.lean; NOT built here.
  2. Only the multiplicand Y must persist across steps. The loop reads each X_i once (the bit wire of step i is dead after step i), but Y = add.Aop must survive every step; this is the load-bearing hornerStep_preserves_Y.

Honest cost #

hornerStep_toffoli derives 30n Toffolis from the exhibited gate list: modDouble 12n (modDouble_toffoli) + cModAdd 18n (cModularAdd_toffoli), composed through cost_comp_toffoli_count.

Generic frame: a wire external to modReduce / modAdd / modDouble survives #

modDouble L = copyReg L ++ modAdd L.addLayout and modAdd L = rippleCirc L.addStep ++ modReduce L.reduceStep. Each block is a frame lemma over its wire families; the three lemmas below compose them so that a wire disjoint from every modDouble-touched family passes through unchanged. These are the only genuinely new structural lemmas of this tranche.

theorem Reversible.modReduce_preserves_external {m n : โ„•} (L : ModReduceLayout m n) (s : State m) (w : Fin m) (hB : โˆ€ (j : โ„•), w โ‰  L.B j) (hA1 : โˆ€ (j : โ„•), w โ‰  L.A1 j) (hC1 : โˆ€ (j : โ„•), w โ‰  L.C1 j) (hA2 : โˆ€ (j : โ„•), w โ‰  L.A2 j) (hC2 : โˆ€ (j : โ„•), w โ‰  L.C2 j) (hanc : w โ‰  L.anc) :
denote (modReduce L) s w = s w

modReduce frame. A wire w disjoint from every reduce-step family (B, A1, C1, A2, C2, anc) is left unchanged by modReduce L. Mirrors modReduce_reduceStep_preserves_Aop but abstracted to an arbitrary external wire and a bare ModReduceLayout.

theorem Reversible.modAdd_preserves_external {m n : โ„•} (L : ModAddLayout m n) (s : State m) (w : Fin m) (hAop : โˆ€ (j : โ„•), w โ‰  L.Aop j) (hB : โˆ€ (j : โ„•), w โ‰  L.B j) (hCadd : โˆ€ (j : โ„•), w โ‰  L.Cadd j) (hA1 : โˆ€ (j : โ„•), w โ‰  L.A1 j) (hC1 : โˆ€ (j : โ„•), w โ‰  L.C1 j) (hA2 : โˆ€ (j : โ„•), w โ‰  L.A2 j) (hC2 : โˆ€ (j : โ„•), w โ‰  L.C2 j) (hanc : w โ‰  L.anc) :
denote (modAdd L) s w = s w

modAdd frame. A wire w disjoint from every modAdd-touched family (Aop, B, Cadd, A1, C1, A2, C2, anc) is left unchanged by modAdd L. Composes rippleCirc_addStep_preserves (add step) with modReduce_preserves_external (reduce step).

theorem Reversible.modDouble_preserves_external {m n : โ„•} (L : ModDoubleLayout m n) (s : State m) (w : Fin m) (hB : โˆ€ (j : โ„•), w โ‰  L.B j) (hAop : โˆ€ (j : โ„•), w โ‰  L.Aop j) (hCadd : โˆ€ (j : โ„•), w โ‰  L.addLayout.Cadd j) (hA1 : โˆ€ (j : โ„•), w โ‰  L.addLayout.A1 j) (hC1 : โˆ€ (j : โ„•), w โ‰  L.addLayout.C1 j) (hA2 : โˆ€ (j : โ„•), w โ‰  L.addLayout.A2 j) (hC2 : โˆ€ (j : โ„•), w โ‰  L.addLayout.C2 j) (hanc : w โ‰  L.addLayout.anc) :
denote (modDouble L) s w = s w

modDouble frame. A wire w disjoint from every modDouble-touched family (B, the scratch operand dbl.Aop, and the bundled add layout's Cadd, A1, C1, A2, C2, anc) is left unchanged by modDouble L. Composes copyReg_preserves (copy step) with modAdd_preserves_external (the bundled modAdd).

theorem Reversible.cModAdd_preserves_external {m n : โ„•} (L : CModAddLayout m n) (s : State m) (w : Fin m) (hAop : โˆ€ k < n, w โ‰  L.Aop k) (hB : โˆ€ (k : โ„•), w โ‰  L.B k) (hctrl : w โ‰  L.ctrl) (hCcadd : โˆ€ k < n + 1, w โ‰  L.Ccadd k) (hancC : w โ‰  L.ancC) (hA1 : โˆ€ (j : โ„•), w โ‰  L.A1 j) (hC1 : โˆ€ (j : โ„•), w โ‰  L.C1 j) (hA2 : โˆ€ (j : โ„•), w โ‰  L.A2 j) (hC2 : โˆ€ (j : โ„•), w โ‰  L.C2 j) (hanc : w โ‰  L.anc) :
denote (cModAdd L) s w = s w

cModAdd frame. A wire w disjoint from every cModAdd-touched family (Aop, B, Ccadd, ctrl, ancC of the controlled add, and A1, C1, A2, C2, anc of the reduce) is left unchanged by cModAdd L. Composes cRippleCirc_preserves_external (controlled add step) with modReduce_preserves_external (reduce step). Register hyps are bounded (< n / < n + 1), as in cRippleCirc_preserves_external.

The Horner-step layout #

A HornerStepLayout bundles the S6.3d-1 doubling sub-layout dbl and the S6.3c controlled-add sub-layout add, sharing the accumulator (dbl.B = add.B, the running acc), with the doubling's wires (scratch operand + carries + ancilla) and the controlled-add's wires (carries + ancilla) fresh and disjoint from each other, from the multiplicand Y = add.Aop, and from the control bit X_i = add.ctrl. The cross-disjointness fields are exactly what modDouble_preserves_external needs to re-establish every cModAdd_correct hypothesis through the doubling.

A Horner-step layout for n-bit registers on Fin m. The two sub-layouts share the accumulator B; everything else of the doubling block is disjoint from everything the controlled-add block reads or carries.

Instances For

    The shared accumulator register (acc), the B of both sub-layouts.

    Equations
    Instances For

      The control wire X_i for this Horner step (the controlled-add's ctrl).

      Equations
      Instances For

        The multiplicand register Y (the controlled-add's read-only operand).

        Equations
        Instances For

          The Horner-step circuit. Double the accumulator (modDouble), then conditionally add the multiplicand Y controlled on the bit X_i (cModAdd).

          Equations
          Instances For

            modDouble preserves the controlled-add block's external wires #

            Each corollary specialises modDouble_preserves_external to one controlled-add family, feeding the eight cross-disjointness fields for that family. These re-establish cModAdd_correct's hypotheses at the post-doubling state.

            theorem Reversible.modDouble_pres_addAop {m n : โ„•} {L : HornerStepLayout m n} (s : State m) (j : โ„•) :
            denote (modDouble L.dbl) s (L.add.Aop j) = s (L.add.Aop j)
            theorem Reversible.modDouble_pres_addA1 {m n : โ„•} {L : HornerStepLayout m n} (s : State m) (j : โ„•) :
            denote (modDouble L.dbl) s (L.add.A1 j) = s (L.add.A1 j)
            theorem Reversible.modDouble_pres_addC1 {m n : โ„•} {L : HornerStepLayout m n} (s : State m) (j : โ„•) :
            denote (modDouble L.dbl) s (L.add.C1 j) = s (L.add.C1 j)
            theorem Reversible.modDouble_pres_addA2 {m n : โ„•} {L : HornerStepLayout m n} (s : State m) (j : โ„•) :
            denote (modDouble L.dbl) s (L.add.A2 j) = s (L.add.A2 j)
            theorem Reversible.modDouble_pres_addC2 {m n : โ„•} {L : HornerStepLayout m n} (s : State m) (j : โ„•) :
            denote (modDouble L.dbl) s (L.add.C2 j) = s (L.add.C2 j)
            theorem Reversible.hornerStep_preserves_external {m n : โ„•} (L : HornerStepLayout m n) (s : State m) (w : Fin m) (hB : โˆ€ (j : โ„•), w โ‰  L.dbl.B j) (hdAop : โˆ€ (j : โ„•), w โ‰  L.dbl.Aop j) (hdCadd : โˆ€ (j : โ„•), w โ‰  L.dbl.addLayout.Cadd j) (hdA1 : โˆ€ (j : โ„•), w โ‰  L.dbl.addLayout.A1 j) (hdC1 : โˆ€ (j : โ„•), w โ‰  L.dbl.addLayout.C1 j) (hdA2 : โˆ€ (j : โ„•), w โ‰  L.dbl.addLayout.A2 j) (hdC2 : โˆ€ (j : โ„•), w โ‰  L.dbl.addLayout.C2 j) (hdanc : w โ‰  L.dbl.addLayout.anc) (hAop : โˆ€ k < n, w โ‰  L.add.Aop k) (haddB : โˆ€ (j : โ„•), w โ‰  L.add.B j) (hctrl : w โ‰  L.add.ctrl) (hCcadd : โˆ€ k < n + 1, w โ‰  L.add.Ccadd k) (hancC : w โ‰  L.add.ancC) (hA1 : โˆ€ (j : โ„•), w โ‰  L.add.A1 j) (hC1 : โˆ€ (j : โ„•), w โ‰  L.add.C1 j) (hA2 : โˆ€ (j : โ„•), w โ‰  L.add.A2 j) (hC2 : โˆ€ (j : โ„•), w โ‰  L.add.C2 j) (hanc : w โ‰  L.add.anc) :
            denote (hornerStep L) s w = s w

            hornerStep frame. A wire w disjoint from every wire of BOTH blocks survives the whole Horner step (modDouble L.dbl ++ cModAdd L.add). Used by the 2-step demo to transport bank 2's clean presets / scratch / carries through bank 1. The modDouble families are {B, dbl.Aop, dbl.Cadd, dbl.A1, dbl.C1, dbl.A2, dbl.C2, dbl.anc}; the cModAdd families are {add.Aop, add.B, add.Ccadd, add.ctrl, add.ancC, add.A1, add.C1, add.A2, add.C2, add.anc}.

            Value correctness of the Horner step #

            theorem Reversible.hornerStep_correct {m n : โ„•} (L : HornerStepLayout m n) (s : State m) (hAop0 : โˆ€ i < n, s (L.dbl.Aop i) = false) (hCadd_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.Cadd j) = false) (hC1_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.C1 j) = false) (hC2_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.C2 j) = false) (hanc_dbl : s L.dbl.addLayout.anc = false) (hCcadd : โˆ€ (j : โ„•), s (L.add.Ccadd j) = false) (hancC : s L.add.ancC = false) (hC1 : โˆ€ (j : โ„•), s (L.add.C1 j) = false) (hC2 : โˆ€ (j : โ„•), s (L.add.C2 j) = false) (hanc : s L.add.anc = false) {N c Yval : โ„•} (h2N : 2 * N โ‰ค 2 ^ n) (hA1_dbl : regValRange L.dbl.addLayout.A1 s n = 2 ^ n - N) (hA2_dbl : regValRange L.dbl.addLayout.A2 s n = N) (hA1 : regValRange L.add.A1 s n = 2 ^ n - N) (hA2 : regValRange L.add.A2 s n = N) (hB : regValRange L.B s n = c) (hcN : c < N) (hY : regValRange L.Y s n = Yval) (hYN : Yval < N) :
            regValRange L.B (denote (hornerStep L) s) n = (2 * c + if s L.add.ctrl = true then Yval else 0) % N

            The verified Horner loop body acc โ† (2ยทacc + [X_i]ยทY) mod N. For a HornerStepLayout with the accumulator B holding c < N, the multiplicand register Y = add.Aop holding Yval < N, 2N โ‰ค 2โฟ, both sub-layouts' presets (A1 = 2โฟ โˆ’ N, A2 = N), all carries / ancillas clean, and the scratch operands of the doubling zeroed, hornerStep L leaves register B holding (2ยทc + (if X_i then Yval else 0)) mod N.

            Proof. The doubling step (modDouble_correct / modDouble_in_range) writes (2c) mod N < N to B, preserves Y, X_i, and the controlled-add block's presets / clean carries / ancillas (modDouble_pres_add*). The controlled add (cModAdd_correct) then writes if X_i then (Yval + (2c mod N)) mod N else (2c mod N). In the set branch Nat.add_mod_mod absorbs the inner reduction: (Yval + (2c mod N)) mod N = (Yval + 2c) mod N = (2c + Yval) mod N; in the clear branch (2c) mod N = (2c + 0) mod N.

            theorem Reversible.hornerStep_in_range {m n : โ„•} (L : HornerStepLayout m n) (s : State m) (hAop0 : โˆ€ i < n, s (L.dbl.Aop i) = false) (hCadd_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.Cadd j) = false) (hC1_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.C1 j) = false) (hC2_dbl : โˆ€ (j : โ„•), s (L.dbl.addLayout.C2 j) = false) (hanc_dbl : s L.dbl.addLayout.anc = false) (hCcadd : โˆ€ (j : โ„•), s (L.add.Ccadd j) = false) (hancC : s L.add.ancC = false) (hC1 : โˆ€ (j : โ„•), s (L.add.C1 j) = false) (hC2 : โˆ€ (j : โ„•), s (L.add.C2 j) = false) (hanc : s L.add.anc = false) {N c Yval : โ„•} (h2N : 2 * N โ‰ค 2 ^ n) (hA1_dbl : regValRange L.dbl.addLayout.A1 s n = 2 ^ n - N) (hA2_dbl : regValRange L.dbl.addLayout.A2 s n = N) (hA1 : regValRange L.add.A1 s n = 2 ^ n - N) (hA2 : regValRange L.add.A2 s n = N) (hB : regValRange L.B s n = c) (hcN : c < N) (hY : regValRange L.Y s n = Yval) (hYN : Yval < N) (hNpos : 0 < N) :

            The Horner-step output is a genuine residue in [0, N). Corollary of hornerStep_correct and Nat.mod_lt.

            theorem Reversible.hornerStep_preserves_Y {m n : โ„•} (L : HornerStepLayout m n) (s : State m) (hCcadd : โˆ€ (j : โ„•), s (L.add.Ccadd j) = false) (hancC : s L.add.ancC = false) {Yval : โ„•} (hY : regValRange L.Y s n = Yval) :
            regValRange L.Y (denote (hornerStep L) s) n = Yval

            The multiplicand Y is preserved. hornerStep L leaves Y = add.Aop at its initial value: the doubling block is disjoint from Y (modDouble_pres_addAop), and the controlled add reads Y read-only (cModAdd_preserves_operand). This is the load-bearing persistence: the loop reuses the SAME Y across all bit positions.

            Derived cost #

            Derived Toffoli cost of the Horner step: 30n Toffolis, from the exhibited gate list. Doubling step 12n (modDouble_toffoli) + controlled add step 18n (cModularAdd_toffoli), composed through cost_comp_toffoli_count.

            2-step composition: the verified n = 2 modular multiply #

            Two Horner-step banks L1 (high bit Xโ‚) then L2 (low bit Xโ‚€) sharing the accumulator B and the multiplicand Y, with fresh per-bank scratch / carries / ancilla. Starting from acc = 0:

            The load-bearing inter-bank obligation is that bank 1 leaves bank 2's clean presets / scratch / carries / ancilla and the low control bit Xโ‚€ UNTOUCHED โ€” taken here as the hp_* hypotheses, each dischargeable from inter-bank disjointness via hornerStep_preserves_external (the fresh-wire model; see the mulCircuit2 #eval cross-check for a concrete instance that satisfies them). This exhibits that the loop body composes; the general-n Horner induction is S6.3d-2b, NOT proved here.

            theorem Reversible.mulStep2_correct {m n : โ„•} (L1 L2 : HornerStepLayout m n) (s : State m) (hBshare : L2.B = L1.B) (hYshare : L2.Y = L1.Y) (h1Aop0 : โˆ€ i < n, s (L1.dbl.Aop i) = false) (h1Cadd_dbl : โˆ€ (j : โ„•), s (L1.dbl.addLayout.Cadd j) = false) (h1C1_dbl : โˆ€ (j : โ„•), s (L1.dbl.addLayout.C1 j) = false) (h1C2_dbl : โˆ€ (j : โ„•), s (L1.dbl.addLayout.C2 j) = false) (h1anc_dbl : s L1.dbl.addLayout.anc = false) (h1Ccadd : โˆ€ (j : โ„•), s (L1.add.Ccadd j) = false) (h1ancC : s L1.add.ancC = false) (h1C1 : โˆ€ (j : โ„•), s (L1.add.C1 j) = false) (h1C2 : โˆ€ (j : โ„•), s (L1.add.C2 j) = false) (h1anc : s L1.add.anc = false) (h2Aop0 : โˆ€ i < n, s (L2.dbl.Aop i) = false) (h2Cadd_dbl : โˆ€ (j : โ„•), s (L2.dbl.addLayout.Cadd j) = false) (h2C1_dbl : โˆ€ (j : โ„•), s (L2.dbl.addLayout.C1 j) = false) (h2C2_dbl : โˆ€ (j : โ„•), s (L2.dbl.addLayout.C2 j) = false) (h2anc_dbl : s L2.dbl.addLayout.anc = false) (h2Ccadd : โˆ€ (j : โ„•), s (L2.add.Ccadd j) = false) (h2ancC : s L2.add.ancC = false) (h2C1 : โˆ€ (j : โ„•), s (L2.add.C1 j) = false) (h2C2 : โˆ€ (j : โ„•), s (L2.add.C2 j) = false) (h2anc : s L2.add.anc = false) {N Yval : โ„•} (h2N : 2 * N โ‰ค 2 ^ n) (hNpos : 0 < N) (h1A1_dbl : regValRange L1.dbl.addLayout.A1 s n = 2 ^ n - N) (h1A2_dbl : regValRange L1.dbl.addLayout.A2 s n = N) (h1A1 : regValRange L1.add.A1 s n = 2 ^ n - N) (h1A2 : regValRange L1.add.A2 s n = N) (h2A1_dbl : regValRange L2.dbl.addLayout.A1 s n = 2 ^ n - N) (h2A2_dbl : regValRange L2.dbl.addLayout.A2 s n = N) (h2A1 : regValRange L2.add.A1 s n = 2 ^ n - N) (h2A2 : regValRange L2.add.A2 s n = N) (hB0 : regValRange L1.B s n = 0) (hY : regValRange L1.Y s n = Yval) (hYN : Yval < N) (hp_2Aop : โˆ€ (i : โ„•), denote (hornerStep L1) s (L2.dbl.Aop i) = s (L2.dbl.Aop i)) (hp_2dCadd : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.dbl.addLayout.Cadd j) = s (L2.dbl.addLayout.Cadd j)) (hp_2dC1 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.dbl.addLayout.C1 j) = s (L2.dbl.addLayout.C1 j)) (hp_2dC2 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.dbl.addLayout.C2 j) = s (L2.dbl.addLayout.C2 j)) (hp_2danc : denote (hornerStep L1) s L2.dbl.addLayout.anc = s L2.dbl.addLayout.anc) (hp_2dA1 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.dbl.addLayout.A1 j) = s (L2.dbl.addLayout.A1 j)) (hp_2dA2 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.dbl.addLayout.A2 j) = s (L2.dbl.addLayout.A2 j)) (hp_2Ccadd : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.add.Ccadd j) = s (L2.add.Ccadd j)) (hp_2ancC : denote (hornerStep L1) s L2.add.ancC = s L2.add.ancC) (hp_2C1 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.add.C1 j) = s (L2.add.C1 j)) (hp_2C2 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.add.C2 j) = s (L2.add.C2 j)) (hp_2anc : denote (hornerStep L1) s L2.add.anc = s L2.add.anc) (hp_2A1 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.add.A1 j) = s (L2.add.A1 j)) (hp_2A2 : โˆ€ (j : โ„•), denote (hornerStep L1) s (L2.add.A2 j) = s (L2.add.A2 j)) (hp_2ctrl : denote (hornerStep L1) s L2.add.ctrl = s L2.add.ctrl) (h1Ccadd' : โˆ€ (j : โ„•), s (L1.add.Ccadd j) = false) (h1ancC' : s L1.add.ancC = false) :
            regValRange L2.B (denote (hornerStep L2) (denote (hornerStep L1) s)) n = ((2 * if s L1.add.ctrl = true then 1 else 0) + if s L2.add.ctrl = true then 1 else 0) * Yval % N

            Concrete #eval cross-check: the verified n = 2 modular multiply on Fin 92 #

            Two Horner-step banks laid out on Fin 92, n = 3 register width (forced by 2N โ‰ค 2โฟ for N = 3), sharing the accumulator B โ†’ {0,1,2} and the multiplicand Y โ†’ {3,4,5}, with a 2-bit multiplier X on the dedicated control wires {6, 7} (wire 6 = bank-1 control Xโ‚, the HIGH bit; wire 7 = bank-2 control Xโ‚€, the LOW bit). Every other wire family is FRESH per bank (the ฮ˜(nยฒ)-ancilla fresh-wire model): bank 1 on {8..49}, bank 2 on {50..91}.

            The full circuit is modDouble dbl1 ++ cModAdd add1 ++ modDouble dbl2 ++ cModAdd add2 โ€” exactly hornerStep (bank 1) followed by hornerStep (bank 2). Reading register B (low 3 bits) off the strict Array Bool evaluator (runArr, via the proven bridge regValRangeArr_eq) gives the value the chained hornerStep_correct / mulStep2_correct constrain, computed instantly. The three witnesses below realise X ยท Yval mod N for Yval = 2, N = 3: X = 3 โ†ฆ 0, X = 2 โ†ฆ 1, X = 1 โ†ฆ 2.

            Bank-1 doubling sub-layout (scratch {8,9,10}, carries/presets {11..29}).

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

              Bank-1 controlled-add sub-layout (Aop = Y โ†’ {3,4,5}, ctrl = 6, carries/presets {30..49}).

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

                Bank-2 doubling sub-layout (scratch {50,51,52}, carries/presets {53..71}).

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

                  Bank-2 controlled-add sub-layout (Aop = Y โ†’ {3,4,5}, ctrl = 7, carries/presets {72..91}).

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    def Reversible.mulState2 (y0 y1 y2 x1 x0 : Bool) :

                    Concrete input state on Fin 92: shared accumulator B = 0 (wires {0,1,2}), multiplicand Y = (y0,y1,y2) (wires {3,4,5}), 2-bit multiplier X = high bit x1 (wire 6) + low bit x0 (wire 7); both banks' presets A1 = 5 = 2ยณ โˆ’ 3 and A2 = 3; all scratch / carries / ancillas false. Parameterised by the data bits.

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