Byte Order

Transaction Hashes and Block Hashes

Diagram showing the natural order of bytes coming out of a hash function, and the reverse byte order below it.

A fun quirk of Bitcoin is that transaction hashes and block hashes have their byte orders reversed when you're displaying and searching for them.

For example, the actual block hash for the genesis block comes out of the hash function like this:

6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000

But when you're searching for this block in Bitcoin Core or on a block explorer, you'll see this byte order:

000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

As you can see, the order of the bytes has been reversed.

So part of working with bitcoin data is getting the hang of reversing the order of bytes for transaction and block hashes. It will probably trip you up a few times (like it did does for me), but like I said, it's just a quirk of bitcoin development.

tool-662caef3d0636
Tool Icon

Reverse Bytes

0 bytes 0 bytes
0 secs

What are the different byte orders?

There are two byte orders used in bitcoin:

  1. Natural Byte Order
  2. Reverse Byte Order

These byte orders are not to be confused with little-endian and big-endian byte orders, which are the byte orders used for representing numbers (and not necessarily hashes like we're talking about here).

Natural Byte Order

Also known as: Native Byte Order, Internal Byte Order

This is the order of bytes as they come out of the hash function. This is the byte order you use when you're referring to a previous block in a raw block header, or when you're referring to a previous TXID in a raw transaction.

In other words, this is the byte order that bitcoin programmers deal with when working with raw bitcoin data.

Block Hash:       6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
Transaction Hash: 169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f4

This byte order is sometimes referred to as "little-endian".

Reverse Byte Order

Also known as: RPC Byte Order, Network Byte Order

This is the reverse order of bytes as they come out of the hash function. This is the byte order you use when searching for transactions/blocks in block explorers, or making RPC requests to Bitcoin Core.

In other words, this is the byte order that bitcoin users see and use.

Block Hash:       000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
Transaction Hash: f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16

This byte order is sometimes referred to as "big-endian".

Where do we use natural byte order?

You use the natural byte order when working with raw bitcoin data internally.

TXIDs (Transaction Data)

Inside raw transactions, each input refers to the output of a previous transaction by using the previous transaction's hash (aka TXID). I've highlighted the TXID referring to a previous transaction in green:

01000000 01 c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 00000000 48 47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 ffffffff 02 00ca9a3b00000000 43 4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac 00286bee00000000 43 410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac 00000000

If you search for c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 in a block explorer you won't find anything.

But if you reverse the byte order to 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9 you'll find it.

Block Hashes (Block Header)

Inside raw block headers, you refer to a previous block using a block hash. I've highlighted the previous block hash in green:

00000020 b91fd2b09d4a8238ad4c814e4fa0ab9ed34bf0f75a3a00000000000000000000 330b32016c8176153071283d3e5fe87c2318b3fd41d6ca1b1a8bf12670908e38 daf0d861 ab980b17 0e69d05c

As you might be able to tell, b91fd2b09d4a8238ad4c814e4fa0ab9ed34bf0f75a3a00000000000000000000 is the natural byte order for the hash of the previous block. All of the zeros are on the right, so it's easier to tell when a block hash is in natural byte order or not (because it looks backwards).

Anyway, if you reverse the byte order to 000000000000000000003a5af7f04bd39eaba04f4e814cad38824a9db0d21fb9 you'll be able to find this block in a block explorer.

Merkle Roots (Block Header)

The merkle root also has its byte order reversed (for some reason) when displaying it on blockchain explorers. I've highlighted the merkle root inside a raw block header in green:

00000020 b91fd2b09d4a8238ad4c814e4fa0ab9ed34bf0f75a3a00000000000000000000 330b32016c8176153071283d3e5fe87c2318b3fd41d6ca1b1a8bf12670908e38 daf0d861 ab980b17 0e69d05c

You don't typically search for merkle roots in block explorers, so it's less likely you'll run in to problems with them. But it's good to know that their byte order gets reversed if you're working with raw block headers.

I'm not too sure why merkle roots get reversed. I'm guessing it's so every hash gets displayed in reverse order, just like block and transaction hashes do. I suppose if you're going to be awkward you might as well be consistent.

Why reverse the byte order?

Only Satoshi knows why, and they never explained their reasoning for it.

So here's my theory on why we reverse the byte order of block hashes and transaction hashes in bitcoin…

Block Hashes

The bytes that come out of a hash function have no meaning. They're just random bytes.

When programming bitcoin, Satoshi came up with the clever idea to interpret the block hashes as integers. This allows you to compare the block hash against a target value, and this forms part of the core mechanism of mining.

However, Satoshi was working on a computer with a little-endian architecture. This meant that when these block hashes got converted to integers, the computer read the bytes from left-to-right. So when you view the bytes for the block hash and target, they look like this:

Natural Byte Order (Little Endian):

                          ┌ lowest value byte
                          │
Block Hash (Bytes):       6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
Target (Bytes):           0000000000000000000000000000000000000000000000000000ffff00000000

Block Hash (Integer):    10628944869218562084050143519444549580389464591454674019345556079
Target (Integer):     26959535291011309493156476344723991336010898738574164086137773096960

The bytes look backwards, which is annoying. That's fine for computers, but humans are used to seeing the largest number/bytes on the left (aka big-endian byte order).

So I believe Satoshi decided to reverse the byte order to make block hashes look more human-friendly when displaying them:

Reverse Byte Order (Big-Endian):

                                                                      lowest value byte ┐
                                                                                        │
Block Hash (Bytes):       000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
Target (Bytes):           00000000ffff0000000000000000000000000000000000000000000000000000

Block Hash (Integer):    10628944869218562084050143519444549580389464591454674019345556079
Target (Integer):     26959535291011309493156476344723991336010898738574164086137773096960

Looking at the block hash now, you can easily see it's below the target.

So internally, all block hashes are handled in their natural byte order. But externally, when making RPC requests or searching on a block explorer, the block hashes are in the human-friendly reverse byte order.

RPC Byte Order. The reverse byte order was originally used when making RPC requests to Bitcoin Core, which is why it's sometimes referred to as RPC Byte Order.

TXIDs

In addition to reversing the byte order of block hashes, Satoshi decided to reverse the byte order for transaction hashes (aka TXIDs) too:

Transaction Hash: 169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f4
TXID:             f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16

There is no need to do this though, as transaction hashes are never interpreted as integers inside bitcoin.

So why do it?

My guess is that Satoshi wanted to have some consistency when searching for blocks and transactions, and seeing as block hashes were already reversed, they decided to do the same thing for transactions too.

So the reason for reversing the byte order for transactions and blocks was to make them more user-friendly. But it does make working with raw data in bitcoin a bit confusing when you're first getting started.

Due to historical accident, the tx and block hashes that bitcoin core uses are byte-reversed. I’m not entirely sure why. May be something like using openssl bignum to store hashes or something like that, then printing them as a number.
Wladimir van der Laan, (on IRC)
In both transaction and block hashes bytes are reversed when displayed by Bitcoin software and websites in hexadecimal form. This makes blocks show up in big endian form, which is the way we humans write numbers down.
user8791, bitcoin.stackexchange.com

Why not change it?

I'll be the first to say that it would be a lot simpler from a developer's perspective to not have to deal with reversing byte orders all the time.

However, this set up has been adopted by so many block explorers and wallets for so long that it's too ingrained to change it. It's easier for new developers to get the hang of this little quirk than it is for everyone to reverse the way they search for transactions and blocks.

But for what it's worth, you're not on your own if you find it a bit annoying:

My pet peeve, related to endianness, is treating hashes as numbers and reversing them. A hash is a byte string with a well-defined order and it makes no more sense to reverse it than to reverse text.
Hal Finney, bitcointalk.org

But it's all part of the fun of working on bitcoin.

How do you reverse the order of bytes?

Here are some code examples:

# hexadecimal string
hex_string = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"

# reverse byte order in hexadecimal string
hex_string_reversed = hex_string.scan(/../).reverse.join
puts hex_string_reversed #=> 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
# TIP: scan(/../) matches every two characters in a string and returns an array


# raw bytes
bytes = "\x6F\xE2\x8C\x0A\xB6\xF1\xB3\x72\xC1\xA6\xA2\x46\xAE\x63\xF7\x4F\x93\x1E\x83\x65\xE1\x5A\x08\x9C\x68\xD6\x19\x00\x00\x00\x00\x00"

# reverse raw bytes
bytes_reversed = bytes.reverse
puts bytes_reversed.unpack("H*")[0] #=> 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// hexadecimal string
$hex_string = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000";

// reverse byte order
$reversed = implode('', array_reverse(str_split($hex_string, 2)));
echo $reversed; //=> 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
package main

import "fmt"
import "encoding/hex" // converting between byte array and hexadecimal string

func main() {

    // Hexadecimal string
    hex_string := "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"

    // Convert hexadecimal string to byte array
    byte_array, _ := hex.DecodeString(hex_string)

    // Reverse the byte array
    reverse_byte_array := make([]byte, 0) // create empty byte slice
  for i := len(byte_array)-1; i >= 0; i-- { // run backwards through the byte slice
      reverse_byte_array = append(reverse_byte_array, byte_array[i]) // append each byte to the new byte slice
  }

    // Convert byte array back to hexadecimal string
    reverse_hex_string := hex.EncodeToString(reverse_byte_array)

    // Print the result
    fmt.Println(reverse_hex_string) //=> 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

}

If you're working with strings, remember that a byte is 2 hexadecimal characters (e.g.6f). So don't make the mistake of just reversing the whole string; you need to reverse the order of the bytes.

Summary

We use two different byte orders for transaction hashes and block hashes in bitcoin:

  1. Natural Byte Order. This is what you get out of the hash function when hashing transaction data and block headers. It's used internally when working with raw bitcoin data to refer to previous transactions and blocks.
  2. Reverse Byte Order. These are the same hashes, but their byte orders are reversed. We use these when searching for transactions and blocks in block explorers.

So when you're working with bitcoin data, you just use the bytes as they come out of the hash function. But when you're displaying block hashes and transaction hashes as hexadecimal strings, you need to reverse the order of the bytes.

We've all been confused by this at some point, but it's all part of the fun of working with raw bitcoin data.