Skip to content

Commit 0f88a0b

Browse files
fpapa250mpharrigan
andauthored
Fix additional bug in ECAdd (#1666)
Team from PsiQuantum reached out and pointed out another bug in the circuit nearly equivalent to one of the other ones that I found/fixed. When [(a, b) = (0, 0) AND x = 0] OR [(x, y) = (0, 0) AND a = 0], the f_1 flag is not cleared. I added the same fix to this situation that I did in the similar scenario when the b/y values are all 0 for the f_2 flag. This cost 2 3n-controlled toffolis. --------- Co-authored-by: Matthew Harrigan <[email protected]>
1 parent 73ee804 commit 0f88a0b

File tree

2 files changed

+104
-191
lines changed

2 files changed

+104
-191
lines changed

qualtran/bloqs/cryptography/ecc/ec_add.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ class _ECAddStepTwo(Bloq):
219219
References:
220220
[How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585)
221221
Fig 10.
222+
[Validation of Quantum Elliptic Curve Point Addition Circuits](https://arxiv.org/abs/2506.03318)
223+
Fig 1.
222224
"""
223225

224226
n: 'SymbolicInt'
@@ -665,7 +667,7 @@ class _ECAddStepFive(Bloq):
665667
is 0, the computed λ is undefined (and with this construction the computed λ will be set to 0),
666668
however the λ is non-zero and should be cleared with λ_r. We accomplish this with a controled
667669
Xor bloq controlled on the ctrl qubit and the condition that the x register (a - x_r) = 0. In
668-
this ase we clear the λ register with λ_r.
670+
this case we clear the λ register with λ_r.
669671
670672
Args:
671673
n: The bitsize of the two registers storing the elliptic curve point
@@ -686,6 +688,8 @@ class _ECAddStepFive(Bloq):
686688
References:
687689
[How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585)
688690
Fig 10.
691+
[Validation of Quantum Elliptic Curve Point Addition Circuits](https://arxiv.org/abs/2506.03318)
692+
Fig 2.
689693
"""
690694

691695
n: 'SymbolicInt'
@@ -826,12 +830,16 @@ class _ECAddStepSix(Bloq):
826830
Include bugfixes for the following scenarios:
827831
1. f_2 is improperly cleared when ((x, y) = (0, 0) AND b = 0) OR ((a, b) = (0, 0) AND
828832
y = 0).
829-
2. f_4 is improperly cleared when P_1 = P_2 AND f_4 is set.
833+
2. f_1 is improperly cleared when ((x, y) = (0, 0) AND a = 0) OR ((a, b) = (0, 0) AND
834+
x = 0).
835+
3. f_4 is improperly cleared when P_1 = P_2 AND f_4 is set.
830836
831837
The bugs are fixed respectively by:
832838
1. Clearing f_2 when x = y = b = 0 OR a = b = y = 0 using an XGate controlled on those
833839
registers.
834-
2. Moving the CModSub and CModAdd bloqs before the Equals bloq.
840+
2. Clearing f_1 when x = y = a = 0 OR a = b = x = 0 using an XGate controlled on those
841+
registers.
842+
3. Moving the CModSub and CModAdd bloqs before the Equals bloq.
835843
836844
Args:
837845
n: The bitsize of the two registers storing the elliptic curve point
@@ -853,6 +861,8 @@ class _ECAddStepSix(Bloq):
853861
References:
854862
[How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585)
855863
Fig 10.
864+
[Validation of Quantum Elliptic Curve Point Addition Circuits](https://arxiv.org/abs/2506.03318)
865+
Fig 3.
856866
"""
857867

858868
n: 'SymbolicInt'
@@ -917,8 +927,12 @@ def build_composite_bloq(
917927
f3 = f_ctrls[1]
918928
f4 = f_ctrls[2]
919929

920-
# Unset f2 if ((a, b) = (0, 0) AND y = 0) OR ((x, y) = (0, 0) AND b = 0).
930+
# Unset f1 if ((x, y) = (0, 0) AND a = 0) OR ((a, b) = (0, 0) AND x = 0).
921931
mcx = XGate().controlled(CtrlSpec(qdtypes=QMontgomeryUInt(self.n), cvs=[0, 0, 0]))
932+
[a, x, y], f1 = bb.add(mcx, ctrl=[a, x, y], q=f1)
933+
[x, a, b], f1 = bb.add(mcx, ctrl=[x, a, b], q=f1)
934+
935+
# Unset f2 if ((a, b) = (0, 0) AND y = 0) OR ((x, y) = (0, 0) AND b = 0).
922936
[a, b, y], f2 = bb.add(mcx, ctrl=[a, b, y], q=f2)
923937
[x, y, b], f2 = bb.add(mcx, ctrl=[x, y, b], q=f2)
924938

@@ -1015,7 +1029,7 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT:
10151029
cvs2 = HasLength(2 * self.n)
10161030
return {
10171031
MultiControlX(cvs=cvs2): 1,
1018-
XGate().controlled(CtrlSpec(qdtypes=QMontgomeryUInt(self.n), cvs=[0, 0, 0])): 2,
1032+
XGate().controlled(CtrlSpec(qdtypes=QMontgomeryUInt(self.n), cvs=[0, 0, 0])): 4,
10191033
MultiControlX(cvs=[0] * 3): 1,
10201034
CModSub(QMontgomeryUInt(self.n), mod=self.mod): 1,
10211035
CModAdd(QMontgomeryUInt(self.n), mod=self.mod): 1,

0 commit comments

Comments
 (0)