diff --git a/docs/source/example_ecdsa.ipynb b/docs/source/example_ecdsa.ipynb new file mode 100644 index 00000000..816aed11 --- /dev/null +++ b/docs/source/example_ecdsa.ipynb @@ -0,0 +1,92 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Private Key: 1\n", + "Public Key: 2\n", + "Message: 0\n", + "Signature: (2, 2)\n", + "Signature valid: True\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "# Extremely simplified parameters\n", + "P = 3 # Prime field\n", + "G = 2 # Generator\n", + "N = 3 # Order of generator\n", + "\n", + "\n", + "def mod_inv(a, m):\n", + " return 1 if a == 1 else 2 # Only valid for P = 3\n", + "\n", + "\n", + "def generate_keypair():\n", + " private_key = random.randint(1, 3) # 2-bit key (1 to 3)\n", + " public_key = pow(G, private_key, P)\n", + " return private_key, public_key\n", + "\n", + "\n", + "def sign(message, private_key):\n", + " z = message % N\n", + " k = random.randint(1, 3) # 2-bit nonce\n", + " r = pow(G, k, P)\n", + " s = (mod_inv(k, N) * (z + r * private_key)) % N\n", + " return (r, s)\n", + "\n", + "\n", + "def verify(message, signature, public_key):\n", + " r, s = signature\n", + " z = message % N\n", + " w = mod_inv(s, N)\n", + " u1 = (z * w) % N\n", + " u2 = (r * w) % N\n", + " v = (pow(G, u1, P) * pow(public_key, u2, P)) % P\n", + " return v == r\n", + "\n", + "\n", + "# Example usage\n", + "private_key, public_key = generate_keypair()\n", + "message = int(\"0b0\", 2) # Single character message\n", + "signature = sign(message, private_key)\n", + "is_valid = verify(message, signature, public_key)\n", + "\n", + "print(f\"Private Key: {private_key}\")\n", + "print(f\"Public Key: {public_key}\")\n", + "print(f\"Message: {message}\")\n", + "print(f\"Signature: {signature}\")\n", + "print(f\"Signature valid: {is_valid}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qlasskit_310-env", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qlasskit/compiler/internalcompiler.py b/qlasskit/compiler/internalcompiler.py index 88a290ba..aa46d0da 100644 --- a/qlasskit/compiler/internalcompiler.py +++ b/qlasskit/compiler/internalcompiler.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from copy import deepcopy + from sympy import Symbol from sympy.logic import And, Not, Xor from sympy.logic.boolalg import Boolean, BooleanFalse, BooleanTrue @@ -25,11 +27,21 @@ class InternalCompiler(Compiler): """InternalCompiler translating an expression list to quantum circuit""" + def is_symbol_referenced_in_remaining_exps(self, symbol): + """Return True if the symbol is referenced in remaining expressions""" + for sym, exp in self.remaining_exps: + if sym == symbol: + return True + if symbol in exp.free_symbols: + return True + return False + def compile( # noqa: C901 self, name, args: Args, returns: Arg, exprs: BoolExpList, uncompute=True ) -> QCircuit: qc = QCircuitEnhanced(name=name) self.expqmap = ExpQMap() + # self.remaining_exps = deepcopy(exprs) # 1. We first add a qubit for every input bit self.input_symbols = [arg_b for arg in args for arg_b in arg.bitvec] @@ -37,6 +49,8 @@ def compile( # noqa: C901 # 2. Iterate over all expressions; iret contains qubit index for the current exp for sym, exp in exprs: + # self.remaining_exps.pop(0) + is_temp = sym.name.startswith("__") symp_exp = self._symplify_exp(exp)