Nate Murray
Nate Murray

Reputation: 3991

Take most significant 8 bytes of the MD5 hash of a string as a long (in Ruby)

Hey Friends, I'm trying to implement a java "hash" function in ruby.

Here's the java side:

import java.nio.charset.Charset;
import java.security.MessageDigest;

/**
 * @return most significant 8 bytes of the MD5 hash of the string, as a long
 */
protected long hash(String value) {
  byte[] md5hash;
  md5hash = md5Digest.digest(value.getBytes(Charset.forName("UTF8")));
  long hash = 0L;
  for (int i = 0; i < 8; i++) {
    hash = hash << 8 | md5hash[i] & 0x00000000000000FFL;
  }
  return hash;
}

So far, my best guess in ruby is:

# WRONG - doesn't work properly.
#!/usr/bin/env ruby -wKU

require 'digest/md5'
require 'pp'

md5hash = Digest::MD5.hexdigest("0").unpack("U*")
pp md5hash
hash = 0
0.upto(7) do |i|
  hash = hash << 8 | md5hash[i] & 0x00000000000000FF
end
pp hash

Problem is, this ruby code doesn't match the java output.

For reference, the above java code given these strings returns the corresponding long:

"00038c53790ecedfeb2f83102e9115a522475d73" => -2059313900129568948
"0" => -3473083983811222033
"001211e8befc8ac22dd265ecaa77f8c227d0007f" => 3234260774580957018

Thoughts:

Any suggestions on how to get the exact same output in ruby?

Upvotes: 0

Views: 2660

Answers (1)

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369594

require 'digest/md5'

class String
  def my_hash
    hi1, hi2, mid, lo = *Digest::MD5.digest(self).unpack('cCnN')
    hi1 << 56 | hi2 << 48 | mid << 32 | lo
  end
end

require 'test/unit'
class TestMyHash < Test::Unit::TestCase
  def test_that_my_hash_hashes_the_string_0_to_negative_3473083983811222033
    assert_equal -3473083983811222033, '0'.my_hash
  end
end

Upvotes: 1

Related Questions