Возьмите наиболее значимые 8 байтов MD5-хеша строки как long (в Ruby) - PullRequest
0 голосов
/ 29 апреля 2010

Привет, друзья, я пытаюсь реализовать java-функцию "hash" в ruby.

Вот сторона java:

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;
}

Пока что мое лучшее предположение в рубине:

# 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

Проблема в том, что этот код ruby ​​не соответствует выводу Java.

Для справки, приведенный выше код Java с учетом этих строк возвращает соответствующий long:

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

Мысль:

  • У меня проблемы с получением байтов UTF8 из строки ruby ​​
  • В ruby ​​я использую hexdigest, я подозреваю, что я должен использовать просто digest вместо
  • Java-код принимает md5 байтов UTF8, тогда как мой код ruby ​​принимает байты md5 (в шестнадцатеричном виде)

Любые предложения о том, как получить точно такой же вывод в ruby?

1 Ответ

1 голос
/ 29 апреля 2010
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
...