require 'openssl' 
require 'prime'

def rsa_encode blocks, e, n
  blocks.map{|b| b.to_bn.mod_exp(e, n).to_i}
end

def rsa_decode ciphers, d, n
  rsa_encode ciphers, d, n
end



def text_to_blocks text, blocksize=64 
  text.each_byte.reduce(){|acc,b| acc << b.to_s(16).rjust(2, )} 
      .each_char.each_slice(blocksize).to_a                          
      .map{|a| a.join().to_i(16)}                                  
end

def blocks_to_text blocks
  blocks.map{|d| d.to_s(16)}.join()                                
        .each_char.each_slice(2).to_a                                
	.map{|s| s.join().to_i(16)}                                
	.flatten.pack()                                          
	.force_encoding(Encoding::default_external)                  
end

def generate_keys p1, p2
  n = p1 * p2
  t = (p1 - 1) * (p2 - 1)
  e = 2.step.each do |i|
    break i if i.gcd(t) == 1
  end
  d = 1.step.each do |i|
    break i if (i * e) % t == 1
  end
  return e, d, n
end

p1, p2 = Prime.take(100).last(2)
public_key, private_key, modulus =
  generate_keys p1, p2

print 
message = gets
blocks = text_to_blocks message, 4 
print ; p blocks
encoded = rsa_encode(blocks, public_key, modulus)
print ; p encoded
decoded = rsa_decode(encoded, private_key, modulus)
print ; p decoded
final = blocks_to_text(decoded)
print ; puts final