4

Ruby ethereum libraries use: https://github.com/phusion/digest-sha3-ruby

require 'digest/sha3'
'0x' + Digest::SHA3.new(256).hexdigest('0x0')
=> "0x77b7d82d931e1a403db0240b08c0716665eec4664af617c457918e4a67bc1810"

... Yet over in javascript land (using both web3 or ethers):

web3.utils.keccak256('0x0')
=> '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'

ethers.utils.keccak256('0x0')
=> '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'

Why are these outputs different?

UPDATE

It appears the problem is when '0x' is prefixed the js libraries are treating things differently.

> web3.utils.sha3('255')
'0xbebb351b5cf10820d8521e899df75c3dc4c8d740dcf450f315119f5c837945c0'

and in ruby:

'0x' + Digest::SHA3.new(256).hexdigest('255')
=> "0xbebb351b5cf10820d8521e899df75c3dc4c8d740dcf450f315119f5c837945c0"

but then as hex:

> web3.utils.sha3('0xff')
'0x8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9'

and in ruby:

'0x' + Digest::SHA3.new(256).hexdigest('0xff')
=> "0x420daffad4b177bce28bead5f76f7bc97ef63c3aae74c496db8ce6aafe9e6513"
'0x' + Digest::SHA3.new(256).hexdigest('ff')
=> "0x979b141b8bcd3ba17815cd76811f1fca1cabaa9d51f7c00712606970f81d6e37"

...

And then this makes even less sense to me:

> web3.utils.sha3('0x0')
'0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'
> web3.utils.sha3('0x00')
'0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'
> web3.utils.sha3('0x000')
'0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798'
> web3.utils.sha3('0x0000')
'0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798'
> web3.utils.sha3('0x00000')
'0x99ff0d9125e1fc9531a11262e15aeb2c60509a078c4cc4c64cefdfb06ff68647'
> web3.utils.sha3('0x000000')
'0x99ff0d9125e1fc9531a11262e15aeb2c60509a078c4cc4c64cefdfb06ff68647'

0x0 or 0x00 or 0x0000000000000000000000000000000000000000000000000000000 is all just 0, so why would those result in different digests?

1
  • A possible difference is that web3.js will accept an hexadecimal string and will convert to a bytes sequence before processing it. Other libraries will not make such conversion.
    – Ismael
    Apr 1, 2020 at 6:26

2 Answers 2

3

Turns out the answer is the format of the string being given to ruby's SHA3 implementation:

'0x' + Digest::SHA3.new(256).hexdigest("\xff")

will give the same output as:

web3.utils.sha3('0xff');
0

The SHA3 gem is no longer maintained and broken for Ruby 3. In addition, it's also ambiguous concerning the SHA3 vs. Keccak confusion. Therefore, I created a keccak digest specifically for Ethereum.

To generate the same hash:

Digest::Keccak.new(256).hexdigest("\x0")
# => "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"

Note that it cannot determine whether 0x0 is a string or a hex-number and your hash in the question is the hash over the string literal of "0x0".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.