Libsecp256k1 Reunión de mantenedores (2022-10-12)
Transcripción De: Bryan Bishop
Traducción Por: Blue Moon
Tags: Libsecp256k1
P: ¿Por qué C89? Cuando te hice esta pregunta hace unos años, creo que dijiste gmaxwell.
R: Hay una serie de dispositivos embebidos que sólo soportan C89 y sería bueno soportar esos dispositivos. Esa fue la respuesta de entonces, al menos.
P: ¿Es un gran coste seguir haciendo C89?
R: El único coste es para las cosas de contexto que queremos hacer threadlocal. El CPUid o las cosas específicas de x86. Estos podrían ser opcionales. Si realmente quieres entrar en este tema, entonces tal vez más tarde. Tiene sentido empezar con una lista de temas.
Temas
- liberación
- MuSig y FROST en secp vs -zkp?
- contexto de escritura
- alcance de la biblioteca en general, rama de puesta en escena, firmas de adaptadores, etc.
- PR para anti-exfil en Schnorr (está en -zkp)
- sidechannels, panorama general; con el nuevo asunto de la filtración de la velocidad de la CPU. Se trata más bien de nonces sintéticos para ECDSA.
- ramas criptográficamente imposibles: convenciones de codificación para cosas que son criptográficamente imposibles de alcanzar, en un CONTRIBUTING.md o algo así; ¿podemos cambiar esto para no incluirlo? Para deshacerse de las ramas. Como cuando se hace el hash de un valor y se comprueba si está en la curva, ¿debería tener código de manejo de casos para las cosas improbables que ocurran?
- cmake/Makefile es otro tema que surge regularmente
- contexto inmutable
Liberación
Para la gente que no está muy al tanto del estado del proyecto libsecp256k1 bitcoin, un poco de contexto: nunca hemos tenido una liberación. Eso es todo. Ese es el contexto. Bueno, queremos cambiar esto. Queremos cambiar esto porque la gente pregunta mucho sobre esto, y se ha distribuido en Debian y otras distribuciones distribuyen nuestras bibliotecas con números de versión como commit ids. Esto plantea algunas preguntas sobre la estabilidad de la API. Por el momento hemos estado tratando de mantener la API estable porque sabemos que la gente está usando nuestro código. Pero sin el control de versiones o lanzamientos, no hay manera de señalar los lanzamientos de ruptura. Hemos pasado efectivamente a un modo de desarrollo en el que tratamos el código como una rama estable porque la gente lo está usando como tal. No hay rama de desarrollo.
La conclusión actual sobre los lanzamientos ha sido, simplemente etiquetar un lanzamiento. No es necesario que sea v0.1. Tenemos una lista de tareas pendientes muy pequeña y creo que por eso voy a dar mi opinión personal, pero creo que todavía estamos bien con esta pequeña lista de tareas pendientes. Actualmente está bloqueada por los cambios en la documentación. Uno de los cambios que queremos hacer, tuvimos algunos cambios en la API que son retrocompatibles oficialmente, pero que aún merecen algo de documentación. Hicimos los cambios sin cambiar la documentación; actualmente, tengo un PR que cambia la documentación. Ha tenido alguna revisión. Llevo varias semanas diciendo que lo abordaría. Sigo creyendo que lo haré en un plazo razonable.
Limpieza de la API con respecto al contexto. Este fue cambiado a borrador porque tenía.. No quería hacer este cambio en todas partes. Lo hice en algunos lugares para mostrarlo como un escaparate, pero quiero que se haga en todas partes. Ha sido el concepto ACKed en la reunión del IRC. Así que en realidad es sólo yo siendo lento.
Hay otros dos pull requests en el hito de lanzamiento inicial. Uno es la habilitación de los módulos no experimentales por defecto. Los módulos no experimentales son ECDH y Schnorr … Creo que la recuperación se mantiene experimental. ¿Por qué? ¿Sólo porque lo odiamos? Sí. La razón está en el mensaje de confirmación. Hay una razón adicional que no se explica en el mensaje de confirmación. No recomendamos que los nuevos protocolos implementen la recuperación de pubkeys ECDSA. Este pull request tiene actualmente sólo un ACK. Bitcoin Core utiliza la recuperación de la pubclave ECDSA para los mensajes de firma.
Una cuestión es la experimentalidad, y otra es la habilitación de un módulo por defecto. No podemos decir razonablemente que la recuperación es experimental. Su API literalmente nunca ha cambiado hasta donde yo sé. Podríamos cambiarlo, supongo. Quería cambiarlo, no sé si lo recuerdas, para optimizar la idea de Russell de optimizar la tasa de n-elección… ¿Pero realmente quieres escribir este código ahora? No, bueno, ya escribí gran parte pero luego hubo ideas de optimización adicionales y eso básicamente lo mató. Eran buenas ideas. Requería mucho más trabajo y lo abandoné en algún momento.
¿Están todas las APIs de secp256k1 pensadas para ser usadas sólo en Bitcoin Core? No. De hecho, ECDH no lo es. Esta es la razón principal por la que secp256k1 es una biblioteca independiente. Creemos que es la mejor implementación de firmas Schnorr del mundo y queremos que los monederos de hardware la usen y que otros monederos la usen. Hay algunos que lo hacen. Hay muchos proyectos que no son de bitcoin ni de criptomonedas que utilizan la biblioteca.
Un PR final en el hito es preparar la liberación inicial por bumping la versión a v0.2.0 porque v0.1 es básicamente ya en el mundo. La versión v000 es la versión de la biblioteca.. no, vale. Pensé que era 0.0.1. Parece un poco raro que.. no se puedan saltar versiones. La primera versión de Windows NT fue la 3, ya sabes.
Otro tema a discutir, quizás, ¿realmente queremos módulos experimentales? El argumento de Rusty es que, básicamente, si tienes un módulo y lo expones, la gente lo usará y empezará a depender de él. No puedes esconderte detrás de “oh, lo llamamos experimental y no deberías usarlo”. Si es útil y es la mejor implementación que existe, entonces la gente lo usará a pesar de todo. Es un argumento justo. Pero a veces hay situaciones reales en las que… Creo que deberíamos tener módulos experimentales, pero deberíamos tratarlos como realmente experimentales. Si no están en desarrollo activo o no se están considerando cambios en la API, entonces no son experimentales y deberían dejar de serlo. No me imagino diciendo que la API de validación de lotes que se está añadiendo que sí queremos experimentar con eso y ver una vez que está allí podemos integrarlo en Bitcoin Core o hay cambios que serían informados por los usuarios de la misma. Esa es una buena razón para mantener algo experimental.
Con el proceso de liberación, esto se está volviendo más fácil porque podemos decir que no garantizamos la estabilidad de la API para esos módulos experimentales. Puedes fijarlos bajo tu propio riesgo. El argumento de las autotools es que no puedes saber si una biblioteca o distribución tiene ese modelo o no. El argumento de las bibliotecas dinámicas es que, si piensas en esto como una biblioteca que se instala en todo el sistema, puedes compilarla con el módulo Schnorr o sin él y entonces tienes algo que necesita eso…
¿Cuál es el argumento en contra de tener una rama experimental en lugar de un módulo? Si sacamos cosas en Bitcoin Core y hay un commit que no está en la rama principal…. estrictamente hablando, este ha sido un argumento en el pasado que debido a la superposición entre el desarrollo en Bitcoin Core y libsecp, no es irrazonable para Bitcoin Core utilizar una API experimental porque en primer lugar, pega versiones y otros pueden hacer eso también. En segundo lugar, es la misma gente. La rama experimental necesita ser rebasada todo el tiempo, lo cual apesta. Pero honestamente, no tan a menudo. Tampoco es una respuesta al problema de las bibliotecas dinámicas. Todavía tienes el problema de… si no está en la rama principal, entonces no es parte de la biblioteca. Eso es una cosa diferente. Eso no es diferente desde la perspectiva del usuario de que sea experimental y no por defecto y no se espera que esté en las versiones compiladas de la línea principal. Depende de lo que hagan las distribuciones. Con otros paquetes, hay informes de errores de una distribución que dicen que hay que recompilar con estas banderas y entonces eso sería una lucha. Sería razonable para nosotros decir que si usted está usando módulos experimentales como usuario, entonces necesita compilar como una biblioteca estática. Entonces los distribuidores deberían activar todas las características, a menos que estén marcadas como experimentales. Hemos estado diciendo que no distribuyan esta biblioteca, y la han estado distribuyendo de todos modos. Bueno, en realidad no hemos estado diciendo nada en primer lugar.
Puntos de acción: más revisión. Los PRs necesitan ser limpiados. Módulos experimentales, tal vez añadir otros como MuSig. Creo que el PR del proceso de liberación añade documentación en torno a los módulos experimentales. Cualquier cambio en un módulo experimental es un parche. El proceso de liberación mitigará muchos de estos problemas, así que tal vez sea el punto en el que no necesitamos preocuparnos por eso. Supongo que la expectativa es que todo lo que no sea experimental se convierta por defecto en activado, excepto la recuperación. Las cosas que tienen APIs que no se espera que cambien se convertirán en no experimentales.
Canales laterales
Hay este reciente aumento de la CPU / estrangulamiento, y luego también conduce a .. Hertzbleed. Todo ataque necesita un buen nombre. Luego otro es la aleatorización del contexto que tiene un alto costo. Sería bueno hablar de esos dos canales laterales.
Hay un módulo utilizado en la generación de claves y la firma y el cálculo de los nonces públicos aquí es donde se utiliza. Lo que he considerado aquí es un modelo de atacante… en primer lugar, esta es una operación muy interesante de proteger porque es la más cara en la generación de claves y luego en la firma. Si eres un atacante de canal lateral, cuanto más largo sea el cálculo y más recursos requiera, más oportunidades tendrás como atacante. Tiene sentido centrarse primero en las operaciones caras.
Digamos que un atacante observa la multiplicación por puntos de n * G
durante muchas muchas veces con el mismo valor de n. Si calculo n * G
una vez, entonces si el atacante ya puede extraer n entonces hemos perdido de todos modos, así que asumimos que se trata de multiplicaciones de puntos repetidas. Los modelos de atacantes de canal lateral generalmente requieren un matiz donde es un atacante matizado que es todo poderoso y puede leer tu memoria pero tienes que hacer algunas suposiciones sobre el atacante pero no hacer que el atacante sea demasiado débil. Estos son límites algo arbitrarios.
Hay algunas cosas ya en el código que proporcionan protección contra los ataques de canal lateral para ECmultchan. Uno de ellos son los nonces sintéticos, que es lo que tenemos en Schnorr. Esto es realmente útil porque lo que hacemos aquí es aleatorizar el propio escalar secreto. Siempre que hay un, cuando en ECDSA usamos nonces deterministas que son una buena idea para derivar de la clave secreta y el mensaje para que su seguridad no dependa de tener una buena aleatoriedad en el momento de la firma, al menos en términos de seguridad tradicional. Se trata de una protección de reutilización de nonce. La razón por la que te preocupa la reutilización del nonce es por la mala aleatoriedad y con los nonces deterministas no necesitas preocuparte por eso.
El problema es que si el atacante, por alguna razón, tiene un oráculo de firma, lo que significa que puede pedirle a tu código que firme cosas… si te pido que firmes el mismo mensaje un millón de veces, entonces usarás el mismo nonce un millón de veces y puede observar el mismo nonce un millón de veces, lo que no es bueno para la protección de canal lateral. En Schnorr, derivamos el nonce usando el mensaje, la clave y también algo de aleatoriedad. Así que si la aleatoriedad se rompe, vuelves a los nonces deterministas, pero si tienes aleatoriedad adicional, tienes protección adicional. Nunca es peor que los nonces deterministas. También podría ser un contador, no necesariamente aleatorio, dependiendo del modelo del atacante. Algún valor no repetitivo al menos. El escalar secreto y el nonce secreto serán aleatorios. Si pido una firma sobre el mismo mensaje un millón de veces diferentes, obtendré un millón de nonces y firmas diferentes.
Mezclar el ciclo de la CPU podría ser útil, dependiendo del modelo de atacante. Hay una diferencia entre el atacante de inyección de fallos de hardware y otros. El contador de instrucciones es como un contador, podrías usar eso. Podrías usar PRNG, podrías usar una marca de tiempo, etc.
Había un PR para usar los nonces sintéticos pero no hace eso.
¿Pasar aleatoriedad a la función de generación de nonces no logra eso? En realidad sí lo hace. Se puede pasar con el vector n.
Así que hacemos esto para Schnorr porque la idea surgió cuando estábamos trabajando en bip340. Todavía no está en el código ECDSA. Esa es una observación.
Otra cosa que hacemos es tener un escalar aleatorio… si calculas n * G
entonces tenemos un valor p en el contexto que generamos en el momento de la creación del contexto. El contexto es un objeto que primero necesitas crear antes de poder usar las funciones de la biblioteca. Tenemos algún valor aleatorio p en el contexto y cuando se computa n * G
lo que realmente se computa es (n - p) * G + pG
donde pG
está precalculado. La operación de aleatorización consiste en restar un número precalculado de un escalar, hacer la multiplicación y luego añadir un punto precalculado. El punto pG está precalculado, por lo que no necesitamos hacer dos multiplicaciones cada vez, sino sólo una. Podemos utilizar esta técnica para cada multa de la CE que estamos haciendo.
Con este modelo de atacante que considero aquí, si miras esto, entonces realmente este cegamiento aleatorio no es particularmente útil. Utiliza el mismo cegamiento cada vez. Sería diferente entre distintos dispositivos de hardware. Me equivoco. Lo que escribí aquí es que es útil, en realidad. El punto de esto es como un atacante ahora ves una multiplicación p * G
precomputación por lo que no puede aprender p porque sólo se ve una vez. Luego ves el millón de otros cálculos; tal vez puedas extraer (n - p)
de esto pero no te ayudaría. Pero hay un valor aleatorio en el momento de la creación del contexto que no podrías extraer. Utiliza la aleatoriedad que tú proporcionas; secp no tiene aleatoriedad en sí mismo. También hay algún otro truco de cegado del que no hablaré ahora pero que es parte de esto.
Después de cada firma, ¿qué pasa si se lanza otro bit en el valor b
? Eso también está relacionado con el contexto.
Una advertencia aquí es que cuando tenía este argumento, sólo se centró en EC mult sí mismo. Si ves un millón de veces la operación escalar (n - p)
entonces puedes calcular lo que es p entonces de nuevo estamos perdidos. En este modelo de atacante, mi conclusión fue que los nonces sintéticos son en realidad una fuerte defensa porque aleatorizan el propio escalar. Siempre que sea posible, creo que se debe hacer esto. Actualmente sólo se utiliza para las firmas Schnorr y no para ECDSA. Lo tenemos en el código ECDSA, es cierto, pero Core no lo hace. Pero Core tampoco lo hace para las firmas Schnorr-o sí? Recuerdo que había un PR para hacerlo pero era tanto para ECDSA como para Schnorr. Creo que ahora lo hace para ECDSA. Si lo hace, entonces también lo hará para Schnorr. Hubo un PR para hacerlo para Schnorr. Si va a hacer eso, entonces debería hacerlo para todo. Comprobando… ECDSA no tiene aleatoriedad en el Core ahora mismo.
Al menos, afirmo que debería hacerlo. La última vez que comprobé el código de Core para ECDSA, estaba intentando crear un PR, pero había muchas cosas que no podía probar en el código. No está roto, pero realmente no me gustó el código. Simplemente me llevó demasiado tiempo trabajar en los cambios.
El truco del nonce sintético solo funciona si tienes nonces. No puedes usar esto para la generación de claves porque la clave es fija. Tampoco se puede usar para ECDH.
Una pregunta que planteo en este tema es, ¿deberíamos hacer algo similar también para la generación de claves? Donde podríamos derivar un valor p
de una sola vez y sólo hacer dos multiplicaciones. Esto duplica el coste, pero ¿cuánto cuesta la generación de claves y con qué frecuencia las generamos? No lo sé. Casi nunca generamos claves. Lo que generamos es una clave maestra y toda la generación de claves ocurre a través del esquema bip32 que es donde, por cierto, también el EC mult gen juega un papel.
También en las operaciones de tweak podemos tomar el tweak como aleatoriedad. Están utilizando las operaciones de pellizco. Podemos tomar ese pellizco como también la aleatoriedad. ¿Pero el pellizco es fijo? Al menos no puede disminuir la seguridad. Creo que en la práctica volvemos a calcular todo cuando se deriva una nueva clave privada. Eso significa que estás repitiendo el mismo…. puedes pedir el recálculo de la misma clave secreta muchas veces y esto es por lo que pienso, no creo que sea un cuello de botella en Bitcoin Core así que duplicar ese tiempo. Duplicar suena muy mal pero quizás valga la pena. Pero… vale, ya veo. Tu punto es que estás computando la misma conclusión múltiples veces y cada vez la vas a computar de una manera diferente con una división diferente. Lo bueno de esto es que duplica el tiempo de computación pero si tienes como en el código sintético nonce si tienes aleatoriedad adicional o un contador disponible entonces la API de esto es fácil. Solo necesitas una función que tome una aleatoriedad adicional y use eso y el secreto para derivar el valor p, y entonces tienes un valor p aleatorio cada vez. La razón por la que me gusta esto es porque no entra en la aleatoriedad del contexto. Eso es un API más complicado.
Contextos
Aquí hay una pregunta más simple de la API. Usted podría tener una bandera cuando se crea el contexto. Podrías añadir esta bandera que lo desactive si realmente sabes lo que estás haciendo. No, no puedes porque necesitas aleatoriedad para eso. La forma en que lo haría es simplemente tener otra función. Una función sin el argumento de la aleatoriedad, y luego otra sin él. A menos que tengas un contexto inmutable que contenga un RNG.
Otra cosa fácil sería si pudiéramos elegir un tamaño de contexto en tiempo de ejecución. Ya no hay tamaños, todo es en tiempo de compilación. En rust-secp, todavía estamos luchando por los contextos inmutables.
La idea de los contextos inmutables es que tenemos este valor fijo p en el contexto y también p * G
precomputación. Hay más cosas en el contexto todavía. Todo lo demás es un valor fijo. No, el contexto tiene las devoluciones de llamada que en este momento se puede cambiar. El argumento ilegal y todo eso. Hay una propuesta para que alguien use el argumento del id de la CPU en el contexto. Hay tres tipos de contexto: el que has estado hablando hasta ahora, el de callbacks que creo que deberíamos eliminar ahora mismo… el único problema de eliminar los callbacks es que complicará las pruebas porque anulará el… los usuarios pueden poner esto en un mutex y está bien si hay contención.
Primero hablemos de las cosas de contexto que están relacionadas con los canales laterales. Me gustaría eliminar cualquier contexto para que las bibliotecas de óxido no tengan que preocuparse por los contextos. Una cosa aquí es que la aleatorización del contexto significaría que de vez en cuando se calcularía un valor p
diferente. En el modelo de atacante que considero aquí, eso no es tan útil como he explicado antes porque ya con una p
fija obtenemos una protección contra este tipo de atacantes. Esto no significa que no debamos hacerlo. Pero deberíamos buscar estas otras posibilidades tal vez primero.
¿Así que la idea sería cambiar de vez en cuando el valor de b
? Yo sugeriría hacerlo cada vez. ¿No requiere eso calcular un nuevo b * G
? Bueno, depende de lo que quieras hacer, como la adición. Una vez que tenemos nonces sintéticos, puede que no queramos hacerlo después del cálculo del nonce, sino sólo después del cálculo de la clave pública. Si haces lo de duplicar el tiempo de computación, entonces puede que no quieras hacerlo en absoluto porque podría ser innecesario. Tal vez todo lo que queremos lograr con eso está cubierto por otras cosas.
Entonces la cuestión es cuándo queremos hacerlo y cómo queremos hacerlo. En primer lugar, ¿queremos calcular un nuevo valor p cada vez? Entonces estamos mejor con mi sugerencia anterior. O podríamos hacer algo como, un poco más barato, es sólo añadir un bit de aleatoriedad con cada llamada que todavía podría ser muy útil porque eso significa que después de 128
bits que está aleatorizado suficiente. Después de 128
llamadas estás lo suficientemente aleatorizado y es de esperar que el atacante no pueda extraer de sólo 128
llamadas.
¿Cómo añades sólo un bit de aleatoriedad sin recrear p? Una posibilidad es que después de cada operación añadas una constante o restes una constante y luego dobles. Después de 256
operaciones de bits, si ese 1
bit está efectivamente descorrelacionado con lo que el atacante conoce, entonces se ha aleatorizado todo. El problema es ¿de dónde sacas el bit? El residuo cuadrático del … no, no puedes hacer eso, y además no tenemos eso como una operación de tiempo constante. Bueno, obtenemos una clave secreta en la creación de la clave pública. Podemos hacer un hash. Ya la hashteamos para computar un nonce. Digo que durante la creación de la clave pública podría ser interesante para eso, donde se toma la clave secreta y se hace un hash.
El contexto es mutable en este momento. La pregunta adicional es si queremos hacer cambios más grandes en la API, ¿queremos una aleatorización automática? ¿Mutará el contexto? ¿La generación de la clave pública mutará el contexto? En este momento el contrato es que ninguna función modifica el estado, excepto la creación, la eliminación y la re-aleatorización de un contexto que modifica explícitamente el contexto. Esto es fácil para los usuarios porque significa que no se necesita una sobrecarga de sincronización o no hay que pensar en la seguridad de los hilos. Una posibilidad es simplemente añadir variantes de las llamadas a la API existentes que tomen un contexto mutable como argumento y luego, al utilizar estas funciones, hay que asegurarse de que se pueden utilizar. Otra alternativa es que tal vez consideremos una ruptura de la API en la que todo requiera contextos mutables. Se puede utilizar threadlocal. Con atomics, es demasiado grande.
Threadlocal .. es posible que desee hacer esto en óxido, y en C creo que requeriría C11 incluso .. a menos que utilice extensiones, como las extensiones de GCC. Otra alternativa, como de, variables threadlocal puede tener una sobrecarga en algunas plataformas mucho más que otros. Usted puede hacer esto externamente por tener el llamador no un threadlocal pero un contexto por hilo y sólo la mano el contexto adecuado a la biblioteca. Esto será muy fácil de mapear en Rust si lo introduces en una variable mutable. Rust puede resolverlo. Ahora mismo en rust soportamos nonstd. Pero podría haber ventajas, incluso si existe la posibilidad de utilizar variables threadlocal tal vez hay alternativas que serían preferidas por algunos usuarios.
Creo que empujar eso al usuario podría ser razonable. API genérica y luego decirle al usuario una buena manera de hacer esto dependiendo de su plataforma es utilizar el contexto threadlocal. La diferencia aquí es, ¿tienes un contexto threadlocal, o tienes en tu contexto tienes una variable threadlocal?
Idealmente me gustaría eliminar el contexto por completo de la API para que no hubiera ningún contexto. Eso nos facilitaría la vida. Intentamos hacer eso con el contexto estático actual, excepto que ahora tenemos una variable global. Movemos las tablas precalculadas; tenemos 3 últimas cosas. Si podemos hacer algún tipo de cosa rara threadlocal… No. No creo que queramos tener algo estático y global. En ese caso, preferiría tener un contexto pasado.
¿Pero hacer el contexto más simple? Lo que podrías hacer es deshacerte de los callbacks. Hay razones para ello. El id de la CPU es fácil. Ahora mismo ni siquiera tenemos el id de la CPU. Básicamente podrías convertir el actual contexto de propósito general en sólo el contexto ECmult y luego pasarlo a cada llamada ECmult y no pasarlo a otras llamadas.
Incluso si mantenemos el objeto de contexto en la biblioteca de óxido, ¿dónde lo obtiene el usuario? Lo ideal sería utilizar una variable global que la biblioteca exporte. Si quieren hacer la suya propia, está bien. Si están usando la variable global, y necesitan mutarla, entonces tenemos un problema. No quieres bloquearla durante toda la llamada, porque qué pasa si tienes cuatro hilos que hacen operaciones secp todas al mismo tiempo.
Imagina que abrieras el interior del objeto contexto y entonces lo que haría es copiar el p
y el p * G
que son pequeños, y luego haría la costosa actualización a b, y luego bloquearía, copiaría y desbloquearía. Así que sólo bloquearía durante el tiempo necesario, sólo para copiar dentro y fuera del objeto de contexto. No pasa nada si se actualiza en el medio porque sólo se añade aleatoriedad. Ahora mismo el contexto es sólo un objeto opaco de múltiples bytes. El problema es que en C el bloqueo requiere p-threads, a menos que uses spinlocks. ¿Qué pasaría si la biblioteca de C expusiera sólo los interiores en rust?
Espera, es una buena idea. Así que tenemos una función donde el usuario proporciona un mecanismo de bloqueo. Bueno, eso es una devolución de llamada. Sí, es una posibilidad. Eso es diferente de exponer el … no, estos serían callbacks vinculados estáticamente. Son lo suficientemente similares para mis propósitos. Bien. ¿Esto nos permitiría eliminar las devoluciones de llamada por completo? Desafortunadamente no, no lo hace.
Ahora mismo si bloqueo todo el contexto y está bloqueado mientras estoy llamando al rerandomizador, entonces estoy bloqueando el contexto para toda la rerandomización que es como 60 microsegundos o algo así. Pero podemos bloquear sólo para la copia o algo así. Creo que todavía es mucho mejor tener contextos threadlocal. Estoy de acuerdo, pero si no tengo almacenamiento threadlocal…. bien, tampoco tengo mutexes en ese caso.
Creo que por ahora en rust-secp donde hemos aterrizado es que si tenemos almacenamiento threadlocal, entonces usamos eso para todo el objeto contexto. Ahora mismo no puedes copiar un contexto porque… bueno ahora mismo no puedes usar una función estática.. hay una función de clonación. No podemos desde fuera clonar la memoria porque tiene punteros dentro de ella. La nueva función de clonación sólo hace un memcpy. No se puede garantizar esto, pero se puede llamar a clone. ¿Podemos hacer que el contexto no sea opaco? ¿No nos parece bien? Para futuros cambios. Esa es una pregunta a plantear como en el secp de bajo nivel que también expone las operaciones de grupo y los campos y esas cosas. No exponer como exponemos una clave pública .. como los datos en bruto. Ahora mismo ni siquiera… podemos comprometernos con un tamaño fijo. Ese es el problema.
Puedes volver a aleatorizar el contexto clonado, y luego sólo bloquearlo por un momento cuando lo vuelvas a copiar. Podrías hacerlo con atómicos. Puedes intercambiar los punteros y liberar la memoria. Si dos hilos diferentes, copian el puntero, editado, y ahora reemplazan el puntero entonces ambos liberarán el mismo. Veo lo que dices. Podríamos usar ARCs y reemplazar los ARKs y ellos se encargarían de la recolección de basura. Pero eso es una doble asignación.
Si tenemos threadlocal, entonces rust-secp usará threadlocal. Si no, entonces haremos algo como esto. Entonces, ¿qué necesitamos de la biblioteca estándar? Esto se convierte en una discusión de rust en este punto. ¿Está el problema resuelto? ¿Necesitamos realmente algo del upstream secp? Si no tenemos threadlocals y hacemos el contexto mutable, entonces no sé qué podemos hacer. A mí me parece que cómo puedo resolver el problema de tener varios hilos mutando los mismos datos sin tener acceso a un mutex, y la respuesta es que no se puede. ¿Cómo puedo sincronizar entre hilos sin primitivas de sincronización?
Quiero revisar la idea de la devolución de llamada. Tenemos atómicos para tener algún mecanismo de sincronización. Atómicos… podemos escribir nuestros propios spinlocks y otras cosas horribles. Puedes tener estructuras de datos desbloqueables con sólo atómicos. Vamos a hacer algo peor: vamos a hacer un spinlock. No va a girar; si se disputa en absoluto, simplemente no se vuelve a aleatorizar. Con optimismo, tratamos de hacer una sola iteración con un spinlock. Si conseguimos el acceso exclusivo, volvemos a aleatorizar, y si no podemos entonces no lo hacemos. ¿Cómo se evita que algo más durante ese tiempo acceda a él? No lo recuerdo. Tenemos una manera. Creo que esto puede funcionar. Es más complejo que mi descripción. Hay más en un spinlock que sólo un bucle y un atómico. Lo he olvidado, pero tenemos código.
La otra sugerencia es obtener un contexto, y cuando quieras actualizarlo lo clonas. Pero, ¿cómo saber cuándo liberar la memoria? Esto es realmente una discusión específica de rust. Pero si el contexto tiene tamaño en tiempo de compilación, entonces podríamos ponerlo en memoria estática. Solo lo digo. Podemos discutirlo fuera de línea. Otros han planteado esta cuestión antes. Para un usuario que va a fijar la biblioteca, que es el proyecto rust, entonces no hay en principio ninguna razón por la que no puedan hacer suposiciones sobre cuáles son los tamaños. Podrías tener una función que te diera el tamaño, pero no está garantizado que te dé el mismo tamaño cada vez que la llames… Vamos a añadirle un aleatorizador, sí.
Fijamos la biblioteca e incluso editamos el código C usando sed para el sistema de construcción. No estamos por encima de modificar. Ponemos todos los nombres de los símbolos y aplicamos parches, como la eliminación de los callbacks. En rust-secp no hay callbacks. Las eliminamos. ¿No hay una bandera de configuración para eliminar las devoluciones de llamada? Se pueden establecer en tiempo de compilación. Todo el mundo lo hace porque el problema es que puedes obtener un callback ilegal al intentar crear el contexto y en ese momento no podrías haberlo establecido ya. Ahí es donde entra nuestro parche; no queremos que… exista en el código. La razón para reemplazar el contexto es… antes de reemplazarlos, necesitas ser capaz de llamarlos.
¿Hay algún beneficio o algo nuevo en principio que aguas arriba pueda añadir una devolución de llamada? ¿O probablemente podamos resolver las cosas en rust nosotros mismos? De las devoluciones de llamada, sí. Lo único es eliminar las devoluciones de llamada en tiempo de ejecución, que es un tema aparte. No veo un callback para bloquear y desbloquear. Podrían ser NOPs. Eso podría ser aceptable para una librería en C, que es como la usan todos los usuarios ahora mismo. Sigo creyendo que no necesitas un contexto, pero si lo necesitas, …. puntero vs puntero const. Las ejecuciones en tiempo de enlace, si hay NOPs al final del enlace.. son un puntero de función mutable. Razonando esto, no creo que tu LTO pueda… si quieres punteros de función, ¿por qué no funciones enlazadas estáticamente? Cambiar la compilación no es posible para los usuarios de una biblioteca de sistema. Mucha gente espera una biblioteca contra la que pueda simplemente enlazar y utilizar. No es lo mismo que en las devoluciones de llamada actuales. Mi suposición es que un usuario los únicos usuarios que quieren cambiar las devoluciones de llamada son los usuarios que están compilando la biblioteca y tienen un conocimiento especial sobre lo que está sucediendo, en este momento. Eso es probablemente cierto en este momento.
Así que voy a pasar en un puntero no-const.. y si implemento el bloqueo y desbloqueo a mi manera? Esa es una buena pregunta. Hay un montón de formas a través de las cuales podemos hacer esto de la mutabilidad. Una de ellas es añadir nuevas APIs que tomen una versión mutable. Asumirían un bloqueo externo. Alternativamente, podría haber una bandera que se establece en la creación del contexto y este contexto sólo se utilizaría en un solo hilo de contexto y usted proporciona su propia sincronización externa y, por lo tanto, ya que estoy dando un puntero const secp se le permite modificarlo y esto es un poco feo y realmente sólo para la compatibilidad hacia atrás. Veo algunas caras de preocupación. Un puntero const no significa nada. Es básicamente una pelusa. Pero en principio, puedes tener memoria estática detrás de un puntero estático y entonces algo puede lanzar eso. Rust es diferente, por supuesto. Otra solución podría ser, si el puntero en sí es el contexto, pero podría haber una bandera diciendo para cualquier cosa mutable por favor, utilice las devoluciones de llamada. Si soy un usuario, tengo un objeto de contexto, y llamo a la señal en él, y automáticamente se reajustará. ¿Qué aspecto tiene esto? Imagino que dependerá de una especie de bandera de modo de sincronización que se establezca en el contexto. Hay un montón de combinaciones que podríamos idear: una sería que para cualquier operación mutable, el bloqueo, tienes que proporcionar un callback de bloqueo y desbloqueo, las cosas fallarían si no lo haces, y serían llamadas antes de cualquier modificación del contexto. Una cuestión interesante, por supuesto, es que actualmente tenemos APIs y la mayoría de ellas utilizan un objeto constante y otras no. Realmente la razón por la que está ahí es para señalar al usuario que ésta es segura de usar sin sincronización y la otra no. Si la expectativa sigue siendo digamos para el uno mutable, principalmente contexto re-aleatorio, y se establece este modo de oh quiero externa…. Supongo que lo llamaría también, incluso para re-aleatorizar entonces. Creo que esto está bien para la función re-randomize porque es una función extraña y tienes que leer los documentos para saber cuándo llamarla. Pero me gustaría pasar a un mundo en el que haya una versión de firma con re-randomización automática, o de nuevo en la generación de claves. La firma tendrá nonces sintéticos, por lo que no te importará, así que la generación de claves se convierte en la más fácil de hablar. Tal vez tengamos dos funciones de generación de claves: una que tome un contexto constante y otra que no, sólo por compatibilidad con el pasado. ¿Se espera que la constante no se modifique nunca, o que siga modificándose después del bloqueo? Eso da miedo porque ¿qué pasa si es un objeto de contexto estático global? El callback de bloqueo probablemente devolverá un booleano. Hacemos una promesa de la API diciendo que podemos modificar los contextos en estas funciones sólo si llamamos a su callback de bloqueo y éste devuelve 1. ¿Aunque sea un puntero constante? Sí.
¿Qué plataformas no tienen threadlocal? Webassembly es un ejemplo. Todas las RISC-V embebidas. Eso es más interesante. No hay hilos. La razón por la que lo pregunto es que si pudiéramos proporcionar una función, para digamos que tenemos nonces sintéticos y luego pudiéramos darte una función de generación de claves en la que pudieras añadir entropía para duplicar los tiempos de cálculo, pero evita por completo todas estas discusiones sobre la API. Digamos que te doy una función de generación de claves donde puedes añadir entropía, y entonces derivaría el valor p en tiempo de ejecución sin contexto en absoluto… ¿Y entonces podemos eliminar el contexto por completo? Lo siento. Me encantaría eso, creo que se resolvería. Es mucho más simple, pero tiene un costo significativo de duplicar el tiempo de cálculo. Tal vez los usuarios podrían decidir y sólo ofrecemos ambos.
Con los nonces sintéticos, la única ventaja de la aleatoriedad está en la generación de la clave. Sí. Si realmente hacemos nonces sintéticos, entonces deberíamos hacer esto. ¿Podríamos no proporcionar más entropía, sino hacer un hash de la clave privada y usar eso como aleatoriedad? En el caso del pellizco, no se puede. Derivar la misma clave pública varias veces también será determinista. A menos que tengamos un contador de destrucción o algo así… pero eso debería ser proporcionado externamente. Supongo que podríamos añadir un callback cuyo trabajo sea de alguna manera el efecto secundario….. en ARM, no puedes leer el contador de instrucciones sin una llamada al sistema. En x86, puedes simplemente llamar a la ejecución del LD y ya está- bueno, en x86 muy moderno. En x86 muy seguro. No tengamos esa pelea aquí. No hay pruebas de Intel. Podría ayudar en algunas plataformas.
…. un valor aleatorio no es… debe ser efímero, el tipo de protecciones en él. Ni siquiera es secreto para el atacante, lo hashamos junto con la clave secreta. Es como el meta contador en los nonces sintéticos. Depende del modelo del atacante, de nuevo. Pero claro. Si el atacante puede leer tu memoria sha256, entonces…. sí, por eso lo mencioné. Hay un modelo de atacante más avanzado. La aleatoriedad es mejor que la aleatoriedad pública, y la aleatoriedad es mejor que un contador, y un contador es mucho mejor que nada.
Realmente me gustaría tener una API donde no tenga que mutar un contexto.
Podríamos tener un contador atómico en secp. Pero eso requiere variables atómicas. En rust por alguna razón tenemos atómicas. O tienen atómicos o son de un solo hilo.
Acciones: hacer una API. Hacer dos APIs de keygen. Y una para las funciones públicas de tweak también. Tal vez añadir una API para generar la aleatoriedad extra y que uno puede hacer cosas raras específicas de la plataforma. No quiero eso dentro de lo normal… Podemos hacerlo externo, pero podemos proporcionar lo externo. La API de keygen es el elemento principal.
Eres un usuario de la librería secp, una librería que maneja información muy secreta y no tienes acceso a un generador de números aleatorios… Si queremos añadir un generador de números aleatorios a secp, entonces necesitaría un contexto. Podríamos hacer un contexto específico de la plataforma que sea global porque entonces también tenemos p-threads. No importa, no importa. Lo siento. Ignórame, por favor.
Podemos cerrar la discusión del contexto como contexto constante. Podemos dejar re-randomize dentro, y añadir documentación que diga, no necesitas usar esto. No hay ningún beneficio en usar esto si estás usando las APIs alternativas. Si la gente por alguna razón piensa que la mutabilidad es más fácil de pensar. Bien, ahora podemos cerrar nuestro hilo de 500 comentarios de hace 2 años. Después de que Matt entró en los spinlocks, dejé de leer.
Ámbito de la biblioteca
La gente es libre de salir. Cierren las puertas. ¿Cuál es el alcance de la discusión del ámbito?
Existe esta extraña situación en la que tenemos libsecp, tenemos libsecp256k1-zkp y luego otras bifurcaciones de la misma. No hay ninguna regla escrita sobre qué va a cada biblioteca. Una aproximación sería, bueno el propósito de libsecp256k1 es que está bajo la biblioteca Bitcoin Core y tal vez sólo incluye la funcionalidad que también está en Core. Esto sería incorrecto porque ya incluye ECDH. Puedes decir que es correcto excepto por ECDH. O puedes decir que va a estar bien en el futuro, o puedes decir que debería estar bien y que deberíamos eliminar ECDH. Creo que esto es completamente erróneo. No creo que ese deba ser el objetivo de libsecp256k1. Es un ámbito relativamente bien definido… si el objetivo principal es servir a Bitcoin Core entonces deberíamos centrarnos en eso y no gastar recursos en otras cosas. Así es como libsecp256k1 puede servir mejor a Bitcoin Core es limitando nuestro alcance.
-zkp en general no tiene el tipo de estabilidad y garantías de calidad y corrección. Incluso sólo usando la firma ECDSA, no querría usar ECDSA de -zkp aunque soy el autor y sé que no ha cambiado, todavía no lo usaré. Para libsecp256k1 en sí, creo que ECDH se usa en lightning y es bastante simple de mantener ahora. Hemos cambiado la API de hashing recientemente. No, el ajuste donde 1
a 2
fue cambiado a 0
y 1
. Alguien se dio cuenta de que todo su hack no era necesario.
Realmente creo que deberíamos exponer ECDH y SHA2. Pero no voy a empezar esa pelea aquí. Bueno, quiero importar SHA2. Quiero que secp tenga una forma de usar el SHA256 de la persona que llama. Hay un tema para eso. Sin embargo, esta es una discusión diferente. Esa discusión era sobre la importación, no sobre la exposición.
No es la discusión que tenía en mente cuando dije alcance. Yo diría que queremos ampliar el alcance porque al final MuSig2 y FROST van a ser utilizados por el ecosistema bitcoin. Esto es básicamente todos los criptógrafos del ecosistema bitcoin. Si un meteorito nos golpea en esta sala, Lloyd puede dar un paso adelante, supongo. libsecp256k1 es la mejor biblioteca del mundo para secp en términos de corrección.
Es mucho más difícil conseguir este tipo de garantías de corrección para MuSig2 y FROST. Son protocolos interactivos con muchas partes móviles. No estoy seguro de que MuSig2 llegue a Bitcoin Core. Ciertamente espero que llegue al Core. MuSig-DN quizás. MuSig2 requiere mantener el estado de forma segura y no reutilizar los nonces y eso es muy difícil de garantizar a menos que ya hagas esa garantía como en lightning.
La API de Musig2 es más compleja que las cosas que tenemos. Creo que estás de acuerdo. FROST aún más. Pero no creo que debamos tener sólo cosas sencillas en la biblioteca como criterio obligatorio de distinción. Si se van a implementar en cualquier lugar, y creemos que tenemos la experiencia para dar la mejor revisión posible disponible en el ecosistema, entonces ¿por qué no íbamos a incluirlo en el ámbito de la biblioteca? No sólo la mejor revisión posible, sino también las mejores funciones subyacentes. La gente podría bifurcarla. Es más ambicioso, estoy de acuerdo, y hay más riesgos.
MuSig es difícil para Bitcoin Core porque no se puede garantizar a un usuario que los nonces no serán reutilizados. ¿Por qué no? Porque si el estado de su sistema es clonado en el momento equivocado, entonces se reutilizará el nonce. Esa es una nueva suposición en Bitcoin Core. No sé. Veo este argumento pero creo que tampoco debemos olvidar que el punto de tener MuSig es que realmente te da más seguridad porque puedes hacer multifirmas. Si no se recalculan los nonces, y se desecha todo el estado si algo va mal de alguna manera, pero no se sabe si algo va mal, ¿verdad?
La razón por la que dices que MuSig en Bitcoin Core puede no tener sentido es porque es peligroso para Core en el estado. Sí, pero es peligroso para todo el mundo, excepto para los rayos, porque ellos ya tienen esta suposición. Sigue siendo peligroso para ellos. ¿Pero estás diciendo que nadie debería usar MuSig? Otra pregunta sería si Core está dispuesto a añadir el rayo? Si la gente no asume las suposiciones de Lightning, ¿debería usar MuSig? Probablemente no. No. Entonces, ¿deberían seguir con las multifirmas, tapscript y SIGADD? Tal vez.
Hay formas potencialmente seguras de utilizar MuSig si la gente sabe cómo utilizarlo correctamente en determinados contextos. Lo que quiere decir es que ahora mismo no existe esa forma. El argumento aquí es que usted está ejecutando MuSig en una máquina virtual que se revive y se instantánea en dos lugares. El estado entre esos dos podría ser literalmente indistinguible. Este es un lema de bifurcación. Las firmas son falsificables si no puedes falsificarlas de esta manera. Eso es lo que probamos. Pero, hay una protección obvia no perfecta pero, lo mejor que se puede hacer es conseguir una aleatoriedad del sistema realmente buena antes de llamar. Hacer la ventana de tiempo tan pequeña como sea posible. Hay mitigaciones. Es más importante ser consciente de este problema que utilizarlo como un salto para no hacerlo.
En MuSig, se necesita un estado incorruptible no reproducible. El problema aparece si alguien hace la ronda 1 contigo, y entonces… hay una forma de extraer tu clave privada. Si te las arreglas para terminar en una situación en la que una VM es instantánea después de la primera ronda y luego se restaura en dos máquinas y el co-firmante atacante logra interactuar con ambos sistemas restaurados, entonces será capaz de extraer la clave. No tienes control de la ventana de tiempo entre la ronda 1 y la ronda 2.
Si asumes que tu propia máquina no es maliciosa, entonces puedes escribir un código que diga que después de unos segundos destruiremos los nonces y volveremos a hacer la ronda 1. Sin embargo, esto no resuelve el problema. En la práctica, si asumes que los relojes son consistentes en las máquinas virtuales, lo cual suele ser cierto, eso podría salvarte. Puedes ir y determinar el reloj. ¿Por qué elegirías como cofirmante a otro cofirmante que está dispuesto a funcionar con un modelo de funcionamiento tan inseguro? No deberías confiar en esa gente, ¿verdad?
No deberíamos tener nonces precomputados en Bitcoin Core. Y en libsecp256k1. Posiblemente. ¿Por qué? Pre-procesamiento… añadiendo el mensaje como argumento para crear los nonces. Es sólo defensa en profundidad. Necesitas aleatoriedad de todos modos. El punto no es guardar. Guardar, sí que es malo. Creo que nos hemos desviado por la seguridad de MuSig.
Digamos que no fuera un problema de seguridad con MuSig y que hubiera una forma segura de usarlo con la que estuviéramos cómodos, pero que no fuera a entrar en Bitcoin Core, ¿tendría sentido ponerlo en libsecp256k1 en lugar de -zkp? Digo que sí porque está claro que se convertirá en una parte importante del ecosistema, aparte de que se adopte e invente algo mejor a corto plazo. Pero también podríamos eliminar MuSig de la biblioteca en el futuro. En su día eliminamos la implementación de la firma Schnorr. El original antes de MuSig sólo añadía los puntos y las firmas, eso fue hace mucho tiempo. Éramos todos jóvenes.
Hay algunas ideas de cómo la gente piensa en libsecp256k1. Por un lado está el pensamiento de que sólo debería servir a Bitcoin Core. Otro lado es que debería servir al ecosistema bitcoin más amplio, por supuesto con algunas restricciones en el alcance. No todas las características posibles, por supuesto, porque tenemos que desarrollarlo y mantenerlo. Pero nos gustaría que fuera la biblioteca mejor revisada. Si todo el mundo viene con su petición de características, entonces no seremos capaces de mantener la calidad que ya tenemos. Debería haber cierto consenso entre los colaboradores de que se trata de una característica que será útil para el ecosistema, por ejemplo. En el otro extremo, es cada módulo que la gente está PRingiendo debe ser añadido. Hay mucho en el medio, como, en el extremo de que sólo sirve a Bitcoin Core entonces no tenemos que prometer ninguna estabilidad de la API, siempre y cuando Bitcoin Core nos dé la API correcta.
A menudo he querido utilizar internos que creo que es imposible. Como para protocolos eficientes para mi propio trabajo. No está relacionado. Es una discusión diferente pero ciertamente se relaciona.d Si hubiera una manera más fácil de bifurcarlo, entonces parte de esta discusión no importaría, o tener internos expuestos. Fork con bindings a rust para los internos de libsecp256k1, eso está en mi lista. Si los mantenedores no lo quieren en libsecp256k1, entonces poder construir en libsecp256k1 estaría bien. La única opción ahora mismo es la bifurcación. Pero si quieres módulos de múltiples bifurcaciones, entonces necesitas esta cosa de rebasamiento, así que tal vez tienes una propuesta para exponer los internos como un módulo experimental?
¿Qué te parecería la posibilidad de compilar otra biblioteca a partir del mismo código fuente con algún truco para asegurarse de que puedes enlazar ambas al mismo tiempo, lo que expone sólo los elementos internos? Esta idea ya se ha planteado antes. Otra idea era dividirlo en dos capas con una biblioteca de bajo nivel y luego una biblioteca de alto nivel, pero esto se encuentra con problemas obvios. No creo que queramos escribir toda la librería de alto nivel como una función de una librería de bajo nivel porque incurre en un coste de desarrollo adicional.
Su propuesta es añadir un módulo interno, marcado como experimental, que exponga las partes internas. Todo el mundo que vincule la biblioteca esperando que esté allí sería desafortunado. Tener una segunda biblioteca estaría bien, porque entonces -zkp puede usar esa otra biblioteca. Todavía se incurre en un coste, convirtiendo a formatos serializables en cada paso de entrada y salida. Si tienes que marshal cosas a través de un límite para hacer un tiempo de ejecución, estoy de acuerdo en que hay un costo … o inline-ability de una operación de campo. ¿Quieres exponer una operación de campo que tarda una fracción de nanosegundo?
Una preocupación que tengo con sólo exponer las cosas de bajo nivel, es decir que quieres implementar algo como MuSig, sería molesto no poder usar las funciones de verificación de Schnorr por ejemplo. Sin embargo, puedes enlazar ambas bibliotecas al mismo tiempo, en esa propuesta. Tienes que saber cuándo llamar a normalizar y no es obvio. Estarías totalmente a tu aire. Lo mismo si te bifurcas. Una interfaz sana de bajo nivel no expondría la normalización y lo haría por ti. Pero esa es una pregunta: ¿hasta dónde llegas? Si vas tan bajo como tener la normalización allí, entonces realmente deberías copiar el código fuente en tu propia cosa. El coste de una llamada a una función va a ser peor que la normalización.
Para la biblioteca interna no tendrías que exponer mucho; escalares y operaciones de grupo. Incluso con la sobrecarga de perder el inlineing y esas cosas, puedes hacer cosas de alto rendimiento con coordenadas jacobianas y llamar a EC multgen. Ese es el nivel que utiliza Simplicity, creo. Necesitas operaciones de campo si quieres ECDSA. Sin embargo, la compartición de secretos Shamir se puede hacer sobre escalares. Incluso si expones las operaciones de campo, si estás de acuerdo con la sobrecarga de la llamada a la función y la sobrecarga de la normalización por llamada, que podría ser porque no hacemos muchas operaciones de campo en bruto. Incluso para las pruebas de balas, todo nuestro trabajo pesado es el material ECmult. No obtendríamos mucho más beneficio de… no obtendríamos mucho más beneficio de poder alinear las operaciones de campo frente al beneficio que ya obtenemos de tener puntos Jacobianos y poder llamar a ECmult.
La razón por la que sugerí una biblioteca separada es más psicológica que otra cosa. Me preocupa exponer eso en la misma biblioteca y que la gente tenga la expectativa equivocada de que esto es tan bueno para usar. “Si enlazo con libsecp entonces sé lo que estoy haciendo”… no se puede simplemente llamar al módulo “sé lo que estoy haciendo”. Pero creo que si lo llamamos interno-inestable o algo así… O algo así como peligrosos-internos o algo así. O palabras como “inestable”. O simplemente palabras desalentadoras. O “internos” también debería ser desalentador. Tendrías que usar ambas bibliotecas, no sólo la interna.
Antes de usar esta biblioteca, entonces tienes que llamarla con la cadena de versión exacta o algo así. ¿Qué vas a hacer si está mal? Simplemente llamarla con una cadena de versión correcta para ella. Quiero que la versión interna sea X, y si no lo es, entonces muérete. Sin embargo, las distribuciones no pueden empaquetarlo. ¡Pero la naturaleza siempre encuentra una manera! Han parcheado la aleatoriedad de openssl. Eso es lo que hizo debian. Esto rompe valgrind, vamos a eliminar la aleatoriedad. ¿Quién lo necesita?
¿Puedo volver al ámbito de aplicación? Podríamos imaginar que podríamos acordar una propuesta que diga que sí queremos cosas que probablemente sean significativamente relevantes para el ecosistema bitcoin según nosotros, la gente que tiene que hacer el trabajo. ¿Tendría sentido hacer un PR de tal cosa en el repositorio? No sé cuánto ayuda si decimos que está bien, que decidimos caso por caso. Pero siempre es así. Si tenemos una política, ayuda a las decisiones futuras. También podría dar unos requisitos mínimos. Antes de escribirla, hay que leer la política.
Hay algunas cosas que suceden con los pagos silenciosos. No sé cuánto se ha desarrollado. Parece que se necesita este ECDH sólo x que tiene un pull request muy antiguo y anticuado a libsecp. Dado el aparente interés en las direcciones de pago silencioso, no creo que sea descabellado que le echemos un vistazo. Ese es el nivel de las cosas.
Para alguien que está tratando de decidir, tal vez quiero esto en secp o tal vez debería vivir en otro lugar, tener algún documento donde pueda ir a mirar y ver aquí están los tipos de cosas que normalmente van a secp y aquí está el proceso de con quién hablar y cuáles son los pasos. Si no es el lugar adecuado, ¿qué hago en su lugar? Los hechos hablan más que las palabras. El hecho de que no hayamos tenido nuevos módulos aparte de Schnorr sig debería establecer una expectativa por sí misma, independientemente de que la gente lea este documento o no.
¿Por qué se hizo PR MuSig en -zkp? ¿Porque es más fácil experimentar e iterar allí? Los módulos experimentales en secp no son realmente experimentales. Los módulos experimentales en libsecp son sólo experimentales en términos de la API es la forma en que pienso en ello no en términos de seguridad. Los módulos experimentales -zkp, como recordar el PR de bulletproofs que nadie leyó para la evaluación comparativa del papel y esas cosas, que fue desplegado en grin. Deberíamos ser conscientes de que la gente hace eso. Así que no es experimental ahora; alguien lo está usando en producción.
Tuve un pull request a libsecp/rust para grin que mejora su rendimiento en un 80%. Ha estado abierto durante 3 años. A ellos no les importa.
Además de los pagos silenciosos, ¿qué pasa con las firmas de los adaptadores? Estoy de acuerdo en que son una parte importante del ecosistema, pero cada vez es más de nicho y se aleja de los límites de la criptografía revisada por pares. Tampoco sé si los contratos de registro discreto serían apropiados. Una buena manera de hacerse una idea sería tener más ejemplos. Una parte de esto es que nosotros, principalmente los mantenedores, pero también los revisores y contribuyentes, tengamos una idea de cuál es la tolerancia y las expectativas de cada uno. Es un hecho que libsecp no estuvo bien mantenida durante mucho tiempo. Ha mejorado en los últimos años. Yo tengo la culpa de esto. Esto ha dado lugar a que no tengamos una liberación, por ejemplo, y a que las expectativas de la biblioteca sean poco claras, algunas cosas no avanza. Podemos mejorar esto.
Sería útil tener una especificación clara de cualquier esquema antes de que pueda ser incluido en libsecp256k1. ¿Cómo debería ser esa especificación? ¿Puede ser un comentario de 20 líneas explicando? ¿Tiene que ser hac-spec? x-sólo ECDH se puede especificar perfectamente en unas pocas líneas… Lo único que quería decir es que esto eleva un poco el listón de lo que consideramos. Es un requisito razonable. Es bueno también porque lo que no queremos es que alguien diga oh, ya sabes, necesito alguna variante de ECDH por la razón que sea y la implemente aquí hay un módulo. La única especificación del esquema es lo que se implementa allí. Al menos tenemos el callback para el hash de las coordenadas, así que es genérico… Pero no hay ninguna especificación, sí. De acuerdo. Así que según lo que digo, supongo que no deberíamos aceptar ECDH en su estado actual. Es efectivamente- inventamos un esquema de ECDH y lo implementamos y no está escrito en ninguna parte, e impactó a muchas bibliotecas. Muchas bibliotecas lo soportan ahora. Junto con esto, aquí proponemos un esquema ECDH que es compatible con secp y aquí hay una implementación diferente- oh todo el mundo adopta la única implementación que existe y por esto ad-hoc define un estándar, no creo que libsecp256k1 deba ser el lugar a través del cual se adoptan los estándares.
Probablemente también queremos sólo cosas demostrables. Como ajustes y otras cosas. Ese es un buen elemento para revisar un esquema. ¿Deberíamos aceptar ECDSA? Está probado. Depende de qué suposiciones. La confianza y la seguridad es un requisito para entrar en libsecp256k1 y la seguridad demostrable es un componente muy útil para ello.
¿Debería haber una sugerencia para llegar a los mantenedores y preguntar si esto es algo en lo que están interesados antes de asumir que algo será fusionado si se escribe? Eso es recomendable en general, no sólo en libsecp256k1. Tal vez si tenemos una política escrita podríamos incluir una mención que hey antes de escribir 2000 líneas de código entonces tal vez llegar y hablar con los mantenedores. Si producimos un documento de este tipo, ¿conseguiría ser revisado? Si el documento es un archivo CONTRIBUTING.md, sería bastante bueno. También sería un buen punto de partida para las convenciones de codificación.
Punto de acción: un archivo CONTRIBUTING.md. ¿Tendremos que reevaluar a dónde pertenece MuSig? ¿O hay que discutirlo más adelante? El sentimiento en la sala es que probablemente MuSig2 debería pertenecer a libsecp256k1. También hay mucha gente que se pregunta cuándo va a entrar MuSig2 en libsecp256k1 para que la biblioteca se utilice de facto en el ecosistema y no sólo en Bitcoin Core. Es una realidad.
El archivo CONTRIBUTING.md debería decir, a grandes rasgos, que el ámbito de aplicación son los módulos que probablemente sean relevantes en el ecosistema bitcoin que tengan algún tipo de especificación o prueba de seguridad y en los que tengamos cierta confianza en la seguridad del protocolo y la implementación. Quizá podamos añadir otros requisitos.
FROST podría formar parte de esto en el futuro. Con la condición de que haya una especificación y confianza, no veo por qué no. Si la gente tiene una idea genial con la que quiere jugar, hay muchas posibilidades de que la PR la incluya en -zkp. Blockstream tiene que decidir si quiere seguir manteniendo -zkp, bueno yo no diría que lo mantenemos realmente. Por lo menos en -zkp no tenemos obligaciones con la comunidad bitcoin de estar liberando código bien depurado.