mirror of
https://github.com/TheAlgorithms/Ruby
synced 2024-12-29 22:24:07 +01:00
71 lines
1.3 KiB
Ruby
Executable file
71 lines
1.3 KiB
Ruby
Executable file
require 'openssl'
|
|
|
|
class MerkleHellman
|
|
SMALLEST_KNAPSACK_ITEM = 2**32
|
|
STEP = 2**32
|
|
|
|
def initialize(size)
|
|
@size = size
|
|
sum = SMALLEST_KNAPSACK_ITEM
|
|
@easy_knapsack = size.times.map do |_k|
|
|
x = sum + rand(STEP)
|
|
sum += x
|
|
x
|
|
end
|
|
@n = sum + rand(STEP)
|
|
|
|
loop do
|
|
@a = rand(0..@n)
|
|
break if @a.gcd(@n) == 1
|
|
end
|
|
|
|
@hard_knapsack = @easy_knapsack.map do |x|
|
|
(@a * x) % @n
|
|
end
|
|
end
|
|
|
|
def encrypt(msg)
|
|
raise ArgumentError, "max length is #{@size / 8} characters" if msg.length * 8 > @size
|
|
|
|
c = 0
|
|
msg.each_codepoint.reverse_each.with_index do |ch, i|
|
|
7.downto(0) do |j|
|
|
wj = ch.>>(j).& 1
|
|
c += wj * @hard_knapsack[i * 8 + 7 - j]
|
|
end
|
|
end
|
|
c
|
|
end
|
|
|
|
def decrypt(c)
|
|
p = @a.to_bn.mod_inverse(@n).mod_mul(c, @n).to_i
|
|
byte = 0
|
|
msg = []
|
|
@easy_knapsack.reverse_each.with_index do |x, i|
|
|
bit = 0
|
|
if p >= x
|
|
p -= x
|
|
bit = 1
|
|
end
|
|
byte |= (bit << (i % 8))
|
|
if i % 8 == 7
|
|
msg << byte.chr
|
|
byte = 0
|
|
end
|
|
end
|
|
msg.join
|
|
end
|
|
attr_accessor :hard_knapsack
|
|
end
|
|
|
|
str = 'Hello there, this is my plaintext'
|
|
mh = MerkleHellman.new(str.length * 8)
|
|
puts "[*] Encrypting \"#{str}\""
|
|
|
|
c = mh.encrypt(str)
|
|
|
|
puts "[*] Ciphertext : #{c}"
|
|
|
|
decrypted = mh.decrypt(c)
|
|
|
|
puts "[*] after decryption : \"#{decrypted}\""
|