From cee69546f0f1db771d1b7dc6ef23a7478e78efd5 Mon Sep 17 00:00:00 2001 From: Frankie Papa Date: Tue, 24 Sep 2024 10:27:27 -0700 Subject: [PATCH] Add serialization for ECPoint arg type. (#1412) Add serialization for ECPoint arg type --- qualtran/protos/bloq.proto | 3 + qualtran/protos/bloq_pb2.py | 43 ++++++------- qualtran/protos/bloq_pb2.pyi | 84 ++++++++++++------------- qualtran/protos/ec_point.proto | 25 ++++++++ qualtran/protos/ec_point_pb2.py | 27 ++++++++ qualtran/protos/ec_point_pb2.pyi | 57 +++++++++++++++++ qualtran/serialization/bloq.py | 6 ++ qualtran/serialization/ec_point.py | 35 +++++++++++ qualtran/serialization/ec_point_test.py | 32 ++++++++++ 9 files changed, 248 insertions(+), 64 deletions(-) create mode 100644 qualtran/protos/ec_point.proto create mode 100644 qualtran/protos/ec_point_pb2.py create mode 100644 qualtran/protos/ec_point_pb2.pyi create mode 100644 qualtran/serialization/ec_point.py create mode 100644 qualtran/serialization/ec_point_test.py diff --git a/qualtran/protos/bloq.proto b/qualtran/protos/bloq.proto index c5e0bc30a..40e467b56 100644 --- a/qualtran/protos/bloq.proto +++ b/qualtran/protos/bloq.proto @@ -18,6 +18,7 @@ syntax = "proto3"; import "qualtran/protos/annotations.proto"; import "qualtran/protos/args.proto"; +import "qualtran/protos/ec_point.proto"; import "qualtran/protos/registers.proto"; import "qualtran/protos/data_types.proto"; import "qualtran/protos/ctrl_spec.proto"; @@ -49,6 +50,8 @@ message BloqArg { // Ctrl Spec for controlled bloqs CtrlSpec ctrl_spec = 12; Complex complex_val = 13; + // An elliptical curve point for ECC bloqs + ECPoint ec_point = 14; } } diff --git a/qualtran/protos/bloq_pb2.py b/qualtran/protos/bloq_pb2.py index 5397b0d0a..383b347f0 100644 --- a/qualtran/protos/bloq_pb2.py +++ b/qualtran/protos/bloq_pb2.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: qualtran/protos/bloq.proto -# Protobuf Python Version: 5.26.1 +# Protobuf Python Version: 4.25.3 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -14,35 +14,36 @@ from qualtran.protos import annotations_pb2 as qualtran_dot_protos_dot_annotations__pb2 from qualtran.protos import args_pb2 as qualtran_dot_protos_dot_args__pb2 +from qualtran.protos import ec_point_pb2 as qualtran_dot_protos_dot_ec__point__pb2 from qualtran.protos import registers_pb2 as qualtran_dot_protos_dot_registers__pb2 from qualtran.protos import data_types_pb2 as qualtran_dot_protos_dot_data__types__pb2 from qualtran.protos import ctrl_spec_pb2 as qualtran_dot_protos_dot_ctrl__spec__pb2 from qualtran.protos import sympy_pb2 as qualtran_dot_protos_dot_sympy__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aqualtran/protos/bloq.proto\x12\x08qualtran\x1a!qualtran/protos/annotations.proto\x1a\x1aqualtran/protos/args.proto\x1a\x1fqualtran/protos/registers.proto\x1a qualtran/protos/data_types.proto\x1a\x1fqualtran/protos/ctrl_spec.proto\x1a\x1bqualtran/protos/sympy.proto\"\xa5\x03\n\x07\x42loqArg\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\x07int_val\x18\x02 \x01(\x03H\x00\x12\x13\n\tfloat_val\x18\x03 \x01(\x01H\x00\x12\x14\n\nstring_val\x18\x04 \x01(\tH\x00\x12$\n\nsympy_expr\x18\x05 \x01(\x0b\x32\x0e.qualtran.TermH\x00\x12$\n\x07ndarray\x18\x06 \x01(\x0b\x32\x11.qualtran.NDArrayH\x00\x12\x11\n\x07subbloq\x18\x07 \x01(\x05H\x00\x12\x18\n\x0e\x63irq_json_gzip\x18\x08 \x01(\x0cH\x00\x12)\n\nqdata_type\x18\t \x01(\x0b\x32\x13.qualtran.QDataTypeH\x00\x12&\n\x08register\x18\n \x01(\x0b\x32\x12.qualtran.RegisterH\x00\x12(\n\tregisters\x18\x0b \x01(\x0b\x32\x13.qualtran.RegistersH\x00\x12\'\n\tctrl_spec\x18\x0c \x01(\x0b\x32\x12.qualtran.CtrlSpecH\x00\x12(\n\x0b\x63omplex_val\x18\r \x01(\x0b\x32\x11.qualtran.ComplexH\x00\x42\x05\n\x03val\"\xe8\x02\n\x0b\x42loqLibrary\x12\x0c\n\x04name\x18\x01 \x01(\t\x12:\n\x05table\x18\x02 \x03(\x0b\x32+.qualtran.BloqLibrary.BloqWithDecomposition\x1a\x8e\x02\n\x15\x42loqWithDecomposition\x12\x0f\n\x07\x62loq_id\x18\x01 \x01(\x05\x12+\n\rdecomposition\x18\x02 \x03(\x0b\x32\x14.qualtran.Connection\x12P\n\x0b\x62loq_counts\x18\x03 \x03(\x0b\x32;.qualtran.BloqLibrary.BloqWithDecomposition.BloqCountsEntry\x12\x1c\n\x04\x62loq\x18\x04 \x01(\x0b\x32\x0e.qualtran.Bloq\x1aG\n\x0f\x42loqCountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.qualtran.IntOrSympy:\x02\x38\x01\"\x8a\x01\n\x04\x42loq\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1f\n\x04\x61rgs\x18\x02 \x03(\x0b\x32\x11.qualtran.BloqArg\x12&\n\tregisters\x18\x03 \x01(\x0b\x32\x13.qualtran.Registers\x12+\n\x0ct_complexity\x18\x04 \x01(\x0b\x32\x15.qualtran.TComplexity\"4\n\x0c\x42loqInstance\x12\x13\n\x0binstance_id\x18\x01 \x01(\x05\x12\x0f\n\x07\x62loq_id\x18\x02 \x01(\x05\"\x8d\x01\n\x06Soquet\x12/\n\rbloq_instance\x18\x01 \x01(\x0b\x32\x16.qualtran.BloqInstanceH\x00\x12\x14\n\ndangling_t\x18\x02 \x01(\tH\x00\x12$\n\x08register\x18\x03 \x01(\x0b\x32\x12.qualtran.Register\x12\r\n\x05index\x18\x04 \x03(\x05\x42\x07\n\x05\x62inst\"M\n\nConnection\x12\x1e\n\x04left\x18\x01 \x01(\x0b\x32\x10.qualtran.Soquet\x12\x1f\n\x05right\x18\x02 \x01(\x0b\x32\x10.qualtran.Soquetb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aqualtran/protos/bloq.proto\x12\x08qualtran\x1a!qualtran/protos/annotations.proto\x1a\x1aqualtran/protos/args.proto\x1a\x1equaltran/protos/ec_point.proto\x1a\x1fqualtran/protos/registers.proto\x1a qualtran/protos/data_types.proto\x1a\x1fqualtran/protos/ctrl_spec.proto\x1a\x1bqualtran/protos/sympy.proto\"\xcc\x03\n\x07\x42loqArg\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\x07int_val\x18\x02 \x01(\x03H\x00\x12\x13\n\tfloat_val\x18\x03 \x01(\x01H\x00\x12\x14\n\nstring_val\x18\x04 \x01(\tH\x00\x12$\n\nsympy_expr\x18\x05 \x01(\x0b\x32\x0e.qualtran.TermH\x00\x12$\n\x07ndarray\x18\x06 \x01(\x0b\x32\x11.qualtran.NDArrayH\x00\x12\x11\n\x07subbloq\x18\x07 \x01(\x05H\x00\x12\x18\n\x0e\x63irq_json_gzip\x18\x08 \x01(\x0cH\x00\x12)\n\nqdata_type\x18\t \x01(\x0b\x32\x13.qualtran.QDataTypeH\x00\x12&\n\x08register\x18\n \x01(\x0b\x32\x12.qualtran.RegisterH\x00\x12(\n\tregisters\x18\x0b \x01(\x0b\x32\x13.qualtran.RegistersH\x00\x12\'\n\tctrl_spec\x18\x0c \x01(\x0b\x32\x12.qualtran.CtrlSpecH\x00\x12(\n\x0b\x63omplex_val\x18\r \x01(\x0b\x32\x11.qualtran.ComplexH\x00\x12%\n\x08\x65\x63_point\x18\x0e \x01(\x0b\x32\x11.qualtran.ECPointH\x00\x42\x05\n\x03val\"\xe8\x02\n\x0b\x42loqLibrary\x12\x0c\n\x04name\x18\x01 \x01(\t\x12:\n\x05table\x18\x02 \x03(\x0b\x32+.qualtran.BloqLibrary.BloqWithDecomposition\x1a\x8e\x02\n\x15\x42loqWithDecomposition\x12\x0f\n\x07\x62loq_id\x18\x01 \x01(\x05\x12+\n\rdecomposition\x18\x02 \x03(\x0b\x32\x14.qualtran.Connection\x12P\n\x0b\x62loq_counts\x18\x03 \x03(\x0b\x32;.qualtran.BloqLibrary.BloqWithDecomposition.BloqCountsEntry\x12\x1c\n\x04\x62loq\x18\x04 \x01(\x0b\x32\x0e.qualtran.Bloq\x1aG\n\x0f\x42loqCountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.qualtran.IntOrSympy:\x02\x38\x01\"\x8a\x01\n\x04\x42loq\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1f\n\x04\x61rgs\x18\x02 \x03(\x0b\x32\x11.qualtran.BloqArg\x12&\n\tregisters\x18\x03 \x01(\x0b\x32\x13.qualtran.Registers\x12+\n\x0ct_complexity\x18\x04 \x01(\x0b\x32\x15.qualtran.TComplexity\"4\n\x0c\x42loqInstance\x12\x13\n\x0binstance_id\x18\x01 \x01(\x05\x12\x0f\n\x07\x62loq_id\x18\x02 \x01(\x05\"\x8d\x01\n\x06Soquet\x12/\n\rbloq_instance\x18\x01 \x01(\x0b\x32\x16.qualtran.BloqInstanceH\x00\x12\x14\n\ndangling_t\x18\x02 \x01(\tH\x00\x12$\n\x08register\x18\x03 \x01(\x0b\x32\x12.qualtran.Register\x12\r\n\x05index\x18\x04 \x03(\x05\x42\x07\n\x05\x62inst\"M\n\nConnection\x12\x1e\n\x04left\x18\x01 \x01(\x0b\x32\x10.qualtran.Soquet\x12\x1f\n\x05right\x18\x02 \x01(\x0b\x32\x10.qualtran.Soquetb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'qualtran.protos.bloq_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._loaded_options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._options = None _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._serialized_options = b'8\001' - _globals['_BLOQARG']._serialized_start=233 - _globals['_BLOQARG']._serialized_end=654 - _globals['_BLOQLIBRARY']._serialized_start=657 - _globals['_BLOQLIBRARY']._serialized_end=1017 - _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION']._serialized_start=747 - _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION']._serialized_end=1017 - _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._serialized_start=946 - _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._serialized_end=1017 - _globals['_BLOQ']._serialized_start=1020 - _globals['_BLOQ']._serialized_end=1158 - _globals['_BLOQINSTANCE']._serialized_start=1160 - _globals['_BLOQINSTANCE']._serialized_end=1212 - _globals['_SOQUET']._serialized_start=1215 - _globals['_SOQUET']._serialized_end=1356 - _globals['_CONNECTION']._serialized_start=1358 - _globals['_CONNECTION']._serialized_end=1435 + _globals['_BLOQARG']._serialized_start=265 + _globals['_BLOQARG']._serialized_end=725 + _globals['_BLOQLIBRARY']._serialized_start=728 + _globals['_BLOQLIBRARY']._serialized_end=1088 + _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION']._serialized_start=818 + _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION']._serialized_end=1088 + _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._serialized_start=1017 + _globals['_BLOQLIBRARY_BLOQWITHDECOMPOSITION_BLOQCOUNTSENTRY']._serialized_end=1088 + _globals['_BLOQ']._serialized_start=1091 + _globals['_BLOQ']._serialized_end=1229 + _globals['_BLOQINSTANCE']._serialized_start=1231 + _globals['_BLOQINSTANCE']._serialized_end=1283 + _globals['_SOQUET']._serialized_start=1286 + _globals['_SOQUET']._serialized_end=1427 + _globals['_CONNECTION']._serialized_start=1429 + _globals['_CONNECTION']._serialized_end=1506 # @@protoc_insertion_point(module_scope) diff --git a/qualtran/protos/bloq_pb2.pyi b/qualtran/protos/bloq_pb2.pyi index f337ce8da..b3481a7aa 100644 --- a/qualtran/protos/bloq_pb2.pyi +++ b/qualtran/protos/bloq_pb2.pyi @@ -16,7 +16,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ - import builtins import collections.abc import google.protobuf.descriptor @@ -26,13 +25,19 @@ import qualtran.protos.annotations_pb2 import qualtran.protos.args_pb2 import qualtran.protos.ctrl_spec_pb2 import qualtran.protos.data_types_pb2 +import qualtran.protos.ec_point_pb2 import qualtran.protos.registers_pb2 import qualtran.protos.sympy_pb2 -import typing +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor -@typing.final +@typing_extensions.final class BloqArg(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -49,40 +54,38 @@ class BloqArg(google.protobuf.message.Message): REGISTERS_FIELD_NUMBER: builtins.int CTRL_SPEC_FIELD_NUMBER: builtins.int COMPLEX_VAL_FIELD_NUMBER: builtins.int + EC_POINT_FIELD_NUMBER: builtins.int name: builtins.str int_val: builtins.int float_val: builtins.float string_val: builtins.str - subbloq: builtins.int - """Integer reference of a subbloq. Assumes access to a BloqLibrary.""" - cirq_json_gzip: builtins.bytes - """Gzipped JSON corresponding to a Cirq object.""" @property def sympy_expr(self) -> qualtran.protos.sympy_pb2.Term: """Sympy expression generated using str(expr).""" - @property def ndarray(self) -> qualtran.protos.args_pb2.NDArray: """N-dimensional numpy array stored as bytes.""" - + subbloq: builtins.int + """Integer reference of a subbloq. Assumes access to a BloqLibrary.""" + cirq_json_gzip: builtins.bytes + """Gzipped JSON corresponding to a Cirq object.""" @property def qdata_type(self) -> qualtran.protos.data_types_pb2.QDataType: """data type""" - @property def register(self) -> qualtran.protos.registers_pb2.Register: """A Register object, accepted as an argument.""" - @property def registers(self) -> qualtran.protos.registers_pb2.Registers: """A repeated list of one or more registers, accepted as arguments.""" - @property def ctrl_spec(self) -> qualtran.protos.ctrl_spec_pb2.CtrlSpec: """Ctrl Spec for controlled bloqs""" - @property def complex_val(self) -> qualtran.protos.args_pb2.Complex: ... + @property + def ec_point(self) -> qualtran.protos.ec_point_pb2.ECPoint: + """An elliptical curve point for ECC bloqs""" def __init__( self, *, @@ -99,14 +102,15 @@ class BloqArg(google.protobuf.message.Message): registers: qualtran.protos.registers_pb2.Registers | None = ..., ctrl_spec: qualtran.protos.ctrl_spec_pb2.CtrlSpec | None = ..., complex_val: qualtran.protos.args_pb2.Complex | None = ..., + ec_point: qualtran.protos.ec_point_pb2.ECPoint | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "float_val", b"float_val", "int_val", b"int_val", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "float_val", b"float_val", "int_val", b"int_val", "name", b"name", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> None: ... - def WhichOneof(self, oneof_group: typing.Literal["val", b"val"]) -> typing.Literal["int_val", "float_val", "string_val", "sympy_expr", "ndarray", "subbloq", "cirq_json_gzip", "qdata_type", "register", "registers", "ctrl_spec", "complex_val"] | None: ... + def HasField(self, field_name: typing_extensions.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "name", b"name", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["val", b"val"]) -> typing_extensions.Literal["int_val", "float_val", "string_val", "sympy_expr", "ndarray", "subbloq", "cirq_json_gzip", "qdata_type", "register", "registers", "ctrl_spec", "complex_val", "ec_point"] | None: ... global___BloqArg = BloqArg -@typing.final +@typing_extensions.final class BloqLibrary(google.protobuf.message.Message): """A library of Bloqs. BloqLibrary should be used to represent both primitive Bloqs and composite Bloqs; i.e. Bloqs consisting of other subbloqs, like `CompositeBloq`, @@ -115,13 +119,13 @@ class BloqLibrary(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor - @typing.final + @typing_extensions.final class BloqWithDecomposition(google.protobuf.message.Message): """Decompositions are specified using integer IDs referencing other Bloqs within this library.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor - @typing.final + @typing_extensions.final class BloqCountsEntry(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -136,8 +140,8 @@ class BloqLibrary(google.protobuf.message.Message): key: builtins.int = ..., value: qualtran.protos.args_pb2.IntOrSympy | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ... BLOQ_ID_FIELD_NUMBER: builtins.int DECOMPOSITION_FIELD_NUMBER: builtins.int @@ -148,15 +152,12 @@ class BloqLibrary(google.protobuf.message.Message): @property def decomposition(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Connection]: """Decomposition of the Bloq as an edge-list.""" - @property def bloq_counts(self) -> google.protobuf.internal.containers.MessageMap[builtins.int, qualtran.protos.args_pb2.IntOrSympy]: """Rough decomposition of the Bloq as bloq-counts.""" - @property def bloq(self) -> global___Bloq: """The Bloq itself.""" - def __init__( self, *, @@ -165,8 +166,8 @@ class BloqLibrary(google.protobuf.message.Message): bloq_counts: collections.abc.Mapping[builtins.int, qualtran.protos.args_pb2.IntOrSympy] | None = ..., bloq: global___Bloq | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["bloq", b"bloq"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["bloq", b"bloq", "bloq_counts", b"bloq_counts", "bloq_id", b"bloq_id", "decomposition", b"decomposition"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["bloq", b"bloq"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["bloq", b"bloq", "bloq_counts", b"bloq_counts", "bloq_id", b"bloq_id", "decomposition", b"decomposition"]) -> None: ... NAME_FIELD_NUMBER: builtins.int TABLE_FIELD_NUMBER: builtins.int @@ -180,11 +181,11 @@ class BloqLibrary(google.protobuf.message.Message): name: builtins.str = ..., table: collections.abc.Iterable[global___BloqLibrary.BloqWithDecomposition] | None = ..., ) -> None: ... - def ClearField(self, field_name: typing.Literal["name", b"name", "table", b"table"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "table", b"table"]) -> None: ... global___BloqLibrary = BloqLibrary -@typing.final +@typing_extensions.final class Bloq(google.protobuf.message.Message): """Messages to enable efficient description of a BloqLibrary, including Bloq decompositions in terms of other simpler bloqs. @@ -203,15 +204,12 @@ class Bloq(google.protobuf.message.Message): @property def args(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___BloqArg]: """`Args` are used to construct the Bloq.""" - @property def registers(self) -> qualtran.protos.registers_pb2.Registers: """`Registers` specify the signature of the Bloq and are often derived using `args`.""" - @property def t_complexity(self) -> qualtran.protos.annotations_pb2.TComplexity: """Other useful annotations.""" - def __init__( self, *, @@ -220,12 +218,12 @@ class Bloq(google.protobuf.message.Message): registers: qualtran.protos.registers_pb2.Registers | None = ..., t_complexity: qualtran.protos.annotations_pb2.TComplexity | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["registers", b"registers", "t_complexity", b"t_complexity"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["args", b"args", "name", b"name", "registers", b"registers", "t_complexity", b"t_complexity"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["registers", b"registers", "t_complexity", b"t_complexity"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["args", b"args", "name", b"name", "registers", b"registers", "t_complexity", b"t_complexity"]) -> None: ... global___Bloq = Bloq -@typing.final +@typing_extensions.final class BloqInstance(google.protobuf.message.Message): """Specific instance of a Bloq.""" @@ -241,11 +239,11 @@ class BloqInstance(google.protobuf.message.Message): instance_id: builtins.int = ..., bloq_id: builtins.int = ..., ) -> None: ... - def ClearField(self, field_name: typing.Literal["bloq_id", b"bloq_id", "instance_id", b"instance_id"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["bloq_id", b"bloq_id", "instance_id", b"instance_id"]) -> None: ... global___BloqInstance = BloqInstance -@typing.final +@typing_extensions.final class Soquet(google.protobuf.message.Message): """One half of a connection.""" @@ -255,9 +253,9 @@ class Soquet(google.protobuf.message.Message): DANGLING_T_FIELD_NUMBER: builtins.int REGISTER_FIELD_NUMBER: builtins.int INDEX_FIELD_NUMBER: builtins.int - dangling_t: builtins.str @property def bloq_instance(self) -> global___BloqInstance: ... + dangling_t: builtins.str @property def register(self) -> qualtran.protos.registers_pb2.Register: ... @property @@ -270,13 +268,13 @@ class Soquet(google.protobuf.message.Message): register: qualtran.protos.registers_pb2.Register | None = ..., index: collections.abc.Iterable[builtins.int] | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "register", b"register"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "index", b"index", "register", b"register"]) -> None: ... - def WhichOneof(self, oneof_group: typing.Literal["binst", b"binst"]) -> typing.Literal["bloq_instance", "dangling_t"] | None: ... + def HasField(self, field_name: typing_extensions.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "register", b"register"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "index", b"index", "register", b"register"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["binst", b"binst"]) -> typing_extensions.Literal["bloq_instance", "dangling_t"] | None: ... global___Soquet = Soquet -@typing.final +@typing_extensions.final class Connection(google.protobuf.message.Message): """A connection between two Soquets. Quantum compute graph can be represented as a list of connections. @@ -296,7 +294,7 @@ class Connection(google.protobuf.message.Message): left: global___Soquet | None = ..., right: global___Soquet | None = ..., ) -> None: ... - def HasField(self, field_name: typing.Literal["left", b"left", "right", b"right"]) -> builtins.bool: ... - def ClearField(self, field_name: typing.Literal["left", b"left", "right", b"right"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["left", b"left", "right", b"right"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["left", b"left", "right", b"right"]) -> None: ... global___Connection = Connection diff --git a/qualtran/protos/ec_point.proto b/qualtran/protos/ec_point.proto new file mode 100644 index 000000000..c57fa1b53 --- /dev/null +++ b/qualtran/protos/ec_point.proto @@ -0,0 +1,25 @@ +/* + Copyright 2024 Google LLC + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + https://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +syntax = "proto3"; + +import "qualtran/protos/args.proto"; + +package qualtran; + +message ECPoint { + IntOrSympy x = 1; + IntOrSympy y = 2; + IntOrSympy mod = 3; + optional IntOrSympy curve_a = 4; +} diff --git a/qualtran/protos/ec_point_pb2.py b/qualtran/protos/ec_point_pb2.py new file mode 100644 index 000000000..f28f2c110 --- /dev/null +++ b/qualtran/protos/ec_point_pb2.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: qualtran/protos/ec_point.proto +# Protobuf Python Version: 4.25.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from qualtran.protos import args_pb2 as qualtran_dot_protos_dot_args__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1equaltran/protos/ec_point.proto\x12\x08qualtran\x1a\x1aqualtran/protos/args.proto\"\xa6\x01\n\x07\x45\x43Point\x12\x1f\n\x01x\x18\x01 \x01(\x0b\x32\x14.qualtran.IntOrSympy\x12\x1f\n\x01y\x18\x02 \x01(\x0b\x32\x14.qualtran.IntOrSympy\x12!\n\x03mod\x18\x03 \x01(\x0b\x32\x14.qualtran.IntOrSympy\x12*\n\x07\x63urve_a\x18\x04 \x01(\x0b\x32\x14.qualtran.IntOrSympyH\x00\x88\x01\x01\x42\n\n\x08_curve_ab\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'qualtran.protos.ec_point_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_ECPOINT']._serialized_start=73 + _globals['_ECPOINT']._serialized_end=239 +# @@protoc_insertion_point(module_scope) diff --git a/qualtran/protos/ec_point_pb2.pyi b/qualtran/protos/ec_point_pb2.pyi new file mode 100644 index 000000000..ac82158cd --- /dev/null +++ b/qualtran/protos/ec_point_pb2.pyi @@ -0,0 +1,57 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file + +Copyright 2024 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +https://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import qualtran.protos.args_pb2 +import sys + +if sys.version_info >= (3, 8): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class ECPoint(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + X_FIELD_NUMBER: builtins.int + Y_FIELD_NUMBER: builtins.int + MOD_FIELD_NUMBER: builtins.int + CURVE_A_FIELD_NUMBER: builtins.int + @property + def x(self) -> qualtran.protos.args_pb2.IntOrSympy: ... + @property + def y(self) -> qualtran.protos.args_pb2.IntOrSympy: ... + @property + def mod(self) -> qualtran.protos.args_pb2.IntOrSympy: ... + @property + def curve_a(self) -> qualtran.protos.args_pb2.IntOrSympy: ... + def __init__( + self, + *, + x: qualtran.protos.args_pb2.IntOrSympy | None = ..., + y: qualtran.protos.args_pb2.IntOrSympy | None = ..., + mod: qualtran.protos.args_pb2.IntOrSympy | None = ..., + curve_a: qualtran.protos.args_pb2.IntOrSympy | None = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_curve_a", b"_curve_a"]) -> typing_extensions.Literal["curve_a"] | None: ... + +global___ECPoint = ECPoint diff --git a/qualtran/serialization/bloq.py b/qualtran/serialization/bloq.py index 6498984f6..99dce0415 100644 --- a/qualtran/serialization/bloq.py +++ b/qualtran/serialization/bloq.py @@ -37,12 +37,14 @@ Signature, Soquet, ) +from qualtran.bloqs.factoring.ecc import ECPoint from qualtran.protos import bloq_pb2 from qualtran.serialization import ( annotations, args, ctrl_spec, data_types, + ec_point, registers, resolver_dict, ) @@ -75,6 +77,8 @@ def arg_to_proto(*, name: str, val: Any) -> bloq_pb2.BloqArg: return bloq_pb2.BloqArg(name=name, ndarray=args.ndarray_to_proto(np.asarray(val))) if np.iscomplexobj(val): return bloq_pb2.BloqArg(name=name, complex_val=args.complex_to_proto(val)) + if isinstance(val, ECPoint): + return bloq_pb2.BloqArg(name=name, ec_point=ec_point.ec_point_to_proto(val)) raise ValueError(f"Cannot serialize {val} of unknown type {type(val)}") @@ -101,6 +105,8 @@ def arg_from_proto(arg: bloq_pb2.BloqArg) -> Dict[str, Any]: return {arg.name: args.ndarray_from_proto(arg.ndarray)} if arg.HasField("complex_val"): return {arg.name: args.complex_from_proto(arg.complex_val)} + if arg.HasField("ec_point"): + return {arg.name: ec_point.ec_point_from_proto(arg.ec_point)} raise ValueError(f"Cannot deserialize {arg=}") diff --git a/qualtran/serialization/ec_point.py b/qualtran/serialization/ec_point.py new file mode 100644 index 000000000..48a4367ce --- /dev/null +++ b/qualtran/serialization/ec_point.py @@ -0,0 +1,35 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from qualtran.bloqs.factoring.ecc import ECPoint +from qualtran.protos import ec_point_pb2 +from qualtran.serialization.args import int_or_sympy_from_proto, int_or_sympy_to_proto + + +def ec_point_from_proto(point: ec_point_pb2.ECPoint) -> ECPoint: + return ECPoint( + x=int_or_sympy_from_proto(point.x), + y=int_or_sympy_from_proto(point.y), + mod=int_or_sympy_from_proto(point.mod), + curve_a=int_or_sympy_from_proto(point.curve_a), + ) + + +def ec_point_to_proto(point: ECPoint) -> ec_point_pb2.ECPoint: + return ec_point_pb2.ECPoint( + x=int_or_sympy_to_proto(point.x), + y=int_or_sympy_to_proto(point.y), + mod=int_or_sympy_to_proto(point.mod), + curve_a=int_or_sympy_to_proto(point.curve_a), + ) diff --git a/qualtran/serialization/ec_point_test.py b/qualtran/serialization/ec_point_test.py new file mode 100644 index 000000000..c9f299bd2 --- /dev/null +++ b/qualtran/serialization/ec_point_test.py @@ -0,0 +1,32 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from qualtran.bloqs.factoring.ecc import ECPoint +from qualtran.serialization.ec_point import ec_point_from_proto, ec_point_to_proto + + +@pytest.mark.parametrize( + "ec_point", + [ + ECPoint(x=15, y=13, mod=17, curve_a=0), + ECPoint(x=0, y=2, mod=7, curve_a=3), + ECPoint(x=0, y=2, mod=7), + ], +) +def test_ec_point_to_proto_roundtrip(ec_point: ECPoint): + ec_point_proto = ec_point_to_proto(ec_point) + ec_point_roundtrip = ec_point_from_proto(ec_point_proto) + assert ec_point == ec_point_roundtrip