Home < Advancing Bitcoin < Advancing Bitcoin 2019 < Advancing Bitcoin 2020 < Andreas Antonopoulos < Austin Bitcoin Developers < Baltic Honeybadger < Bit Block Boom < Bitcoin Core Dev Tech < Bitcoin Design < Bitcoin Magazine < Chaincode Labs < Greg Maxwell < Lets Talk Bitcoin Podcast < Misc < Andrew Poelstra - Miniscript Introducción (2020-02-06)

Andrew Poelstra - Miniscript Introducción (2020-02-06)

Transcripción De: Michael Folkson

Traducción Por: Blue Moon

Tags: Miniscript, Cartera

Categoría: Conferencia

Nombre: Andrew Poelstra

Tema: Introducción a Miniscript

Locación: El avance de Bitcoin

Día: 6 de febrero de 2020

Vídeo: https://www.youtube.com/watch?v=eTUuwASdUBE

Diapositivas: https://www.dropbox.com/s/vgh5vaooqqbgg1v/andrew-poelstra.pdf

Introducción

Hola a todos. Algunos de vosotros estuvisteis en mi presentación de Bitcoin sobre Miniscript hace un par de días donde me las arreglé para pasar más de 2 horas dando una presentación sobre esto. Creo que esta vez la he reducido a 20 minutos, pero no prometo nada. Voy a mantener un ojo en el reloj.

Descriptores

Es muy agradable tener esto programado inmediatamente después de la charla de Andrew Chow sobre descriptores de salida porque hay una buena transición aquí. Como Andrew mencionó la forma en que la cartera de Bitcoin Core solía trabajar y todavía funciona es esta cosa de la bolsa de claves. Tienes un montón de claves de curva elíptica y éstas se interpretan de la manera que sea conveniente en ese momento. Esto da lugar a un modelo de usuario desordenado y a cosas potencialmente extrañas como la posibilidad de que terceros manipulen las direcciones de forma inesperada. Los descriptores solucionan esto básicamente siendo mucho más precisos sobre la forma en que se supone que se utilizan las claves y también siendo más expresivos. Pero, como ha señalado Andrew, hay más formas de que los descriptores sean expresivos y eso nos lleva a Miniscript. Hay cosas como las multifirmas, varias políticas de claves múltiples y sería bueno que los descriptores pudieran soportar ahora que tenemos una buena representación legible de ingeniería de las cosas.

Hay un montón de casos de uso, incluso para los usuarios ordinarios. No se trata necesariamente de cosas como Lightning o protocolos complicados o cualquier cosa en la que se necesiten múltiples claves. Los usuarios ordinarios que sólo quieren tener múltiples carteras de hardware redundantes como Stepan (Snigirev) estaba hablando podría querer usar multifirmas. La gente que quiera tener una clave de respaldo, un interruptor de hombre muerto en el que si pierden sus claves calientes después de un tiempo todavía pueden recuperar sus monedas. Eso es algo sensato. Eso requeriría un bloqueo de tiempo o algo así. Entonces, estas cosas también podrían estar incrustadas en algún esquema más grande. Puedes imaginar a alguien que quiere hacer esta complicada multifirma para sus propios fines, pero que es un participante en un esquema más grande. Por ejemplo, están en una cartera de custodia dividida, tienen una contraparte que va a refrendar todas sus transacciones. Tal vez les gustaría hacer algo interesante y la contraparte, con suerte, no debería tener que decodificar scripts extraños para entender lo que el usuario está haciendo. O tal vez son parte de un conjunto de custodia o una junta para una empresa que tiene un montón de Bitcoin como Blockstream decir. Ellos tienen su propia y complicada configuración de múltiples claves. Todo el mundo que trabaja en Blockstream tiene su propia y complicada cosa de multiples claves. ¿No sería genial si todos pudieran aportar sus políticas a la mesa y pudiéramos combinarlas y tener algún umbral? Digamos 3 de 5 personas u 8 de 10 o el número que podamos conseguir. Cada una de esas políticas individuales era algo complicado. Este es el tipo de cosas que son muy difíciles de hacer hoy en día porque no tenemos una buena manera de representar guiones complicados.

La forma en que representamos los guiones es a través de esta cosa llamada guión de Bitcoin. He estado usando esta palabra script pero lo que estoy tratando de insinuar son las políticas de gasto. Pero la forma en que se implementa es Bitcoin script. El script puede hacer todo tipo de cosas interesantes. Un ejemplo interesante es que Peter Todd tiene algunas monedas por ahí que pueden ser tomadas si puedes encontrar una colisión de hash. Hay una para SHA1 que ha sido tomada. Hay otras para SHA2 y RIPEMD que no han sido tomadas. Eso es algo genial que puedes hacer con un script. En la práctica, lo que la gente suele hacer es utilizar un script para comprobar las firmas con ciertas claves, comprueban las preimágenes de hash para cosas como los intercambios atómicos y los HTLCs de Lightning y comprueban los timelocks para cosas como estos cambios de hombre muerto o retrocesos o construcciones de reclamación de reembolso. Luego componen estos en varias formas llamadas funciones monótonas. Una función monótona es sólo ANDs y ORs y umbrales. Poniendo las cosas juntas en algún árbol de ANDs y ORs y umbrales.

Conceptualmente estas funciones monótonas de varias condiciones de gasto, son políticas de gasto, no son realmente scripts, no son realmente programas que estés ejecutando. Así que puedes imaginar que si Bitcoin estuviera diseñado de forma diferente podrías codificar directamente una lista de políticas de gasto. He dado un ejemplo aquí en un formato sugerentemente descriptivo.

(pk(A),or(pk(B),or(pk(C),older(1000))))

Podrías imaginar tener una especie de política de multifirma. Tenemos estas tres claves A, B y C. Tenemos un tiempo de espera de 1000 bloques y las juntamos de esta manera. ¿No sería genial si pudieras poner eso en un descriptor? Entonces, la pregunta es ¿cómo se puede mapear algo tan sensato como eso en Bitcoin Script? Ahí es donde entra Miniscript.

Miniscript

La idea detrás de Miniscript es que podemos tomar una política así, todos tenemos estos componentes, claves, hashes y demás y los mapeamos directamente en Script. Tenemos estas plantillas de scripts que cuando se ejecutan hacen la comprobación requerida. También tenemos estas plantillas de scripts que funcionarán como ANDs o ORs para que puedas componerlas. Puedes coger una plantilla que tenga un par de huecos y rellenar otros componentes de script, literalmente una codificación de estas políticas de gasto en Bitcoin Script. Es genial porque conceptualmente hay dos maneras de leer esto. Puedes leerlo como un árbol de ANDs y ORs o puedes leerlo como un programa que se ejecuta en el blockchain de Bitcoin.

Guión: Problemas de alto nivel

Para resumir esta situación que estoy describiendo Script funciona manipulando estos blobs opacos de datos. Es una máquina de pila de muy bajo nivel. Le das un montón de objetos, algunos de ellos representan booleanos, otros representan firmas, otros representan claves públicas o hashes. Algunos representan números que puedes sumar, puedes hacer varias operaciones con ellos. En realidad, no se trata de pensar en términos de políticas de gasto. La dificultad con la situación actual es exactamente esta. El modelo de script es esta máquina de pila de bajo nivel que no tiene ningún mapeo obvio en absoluto al modelo que estoy tratando de describir donde tienes una colección de diferentes condiciones de gasto. Miniscript, como veremos, coincide con este modelo de usuario.

Permítanme resumir los problemas de Script tal y como yo los veo. Una lista gigante de muchos problemas que veo con Script muy rápido. Cuando estás en este modelo de opcode de bajo nivel basado en la pila, es difícil argumentar que tu script es correcto, que realmente va a hacer lo que esperas. Es difícil argumentar que es seguro, es decir, que no hará lo que no esperas. Es difícil argumentar sobre la maleabilidad. Es algo de lo que hablaré en un par de diapositivas. Si eres un implementador de carteras te encuentras con problemas de estimación de tarifas. Es difícil estimar la cuantía de un testigo cuando estás satisfaciendo un guión determinado. Es difícil saber, si tienes varias partes involucradas, qué claves públicas requieren firmas, cuántas firmas necesitas y si requieres hashlocks y si requieres un determinado timelock para ser firmado, etc. Incluso si puedes averiguar esos datos, averiguar cómo ensamblarlos en un testigo no es trivial porque Bitcoin Script tiene un montón de diferentes opcodes que requieren diferentes cosas en diferentes órdenes y en diferentes formatos. Si estás tratando de escribir un software que pueda trabajar con scripts arbitrarios tienes un análisis de programa bastante difícil en tus manos.

Miniscript

Estos problemas con Script se traducen directamente en problemas para diseñar algo como Miniscript. La idea es que puedo simplemente codificar mis políticas de gasto como scripts. Pero los scripts tienen estos problemas en el diseño de estos fragmentos, estas plantillas. Uno es que hay muchas maneras de escribir cada fragmento. Si estoy tratando de hacer una comprobación de la clave pública puedo utilizar un operador CHECKSIG, podría utilizar el operador CHECKSIGVERIFY que es ligeramente diferente semánticamente. Podría usar el operador CHECKMULTISIG y lanzar una sola clave pública allí o algo raro como eso. Hay tres formas de escribir una comprobación de clave pública. La de CHECKMULTISIG es obviamente ineficiente. No hay razón para hacerlo, pero las otras dos podrían ser utilizables en diferentes contextos. Es difícil componer estos fragmentos. El operador CHECKSIG si tiene éxito pondrá un 1 en la pila, si falla pondrá un 0 en la pila. CHECKSIGVERIFY si tiene éxito no pondrá nada en la pila y si falla abortará el script. Así que si estoy tratando de escribir un fragmento de script que represente un AND booleano o un OR booleano necesito considerar que para algunas cosas que conecto tendré un 1 o un 0 por ahí y para otras cosas que conecto no. Quizás necesito diferentes tipos de fragmentos AND y OR que puedan manejar estas diferentes posibilidades. Hay un problema de diseño aquí y hay un problema de análisis de asegurarse de que la composición real de los fragmentos que un usuario viene con es algo sensible. Otra restricción es que no puedo tirar todos los fragmentos excepto uno. No puedo hacer algo tonto, ineficiente y simple porque el coste es realmente crítico aquí. Cada byte importa aquí. Como dijo Monty Python “Cada byte es precioso” en Bitcoin. Los usuarios realmente se preocupan por el tamaño de sus scriptPubKeys, se preocupan por el tamaño de los testigos que producen para gastar sus monedas y esas son en realidad dos cosas diferentes. Cuando están componiendo cosas puede que les importe el tamaño del testigo si no están satisfaciendo algo. Si tienen una OR de dos ramas diferentes, tal vez satisfagan una pero no satisfagan la otra. Existen todas estas dimensiones de coste diferentes cuando se considera el tamaño de los fragmentos. Cuando se diseña un Miniscript hay que considerar para cada fragmento la probabilidad de que se satisfaga realmente, la probabilidad de que no se satisfaga y la probabilidad de que se salte completamente si es una rama IF que no se llama. Esto significa que hay compensaciones. No se puede elegir un solo fragmento que sea obviamente el mejor. Incluso si sabes cómo es tu política, no hay un fragmento que sea obviamente el mejor. Hay que soportar todos estos fragmentos diferentes y se necesita una forma de que el usuario verifique que lo que está haciendo no sólo es sensato y no sólo es eficiente, sino que es lo más eficiente para el caso de uso específico que está considerando. Un último punto en esta diapositiva es que conseguir un script óptimo puede implicar algunas cosas extrañas. Si ves que la misma clave pública aparece dos veces, tal vez quieras reorganizarla para que sólo aparezca una vez. Reestructurarías completamente el aspecto de tu predicado. Eso está fuera del alcance de Miniscript. Hacer cosas de optimización de programas completos como esta sería genial y en teoría es posible, pero rompe este modelo de usuario agradable y simple donde tienes un árbol de condiciones de gasto y produces una política de esa manera. Si se hace cualquier manipulación avanzada en estas cosas, entonces perderíamos esa ingeniería simple, legible, fácil de razonar, fácil de comprobar las propiedades de consistencia.

Miniscript - Maleabilidad

Entonces, entremos en la maleabilidad. Más allá de pensar en la corrección, que en cierto sentido es un problema directo de ingeniería, y en la optimización, que también es, en cierto sentido, ingeniería, tenemos el problema de la maleabilidad. Esta era una palabra muy caliente antes de que SegWit existiera. En primer lugar, lo que la maleabilidad es la capacidad de un tercero, dada una transacción de Bitcoin, para reemplazar los testigos con algunos otros testigos que también son válidos. Se obtiene una transacción diferente que sigue haciendo exactamente lo mismo, sigue siendo una transacción válida pero es diferente de alguna manera. Antes de SegWit esto era realmente grave porque los testigos entraban en el ID de la transacción, así que si encadenabas varias transacciones offchain este tercero rompía toda la cadena y te metías en un buen lío. Después de SegWit la maleabilidad sigue existiendo, ya no es algo que rompa el protocolo, pero sí es algo que afecta a la eficiencia de dos maneras importantes. Una es que puede afectar a las propiedades de propagación de las transacciones. Si alguien cambia un testigo y algunos nodos han visto una transacción con un testigo y otros ven una transacción con otro testigo, uno de ellos va a entrar en un bloque y esto puede interferir con la reconciliación de bloques compactos. En algún momento necesitas el testigo completo y todo eso, y si tu nodo se ve sorprendido por lo que resulta ser el testigo en la cadena de bloques, eso es una ineficiencia para la red. Desde el punto de vista del usuario, si existe la posibilidad de sustituir un testigo por otro más grande, eso significa que tu transacción, al llegar a la red, es más grande que la transacción que creaste y, por lo tanto, la tasa que ve la red es menor que la tasa que estableciste. Ahora te encuentras con la sorpresa de que tu transacción tiene una prioridad inferior a la que querías. Esto es potencialmente un problema de seguridad porque significa que su transacción podría no propagarse cuando usted lo esperaba. O podría no ser aceptada en el mempool de la gente cuando usted esperaba que lo fuera.

Miniscript - Trazabilidad

Así que para hacer la tarea de diseñar Miniscript tractable establecemos algunas reglas de diseño aquí que más o menos ya he dicho. La primera es que vamos a asumir las reglas estándar de la política de mempool de Bitcoin Core. Estandarización es el término que usamos. La razón por la que hacemos esto es que hay un montón de cosas anti-maleabilidad en las reglas de política de Core que no están en el consenso de Bitcoin. Un ejemplo destacado de esto es que hay un opcode IF en Bitcoin. Si le das un 1 hará la cosa, si le das un 0 no hará la cosa. Hay muchas, muchas formas de codificar el 1, hay muchas formas de codificar el 0. Si tienes un script que está usando este OP_IF y proporcionas un 0 o un 1 en tu testigo, en principio algún tercero podría cambiar ese 0 en un 0 que tiene veinte ceros seguidos. O podría cambiar su 1 en cualquier valor distinto de cero o algo así y hacer su transacción más grande y entonces usted está en problemas. Puedes prevenir esto, puedes hacer que la transacción no sea válida en este caso usando este truco. Usas OP_SIZE seguido de OP_EQUALVERIFY. Este es el único pedacito de Bitcoin Script que voy a lanzar aquí. SIZE EQUALVERIFY es un truco muy bonito. SIZE pone el tamaño del elemento más alto de la pila en la pila. EQUALVERIFY comprueba que las dos cosas son iguales. Lo que hace SIZE EQUALVERIFY es que si tu elemento superior de la pila es igual a su propio tamaño de bit es genial. Si no lo es, fallará la transacción. Resulta que en Bitcoin Script sólo hay dos valores que son iguales a su propio tamaño. Esto es 0 que es la cadena vacía que tiene tamaño 0 y 1 que es el byte 1 que tiene tamaño 1. Podríamos poner SIZE EQUALVERIFY delante de cada IF y también podríamos poner comprobaciones de validez y longitud adicionales delante de todas nuestras comprobaciones de firma, por ejemplo. Hay un montón de otros guardias que podríamos poner en todos nuestros fragmentos de script, pero no queremos hacer eso porque estamos desperdiciando bytes allí. En la práctica esto no es realmente un problema porque la red está aplicando tan abrumadoramente estas reglas de política que realmente sólo los mineros podrían explotar este tipo de maleabilidad. Los mineros ya tienen la capacidad de alterar las transacciones. Si los mineros quieren dañar la propagación de la red pueden simplemente producir un montón de transacciones que nadie ha visto antes y llenar los bloques con ellas. Ahora los bloques compactos no funcionan. Los mineros ya tienen la capacidad. Los problemas de maleabilidad ya son cosas que los mineros pueden hacer, así que vamos a seguir con las reglas de política. Como mencioné, no vamos a intentar ninguna eliminación de subexpresiones comunes, no vamos a intentar manipular nuestro programa, no vamos a intentar reordenar las cosas. En primer lugar, esto es muy difícil en general para encontrar la codificación óptima de un programa. En segundo lugar, rompe la analizabilidad. Entonces también vamos a asumir con el propósito de razonar automáticamente sobre la maleabilidad, que es algo que hacemos en Miniscript que tocaré pero no entraré en mucho detalle, vamos a asumir que las claves de la gente no son reutilizadas dentro de un script específico. La razón de esto es que si alguien usa la misma clave dos veces, entonces si firma en una rama, un tercero podría ver esa firma y copiarla y usarla en una rama diferente. Esto introduce potencialmente un vector de maleabilidad donde de otro modo no lo habría. Esto es muy difícil de razonar de forma automatizada. Realmente tienes que saber qué ramas son disjuntas de otras ramas. En general, parece un problema intratable. También asumimos que no hay reutilización de claves para la estimación de tasas. Esto aparece en algunos casos extremos cuando se piensa en cómo estimar el tamaño del testigo. Vamos a desechar eso con el propósito de tener algo que podamos describir y podamos desplegar.

Miniscript y políticas de gasto

La última cosa de diseño en Miniscript a la que nos vemos obligados es a separar esta noción del lenguaje de Políticas que es algo que te mostré hace varias diapositivas donde tienes estos ANDs y ORs y demás, de Miniscript en sí mismo. La idea es que el lenguaje de políticas es de alto nivel, es decir, la cosa legible para el ingeniero o incluso para el usuario. Describe directamente qué condiciones de gasto están disponibles y en qué combinaciones. En estas políticas también permitimos etiquetar diferentes ramas con diferentes probabilidades de que se tomen ciertas ramas. Esto nos permite tomar una política, compilarla en un Miniscript y tomar decisiones sobre qué fragmentos de script específicos queremos utilizar en función de la probabilidad de que se tomen ciertas ramas. Tenemos una gran capacidad de optimización aquí. Tenemos este lenguaje de políticas, de alto nivel. Esto es distinto pero muy similar al propio Miniscript que voy a mostrar en el próximo par de diapositivas. Miniscript realmente corresponde directamente a Bitcoin Script. Es una codificación alternativa de un subconjunto de Bitcoin Script donde esta codificación es claramente un árbol de ANDs y ORs y umbrales. Tenemos el propio Miniscript que realmente es esta recodificación de Script. La diferencia entre Miniscript y el lenguaje de políticas es, en primer lugar, que no hay probabilidades en Miniscript. En segundo lugar, en Miniscript etiquetamos explícitamente qué fragmentos estamos utilizando en todos los casos en los que hay varias opciones.

Permítame mostrarle cómo es esto. Aquí hay un ejemplo de una política. En lugar de escribirla en el formato de descriptor de cadena, tengo la capacidad de dibujar estas bonitas imágenes. Esto es lo bueno de Miniscript que no puedes hacer con los scripts normales. Conceptualmente lo que tengo es este árbol de objetos en lugar de tener un montón de instrucciones para una máquina de pila. Obtengo este bonito formato. Aquí está la política. Puedes ver que tengo cuatro llaves dando vueltas, tengo una preimagen de hash, tengo un bloqueo de tiempo. Hay varios análisis que podría querer hacer en esta política. Digamos que soy el propietario de la clave pública 4 (pk_4) a la derecha allí y mi trabajo es ser un refrendador. Realmente no me importa qué más está pasando aquí. Lo que quiero saber es si este script se puede gastar sin mi permiso, sin que yo lo firme. O después de que las monedas hayan estado quietas durante 1000 bloques tal vez esté dispuesto a retroceder. Puedo fácilmente repasar esto y decir “¿Existe alguna forma de gastar esto donde no aparezca mi clave?” Vamos a repasar todas las posibilidades de gasto. En el nivel superior tengo este Y, por lo que ambos tienen que suceder. En el lado derecho tengo un AND así que ambos tienen que suceder. La única forma de gastar estas monedas, inmediatamente puedo ver visualmente que ambas ramas se satisfacen. Puedo ver que una de ellas es exactamente la política que quiero. Así que sé sin duda que no hay ninguna forma secreta de que estas monedas puedan ser gastadas fuera de mi control aunque no miré la mayor parte del script. Todo lo que hice fue correr a través de las ramas y comprobar que existía una en cada ruta de gasto posible donde mi clave estaba involucrado o este tiempo de espera alternativo.

Este es el aspecto de un Miniscript. Son casi la misma imagen. Puedes ver que la diferencia aquí es que en Miniscript he etiquetado todos los ANDs y ORs y cosas con específicamente qué fragmento de script quiero usar. También los he etiquetado con B’s y V’s, hay K’s y W’s también. Estos representan tipos que no voy a tratar en esta charla. Miniscript tiene un sistema de tipos que permite la verificación automática de la corrección. También tengo estos c’s, vc’s y jv’s y demás. Por ejemplo, v significa que añades un OP_VERIFY al final de algo, lo que convierte un resultado de 1 o 0, como hace CHECKSIG, en un resultado de aprobado o suspenso, como hace CHECKSIGVERIFY. v significa que pones un VERIFY. j es esta extraña envoltura en la que miramos si el usuario nos ha dado o no un cero. Si el usuario nos ha dado cero nos saltamos lo que estamos envolviendo. Si nos da un valor distinto de cero, lo pasamos como entrada al fragmento. La razón por la que hacemos esto es que para una preimagen de hash queremos dar al usuario la opción de proporcionar una preimagen de hash válida o proporcionar la cadena de bytes cero, lo que significa saltar esto, fallar la comprobación. Esta envoltura j nos da exactamente esa semántica. Puedes ver que no tiene nada que ver con la política pero es claramente importante para codificar cosas como Script. En la parte inferior tengo el Script de Bitcoin y los opcodes. Esto es lo que parece.

Miniscript y PSBT

Por razones de tiempo voy a saltarme esta diapositiva. Básicamente, uno de los proyectos de Andrew (Chow) es PSBT, que es un formato de intercambio de carteras de transacciones sin firma. Miniscript fue diseñado para trabajar con PSBT. Ambos se potencian mutuamente. Hay algunas herramientas muy genéricas de monederos múltiples que podemos escribir usando el golpe de Miniscript y PSBT. Eso es todo lo que voy a decir aquí.

Taller de mañana

Permítanme anunciar rápidamente mi taller y luego terminaré. Mañana por la mañana voy a hacer un taller de 9:30 a 12:30. A diferencia de los otros talleres aquí este no va a ser súper enfocado a la programación. La razón es que mi biblioteca Miniscript está escrita en el lenguaje de programación Rust y no creo que sea razonable esperar que la gente ya conozca Rust o lo aprenda en un par de días. Tiene una curva de aprendizaje muy alta, como es sabido. Hay una implementación en Python que escribió James Chiang pero no creo que esté del todo terminada. Es un PR para Bitcoin Core como parte del marco de pruebas de Python. No está del todo terminada y no la he revisado y no sé realmente cómo usarla. Sería algo bueno para usar en un taller pero no tenemos acceso a él. En su lugar, voy a hacer algo un poco más teórico. Vamos a repasar muchas de las rarezas de Bitcoin Script. Tal vez vamos a mirar a interpreter.cpp que es uno de los archivos más extraños y más antiguos en Bitcoin Core y ver algunas de las cosas raras que el intérprete de script hace que podría confundir varios tipos de análisis. Profundizaremos en cosas como la corrección y la maleabilidad y las sorprendentes pistolas de pie que se encuentran cuando se trabaja con Script. Incluso cuando se trabaja con Miniscript hay cosas sorprendentes que a veces el sistema de tipos de Miniscript puede atrapar por ti, pero sin embargo son a menudo cosas no obvias y sutiles. En el transcurso del desarrollo a menudo intentaba hacer cosas raras con Miniscript y mi código se negaba a firmar las transacciones, las rechazaba de alguna manera. Creo que el código está roto, pero cuando rastreo la forma en que estaba fallando, me estaba mostrando que había algún vector de maleabilidad en lo que estaba tratando de hacer. Había un ataque real que no había considerado. Es realmente genial que podamos hacer esto de forma automatizada porque se trata de cosas realmente sutiles y realmente a pie de cañón y no obvias.

Conclusiones

Para terminar, hay una cosa llamada Miniscript. Hace que las políticas de gasto estén codificadas en Bitcoin Script. Legible por humanos, digamos legible por ingenieros, me gusta el término de Andrew. Y analizable por la máquina. Podemos hacer todo tipo de cosas geniales, en particular cosas como construir testigos, determinar qué claves son necesarias, estimar el tamaño de los testigos incluso bajo ciertas restricciones. Esto se vuelve manejable y, de hecho, podemos hacerlo de una manera muy genérica en la que alguien como yo podría escribir algún código que lo haga y luego todo el mundo podría utilizarlo. Ya no estamos reinventando la rueda para cada política individual extraña. También se consigue la composibilidad que mencioné al principio de la charla. Si tienes un Miniscript más grande, como vimos con la imagen, puedo tomar algún pequeño fragmento que me interese para mis propósitos y no preocuparme realmente de lo que los otros participantes estén haciendo, siempre y cuando el script general esté usando mi política de la manera que yo quiero. Conseguimos esta componibilidad en la que puedo participar en la custodia de las monedas que Blockstream controla, digamos, y me presento en la mesa con alguna cosa loca de multifirma con bloqueo de tiempo y todo lo que los demás tienen que hacer es que soy yo. De alguna manera esa gran mancha soy yo. Saben que de alguna manera no me he echado atrás haciendo esta cosa complicada. Todo lo que necesito saber es que estoy contribuyendo. No puedes mover las monedas sin mí o sin un gran número de personas. Vamos a entrar en esto en un poco más de detalle mañana por la mañana. Gracias a todos por escuchar.

PREGUNTAS Y RESPUESTAS

P - Decías que había un problema con la reutilización de la clave pública. ¿Has pensado en utilizar el muy poco famoso operador OP_CODESEPARATOR que te permite realmente utilizar una sola clave pública para una persona pero firmar una rama específica de tu script?

R - Esta es una pregunta muy interesante. La pregunta es sobre el uso de OP_CODESEPARATOR que es este oscuro opcode que te permite básicamente etiquetar lo que estás firmando de una manera técnica para que una firma para una parte de tu script no pueda ser reutilizada para una firma en otra parte de tu script. En primer lugar, esto es un poco ineficiente. Estamos añadiendo bytes extra al pegar estos OP_CODESEPARATORs en lugares. A algunos usuarios quizás no les importe esto. En segundo lugar, esto no cubre todos los casos que podrían importarnos por razones técnicas, pero que tal vez pueda tratar mañana. Usted puede imaginar una política de umbral donde usted tiene 3 de 5 participantes dicen. Hay 5 eligen 3 formas diferentes de gastar esto. Puedes imaginar que una persona firma usando los tres primeros firmantes. Entonces alguien lo cambia para usar los tres últimos. Ahora el firmante del medio está en ambos casos. Pero OP_CODESEPARATOR como solo aparece una vez en esa llave no podrá detectar este tipo de cambio de testigo. Así que en ese ejemplo esto probablemente no importa porque no es un ejemplo de reutilización de claves. Pero puedes imaginar una política de umbrales que sea más complicada. Puedes imaginar un umbral de umbrales, algo más elaborado, donde esto sí importa. Tengo algunos ejemplos de estos, pero no en mi cabeza ahora mismo.

P - Cuando hablaste de j dijiste que quizás el usuario quiere que el script falle. Por qué querrían eso, simplemente no enviar la transacción?

R - Nunca quieres que todo el script falle, pero puedes querer que algunos subconjuntos específicos de tu script fallen. Si tienes un OR, una forma de hacer un OR en Bitcoin es ejecutar un fragmento de script, puedes almacenar el resultado, que será 0 o 1, y tirarlo a la pila de altstack, por ejemplo. Luego ejecutas otro fragmento y almacenas ese 0 o 1. Luego sacas los dos resultados y ejecutas la operación OP_BOOLOR sobre eso. La expectativa es que cualquier rama que el usuario tome va a fallar una de las dos cosas y tener éxito en la otra. Esto puede ser más eficiente que hacerlo de otra manera, usando OP_VERIFY o algo así. En ese caso tienes un subconjunto de tu script que sí quieres que pueda fallar. Quieres que ponga un 0 en la pila que luego pasas por OP_BOOLOR para obtener un 1 y pasar el script más grande. Esta es la razón. Siempre que tengas condicionales es por lo que querrás fallar cosas.

P - Así que Andrew Chow dijo en la charla anterior que los descriptores de scripts de salida describen todo lo que se necesita para resolverlos. Significa eso que hay redundancia entre los descriptores y Miniscript tal y como están diseñados actualmente?

R - No, no hay redundancia. Lo que describen los descriptores de salida es dónde pones los testigos. Si tienes un PKH o algo así simplemente pones una firma en tu scriptSig. Si estás usando SegWIt pones tus testigos en el campo de testigos. Si no estás usando SegWit lo pones en el scriptSig. Ese tipo de cosas. Lo que Miniscript describe es cómo construir esos testigos en primer lugar. Se complementan entre sí. Los descriptores de salida, tal y como se han implementado o en la hoja de ruta inmediata para el núcleo, no soportan todas estas cosas avanzadas que hace Miniscript. Sólo soportan, creo, la multisigencia básica y todas las formas diferentes en las que se pueden utilizar claves de un solo firmante. Lo que Miniscript consigue es la capacidad de hacer muchas más cosas con los descriptores de salida. Pero las dos partes que hacen son disjuntas, son complementarias.