Las criptomonedas funcionan utilizando cadenas de bloques (blockchain), que son, básicamente, listas crecientes de registros de información cifrada, cada uno encadenado al anterior con criptografía. Esos ‘registros’ son los bloques en los que se asientan y validan las transacciones, pero eso no es lo único que hay dentro de ellos.
A continuación, daremos un paseo por el contenido de un bloque en una blockchain, tomando como referencia sobre todo la blockchain de Bitcoin. De esta forma, podremos aproximarnos a su funcionamiento.
Antes de empezar, debes tener en cuenta que este es un artículo para usuarios que ya dominan, al menos, las principales nociones sobre los conceptos de blockchain y criptomonedas. Si aún no lo haces, lo mejor es iniciar con información más básica.
Hash criptográfico
Una función hash criptográfica es un algoritmo que cuenta con ciertas propiedades útiles para el cifrado de datos, esto es, proteger contenidos mediante el uso de claves. Al aplicarla, se toma un mensaje de cualquier tamaño, se cifra, y se consigue a cambio una cadena alfanumérica única de longitud fija (llamada digest o simplemente hash), sin importar el tamaño del mensaje original. Funciona para verificar que, en efecto, se trata de ese mensaje (o transacción) en particular y que no fue modificado antes de su entrega. Si una sola parte, aunque sea un solo punto del mensaje original cambia, el hash (digest) también lo hace de forma radical.
Por ejemplo, usando una herramienta en línea para cifrar con el algoritmo SHA256 (del que hablaremos más adelante) podemos introducir el siguiente mensaje:
Bitcoin es la primera criptomoneda
Y conseguir a cambio el siguiente resultado:
91D3081626672039C99F27323895D06B88376312706BF7AB035A662B6C5C0B1B
Si añadiéramos palabras o cambiáramos aunque fuera un punto en el mensaje original, el hash obtenido también cambiaría, aunque continuaría siendo de la misma extensión (64 caracteres). Veamos:
Bitcoin es la primera criptomoneda.
AE0B40E7FC912BCE189A06F3A8069776FB24DCCC493332F2D349F0A470DE1254
Nótese que sólo añadimos un punto al final de la frase. Aun así, el resultado es completamente distinto al primero. En otro caso, si las frases volvieran a cifrarse con este mismo algoritmo, pero con otra herramienta, sus digest continuarían siendo los mismos: una entrada particular produce siempre el mismo resultado único.
De esa forma, los mensajes se transmiten de manera segura e íntegra, pues es casi imposible averiguar el mensaje original a partir del digest, y, por tanto, tampoco sería posible modificarlo. A esto se le conoce como funciones de un solo sentido o unidireccionales. Podemos profundizar más al respecto.
Hash como función unidireccional
Una función unidireccional, en matemática, se define como una función (relación entre los elementos de dos conjuntos) que tiene la característica de ser fácil de calcular, pero difícil de invertir. Nótese que se dice “difícil”, pero no imposible. En realidad, las funciones totalmente unidireccionales en ciencias de la computación aún son sólo una conjetura.
Las funciones hash, sin embargo, se hacen para ser lo suficientemente difíciles de invertir. Sólo así es posible que sean útiles para la criptografía, pues revertirlas tomaría una cantidad contraproducente (para el atacante) de tiempo y recursos.
Construir un hash es un proceso matemático complejo, pero una de las formas de hacerlo es mediante funciones modulares, que asegurarían su ‘unidireccionalidad’. Puesto de forma sencilla, las funciones modulares producen el remanente de una división. Así, por ejemplo, 10 mod 3 = 1, porque 10 dividido entre 3 es 3 más un remanente de 1. En otra forma, 3 cabe 3 veces en 10, y queda un añadido de 1.Publicidad
Ahora, digamos que para construir un hash tenemos una llave privada (X) mod 5 = 2. Sólo tú sabrías el valor de X, el cual, digamos que es 27, porque dividido entre 5 es igual a 5 más un remanente de 2. Supongamos, además, que 5 son los datos de una transacción que realizaste y 2 es el hash resultante de esa transacción. Aunque estos últimos datos sean públicos, es casi imposible averiguar que tu llave privada es 27, pues para llegar al resultado de 2 utilizando también 5 existen infinitas posibilidades. Tu “X” pudo ser 7, 52, 23390787 u otro: averiguarlo es casi imposible.
En la práctica, este mismo principio se aplica a algoritmos más sofisticados y cantidades de datos muy superiores, por lo que la dificultad de averiguar el dato de origen aumenta muchísimo más. Los datos resguardados por una función hash están seguros.
Propiedades de una función hash segura
Existen varios tipos de funciones hash, pero todos ellos, para ser seguros, deben poseer cuatro características principales:
- Computacionalmente eficiente
Las funciones hash se utilizan en computadores, así que, aunque suene un poco obvio, estos computadores deben ser capaces de llevar a cabo la labor matemática necesaria para crear un hash en un período de tiempo muy corto. Si no fuera así, cada proceso que involucre la emisión de un hash tardaría demasiado y sería poco práctico utilizarlos. En la actualidad, esto no es un problema, pues una computadora promedio puede realizar la tarea en menos de un segundo.
- Determinista
Esto implica que el mismo mensaje (entrada) debe producir siempre el mismo digest (salida) cada vez que sea utilizado o consultado. Si la función produjera un resultado al azar cada vez sería inútil, pues no serviría para verificar que se trata del mensaje original. El punto de un hash, para el caso que nos ocupa, es corroborar que una firma digital sea auténtica sin tener acceso a la llave privada.
- Resistente a preimagen
Significa que la salida no debe revelar ningún dato en absoluto sobre la entrada. Es por eso que un hash debería tener siempre la misma longitud en el digest, independientemente del tamaño del mensaje. Tampoco debe darse ninguna pista sobre el contenido de tal mensaje, por lo que, al más mínimo cambio, el hash resultante debe ser por completo distinto.
- Resistente a colisión
Dos (o más) entradas diferentes no deberían producir la misma salida (digest). Es necesario mencionar que ninguna función hash está por completo libre de colisión: es una simple probabilidad matemática. Las salidas tienen una longitud determinada, a diferencia de las entradas que pueden ser de cualquier tamaño, así que el número de resultados es finito y, por tanto, propenso a colisión. Sin embargo, esta probabilidad es bastante pequeña, y la meta de cualquier función hash es hacerla lo más pequeña posible.
Sobre los tipos de hash
Existen numerosos tipos de algoritmos para crear hash en distintas plataformas, con diversas funciones, desde autenticación de documentos y verificación de contraseñas, hasta verificación de firmas digitales y, por supuesto, minería de criptomonedas. Entre los que continúan siendo efectivos, podemos mencionar el BLAKE2, MD6, Streebog y, especialmente, la serie SHA (Secure Hash Algorithm).
La serie SHA fue diseñada por la Agencia Nacional de Seguridad (NSA) estadounidense e incluye el SHA-256, ampliamente utilizado en el criptomundo debido a que fue el algoritmo escogido por Satoshi Nakamoto para hacer funcionar la blockchain de Bitcoin, de la cual, a su vez, se han derivado otras criptomonedas que han conservado el mismo algoritmo (como Peercoin).
El SHA-256 produce un digest de 256 bits y 64 caracteres. Por otro lado, tenemos el SHA-3, incluido en el mismo estándar, pero con estructura diferente, pues produce digest de tamaño arbitrario. Este es el algoritmo utilizado para el sistema Ethash de Ethereum.
Árbol de Merkle
Sabiendo ya qué es un hash, hay que apuntar que las transacciones en una blockchain usan hashes para cifrar los datos, pero estas líneas alfanuméricas no sólo “flotan” libremente en una nube digital. Se ordenan de forma estricta y se resumen a medida que aumenta la cadena, proporcionando un método seguro, rápido y ligero para verificar los datos. Con ese propósito está implementado el Árbol de Merkle.
Este concepto, también conocido como Árbol de Hash, se trata de una estructura de datos en árbol, es decir, aquella que simula un orden jerárquico de arriba hacia abajo, empezando por un único valor “raíz” que se va dividiendo en valores “hoja”, como un árbol al revés. En el caso del Árbol de Merkle, estos valores son todos hashes, y en una blockchain, esos hashes provendrían de los datos de las transacciones.
El nombre del árbol criptográfico proviene de su inventor, Ralph Merkle, un científico computacional estadounidense que patentó esta estructura en 1979. Cabe resaltar que Merkle, a 2019 con 67 años de edad, también es el inventor del hash criptográfico y uno de los inventores de la criptografía de llave pública.
Raíz de Merkle
El principal propósito del árbol de hash es crear una raíz de Merkle, es decir, el valor raíz que mencionamos antes. En este caso, se podría creer que de este valor provienen los valores “hoja”, pero, en realidad, el valor raíz es un resumen de todos los valores hoja.
Este resumen se crea agrupando todos los hashes de las transacciones en pares a los que, a su vez, les será aplicada de nuevo la función hash criptográfica pertinente para crear un nuevo digest que equivale a ambos. Si acaso el número de entradas fuera impar, la última se copiaría a sí misma y se emparejaría con esa copia para permitir el proceso. Los digest resultantes volverán a organizarse por pares y a repetir la misma técnica, hasta que sólo quede una única línea hash como resumen de todas las que pasaron por este proceso de fusión. Esa es la raíz de Merkle, y hay una sola por bloque en una blockchain.
Así, por ejemplo, si en un bloque están contenidas 512 transacciones, el árbol de Merkle se encargaría de agruparlas en 256 pares, que se reducirían luego a 128, luego a 64, de ahí a 32, después 16, 8, 4, 2 y la última. Una sola línea alfanumérica se queda allí para representar esas 512 transacciones, en lugar de recargar el bloque con 512 hashes.
Recordemos que cada transacción en una blockchain tiene su propio hash, y, si hablamos de hashes creados con SHA-256, cada uno pesa 32 bytes. Volviendo al ejemplo de los 512 hashes, ese bloque soportaría entonces (además de otros datos) 16.384 bytes cuando, usando la raíz de Merkle, puede contener sólo 32 bytes. Ella contiene al resto matemáticamente, así que no es necesario incluirlos todos.Publicidad
Como vemos, a largo plazo, con miles y miles de transacciones realizadas por usuarios de todo el mundo, el espacio para almacenar completa una blockchain podría llegar a convertirse en un problema de no ser por la raíz de Merkle, que resume una gran cantidad de datos en un solo hash.
El propio Satoshi Nakamoto en el Libro Blanco de Bitcoin explica que una vez que una transacción está enterrada bajo suficientes bloques, las transacciones anteriores a esa pueden ser descartadas para salvar espacio. Para lograrlo sin romper el hash que las asegura y conecta al resto de la blockchain, los viejos bloques se compactan con el árbol de Merkle, mientras que los hashes interiores que formaron la raíz no necesitan ser conservados.
Una cabecera de bloque sin transacciones sería de unos 80 bytes. Si suponemos que los bloques se generan cada 10 minutos, 80 bytes * 6 * 24 * 365 = 4,2MB por año. Con sistemas informáticos siendo típicamente vendidos con 2 GB de RAM a partir de 2008, y la Ley de Moore prediciendo un crecimiento actual de 1,2 GB por año, el almacenamiento no debería ser un problema incluso si las cabeceras de bloque deben mantenerse en la memoria.
Satoshi Nakamoto, libro blanco de Bitcoin.
Artículo por Isabel Pérez.
Fuente: Diario Bitcoin
Imagen destacada por phive2015 / stock.adobe.com