Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
949 changes: 495 additions & 454 deletions src/point_add/arith/adder.rs

Large diffs are not rendered by default.

107 changes: 70 additions & 37 deletions src/point_add/arith/compare.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::*;

pub(crate) fn cmp_lt_into_fast(b: &mut B, u: &[QubitId], v: &[QubitId], flag: QubitId) {

// The vented D1 core uses the slow (no-carries) comparator which
// saves n peak qubits at cost of ~n CCX per call.
if kal_vent_modadd_enabled() {
cmp_lt_into(b, u, v, flag);
return;
Expand All @@ -14,6 +15,7 @@ pub(crate) fn cmp_lt_into_fast(b: &mut B, u: &[QubitId], v: &[QubitId], flag: Qu
b.x(u[i]);
}

// Forward MAJ sweep with carry ancillae
b.cx(u[0], v[0]);
b.cx(u[0], c_in);
b.ccx(c_in, v[0], carries[0]);
Expand All @@ -27,6 +29,7 @@ pub(crate) fn cmp_lt_into_fast(b: &mut B, u: &[QubitId], v: &[QubitId], flag: Qu

b.cx(u[n - 1], flag);

// Backward inv_MAJ with measurement
for i in (1..n).rev() {
b.cx(carries[i], u[i]);
let m = b.alloc_bit();
Expand Down Expand Up @@ -102,6 +105,9 @@ pub(crate) fn cmp_lt_into_fast_with_cin(
b.free_vec(&carries);
}

/// Like `cmp_lt_into_fast_with_cin` but the n-wide measured-uncompute carry lane
/// is supplied by the caller as borrowed clean (|0>) qubits (restored clean on
/// exit) instead of being allocated — so the comparator adds no peak qubits.
pub(crate) fn cmp_lt_into_fast_with_cin_borrowed_carries(
b: &mut B,
u: &[QubitId],
Expand Down Expand Up @@ -338,6 +344,9 @@ pub(crate) fn cmp_lt_fast_prefix_window_inverse(
b.cx(u[0], v[0]);
}

/// Apply the HMR phase correction for one comparator carry. The exact
/// nonlinear replay is classically conditioned on the HMR result, so its CCX
/// gates execute on half the shots on average.
pub(crate) fn cmp_lt_phase_conditioned_with_cin(
b: &mut B,
u: &[QubitId],
Expand Down Expand Up @@ -365,9 +374,9 @@ pub(crate) fn cmp_lt_phase_conditioned_with_cin(
b.pop_condition();
}

pub(crate) fn cmp_lt_phase_conditioned_borrowed_carries(
b: &mut B,
u: &[QubitId],
pub(crate) fn cmp_lt_phase_conditioned_borrowed_carries(
b: &mut B,
u: &[QubitId],
v: &[QubitId],
c_in: QubitId,
carries: &[QubitId],
Expand All @@ -389,38 +398,41 @@ pub(crate) fn cmp_lt_phase_conditioned_borrowed_carries(
for &q in u {
b.x(q);
}
b.pop_condition();
}

pub(crate) fn cmp_lt_phase_conditioned_with_cin_borrowed_carries(
b: &mut B,
u: &[QubitId],
v: &[QubitId],
c_in: QubitId,
carries: &[QubitId],
phase: BitId,
) {
let n = u.len();
assert_eq!(v.len(), n);
assert!(n > 0);
assert!(carries.len() >= n);

b.push_condition(phase);
for &q in u {
b.x(q);
}
cmp_lt_fast_prefix_window_forward(b, u, v, c_in, carries, c_in, &[]);
b.cz(u[n - 1], u[n - 1]);
cmp_lt_fast_prefix_window_inverse(b, u, v, c_in, carries);
for &q in u {
b.x(q);
}
b.pop_condition();
}

pub(crate) fn cmp_lt_phase_conditioned(
b: &mut B,
u: &[QubitId],
b.pop_condition();
}

/// Apply the HMR phase correction for `u < v + c_in` without an additional
/// quantum control. The nonlinear comparator replay executes only when the
/// classical HMR result is one.
pub(crate) fn cmp_lt_phase_conditioned_with_cin_borrowed_carries(
b: &mut B,
u: &[QubitId],
v: &[QubitId],
c_in: QubitId,
carries: &[QubitId],
phase: BitId,
) {
let n = u.len();
assert_eq!(v.len(), n);
assert!(n > 0);
assert!(carries.len() >= n);

b.push_condition(phase);
for &q in u {
b.x(q);
}
cmp_lt_fast_prefix_window_forward(b, u, v, c_in, carries, c_in, &[]);
b.cz(u[n - 1], u[n - 1]);
cmp_lt_fast_prefix_window_inverse(b, u, v, c_in, carries);
for &q in u {
b.x(q);
}
b.pop_condition();
}

pub(crate) fn cmp_lt_phase_conditioned(
b: &mut B,
u: &[QubitId],
v: &[QubitId],
phase: BitId,
) {
Expand Down Expand Up @@ -578,6 +590,12 @@ pub(crate) fn ccx_cmp_lt_into_fast_prefix_targets_split(
}
}


/// Slow (carry-array-free) `flag ^= (u < v + c_in)` comparator. Like
/// `cmp_lt_into` but threads a borrowed carry-IN qubit (left clean on exit)
/// through the bottom MAJ. Peak cost: 0 extra qubits beyond the supplied c_in
/// (the MAJ sweep works in place on `u`). Toffoli ~2n (no measured uncompute),
/// traded against the n-wide carry array the fast variant allocates.
pub(crate) fn cmp_lt_into_with_cin_slow(
b: &mut B,
u: &[QubitId],
Expand Down Expand Up @@ -611,29 +629,43 @@ pub(crate) fn cmp_lt_into(b: &mut B, u: &[QubitId], v: &[QubitId], flag: QubitId

let c_in = b.alloc_qubit();

// ~u in place (X is free in the metric).
for i in 0..n {
b.x(u[i]);
}

// Forward MAJ sweep — n MAJs (one more than cuccaro_add, which omits
// the top one because it doesn't need the carry-out).
maj(b, c_in, v[0], u[0]);
for i in 1..n {
maj(b, u[i - 1], v[i], u[i]);
}

// u[n-1] now holds the high carry = (u < v).
b.cx(u[n - 1], flag);

// Inverse sweep restores u and v to their (negated u) state.
for i in (1..n).rev() {
inv_maj(b, u[i - 1], v[i], u[i]);
}
inv_maj(b, c_in, v[0], u[0]);

// Un-negate u.
for i in 0..n {
b.x(u[i]);
}

b.free(c_in);
}

/// Controlled (`target ^= ctrl & (u < v)`) borrow-comparator that takes its
/// `c_in` + `carries` lanes as borrowed clean (|0>) qubits instead of allocating
/// them. Identical gate sequence to `ccx_cmp_lt_into_fast` except the final
/// reduction is `ccx(ctrl, u[n-1], target)` (controlled). The borrowed lanes are
/// restored to |0> by the measured backward inv-MAJ sweep, so the host slice is
/// returned clean (Bennett/measured-clean, safe outside emit_inverse since it
/// uses hmr/cz_if not a recompute). Used by the GCD branch-bit comparator to host
/// its transient on the idle future-log region, freeing the peak qubit it would
/// otherwise allocate at the branch_bits instant.
pub(crate) fn ccx_cmp_lt_into_fast_borrowed_carries(
b: &mut B,
u: &[QubitId],
Expand Down Expand Up @@ -684,3 +716,4 @@ pub(crate) fn ccx_cmp_lt_into_fast_borrowed_carries(
b.x(u[i]);
}
}

65 changes: 65 additions & 0 deletions src/point_add/arith/compare.rs.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
--- /Users/zuiris/ecdsa.fail/challenge/src/point_add/arith/compare.rs
+++ /Users/zuiris/ecdsa.fail/challenge/src/point_add/arith/compare.rs
@@ -158,6 +158,56 @@
b.free_vec(&carries);
b.free(c_in);
}
+
+pub(crate) fn ccx_cmp_lt_into_fast_vent_uncompute(b: &mut B, u: &[QubitId], v: &[QubitId], ctrl: QubitId, target: QubitId) {
+ if kal_vent_modadd_enabled() {
+ let flag = b.alloc_qubit();
+ cmp_lt_into(b, u, v, flag);
+ let m = b.alloc_bit();
+ b.hmr(target, m);
+ b.cz_if(ctrl, flag, m);
+ cmp_lt_into(b, u, v, flag);
+ b.free(flag);
+ return;
+ }
+
+ let n = u.len();
+ assert_eq!(n, v.len());
+ let c_in = b.alloc_qubit();
+ let carries = b.alloc_qubits(n);
+ for i in 0..n {
+ b.x(u[i]);
+ }
+
+ b.cx(u[0], v[0]);
+ b.cx(u[0], c_in);
+ b.ccx(c_in, v[0], carries[0]);
+ b.cx(carries[0], u[0]);
+ for i in 1..n {
+ b.cx(u[i], v[i]);
+ b.cx(u[i], u[i - 1]);
+ b.ccx(u[i - 1], v[i], carries[i]);
+ b.cx(carries[i], u[i]);
+ }
+
+ let m_tgt = b.alloc_bit();
+ b.hmr(target, m_tgt);
+ b.cz_if(ctrl, u[n - 1], m_tgt);
+
+ for i in (1..n).rev() {
+ b.cx(carries[i], u[i]);
+ let m = b.alloc_bit();
+ b.hmr(carries[i], m);
+ b.cz_if(u[i - 1], v[i], m);
+ b.cx(u[i], u[i - 1]);
+ b.cx(u[i], v[i]);
+ }
+ b.cx(carries[0], u[0]);
+ let m0 = b.alloc_bit();
+ b.hmr(carries[0], m0);
+ b.cz_if(c_in, v[0], m0);
+ b.cx(u[0], c_in);
+ b.cx(u[0], v[0]);
+
+ for i in 0..n {
+ b.x(u[i]);
+ }
+ b.free_vec(&carries);
+ b.free(c_in);
+}

pub(crate) fn ccx_cmp_lt_into_fast_prefix_targets(
Loading
Loading