Una cadena de bloques no es más que datos ligados entre sí por hashes. Entender qué es un hash alcanza para entender por qué reescribir el pasado en una blockchain es tan costoso.
Qué hace una función hash
Una función hash criptográfica toma una entrada de cualquier tamaño y devuelve una salida de tamaño fijo. SHA-256 devuelve siempre 256 bits, que solemos escribir como 64 caracteres hexadecimales. Tres propiedades nos interesan:
- Es determinista: la misma entrada da siempre la misma salida, en cualquier computadora.
- Es difícil de invertir: a partir del hash no hay forma práctica de recuperar la entrada, salvo probar candidatos.
- Es sensible a cualquier cambio: una diferencia mínima en la entrada produce un hash que no se parece al anterior. Es el llamado efecto avalancha.
Podés comprobarlo en una terminal. La diferencia entre las dos entradas es una sola letra:
$ printf 'hola' | sha256sum
b221d9dbb083a7f33428d7c2a3c3198ae925614d70210e28716ccaa7cd4ddb79
$ printf 'holA' | sha256sum
e028fa3463f8bbcb76607c0819bd85103de648004fcabb0648ce3662459956f4
Entre esos dos hashes difieren 131 de los 256 bits, es decir, un poco más de la mitad. No hay forma de "acercarse" a un hash buscado cambiando la entrada de a poco.
De un hash a una cadena
Un bloque agrupa transacciones y un encabezado. Según la documentación de Ethereum, ese encabezado incluye, entre otros campos, el hash del bloque padre (parent_hash), la raíz de las transacciones (transactions_root) y la raíz del estado (state_root). El hash del bloque se deriva de esos datos, de modo que cada bloque queda atado al anterior: si cambia algo en un bloque, cambia su hash, y el bloque siguiente guardaba el hash viejo.
Para verlo sin la complejidad de una red real, este programa en Python arma una cadena mínima de tres bloques. Cada uno guarda sus datos, el hash del anterior y su propio hash, calculado sobre ambos:
import hashlib
def sha(texto):
return hashlib.sha256(texto.encode()).hexdigest()
def bloque(previo, datos):
return {"previo": previo, "datos": datos, "hash": sha(previo + datos)}
cadena = [bloque("0" * 64, "Ana paga 5 a Beto")]
cadena.append(bloque(cadena[-1]["hash"], "Beto paga 2 a Carla"))
cadena.append(bloque(cadena[-1]["hash"], "Carla paga 1 a Ana"))
def valida(cadena):
for i, b in enumerate(cadena):
if b["hash"] != sha(b["previo"] + b["datos"]):
return f"bloque {i}: su contenido no coincide con su hash"
if i and b["previo"] != cadena[i - 1]["hash"]:
return f"bloque {i}: el hash previo no coincide con el bloque {i - 1}"
return "cadena válida"
print(valida(cadena))
cadena[0]["datos"] = "Ana paga 50 a Beto" # adulteramos el bloque 0
print(valida(cadena))
cadena[0]["hash"] = sha(cadena[0]["previo"] + cadena[0]["datos"]) # recalculamos su hash
print(valida(cadena))
La salida de esta ejecución es:
cadena válida
bloque 0: su contenido no coincide con su hash
bloque 1: el hash previo no coincide con el bloque 0
Por qué el atacante no puede "arreglarlo"
Mirá la tercera línea de salida. Después de modificar el bloque 0 recalculamos su hash para que sea consistente, y aun así la cadena sigue rota: ahora el que no cierra es el bloque 1, que conserva el hash viejo de su padre. Para repararlo habría que recalcular el bloque 1, lo que cambia su hash y rompe el bloque 2, y así hasta el final de la cadena.
En una red real el problema es mayor, porque no hay un único dueño de la cadena. Cada nodo mantiene su copia y verifica los bloques que recibe, así que una versión adulterada simplemente no es aceptada por el resto. En las redes con prueba de trabajo, además, cada bloque reescrito exigía repetir el trabajo computacional que lo respaldaba, y la red daba por válida la cadena con más trabajo acumulado. Ethereum dejó de usar prueba de trabajo en 2022 y hoy usa prueba de participación (proof of stake), con otro mecanismo de consenso, pero el encadenamiento por hashes sigue siendo la base de la detección de cambios.
Una salvedad sobre el algoritmo
El ejemplo usa SHA-256. Solidity ofrece como funciones integradas tanto sha256 como keccak256, y esta última es la que se usa habitualmente en contratos de Ethereum. Son funciones distintas: no esperes obtener el mismo valor de una y de otra para la misma entrada. Tené presente también que Solidity eliminó en la versión 0.5.0 el alias sha3 de keccak256, así que conviene leer siempre el nombre exacto de la función que usa cada herramienta.
Lo que un hash no garantiza
El encadenamiento hace que los cambios sean detectables, no que la información sea verdadera. Un hash no dice si la transacción original era honesta, ni quién la firmó: para eso están las firmas digitales y el consenso. Tampoco oculta el contenido si es predecible; hashear un dato con pocas variantes posibles permite descubrirlo probando todas.
Fuentes
Verificadas el 27/10/2026. Los ejemplos de código se compilaron y probaron con Foundry (Solidity 0.8.33, OpenZeppelin Contracts 5.7.0) y Python 3.