Last active
December 15, 2015 21:08
-
-
Save havenwood/b39abc979402ecd1e496 to your computer and use it in GitHub Desktop.
The hash function RIPEMD-128 in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'digest' | |
require 'stringio' | |
module Digest | |
class RMD128 < Digest::Class | |
## | |
# http://homes.esat.kuleuven.be/~bosselae/ripemd/rmd128.txt | |
# | |
# RIPEMD-128 is an iterative hash function that operates on 32-bit words. | |
# The round function takes as input a 4-word chaining variable and a 16-word | |
# message block and maps this to a new chaining variable. All operations are | |
# defined on 32-bit words. Padding is identical to that of MD4. | |
MASK = (1 << 32).pred | |
private_constant :MASK | |
# RIPEMD-128: definitions | |
# nonlinear functions at bit level: exor, mux, -, mux | |
F = [ ->(x, y, z) { x ^ y ^ z }, | |
->(x, y, z) { x & y | (x ^ MASK) & z }, | |
->(x, y, z) { x | (y ^ MASK) ^ z}, | |
->(x, y, z) { x & z | y & (z ^ MASK) } | |
].freeze | |
private_constant :F | |
# added constants (hexadecimal) | |
K = [0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc].freeze | |
KK = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x00000000].freeze | |
private_constant :K, :KK | |
# selection of message word | |
R = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | |
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, | |
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, | |
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2].freeze | |
RR = [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, | |
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, | |
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, | |
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14].freeze | |
private_constant :R, :RR | |
# amount for rotate left (rol) | |
S = [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, | |
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, | |
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, | |
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12].freeze | |
SS = [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, | |
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, | |
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, | |
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8].freeze | |
private_constant :S, :SS | |
# initial value (hexadecimal) | |
WORDS = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476].freeze | |
private_constant :WORDS | |
def initialize | |
@buffer = '' | |
end | |
def block_length | |
64 | |
end | |
def reset | |
@buffer.clear | |
self | |
end | |
def << string | |
@buffer << string | |
self | |
end | |
alias update << | |
def finish | |
string_io = StringIO.new @buffer | |
block = '' | |
term = false | |
last = false | |
until last | |
string_io.read 64, block | |
# the same padding as http://rosettacode.org/wiki/RIPEMD-160#Ruby | |
case block_size = block.size | |
when 64 | |
x = block.unpack 'V16' | |
when 56..63 | |
block << "\x80" << ("\0" * (63 - block_size)) | |
x = block.unpack 'V16' | |
term = true | |
when 0..55 | |
block << (term ? "\0" : "\x80") << ("\0" * (55 - block_size)) | |
x = block.unpack 'V14' | |
bit_length = @buffer.size << 3 | |
x.push bit_length & MASK, bit_length >> 32 | |
last = true | |
end | |
h0, h1, h2, h3 = WORDS | |
a, b, c, d = WORDS | |
aa, bb, cc, dd = WORDS | |
j = 0 | |
WORDS.size.times do |round| | |
f, ff = F[round], F[WORDS.size.pred - round] | |
k, kk = K[round], KK[round] | |
16.times do | |
a, d, c, b = d, c, b, rol(a + f[b, c, d] + x[R[j]] + k, S[j]) | |
aa, dd, cc, bb = dd, cc, bb, rol(aa + ff[bb, cc, dd] + x[RR[j]] + kk, SS[j]) | |
j += 1 | |
end | |
end | |
h0, h1, h2, h3 = (h1 + c + dd) & MASK, (h2 + d + aa) & MASK, | |
(h3 + a + bb) & MASK, (h0 + b + cc) & MASK | |
end | |
[h0, h1, h2, h3].pack "V#{WORDS.size}" | |
end | |
private | |
def rol value, shift | |
((value << shift) & MASK) | (value & MASK) >> (32 - shift) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment