Quantum computer, quantum key distribution algos
This commit is contained in:
commit
e839ac4006
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
venv
|
||||
.idea
|
113
computer.py
Normal file
113
computer.py
Normal file
@ -0,0 +1,113 @@
|
||||
import random
|
||||
from math import sqrt, log
|
||||
|
||||
|
||||
class Gate(list):
|
||||
# Matrix multiplication
|
||||
def __mul__(self, other):
|
||||
rv = Gate()
|
||||
for kol in range(len(other[0])):
|
||||
for _ in range(len(self)):
|
||||
rv.append([0])
|
||||
# iterate through rows of a
|
||||
for i in range(len(self)):
|
||||
# iterate through columns of b
|
||||
for j in range(len(other[0])):
|
||||
# iterate through rows of b
|
||||
for k in range(len(other)):
|
||||
rv[i][j] += self[i][k] * other[k][j]
|
||||
return rv
|
||||
|
||||
|
||||
class Qubit(list):
|
||||
# tensor multiplication
|
||||
def __mul__(self, other):
|
||||
rv = Qubit()
|
||||
for i in self:
|
||||
for j in other:
|
||||
rv.append([i[0] * j[0]])
|
||||
return rv
|
||||
|
||||
|
||||
def measure(qubits):
|
||||
"""
|
||||
Measure result from computation
|
||||
"""
|
||||
probabilites = [q[0] ** 2 for q in qubits]
|
||||
return bin(random.choices(
|
||||
population=range(len(qubits)),
|
||||
weights=probabilites
|
||||
)[0])
|
||||
|
||||
|
||||
_0 = Qubit([[1], [0]])
|
||||
_1 = Qubit([[0], [1]])
|
||||
|
||||
I = Gate([
|
||||
[1, 0],
|
||||
[0, 1],
|
||||
])
|
||||
X = Gate([
|
||||
[0, 1],
|
||||
[1, 0],
|
||||
])
|
||||
Y = Gate([
|
||||
[0, complex(0, -1)],
|
||||
[complex(0, 1), 0],
|
||||
])
|
||||
Z = Gate([
|
||||
[1, 0],
|
||||
[0, -1],
|
||||
])
|
||||
CNOT = Gate([
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0],
|
||||
])
|
||||
H = Gate([
|
||||
[1 / sqrt(2), 1 / sqrt(2)],
|
||||
[1 / sqrt(2), -1 / sqrt(2)],
|
||||
])
|
||||
|
||||
|
||||
def main():
|
||||
# TEST IDENTITY
|
||||
assert _1 == I * _1
|
||||
assert _0 == I * _0
|
||||
|
||||
# TEST BIT-FLIP
|
||||
assert _1 == X * _0
|
||||
assert _0 == X * _1
|
||||
|
||||
# TEST CNOT GATE - Control * Target
|
||||
# Control is FALSE, so target doesn't change
|
||||
assert CNOT * (_0 * _0) == (_0 * _0)
|
||||
assert CNOT * (_0 * _1) == (_0 * _1)
|
||||
# Control is TRUE, so target MUST change
|
||||
assert CNOT * (_1 * _0) == (_1 * _1)
|
||||
assert CNOT * (_1 * _1) == (_1 * _0)
|
||||
|
||||
# TEST HADAMARD
|
||||
superposition = Qubit(H * _0) * Qubit(H * _0)
|
||||
print(superposition)
|
||||
CNOT_superposition = Qubit(CNOT * superposition)
|
||||
print(CNOT_superposition)
|
||||
|
||||
print(measure(CNOT_superposition))
|
||||
# print(INVERTED_CNOT)
|
||||
|
||||
# TEST MY MEMORY
|
||||
# rv = _0
|
||||
# QUBITS = 23
|
||||
# print(2**QUBITS)
|
||||
# print("{:.1f} KB".format(2**QUBITS / 2**10))
|
||||
# print("{:.1f} MB".format(2**QUBITS / 2**20))
|
||||
# print("{:.1f} GB".format(2**QUBITS / 2**30))
|
||||
# for i in range(QUBITS):
|
||||
# rv *= _0
|
||||
# print(len(rv))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
105
qkd.py
Normal file
105
qkd.py
Normal file
@ -0,0 +1,105 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import random
|
||||
|
||||
STREAM_LENGTH = 100
|
||||
|
||||
|
||||
@dataclass
|
||||
class Photon(object):
|
||||
basis: int
|
||||
value: int
|
||||
_measured: bool = False
|
||||
_measured_value: bool = None
|
||||
|
||||
def measure(self, basis):
|
||||
self._measured = True
|
||||
if self.basis == basis:
|
||||
return self.value
|
||||
else:
|
||||
if not self._measured:
|
||||
self._measured_value = random.randint(0, 1)
|
||||
return self._measured_value
|
||||
|
||||
def __repr__(self):
|
||||
return '{}:{}'.format(self.basis, self.value)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Alice:
|
||||
_otp: list = None
|
||||
bases: list = field(default_factory=list)
|
||||
_values: list = field(default_factory=list)
|
||||
|
||||
def encode_qbit(self, value):
|
||||
basis = random.randint(0, 1)
|
||||
self.bases.append(basis)
|
||||
return Photon(basis, value)
|
||||
|
||||
def generate_stream(self, stream_size=10):
|
||||
for _ in range(stream_size):
|
||||
qbit = random.randint(0, 1)
|
||||
self._values.append(qbit)
|
||||
yield self.encode_qbit(qbit)
|
||||
|
||||
def set_otp(self, other_correct):
|
||||
self._otp = [v for c, v in zip(other_correct, self._values) if c]
|
||||
|
||||
def get_otp_length(self):
|
||||
return len(self._otp)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Bob:
|
||||
correct: list = None
|
||||
_otp: list = None
|
||||
_bases: list = field(default_factory=list)
|
||||
_values: list = field(default_factory=list)
|
||||
|
||||
def ingest_stream(self, stream):
|
||||
for photon in stream:
|
||||
basis = random.randint(0, 1)
|
||||
self._bases.append(basis)
|
||||
qbit_value = photon.measure(basis)
|
||||
self._values.append(qbit_value)
|
||||
|
||||
def insecure_get_bases(self, other_bases):
|
||||
self.correct = [not (a ^ b) for a, b in zip(self._bases, other_bases)]
|
||||
self._otp = [v for c, v in zip(self.correct, self._values) if c]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Mallory:
|
||||
_bases: list = field(default_factory=list)
|
||||
_values: list = field(default_factory=list)
|
||||
|
||||
def ingest_stream(self, stream):
|
||||
for photon in stream:
|
||||
basis = random.randint(0, 1)
|
||||
self._bases.append(basis)
|
||||
qbit_value = photon.measure(basis)
|
||||
self._values.append(qbit_value)
|
||||
yield photon
|
||||
|
||||
|
||||
def main():
|
||||
alice, bob, mallory = Alice(), Bob(), Mallory()
|
||||
|
||||
# Step 1. Generate a stream of random photons polarizations in a random basis
|
||||
stream = alice.generate_stream(STREAM_LENGTH)
|
||||
|
||||
# Step 1.5 MALLORY ALSO INGESTS AND COPIES THE PHOTONS
|
||||
stream = mallory.ingest_stream(stream)
|
||||
|
||||
# Step 2. Bob ingests the stream of photons
|
||||
bob.ingest_stream(stream)
|
||||
|
||||
bob.insecure_get_bases(alice.bases)
|
||||
alice.set_otp(bob.correct)
|
||||
|
||||
assert alice._otp == bob._otp
|
||||
print("OTP Length: {}".format(alice.get_otp_length()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
24
test_generator.py
Normal file
24
test_generator.py
Normal file
@ -0,0 +1,24 @@
|
||||
def gen():
|
||||
print("start gen")
|
||||
for i in range(30):
|
||||
print('gen {}'.format(i))
|
||||
yield i
|
||||
|
||||
|
||||
def ingest(stream):
|
||||
print("start ingest+")
|
||||
for number in stream:
|
||||
print("injest {}".format(number))
|
||||
yield number
|
||||
|
||||
|
||||
def main():
|
||||
print("main")
|
||||
stream = gen()
|
||||
something = ingest(stream)
|
||||
for i in something:
|
||||
print(i)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user