Skip to content

Commit 2e9e940

Browse files
authored
Elliptic curve cryptography algorithm (top-down) (#923)
* Elliptic curve cryptography algorithm * Underscore in bloq doc * remove import * * remove print * little note for mod inv listing * shim note * un-private
1 parent d6caf66 commit 2e9e940

22 files changed

Lines changed: 1992 additions & 1 deletion

dev_tools/autogenerate-bloqs-notebooks-v2.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import qualtran.bloqs.chemistry.trotter.ising.unitaries
7373
import qualtran.bloqs.chemistry.trotter.trotterized_unitary
7474
import qualtran.bloqs.data_loading.qrom
75+
import qualtran.bloqs.factoring.ecc
7576
import qualtran.bloqs.factoring.mod_exp
7677
import qualtran.bloqs.hamiltonian_simulation.hamiltonian_simulation_by_gqsp
7778
import qualtran.bloqs.mcmt.and_bloq
@@ -339,6 +340,21 @@
339340
bloq_specs=[qualtran.bloqs.factoring.mod_mul._MODMUL_DOC],
340341
directory=f'{SOURCE_DIR}/bloqs/factoring',
341342
),
343+
NotebookSpecV2(
344+
title='Elliptic Curve Cryptography',
345+
module=qualtran.bloqs.factoring.ecc,
346+
bloq_specs=[
347+
qualtran.bloqs.factoring.ecc.find_ecc_private_key._ECC_BLOQ_DOC,
348+
qualtran.bloqs.factoring.ecc.ec_phase_estimate_r._EC_PE_BLOQ_DOC,
349+
qualtran.bloqs.factoring.ecc.ec_add_r._ECC_ADD_R_BLOQ_DOC,
350+
qualtran.bloqs.factoring.ecc.ec_add_r._EC_WINDOW_ADD_BLOQ_DOC,
351+
],
352+
),
353+
NotebookSpecV2(
354+
title='Elliptic Curve Addition',
355+
module=qualtran.bloqs.factoring.ecc.ec_add,
356+
bloq_specs=[qualtran.bloqs.factoring.ecc.ec_add._EC_ADD_DOC],
357+
),
342358
]
343359

344360

docs/bloqs/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ Bloqs Library
6161
arithmetic/conversions.ipynb
6262
factoring/mod_exp.ipynb
6363
factoring/mod_mul.ipynb
64+
factoring/ecc/ecc.ipynb
65+
factoring/ecc/ec_add.ipynb
6466

6567
.. toctree::
6668
:maxdepth: 2

qualtran/_infra/data_types.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ def assert_valid_classical_val_array(
226226
if np.any(val_array >= 2 ** (self.bitsize - 1)):
227227
raise ValueError(f"Too-large classical {self}s encountered in {debug_str}")
228228

229+
def __str__(self):
230+
return f'QInt({self.bitsize})'
231+
229232

230233
@attrs.frozen
231234
class QIntOnesComp(QDType):
@@ -317,6 +320,9 @@ def assert_valid_classical_val_array(
317320
if np.any(val_array >= 2**self.bitsize):
318321
raise ValueError(f"Too-large classical values encountered in {debug_str}")
319322

323+
def __str__(self):
324+
return f'QUInt({self.bitsize})'
325+
320326

321327
@attrs.frozen
322328
class BoundedQUInt(QDType):
@@ -516,7 +522,7 @@ class QMontgomeryUInt(QDType):
516522
fast modular multiplication.
517523
518524
In order to convert an unsigned integer from a finite field x % p into Montgomery form you
519-
first must choose a value r > p where gcd(r, p) = 1. Typically this value is a power of 2.
525+
first must choose a value r > p where gcd(r, p) = 1. Typically, this value is a power of 2.
520526
521527
Conversion to Montgomery form:
522528
[x] = (x * r) % p

qualtran/bloqs/arithmetic/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@
3939
SumOfSquares,
4040
)
4141
from qualtran.bloqs.arithmetic.sorting import BitonicSort, Comparator
42+
43+
from ._shims import AddK, CHalf, Lt, MultiCToffoli, Negate, Sub
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""This module has a selection of minimally-implemented modular arithmetic primitives.
15+
16+
These bloqs serve as the callees in the call graphs of the algorithms found
17+
in `qualtran.bloqs.factoring` and `qualtran.bloqs.mod_arithmetic`. They are place-holders,
18+
so we don't have undefined symbols and can still merge the high-level algorithms. These shims
19+
will be fleshed out and moved to their final organizational location soon (written: 2024-05-06).
20+
"""
21+
from functools import cached_property
22+
from typing import Set
23+
24+
from attrs import frozen
25+
26+
from qualtran import Bloq, QBit, QUInt, Register, Signature
27+
from qualtran.bloqs.basic_gates import Toffoli
28+
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
29+
30+
31+
@frozen
32+
class MultiCToffoli(Bloq):
33+
n: int
34+
35+
@cached_property
36+
def signature(self) -> 'Signature':
37+
return Signature([Register('ctrl', QBit(), shape=(self.n,)), Register('target', QBit())])
38+
39+
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
40+
return {(Toffoli(), self.n - 2)}
41+
42+
43+
@frozen
44+
class AddK(Bloq):
45+
n: int
46+
k: int
47+
48+
@cached_property
49+
def signature(self) -> 'Signature':
50+
return Signature([Register('x', QUInt(self.n))])
51+
52+
53+
@frozen
54+
class Sub(Bloq):
55+
n: int
56+
57+
@cached_property
58+
def signature(self) -> 'Signature':
59+
return Signature([Register('x', QUInt(self.n)), Register('y', QUInt(self.n))])
60+
61+
62+
@frozen
63+
class Lt(Bloq):
64+
n: int
65+
signed: bool = False
66+
67+
@cached_property
68+
def signature(self) -> 'Signature':
69+
return Signature(
70+
[Register('x', QUInt(self.n)), Register('y', QUInt(self.n)), Register('out', QBit())]
71+
)
72+
73+
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
74+
# litinski
75+
return {(Toffoli(), self.n)}
76+
77+
78+
@frozen
79+
class CHalf(Bloq):
80+
n: int
81+
82+
@cached_property
83+
def signature(self) -> 'Signature':
84+
return Signature([Register('ctrl', QBit()), Register('x', QUInt(self.n))])
85+
86+
87+
@frozen
88+
class Negate(Bloq):
89+
n: int
90+
91+
@cached_property
92+
def signature(self) -> 'Signature':
93+
return Signature([Register('x', QUInt(self.n))])
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# isort:skip_file
16+
17+
r"""Bloqs for breaking elliptic curve cryptography systems via the discrete log.
18+
19+
Elliptic curve cryptography is a form of public key cryptography based on the finite
20+
field of elliptic curves. For our purposes, we will denote the group operation as addition
21+
(whose definition we will explore later) $A + B$. We will denote repeated addition
22+
as $[k] A = A + \dots + A$ ($k$ times).
23+
24+
Within this algebra, the cryptographic scheme relates the public and private keys via
25+
$$
26+
Q = [k] P
27+
$$
28+
for private key $k$, public key $Q$, and a choice of base point $P$. The cryptographic
29+
security comes from the difficulty of inverting the multiplication. I.e. it is difficult
30+
to do a discrete logarithm in this field.
31+
32+
Using Shor's algorithm for the discrete logarithm, we can find $k$ in polynomial time
33+
with a quantum algorithm.
34+
"""
35+
36+
from .ec_point import ECPoint
37+
from .ec_add import ECAdd
38+
from .ec_add_r import ECAddR, ECWindowAddR
39+
from .ec_phase_estimate_r import ECPhaseEstimateR
40+
from .find_ecc_private_key import FindECCPrivateKey
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from functools import cached_property
16+
17+
from attrs import frozen
18+
19+
from qualtran import Bloq, DecomposeTypeError, QBit, Register, Side, Signature, Soquet
20+
from qualtran.drawing import RarrowTextBox, WireSymbol
21+
22+
23+
@frozen
24+
class MeasureQFT(Bloq):
25+
n: int
26+
27+
@cached_property
28+
def signature(self) -> 'Signature':
29+
return Signature([Register('x', QBit(), shape=(self.n,), side=Side.LEFT)])
30+
31+
def decompose_bloq(self) -> 'CompositeBloq':
32+
raise DecomposeTypeError('MeasureQFT is a placeholder, atomic bloq.')
33+
34+
def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol':
35+
if soq.reg.name == 'x':
36+
return RarrowTextBox('MeasQFT')
37+
38+
def __str__(self):
39+
return 'MeasureQFT'
40+
41+
def cost_attrs(self):
42+
return [('n', self.n)]

0 commit comments

Comments
 (0)