diff --git a/hw3.py b/hw3.py new file mode 100644 index 0000000..3fc464c --- /dev/null +++ b/hw3.py @@ -0,0 +1,173 @@ +from sys import argv +from fractions import gcd + +class Polynomial(): + def __init__(self, lst, mod): + self.poly = list(map(lambda x: x % mod, lst)) + self.mod = mod + self.normalize() + def normalize(self): + while self.poly and self.poly[-1] == 0: + self.poly.pop() + + #zwraca jednomian stopnia n + @staticmethod + def Monomial(n, c, mod): + zeros = [0]*n + zeros.append(c) + return Polynomial(zeros, mod) + + def __add__(self, p2): + p1 = self + len_p1, len_p2= len(p1.poly), len(p2.poly) + res = [0] * max(len_p1, len_p2) + if len_p1 > len_p2: + for _ in range(len_p1-len_p2): + p2.poly.append(0) + else: + for _ in range(len_p2-len_p1): + p1.poly.append(0) + + for i in range(len(res)): + res[i] = (p1.poly[i] + p2.poly[i]) % self.mod + return Polynomial(res, self.mod) + + def __sub__(self, p2): + p1 = self + res = [] + len_p2 = len(p2.poly) + for i in range(len(p1.poly)): + if i < len_p2: + res.append(p1.poly[i] - p2.poly[i] % self.mod) + else: + res.append(p1.poly[i]) + return Polynomial(res, self.mod) + + def __mul__(self, p2): + res = [0]*(len(self.poly)+len(p2.poly)-1) + for i, x1 in enumerate(self.poly): + for j, x2 in enumerate(p2.poly): + res[i+j] += x1 * x2 % self.mod + return Polynomial(res, self.mod) + + def __truediv__(self, p2): + p1 = self + m = self.mod + + if len(p1.poly) < len(p2.poly): + return p1 + + if len(p2.poly) == 0: + raise ZeroDivisionError + + divisor_coeff = p2.poly[-1] + divisor_exp = len(p2.poly) - 1 + while len(p1.poly) >= len(p2.poly): + max_coeff_p1 = p1.poly[-1] #wspolczynnik przy najwyzszej potedze + try: + tmp_coeff = modDiv(max_coeff_p1, divisor_coeff, m) + except ZeroDivisionError as e: + raise e + + tmp_exp = len(p1.poly)-1 - divisor_exp + tmp = [0] * tmp_exp + tmp.append(tmp_coeff) + sub = Polynomial(tmp, m) * p2 + p1 = p1 - sub + p1.normalize() + return Polynomial(p1.poly, m) + +def modDiv(a, b, m): # a*b^-1 (mod m) + if gcd(b, m) != 1: + raise ZeroDivisionError + else: + return (a * modinv(b, m)) % m +#rozszerzony algorytm euklidesa +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) + return x % m +#lista stringow binarnych -> lista intow 0/1 +def bin_str_to_list(lst): + res = [] + for elem in lst: + for ch in elem: + res.append(int(ch)) + return res + +def mod8format(lst): + while len(lst) % 8 != 0: + lst.append(0) + return lst + +def to_bin(x): + data = bin(ord(x)).replace('b', '') + while len(data) != 8: + if len(data) < 8: + data = str(0) + data + else: + data.replace(data[0], '') + return data + +def to_ascii_val(lst): + sum = 0 + for i in range(len(lst)): + if lst[i] == 1: + sum += 2**(7-i) + return chr(sum) + +def data(): + p = bin_str_to_list(list(map(lambda x: to_bin(x), m))) + p.reverse() + Lx = Polynomial([1] * 16, 2) #L(x) + X16 = Polynomial.Monomial(16, 1, 2) #X^16 + Gx = Polynomial([1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1], 2) #G(x) + return (p, Lx, X16, Gx) + +def fcs(m): + p, Lx, X16, Gx = data() + Mx = Polynomial(p, 2) #M(x) #X^16 + Xnsub16 = Polynomial.Monomial(len(m)*8, 1, 2) #X^(n-16) + rhs = Xnsub16 * Lx + lhs = X16 * Mx + xor = lhs + rhs + fcs = xor/Gx + #algorytm dzielenia ucina zera, trzeba dopelnic do 16 bitow + for i in range(16 - len(fcs.poly)): + fcs.poly.append(0) + fcs.poly.reverse() + return fcs.poly + +def check(m): + p, Lx, X16, Gx = data() + Xn = Polynomial.Monomial(len(p), 1, 2) #X^n + Cx = Polynomial(p, 2) + Cx = X16 * Cx + Cx.poly = mod8format(Cx.poly) + Sx = (Cx + Xn * Lx) / Gx + if Sx.poly == []: + return True + return False + +def main(): + global m + m = list(argv[1]) + mode = argv[2] # flagi -e -d (encode, decode) + if mode == '-e': + res = fcs(m) + fcs_ch1 = to_ascii_val(res[:8]) + fcs_ch2 = to_ascii_val(res[8:]) + m.append(fcs_ch1) + m.append(fcs_ch2) + print(''.join(m)) + elif mode == '-d': + print(check(m)) + +if __name__ == '__main__': + main() \ No newline at end of file