From 7944ed3ae230e450bf20cc98d128d7a4d688f728 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:03:53 +0530 Subject: [PATCH 01/11] Added E91 QKD Implementation Covers the implementation of E91 QKD, for a predefined num_bits = 2000. --- quantum/e91.py | 175 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 quantum/e91.py diff --git a/quantum/e91.py b/quantum/e91.py new file mode 100644 index 000000000000..830729f64eb0 --- /dev/null +++ b/quantum/e91.py @@ -0,0 +1,175 @@ + +""" +Implements the E91 quantum key distribution (QKD) protocol. +This protocol uses the principles of quantum entanglement and the violation of +Bell's inequality to securely distribute a secret key +between two parties (Alice and Bob) and to detect +the presence of an eavesdropper (Eve). + +How it works: +1. A source (Charlie) generates pairs of entangled qubits in a Bell + state and sends one qubit of each pair to Alice and the other to Bob. +2. Alice and Bob each independently and randomly choose to measure their + incoming qubits in one of three predefined measurement bases. +3. After all measurements are complete, they communicate over a public + channel to compare the bases they chose for each qubit. +4. They divide their measurement results into two sets: + a) Cases where their chosen bases were "compatible" are used to + generate a secret key. Due to entanglement, their results in these + cases should be perfectly correlated. + b) Cases where their bases were "incompatible" are used to test for + eavesdropping by calculating the CHSH inequality parameter 'S'. +5. Quantum mechanics predicts that for an entangled system, |S| can reach + 2*sqrt(2) (~2.828), whereas any classical (or eavesdropped) system is + bound by |S| <= 2. If their calculated S-value significantly violates + the classical bound, they can be confident that no eavesdropping + occurred and their generated key is secure. +""" + +import numpy as np +import qiskit +import random +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister +from qiskit_aer import AerSimulator + + +def e91_protocol(n_bits: int = 2000) -> dict: + """ + Simulates the E91 QKD protocol for a specified number of bits. + + Args: + n_bits: The total number of entangled pairs to be generated and + measured. This determines the potential length of the raw key. + + Returns: + A dictionary containing the simulation results: + - "alice_key": Alice's final, sifted secret key. + - "bob_key": Bob's final, sifted secret key. + - "s_value": The calculated CHSH inequality parameter 'S'. + - "eavesdropper_detected": A boolean indicating if |S| <= 2. + - "key_match": A boolean indicating if Alice's and Bob's keys match. + - "key_length": The final length of the sifted keys. + """ + + if not isinstance(n_bits, int): + raise TypeError("Number of bits must be an integer.") + if n_bits <= 0: + raise ValueError("Number of bits must be > 0.") + if n_bits > 10000: + raise ValueError("Number of bits is too large to simulate efficiently.") + + # Define the measurement angles for Alice and Bob's bases. + # The keys correspond to the basis name, and values are angles in radians. + alice_bases = {'A1': 0, 'A2': np.pi / 8, 'A3': np.pi / 4} + bob_bases = {'B1': np.pi / 8, 'B2': np.pi / 4, 'B3': 3 * np.pi / 8} + + # Lists to store the choices and results for each bit. + alice_chosen_bases, bob_chosen_bases = [], [] + alice_results, bob_results = [], [] + + # Get the quantum simulator backend. + backend = AerSimulator() + + for _ in range(n_bits): + # Alice and Bob randomly choose their measurement bases. + alice_basis_name = random.choice(list(alice_bases.keys())) + bob_basis_name = random.choice(list(bob_bases.keys())) + alice_angle = alice_bases[alice_basis_name] + bob_angle = bob_bases[bob_basis_name] + + # Create a quantum circuit for one entangled pair. + qr = QuantumRegister(2, 'q') + cr = ClassicalRegister(2, 'c') + circuit = QuantumCircuit(qr, cr) + + # Create a Bell state |Φ+⟩ = (|00⟩ + |11⟩)/sqrt(2) + circuit.h(qr[0]) + circuit.cx(qr[0], qr[1]) + + # Apply rotations to simulate measurements in the chosen bases. + # We use RY gates, which rotate around the Y-axis of the Bloch sphere. + circuit.ry(-2 * alice_angle, qr[0]) + circuit.ry(-2 * bob_angle, qr[1]) + + # Measure the qubits. + circuit.measure(qr, cr) + + # Execute the circuit and get the result. + job = backend.run(circuit, shots=1) + result = list(job.result().get_counts().keys())[0] + + # Store choices and results. Qiskit's bit order is reversed. + alice_chosen_bases.append(alice_basis_name) + bob_chosen_bases.append(bob_basis_name) + alice_results.append(int(result[1])) + bob_results.append(int(result[0])) + + # Sift for generating the secret key. + # The key is formed when Alice and Bob choose compatible bases. + alice_key, bob_key = [], [] + for i in range(n_bits): + is_A2B1 = alice_chosen_bases[i] == 'A2' and bob_chosen_bases[i] == 'B1' + is_A3B2 = alice_chosen_bases[i] == 'A3' and bob_chosen_bases[i] == 'B2' + if is_A2B1 or is_A3B2: + alice_key.append(alice_results[i]) + bob_key.append(bob_results[i]) + + # Sift for the CHSH inequality test (Eve detection). + # We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3 + chsh_correlations = {'ab': [], 'ab_': [], 'a_b': [], 'a_b_': []} + + for i in range(n_bits): + a_val = 1 if alice_results[i] == 0 else -1 + b_val = 1 if bob_results[i] == 0 else -1 + product = a_val * b_val # +1 if correlated, -1 if anti-correlated + + alice_basis = alice_chosen_bases[i] + bob_basis = bob_chosen_bases[i] + + if alice_basis == 'A1' and bob_basis == 'B1': + chsh_correlations['ab'].append(product) + elif alice_basis == 'A1' and bob_basis == 'B3': + chsh_correlations['ab_'].append(product) + elif alice_basis == 'A3' and bob_basis == 'B1': + chsh_correlations['a_b'].append(product) + elif alice_basis == 'A3' and bob_basis == 'B3': + chsh_correlations['a_b_'].append(product) + + # Calculate the expectation value (average correlation) for each combination. + E = {} + for key, values in chsh_correlations.items(): + E[key] = np.mean(values) if values else 0 + + # Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b') + s_value = E['ab'] - E['ab_'] + E['a_b'] + E['a_b_'] + + # Check for eavesdropper: |S| > 2 indicates security. + eavesdropper_detected = abs(s_value) <= 2 + + return { + "alice_key": "".join(map(str, alice_key)), + "bob_key": "".join(map(str, bob_key)), + "s_value": s_value, + "eavesdropper_detected": eavesdropper_detected, + "key_match": alice_key == bob_key, + "key_length": len(alice_key) + } + + +if __name__ == "__main__": + # num_bits is initialized to 2000 + num_bits = 2000 + results = e91_protocol(num_bits) + + print(f"Total bits simulated: {num_bits}") + print(f"CHSH S-value: {results['s_value']:.4f}") + print(f"Eavesdropper detected: {results['eavesdropper_detected']}") + print(f"Final key length: {results['key_length']}") + print(f"Keys match: {results['key_match']}") + + if not results['eavesdropper_detected'] and results['key_match'] and results['key_length'] > 0: + print("\nProtocol successful! Secret key generated securely.") + print(f" Alice's key: {results['alice_key']}") + print(f" Bob's key: {results['bob_key']}") + else: + print("\nProtocol failed or eavesdropper detected. Key discarded.") From 69ef334c1c533855a4c3ce87d450e6d903fe78d7 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:14:15 +0530 Subject: [PATCH 02/11] Added Implementation for E91 QKD Protocol Covers the implementation of E91 QKD, for a predefined num_bits = 2000. --- quantum/e91_qkd.py | 167 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 quantum/e91_qkd.py diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py new file mode 100644 index 000000000000..65dc8d6f5eb0 --- /dev/null +++ b/quantum/e91_qkd.py @@ -0,0 +1,167 @@ +import math +import random +import numpy as np +import qiskit +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister +from qiskit_aer import AerSimulator + + +def e91_protocol(n_bits: int = 2000) -> dict: + """ + Simulates the E91 QKD protocol for a specified number of bits. + + Args: + n_bits: The total number of entangled pairs to be generated and + measured. This determines the potential length of the raw key. + + Returns: + A dictionary containing the simulation results: + - "alice_key": Alice's final, sifted secret key. + - "bob_key": Bob's final, sifted secret key. + - "s_value": The calculated CHSH inequality parameter 'S'. + - "eavesdropper_detected": A boolean indicating if |S| <= 2. + - "key_match": A boolean indicating if Alice's and Bob's keys match. + - "key_length": The final length of the sifted keys. + + >>> e91_protocol(100) # doctest: +SKIP + {'alice_key': '1011110', 'bob_key': '1011110', 's_value': 2.73, ...} + + >>> e91_protocol(-10) + Traceback (most recent call last): + ... + ValueError: Number of bits must be > 0. + + >>> e91_protocol('abc') + Traceback (most recent call last): + ... + TypeError: Number of bits must be an integer. + + >>> e91_protocol(10001) + Traceback (most recent call last): + ... + ValueError: Number of bits is too large to simulate efficiently (>10000). + """ + # --- Input Validation --- + if not isinstance(n_bits, int): + raise TypeError("Number of bits must be an integer.") + if n_bits <= 0: + raise ValueError("Number of bits must be > 0.") + if n_bits > 10000: + raise ValueError("Number of bits is too large to simulate efficiently (>10000).") + + # Define the measurement angles for Alice and Bob's bases as constants. + # The keys correspond to the basis name, and values are angles in radians. + ALICE_BASES = {'A1': 0, 'A2': np.pi / 8, 'A3': np.pi / 4} + BOB_BASES = {'B1': np.pi / 8, 'B2': np.pi / 4, 'B3': 3 * np.pi / 8} + + # Lists to store the choices and results for each bit. + alice_chosen_bases, bob_chosen_bases = [], [] + alice_results, bob_results = [], [] + + # Get the quantum simulator backend. + backend = AerSimulator() + + for _ in range(n_bits): + # Alice and Bob randomly choose their measurement bases. + alice_basis_name = random.choice(list(ALICE_BASES.keys())) + bob_basis_name = random.choice(list(BOB_BASES.keys())) + alice_angle = ALICE_BASES[alice_basis_name] + bob_angle = BOB_BASES[bob_basis_name] + + # Create a quantum circuit for one entangled pair. + qr = QuantumRegister(2, 'q') + cr = ClassicalRegister(2, 'c') + circuit = QuantumCircuit(qr, cr) + + # Create a Bell state |Φ+⟩ = (|00⟩ + |11⟩)/sqrt(2) + circuit.h(qr[0]) + circuit.cx(qr[0], qr[1]) + + # Apply rotations to simulate measurements in the chosen bases. + circuit.ry(-2 * alice_angle, qr[0]) + circuit.ry(-2 * bob_angle, qr[1]) + + # Measure the qubits. + circuit.measure(qr, cr) + + # Execute the circuit and get the result. + job = backend.run(circuit, shots=1) + result = list(job.result().get_counts().keys())[0] + + # Store choices and results. Qiskit's bit order is reversed. + alice_chosen_bases.append(alice_basis_name) + bob_chosen_bases.append(bob_basis_name) + alice_results.append(int(result[1])) + bob_results.append(int(result[0])) + + + # Sift for generating the secret key. + # The key is formed when Alice and Bob choose compatible bases. + # Here, compatible means A2/B1 or A3/B2, where angles are identical. + alice_key, bob_key = [], [] + for i in range(n_bits): + is_a2b1 = alice_chosen_bases[i] == 'A2' and bob_chosen_bases[i] == 'B1' + is_a3b2 = alice_chosen_bases[i] == 'A3' and bob_chosen_bases[i] == 'B2' + if is_a2b1 or is_a3b2: + alice_key.append(alice_results[i]) + bob_key.append(bob_results[i]) + + # Sift for the CHSH inequality test (Eve detection). + # We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3 + chsh_correlations = {'ab': [], 'ab_': [], 'a_b': [], 'a_b_': []} + + for i in range(n_bits): + # Convert results {0, 1} to {-1, 1} for calculating correlation. + a_val = 1 if alice_results[i] == 0 else -1 + b_val = 1 if bob_results[i] == 0 else -1 + product = a_val * b_val # +1 if correlated, -1 if anti-correlated + + alice_basis = alice_chosen_bases[i] + bob_basis = bob_chosen_bases[i] + + if alice_basis == 'A1' and bob_basis == 'B1': + chsh_correlations['ab'].append(product) + elif alice_basis == 'A1' and bob_basis == 'B3': + chsh_correlations['ab_'].append(product) + elif alice_basis == 'A3' and bob_basis == 'B1': + chsh_correlations['a_b'].append(product) + elif alice_basis == 'A3' and bob_basis == 'B3': + chsh_correlations['a_b_'].append(product) + + # Calculate the expectation value (average correlation) for each combination. + E = {} + for key, values in chsh_correlations.items(): + E[key] = np.mean(values) if values else 0 + + # Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b') + s_value = E['ab'] - E['ab_'] + E['a_b'] + E['a_b_'] + + # Check for eavesdropper: |S| > 2 indicates security. + eavesdropper_detected = abs(s_value) <= 2 + + return { + "alice_key": "".join(map(str, alice_key)), + "bob_key": "".join(map(str, bob_key)), + "s_value": s_value, + "eavesdropper_detected": eavesdropper_detected, + "key_match": alice_key == bob_key, + "key_length": len(alice_key) + } + + +if __name__ == "__main__": + # num_bits is initialized to 2000 + num_bits = 2000 + results = e91_protocol(num_bits) + + print(f"CHSH S-value: {results['s_value']:.4f}") + print(f"Eavesdropper detected: {results['eavesdropper_detected']}") + print(f"Final key length: {results['key_length']}") + print(f"Keys match: {results['key_match']}") + + if not results['eavesdropper_detected'] and results['key_match'] and results['key_length'] > 0: + print("\nProtocol successful! Secret key generated securely.") + print(f" Alice's key: {results['alice_key']}") + print(f" Bob's key: {results['bob_key']}") + else: + print("\nProtocol failed or eavesdropper detected. Key discarded.") From c9b1bf0163753bdd6e9921bab8dc3b8d2d93b033 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:14:36 +0530 Subject: [PATCH 03/11] Delete quantum/e91.py --- quantum/e91.py | 175 ------------------------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 quantum/e91.py diff --git a/quantum/e91.py b/quantum/e91.py deleted file mode 100644 index 830729f64eb0..000000000000 --- a/quantum/e91.py +++ /dev/null @@ -1,175 +0,0 @@ - -""" -Implements the E91 quantum key distribution (QKD) protocol. -This protocol uses the principles of quantum entanglement and the violation of -Bell's inequality to securely distribute a secret key -between two parties (Alice and Bob) and to detect -the presence of an eavesdropper (Eve). - -How it works: -1. A source (Charlie) generates pairs of entangled qubits in a Bell - state and sends one qubit of each pair to Alice and the other to Bob. -2. Alice and Bob each independently and randomly choose to measure their - incoming qubits in one of three predefined measurement bases. -3. After all measurements are complete, they communicate over a public - channel to compare the bases they chose for each qubit. -4. They divide their measurement results into two sets: - a) Cases where their chosen bases were "compatible" are used to - generate a secret key. Due to entanglement, their results in these - cases should be perfectly correlated. - b) Cases where their bases were "incompatible" are used to test for - eavesdropping by calculating the CHSH inequality parameter 'S'. -5. Quantum mechanics predicts that for an entangled system, |S| can reach - 2*sqrt(2) (~2.828), whereas any classical (or eavesdropped) system is - bound by |S| <= 2. If their calculated S-value significantly violates - the classical bound, they can be confident that no eavesdropping - occurred and their generated key is secure. -""" - -import numpy as np -import qiskit -import random -from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister -from qiskit_aer import AerSimulator - - -def e91_protocol(n_bits: int = 2000) -> dict: - """ - Simulates the E91 QKD protocol for a specified number of bits. - - Args: - n_bits: The total number of entangled pairs to be generated and - measured. This determines the potential length of the raw key. - - Returns: - A dictionary containing the simulation results: - - "alice_key": Alice's final, sifted secret key. - - "bob_key": Bob's final, sifted secret key. - - "s_value": The calculated CHSH inequality parameter 'S'. - - "eavesdropper_detected": A boolean indicating if |S| <= 2. - - "key_match": A boolean indicating if Alice's and Bob's keys match. - - "key_length": The final length of the sifted keys. - """ - - if not isinstance(n_bits, int): - raise TypeError("Number of bits must be an integer.") - if n_bits <= 0: - raise ValueError("Number of bits must be > 0.") - if n_bits > 10000: - raise ValueError("Number of bits is too large to simulate efficiently.") - - # Define the measurement angles for Alice and Bob's bases. - # The keys correspond to the basis name, and values are angles in radians. - alice_bases = {'A1': 0, 'A2': np.pi / 8, 'A3': np.pi / 4} - bob_bases = {'B1': np.pi / 8, 'B2': np.pi / 4, 'B3': 3 * np.pi / 8} - - # Lists to store the choices and results for each bit. - alice_chosen_bases, bob_chosen_bases = [], [] - alice_results, bob_results = [], [] - - # Get the quantum simulator backend. - backend = AerSimulator() - - for _ in range(n_bits): - # Alice and Bob randomly choose their measurement bases. - alice_basis_name = random.choice(list(alice_bases.keys())) - bob_basis_name = random.choice(list(bob_bases.keys())) - alice_angle = alice_bases[alice_basis_name] - bob_angle = bob_bases[bob_basis_name] - - # Create a quantum circuit for one entangled pair. - qr = QuantumRegister(2, 'q') - cr = ClassicalRegister(2, 'c') - circuit = QuantumCircuit(qr, cr) - - # Create a Bell state |Φ+⟩ = (|00⟩ + |11⟩)/sqrt(2) - circuit.h(qr[0]) - circuit.cx(qr[0], qr[1]) - - # Apply rotations to simulate measurements in the chosen bases. - # We use RY gates, which rotate around the Y-axis of the Bloch sphere. - circuit.ry(-2 * alice_angle, qr[0]) - circuit.ry(-2 * bob_angle, qr[1]) - - # Measure the qubits. - circuit.measure(qr, cr) - - # Execute the circuit and get the result. - job = backend.run(circuit, shots=1) - result = list(job.result().get_counts().keys())[0] - - # Store choices and results. Qiskit's bit order is reversed. - alice_chosen_bases.append(alice_basis_name) - bob_chosen_bases.append(bob_basis_name) - alice_results.append(int(result[1])) - bob_results.append(int(result[0])) - - # Sift for generating the secret key. - # The key is formed when Alice and Bob choose compatible bases. - alice_key, bob_key = [], [] - for i in range(n_bits): - is_A2B1 = alice_chosen_bases[i] == 'A2' and bob_chosen_bases[i] == 'B1' - is_A3B2 = alice_chosen_bases[i] == 'A3' and bob_chosen_bases[i] == 'B2' - if is_A2B1 or is_A3B2: - alice_key.append(alice_results[i]) - bob_key.append(bob_results[i]) - - # Sift for the CHSH inequality test (Eve detection). - # We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3 - chsh_correlations = {'ab': [], 'ab_': [], 'a_b': [], 'a_b_': []} - - for i in range(n_bits): - a_val = 1 if alice_results[i] == 0 else -1 - b_val = 1 if bob_results[i] == 0 else -1 - product = a_val * b_val # +1 if correlated, -1 if anti-correlated - - alice_basis = alice_chosen_bases[i] - bob_basis = bob_chosen_bases[i] - - if alice_basis == 'A1' and bob_basis == 'B1': - chsh_correlations['ab'].append(product) - elif alice_basis == 'A1' and bob_basis == 'B3': - chsh_correlations['ab_'].append(product) - elif alice_basis == 'A3' and bob_basis == 'B1': - chsh_correlations['a_b'].append(product) - elif alice_basis == 'A3' and bob_basis == 'B3': - chsh_correlations['a_b_'].append(product) - - # Calculate the expectation value (average correlation) for each combination. - E = {} - for key, values in chsh_correlations.items(): - E[key] = np.mean(values) if values else 0 - - # Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b') - s_value = E['ab'] - E['ab_'] + E['a_b'] + E['a_b_'] - - # Check for eavesdropper: |S| > 2 indicates security. - eavesdropper_detected = abs(s_value) <= 2 - - return { - "alice_key": "".join(map(str, alice_key)), - "bob_key": "".join(map(str, bob_key)), - "s_value": s_value, - "eavesdropper_detected": eavesdropper_detected, - "key_match": alice_key == bob_key, - "key_length": len(alice_key) - } - - -if __name__ == "__main__": - # num_bits is initialized to 2000 - num_bits = 2000 - results = e91_protocol(num_bits) - - print(f"Total bits simulated: {num_bits}") - print(f"CHSH S-value: {results['s_value']:.4f}") - print(f"Eavesdropper detected: {results['eavesdropper_detected']}") - print(f"Final key length: {results['key_length']}") - print(f"Keys match: {results['key_match']}") - - if not results['eavesdropper_detected'] and results['key_match'] and results['key_length'] > 0: - print("\nProtocol successful! Secret key generated securely.") - print(f" Alice's key: {results['alice_key']}") - print(f" Bob's key: {results['bob_key']}") - else: - print("\nProtocol failed or eavesdropper detected. Key discarded.") From 81ce6eeee228550c69d076e90fa713e14266b340 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:29:05 +0530 Subject: [PATCH 04/11] Updated e91_qkd.py --- quantum/e91_qkd.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 65dc8d6f5eb0..8b3b9f134046 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -1,3 +1,32 @@ +""" +Implements the E91 quantum key distribution (QKD) protocol. +This protocol uses the principles of quantum entanglement and the violation of +Bell's inequality to securely distribute a secret key +between two parties (Alice and Bob) and to detect +the presence of an eavesdropper (Eve). + +How it works: +1. A source (Charlie) generates pairs of entangled qubits in a Bell + state and sends one qubit of each pair to Alice and the other to Bob. +2. Alice and Bob each independently and randomly choose to measure their + incoming qubits in one of three predefined measurement bases. +3. After all measurements are complete, they communicate over a public + channel to compare the bases they chose for each qubit. +4. They divide their measurement results into two sets: + a) Cases where their chosen bases were "compatible" are used to + generate a secret key. Due to entanglement, their results in these + cases should be perfectly correlated. + b) Cases where their bases were "incompatible" are used to test for + eavesdropping by calculating the CHSH inequality parameter 'S'. +5. Quantum mechanics predicts that for an entangled system, |S| can reach + 2*sqrt(2) (~2.828), whereas any classical (or eavesdropped) system is + bound by |S| <= 2. If their calculated S-value significantly violates + the classical bound, they can be confident that no eavesdropping + occurred and their generated key is secure. + +Reference: https://en.wikipedia.org/wiki/Quantum_key_distribution#E91_protocol:_Artur_Ekert_.281991.29 +""" + import math import random import numpy as np From 5918007914a118d2993b59a05a31a240e409925a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:07:31 +0000 Subject: [PATCH 05/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- quantum/e91_qkd.py | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 8b3b9f134046..3201ffef8a43 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -76,12 +76,14 @@ def e91_protocol(n_bits: int = 2000) -> dict: if n_bits <= 0: raise ValueError("Number of bits must be > 0.") if n_bits > 10000: - raise ValueError("Number of bits is too large to simulate efficiently (>10000).") + raise ValueError( + "Number of bits is too large to simulate efficiently (>10000)." + ) # Define the measurement angles for Alice and Bob's bases as constants. # The keys correspond to the basis name, and values are angles in radians. - ALICE_BASES = {'A1': 0, 'A2': np.pi / 8, 'A3': np.pi / 4} - BOB_BASES = {'B1': np.pi / 8, 'B2': np.pi / 4, 'B3': 3 * np.pi / 8} + ALICE_BASES = {"A1": 0, "A2": np.pi / 8, "A3": np.pi / 4} + BOB_BASES = {"B1": np.pi / 8, "B2": np.pi / 4, "B3": 3 * np.pi / 8} # Lists to store the choices and results for each bit. alice_chosen_bases, bob_chosen_bases = [], [] @@ -98,8 +100,8 @@ def e91_protocol(n_bits: int = 2000) -> dict: bob_angle = BOB_BASES[bob_basis_name] # Create a quantum circuit for one entangled pair. - qr = QuantumRegister(2, 'q') - cr = ClassicalRegister(2, 'c') + qr = QuantumRegister(2, "q") + cr = ClassicalRegister(2, "c") circuit = QuantumCircuit(qr, cr) # Create a Bell state |Φ+⟩ = (|00⟩ + |11⟩)/sqrt(2) @@ -123,21 +125,20 @@ def e91_protocol(n_bits: int = 2000) -> dict: alice_results.append(int(result[1])) bob_results.append(int(result[0])) - # Sift for generating the secret key. # The key is formed when Alice and Bob choose compatible bases. # Here, compatible means A2/B1 or A3/B2, where angles are identical. alice_key, bob_key = [], [] for i in range(n_bits): - is_a2b1 = alice_chosen_bases[i] == 'A2' and bob_chosen_bases[i] == 'B1' - is_a3b2 = alice_chosen_bases[i] == 'A3' and bob_chosen_bases[i] == 'B2' + is_a2b1 = alice_chosen_bases[i] == "A2" and bob_chosen_bases[i] == "B1" + is_a3b2 = alice_chosen_bases[i] == "A3" and bob_chosen_bases[i] == "B2" if is_a2b1 or is_a3b2: alice_key.append(alice_results[i]) bob_key.append(bob_results[i]) # Sift for the CHSH inequality test (Eve detection). # We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3 - chsh_correlations = {'ab': [], 'ab_': [], 'a_b': [], 'a_b_': []} + chsh_correlations = {"ab": [], "ab_": [], "a_b": [], "a_b_": []} for i in range(n_bits): # Convert results {0, 1} to {-1, 1} for calculating correlation. @@ -148,14 +149,14 @@ def e91_protocol(n_bits: int = 2000) -> dict: alice_basis = alice_chosen_bases[i] bob_basis = bob_chosen_bases[i] - if alice_basis == 'A1' and bob_basis == 'B1': - chsh_correlations['ab'].append(product) - elif alice_basis == 'A1' and bob_basis == 'B3': - chsh_correlations['ab_'].append(product) - elif alice_basis == 'A3' and bob_basis == 'B1': - chsh_correlations['a_b'].append(product) - elif alice_basis == 'A3' and bob_basis == 'B3': - chsh_correlations['a_b_'].append(product) + if alice_basis == "A1" and bob_basis == "B1": + chsh_correlations["ab"].append(product) + elif alice_basis == "A1" and bob_basis == "B3": + chsh_correlations["ab_"].append(product) + elif alice_basis == "A3" and bob_basis == "B1": + chsh_correlations["a_b"].append(product) + elif alice_basis == "A3" and bob_basis == "B3": + chsh_correlations["a_b_"].append(product) # Calculate the expectation value (average correlation) for each combination. E = {} @@ -163,7 +164,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: E[key] = np.mean(values) if values else 0 # Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b') - s_value = E['ab'] - E['ab_'] + E['a_b'] + E['a_b_'] + s_value = E["ab"] - E["ab_"] + E["a_b"] + E["a_b_"] # Check for eavesdropper: |S| > 2 indicates security. eavesdropper_detected = abs(s_value) <= 2 @@ -174,7 +175,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: "s_value": s_value, "eavesdropper_detected": eavesdropper_detected, "key_match": alice_key == bob_key, - "key_length": len(alice_key) + "key_length": len(alice_key), } @@ -188,7 +189,11 @@ def e91_protocol(n_bits: int = 2000) -> dict: print(f"Final key length: {results['key_length']}") print(f"Keys match: {results['key_match']}") - if not results['eavesdropper_detected'] and results['key_match'] and results['key_length'] > 0: + if ( + not results["eavesdropper_detected"] + and results["key_match"] + and results["key_length"] > 0 + ): print("\nProtocol successful! Secret key generated securely.") print(f" Alice's key: {results['alice_key']}") print(f" Bob's key: {results['bob_key']}") From 1c81b82cf9cb756d37db400e33c0e562b9739092 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:47:43 +0530 Subject: [PATCH 06/11] Updated Formatting - e91_qkd.py --- quantum/e91_qkd.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 3201ffef8a43..93596783b4bb 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -27,10 +27,9 @@ Reference: https://en.wikipedia.org/wiki/Quantum_key_distribution#E91_protocol:_Artur_Ekert_.281991.29 """ -import math import random + import numpy as np -import qiskit from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister from qiskit_aer import AerSimulator @@ -82,8 +81,8 @@ def e91_protocol(n_bits: int = 2000) -> dict: # Define the measurement angles for Alice and Bob's bases as constants. # The keys correspond to the basis name, and values are angles in radians. - ALICE_BASES = {"A1": 0, "A2": np.pi / 8, "A3": np.pi / 4} - BOB_BASES = {"B1": np.pi / 8, "B2": np.pi / 4, "B3": 3 * np.pi / 8} + alice_bases = {"A1": 0, "A2": np.pi / 8, "A3": np.pi / 4} + bob_bases = {"B1": np.pi / 8, "B2": np.pi / 4, "B3": 3 * np.pi / 8} # Lists to store the choices and results for each bit. alice_chosen_bases, bob_chosen_bases = [], [] @@ -94,10 +93,10 @@ def e91_protocol(n_bits: int = 2000) -> dict: for _ in range(n_bits): # Alice and Bob randomly choose their measurement bases. - alice_basis_name = random.choice(list(ALICE_BASES.keys())) - bob_basis_name = random.choice(list(BOB_BASES.keys())) - alice_angle = ALICE_BASES[alice_basis_name] - bob_angle = BOB_BASES[bob_basis_name] + alice_basis_name = random.choice(list(alice_bases.keys())) + bob_basis_name = random.choice(list(bob_bases.keys())) + alice_angle = alice_bases[alice_basis_name] + bob_angle = bob_bases[bob_basis_name] # Create a quantum circuit for one entangled pair. qr = QuantumRegister(2, "q") @@ -117,7 +116,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: # Execute the circuit and get the result. job = backend.run(circuit, shots=1) - result = list(job.result().get_counts().keys())[0] + result = next(iter(job.result().get_counts().keys())) # Store choices and results. Qiskit's bit order is reversed. alice_chosen_bases.append(alice_basis_name) @@ -137,7 +136,8 @@ def e91_protocol(n_bits: int = 2000) -> dict: bob_key.append(bob_results[i]) # Sift for the CHSH inequality test (Eve detection). - # We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3 + # We use four specific combinations of bases for the test: + # a = A1, a' = A3 | b = B1, b' = B3 chsh_correlations = {"ab": [], "ab_": [], "a_b": [], "a_b_": []} for i in range(n_bits): @@ -159,12 +159,12 @@ def e91_protocol(n_bits: int = 2000) -> dict: chsh_correlations["a_b_"].append(product) # Calculate the expectation value (average correlation) for each combination. - E = {} + e = {} for key, values in chsh_correlations.items(): - E[key] = np.mean(values) if values else 0 + e[key] = np.mean(values) if values else 0 - # Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b') - s_value = E["ab"] - E["ab_"] + E["a_b"] + E["a_b_"] + # Calculate the S-value: S = e(a,b) - e(a,b') + e(a',b) + e(a',b') + s_value = e["ab"] - e["ab_"] + e["a_b"] + e["a_b_"] # Check for eavesdropper: |S| > 2 indicates security. eavesdropper_detected = abs(s_value) <= 2 From 99724811ed695f1376b3969287aae0f3951a3fbe Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:59:30 +0530 Subject: [PATCH 07/11] Updated chsh_correlations - e91_qkd.py --- quantum/e91_qkd.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 93596783b4bb..89c377e22744 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -127,7 +127,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: # Sift for generating the secret key. # The key is formed when Alice and Bob choose compatible bases. # Here, compatible means A2/B1 or A3/B2, where angles are identical. - alice_key, bob_key = [], [] + alice_key, bob_key = [], [] for i in range(n_bits): is_a2b1 = alice_chosen_bases[i] == "A2" and bob_chosen_bases[i] == "B1" is_a3b2 = alice_chosen_bases[i] == "A3" and bob_chosen_bases[i] == "B2" @@ -138,7 +138,12 @@ def e91_protocol(n_bits: int = 2000) -> dict: # Sift for the CHSH inequality test (Eve detection). # We use four specific combinations of bases for the test: # a = A1, a' = A3 | b = B1, b' = B3 - chsh_correlations = {"ab": [], "ab_": [], "a_b": [], "a_b_": []} + chsh_correlations: dict[str, list[int]] = { + "ab": [], + "ab_": [], + "a_b": [], + "a_b_": [], + } for i in range(n_bits): # Convert results {0, 1} to {-1, 1} for calculating correlation. @@ -159,9 +164,9 @@ def e91_protocol(n_bits: int = 2000) -> dict: chsh_correlations["a_b_"].append(product) # Calculate the expectation value (average correlation) for each combination. - e = {} + e: dict[str, float] = {} for key, values in chsh_correlations.items(): - e[key] = np.mean(values) if values else 0 + e[key] = np.mean(values) if values else 0.0 # Calculate the S-value: S = e(a,b) - e(a,b') + e(a',b) + e(a',b') s_value = e["ab"] - e["ab_"] + e["a_b"] + e["a_b_"] From a9467bc5f10444af1209cead3bb936f76ed5e4a6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:29:50 +0000 Subject: [PATCH 08/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- quantum/e91_qkd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 89c377e22744..0de739f5d3cc 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -127,7 +127,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: # Sift for generating the secret key. # The key is formed when Alice and Bob choose compatible bases. # Here, compatible means A2/B1 or A3/B2, where angles are identical. - alice_key, bob_key = [], [] + alice_key, bob_key = [], [] for i in range(n_bits): is_a2b1 = alice_chosen_bases[i] == "A2" and bob_chosen_bases[i] == "B1" is_a3b2 = alice_chosen_bases[i] == "A3" and bob_chosen_bases[i] == "B2" From da9c13caebb3e15905e67eb771d7e280169596e9 Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Wed, 1 Oct 2025 16:02:54 +0530 Subject: [PATCH 09/11] Updated Trailing Spaces - e91_qkd.py --- quantum/e91_qkd.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index 0de739f5d3cc..e256e1d85064 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -26,7 +26,6 @@ Reference: https://en.wikipedia.org/wiki/Quantum_key_distribution#E91_protocol:_Artur_Ekert_.281991.29 """ - import random import numpy as np @@ -51,8 +50,8 @@ def e91_protocol(n_bits: int = 2000) -> dict: - "key_match": A boolean indicating if Alice's and Bob's keys match. - "key_length": The final length of the sifted keys. - >>> e91_protocol(100) # doctest: +SKIP - {'alice_key': '1011110', 'bob_key': '1011110', 's_value': 2.73, ...} + >>> e91_protocol(10) # doctest: +SKIP + {'alice_key': '10', 'bob_key': '10', 's_value': 2.0, ...} >>> e91_protocol(-10) Traceback (most recent call last): @@ -169,7 +168,7 @@ def e91_protocol(n_bits: int = 2000) -> dict: e[key] = np.mean(values) if values else 0.0 # Calculate the S-value: S = e(a,b) - e(a,b') + e(a',b) + e(a',b') - s_value = e["ab"] - e["ab_"] + e["a_b"] + e["a_b_"] + s_value = e.get("ab", 0.0) - e.get("ab_", 0.0) + e.get("a_b", 0.0) + e.get("a_b_", 0.0) # Check for eavesdropper: |S| > 2 indicates security. eavesdropper_detected = abs(s_value) <= 2 From 50ea388a127e7d5fd573216134d4610e57c8c16e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:33:15 +0000 Subject: [PATCH 10/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- quantum/e91_qkd.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py index e256e1d85064..c22a15dd81f8 100644 --- a/quantum/e91_qkd.py +++ b/quantum/e91_qkd.py @@ -26,6 +26,7 @@ Reference: https://en.wikipedia.org/wiki/Quantum_key_distribution#E91_protocol:_Artur_Ekert_.281991.29 """ + import random import numpy as np @@ -168,7 +169,9 @@ def e91_protocol(n_bits: int = 2000) -> dict: e[key] = np.mean(values) if values else 0.0 # Calculate the S-value: S = e(a,b) - e(a,b') + e(a',b) + e(a',b') - s_value = e.get("ab", 0.0) - e.get("ab_", 0.0) + e.get("a_b", 0.0) + e.get("a_b_", 0.0) + s_value = ( + e.get("ab", 0.0) - e.get("ab_", 0.0) + e.get("a_b", 0.0) + e.get("a_b_", 0.0) + ) # Check for eavesdropper: |S| > 2 indicates security. eavesdropper_detected = abs(s_value) <= 2 From f6f2b33545a7ce0063fd71e466cf4b7d87c8d15d Mon Sep 17 00:00:00 2001 From: Sricharan Sridhar <140080879+sricharan2901@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:57:41 +0530 Subject: [PATCH 11/11] Rename e91_qkd.py to e91_qkd.py.DISABLED.txt --- quantum/{e91_qkd.py => e91_qkd.py.DISABLED.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename quantum/{e91_qkd.py => e91_qkd.py.DISABLED.txt} (100%) diff --git a/quantum/e91_qkd.py b/quantum/e91_qkd.py.DISABLED.txt similarity index 100% rename from quantum/e91_qkd.py rename to quantum/e91_qkd.py.DISABLED.txt