#!/usr/bin/ruby # coding: utf-8 ##################################### # # Marcin Woźniak # s434812 # ##################################### require 'openssl' require 'securerandom' require 'prime' require 'thread' require 'thwait' #################################### # Funkcja nwd(a,b) # # Oblicza nwd podanych liczb np # nwd(10,14) => 2 # #################################### def nwd(a, b) if a == 0 return false end b == 0 ? a : nwd(b, a.modulo(b)) end #################################### # Funkcja extended_euklides(a,b) # # Oblicza rozszerzony algorytm euklidesa # zwracajac u,v # extended_euklides(10,14) => [3, -2] # ##################################### def extended_euklides(a, b) return 1, 0 if b == 0 q, r = a.divmod b s, t = extended_euklides(b, r) return t, s - q * t end #################################### # Funkcja random_gen_Zn(k,n) # # Oblicza losowy element z zbioru Z_n # random_gen_Zn(1,10) => 1 # #################################### def random_gen_Zn(k,n) if n == 0 n = 2 ** k end if k == 1 max = 1 else kb = k.to_s(2) minimum = [] minimum << 1 k = kb.length - 1 while (k != 0) do j = SecureRandom.random_number(2) minimum << j k = k - 1 end min = minimum.join.to_i(2) max = n - 1 if min < max return SecureRandom.random_number(min..max) end end end #################################### # Funkcja reciprocal_Phi_p(n,p) # # Oblicza odwrotnosc w grupie Phi(n) # reciprocal_Phi_p(10,7) => 5 # # Funkcja oblicza 10^(-1) mod 7 = 5 # Dowód: 5 * 10 mod 7 = 1 # a^(-1) * a mod p = e = 1 #################################### def reciprocal_Phi_p(n,p) u = extended_euklides(n,p)[0] v = extended_euklides(n,p)[1] if (u * n % p) == 1 if u < 0 return u + p end return u else if v < 0 return v + p end return v end end #################################### # Funkcja betterExponentiation(x,k,n) # # Oblicza potęgi x^k mod n # betterExponentiation(8,2,30) => 4 # #################################### def betterExponentiation(x,k,n) if n == 0 return false end if x == 0 return 0 end if x < n && x > 0 b = k.to_s(2).reverse l = b.count "[0-1]" y = 1 i = l - 1 while i >= 0 y = y**2 % n if b[i]=="1" y = y * x % n end i = i - 1 end return y end end #################################### # Funkcja remSqEuler(a,b) # # Sprawdzenie czy element a jest # reszta kwadratowa w Z_p # remSqEuler(3,13) => true # #################################### def remSqEuler(a,p) ans = betterExponentiation(a,(p-1)/2,p) if ans == 1 && primalityTest(p) return true else return false end end #################################### # Funkcja squareRootFp(a,b) # #################################### def squareRootFp(p,b) if p % 4 == 3 && remSqEuler(p,b) == true a = betterExponentiation(b, (p+1)/4, p) return a end end #################################### # Funkcja primalityTest(n) # # Test pierwszości # primalityTest(13) => true # #################################### def primalityTest(n) if n == 1 return false end if n == 2 || n == 3 return true end counter = 10 while (counter != 0) do b = SecureRandom.random_number(2..n-2) # Tez dziala n-1 if betterExponentiation(b,n-1,n) != 1 return false end counter = counter - 1 end return true end #################################### # Funkcja specyficPrimaryNumber # # Generuje potrzebne do pierwszego # ElGamala ##################################### def specyficPrimaryNumber p = 0 q = 0 qThread = Thread.new { while true q = SecureRandom.random_number(2 ** 256) if primalityTest(q) break end end } qThread.join while true do q = SecureRandom.random_number(2 ** 256) p = 2 * q + 1 if primalityTest(p) return p,q end end end #################################### # Funkcja generator(a,b) # # Generuje generator dla podanych liczb # do RSA i ElGamala # #################################### def generator(p,q) while true g = SecureRandom.random_number(2..p-2) if betterExponentiation(g,q,p) == 1 next else return g end end end #################################### # Funkcja generate(n) # # Generator liczby losowej o podanej # n-bitowej liczbie # #################################### def generate(n) return `openssl prime -generate -bits '#{n}'`.gsub(/\n$/, '').to_i end #### MODULE 2 #### #################################### # Funkcja returnRownanie(a,b,p) # # Zwraca ładniejszą formę równania # #################################### def returnRownanie(a,b,p) puts puts "Równanie krzywej jest równe: " + "Y^2 = X^3+" + a.inspect + "X+" + b.inspect + " mod "+ p.inspect puts end #################################### # Funkcja delta(a,b,p) # # Oblicza deltę dla krzywej # eliptycznej o podanych parametrach # a,b nad ciałem F_p # #################################### def delta(a,b,p) d = ((4 * betterExponentiation(a,3,p) % p) + (27 * betterExponentiation(b,2,p) % p)) % p return d end #################################### # Funkcja rownanieKrzywej(a,b,p,x) # # Oblicza wartość fx dla podanej # krzywej eliptycznej o podanych # parametrach a,b,p,x # #################################### def rownanieKrzywej(a,b,p,x) fx = ((betterExponentiation(x,3,p) + (a * x) % p + b % p) % p) % p return fx end #################################### # Funkcja generatorKrzywej(p) # # Generuje krzywą o podanej liczbie # pierwszej p. # #################################### def generatorKrzywej(p) a = 0 b = 0 while true if primalityTest(p) && (p % 4 == 3) threads = [] threads << Thread.new { a = SecureRandom.random_number(1..p-1) } threads << Thread.new { b = SecureRandom.random_number(1..p-1) } ThreadsWait.all_waits(*threads) if delta(a,b,p) != 0 #returnRownanie(a,b,p) return a,b end else puts "Liczba nie spełnia wymagań" break end end end #################################### # Funkcja punktNaKrzywej(a,b,p) # # Zwraca losowy punkt na krzywej # eliptycznej o podanych wartościach # a,p,p. # #################################### def punktNaKrzywej(a,b,p) if (delta(a,b,p) != 0) && (p % 4 == 3) while true x = SecureRandom.random_number(0..p-1) fx = rownanieKrzywej(a,b,p,x) if remSqEuler(fx,p) y = betterExponentiation(fx,((p+1)/4),p) return x,y end end end end #################################### # Funkcja czyPunktNalezyDoKrzywej(a,b,p,x,y) # # Sprawdza czy podany punkt nalezy # do krzywej eliptycznej. # #################################### def czyPunktNalezyDoKrzywej(a,b,p,x,y) fx = rownanieKrzywej(a,b,p,x) if fx == betterExponentiation(y,2,p) return true else return false end end #################################### # Funkcja punktPrzeciwny(x,y) # # Zwraca przeciwny punkt dla (x,y) # #################################### def punktPrzeciwny(x,y) return x,-y end #################################### # Funkcja sumaPunktow(a,b,p,x1,y1,x2,y2) # # Oblicza sumę punktów na krzywej # eliptycznej dla podanych a,b,p,x1,y1,x2,y2 # #################################### def sumaPunktow(a,b,p,x1,y1,x2,y2) # 0 - element neutrany --> P + 0 = P if (x1 == "e" && y1 == "e" ) return x2,y2 elsif (x2 == "e" && y2 == "e") return x1,y1 end # P + Q = R if (x1 != x2) lambda = (((y2 - y1) % p) * reciprocal_Phi_p((x2 - x1),p)) % p x3 = (betterExponentiation(lambda,2,p) - (x1 % p) - (x2 % p)) % p y3 = (lambda * (x1 - x3) - y1) % p return x3,y3 end # P + -Q = 0 DZIALA if (x1 == x2) && (y1 == -y2) #puts "0 - el.neutralny" return "e","e" end # P + P = 2P DZIALA if (x1 == x2) && (y1 == y2) lambda = (((3 * betterExponentiation(x1,2,p) % p + a) % p) * reciprocal_Phi_p(2 * y1,p)) % p x3 = (betterExponentiation(lambda,2,p) - (x1 % p) - (x2 % p)) % p y3 = (lambda * (x1 - x3) - y1) % p return x3,y3 end end #### MODULE 3 #### #################################### # Funkcja wielokrotnoscPunktu(a,b,p,n,x,y) # # Oblicza wielokrotność punktów np. # 2n = n + n #################################### def wielokrotnoscPunktu(a,b,p,n,x,y) punktQ = [x,y] punktR = ["e","e"] while n > 0 if n % 2 == 1 punktR = sumaPunktow(a,b,p,punktR[0],punktR[1],punktQ[0],punktQ[1]) n = n - 1 end punktQ = sumaPunktow(a,b,p,punktQ[0],punktQ[1],punktQ[0],punktQ[1]) n = n / 2 end return punktR end #################################### # Funkcja liczenieOrd(a,b,p) # # Oblicza wartość ord dla podanych # a,b,p. #################################### def liczenieOrd(a,b,p) threads = [] punktyNaKrzywej = Array.new unikalnePunktyNaKrzywej = Array.new threads << Thread.new { counter = 10 while counter > 0 punktyNaKrzywej << punktNaKrzywej(a,b,p)[0] counter = counter -1 end } threads << Thread.new { counter = 10 while counter > 0 punktyNaKrzywej << punktNaKrzywej(a,b,p)[0] counter = counter -1 end } threads << Thread.new { counter = 10 while counter > 0 punktyNaKrzywej << punktNaKrzywej(a,b,p)[0] counter = counter -1 end } ThreadsWait.all_waits(*threads) punktyNaKrzywej.sort.each { |e| unikalnePunktyNaKrzywej.push(e) if e != unikalnePunktyNaKrzywej[-1] } return unikalnePunktyNaKrzywej.count end #################################### # Funkcja generowanieKluczyElGamalKrzywaEliptyczna(k) # # Generatoruje klucz publiczny # oraz prywatny. #################################### def generowanieKluczyElGamalKrzywaEliptyczna(k) while true p = generate(k) if (primalityTest(p)) && (p % 4 == 3) krzywa = generatorKrzywej(p) a = krzywa[0].to_i b = krzywa[1].to_i punktyNaKrzywej = Array.new punktP = punktNaKrzywej(a,b,p) ord = liczenieOrd(a,b,p) while true x = SecureRandom.random_number(1..ord) if x < ord punktQ = wielokrotnoscPunktu(a,b,p,x,punktP[0],punktP[1]) pubKey = [a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1]] privKey = [a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1],x] return a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1],x end end end end end #################################### # Funkcja algorytmKodowania(a,b,p,m,n,u) # #################################### def algorytmKodowania(a,b,p,m,n,u) if (m < n) && (p > n*u) for i in 1..u x = (m * u % p) + (i % p) fx = rownanieKrzywej(a,b,p,x) if remSqEuler(fx,p) y = betterExponentiation(fx,((p+1)/4),p) end end else puts "Nieprawidołowe dane" end return [x,y] end #################################### # Funkcja algorytmDeKodowania(a,b,p,x,y,n,u) # # Zwraca odszyfrowaną wiadomość. #################################### def algorytmDeKodowania(a,b,p,x,y,n,u) m = (x - 1) / u return m end #################################### # Funkcja szyfrowanieElGamala(m,n,u,a,b,p,px,py,qx,qy) # # Koduje wiadomość na punkt na krzywej # eliptycznej. #################################### def szyfrowanieElGamala(m,n,u,a,b,p,px,py,qx,qy) c = algorytmKodowania(a,b,p,m,n,u) puts "Wiadomość na prostej jako punkt #{c.inspect}" return c end