Little Endian

El orden de bytes usado para almacenar enteros

Little Endian

Convierte un número entre los órdenes de bytes big-endian y little-endian.

0d
0x
0 bytes
0x
0 bytes
Tamaño del campo

El término little-endian se refiere al orden de los bytes al almacenar enteros en una computadora. Es cuando el byte menos significativo va primero o, más simplemente, cuando los bytes aparecen al revés.

Casi todos los enteros en los datos brutos de Bitcoin están en orden little-endian, así que conviene acostumbrarse.

Ejemplo

¿Qué es little-endian?

Supongamos que estamos definiendo el valor de una salida de transacción como 12345678 satoshis.

Ahora, el campo valor tiene 8 bytes de tamaño. Así que, si convertimos ese valor a bytes hexadecimales, queda así:

00 00 00 00 00 bc 61 4e

Este orden de bytes se llama big-endian.

Obviamente no agotamos ese campo, ya que el entero más grande que este campo de 8 bytes puede contener es 0xffffffffffffffff (o 18446744073709551615). Esto es obvio porque hay muchos ceros a la izquierda, y nosotros, los humanos, esperamos ver los números más grandes a la izquierda.

Sin embargo, las computadoras (y Bitcoin) prefieren leer esos bytes en la otra dirección:

4e 61 bc 00 00 00 00 00

Este orden de bytes se llama little-endian.

Tenemos exactamente los mismos bytes, pero en orden inverso. Así que, en vez de leer los bytes menores de derecha a izquierda, ahora los leemos de izquierda a derecha.

Órdenes de bytes

Diagrama que muestra bytes de datos representados en binario, decimal y hexadecimal.

Como mencioné, hay dos formas distintas de ordenar bytes al almacenar enteros en una computadora:

  1. Big Endian
  2. Little Endian

Algunas computadoras usan arquitectura big-endian, y otras usan little-endian.

1. Big Endian

(Rara vez usado en Bitcoin)

Es el formato más "legible para humanos". El byte que contiene el número mayor va primero:

00 00 00 00 00 bc 61 4e

O, más técnicamente, es cuando el byte más significativo se almacena en la dirección de memoria más pequeña de un bloque de bytes. Por ejemplo:

┌────────────────┬──────────┐
│ Dirección de   │ Contenido│
│ memoria        │          │
├────────────────┼──────────┤
│ 100            │ 0x00     │
│ 101            │ 0x00     │
│ 102            │ 0x00     │
│ 103            │ 0x00     │
│ 104            │ 0x00     │
│ 105            │ 0xbc     │
│ 106            │ 0x61     │
│ 107            │ 0x4e     │
└────────────────┴──────────┘

2. Little Endian

(Usado comúnmente en Bitcoin)

Es el formato más "legible para computadoras". El byte que contiene el número menor va primero:

4e 61 bc 00 00 00 00 00

O, más técnicamente, es cuando el byte más significativo se almacena en la dirección de memoria más grande de un bloque de bytes. Por ejemplo:

┌────────────────┬──────────┐
│ Dirección de   │ Contenido│
│ memoria        │          │
├────────────────┼──────────┤
│ 100            │ 0x4e     │
│ 101            │ 0x61     │
│ 102            │ 0xbc     │
│ 103            │ 0x00     │
│ 104            │ 0x00     │
│ 105            │ 0x00     │
│ 106            │ 0x00     │
│ 107            │ 0x00     │
└────────────────┴──────────┘

Como puedes imaginar, Satoshi estaba trabajando en una computadora little-endian al programar Bitcoin.

Terminología

¿Por qué se llama "little-endian" y "big-endian"?

Diagrama que muestra el extremo pequeño y el extremo grande de unos huevos.

Por culpa de huevos, básicamente.

Los términos "little-endian" y "big-endian" vienen del libro Los viajes de Gulliver (1726). Hay una parte que se refiere a dos grupos distintos de personas: uno que rompe los huevos por el "extremo pequeño" (little end) y otro que los rompe por el "extremo grande" (big end).

Esos términos "little end" y "big end" se adoptaron luego para describir las dos formas distintas de ordenar bytes en una computadora.

Uso

¿Cuándo usamos little-endian en Bitcoin?

Encontrarás campos little-endian en Bitcoin siempre que trabajes con enteros dentro de mensajes de red. Los lugares más comunes son los datos brutos de transacción y las cabeceras de bloque brutas.

Datos de transacción

Aquí tienes una transacción bruta. La he dividido y resaltado los campos little-endian en verde.

02000000 <- versión (little-endian)
    01 <- conteo de entradas
        79fe743502ff8cd181121572fececac3feee5ef3034edfb3ccd2bfaa24537dae <- txid
        01000000 <- vout (little-endian)
        6a 473044022...915 <- scriptsig
        fdffffff <- sequence (little-endian)
    01 <- conteo de salidas
        2a5f020000000000 <- valor de la salida (little-endian)
        19 76a914a9970b7ed051822ea52a088b9c628eb158dd57e588ac <- scriptpubkey
ff30a00 <- locktime (little-endian)

Por ejemplo, el vout es un campo little-endian de 4 bytes y, en esta transacción, se refiere a una salida anterior número 1. Si ese campo fuera big-endian, sería 00000001, pero, al ser little-endian, los bytes van en orden inverso: 01000000.

Cabecera de bloque

Aquí tienes una cabecera de bloque bruta.

00000020 <- versión (little-endian)
b91fd2b09d4a8238ad4c814e4fa0ab9ed34bf0f75a3a00000000000000000000 <- hash del bloque anterior
330b32016c8176153071283d3e5fe87c2318b3fd41d6ca1b1a8bf12670908e38 <- raíz de merkle
daf0d861 <- tiempo (little-endian)
ab980b17 <- bits (little-endian)
0e69d05c <- nonce (little-endian)

Como puedes ver, todos los campos little-endian son los que contienen algún tipo de número. Por ejemplo, el tiempo en la cabecera es un campo little-endian de 4 bytes que contiene un timestamp Unix. Aquí es daf0d861, que en big-endian sería 61d8f0da. Convertido a decimal, obtenemos 1641607386, un timestamp Unix para el 8 de enero de 2022, 02:03:06 UTC.

Conversión

Cómo convertir entre big-endian y little-endian

Si estás trabajando con cadenas, una forma rápida y simple de invertir el orden de los bytes es dividir la cadena en fragmentos de 2 caracteres (2 caracteres hex = 1 byte) y luego invertir el array.

# invierte el orden de los bytes de una cadena hex
hex = "0000000000bc614e"
little = hex.scan(/../).reverse.join
puts little #=> 4e61bc0000000000

Aquí va una forma rápida de convertir desde la línea de comandos:

echo "0000000000bc614e" | fold -w2 | tac | tr -d '\n' #=> 4e61bc0000000000

¿Por qué Bitcoin usa little-endian?

Porque Satoshi desarrolló Bitcoin en una computadora con arquitectura little-endian.

Puede parecer raro al principio, pero el orden little-endian es en realidad más común de lo que imaginas:

Casi todas las CPUs de hoy en día funcionan nativamente en little-endian.
Pieter Wuille, bitcoin.stackexchange.com

Así que, aunque parezca al revés para los humanos, es bastante estándar para las computadoras.

Normalmente no te importa la arquitectura subyacente de tu sistema en la programación cotidiana. Pero la endianness puede volverse relevante cuando empiezas a trabajar con los bytes brutos de datos que se envían por la red (por ejemplo, datos de transacción).

Resumen

Little-endian es el orden de bytes que usamos para almacenar enteros (y otras estructuras de múltiples bytes, como el campo bits) en los datos brutos de Bitcoin, como transacciones y cabeceras de bloque.

Para el ojo humano, little-endian parece tener los bytes en orden inverso. Sin embargo, muchas computadoras modernas usan arquitectura little-endian, y Satoshi programó la primera versión de Bitcoin en una computadora little-endian, y por eso usamos little-endian en Bitcoin.

Probablemente sería más fácil, desde el punto de vista del desarrollo, tener todo en big-endian, pero little-endian fue la elección de Satoshi, así que solo tienes que acostumbrarte.

Bienvenido a la programación en Bitcoin.