Python program not handling long integers for Diffie-Hellman implementation - python

Im creating a Python program that implements the Diffie-Hellman protocol for Computer Security...
The program is supposed to take a single input, p, from the user which is the size of a prime number in bits.
I've coded all of it, except when I input a bitsize over 50, it will not give me an output. Im assuming its because of the extremely large numbers it is working with.
values g, a, and b are supposed to be parameter values in the group {1, 2, ..., p-1}, in which case, its supposed to be a random integer from this group.
Problem Block of Code
A = (g ** a) % p
B = (g ** b) % p
k1 = (B ** a) % p
k2 = (A ** b) % p
The Whole Program
import random
import math
import sympy
p_bits = input("Enter number of bits of prime number: ")
p_bits = int(p_bits)
p_bitsmax = ((2 ** p_bits) - 1)
p_bitsmin = (2 ** (p_bits - 1))
p = sympy.randprime(p_bitsmin, p_bitsmax)
g = random.randint(1, p-1)
a = random.randint(1, p-1)
b = random.randint(1, p-1)
A = (g ** a) % p
B = (g ** b) % p
k1 = (B ** a) % p
k2 = (A ** b) % p
print("The value of p selected:", p)
print("The value of g selected:", g)
print("The value of a selected by Alice:", a)
print("The value of b selected by Bob:", b)
print("The value of A sent to Bob by Alice:", A)
print("The value of B sent to Alice by Bob:", B)
print("The value of shared key computed by Alice:", k1)
print("The value of shared key computed by Bob:", k2)
print("")
if k1 == k2:
print("The shared keys match.")
else:
print("The shared keys don't match. Something went wrong.")
EDIT:
After testing the code in Jupyter Notebook, I see it has no problems assigning random values to g, a, and b, but rather it can't compute A, B, and shared keys with bit sizes over 50.

Related

z3 power mod constraint throws Z3Exception

I have set up a large table of constraints, as such:
value_n=1319677575750664593269928592823122088231102756079484792845079638972350094036132691958059688916820689747030184510113829740113041751835106779040361964704732781674939111970921386382076965209456061359009064103696057581141587585573457409644899626416953339600078178839886677162434056466419378007334549881514299423667452655244230384294862385143577667675301828094532154331478209619704980444350466007158636501159025323438259949492591777519923746198537834074290240109117233
value_a=342691274423584349791056473125411134098438481683180895903867322580082465637958239934448846612075098614285219068292647847040005389205050272757677433858953494823759242244829180636673330238802274884481886959589470615694177803698174718690765848886907721839332228324388423577817424201793491303906581758910921445168317877902384290187158732544836897687264045955879735934334920222645677067477720579027115764510363046519727124832263309244176383203195395120143396393280178
value_c=966614148477848624030200621625258849031380625915218872283078816676928740125344244698257425964002821854099461580094436358123535723290845114669846893220163142039503329214545667563764436310988727558365456532947041619144359286499858057080380889267035885314605337688144688305837511055021190348080983083350965687703714494963398464234969815079998913589315977406087449734769882954669673024108621512376903207095402574078110055132403183173806026764738715566878703793779398
value_sigma=8464844919528024050776743166493391951099685330616502566136514764715071037185126965166263456592507665693764888945402100735300264199432720007286127252491425
value_tau=10382212427405516607551590772908169835382410408959523296597160297199683505639053103035865826384731049385602808678770211265514520018139117856623297634063128
value_rho=2180308065203712074036416623837957892343118044869765657224934920507007488415740097667016690791656923501004556879088800046225392947371826678430341848539725784764496743600951899723067587234367926146679537689197024965709655834286819439034454072201704826252187806261154259276367446581026005274199093558591833001447262700832466548485390911986069977032843293472245605677321290489737169381053552716457700040526454320831401386889040870267821074531233371107830697865854527
sigma = Int('sigma')
tau = Int('tau')
rho = Int('rho')
random_1340 = Int('random_1340')
random_1160 = Int('random_1160')
random_335 = Int('random_335')
n = Int('n')
a = Int('a')
c = Int('c')
p = Int('p')
q = Int('q')
a_to_n = Int('a_to_n')
a_to_flag = Int('a_to_flag')
a_to_p_1 = Int('a_to_p_1')
kappa = Int('kappa')
flag = Int('flag')
equations = [
flag < p,
n == value_n, a == value_a, c == value_c, sigma == value_sigma, tau == value_tau, rho == value_rho,
a_to_n == a ** n,
a_to_flag == a ** flag,
a_to_p_1 == a ** (p-1),
c == ((((a_to_n % n) ** kappa) % n) * (a_to_flag % n)) % n,
n == p ** 2 * q,
kappa >= 1, kappa <= n - 1,
p > q, 2 * q > p,
a >= 2, a <= n - 1 , a_to_p1 % (p * p) != 1,
sigma >= 2, sigma <= q - 1,
random_1340 >= 1, random_1340 <= 2**1340, random_1160 >= 1, random_1160 <= 2**1160, random_335 >= 1, random_335 <= 2 ** 335,
tau == (p * p * sigma - random_1340) / q ** 2 + random_335,
rho == p * p * sigma + q * q * tau + random_1160
]
When I try to solve, two of the equations are giving me issues:
[
c == ((((a_to_n % n) ** kappa) % n) * (a_to_flag % n)) % n,
a_to_p1 % (p * p) != 1,
]
I get a z3.z3types.Z3Exception: Z3 integer expression expected:
c == ((((a_to_n % n) ** kappa) % n) * (a_to_flag % n)) % n,
File "/home/retep/.local/lib/python3.8/site-packages/z3/z3.py", line 2411, in __mod__
_z3_assert(a.is_int(), "Z3 integer expression expected")
A is defined as an Int type, so why does this happen and how do I resolve it?
The problem here is that ** produces a Real number, not an Int, and thus you cannot combine the result with % later on. Here's a simple example to illustrate:
>>> from z3 import *
>>> a, n = Ints('a n')
>>> (a ** n).sort()
Real
That is, the expression a ** n is Real valued; so you cannot take the modulus with an integer later on. To convert back to integer, use ToInt:
>>> ToInt(a ** n).sort()
Int
So, whenever you use **, wrap the result in a call to ToInt to avoid this issue.
Having said that, mixing reals and integers this way will no doubt make your problem quite hard to deal with in z3. I wouldn't be surprised if z3 had very hard time solving your equations, assuming they're not merely constant folding. Perhaps you should simply stick to Real values for everything, which has a decidable theory. (Doesn't mean z3 can answer your queries easily; it just means z3 can decide it if you are willing to wait long enough and have enough computing resources.)

Why the program does not correctly search for the general solution of the Diophantine equation

I wrote a program that looks for a general solution to a Diophantine equation, but the solution is not entirely correct when I check the online calculator. For example, for the equation "45x-128y=177" the solution in general form should be "x=6549-128k" and "y=2301-45k", but I get "x=6549+k128" and
"y=-2301+k45".
My code:
import re
def extended_gcd(a, b):
if a == 0:
return (0, 1)
(x, y) = extended_gcd(b % a, a)
return (y - (b // a) * x), x
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def main():
s = input('Enter the Diophantine equation: ')
s1 = re.findall(r'\d+', s)
a = int(s1[0])
b = int(s1[1])
c = int(s1[2])
d = gcd(a, b)
print(f'GCD({a},{b}) = {d}')
if d % c != 0:
print('This equation has an infinite set of solutions')
a1 = a // d
b1 = b // d
print(f'Short equation: {a1}s + {b1}t = {1}')
(s, t) = extended_gcd(a1, b1)
x0 = (c // d) * s
y0 = (c // d) * t
print("General solution")
print(f"x = {x0} + k * {b // d}")
print(f"y = {y0} + k * {a // d}")
else:
print('This equation has no solution')
if __name__ == "__main__":
main()
What is the problem and how to solve it?
One Python problem you have is your regex does not match negative numbers, ie in your example s1[1] is 128 not -128. To match the sign you can change the regex matching line to
s1 = re.findall(r'[-+]?\d+', s)
so s1[1] is now the correct -128, as you can check by printing it at the right point
It still does not produce the right answer it seems but at least the inputs should be correct after the fix. You should double check that you coded the algorithm correctly and for example print intermediate results and check them against your by-hand (or Excel) calculations. We can help you with coding problems here but not so much with your algorithm issues...

Calculating Payment Size Using Bisection Method in Python

I've been working on this problem for MIT's edX course. The goal of the problem is to calculate the payment size for one year given the loan size and APY. My problem is that my answer keeps coming up too high. I'm not exactly sure why this is. Any help would be greatly appreciated.
Here is the code:
b = float(input("balance = "))
r = float(input("annualInterestRate = "))
t = float(input("How many months do you want to take = "))
p = (b / t)
bval = []
new = b
def interest(b, r, p, t):
bal = (b - p)
max = (b * (1 + r / 12)**(12))/12
min = (b / t)
def update(bal, r):
balance = (bal + (r / 12.0) * bal)
return balance
if len(bval) < t:
bval.append(update(bal, r))
return(interest(bval[-1], r, p, t))
if (len(bval) == t):
if bval[-1]< 10:
return print(" Minimum payment: %i" % p)
p = (max + min) / 2.0
if bval[-1] < 0:
min = bval[-1]
elif bval[-1] > 0:
max = bval[-1]
bval.clear()
bval.append(update((new - p), r))
return(interest(bval[-1], r, p, t))
interest(b, r, p, t)
There may be an issue with your order of operations in max. You might want to try adding parentheses around 1+r before dividing it by 12.

Python RSA Brute Force Check

I have an exercise to brute force a piece of text that has been encrypted with a very small key. The public key I have is (e = 5, n = 203). The text has been converted to ASCII, shifted a fixed number and then encrypted with the RSA public key. I have to decrypt this text using brute force only. To decrypt I'm using the simple formula of:
decrypt = (value**d)%n
Where value is the thing I want to decrypt, d being the value I am unsure of and n being the modulus.
So far I have put the numbers in a tuple called en and I loop through it like this:
for i in range(1,10):
for a in range(0,41):
ans = (en[a]**i)%203
print (chr(ans))
The first for loop is "d" the private key value I am not sure of and the second for loop is for going through the 41 length tuple. I don't have the block shift part implemented yet but I want to check if this is the correct way of brute forcing a simple RSA key.
You should try to factor n by brute force:
for i in range(n):
if n%i == 0:
print i
, from which you will find p=7 and q=29.
d = e^-1 mod phi(n)
= e^-1 mod (p-1)*(q-1)
therefore d = e^-1 mod 168, ergo d=162.
I took the liberty to improve on L3viathan's answer and provide a full working source ready to copy paste and run:
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def factor(n):
for i in range(3, n):
if n%i == 0:
return i
e = 5
n = 203
p = factor(n)
q = n//p
phi_n = (p-1) * (q-1)
# Only for python >= 3.8
# From https://docs.python.org/3/library/functions.html#pow
# If mod is present and exp is negative, base must be relatively prime to mod.
# In that case, pow(inv_base, -exp, mod) is returned, where inv_base is an inverse to base modulo mod.
# d_crack = pow(e, -1, phi_n)
# python < 3.8
d_crack = modinv(e, phi_n)
print('cracked d:', d_crack) # prints "cracked d: 101"

Dividing by zero error in Python?

I'm writing a program where the user enters a, b, c, d, e, and f and displays the result. If ad - bc = 0, I'm supposed to report that there is no solution. But even when I include the part of code where:
if denominator == 0: print("The equation has no solution")
I keep getting a dividing by zero error. The numbers I use for the prompt are 1.0, 2.0, 2.0, 4.0, 4.0, 5.0 respectively. Here's my code:
def cramersRule():
a = float(input("Enter a: "))
b = float(input("Enter b: "))
c = float(input("Enter c: "))
d = float(input("Enter d: "))
e = float(input("Enter e: "))
f = float(input("Enter f: "))
denominator = ((a * d) - (b * c))
x = (((e * d) - (b * f)) / denominator)
y = (((a * f) - (e * c)) / denominator)
e = ((a * x) + (b * y))
f = ((c * x) + (d * y))
if denominator == 0:
print("The equation has no solution.")
else:
print("x is", x , "and y is" , y)
Please help!
You are performing calculations with it:
x = (((e * d) - (b * f)) / denominator)
y = (((a * f) - (e * c)) / denominator)
That's why you get the error. You must first check if the denominator is zero.
def cramersRule():
a = float(input("Enter a: "))
b = float(input("Enter b: "))
c = float(input("Enter c: "))
d = float(input("Enter d: "))
e = float(input("Enter e: "))
f = float(input("Enter f: "))
denominator = ((a * d) - (b * c))
if denominator == 0:
print("The equation has no solution.")
else:
x = (((e * d) - (b * f)) / denominator)
y = (((a * f) - (e * c)) / denominator)
e = ((a * x) + (b * y))
f = ((c * x) + (d * y))
print("x is", x , "and y is" , y)
Everyone else has solved the problem you asked about; here's the problem you didn't ask about, better code organization!
from __future__ import division # all division is floating-point
import sys
# version compatibility
if sys.hexversion < 0x3000000:
inp = raw_input # Python 2.x
else:
inp = input # Python 3.x
def get_float(prompt):
while True:
try:
return float(inp(prompt))
except ValueError:
pass
def cramers_rule(a, b, c, d, e, f):
denominator = a*d - b*c
if denominator:
x = (e*d - b*f) / denominator
y = (a*f - e*c) / denominator
e = a*x + b*y
f = c*x + d*y
return x, y, e, f
else:
return None # no solution
def main():
prompt = "Enter {0}: ".format
kwargs = {ch:get_float(prompt(ch)) for ch in 'abcdef'}
res = cramers_rule(**kwargs)
if res is None:
print("The equation has no solution.")
else:
print("x is {0} and y is {1}".format(*res))
if __name__=="__main__":
main()
.
Each function should only do one thing: cramers_rule() should calculate Cramer's Rule, it should not be doing input and output. Having cramers_rule() accept arguments and return the result means it can be reused (ie in actual calculations).
Error checking on inputs - it's nice if it doesn't crash if, when you ask the user for a float, they enter 'potato' (you know someone will). Delegated to get_float(), where it belongs.
if x == 0: is unPythonic; PEP-8 says if not x: is preferred because it allows duck-typing - the function will now work on any type that knows how to do elementary operations. I don't know if it makes sense to apply Cramer's Law to tensors, but if it does, now you can.
Python operators obey order of operations; I got rid of a bunch of extraneous parentheses.
Hope that helps ;-)
You should use the try-except error handling pattern. Here's a basic example:
try:
x = (((e * d) - (b * f)) / denominator)
except ZeroDivisionError:
print("The equation has no solution.")
else:
print("Success!")
Move your check for zero to earlier in your function like so:
...
denominator = ((a * d) - (b * c)
if denominator == 0:
print("The equation has no solution.")
else:
x = (((e * d) - (b * f)) / denominator)
y = (((a * f) - (e * c)) / denominator)
e = ((a * x) + (b * y))
f = ((c * x) + (d * y))
print("x is", x , "and y is" , y)

Categories

Resources