1 Using Ruby in CS465 By Harshwardhan Nagaonkar, Devlin Daley and the BYU Ruby Users Group 2 Using Ruby in CS465 ......................................................................................................... 1 Ruby Conventions Used in the Following Examples ..................................................... 3 Modular Exponentiation ................................................................................................. 3 Generating Random Numbers......................................................................................... 4 Generating Random Prime Numbers .............................................................................. 5 Extended Euclidean Algorithm ....................................................................................... 6 3 Here are some code samples that detail performing basic tasks in Ruby. They are all pure Ruby methods of doing certain library tasks in the CS465 labs. There exist ways to accomplish them using external Ruby bindings, but these examples do not use them to guarantee portability between Ruby installations. Ruby Conventions Used in the Following Examples Some things to remember about Ruby that are used in the following examples: The last expression in a block or function is the value(s) that is(are) returned from that block or function. It is possible to return more than one value (look at the Euclidean section for this property in action). Bignums are built-in data types in Ruby. Once a number exceeds the normal size limits, it is automatically converted to a BigNum (and when BigNums are small enough, Ruby converts them back to regular size FixNums). Modular Exponentiation Here is one way to perform modular exponentiation in Ruby: def modpow(number, exponent, modulus) result = 1 while (exponent > 0) if ((exponent & 1) > 0) result = (result * number) % modulus; end exponent >>= 1; number = (number * number) % modulus; end result end 4 Sockets It is easy to send the parameters to the TA server automatically in Ruby using sockets. Here is a code example. require 'net/telnet' sendthis = "p (passoff) : \n" << prime.to_s << "\ng^s%p: \n" << publickey.to_s puts sendthis server = Net::Telnet.new('Host' => 'ta-14.cs.byu.edu', 'Port' => 1337, 'Timeout' => 15, 'Telnetmode' => false) result = server.cmd(sendthis) puts result #By splitting on newlines, we can separate the parts of the server output, including the #server’s public key and the encrypted text itself. #For example, array[0] is the string “g^t%p:” array = result.split(/\n/) puts "--------------------------------------------------" server_publickey = array[1] puts "Server's public key is: " << server_publickey #puts OpenSSL::BN.methods #This is secret = (server_publickey ^ random) % prime secret = modpow(server_publickey.to_i, random, prime) puts "secret is ----------------" << secret.to_s << "----------------" Generating Random Numbers You can use the OpenSSL library to generate prime numbers. However, the Ruby bindings for OpenSSL are not very well documented. Here is a way to generate random numbers in pure ruby using Linux’s /dev/urandom facility. # The string contains random bytes read from urandom # we unpack it using "H*". This directive puts all the bytes into a hex string # we call “first” because unpack returns an array of one and we only want the 1st element # then we convert the hex string into a number with to_i with base 16(hex) def get_random(bytelength=64) File.open("/dev/urandom","r").read(bytelength).unpack("H*").first.to_i(16) end 5 Generating Random Prime Numbers We just modify the code for generating random numbers so that it checks using Fermat’s Primality test that a given random number is prime or not. # use /dev/urandom to get a random number def get_prime(bytelength=64) File.open("/dev/urandom","r") do |file| number = string_to_num(file.read(bytelength)) until prime?(number) do number = string_to_num(file.read(bytelength)) end number end end # The string contains random bytes read from urandom # we unpack it using "H*" which puts all the bytes into a hex string # we call first because unpack returns an array of one # then we convert the hex string into a number with to_i with base 16(hex) def string_to_num(str="") str.unpack("H*").first.to_i(16) end # Primality is determined by Fermat's primality test using witnesses. #A number p is relatively prime to number w if and only if the expression # “w^(p-1)%p = 1” is true #Ruby has a method ‘inject’ for carrying an accumulated value through a block which is #applied to every element of the block (in this case, the “true” of the primality test for the #witnesses 2,3,5 and 7 def prime?(p) [2,3,5,7].inject(true){ |is_prime,w| is_prime && (modpow(w,p-1,p)==1) } end 6 Extended Euclidean Algorithm We used a recursive function found in Foundations of Algorithms, Using Java Pseudocode by Richard Neapolitan and Kumarss Naimipour. Here is a table that helps to visualize the algorithm. Call N m gcd i j 0 1 2 3 42 30 12 6 30 12 6 0 6 6 6 6 -2 1 0 1 3 -2 1 0 The values determined by the Algorithm when n=42 and m=30. The top level is labeled 0; the three recursive calls are labeled 1—3. The arrows show the order in which the values are determined. Note that Ruby allows for multiple variables to be returned from a function. This makes the extended Euclidean algorithm be much easier than in other languages because it parallels the way that you think about it. # The extended euclidean algorithm returns i,j,gcd for numbers n,m # where in + jm =1 # and gcd is the greatest common denominator between n and m def extended_euclidean(n,m) return 1,0,n if m==0 i,j,gcd = extended_euclidean(m,n%m) i,j,gcd = j, i-((n/m)*j), gcd end