W związku z zajęciami z kryptografii, potrzebowałem mieć pod ręką trochę narzędzi umożliwiających obliczenie fi (funkcji Eulera), odwrotności modulo, rozkładu liczby na czynniki pierwsze, wyznaczanie odwrotności modulo macierzy 2x2 oraz mnożenie macierzy 2x2 razy 1x2 oraz obliczenia modulo z duuuuuużych liczb przedstawionych jako potęg. Dlatego też powstał kod działający na Androidzie. Jedyne wymaganie to Ruboto - do znalezienia na Markecie. Jest to JRuby dla Androida, umożliwiający odpalanie prostych skryptów na telefonie. Idealne kiedy trzeba napisać coś na szybko. Zaczniemy od potęgowania. Spróbuj dokonać takiego obliczenia modulo: 12345^12345 mod126 w kalkulatorze na Windows. Chyba się nie udało ;) A ten oto poniższy kod, świetnie sobie z tym radzi:
liczba = 12345 power = 12345 n = 126 #-------------------------------------- def mod(liczba, power, n) val = 1 power.times do |i| val *= liczba val %= n end val end puts "#{liczba}^#{power}(mod#{n})= #{mod(liczba, power, n)}"
A wynikiem jest: 99 Następnie mamy funkcję Eulera (fi):
liczba = 30 #-------------------------------------- def phi(m) r = (2..m) primes = r.inject(r){|p, i| p.select{|n| n==i || n%i!=0}} primes.inject(m){|e, p| e%p==0 ? e/p*(p-1) : e} end puts "fi dla #{liczba} wynosi: #{phi(liczba)}"
Która też działa niczego sobie :) - oczywiście to obliczenie dla zbyt dużych liczb na telefonie komórkowym nie będzie przebiegać zbyt szybko, więc używajcie z rozwagą ;) Kolejnym kawałkiem kodu jest kod obliczający odwrotność zadanej liczby w sensie modulo:
liczba = 315 n = 676 #-------------------------------------- class Integer def to_ba(size=128) a=[] (size-1).downto(0) do |i| a<<< 2**index } val = 1 powers.each { |pow| pow.times do |i| val *= liczba val %= n end } val end def check(liczba, odw, n) (liczba*odw)%n == 1 end odw = odwrotnosc(liczba, n) if odw == 0 puts "Odwrotnosc nie istnieje NWD(#{liczba}, #{n}) != 1" else if check(liczba, odw, n) puts "#{liczba}^-1 (mod#{n})= #{odw}" else puts "NWD(#{liczba}, #{n}) != 1" end end
Rozkład liczby na czynniki pierwsze:
liczba = 2 # ----------------------------------------------------------------------------- def factorize(orig) factors = {} factors.default = 0 n = orig i = 2 sqi = 4 while sqi <= n do while n.modulo(i) == 0 do n /= i factors[i] += 1 end sqi += 2 * i + 1 i += 1 end if (n != 1) && (n != orig) factors[n] += 1 end factors end def printfactorhash(orig, factorcount) print format("%-10d ", orig) if factorcount.length == 0 print "Liczba pierwsza" else factorcount.sort.each { |factor,exponent| print factor if exponent > 1 print "^", exponent end print " " } end puts end n = liczba.to_i mfactors = factorize(n) printfactorhash(n, mfactors)
Odwrotność macierzy (w sensie modulo):
MATRIX = [[0,11], [17,0]] #[a, b] #[c, d] n = 29 #-------------------------------------- class Integer def to_ba(size=128) a=[] (size-1).downto(0) do |i| a<<self[i] end a end end def phi(m) r = (2..m) primes = r.inject(r){|p, i| p.select{|n| n==i || n%i!=0}} primes.inject(m){|e, p| e%p==0 ? e/p*(p-1) : e} end def odwrotnosc(liczba, n) fi = phi(n) powers = [] (fi-1).to_ba.reverse.each_with_index { |b, index| next if b == 0 powers << 2**index } val = 1 powers.each { |pow| pow.times do |i| val *= liczba val %= n end } val end def nwd(a,b) if a > b then a -= b else b -= a end while a != b; return a end def det(m) m[0][0].to_i*m[1][1].to_i-m[0][1].to_i*m[1][0].to_i end def inverse(m, n) det = det(m) det = det%n if nwd(det, n) != 1 puts "NWD(m, n) != 1" exit end puts "det= #{det}" odw_a = odwrotnosc(det, n) puts "det^-1mod(#{n})= #{odw_a}" w = [] w << [odw_a*m[1][1]%n, -odw_a*m[0][1]%n ] w << [-odw_a*m[1][0]%n, odw_a*m[0][0]%n ] w end def print_res(w) puts "[#{w[0][0]}, #{w[0][1]}]" puts "[#{w[1][0]}, #{w[1][1]}]" end print_res(inverse(MATRIX, n))
Mnożenie macierzy 2x2 przez 1x2 (w sensie modulo n)
MATRIX1 = [ [21,19], [22,18]] MATRIX2 = [15, 24] n = 29 def multiply(m1, m2, n) w = [(m1[0][0]*m2[0]+m1[0][1]*m2[1])%n, (m1[1][0]*m2[0]+m1[1][1]*m2[1])%n ] end def print_res(res) puts "[ #{res[0]}, #{res[1]}]" end print_res(multiply(MATRIX1, MATRIX2, n))
Podsumowując: powyżej zamieściłem kod który wykonuje następujące czynności:
- Obliczanie modulo dużych liczb przedstawionych w postaci potęg
- Funkcja Eulera - algorytm obliczenia wartości funkcji fi
- Obliczanie odwrotności liczby w sensie modulo
- Rozkład liczby na czynniki pierwsze
Mam nadzieję że się przyda :) A tutaj: źródełko