SHA-256 implementation in Python - python

I'm looking for a Python implementation of the SHA-256 hash function. I want to use it to get a better understanding of how the SHA-256 function works, and I think Python is the ideal language for this. Pseudo-code has the limitation that I can't run/test it, to see what my modifications of the code do to the output.

PyPy's source contains a pure-python implementation of SHA-256 here. Poking around in that directory, you'll probably also find pure-python implementations of other standard hashes.

initial_hash_values=[
'6a09e667','bb67ae85','3c6ef372','a54ff53a',
'510e527f','9b05688c','1f83d9ab','5be0cd19'
]
sha_256_constants=[
'428a2f98','71374491','b5c0fbcf','e9b5dba5',
'3956c25b','59f111f1','923f82a4','ab1c5ed5',
'd807aa98','12835b01','243185be','550c7dc3',
'72be5d74','80deb1fe','9bdc06a7','c19bf174',
'e49b69c1','efbe4786','0fc19dc6','240ca1cc',
'2de92c6f','4a7484aa','5cb0a9dc','76f988da',
'983e5152','a831c66d','b00327c8','bf597fc7',
'c6e00bf3','d5a79147','06ca6351','14292967',
'27b70a85','2e1b2138','4d2c6dfc','53380d13',
'650a7354','766a0abb','81c2c92e','92722c85',
'a2bfe8a1','a81a664b','c24b8b70','c76c51a3',
'd192e819','d6990624','f40e3585','106aa070',
'19a4c116','1e376c08','2748774c','34b0bcb5',
'391c0cb3','4ed8aa4a','5b9cca4f','682e6ff3',
'748f82ee','78a5636f','84c87814','8cc70208',
'90befffa','a4506ceb','bef9a3f7','c67178f2'
]
def bin_return(dec):
return(str(format(dec,'b')))
def bin_8bit(dec):
return(str(format(dec,'08b')))
def bin_32bit(dec):
return(str(format(dec,'032b')))
def bin_64bit(dec):
return(str(format(dec,'064b')))
def hex_return(dec):
return(str(format(dec,'x')))
def dec_return_bin(bin_string):
return(int(bin_string,2))
def dec_return_hex(hex_string):
return(int(hex_string,16))
def L_P(SET,n):
to_return=[]
j=0
k=n
while k<len(SET)+1:
to_return.append(SET[j:k])
j=k
k+=n
return(to_return)
def s_l(bit_string):
bit_list=[]
for i in range(len(bit_string)):
bit_list.append(bit_string[i])
return(bit_list)
def l_s(bit_list):
bit_string=''
for i in range(len(bit_list)):
bit_string+=bit_list[i]
return(bit_string)
def rotate_right(bit_string,n):
bit_list = s_l(bit_string)
count=0
while count <= n-1:
list_main=list(bit_list)
var_0=list_main.pop(-1)
list_main=list([var_0]+list_main)
bit_list=list(list_main)
count+=1
return(l_s(list_main))
def shift_right(bit_string,n):
bit_list=s_l(bit_string)
count=0
while count <= n-1:
bit_list.pop(-1)
count+=1
front_append=['0']*n
return(l_s(front_append+bit_list))
def mod_32_addition(input_set):
value=0
for i in range(len(input_set)):
value+=input_set[i]
mod_32 = 4294967296
return(value%mod_32)
def xor_2str(bit_string_1,bit_string_2):
xor_list=[]
for i in range(len(bit_string_1)):
if bit_string_1[i]=='0' and bit_string_2[i]=='0':
xor_list.append('0')
if bit_string_1[i]=='1' and bit_string_2[i]=='1':
xor_list.append('0')
if bit_string_1[i]=='0' and bit_string_2[i]=='1':
xor_list.append('1')
if bit_string_1[i]=='1' and bit_string_2[i]=='0':
xor_list.append('1')
return(l_s(xor_list))
def and_2str(bit_string_1,bit_string_2):
and_list=[]
for i in range(len(bit_string_1)):
if bit_string_1[i]=='1' and bit_string_2[i]=='1':
and_list.append('1')
else:
and_list.append('0')
return(l_s(and_list))
def or_2str(bit_string_1,bit_string_2):
or_list=[]
for i in range(len(bit_string_1)):
if bit_string_1[i]=='0' and bit_string_2[i]=='0':
or_list.append('0')
else:
or_list.append('1')
return(l_s(or_list))
def not_str(bit_string):
not_list=[]
for i in range(len(bit_string)):
if bit_string[i]=='0':
not_list.append('1')
else:
not_list.append('0')
return(l_s(not_list))
'''
SHA-256 Specific Functions:
'''
def Ch(x,y,z):
return(xor_2str(and_2str(x,y),and_2str(not_str(x),z)))
def Maj(x,y,z):
return(xor_2str(xor_2str(and_2str(x,y),and_2str(x,z)),and_2str(y,z)))
def e_0(x):
return(xor_2str(xor_2str(rotate_right(x,2),rotate_right(x,13)),rotate_right(x,22)))
def e_1(x):
return(xor_2str(xor_2str(rotate_right(x,6),rotate_right(x,11)),rotate_right(x,25)))
def s_0(x):
return(xor_2str(xor_2str(rotate_right(x,7),rotate_right(x,18)),shift_right(x,3)))
def s_1(x):
return(xor_2str(xor_2str(rotate_right(x,17),rotate_right(x,19)),shift_right(x,10)))
def message_pad(bit_list):
pad_one = bit_list + '1'
pad_len = len(pad_one)
k=0
while ((pad_len+k)-448)%512 != 0:
k+=1
back_append_0 = '0'*k
back_append_1 = bin_64bit(len(bit_list))
return(pad_one+back_append_0+back_append_1)
def message_bit_return(string_input):
bit_list=[]
for i in range(len(string_input)):
bit_list.append(bin_8bit(ord(string_input[i])))
return(l_s(bit_list))
def message_pre_pro(input_string):
bit_main = message_bit_return(input_string)
return(message_pad(bit_main))
def message_parsing(input_string):
return(L_P(message_pre_pro(input_string),32))
def message_schedule(index,w_t):
new_word = bin_32bit(mod_32_addition([int(s_1(w_t[index-2]),2),int(w_t[index-7],2),int(s_0(w_t[index-15]),2),int(w_t[index-16],2)]))
return(new_word)
'''
This example of SHA_256 works for an input string <56 characters.
'''
def sha_256(input_string):
assert len(input_string) < 56, "This example of SHA_256 works for an input string <56 characters."
w_t=message_parsing(input_string)
a=bin_32bit(dec_return_hex(initial_hash_values[0]))
b=bin_32bit(dec_return_hex(initial_hash_values[1]))
c=bin_32bit(dec_return_hex(initial_hash_values[2]))
d=bin_32bit(dec_return_hex(initial_hash_values[3]))
e=bin_32bit(dec_return_hex(initial_hash_values[4]))
f=bin_32bit(dec_return_hex(initial_hash_values[5]))
g=bin_32bit(dec_return_hex(initial_hash_values[6]))
h=bin_32bit(dec_return_hex(initial_hash_values[7]))
for i in range(0,64):
if i <= 15:
t_1=mod_32_addition([int(h,2),int(e_1(e),2),int(Ch(e,f,g),2),int(sha_256_constants[i],16),int(w_t[i],2)])
t_2=mod_32_addition([int(e_0(a),2),int(Maj(a,b,c),2)])
h=g
g=f
f=e
e=mod_32_addition([int(d,2),t_1])
d=c
c=b
b=a
a=mod_32_addition([t_1,t_2])
a=bin_32bit(a)
e=bin_32bit(e)
if i > 15:
w_t.append(message_schedule(i,w_t))
t_1=mod_32_addition([int(h,2),int(e_1(e),2),int(Ch(e,f,g),2),int(sha_256_constants[i],16),int(w_t[i],2)])
t_2=mod_32_addition([int(e_0(a),2),int(Maj(a,b,c),2)])
h=g
g=f
f=e
e=mod_32_addition([int(d,2),t_1])
d=c
c=b
b=a
a=mod_32_addition([t_1,t_2])
a=bin_32bit(a)
e=bin_32bit(e)
hash_0 = mod_32_addition([dec_return_hex(initial_hash_values[0]),int(a,2)])
hash_1 = mod_32_addition([dec_return_hex(initial_hash_values[1]),int(b,2)])
hash_2 = mod_32_addition([dec_return_hex(initial_hash_values[2]),int(c,2)])
hash_3 = mod_32_addition([dec_return_hex(initial_hash_values[3]),int(d,2)])
hash_4 = mod_32_addition([dec_return_hex(initial_hash_values[4]),int(e,2)])
hash_5 = mod_32_addition([dec_return_hex(initial_hash_values[5]),int(f,2)])
hash_6 = mod_32_addition([dec_return_hex(initial_hash_values[6]),int(g,2)])
hash_7 = mod_32_addition([dec_return_hex(initial_hash_values[7]),int(h,2)])
final_hash = (hex_return(hash_0),
hex_return(hash_1),
hex_return(hash_2),
hex_return(hash_3),
hex_return(hash_4),
hex_return(hash_5),
hex_return(hash_6),
hex_return(hash_7))
return(final_hash)

Some time ago I was also studying SHA-256 and created pure-python class that implements this hash. If I remember correctly, mostly I've taken algorithm from Wikipedia SHA-256 Pseudocode and partially from some open-source projects.
Algorithm doesn't import any (even standard) modules. Of cause it is much slower than hashlib's variant and only meant for studying.
If you just run the script it executes 1000 tests comparing hashlib's and my variants. Only testing function imports some modules, algorithm's class itself doesn't need any modules. Interface is same as in hashlib's sha256 class. See test() function for examples of usage.
Try it online!
class Sha256:
ks = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
]
hs = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
]
M32 = 0xFFFFFFFF
def __init__(self, m = None):
self.mlen = 0
self.buf = b''
self.k = self.ks[:]
self.h = self.hs[:]
self.fin = False
if m is not None:
self.update(m)
#staticmethod
def pad(mlen):
mdi = mlen & 0x3F
length = (mlen << 3).to_bytes(8, 'big')
padlen = 55 - mdi if mdi < 56 else 119 - mdi
return b'\x80' + b'\x00' * padlen + length
#staticmethod
def ror(x, y):
return ((x >> y) | (x << (32 - y))) & Sha256.M32
#staticmethod
def maj(x, y, z):
return (x & y) ^ (x & z) ^ (y & z)
#staticmethod
def ch(x, y, z):
return (x & y) ^ ((~x) & z)
def compress(self, c):
w = [0] * 64
w[0 : 16] = [int.from_bytes(c[i : i + 4], 'big') for i in range(0, len(c), 4)]
for i in range(16, 64):
s0 = self.ror(w[i - 15], 7) ^ self.ror(w[i - 15], 18) ^ (w[i - 15] >> 3)
s1 = self.ror(w[i - 2], 17) ^ self.ror(w[i - 2], 19) ^ (w[i - 2] >> 10)
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & self.M32
a, b, c, d, e, f, g, h = self.h
for i in range(64):
s0 = self.ror(a, 2) ^ self.ror(a, 13) ^ self.ror(a, 22)
t2 = s0 + self.maj(a, b, c)
s1 = self.ror(e, 6) ^ self.ror(e, 11) ^ self.ror(e, 25)
t1 = h + s1 + self.ch(e, f, g) + self.k[i] + w[i]
h = g
g = f
f = e
e = (d + t1) & self.M32
d = c
c = b
b = a
a = (t1 + t2) & self.M32
for i, (x, y) in enumerate(zip(self.h, [a, b, c, d, e, f, g, h])):
self.h[i] = (x + y) & self.M32
def update(self, m):
if m is None or len(m) == 0:
return
assert not self.fin, 'Hash already finalized and can not be updated!'
self.mlen += len(m)
m = self.buf + m
for i in range(0, len(m) // 64):
self.compress(m[64 * i : 64 * (i + 1)])
self.buf = m[len(m) - (len(m) % 64):]
def digest(self):
if not self.fin:
self.update(self.pad(self.mlen))
self.digest = b''.join(x.to_bytes(4, 'big') for x in self.h[:8])
self.fin = True
return self.digest
def hexdigest(self):
tab = '0123456789abcdef'
return ''.join(tab[b >> 4] + tab[b & 0xF] for b in self.digest())
def test():
import secrets, hashlib, random
for itest in range(500):
data = secrets.token_bytes(random.randrange(257))
a, b = hashlib.sha256(data).hexdigest(), Sha256(data).hexdigest()
assert a == b, (a, b)
for itest in range(500):
a, b = hashlib.sha256(), Sha256()
for j in range(random.randrange(10)):
data = secrets.token_bytes(random.randrange(129))
a.update(data)
b.update(data)
a, b = a.hexdigest(), b.hexdigest()
assert a == b, (a, b)
print('Sha256 tested successfully.')
if __name__ == '__main__':
test()

If you only want the hash value:
from hashlib import sha256
data = input('Enter plaintext data: ')
output = sha256(data.encode('utf-8'))
print(output)
Python's hashlib also has SHA-1, SHA-384, SHA-512, and MD5 hash functions.

Here is my proposition with redis:
for i in range(len(rserver.keys())):
mdp_hash = rserver.get(rserver.keys()[i])
rserver.set(rserver.keys()[i], hashlib.sha256(mdp_hash.encode()).hexdigest())

Translating http://en.wikipedia.org/wiki/SHA-2#SHA-256_.28a_SHA-2_variant.29_pseudocode to Python should be straight forward.

Related

SciPy Optimise minimise error - challenge to solve

How do I solve this error?
TypeError: NumPy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
I have programmed an optimizing program that must minimize the cost of a wall design. The wall is based on 3 parameters, x, k and m. There are constraints to the sizes of x, k and m as shown. Another constraint is that z (or deflection) must be kept under 100mm. The equation for deflection changes based on a certain t (or time) at which the blast wall is experiencing the blast. If t is below a certain time value which is calculated dependent on, x, k and m the equation is as shown. If t is above the same certain time value, the equation for z changes.
Here is the programming... Please help many thanks :)
import numpy as np
from numpy import linspace
from math import cos
from math import sin
from scipy.optimize import minimize
#Function for minimising
def calcCost(c):
k = c[0]
m = c[1]
x = c[2]
Cost = (900 + 825*k**2 - 1725) + (10*m - 200) + ((2400*x**2)/4)
return Cost
#Objective function
def objective(c):
return calcCost(c)
#Defining Variables
def calck(c):
k = c[0]
k=k
k.resize(12,)
return k
def calcm(c):
m = c[1]
m=m
m.resize(12,)
return m
def calcx(c):
x = c[2]
x=x
x.resize(12,)
return x
def calcz(c):
k = c[0]
x = c[1]
m = c[2]
l = linspace(0,140,141)
for t in l:
if t <= ((20 - 0.12*x**2 + 4.2*x)/1000):
deflection = ((((1000+9*x**2-183*x)*1000)/k)*(1-cos(t*((k/m)**0.5))) + (((1000+9*x**2-183*x)*1000)/k*((20 - 0.12*x**2 + 4.2*x)/1000))*((sin(t*((k/m)**0.5))/((k/m)**0.5))-t))*1000
else:
deflection = ((((1000+9*x**2-183*x)*1000)/(k*((k/m)**0.5)*((20 - 0.12*x**2 + 4.2*x)/1000)))*(sin(((k/m)**0.5)*t))-(sin(((k/m)**0.5)*(t-((20 - 0.12*x**2 + 4.2*x)/1000))))-(((1000+9*x**2-183*x)*1000)/k)*cos(((k/m)**0.5)*t))*1000
deflection.resize(12,)
return deflection
#Constraint functions
def kconstraint1(c):
k = c[0]
return k-(1*10**6) >= 0
def kconstraint2(c):
k = c[0]
return k-(7*10**6) <= 0
def mconstraint1(c):
m = c[0]
return m-200 >= 0
def mconstraint2(c):
m = c[0]
return m-1200 <= 0
def xconstraint1(c):
x = c[0]
return x >= 0
def xconstraint2(c):
x = c[0]
return x <= 10
def zconstraint1(c):
k = c[0]
x = c[1]
m = c[2]
l = linspace(0,140,141)
for t in l:
if t <= ((20 - 0.12*x**2 + 4.2*x)/1000):
deflection = ((((1000+9*x**2-183*x)*1000)/k)*(1-cos(t*((k/m)**0.5))) + (((1000+9*x**2-183*x)*1000)/k*((20 - 0.12*x**2 + 4.2*x)/1000))*((sin(t*((k/m)**0.5))/((k/m)**0.5))-t))*1000
else:
deflection = ((((1000+9*x**2-183*x)*1000)/(k*((k/m)**0.5)*((20 - 0.12*x**2 + 4.2*x)/1000)))*(sin(((k/m)**0.5)*t))-(sin(((k/m)**0.5)*(t-((20 - 0.12*x**2 + 4.2*x)/1000))))-(((1000+9*x**2-183*x)*1000)/k)*cos(((k/m)**0.5)*t))*1000
return deflection <= 99.99999999
b = (0.5,1)
be = (0.5,10)
bb = (0.1,2.0)
bnds = (b,be,bb,bb)
con1 = ({'type':'ineq','fun':kconstraint1})
con2 = ({'type':'ineq','fun':kconstraint2})
con3 = ({'type':'ineq','fun':mconstraint1})
con4 = ({'type':'ineq','fun':mconstraint2})
con5 = ({'type':'ineq','fun':xconstraint1})
con6 = ({'type':'ineq','fun':xconstraint2})
con7 = ({'type':'ineq','fun':zconstraint1})
cons = [con1,con2,con3,con4,con5,con6,con7]
xGUESS = 5
kGUESS = 3*10**6
mGUESS = 700
zGUESS = 90
x0 = np.array([xGUESS,kGUESS,mGUESS,zGUESS])
sol = minimize(objective,x0,method='SLSQP',bounds=bnds,constraints=cons,options={'disp':True})
xOpt = sol.x
CostOPT = sol.fun
kOPT = calck(xOpt)
xOPT = calcx(xOpt)
mOPT = calcm(xOpt)
zOPT = calcz(xOpt)
print(str(CostOPT))
print(str(calcx))
print(str(calcm))
print(str(calck))
print(str(calcz))

Rabin-Karp 2D pattern search runs slower than brute force

I have implemented the Rabin-Karp 2D algorithm for pattern searching in python. However, my implementation is slower than the brute force version over a 1000x2000 matrix. Please help me identify the bottle neck. Thanks, and I appreciate your comments.
Note 1: the code is right in finding the position where the pattern matches but runs slower, 1.23s v.s. 0.54s for brute force version on my computer.
Note 2: although one can come up with the worst-case such that Rabin-Karp could be as slow as brute force, the test case given is not designed on purpose to make it O(m(n-m+1)).
Disclaimer : Although this problem is an assignment problem in Algorithms, 4th Edition by Sedgewick and Wayne, it is not my homework. I am learning this algorithm.
Here is the code:
'''
Searches for a 2D pattern in a 2D text. Assumes that both the pattern and the
text are rectangles of characters.
O(Mr * Nr * Nc), where Mr is the pattern row length, Nr is the text row length
and Nc is the text column length
'''
MOD = 10**9+7
class RabinKarp2DV3(object):
def __init__(self, rad, pattern):
#Radix of the alphabet. Assumes ASCII characters
self.RADIX = rad
self.pattern = pattern
self.height = len(pattern)
self.width = len(pattern[0])
self.factors_col = [0]*(self.height)
self.factors_row = [0]*(self.width)
self.factors_col[0] = 1
for i in range(1, len(self.factors_col)):
self.factors_col[i] = (self.RADIX * self.factors_col[i - 1]) % MOD
self.factors_row[0] = 1
for i in range(1, len(self.factors_row)):
self.factors_row[i] = (self.RADIX * self.factors_row[i - 1]) % MOD
hash1d_p = [0]*self.width
self.hash2D(self.pattern, hash1d_p, self.width)
self.patternHash = self.SingleHash(hash1d_p)
def hash2D(self, data, hash1d, hei):
for i in range(hei):
hash1d[i] = 0
for j in range(self.height):
hash1d[i] = (self.RADIX * hash1d[i] + ord(data[j][i])) % MOD
def rehash2D(self, data, hash1d, hei, j):
for i in range(hei):
hash1d[i] = self.RADIX*((hash1d[i] + MOD - self.factors_col[self.height-1]
* ord(data[j][i])%MOD) % MOD) % MOD
hash1d[i] = (hash1d[i] + ord(data[j+self.height][i])) % MOD
def SingleHash(self, hash1d):
res = 0
for i in range(self.width):
res = (self.RADIX * res + hash1d[i]) % MOD
return res
def SingleReHash(self, hash, hash1d, pos):
hash = self.RADIX*((hash + MOD - self.factors_row[self.width-1]*hash1d[pos]%MOD) % MOD) % MOD
hash = (hash + hash1d[pos+self.width]) % MOD
return hash
def check(self, text, i, j):
x, y = i, j
for a in range(self.height):
for b in range(self.width):
if text[x][y] != self.pattern[a][b]:
return False
y += 1
x += 1
y = j
return True
def search(self, text):
hash1d = [0]*len(text[0])
for i in range(len(text)-self.height+1):
if i == 0:
self.hash2D(text, hash1d, len(text[0]))
else:
self.rehash2D(text, hash1d, len(text[0]), i-1)
textHash = 0
for j in range(len(text[0]) - self.width+1):
if j == 0:
textHash = self.SingleHash(hash1d)
else:
textHash = self.SingleReHash(textHash, hash1d, j-1)
#print(i, j, textHash, patternHash)
if textHash == self.patternHash and self.check(text, i, j):
return [i, j]
return None
class BruteForce(object):
def __init__(self, pattern):
self.pattern = pattern
self.height = len(pattern)
self.width = len(pattern[0])
def check(self, text, i, j):
x, y = i, j
for a in range(self.height):
for b in range(self.width):
if text[x][y] != self.pattern[a][b]:
return False
y += 1
x += 1
y = j
return True
def search(self, text):
for i in range(len(text)-self.height+1):
for j in range(len(text[0]) - self.width+1):
if self.check(text, i, j):
return [i, j]
return None
if __name__ == "__main__":
import random
import string
import time
chars = string.ascii_uppercase
im, jm = 1000, 2000
text = []
for i in range(im):
s = ''
for j in range(jm):
s += random.choice(chars)
text.append(s)
pattern = []
for i in range(20):
pattern.append(text[357+i][478:478+40])
start_time = time.time()
matcher = RabinKarp2DV3(256, pattern)
print(matcher.search(text))
print("--- %s seconds ---" % (time.time() - start_time))
start_time = time.time()
matcher = BruteForce(pattern)
print(matcher.search(text))
print("--- %s seconds ---" % (time.time() - start_time))

TypeError: int object is not iterable when trying to use a list of prime numbers

So I have been writing a function to generate a key as a tuple using randomly generated prime numbers, and when I try to run the code it generates the error(s),
PS C:\Users\cinna\workspace\project4> py rsa.py S
Traceback (most recent call last):
File "C:\Users\cinna\workspace\project4\rsa.py", line 104, in <module>
_main()
File "C:\Users\cinna\workspace\project4\rsa.py", line 91, in _main
n, e, d = keygen(25, 100)
File "C:\Users\cinna\workspace\project4\rsa.py", line 10, in keygen
primes = _primes(lo, hi)
File "C:\Users\cinna\workspace\project4\rsa.py", line 69, in _primes
primes += p
TypeError: 'int' object is not iterable
Edit: Here is my code for keygen(), _primes() and main(). Thanks for the patience, still learning StackOverflow etiquette.
def keygen(lo, hi):
primes = _primes(lo, hi)
for i in range(lo, hi):
if _primes(i):
ptemp = stdrandom.uniformInt(0, len(primes))
qtemp = stdrandom.uniformInt(0, len(primes))
p = primes[ptemp]
q = primes[qtemp]
n = p * q
m = (p - 1) * (q - 1)
while True:
e = stdrandom.uniformInt(2, m)
if e % m == 0 and m % e != 0:
break
d = 0
for a in range(1, m):
if (e * a) % m == 1:
d = a
break
return n, e, d
def _primes(lo, hi):
primes = []
for p in range(lo, hi + 1):
j = 2
f = 1
while(j * j <= p):
if(p % j == 0):
f = 0
break
j = j + 1
if(f == 1):
primes += p
return primes
def _main():
x = ord(sys.argv[1])
n, e, d = keygen(25, 100)
encrypted = encrypt(x, n, e)
stdio.writef('encrypt(%c) = %d\n', x, encrypted)
decrypted = decrypt(encrypted, n, d)
stdio.writef('decrypt(%d) = %c\n', encrypted, decrypted)
width = bitLength(x)
stdio.writef('bitLength(%d) = %d\n', x, width)
xBinary = dec2bin(x, width)
stdio.writef('dec2bin(%d) = %s\n', x, xBinary)
stdio.writef('bin2dec(%s) = %d\n', xBinary, bin2dec(xBinary))
if __name__ == '__main__':
_main()
The problem is this expression:primes += p
You can use that operator, but it works like this:
[1,2,3,4] = [1,2,3,4] + x
Now x has to be a list so that this expression works. It just concatenates to lists together.
You are trying to append an int to a list, which is illegal. You can append a list to a list. Try doing primes += [p] or primes.append(p).

Python Linear Diophantine Equation

I am doing the homework for class and I was doing some research. I found the example equation for finding the diophantine equation.
The assignment is given when there is gcd(a, b) == 1, then there is a diophantine equation where
ax + by = 1.
I understood how this equation finds the value for x and y but I am not sure how this function is working. I got the part where there is divmod and recursive method inside the function, but I do not know when does it stop.
sorry for complex and ambiguous questions, but I wanna know how this equation works. I mean, how this equation ends.
For example, when there is given number 43 and 486 then gcd(43, 486) == 1.
That mean there's a equation where 43x + 486y = 1. the solution said 43(-113) + 486(10) = 1. And the function solve got the x and y value as well.
I was trying to follow through the code and see how it process, but I do not understand else: part.
def isolve(a, b):
quotient, remainder = divmod(a, b)
if remainder == 0:
return [0, 1 / b]
else:
sol = isolve(b, remainder)
x = sol[0]
y = sol[1]
return [y, x - quotient * y]
I am not sure I understand exactly what you are after, but let's consider the following modified code:
def simple_linear_diophantine_r(a, b):
q, r = divmod(a, b)
if r == 0:
return (0, b)
else:
x, y = simple_linear_diophantine_r(b, r)
return (y, x - q * y)
a, b = 43, 486
x, y = simple_linear_diophantine_r(a, b)
print(f'({a}) * ({x}) + ({b}) * ({y}) == {a * x + b * y}')
# (43) * (-113) + (486) * (10) == 1
which works as expected. Compared to the original code, I have rewritten the math in a way that only int-safe operations are used (no float division is used).
Additionally, I have renamed the function itself and some of the internal variables.
So far, this is more or less what you knew already.
Now, one way to understand what is happening is to use a Python's debugger.
A simpler to illustrate approach is to place some print() calls in strategic places:
def simple_linear_diophantine_r(a, b):
q, r = divmod(a, b)
print(f'a={a}, b={b}, q={q}, r={r}') # DEBUG
if r == 0:
return (0, b)
else:
x, y = simple_linear_diophantine_r(b, r)
print(f'x={x}, y={y}') # DEBUG
return (y, x - q * y)
a, b = 43, 486
x, y = simple_linear_diophantine_r(a, b)
print(f'(a={a}) * (x={x}) + (b={b}) * (y={y}) == {a * x + b * y}')
# a=43, b=486, q=0, r=43
# a=486, b=43, q=11, r=13
# a=43, b=13, q=3, r=4
# a=13, b=4, q=3, r=1
# a=4, b=1, q=4, r=0
# x=0, y=1, q=3
# x=1, y=-3, q=3
# x=-3, y=10, q=11
# x=10, y=-113, q=0
# -113 10
# (a=43) * (x=-113) + (b=486) * (y=10) == 1
and now you can more easily follow what is happening at each function call.
The same result can be obtained with an iterative function:
def simple_linear_diophantine_i(a, b, debug=False):
qs = []
while True:
q, r = divmod(a, b)
if debug:
print(f'a={a}, b={b}, q={q}, r={r}')
a = b
b = r
if r != 0:
qs.append(q)
else:
break
x, y = b, a
for q in qs[::-1]:
if debug:
print(f'x={x}, y={y}, q={q}')
x, y = y, x - q * y
return x, y
a, b = 43, 486
x, y = simple_linear_diophantine_i(a, b, True)
print(x, y)
# a=43, b=486, q=0, r=43
# a=486, b=43, q=11, r=13
# a=43, b=13, q=3, r=4
# a=13, b=4, q=3, r=1
# a=4, b=1, q=4, r=0
# x=0, y=1, q=3
# x=1, y=-3, q=3
# x=-3, y=10, q=11
# x=10, y=-113, q=0
# (a=43) * (x=-113) + (b=486) * (y=10) == 1
with somewhat similar timing:
a = 123464357645765475246432152143432154321543256432654367547658641353276548767132465498760908567542543215
b = 65432654786531234532634712432
funcs = simple_linear_diophantine_r, simple_linear_diophantine_i
base = funcs[0](a, b)
print(base)
# (-14645224987639174972552062305, 27633958939547408859252562549330013276609719423270432707256961858787144635978588031424076994432005543)
for func in funcs:
res = func(a, b)
is_good = base == res
timed = %timeit -n 128 -r 128 -oq func(a, b)
timing = timed.best * 1e6
print(f"{func.__name__:>24} {is_good} {timing:10.3f} µs")
# simple_linear_diophantine_r True 25.855 µs
# simple_linear_diophantine_i True 22.439 µs
I also wrote a Linear Diophantine program that has stats and is faster than egcd python programs iv'e used so wanted to include it here for others interested in programs that solve these:
def llinear_diophantinex(a, b, divmodx=1, x=1, y=0, withstats=False):
origa, origb = a, b
r=a
q = a//b
prevq=1
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}")
while r != 0:
prevr = r
a,r,b = b, b, r
q,r = divmod(a,b)
x, y = y, x - q * y
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}, x = {x}, y = {y}")
y = 1 - origb*x // origa - 1
x,y=y,x
modx = (-abs(x)*divmodx)%origb
if withstats == True:
print(f"x = {x}, y = {y}, modx = {modx}")
return x, y, modx
In [5410]: llinear_diophantinex(272,1009, withstats=True)
a = 272, b = 1009, q = 0, r = 272
a = 1009, b = 272, q = 3, r = 193, x = 0, y = 1
a = 272, b = 193, q = 1, r = 79, x = 1, y = -1
a = 193, b = 79, q = 2, r = 35, x = -1, y = 3
a = 79, b = 35, q = 2, r = 9, x = 3, y = -7
a = 35, b = 9, q = 3, r = 8, x = -7, y = 24
a = 9, b = 8, q = 1, r = 1, x = 24, y = -31
a = 8, b = 1, q = 8, r = 0, x = -31, y = 272
x = 115, y = -31, modx = 894
Out[5410]: (115, -31, 894)

Sending a Polynomial to PARI/GP from Python (ctypes)

I would like to call nfroots({nf}; x) function of PARI/GP from Python. (see function no 3.13.135.on page 371 in this link:), but the probllem is, I couldn't send the algebraic expression or the polynomial, that need to be send, for example, x^2-7x+12, here is a very simple example of what gp can do with a quartic polynomial:
> V = readvec("coeff.txt");
> print(V)
[1,-7,12]
> P = Pol(V); # I get following error when I use Pol in my code: func=self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'pol' not found
> print(P)
x^2 -7*x +12
> print(nfroots(,P))
>4, 3
From the answer of Stephan Schlecht (click here), I manage to write -
from ctypes import *
pari = cdll.LoadLibrary("C:\\Program Files\\Pari64-2-11-3\\libpari.dll")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.nfroots.restype = POINTER(POINTER(c_long))
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(10)) #t_POL = 10,
for i in range(1, l):
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def main():
h = "x^2-7x+12"
res = pari.nfroots(t_vec(h))
for i in range(1, len(res)):
print(pari.itos(res[i]))
if __name__ == '__main__':
main()
Note that there is specific process to create of PARI objects (see the answer of Stephan Schlecht), I changed the value for t_POL = 10 , but the code didn't work, How can I execute the above PARI/GP code from python?
One solution could be:
use gtopoly, return type is POINTER(c_long)
return type of nfroots is POINTER(POINTER(c_long))
output of result with .pari_printf
Code
from ctypes import *
pari = cdll.LoadLibrary("libpari.so")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
precision = c_long(38)
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def main():
V = (1, -7, 12)
P = pari.gtopoly(t_vec(V), c_long(-1))
res = pari.nfroots(None, P)
pari.pari_printf(bytes("%Ps\n", "utf8"), res)
if __name__ == '__main__':
main()
Test
If you run the program you get the desired output in the debug console:
[3, 4]
Conversions
With glength one can determine the length of a vector, see
https://pari.math.u-bordeaux.fr/dochtml/html/Conversions_and_similar_elementary_functions_or_commands.html#length
With itos a long can be returned if the parameter is of type t_INT, see section 4.4.6 of https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf.
In code it would look like this:
pari.glength.restype = c_long
pari.itos.restype = c_long
...
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
print(pari.itos(res[i]))
To GENtostr gives a string representation of the argument. It could be used like so:
pari.GENtostr.restype = c_char_p
...
print("elements as generic strings: ")
for i in range(1, pari.glength(res) + 1):
print(pari.GENtostr(res[i]).decode("utf-8"))
There are many more conversion options, see the two links above.

Categories

Resources