Hosted on bitcointuesdaymadrid.com via the Hypermedia Protocol.
Las firmas digitales son una proeza de la criptografía, las utilizamos para todo, pero … ¿y si ya estamos hartos de ellas?
Pues sí, lo estamos, y por ello vamos a dejar de usarlas aunque sea solo en este artículo...
Pero que no cunda el pánico, tranquilidad.
Si antes protegíamos nuestros fondos con firmas digitales,
ahora lo vamos a hacer de maneras mucho más creativas.
¿Te lo vas a perder?
Condiciones de Gasto
En Bitcoin, mover unos fondos no es solo cuestión de querer hacerlo; implica cumplir con una serie de cláusulas definidas dentro de la condición de gasto que los bloquea, impidiendo que se muevan. Las cláusulas más comunes incluyen algunas como "que la firma digital sea válida" o "que los hashes de dos valores sean iguales"; aunque dada la naturaleza de Bitcoin, las posibilidades son muchas más que las que usualmente empleamos.
En esencia, una transacción en Bitcoin es un proceso de desbloqueo y bloqueo de fondos: por un lado (el lado de los inputs) aporto la información necesaria para cumplir con las cláusulas que determiné como receptor de la transacción anterior, desbloqueando los fondos; y por el otro lado (el lado de los outputs) bloqueo de nuevo esos fondos bajo una nueva condición de gasto, con nuevas cláusulas, determinada por el nuevo receptor.
El sentido de este proceso es, como receptor, establecer una serie de cláusulas que solo podemos desbloquear nosotros con información que deberíamos mantener de manera confidencial, como una clave privada.
Este mecanismo es el que permite que bitcoin cambie de manos: cada nuevo receptor establecerá sus propias cláusulas dentro de una condición de gasto y aportará la información necesaria para cumplirlas cuando quiera mover los fondos que ha recibido. La red de nodos de Bitcoin dará el visto bueno a la transacción si las cláusulas son correctamente satisfechas, permitiendo que esa transacción sea inscrita en el registro descentralizado, la timechain de Bitcoin.
En cierto modo, los fondos bitcoin realmente nunca se mueven. Lo único que cambia es el acceso a los mimos, transmitiéndose de individuo a individuo la posibilidad de gastarlos y no el activo en sí. En algunas ocasiones, dispersas fracciones de bitcoin se unificarán bajo un mismo acceso (una consolidación), y en otras, una misma fracción de bitcoin se dividirá en nuevas fracciones, cada una de ellas bajo nuevos accesos. El acceso será la condición de gasto, y la información que cumple las cláusulas de la condición de gasto será la llave que abra el acceso.
Esta forma de transmitir la propiedad en Bitcoin se asemeja a la tradición instrumental en la transmisión de bienes inmuebles: cuando un individuo vende un bien inmueble a otro, el bien inmueble no cambia de lugar. Lo que ocurre es que se crea un nuevo apunte en el Registro de la Propiedad donde se cambia quien tiene derecho a poseer ese bien inmueble. Importante recalcar "derecho a poseer", puesto que en Bitcoin no tienes el derecho a poseer, posees.
Quién tiene la información para desbloquear los fondos, es el absoluto propietario. La propiedad se halla en el conocimiento, no en la opinión de otros.
Locking Script, Unlocking Script y OP_CODES
Las condiciones de gasto son conocidas formalmente como Locking Script, y las cláusulas que las componen serán un compendio de argumentos (como números) y de operadores (los OP_CODES).
La información precisa que se deberá aportar para desbloquear un Locking Script, tiene el nombre de Unlocking Script y contendrá los argumentos y los operadores necesarios para que, una vez ejecutados en conjunto con el Locking Script, los nodos puedan dar validez a esa transacción.
Un script será, por tanto, un pequeño programa compuesto por argumentos y operadores embebido en cada transacción.
Imaginemos el caso en que hemos bloqueado unos fondos con el siguiente Locking Script:
OP_2 OP_ADD OP_4 OP_EQUAL
Donde la cláusula que establecemos es: "aporta un número tal que sumado (OP_ADD) a dos (OP_2), sea igual (OP_EQUAL) a cuatro (OP_4)"
¿Fácil de resolver, no? El Unlocking Script que desbloquea este Locking Script lucirá tal que así:
OP_2
Ambos, el Locking y el Unlocking Script, son pequeños programas que indican al nodo que debe hacer gracias a los operadores (OP_CODES) que hay dentro. En este caso, el script está conformado solo por OP_CODES que se ejecutarán comenzando por el Unlocking Script y finalizando con el Locking Script:
OP_2 OP_2 OP_ADD OP_4 OP_EQUAL
En Bitcoin la ejecución siempre se hará tal que así, tomando los operadores de izquierda a derecha y ejecutándolos en formato de pila en la que los últimos en llegar son los primeros en salir (LIFO); operándose siempre sobre los elementos de más arriba del stack de la pila:
El estado de la pila cambiará según los operadores que sean empleados sobre la misma
Primero se añade el 2 (OP_2) a la pila, el cual era el operador aportado por el Unlocking Script. Acto seguido se añade de nuevo 2 (OP_2) y se suman ambos valores de la pila (OP_ADD). Después se añade 4 (OP_4) y finalmente se comparan si los dos elementos de arriba de la pila son iguales (OP_EQUAL). De ser así, este operador eliminará esos dos elementos superiores de la pila y añadirá "True" al stack, confirmando que la validación del script ha sido exitosa.
Si el Unlocking Script aportado fuera OP_3 en vez de OP_2, el resultado de la suma hubiera sido 5, provocando que OP_EQUAL devuelva "False" (5 ≠ 4); haciendo que la transacción sea inválida.
Y ahora veamos otro ejemplo, con un Locking Script que quizá te resulte más familiar:
<ClavePública> OP_CHECKSIG
Este es el Locking Script de la condición de gasto P2PK (las direcciones que empiezan por 02, 03 y 04), donde la cláusula que definimos es: "aporta una firma digital válida (OP_CHECKSIG) que haya sido creada con la misma Clave Privada desde la que se derivó la Clave Pública (<ClavePública>)"
En este caso, el Unlocking Script será la Firma Digital:
<SIGNATURE>
El script completo que ejecutará el nodo una vez se aporte el Unlocking Script será:
<SIGNATURE> <ClavePública> OP_CHECKSIG
Donde el operador OP_CHECKSIG tomará los argumentos <SIGNATURE> y <ClavePública> para corroborar la validez. (Nota 1)
El conjunto de operadores que hay en Bitcoin y la lógica de ejecución basada en pilas, conforman lo que conocemos como Bitcoin Script. Su función es crucial: reducir posibles errores y reducir el tamaño de las transacciones.
Cada operador es una llamada a una función específica ya determinada en el código del nodo.
Por ejemplo, cuando en una condición de gasto es necesario comparar si dos valores son iguales, si no tuviéramos los operadores, habría que introducir en la transacción en sí todas estas líneas de código para realizar esa acción:
case OP_EQUAL:
{
    if (stack.size() < 2)
        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
    valtype& vch1 = stacktop(-2);
    valtype& vch2 = stacktop(-1);
    bool fEqual = (vch1 == vch2);
    popstack(stack);
    popstack(stack);
    stack.push_back(fEqual ? vchTrue : vchFalse);
}
break;

#¿Te imaginas tener que meter todas estas líneas en una transacción? 
#Qué pereza, menos mal que el tito Satoshi nos lo dejó fácil.
Sin embargo, con tal solo incluir la partícula en hexadecimal "87" en el script, el nodo validador entenderá que hay que interpretar ese 87 como el operador OP_EQUAL, ejecutándolo y comparando si los dos últimos valores son equivalentes. La ejecución de cada operador se encuentra recogida en el archivo "interpreter.cpp" del código de Bitcoin Core.
Esto es, gracias a los operadores, se están moviendo las líneas de código de la transacción al nodo. Se reduce el tamaño de la misma, se reducen los posibles errores y más importante aún: se estandarizan las funciones empleadas, dificultando enormemente que una transacción contenga un script que haga crashear a los nodos y facilitando que el código de Bitcoin pueda ser ejecutado por la mayor cantidad de dispositivos. (Nota 2)
En su forma más pura la transacción es en realidad un metaprograma, que llama a otros programas o funciones (los operadores) y que a su vez contiene la información necesaria para que esos operadores puedan ejecutarse. Un metaprograma que, aunque autosuficiente hasta cierto punto, necesita acoplarse a otros metaprogramas del pasado para ser considerado válido.
Sin lugar a duda, Bitcoin Script es una implementación brillante por parte de Satoshi.
La Estandarización
¿Y de qué manera empleamos los scripts en Bitcoin?
Bueno, es bastante sencillo. Los empleamos constantemente cada vez que hacemos una transacción. Ya sea de manera manual o con una aplicación que nos simplifica el proceso, estaremos aportando en lado de los inputs el Unlocking Script necesario para desbloquear los fondos a gastar y en el lado de los outputs, la condición de gasto (Locking Script) que el receptor haya establecido.
Aunque hay un pequeño detalle: la Estandarización.
La estandarización limita nuestro libre albedrío, como receptor de unos fondos, a la hora de construir condiciones de gasto con los operadores y argumentos que deseemos.
Es el conjunto de reglas que deben cumplir las transacciones para que éstas se retransmitan por la red. Es decir, la transacción puede ser válida, pero si no cumple estas reglas, los nodos no la irán pasando hasta llegar al nodo minero. (Nota 3)
Entre estas reglas se establece que solo se retransmitirán transacciones cuyos Locking Scripts de los outputs (las condiciones de gasto que impone el receptor) sean alguno de los siguientes tipos:
P2PK, P2PKH, P2SH, P2MS, OP_RETURN, P2WPKH, P2WSH, P2TR, P2A
Cada tipo tiene una serie de argumentos y operadores ya determinados, y si no se siguen, la transacción no se retransmitirá (aunque sea válida). Algunas de estas condiciones de gasto se pueden codificar en formato de una dirección, facilitando el envío de fondos tanto para el emisor como para el receptor. Es importante recalcar que las direcciones no forman parte de la timechain en sí, sino que son un estándar diseñado específicamente para simplificar y estandarizar el proceso de envío de fondos.
P2SH
Entonces, ¿cómo es posible bloquear los fondos a un Locking Script como el que veíamos OP_2 OP_ADD OP_4 OP_EQUAL si ninguno de los tipos que son estándar contempla esos operadores?
Es decir, ¿de qué manera podemos emplear scripts que sean creativos a la hora de bloquear fondos?
Es aquí donde llega nuestro salvador, P2SH.
P2SH, Pay-to-Script-Hash, es una condición de gasto estándar, que permite enviar fondos al hash de un script.
Y es ahí donde está la ventaja: el script (la condición de gasto) que va a ser hasheado puede ser el que sea, el que el receptor de los fondos quiera, no hay una reglas de estandarización que limiten el conjunto de operadores que se pueden emplear. (Nota 4)
Ese script puede ser el correspondiente a una de las condiciones de gasto que ya son estándar como P2PKH (lo que es conocido como un script anidado) o por el contrario, puede ser una condición de gasto totalmente nueva y creativa, con cláusulas únicas.
Y el potencial de esto es, como puedes imaginar, abismal.
Habilita formas avanzadas de custodia que emplean scripts más complejos para aumentar el nivel de seguridad los fondos, a la vez que se pueden construir scripts que bloqueen los fondos de maneras muy originales.
¿Y cómo funciona P2SH?
P2SH es un tipo de condición de gasto estándar que permite encapsular todo tipo de condiciones de gasto, ya sean estándar o no estándar; y lo hace tomando el hash de las mismas.
Esto es, los fondos no se bloquean en una condición de gasto visible, sino en su versión hasheada, lo que mejora la privacidad y la eficiencia. Para posteriormente gastarlos, es imprescindible revelar la condición de gasto original (Locking Script), demostrando que su hash coincide con el registrado y aportar el Unlocking Script que la satisface.
Cuando se aporta nuevamente el Locking Script original, este recibe un nuevo nombre: Redeem Script (Script de Canjeo).
Dado que la validación requiere el Redeem Script para comprobar que su hash coincide con el hash de destino de los fondos, no basta con proporcionar un Unlocking Script válido: es imprescindible conservar también el Redeem Script. De lo contrario, los fondos quedan bloqueados sin posibilidad de ser gastados.
Este mecanismo beneficia al emisor de la transacción, ya que independientemente de la complejidad del Locking Script diseñado por el receptor, el hash al que se envían los fondos siempre tiene un tamaño fijo. Así, si el receptor crea un Locking Script extenso o complejo, será él quien asuma los mayores costos en fees al gastar los fondos, no el emisor.
Veámos todo esto con el ejemplo que ya conocíamos:
Los fondos se envían al hash de OP_2 OP_ADD OP_4 OP_EQUAL, que en su representación en Bitcoin Script se codifica como la cadena hexadecimal 52935487. Esta cadena, al pasar por la función HASH160, se convierte en un hash de 20 bytes:
ec12fd48e32f2f51d5580ba4bb0c15aa79fae6ca
Este hash se combina con los operadores propios de P2SH para formar el Locking Script:
OP_HASH160 OP_PUSHBYTES20 <ec12fd48e32f2f51d5580ba4bb0c15aa79fae6ca> OP_EQUAL
Quedando el Locking Script tal que así:
a914ec12fd48e32f2f51d5580ba4bb0c15aa79fae6ca87
Aquí, a9 indica al nodo que debe aplicar OP_HASH160, 14 especifica que los siguientes 20 bytes se deben añadir al stack (los correspondientes al hash del script), y 87 señala que debe ejecutarse OP_EQUAL, verificando así la equivalencia de hashes.
A nivel visual, este Locking Script completo se podrá codificar como una dirección del tipo P2SH (las que comienzan por "3"):
3PDG9Dpnf55LUVE6usVc7uLE6oBx63batJ - parece que nadie ha enviado, por ahora, fondos a este pequeño "puzzle matemático".
A la hora de gastar estos fondos, dentro del Unlocking Script se deberá aportar tanto lo necesario para desbloquear la condición de gasto, en nuestro caso "OP_2" , como el Redeem Script "52935487", en ese orden.
Es decir, el Redeem Script es parte del Unlocking Script al ser necesario para comprobar que los hashes son equivalentes.
La verificación seguirá los siguientes pasos:
    Comprobación del Hash
Tomaremos el Script completo: Unlocking Script (Unlocking Script + Redeem Script) + Locking Script
OP_2 OP_PUSHBYTES4 <52935487> OP_HASH160 OP_PUSHBYTES20 <ec12fd48e32f2f51d5580ba4bb0c15aa79fae6ca> OP_EQUAL
Y se ejecuta:
Si se da la equivalencia de hashes, la comprobación es exitosa y da comienza el siguiente paso:
    Comprobación del Script
Donde antes el nodo interpretaba el Redeem Script como una cadena hexadecimal de texto "52935487", ahora la descompondrá y la reinterpretará como la cadena de operadores que es: "OP_2 OP_ADD OP_4 OP_EQUAL"
Y tomando de nuevo el Unlocking Script "OP_2" se verificará que efectivamente se desbloquea el Redeem Script, tal y como demostrábamos al principio:
OP_2 OP_2 OP_ADD OP_4 OP_EQUAL
Nos ponemos creativos
Aplicando todo lo que ya sabes, vamos a utilizar ecuaciones para bloquear fondos.
Sí, ecuaciones, de esas que tanto te gustaban en el instituto; don't worry my friend, estas serán sencillitas.
Además vamos a descubrir cómo Peter Todd propuso una serie de retos con premios muy suculentos.
Te adelanto que todavía estás a tiempo de llevarte alguno de esos jugosos premios, pillín. Aunque también te adelanto que dudo que lo consigas. Ya verás por qué. Bueno, y si lo consiguieras, te invito a unas cañas (o mejor invitas tú, que te has llevado el premio).
Con Ecuaciones
La ecuación a resolver va a ser la siguiente:
6e - OP_2DUP - Duplica los dos elementos superiores de la pila
93 - OP_ADD - Suma los dos elementos superiores de la pila
59 - OP_9 - Añade el valor 9 a la pila
88 - OP_EQUALVERIFY - Comprueba que los dos valores superiores son iguales, de ser así permite que continúe la ejecución.
94 - OP_SUB - Resta al segundo elemento el primero
53- OP_3 - Añade el valor 3 a la pila
87 - OP_EQUAL - Comprueba que los dos valores superiores son iguales, de ser devuelve True
¿Qué porqué he utilizado OP_EQUALVERIFY para la primera comprobación y OP_EQUAL para la segunda? Porque puedo. Y porque así aprovecho para explicarte algo más, para lo cual tendrás que ir al apartado "EXTRA: True or False" Que no te quite el sueño este detalle.
Y ahora, volviendo a la ecuación, saca papel y lápiz, y resuélvela.
...
¿Ya? Te tiene que salir x=6, y=3
Entonces, el Unlocking Script que desbloquee esta condición de gasto será "5653", donde:
56 - OP_6 - Añade el valor 6 a la pila
53 - OP_3 - Añade el valor 3 a la pila
La ejecución completa será tal que así:
5653 (Unlocking Script) + 6e935988945387 (Locking Script)
Al ser un Locking Script no estándar, se debe meter dentro de la condición de gasto P2SH. Esto es justo lo que hice en la red de test de Bitcoin "Testnet4":
https://mempool.space/es/testnet4/tx/243ec1806d8eb9cd4bb9339a45ffaae629de283e171812d1cde154692fc3ac18
Cuando codificas ese Locking Script en una dirección, tras hacerle el HASH160 y añadirle los OP_CODES propios de P2SH, queda tal que así en Testnet4:
2NEL5vpFifNyJcyTpdYYgx4wsQw6AtUw8Tk
Y una vez queramos gastar esos fondos, aportaremos el Unlocking Script que veíamos "5653" junto con el Redeem Script. Se verificará que el hash del Redeem Script coincide con el del Locking Script, y de ser así, se ejecutará el script completo, tal y como vemos un poco más arriba.
Eso mismo hice para gastar los fondos, y enviarlos de nuevo a una dirección P2PKH de Testnet4 bajo mi control "myjkHN5wWMbKTteqsTxC8NyWB9hP69g2B2":
https://mempool.space/es/testnet4/tx/95fa867e78213c52632ca2ca7eae93060d7cea945c52bfa3f9798eed8c05ad3d
Aunque si te fijas, hay un pequeño detalle: hay dos transacciones y los fondos no fueron a la dirección que yo quería originalmente. ¿Alguien me ha atacado y se ha quedado con lo que me pertenecía? Stay Tunned
Los Retos de Peter Todd
En Bitcoin Script aparte de existir operadores que te permiten hacer operaciones matemáticas, comparar elementos, comprobar firmas digitales o incluso cambiar de posición elementos dentro de la pila, existe un conjunto de OP_CODES que son los necesarios para hashear un elemento de la pila.
Estos OP_CODES son:
    SHA1
    SHA256
    RIPEMD160
    HASH256 = SHA256(SHA256)
    HASH160 = RIPEMD160(SHA256)
Principalmente son usados para, como ocurre en P2SH o en P2PKH, comprobar que efectivamente el hash de un argumento dado coincide con un hash que previamente fue proporcionado en el Locking Script.
Las funciones de Hash no deberían tener colisiones, esto es, no deben existir dos inputs distintos que generen el mismo output tras ser hasheados. Esta característica es base para la seguridad de la función de hash.
Esto permite proponer una serie de retos muy curiosos: buscar dos argumentos distintos que una vez hasheados tengan el mismo hash. Es decir, encontrar una colisión en las de las funciones de hash.
Justo lo que propuso Peter Todd en Septiembre de 2013: un total de 5 desafíos basados en buscar la colisión de las distintas funciones de Hash, con un premio que con el tiempo ha ido subiendo, y de los cuales solo uno ha sido resuelto: en 2017 se encontró una colisión en el SHA 1, como ya se predecía en 2012. Y alguien empleó esa colisión para llevarse el premio del primero de los retos. 2,48 BTC.
El funcionamiento del Locking Script que comprueba que la colisión es correcta, es ingenioso:
Dados dos argumentos distintos "Arg1" y "Arg2", primero se comprueba si son efectivamente distintos el uno del otro: se duplican y se utiliza el operador OP_EQUAL para comprobar si son iguales. Si no lo son, este operador devuelve False. Con el operador OP_NOT, lo que era False pase a ser True (Not False = True), para que el operador OP_VERIFY permita que se siga ejecutando el script.
¿Qué sentido tiene esto? Bueno, veámoslo al revés. Si los dos argumentos son iguales en inicio, el operador OP_EQUAL devolverá "True". Se convertirá en "False" gracias a OP_NOT y dado que OP_VERIFY solo deja que continúe la ejecución si el elemento superior de la pila es True, pues no permitirá que continúe dado que es False.
De esta forma se comprueba que son argumentos distintos en origen. Una vez ha pasado esa prueba se hace el hash de cada uno y se comprueba finalmente que los hash coinciden, esto es, que existe una colisión dados los argumentos "Arg1" y "Arg2".
Esta ejecución es similar para el resto de retos, cambiando únicamente los operadores correspondientes a las funciones de Hash.
Si eres capaz de encontrar una colisión en las funciones de Hash restantes, adelante, tienes unas buenas recompensas que obtener.
Eso sí, un detalle: romper SHA1, la función de Hash más débil presente en Bitcoin, no fue cuestión de fuerza bruta. Habrían hecho falta 12 millones de años de computación. En su lugar, se usaron métodos mucho más sofisticados. Suerte :D
Ataques y la Necesidad de usar Firmas Digitales
Si recuerdas, en el ejemplo de bloquear fondos con ecuaciones, vimos como al probarlo en Testnet4 los fondos no fueron a la dirección que yo especifiqué, sino a otra. Alguien se había quedado con los fondos.
Ese alguien fui yo, para demostrar lo fácil que es quedarse con fondos ajenos cuando no se utilizan Firmas Digitales.
No usar Firmas Digitales hace vulnerables tus fondos, cosa que ya adelantaba en mi anterior entrada al blog "Si haces vulnerables tus bitcoin, no llores cuando alguien se los lleve".
Cuando retransmitimos una transacción con un Unlocking Script que no está ligado a la propia transacción (como ocurre cuando resolvemos el reto matemático de las ecuaciones o cuando resolvemos el reto de la colisión de hashes), estaremos dando a conocer la solución al Locking Script y dando la posibilidad, hasta que se confirme nuestra transacción, de que otro individuo tome esa misma solución y construya una nueva transacción que gaste esos fondos pero mandándolos hacia otro lugar.
Es por ello que empleamos Firmas Digitales, dado que demuestran tanto que tienes la Clave Privada correspondiente, como que el mensaje firmado (la transacción) no ha sido modificado.
Esto ocurre puesto que a la hora de firmar digitalmente, el mensaje es introducido como variable para crear la firma digital; ligándose de esta forma la firma al mensaje firmado.
Y es justo eso lo que permite que cuando retransmitimos una transacción que desbloquea los fondos con Firmas Digitales, nadie se atreva a atacarnos cambiando por ejemplo los outputs, puesto que la verificación fallará. (Nota 5)
Puedes indagar más sobre este tema tanto en mi artículo "Firmas Digitales en Bitcoin - ¿Lo tuyo es tuyo?" como en "Maleabilidad en Bitcoin".
El propio Peter Todd, al final del mensaje que envía por el foro Bitcoin Talk en septiembre de 2013 anunciando los retos de colisión de hashes, aclara que si obtienes la solución a uno de los retos seas tu mismo quien mine el bloque donde se confirme esa transacción, sin retransmitirla por la red:
"We advise mining the block in which you collect your bounty yourself; scriptSigs satisfying the above scriptPubKeys do not cryptographically sign the transaction's outputs. If the bounty value is sufficiently large other miners may find it profitable to reorganize the chain to kill your block and collect the reward themselves. This is particularly profitable for larger, centralized, mining pools." ~ Peter Todd
Una buena opción actualmente sería contactar con una pool de minería y firmar un contrato con ellos por el cual minan tu transacción (a cambio de una parte de la recompensa), dada la dificultad de minar actualmente por tu cuenta el bloque en cuestión. Hablo de firmar un contrato, porque de lo contrario, nada te asegura que ellos se queden con tus fondos.
A futuro
Más allá de usar P2SH como encapsulamiento de condiciones de gasto que proponen retos novedosos y en todo caso anecdóticos, P2SH es empleado formas avanzadas de autocustodia.
Desde bloqueos de fondos que necesitan las firmas digitales de hasta 15 claves privadas para ser desbloqueados, hasta condiciones de gasto que proponen nuevos esquemas de propiedad: sistemas de herencia donde los herederos se han de poner de acuerdo, bóvedas con apertura retardada para protegerte ante ataques de "llave inglesa", la posibilidad de incluir un árbitro (como un notario) a la hora de gastar unos fondos que pertenecen a varias personas...
Y todo eso, dentro de Bitcoin. Sin necesidad de acudir a otras soluciones fuera de la red de Bitcoin, todo posibilitado por los operadores que ya están presentes y por implementaciones ingeniosas que facilitan la creación de este tipo de condiciones, como MiniScript.
Aunque esta madriguera de Bitcoin y todo lo que va a traer, lo dejo para un próximo artículo.
Por ahora, si quieres ver algo chulo creado con MiniScript, échale un vistazo a lo que está haciendo José Luis Landabaso con el wallet Rewind Bitcoin. Si lo haces, estarás viendo el futuro.
Conclusión
Hemos conseguido evitar el uso de Firmas Digitales en este artículo. Prueba superada.
Eso sí, es inevitable e ilógico no emplearlas si nuestro objetivo es bloquear fondos de manera segura.
"Las condiciones de gasto lo son todo en Bitcoin. Un sistema donde eres propietario si puedes desbloquear unos fondos. He aquí el radical cambio: la propiedad se haya en el conocimiento, no en la opinión de otros. A Bitcoin solo le importa si eres capaz de desbloquear no quien seas. Realmente los bitcoin siempre están ahí."
EXTRA: True or False
En cualquier ejecución de un script en Bitcoin, es necesario que quede como único elemento final en la pila el número 1 (OP_1). Este número es interpretado como "True" (verdadero) y permitirá que el nodo validador de por bueno ese script. Si quedan otros valores, o queda "False", el nodo validador rechazará el script, dando por inválida la transacción.
Partiendo de esto, existe un operador "OP_VERIFY" que permite comprobar en cualquier punto de la ejecución si el elemento de más arriba de la pila es True (1). Si es True, permite que la ejecución continúe y elimina ese elemento de la pila. De ser False (0), corta la ejecución.
Otros operadores como OP_EQUAL o OP_CHECKSIG, devuelven True si los dos valores de arriba de la pila son iguales o si la Firma Digital es válida, respectivamente.
Con tal de hacer más eficiente la ejecución, existen variantes de estos operadores que ya incluyen el OP_VERIFY: OP_EQUALVERIFY, OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY...
Es decir, no solo hacen la función para la que están predeterminados, sino que también ejecutan OP_VERIFY acto seguido.
Si por algún casual dejáramos uno de estos operadores que están combinados con OP_VERIFY al final de la ejecución, provocaríamos que se eliminara el True de la pila y para cuando el nodo compruebe si ha quedado un True en la pila, no habría nada, dando por inválida la transacción.
Por ejemplo, en el Locking Script de la condición de gasto estándar P2PKH se ve claramente:
"OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG"
Con OP_EQUALVERIFYse comprueba que los dos elementos de arriba de la pila son iguales. Si lo son, OP_EQUAL devuelve True y OP_VERIFY comprueba que efectivamente es True, eliminándolo y permitiendo que continúe la ejecución.
Con OP_CHECKSIG se comprueba que la Firma Digital es válida. De ser así, se devuelve True y como es el último elemento que queda en la pila, el nodo dará por válida la transacción.
Si se hubiera utilizado OP_CHECKSIGVERIFY, el True que devuelve OP_CHECKSIG habría sido eliminado de la pila y no quedaría ningún True en la pila, provocando que el nodo diera por inválida la transacción.
Notas:
Nota 1: Delante de cada dato (como un número) que se emplea en la comprobación de un script, siempre va un operador llamado "OP_PUSH(bytes)" o "OP_PUSHBYTES <bytes>" que indica al nodo que debe tomar los siguientes bytes como una pieza de información que debe añadir al stack de la pila.
Nota 2: No se pueden crear scripts que usen líneas de código o programas fuera de los OP_CODES disponibles. Esta característica de Bitcoin, aunque beneficiosa en muchos aspectos, genera debates sobre cómo dirigir la escalabilidad de la red, ya sea mediante la incorporación de nuevos OP_CODES o la reactivación de aquellos deshabilitados en el pasado. Estos operadores podrían habilitar nuevas funcionalidades o hacer los procesos actuales más eficientes.
Nota 3:
Por un lado tenemos las "Reglas De Validación" o de consenso, definidas en el archivo script.cpp, las cuales son obligatorias para que una transacción sea válida en la red de Bitcoin. Si cambian haciéndose incompatibles con las anteriores, estaremos ante un hard-fork. Si cambian haciéndose más restrictivas pero compatibles con las anteriores, estaremos ante un soft-fork.
Por el otro lado tenemos las "Reglas de Estandarización" definidas en el archivo policy.h, las cuales restringen lo ya acotado por las Reglas de Validación, con el objetivo principal de mantener la red de Bitcoin eficiente. Es decir, si tenemos acceso a un minero o somos el propio minero, podríamos emitir y confirmar una transacción que no cumpla las Reglas de Estandarización, siempre y cuando sea válida.
Si cambian estaremos ante un soft-fork que restringirá de distinta forma qué transacciones se retransmiten por la red, aunque esto no impedirá que otras implementaciones de Bitcoin que no sean Bitcoin Core tengan su propio conjunto de normas.
Diferentes implementaciones de Bitcoin solo necesitan cumplir con las de validación, siempre y cuando haya mineros que las añadan.
Nota 4: Si existen limitaciones por las reglas de estandarización de cómo debe ser el Locking Script (Redeem Script) que hemos creado, como que no supere los 520 bytes de tamaño.
Nota 5: Excepto si firmas con un SigHash que permita modificar los outputs.
Nota EXTRA: Los argumentos que provocan una colisión en el SHA1 son los siguientes,
255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017f46dc93a6b67e013b029aaa1db2560b45ca67d688c7f84b8c4c791fe02b3df614f86db1690901c56b45c1530afedfb76038e972722fe7ad728f0e4904e046c230570fe9d41398abe12ef5bc942be33542a4802d98b5d70f2a332ec37fac3514e74ddc0f2cc1a874cd0c78305a21566461309789606bd0bf3f98cda8044629a1
255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de218f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d23c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1
Prueba a hashearlos (en formato hex)!
Nota EXTRA2: Hasta la versión 0.9.2 de Bitcoin Core, solo se podían introducir scripts estándares dentro de P2SH.
Agradecimientos:
Agradecer a @PatrimonioBTC por su inestimable ayuda con la revisión del artículo.