diff --git a/qkd.py b/00_qkd.py similarity index 100% rename from qkd.py rename to 00_qkd.py diff --git a/computer.py b/01_computer.py similarity index 100% rename from computer.py rename to 01_computer.py diff --git a/02_cirq.py b/02_cirq.py new file mode 100644 index 0000000..f40d918 --- /dev/null +++ b/02_cirq.py @@ -0,0 +1,18 @@ +import cirq + +# Pick a qubit. +qubit = cirq.GridQubit(0, 0) + +# Create a circuit +circuit = cirq.Circuit.from_ops( + cirq.X(qubit)**0.5, # Square root of NOT. + cirq.measure(qubit, key='m') # Measurement. +) +print("Circuit:") +print(circuit) + +# Simulate the circuit several times. +simulator = cirq.Simulator() +result = simulator.run(circuit, repetitions=20) +print("Results:") +print(result) \ No newline at end of file diff --git a/03_shors.md b/03_shors.md new file mode 100644 index 0000000..6de8fb4 --- /dev/null +++ b/03_shors.md @@ -0,0 +1,29 @@ +RSA relies on: + +``` +N = p*q +``` + +where N is a big number and `p` and `q` are large prime number. + +So, say we have `N`. Make a guess `g`. `g` doesn't have to be a factor of N, +it can be a number that shares factors with N, e.g. + +``` +N = g * h + +N = a * b # 4 = 2 * 2 +g = a * c # 6 = 2 * 3 +gcd(N, g) = a + +g^(p/2) +- 1 + +A, B -> no common factors +A, B -> A^p = m*B + 1 +7, 15 -> 7^2 = 3*15 + 1 + 7^3 = 22*15 + 13 + 160*15 + 1 + +``` + + diff --git a/03_shors.py b/03_shors.py new file mode 100644 index 0000000..e5d5226 --- /dev/null +++ b/03_shors.py @@ -0,0 +1,84 @@ +""" +RSA is an asymmetric encr algo that relies on a public key and a private key. +Public key encrypts message M to a cyphertext C: + + C = M^e % N + +e is part of the public key and is implementation specific, chosen +but frequently chosen to be 3 (bad) or 17 or 65537 (a number that has a +lot of 0s, makes "computer maths easy). + +N is also part of the public key - N = p*q, where p and q are (large) prime +numbers. + +Decrypting the message: + + M = C^d % N + +d is the part of the private key (private exponent) derived using p and q, +such that: + + e*d=1%((p-1)(q-1)) + +To break the encryption, if one gets to factor N to p and q, d can be +derviced from there + +""" +import sys + +def d(p, q, e=3): + """ TODO: Doesn't make sense!?""" + return 1%((p-1)*(q-1)) + +def gcd(a, b): + if b == 0: + return a + return gcd(b, a % b) + + +def trick(A, B, p_max=10): + """ + If A and B are mutually prime (gcd is 1): + + A^p = m*B + 1 + + for some p and m. + + returns p and m + """ + if gcd(A,B) != 1: + print("ERROR: A, B not mutually prime!") + return None, None + for p in range(2, p_max): + m, found = 1, False + lhs, rhs = A**p, m*B + 1 + while lhs > rhs: + rhs = m*B + 1 + print("({}, {}): {} =? {}".format(p, m, lhs, rhs)) + if lhs == rhs: + found = True + break + m += 1 + if found: + print('===== FOUND') + print("p={}, m={}".format(p, m)) + return p, m + print("Not found up to {}".format(p_max)) + return None, None + + + +# (g^p/2 + 1) * (g^p/2 -1) = m*N --- this is almost like a*b~=N +# because of m*N, the terms on LHS might not be the factors but +# multiple of factors, i.e. a*factor, b*factor +# e.g. 7^4/2 + 1 = 50; 7^4/2 - 1 = 48; which are not factors of 15 +# gcd(50, 15) = 5, gcd(48, 15) = 3 + +# Trick #2: +# g^x = m_1*N + r +# g^(x+p) = m_2*N + r +# [if g^p = m_1*N + 1 => expanding g^(x+p)=g^x*x^p=(m_1*N+1)*(m_2*N+r)=...=(m_1*m_2 + 3m_1+m_2)*N +r ~= something*N+r + +if __name__ == '__main__': + trick(int(sys.argv[1]), int(sys.argv[2])) +