Reversible controlled modular addition — (ctrl, a, b) ↦ if ctrl then (a+b) mod N else b (ECDLP Phase 2, Stage S6.3c) #
Category: 1-Mathlib (CSD-free; staged as a Mathlib-upstream candidate).
This module verifies the controlled modular-addition VALUE primitive — the controlled analogue of
S6.3b's modAdd — by chaining two already-verified blocks:
cModAdd L = cRippleCirc L.cAddStep ++ modReduce L.reduceStep
- Controlled add step
cRippleCirc L.cAddStep(S2): addendAop(=a, read-only), accumulatorB(=b), control wirectrl, the cRipple carry chainCcadd, shared ancillaancC(restored bycRippleCirc_anc_restored). Witha + b < 2N ≤ 2ⁿ,cRippleCirc_correctgivesB ← if ctrl then (a + b) mod 2ⁿ else b = if ctrl then a + b else b(no wrap). In both branchesB < 2N(ctrl:a + b < 2N; ¬ctrl:b < N < 2N). - Reduce step
modReduce L.reduceStep(S6.3a) — UNCONDITIONAL, it always runs: sinceB < 2Nin both branches,modReduce_correctmapsB ← B mod N. In the ctrl branch that is(a + b) mod N; in the ¬ctrl branch it isb mod N = b(sinceb < N). The reduce being unconditional is the whole trick:bis already a valid reduced residue, so reducing it again is the identity.
So the headline value is B ← if ctrl then (a + b) mod N else b.
Carve line (what this is, and is NOT) #
This VERIFIES the controlled modular-addition value primitive B ← if ctrl then (a+b) mod N else b
by chaining the verified cRippleCirc (S2) with S6.3a's modReduce; the unconditional reduce is
correct in both branches because b < N is already a valid residue. This is ℕ / mod N bit
arithmetic — NO field / group semantics are in play.
This is the inner-loop primitive of the interleaved MSB-first modular MULTIPLY over 𝔽_p (the next
stage, S6.3d), which also needs a modular DOUBLING gadget (2·acc mod N, the register-to-itself
add) and the Horner loop invariant. This module is NOT the multiply.
Named residue (same as S6.3b; name it): the carry chains Ccadd, C1, C2 and the comparison
flag C1 n are left DIRTY after cModAdd. Correctness holds because the layout supplies fresh
wires per use (cModAdd_correct requires C* / anc initialised false). In-place reuse across the
many additions of a modular multiply needs carry-clean / ancilla-restoring adders (Cuccaro-style
inline carry-uncompute, or reversing carry generation) which the corpus's rippleCirc / cRippleCirc
do NOT provide. That carry-clean adder is the genuine orthogonal residue, NOT built here.
Honest cost #
cModularAdd_toffoli derives 18n Toffolis from the exhibited gate list: controlled add step 8n
(cRippleCirc_toffoli, the quantum×quantum overhead) + reduce step 10n (modReduceCtrl_toffoli),
composed through cost_comp_toffoli_count. (Heavier than S6.3b's uncontrolled 12n precisely by the
4× quantum×quantum cost of the controlled add, 8n vs 2n.)
A controlled-modular-addition layout on Fin m for n-bit registers. Like ModAddLayout but the
add step is a CRippleLayout: it bundles the operand register Aop (read-only addend a), the
accumulator B (holds b, overwritten with if ctrl then (a+b) mod N else b), the controlled-add
step's own carry chain Ccadd, the control wire ctrl, the cRipple shared ancilla ancC, and the
reduce sub-data (A1, A2, C1, C2, anc).
The geometry fields give: (i) cAddStep : CRippleLayout well-formed (Aop, B, Ccadd, ctrl,
ancC pairwise disjoint + bounded-injective), (ii) reduceStep : ModReduceLayout well-formed, and
(iii) Ccadd, Aop, ctrl, ancC all disjoint from every reduce-step wire so the controlled-add
step's carries / ancilla are fresh and the operand + control bit survive the whole circuit.
Injectivity fields are bounded (< n for registers, < n + 1 for carry chains), exactly as
ModAddLayout / ModReduceLayout / MulLayout: an unbounded ℕ → Fin m injectivity field is
uninhabitable and would make the theorems vacuous.
Operand register: holds
a, read-only addend (preserved bycModAdd).Accumulator: holds
b, overwritten withif ctrl then (a + b) mod N else b.Controlled-add-step carry chain (disjoint from the reduce step).
- ctrl : Fin m
The control wire (set ⇒ add
a; clear ⇒ leaveb). Read, never written. - ancC : Fin m
The controlled-add-step shared clean ancilla (
CCCXdecomposition; restoredfalse). Reduce step-1 constant register (preset to
2ⁿ − N).Reduce step-1 carry chain;
C1 nis the comparison flag.Reduce step-3 constant register (preset to
N).Reduce step-3 carry chain.
- anc : Fin m
Reduce shared clean ancilla.
Instances For
The reduce step as a ModReduceLayout (S6.3a).
Equations
- One or more equations did not get rendered due to their size.
Instances For
The controlled modular-addition circuit. Controlled register add (cRippleCirc) followed by
the S6.3a single-step modular reduction (modReduce), the latter run unconditionally.
Equations
Instances For
Frame: a wire disjoint from cAddStep's wires survives the controlled add step #
cRippleCirc L.cAddStep touches only {ctrl, ancC} ∪ {Aop k, B k, Ccadd k}. Any wire distinct from all
of those passes through unchanged (cRippleCirc_preserves_external). The four corollaries below
specialise it to the reduce step's A1 / A2 / C1 / C2 / anc wires.
After the controlled add step, A1 is unchanged on every wire (disjoint from the add step).
After the controlled add step, A2 is unchanged on every wire.
After the controlled add step, C1 is unchanged on every wire.
After the controlled add step, C2 is unchanged on every wire.
After the controlled add step, anc is unchanged.
Frame: the operand Aop and the control bit ctrl survive the reduce step #
modReduce L.reduceStep touches only {A1, A2, C1, C2, anc, B} (and the flag C1 n). Since Aop and
ctrl are disjoint from all of these, they pass through the reduce step unchanged.
Operand frame through the reduce step. Aop j is untouched by modReduce L.reduceStep.
Control frame through the reduce step. ctrl is untouched by modReduce L.reduceStep.
Value correctness #
The verified controlled modular-addition value primitive. For a disjoint-wire CModAddLayout
with all carry chains (Ccadd, C1, C2) and both ancillas (ancC, anc) initialised false,
register A1 preset to 2ⁿ − N, register A2 preset to N, operand register Aop holding a,
accumulator B holding b, with a < N, b < N, 2N ≤ 2ⁿ: cModAdd L leaves register B holding
if ctrl then (a + b) mod N else b.
Proof. The controlled add step (cRippleCirc_correct) writes
if ctrl then (a + b) mod 2ⁿ else b = if ctrl then a + b else b to B (no wrap, since
a + b < 2N ≤ 2ⁿ), preserving Aop = a and — via the frame lemmas — the reduce step's presets
A1 = 2ⁿ − N, A2 = N and clean carries C1 = C2 = false, anc = false. In both control
branches B < 2N (ctrl: a + b < 2N; ¬ctrl: b < N < 2N), so the unconditional reduce step
(modReduce_correct, S6.3a) maps B to B mod N: (a + b) mod N in the ctrl branch, and
b mod N = b in the ¬ctrl branch (b < N, Nat.mod_eq_of_lt). The reduce being unconditional is the
whole trick: b is already a valid residue.
The operand register is intact. cModAdd L leaves Aop holding a (read-only addend). The
controlled add step preserves Aop (P2 of the controlled-ripple invariant) and the reduce step is
disjoint from Aop.
The control bit is preserved. cModAdd L leaves ctrl at its initial value (it is read by the
controlled add step, never written, and the reduce step is disjoint from it). The interleaved modular
multiply needs this to keep each partial-product's control bit equal to the original register bit across
the accumulation loop.
The controlled modular-addition output is a genuine residue in [0, N). In both branches:
(a + b) % N < N (ctrl set) and b < N (ctrl clear). Corollary of cModAdd_correct.
Derived cost #
Derived Toffoli cost of the controlled modular adder: 18n Toffolis, from the exhibited gate
list. Controlled add step 8n (cRippleCirc_toffoli, the quantum×quantum overhead) + reduce step 10n
(modReduceCtrl_toffoli), composed through cost_comp_toffoli_count. Heavier than S6.3b's uncontrolled
12n precisely by the 4× cost of the controlled add (8n vs 2n).
Non-vacuity witness #
A concrete 3-bit controlled-modular-addition layout on Fin 27:
- operand
Aop → {0,1,2}, accumulatorB → {3,4,5}, controlled-add carryCcadd → {6,7,8,9}, control25, cRipple ancilla26, - reduce step-1 constant
A1 → {10,11,12}, step-1 carryC1 → {13,14,15,16}, - reduce step-3 constant
A2 → {17,18,19}, step-3 carryC2 → {20,21,22,23}, reduce ancilla24.
(n = 3 is needed, as in S6.3b: the modular adder requires 2N ≤ 2ⁿ so the controlled add does not
wrap; for N = 3 that forces 2ⁿ ≥ 6, i.e. n ≥ 3.) This exhibits that CModAddLayout is inhabited,
so the headlines are not vacuously quantified. The concrete runs below exercise both control
branches at fully-specified input states: a = 2, b = 2, N = 3, ctrl = true ↦ (2+2) mod 3 = 1, and
the same a, b with ctrl = false ↦ B stays b = 2.
A concrete 3-bit controlled-modular-addition layout on Fin 27.
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.
cModAddLayout2's operand register wires.
cModAddLayout2's accumulator wires.
cModAddLayout2's control wire.
cModAddLayout2's controlled-add clean-ancilla wire.
cModAddLayout2's step-1 constant-register wires.
cModAddLayout2's step-3 constant-register wires.
cModAddLayout2's reduce-step ancilla wire.
Concrete input state for n = 3, N = 3: operand Aop = a (wires 0,1,2), accumulator B = b
(wires 3,4,5), control wire 25 = ctrl, A1 = 5 = 2³ − 3 (wires 10,12), A2 = 3 (wires 17,18),
all carries / ancillas false. Parameterised by the data bits of a, b, and the control bit.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The concrete input state at a wire, as its defining case chain (interface lemma, §9.1).
The hypotheses of cModAdd_correct hold at cModAddState2 (carries/ancillas clear, A1 = 5,
A2 = 3), for any data / control bits. The regValRange register-value preconditions are concrete
sums, discharged by decide.