The Bitcoin Protocol-specification gives an example of double-SHA-256 encoding.

2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (first round of sha-256)
9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50 (second round of sha-256)

I've tried various SHA256 calculators and the first encoding matches no problem, but the second always resolves to


I've also tried UPPERCASE and swapping the byte endianness.

  • 3
    Just semantics, but to avoid a common misunderstanding: sha256 does hashing, not encoding. Encoding is something entirely different. For one it implies it can be decoded, whereas hashing is strictly a one-way (and destructive) operation. – RocketNuts Feb 29 '16 at 18:48

You're hashing the hexadecimal representation of the first hash. You need to hash the actual hash -- the binary data that the hex represents.

Try this:

$ echo -n hello |openssl dgst -sha256 -binary |openssl dgst -sha256
  • 1
    This seems right, but how did the first round work when hashing the ASCII string "HELLO" vs the binary representation of ASCII hello? – halfbit Dec 9 '12 at 2:44
  • 2
    @makerofthings7 "HELLO" is binary. H is a byte with value 72, E is 69, etc. A raw, binary hash can also be printed, but many of its characters are likely to be invisible control characters, so it's generally written in hex. I can also write "HELLO" in hex: it's 48454c4c4f. – theymos Dec 9 '12 at 4:08
  • 2
    @makerofthings7: There is no difference between "the ASCII string 'HELLO' and "the binary representation of ASCII 'HELLO'". However, there is a difference between the ASCII representation of a number in hexadecimal and that number in binary. – David Schwartz Dec 9 '12 at 6:14
  • theymos and @DavidSchwartz it all makes perfect sense now. thanks – nyusternie Dec 11 '12 at 21:11
  • Hi, there are an optimized (direct and faster) option to perform SHA256d? Some openssl or similar (reliable) optimized algorith for it? – Peter Krauss May 8 '18 at 9:27

You want to work with the digests, not the hex strings.

Here's some Ruby:

require 'digest'
d = Digest::SHA2.new 256
d2 = Digest::SHA2.new 256
d << 'hello'
d2 << d.digest

This will be the output from irb:

1.9.3p194 :001 > require 'digest'
 => true 
1.9.3p194 :003 >   d = Digest::SHA2.new 256
 => #<Digest::SHA2:256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855> 
1.9.3p194 :004 > d2 = Digest::SHA2.new 256
 => #<Digest::SHA2:256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855> 
1.9.3p194 :005 > d << 'hello'
 => #<Digest::SHA2:256 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824> 
1.9.3p194 :006 > d.to_s
 => "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" 
1.9.3p194 :007 > d2 << d.digest
 => #<Digest::SHA2:256 9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50> 
1.9.3p194 :008 > d2.to_s
 => "9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50"

Here's the same thing in Python:

import hashlib
d = hashlib.sha256(b"hello")
d2 = hashlib.sha256()

And the output from within a Python shell:

>>> d = hashlib.sha256(b"hello")
>>> d2 = hashlib.sha256()
>>> d.hexdigest()
>>> d2.update(d.digest())
>>> d2.hexdigest()
  • thanks for code samples. I later found the Python code on the wiki, but still couldn't understand what made it work. +1 – nyusternie Dec 11 '12 at 21:07

For the second round of sha256, you need to hash the raw binary output from the first round, not the textual version.

A sha256 hash is 256 bits, or 32 bytes. Thus for the second round you should be hashing a piece of data that's 32 bytes. When hashing a hexadecimal string as the literal input for the second round, your data is 64 bytes.

Try a hashing tool that can interpret hexadecimal input. For example see here, copy/paste the hash to the input field and check the 'Hex' checkbox.


For easy reference, lets name the various inputs and outputs from your question like so:

pre-image 1:                     hello
hash operation 1:                SHA256
hash output 1 (aka pre-image 2): 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash operation 2:                SHA256
hash output 2:                   9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50

Pre-image 1 is binary (ASCII) data. We know this because the range of hexadecimal characters is 0-9 and a-f, and there are characters beyond f in pre-image 1. So hash operation 1 must be performed using a binary input.

By definition, a SHA256 hash operation always produces a 256 bit integer. We typically represent this in hexadecimal format, however it could just as correctly be written in decimal format and nothing would change:

hex:     2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
decimal: 20329878786436204988385760252021328656300425018755239228739303522659023427620

(Decimal conversion using Wolfram Alpha)

Since we know that pre-image 2 is a hexadecimal number, then hash operation 2 must be performed upon a number, rather than upon binary data.

In Javascript, using the Stanford Javascript Crypto Library, the two hashes would be done like so:

var preImage1 = 'hello';
var hashOutput1 = sjcl.hash.sha256.hash(preImage1);
console.log('hash output 1: ' + sjcl.codec.hex.fromBits(hashOutput1));
var preImage2 = hashOutput1;
var hashOutput2 = sjcl.hash.sha256.hash(preImage2);
console.log('hash output 2: ' + sjcl.codec.hex.fromBits(hashOutput2));

The SJCL is clever enough to figure out the pre-image formats and perform the hash correctly in each case.

You can also do these hash operations live on my blog, here: https://analysis.null.place/how-do-the-bitcoin-mining-algorithms-work/#form10

Note how the hash output changes when you click the pre-image is hexadecimal checkbox (this only works when hexadecimal characters are present in the input).


Late to the party, but here is a Node.js implementation using the built-in crypto module:

const crypto = require('crypto');
 * @param {Buffer} data
 * @returns {Buffer}
function doubleSHA256(data) {
  return crypto.createHash('sha256').update(crypto.createHash('sha256').update(data).digest()).digest();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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