Using Ruby in CS465

advertisement
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
Download