Skip to content

Commit

Permalink
Implement CtrlScaleModAdd and CModAddK bloqs for Modular Exponentiati…
Browse files Browse the repository at this point in the history
…on (#1432)

* Add some classical simulation

* Implement primitives for ModExp

* Fix serialization test error

* Change Union -> SymbolicInt

* Fix nits

* Better symbolic decomposition error messages

* Fix merge conflicts

* Fixed docstring to be more readable (hopefully)

* Address nits

---------

Co-authored-by: Matthew Harrigan <[email protected]>
  • Loading branch information
fpapa250 and mpharrigan authored Oct 17, 2024
1 parent 3210c30 commit 0220df2
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 36 deletions.
2 changes: 2 additions & 0 deletions dev_tools/qualtran_dev_tools/notebook_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@
qualtran.bloqs.mod_arithmetic.mod_addition._MOD_ADD_DOC,
qualtran.bloqs.mod_arithmetic.mod_addition._MOD_ADD_K_DOC,
qualtran.bloqs.mod_arithmetic.mod_addition._C_MOD_ADD_DOC,
qualtran.bloqs.mod_arithmetic.mod_addition._C_MOD_ADD_K_DOC,
qualtran.bloqs.mod_arithmetic.mod_addition._CTRL_SCALE_MOD_ADD_DOC,
],
),
NotebookSpecV2(
Expand Down
5 changes: 3 additions & 2 deletions qualtran/bloqs/basic_gates/z_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
)
from qualtran.bloqs.bookkeeping import ArbitraryClifford
from qualtran.drawing import Circle, directional_text_box, Text, TextBox, WireSymbol
from qualtran.symbolics import SymbolicInt

if TYPE_CHECKING:
import cirq
Expand Down Expand Up @@ -453,7 +454,7 @@ class IntState(_IntVector):
val: The register of size `bitsize` which initializes the value `val`.
"""

def __init__(self, val: Union[int, sympy.Expr], bitsize: Union[int, sympy.Expr]):
def __init__(self, val: SymbolicInt, bitsize: SymbolicInt):
self.__attrs_init__(val=val, bitsize=bitsize, state=True)


Expand All @@ -478,7 +479,7 @@ class IntEffect(_IntVector):
val: The register of size `bitsize` which de-allocates the value `val`.
"""

def __init__(self, val: int, bitsize: int):
def __init__(self, val: SymbolicInt, bitsize: SymbolicInt):
self.__attrs_init__(val=val, bitsize=bitsize, state=False)


Expand Down
240 changes: 240 additions & 0 deletions qualtran/bloqs/mod_arithmetic/mod_addition.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,246 @@
"show_call_graph(cmodadd_example_g)\n",
"show_counts_sigma(cmodadd_example_sigma)"
]
},
{
"cell_type": "markdown",
"id": "0523961e",
"metadata": {
"cq.autogen": "CModAddK.bloq_doc.md"
},
"source": [
"## `CModAddK`\n",
"Perform x += k mod m for constant k, m and quantum x.\n",
"\n",
"#### Parameters\n",
" - `k`: The integer to add to `x`.\n",
" - `mod`: The modulus for the addition.\n",
" - `bitsize`: The bitsize of the `x` register. \n",
"\n",
"#### Registers\n",
" - `ctrl`: The control bit\n",
" - `x`: The register to perform the in-place modular addition. \n",
"\n",
"#### References\n",
" - [How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits](https://arxiv.org/abs/1905.09749). Gidney and Ekerå 2019. The reference implementation in section 2.2 uses CModAddK, but the circuit that it points to is just ModAdd (not ModAddK). This ModAdd is less efficient than the circuit later introduced in the Litinski paper so we choose to use that since it is more efficient and already implemented in Qualtran.\n",
" - [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585). Litinski et al. 2023. This CModAdd circuit uses 2 fewer additions than the implementation referenced in the paper above. Because of this we choose to use this CModAdd bloq instead.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "341211fa",
"metadata": {
"cq.autogen": "CModAddK.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.mod_arithmetic import CModAddK"
]
},
{
"cell_type": "markdown",
"id": "6b00aef7",
"metadata": {
"cq.autogen": "CModAddK.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b8877f17",
"metadata": {
"cq.autogen": "CModAddK.cmod_add_k"
},
"outputs": [],
"source": [
"n, m, k = sympy.symbols('n m k')\n",
"cmod_add_k = CModAddK(bitsize=n, mod=m, k=k)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87fe8b8f",
"metadata": {
"cq.autogen": "CModAddK.cmod_add_k_small"
},
"outputs": [],
"source": [
"cmod_add_k_small = CModAddK(bitsize=4, mod=7, k=1)"
]
},
{
"cell_type": "markdown",
"id": "f44f0268",
"metadata": {
"cq.autogen": "CModAddK.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7a02d6e",
"metadata": {
"cq.autogen": "CModAddK.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([cmod_add_k, cmod_add_k_small],\n",
" ['`cmod_add_k`', '`cmod_add_k_small`'])"
]
},
{
"cell_type": "markdown",
"id": "48b87ff2",
"metadata": {
"cq.autogen": "CModAddK.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f6e6770b",
"metadata": {
"cq.autogen": "CModAddK.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"cmod_add_k_g, cmod_add_k_sigma = cmod_add_k.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(cmod_add_k_g)\n",
"show_counts_sigma(cmod_add_k_sigma)"
]
},
{
"cell_type": "markdown",
"id": "21f93349",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.bloq_doc.md"
},
"source": [
"## `CtrlScaleModAdd`\n",
"Perform y += x*k mod m for constant k, m and quantum x, y.\n",
"\n",
"#### Parameters\n",
" - `k`: The constant integer to scale `x` before adding into `y`.\n",
" - `mod`: The modulus of the addition\n",
" - `bitsize`: The size of the two registers. \n",
"\n",
"#### Registers\n",
" - `ctrl`: The control bit\n",
" - `x`: The 'source' quantum register containing the integer to be scaled and added to `y`.\n",
" - `y`: The 'destination' quantum register to which the addition will apply. \n",
"\n",
"#### References\n",
" - [How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits](https://arxiv.org/abs/1905.09749). Construction based on description in section 2.2 paragraph 4. We add n And/And† bloqs because the bloq is controlled, but the construction also involves modular addition controlled on the qubits comprising register x.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4ac170e5",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.mod_arithmetic import CtrlScaleModAdd"
]
},
{
"cell_type": "markdown",
"id": "58ee7de2",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "73c2c6f7",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.ctrl_scale_mod_add"
},
"outputs": [],
"source": [
"n, m, k = sympy.symbols('n m k')\n",
"ctrl_scale_mod_add = CtrlScaleModAdd(bitsize=n, mod=m, k=k)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e822d5eb",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.ctrl_scale_mod_add_small"
},
"outputs": [],
"source": [
"ctrl_scale_mod_add_small = CtrlScaleModAdd(bitsize=4, mod=7, k=1)"
]
},
{
"cell_type": "markdown",
"id": "fe4c8957",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4dc8923",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([ctrl_scale_mod_add, ctrl_scale_mod_add_small],\n",
" ['`ctrl_scale_mod_add`', '`ctrl_scale_mod_add_small`'])"
]
},
{
"cell_type": "markdown",
"id": "97d6888d",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bd734f6b",
"metadata": {
"cq.autogen": "CtrlScaleModAdd.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"ctrl_scale_mod_add_g, ctrl_scale_mod_add_sigma = ctrl_scale_mod_add.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(ctrl_scale_mod_add_g)\n",
"show_counts_sigma(ctrl_scale_mod_add_sigma)"
]
}
],
"metadata": {
Expand Down
Loading

0 comments on commit 0220df2

Please sign in to comment.