Entendiendo el blockchain

Resumen

Con la burbuja experimentada por el Bitcoin en 2017, y su posterior desplome en 2018, se ha despertado interés por la tecnología subyacente, el blockchain. Sus defensores afirman que es revolucionaria, con aplicaciones que van más allá de facilitar pagos. Para desmitificar este concepto y facilitar las discusiones acerca de este tema, acá se explica de manera sencilla, con ayuda de Python, qué es y cómo funciona el blockchain.

Más allá de la discutible utilidad del Bitcoin como dinero, genera interés el blockchain o cadena de bloques y el distributed ledger o libro mayor distribuido.

El distributed ledger fue concebido como un mecanismo para descentralizar los registros de valor de las instituciones financieras, que es indispensable para la operación de los sistemas de pagos. Por ejemplo, cuando Ariel desea pagarle a María a través de una transferencia bancaria, es el banco que en sus registros contables anota una disminución en los activos de Ariel y un aumento en los de María.

El registro centralizado de valor es vulnerable a ataques informáticos, pero se ha sido visto necesario porque era difícil resolver el problema del “doble gasto” en una red descentralizada. Esto es que una persona pudiese gastar más de una vez el mismo valor aprovechándose de la descoordinación o asincronismo entre los distintos registros.

En medio de la Gran Recesión de 2008, se publicó un artículo bajo el nombre de Satoshi Nakamoto (2008) que describe una forma de resolver este problema: el blockchain.

Un blockchain es un registro de transacciones fragmentando en bloques secuenciales de información, vinculados entre sí por medio de algoritmos cartográficos. Estas cadenas de bloques pueden ser compartidas entre muchos usuarios, quienes posiblemente no se conozcan entre sí, a través de una red peer-to-peer. Cuando se produce una transacción, esta es registrada en el bloque más reciente de la cadena casi simultáneamente por numerosos nodos de esta red descentralizada, que resuelve el problema de doble gasto por medio del consenso: dar por válidas las transacciones que están incluidas en nodos que constituyen una mayoría.

Aquí se muestra versión muy simple de un código para llevar a cabo transacciones en cococoins. La intención es explicar de manera sencilla qué es un blockchain. Para esto se dejan de lado algunas cuestiones técnicas de una red de pagos, como la autenticación de usuarios, el protocolo de comunicación, y la distribución de registros contables.

1 Encriptando información

Para empezar, se importan algunos paquetes de Python:

La función hashlib.sha3_256 se requiere para encriptar información, datetime contiene la función now para anotar la fecha y hora de las transacciones, pandas facilita almacenar los datos, numpy y random serán necesarios para hacer simulaciones.

El primer paso es encriptar la información. sha3_256 es la función hash más reciente (2015) de la familia SHA (Secure Hash Algorithm), publicada por el Instituto Nacional de Normas y Tecnología de Estados Unidos.

Una función hash es un algoritmo que toma un texto de cualquier tamaño y lo transforma en un número hexadecimal (expresado con los dígitos 0-9 y las letras A-F) de un tamaño predeterminado, que cumple:

  1. bajo costo computacional,
  2. compresión (toma un texto de mayor tamaño y lo reducen a una longitud pequeña),
  3. determinista (para un texto dado, siempre se obtiene el mismo resultado),
  4. difícil de invertir (a partir del resultado, es prácticamente imposible saber el texto original, sin lo cual la función sería inútil para encriptar),
  5. inyectividad (dos textos distintos dan por resultados dos resultados distintos).

Para que se cumpla la última condición es indispensable que el número de potenciales textos a encriptar sea menor que el número de hashs.

El tamaño del hash depende del nivel de seguridad deseado. Por ejemplo, sha3_256 da un resultado de 256 bits, con el cual se representa un número hexadecimal de 64 dígitos (cada número hexadecimal requiere 4 bits para almacenarse).

64 dígitos hexadecimales parecen pocos para encriptar todos los posibles textos, pero puede encriptarse $16^{64}\approx 1.16\times 10^{77}$ textos distintos, un número muy superior al número de estrellas del universo veces el número de granos de arena en el planeta (10.000.000.000.000.000.000.000 de estrellas en el universo 4.000.000.000.000.000.000.000 granos de arena en el mundo)...

A continuación, se define la función encriptar, que toma una frase y la guarda en formato unicode (.encode), lo encripta con sha3_256, y lo representa en hexadecimal (.hexdigest). Para facilidad de lectura, este número se escribe en mayúscula (.upper) y se parte en secuencias de cuatro dígitos.

Para probar esta función, se encripta "Bad Guy", lo cual da por resultado este código de 64 dígitos:

Para ilustrar las propiedades de la función hash, se ve cómo cambia ese código ante pequeños cambios en el texto:

¿Y si se omite el espacio?

Por lo tanto, pequeños cambios en el texto da por resultado códigos completamente distintos. Conocer los códigos de algunos textos es inútil para adivinar el mensaje encriptado en otro código.

2 Creando un bloque

Para hacer una cadena de bloques primero se necesita construir los bloques individuales. Cada bloque contiene datos, y la cadena de bloques es una secuencia ordenada de bloques de información por medio de claves criptográficas.

A continuación, se programa una clase llamada Bloque: un prototipo de bloque en el que se describe qué datos contendrá y qué acciones podrá hacer con ellos. Posteriormente se crean los bloques individuales (objetos) de la cadena a partir de este prototipo.

Bloque es una caja con información. Esto se ilustra en la figura 1, donde los datos contenidos en el bloque se muestran en cuadros rosados, y las acciones en cuadros celestes en la parte baja del bloque.

Figura 1: Clase Bloque

__init__ se utiliza para indicarle a Python cómo crear o “iniciar” un nuevo objeto. En este caso, para crear un Bloque nuevo se requiere de tres datos: índice, saldos, código_previo, que simplemente son almacenados en el bloque.

Aparte de estos tres datos, esta clase indica que cada bloque tendrá:

Además, la clase define dos métodos o acciones que puede realizar un bloque:

3 Creando la cadena de bloques

Para diseñar la cadena de bloques se crea la clase que hereda de list, lo que quiere decir que la cadena de bloques será similar a una lista pero con características especiales. Al igual que en el diseño de Bloque, estas características serán los datos que contiene la cadena (que se definen con @property) y las acciones que puede ejecutar la cadena.

Figura 2: Clase BlockChain

De nuevo, __init__ indica cómo Python debe crear o “iniciar” una nueva cadena de bloques. En este caso se crea un Bloque inicial, el bloque “génesis”.

Para crear un Bloque nuevo se necesita: índice, saldos, código_previo. Por tratarse del primer bloque, se le asigna el índice 0, con un saldo original de 0 a favor del 'Banco Central', y ningún (None) código anterior por no haber un bloque antes del inicial. Este primer bloque se agrega (.append) al final de la cadena, que hasta ahora estaba vacía.

Aparte de los bloques, la cadena contiene tres propiedades o datos:

Blockchain define seis acciones que puede hacer la cadena:

La descrición de los métodos nuevo_desafio y verificar_solucion queda para la sección 5, cuando se discute una forma de “minar” cococoins.

4 Simulación del “blockchain”

Se empieza creando el blockchain de COCOCOIN, emitiendo los primero 5000 cococoins, y revisando los saldos de la cadena:

El único saldo hasta ahora corresponde a la emisión inicial de cococoins.

Ahora, el 'Banco Central' le paga 600 cococoins a cada colaborador 'Tamar', 'Esteban', 'Jordy', 'Daniela'

Revisando los saldos:

y el registro de transacciones:

Ahora se simulan pagos aleatorios para crear 5 nuevos bloques, cada uno de los cuales tendrá un NÚMERO_DE_PAGOS aleatorio entre 3 y 6. Para cada uno de esos pagos, se eligen dos cuentas al azar, así como una cantidad aleatoria de entre 10 y 110 cococoins. El pago se procesa en la última línea:

Hay una semilla para obtener los mismos resultados cada vez (para poder reproducir los resultados, aunque los hash serán distintos porque cambia la fecha y hora de ejecución del código).

Se revisan de nuevo los saldos, y se ve de los cuatro participantes que:

Ahora se imprime la tabla completa de transacciones, y se comprueba que su detalle es consistente con la bitácora que quedó impresa más arriba:

Finalmente, se verifica la integridad de la cadena de bloques y se comprueba que la cadena está bien, porque todos los bloques siguen enlazados correctamente: la información encriptada de cada bloque corresponde con la clave previa guardada por el siguiente bloque.

Suponga ahora que un hacker logra infiltrarse en la cadena y modifica un dato, poniendo un saldo de 1000 cococoins a su favor:

Al verificar la integridad de la cadena, se detecta que ha sido adulterada porque la modificación del 'HACKER' ocasiona que el hash del bloque 3 ya no coincida con lo que el bloque 4 esperaba encontrar.

5 Minando cococoins

La cadena de bloques emite nuevos cococoins de manera sencilla: el 'Banco Central' los emite y los pone en circulación “pagándole” a 'Tamar', 'Esteban', 'Jordy', 'Daniela' 600 cocoins a cada uno. En esta situación el 'Banco Central' recibe todo el señoreaje.

Supongamos ahora que el 'Banco Central' decide “democratizar” el señoreaje e implementa un sistema “PoW” (proof-of-work o prueba de trabajo), que consiste en acreditarle 20 cococoins al primero de sus cuatro colaboradores que resuelva un problema. Un problema PoW resulta relativamente lento de resolver pero sumamente fácil de verificar que ha sido resuelto.

La prueba de trabajo se implementa en los siguientes dos métodos:

Simulando ahora un primer desafío:

'Tamar', 'Esteban', 'Jordy', 'Daniela' saben que es prácticamente imposible “invertir” el hash. Sin embargo, dado que conocen las reglas del juego, saben que ese código corresponde a un número entre 0 y 9999. Así, la alternativa que tienen es encriptar secuencialmente todos esos números y comparando los resultados con el código publicado.

En vez de ir encriptando uno a uno los números, escriben una función que hace todo el trabajo:

Esta función itera sobre todos los posibles números, los encripta y los compara con el hash. Una vez que resuelve el problema, le comunica a la cadena de COCOCOIN el resultado y el nombre del minero para que se le acrediten los fondos respectivos.

Cuando 'Tamar' empieza a minar, logra encontrar el número que el 'Banco Central' había escogido, y consigue así 20 cococoins de recompensa.

'Esteban', 'Jordy' y 'Daniela' también están interesados en ganar estos cococoins con solo tener sus propias computadoras ejecutando la función adivinar. Esta vez 'Esteban' obtiene los siguiente 20 cococoins:

Conforme aumente el valor de los cococoins, el número de interesados en minarlos irá aumentando. Dado que solo el primer minero en resolver el problema actual recibirá cococoins, compiten aumentando la capacidad computacional. Con tantos mineros y recursos dedicados a esta actividad, la velocidad con la que se resuelven los problemas aumenta y la cadena eventualmente responde aumentando el valor de $p$, para que sea cada vez más difícil resolverlos (de lo contrario se crean bloques nuevos demasiado pronto).

El resultado final de todo esto es el dilema del prisionero.

En esta situación hay dos equilibrios: el primero de ellos es un equilibrio inestable, donde todos los mineros dedican un mínimo de recursos computacionales a resolver los problemas, y el segundo es un equilibrio estable en el cual todos los mineros dedican muchísimos recursos.

El dilema se presenta porque, aunque en ambos equilibrios el premio es el mismo, el costo de minarlos en el segundo equilibrio es considerablemente mayor al del primero.

A pesar de ser socialmente deseable el primer equilibrio, ¿por qué es inestable?: porque en tal situación para cada minero es individualmente deseable dedicar más recursos a la minería, para aumentar sus propios ingresos esperados. Como todos los mineros saben esto, todos terminan dedicando más recursos a la actividad.

Esta manera de “democratizar” el señoreaje a través de la minería no es más que un gran desperdicio de energía. De hecho, el consumo energético de la red de Bitcoin es tan alto que alcanzaría para dotar permanente de electricidad a un país entero (Austria).

6 Reflexiones finales

Muchas veces no es necesario saber cómo funciona algo para sacarle provecho: no se necesita saber cómo funciona un motor de combustión interna para manejar un carro. Pero para juzgar si un sistema de pagos basado en una innovación informática es seguro y confiable, sí resulta necesario entender más.

Conociendo cómo funciona el blockchain, hay, al menos, dos reflexiones:

(1) ¿puede un sistema de pagos prescindir de la confianza?, y (2) ¿es realmente el blockchain una tecnología valiosa?

¿En quién confiamos?

Según su creador, Bitcoin fue pensado como un sistema de pagos completamente descentralizado, para sustituir lo que consideraba un sistema ineficiente

La raíz del problema con el dinero convencional es toda la confianza que se requiere para hacerlo funcionar. Debe confiarse en que el banco central no degrade el dinero, pero la historia del dinero fiduciario está lleno de incumplimientos a esta confianza. Debe confiarse en que los bancos guarden nuestro dinero y que lo transfieran de manera electrónica, pero los bancos lo prestan en olas de burbujas de crédito con apenas una fracción en reserva.

-- Nakamoto (2009), traducción libre.

Lo que parece ignorar Nakamoto es que todo sistema de pagos necesita de que sus usuarios confíen en su correcto funcionamiento. Su afirmación de que su Bitcoin es un sistema de pagos completamente descentralizado "porque todo se basa en prueba criptográfica en vez de confianza” resulta cínica.

¿Por qué? Porque lo único que hace bitcoin es obligar a sus usuarios a trasladar la confianza en las instituciones financieras a la red de pagos de Bitcoin.

Considere los siguientes casos ilustrativos:

1. al ser Bitcoin un sistema basado en tokens o fichas quedebo poseer para demostrar que son mías (como sucede con el dinero en efectivo), al resguarlas debo confiar en:

  • el dispositivo de almacenamiento (disco duro o sólido); si falla se pierden los bitcoins,
  • la seguridad de red de la computadora (en caso de que un hacker intente robarse los bitcoins)
  • memoria propia para recordar las claves.
  • 2. al utilizar un monedero en Internet para evitar los riesgos del punto 1, hay que confiar en el dueño de tal sitio web, del que posiblemente ni siquiera sé dónde está domiciliado. En este caso debo confiar tanto de su honorabilidad como de su competencia (no son infrecuentes las noticias de ciberataques a este tipo de sitios). Esto es similar a la confianza requerida para depositar efectivo en un banco.

    3. para gastar los bitcoins, es necesario confiar en los proveedores de conexión al blockchain de Bitcoin (sin esta conexión resulta literalmente imposible pagar con bitcoins). La inmensa mayoría del público carece de las competencias informáticas necesarias para conectarse directamente a Bitcoin, por lo que al final terminan confiando en proveedores de aplicaciones.

    4. según lo prometido por Nakamoto, el Bitcoin es una red “completamente descentralizada”, lo cual resultaría atractivo en tanto esto haría que el valor de Bitcoin no dependiese de las decisiones arbitrarias de un pequeño grupo de personas. Pero la descentralización de la red no implica la descentralización de los saldos de bitcoins, por lo que algunos pocos participantes en este mercado pueden manipular fácilmente su precio (Kharif 2017, Orcutt 2018).

    5. si se quiere el Bitcoin como resguardo de valor, hay confiar en que su precio será estable en el tiempo. En esto es donde peores resultados ha dado la criptomoneda, dado su enorme volatilidad, ante la cual las pérdidas de valor de la moneda fiduciaria mencionadas por Nakamoto apenas parecen visibles.

    En este último punto en específico es importante señalar que luego de la crisis financiera internacional de 2008 el dinero fiduciario de las principales economías del mundo no perdieron mucho valor (las tasas de inflación han permanecido realmente bajas en la última década). Lo que sí ocurrió fue un aumento en la variabilidad de los tipos de cambio, pero hay que recordar que un tipo de cambio es el precio relativo de una moneda en términos de otra, por lo que si una baja su valor entonces necesariamente la otra lo sube.


    Notas

    1. Este código fue tomado de Romero (2019), inspirado por por Nash (2017).

    Referencias