Reversible modular multiplication — semantic target + shift-and-add multiplier cost (ECDLP Tranche 3, Stage A) #
Category: 1-Mathlib (CSD-free; staged as a Mathlib-upstream candidate).
The multiplication layer of the reversible-circuit substrate
(Circuit.lean / Cost.lean / ModAdd.lean, specs/ecdlp-resource-plan.md). The semantic target is
Shor's modular-multiplication oracle mulOracle : |y⟩ ↦ |a·y⟩ on ZMod N (a permutation when a
is a unit), which the corpus's Empirical/QM/Algorithms/ShorCore.lean carries with no gate-level
content. This tranche builds the missing reversible circuit + derived cost.
What is proved here (Stage A) #
mulConst— the semantic target: theZMod Nmapy ↦ a · y, withmulConst_bijective(a unit acts as a permutation — the reversibility that lets a circuit realise it).multiplier— the shift-and-add multiplier as the concatenation of a list of partial-product adder circuits, with derived costmultiplier_toffoli/_cnot(the total count is the list-sum of the block counts, composed through the Tranche-1cost_comp_*lemmas — not annotated).rippleCirc_toffoli/_cnot— a ripple adder block costs2 * nToffolis / CNOTs (derived), so a multiplier built frommwidth-nadders costs2 * n * m(multiplier_ripple_toffoli).- The per-partial-product correctness is
ModAdd.rippleCirc_correct(one shifted add); the building block is in hand.
Stage B.1 — the per-step accumulation correctness (landed below) #
regValRange_split— split a register readout at an offset (low + 2^i · window), the tool relating a windowed add to the full accumulator value with no division.rippleCirc_preserves_external— a ripple circuit preserves any wire disjoint from its layout (the frame lemma at circuit granularity).accStep— THE per-step heart: one full-remaining-width ripple add of the multiplicand (valueYv) into the accumulator windowAcc[i, W)increases the full accumulator value by exactly2^i · Yv(carry propagating through the whole upper accumulator; lowibits preserved; no overflow).
Stage B.2 — the fold to Acc = a · Y (landed below) #
MulLayout— the multi-register wire geometry (accumulator, multiplicand with high bits held zero, per-shift carry chains; bounded injectivity/disjointness, so it is inhabitable — seemulLayout1).mulCircuit— the shift-and-add multiplier: one partial-product ripple add per shift inshifts.mulCircuit_correct— THE headline: the multiplier leaves the accumulator holdingAcc + (∑ sh ∈ shifts, 2^sh) · Y, by foldingaccStepover the shifts (an induction threadingY-preservation viastepLayout_preserves_Yand carry-freshness viastepLayout_preserves_carry; each step at its own widthW - sh, applied individually so there is no dependent-width fold). WithAccinitialised0and∑ 2^sh = a(the set bits of the classical constant), this isAcc = a · Y.mulLayout1+ the closingexample— a concreteFin 6witness, so the headline is non-vacuous.
Stage B.3 — the modular (ZMod N) capstone (landed below) #
mulCircuit_correct_zmod— connects the exact integer product to the semantic target: the output register, read inZMod N, ismulConst N (∑ 2^sh) Y(Shor'smulOracleactiony ↦ a·y mod N). TheZMod Ncast performs the reduction (noN = 2^Wassumption); the no-overflow hypothesis keeps the register exact. Honest residue: the register holds the exact integera·Y— reducing it in place to abitlen N-bit representative is a reversible conditional-subtract circuit (qubit optimisation), not built here.
The modular-multiplication oracle action: y ↦ a · y on ZMod N. This is the permutation Shor's
mulOracle realises (for a a unit); the circuit below is its reversible implementation.
Equations
- Reversible.mulConst N a y = a * y
Instances For
For a unit a, mulConst is a bijection (the reversibility that admits a reversible circuit):
its inverse is multiplication by a⁻¹.
The shift-and-add multiplier circuit and its derived cost #
The shift-and-add multiplier: the concatenation of a list of partial-product adder circuits. Each
entry is the circuit that adds one shifted copy of the multiplicand into the accumulator; the multiplier
is their composition. (Which adders appear is fixed by the classical constant a — its set bits — so no
quantum control is needed; the gate list, hence the cost, is determined.)
Equations
- Reversible.multiplier adders = List.flatMap id adders
Instances For
Multiplier Toffoli count is the sum of the block counts (derived, composed through the
Tranche-1 cost_comp_toffoli_count). Not annotated — read off the concatenated gate list.
Multiplier CNOT count is the sum of the block counts (derived).
The first k slices of a ripple adder cost 2 * k Toffolis (derived, induction on k composing
cost_comp_toffoli_count + fullAdder_toffoli).
A ripple adder block (n slices) costs 2 * n Toffolis (derived).
A multiplier built from m' width-n ripple-adder blocks costs 2 * n * m' Toffolis (derived).
The count is independent of whether the layouts are valid (disjoint-wire) — cost is syntactic, so this
is a cost statement, not a correctness one; the multiplier's correctness is Stage B.
Stage B: multiplication correctness — arithmetic tools #
A ripple circuit preserves any wire external to its layout (disjoint from all of A, B, C).
The frame lemma at circuit granularity, lifting denote_apply_of_forall_not_mem: every gate of
rippleCirc L has wires among L.A, L.B, L.C, so a wire avoiding all three is untouched.
Single accumulation step. One full-remaining-width ripple add of the multiplicand (value Yv,
read by L.A) into the accumulator window Acc[i, W) increases the full accumulator value by
2^i · Yv — provided the add does not overflow the window. The carry propagates through the whole
upper accumulator (width w = W - i), so nothing is dropped; the low i bits are preserved.
Stage B.2: the fold to Acc = a · Y #
A MulLayout lays out, on Fin M, the accumulator Acc (W wires), the multiplicand Y (a W-wire
register whose high bits [n, W) are held zero, so no separate addend-pad wires are needed), and a
per-shift carry chain Carry sh. The multiplier is the concatenation, over a list of shifts (the set
bits of the classical constant a), of one full-window ripple add of Y into Acc[sh, W) per shift.
Folding accStep over the shifts gives Acc ← Acc + (∑ 2^sh) · Y. Each step has its own width
W - sh, but the steps are applied individually (the circuits are all Circuit M), so there is no
dependent-width fold.
A multiplier layout on Fin M: accumulator Acc, multiplicand Y (high bits held zero), and a
per-shift carry chain Carry. The fields are pure wire geometry (disjointness + injectivity).
Accumulator wires (indices
[0, W)).Multiplicand wires (a
W-wire register; values live in[0, n), high bits held zero).Carry chain for the partial-product add at shift
sh.
Instances For
The shift-and-add multiplier circuit: one partial-product ripple add per shift in shifts.
Equations
- Reversible.mulCircuit L shifts = Reversible.multiplier (List.map (fun (sh : ℕ) => Reversible.rippleCirc (Reversible.stepLayout L sh)) shifts)
Instances For
Multiplier correctness (Stage B.2 headline). The shift-and-add multiplier over shifts (the
set bits of the classical constant a) leaves the accumulator holding Acc + (∑ 2^sh) · Y, provided
the carries start false, Y's high bits are zero, and the result does not overflow 2^W. With
Acc initialised to 0 and ∑ 2^sh = a, this is Acc = a · Y.
Non-vacuity witness #
A concrete MulLayout showing the structure is inhabited (the bounded injectivity/disjointness fields
are jointly satisfiable in finitely many wires) and mulCircuit_correct applies. Accumulator on wire
0, multiplicand on wire 1, and two disjoint carry banks ({2,3} for shift 0, {4,5} for shift
1) so the cross-shift disjointness hCarryCross is non-vacuous.
A concrete 1-bit multiplier layout on Fin 6 (n = W = 1): accumulator wire 0, multiplicand
wire 1, carry banks {2,3} (shift 0) and {4,5} (shift 1), via the arithmetic encoding
Carry sh k = 2 + 2·min sh 1 + min k 1 (no case split — every field proof is omega).
Equations
- One or more equations did not get rendered due to their size.
Instances For
Stage B.3: the modular (ZMod N) connection — the multiplier realises mulConst #
mulCircuit_correct gives the exact integer product a · Y in the W-bit accumulator (no
overflow). The Shor mulOracle action is y ↦ a · y on ZMod N (mulConst), and that is precisely
the accumulator's value cast into ZMod N — the cast performs the mod N reduction, with no
N = 2^W assumption and no truncation hypothesised away (the no-overflow hypothesis guarantees the
register holds the exact integer; the ZMod N cast then reduces it honestly).
Honest scope: the accumulator physically holds the exact integer a · Y (W bits, W chosen large
enough — for Shor W ≥ 2·bitlen N, since a, y < N ⇒ a·y < N²); its ZMod N interpretation is the
oracle action. Reducing the register in place to a bitlen N-bit representative of a·y mod N is a
reversible modular-reduction circuit (conditional-subtract), a qubit-count optimisation not built here.
Modular-multiplication correctness (Tranche 3 capstone). With the accumulator initialised 0
and no overflow, the shift-and-add multiplier's output register, read in ZMod N, is the mulConst
(modular-multiplication) action (∑ 2^sh) · Y. For ∑ 2^sh = a this is Shor's mulOracle action
y ↦ a · y mod N.