Capítulo 02 de 10 · 11 min de lectura

Hashes: la huella digital

Una función que convierte cualquier cosa —una palabra, una foto, una biblioteca entera— en 64 caracteres. Parece poca cosa. Es la pieza de la que sale todo lo demás.

Una huella digital para los datos

Una función hash toma un dato de cualquier tamaño y devuelve un número de tamaño fijo, su hash. La que usan Bitcoin y xavicoin se llama SHA-256, y su resultado mide siempre 256 bits: 32 bytes, que se suelen escribir como 64 caracteres hexadecimales (del 0 al 9 y de la a a la f).

La mejor forma de entenderla es usarla. Esta calculadora ejecuta SHA-256 en tu navegador; nada de lo que escribas sale de tu ordenador:

SHA-256

Activa JavaScript para usar la calculadora.

Doble SHA-256 · el que usa xavicoin

Cambia una letra y mira cuántos de los 256 bits del hash se dan la vuelta.

Guarda la huella del texto y luego intenta modificarlo sin que se note.

Juega un rato. Pulsa hola y luego Hola: solo cambia una mayúscula y, sin embargo, el hash es completamente distinto. Prueba con el millón de letras: la entrada es enorme y la salida sigue midiendo lo mismo. Guarda una huella e intenta cambiar el texto sin que se note.

Todo lo que acabas de ver se resume en cuatro propiedades.

Las cuatro propiedades que importan

1. Determinista y de tamaño fijo

El mismo dato da siempre el mismo hash, en cualquier ordenador, hoy y dentro de cien años. Y da igual que la entrada sea una letra o una película: la salida son 256 bits. El hash de hola es, y será siempre:

b221d9dbb083a7f33428d7c2a3c3198ae925614d70210e28716ccaa7cd4ddb79

2. Efecto avalancha

Cambiar un solo bit de la entrada cambia, de media, la mitad de los bits de la salida, y no hay forma de predecir cuáles. De hola a Hola cambian 138 de los 256. No existen los hashes “parecidos”: dos textos casi iguales tienen huellas que no se parecen en nada.

Esto es lo que hace que un hash sirva de precinto: es imposible retocar un dato “solo un poquito” para que el hash apenas cambie.

3. De un solo sentido

Calcular el hash de un dato es instantáneo. Hacer el camino inverso —encontrar un dato que produzca un hash concreto— no tiene atajo conocido: solo queda probar entradas una detrás de otra hasta acertar. ¿Cuántas? El número de hashes posibles es 2256:

115.792.089.237.316.195.423.570.985.008.687.907.853.269.984.665.640.564.039.457.584.007.913.129.639.936

Son unos 1077, un número del orden de los átomos del universo observable. Toda la red Bitcoin junta calcula hoy del orden de 1021 hashes por segundo; a ese ritmo, recorrer todas las posibilidades llevaría unos 1048 años. El universo tiene unos 1010.

4. Sin colisiones (en la práctica)

Como hay infinitos datos posibles y “solo” 2256 hashes, por fuerza existen datos distintos con el mismo hash: colisiones. Pero nadie ha encontrado jamás una en SHA-256, y buscarla a ciegas exigiría unos 2128 intentos, que sigue estando fuera del alcance de cualquier tecnología imaginable.

A efectos prácticos, por tanto, el hash identifica al dato. Si dos ficheros tienen el mismo SHA-256, son el mismo fichero.

Para qué los usa una blockchain

Con esas propiedades en la mano, mira cuántas piezas de Bitcoin son, en el fondo, un hash:

Uso Qué se hashea Qué se consigue
Identificador de transacción La transacción Un nombre único e infalsificable para cada pago
Identificador de bloque La cabecera del bloque (80 bytes) Lo mismo, para cada bloque
Encadenado Cada bloque incluye el hash del anterior Tocar un bloque antiguo rompe todos los siguientes
Árbol de Merkle Las transacciones, de dos en dos, hasta que queda un hash Toda la lista de pagos de un bloque resumida en 32 bytes
Direcciones La clave pública Una dirección corta que no revela la clave hasta que se gasta
Código de control La propia dirección Si te equivocas en una letra al copiarla, se detecta
Prueba de trabajo La cabecera, cambiando un número cada vez Un acertijo que solo se resuelve a base de probar

La última fila es la más ingeniosa, porque convierte un defecto en una virtud. Que un hash sea impredecible significa que, si te pido uno que empiece por muchos ceros, no tienes otra que probar millones de entradas hasta que suene la flauta. Y en cambio a mí me basta calcular uno para comprobar que lo has conseguido. Eso es minar, y lo puedes hacer ahora mismo en la demo de la portada. Lo veremos a fondo en el capítulo 6.

Cómo lo hace xavicoin

En xavicoin, todo esto son tres funciones cortas. La principal aplica SHA-256 dos veces, igual que Bitcoin:

// internal/crypto/hash.go

// Hash256 calcula SHA256(SHA256(data)), el hash que Bitcoin usa para bloques
// y transacciones.
func Hash256(data []byte) Hash {
	first := sha256.Sum256(data)
	return sha256.Sum256(first[:])
}

¿Por qué dos veces? Satoshi nunca lo explicó. La hipótesis más aceptada es que fue una precaución frente a una debilidad conocida de la familia SHA-2 (los ataques de extensión de longitud), que el doble hash elimina. No era imprescindible, pero ya forma parte de las reglas.

Para las direcciones se usa una segunda función, que encadena SHA-256 con otro algoritmo distinto, RIPEMD-160. El resultado mide 20 bytes en lugar de 32, así que las direcciones salen más cortas; y si algún día se rompiera uno de los dos algoritmos, el otro seguiría protegiendo:

// Hash160 calcula RIPEMD160(SHA256(data)). Aplicado a una clave pública da el
// "pubKeyHash" de 20 bytes que identifica al destinatario de una salida.
func Hash160(data []byte) (out [20]byte) {
	first := sha256.Sum256(data)
	r := ripemd160.New()
	r.Write(first[:])
	copy(out[:], r.Sum(nil))
	return out
}

Una rareza: los hashes se muestran al revés

Si comparas un hash de bloque de xavicoin con lo que devuelve sha256sum, verás que los bytes salen en orden inverso. No es un error, es una herencia de Bitcoin: para la prueba de trabajo el hash se interpreta como un número escrito con el byte menos significativo primero (little-endian), y al mostrarlo se le da la vuelta para que se lea como un número normal. Por eso los hashes de bloque se ven con los ceros delante:

// String devuelve el hash en hexadecimal con los bytes invertidos, el formato
// con el que se ven los hashes en cualquier explorador de Bitcoin.
func (h Hash) String() string {
	var rev [HashSize]byte
	for i, b := range h {
		rev[HashSize-1-i] = b
	}
	return hex.EncodeToString(rev[:])
}

La prueba de que es el mismo hash que Bitcoin

El primer test de xavicoin toma los 80 bytes reales de la cabecera del bloque génesis de Bitcoin, les aplica Hash256 y comprueba que sale el hash que aparece en cualquier explorador de bloques:

000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

Diez ceros hexadecimales delante: hicieron falta miles de millones de intentos para encontrarlo en 2009. Comprobarlo cuesta dos llamadas a SHA-256.

Lo que viene

Ya tenemos con qué identificar datos y detectar cualquier manipulación. Lo que un hash no dice es de quién es algo: cualquiera puede calcular el hash de cualquier cosa. Para que una moneda tenga dueño hace falta la otra gran herramienta de la criptografía: las claves y las firmas digitales.