-
Notifications
You must be signed in to change notification settings - Fork 4
Add new protocol version blog post (EN/ES) #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| +++ | ||
| title = "Nueva versión del protocolo Mostro" | ||
| date = "2026-06-18T12:00:00Z" | ||
|
|
||
| [extra] | ||
| author = "negrunch" | ||
| img = "/img/vesion2.jpg" | ||
| summary = "La versión 2 del protocolo Mostro deja atrás los gift wraps (NIP-59) para el envío de mensajes entre Mostro y los clientes, adoptando en su lugar eventos kind 14 con contenido encriptado mediante NIP-44. Este cambio cierra la ventana de ataque que bautizamos como \"Gift Wrap Apocalypse\", un vector de spam que, cualquiera podría usar para inutilizar un nodo Mostro, sin sacrificar la privacidad, ya que mantenemos la rotación de llaves por cada orden. La mejora llega en la versión 0.18.0 del nodo Mostro y, junto al anti-abuse bond, deja a Mostro listo para producción." | ||
| +++ | ||
|
|
||
| ## Cómo empezamos | ||
|
|
||
| Cuando comenzamos a trabajar en Mostro, teníamos que decidir de qué manera los clientes y el nodo Mostro se iban a comunicar. Los primeros experimentos los hicimos utilizando NIP-04, con el que encriptábamos la data en Nostr; en ese momento NIP-04 era el estándar. | ||
|
|
||
| NIP-04 tenía un problema: filtraba información de los usuarios, y esa información podía servir para que terceros los deanonimizaran. Como en los inicios de Mostro el usuario podía publicar órdenes utilizando cualquier llave privada, empezamos a notar que algunos usuarios usaban la misma llave privada con la que posteaban en clientes como Amethyst, Damus, etc., lo cual era todavía mucho más terrible para su privacidad. | ||
|
|
||
| Inmediatamente comenzamos a trabajar en una solución que le permitiera al usuario estar protegido sin afectar la UX de los clientes. Por eso pensamos, implementamos, repensamos y reimplementamos la primera versión del protocolo. | ||
|
|
||
| ## La primera versión: gift wraps y rotación de llaves | ||
|
|
||
| Decidimos utilizar gift wraps (NIP-59), que nos venían como anillo al dedo, ya que ocultaban datos como el origen del mensaje: cada mensaje se envía con una llave efímera. Aun así, seguíamos teniendo un problema. Los mensajes que Mostro enviaba al cliente iban dirigidos a una pubkey única del usuario, y si los usuarios estaban usando la misma pubkey con la que posteaban en Damus, iba a ser muy sencillo vincularlos con Mostro. | ||
|
|
||
| Así que decidimos crear un sistema de rotación de llaves. En lugar de permitir al usuario ingresar una llave privada, hicimos que los clientes generaran una seed (BIP-39) y, a partir de ahí, el cliente generara una llave para cada orden que el usuario creara o tomara, al más puro estilo de una wallet de Bitcoin (BIP-32). | ||
|
|
||
| La implementación no era sencilla, pero el resultado era que el usuario obtenía un alto grado de privacidad. | ||
|
|
||
| ## El "Gift Wrap Apocalypse" | ||
|
|
||
| En la teoría esto funciona muy bien, pero la utilización de gift wraps en Nostr abre una ventana de ataque a los relays y a los nodos Mostro. A este ataque yo lo llamo "Gift Wrap Apocalypse". | ||
|
|
||
| Como los gift wraps se envían con llaves efímeras y el timestamp modificado, un atacante puede enviar cualquier cantidad de estos eventos con basura dentro, espameando, y hasta que Mostro no los desencripte no sabrá si son eventos legítimos o no. Esto hace muy costoso resistir estos ataques, ya que desencriptar requiere recursos de Mostro. En teoría es muy fácil inutilizar un nodo Mostro enviando una gran cantidad de estos eventos; ahora, con IA, cualquier script kiddie sin ningún conocimiento técnico puede atacar a un nodo Mostro hasta dejarlo sin capacidad de respuesta. | ||
|
|
||
| Hasta ahora no hemos recibido este temido ataque, pero antes de que ocurra nos hemos adelantado y hemos decidido prescindir de los gift wraps para el envío de mensajes entre Mostro y los clientes. Sí, eliminamos una capa de privacidad, pero, siendo sinceros, al rotar llaves por cada orden seguimos manteniendo un alto grado de privacidad al operar en Mostro. | ||
|
|
||
| ## La solución: kind 14 + NIP-44 | ||
|
|
||
| En su lugar utilizamos eventos kind 14 con el contenido encriptado (NIP-44). Así, sin más, tan sencillo como eso. Hemos pasado de tener un contenido encriptado como este: | ||
|
|
||
| ```json | ||
| // external wrap layer | ||
| { | ||
| "id": "<id>", | ||
| "kind": 1059, | ||
| "pubkey": "<Buyer's ephemeral pubkey>", | ||
| "content": { | ||
| // seal | ||
| "id": "<seal's id>", | ||
| "pubkey": "<index 0 pubkey (identity key)>", | ||
| "content": { | ||
| // rumor | ||
| "id": "<rumor's id>", | ||
| "pubkey": "<Index 1 pubkey (trade key)>", | ||
| "kind": 1, | ||
| "content": [ | ||
| { | ||
| "order": { | ||
| "version": 1, | ||
| "id": "<Order Id>", | ||
| "trade_index": 1, | ||
| "action": "take-sell", | ||
| "payload": null | ||
| } | ||
| }, | ||
| "<index 1 signature of the sha256 hash of the serialized first element of content>" | ||
| ], | ||
| "created_at": 1691518405, | ||
| "tags": [] | ||
| }, | ||
| "kind": 13, | ||
| "created_at": 1686840217, | ||
| "tags": [], | ||
| "sig": "<index 0 pubkey (identity key) signature>" | ||
| }, | ||
| "tags": [["p", "<Mostro's pubkey>"]], | ||
| "created_at": 1234567890, | ||
| "sig": "<Buyer's ephemeral pubkey signature>" | ||
| } | ||
| ``` | ||
|
|
||
| A este: | ||
|
|
||
| ```json | ||
| [ | ||
| { | ||
| "order": { | ||
| "version": 2, | ||
| "id": "<Order Id>", | ||
| "trade_index": 1, | ||
| "action": "take-sell", | ||
| "payload": null | ||
| } | ||
| }, | ||
| "<index 1 signature of the sha256 hash of the serialized first element>", | ||
| ["<index 0 pubkey (identity key)>", "<index 0 identity proof signature>"] | ||
| ] | ||
| ``` | ||
|
|
||
| No ahondaré en detalles técnicos, ya que esto puedes verlo en la [documentación del protocolo](https://mostro.network/protocol/key_management.html). | ||
|
|
||
| ## Versionado y disponibilidad | ||
|
|
||
| Esta mejora sale en la versión 0.18.0 de Mostro node. A partir de ahí, la versión 1 del protocolo queda deprecada, pero todavía se puede utilizar. En la versión 0.19.0, la opción de protocolo por defecto de Mostro será la "2", y todo rastro de la versión "1" será eliminado: es tiempo suficiente para que todos los clientes Mostro se actualicen. | ||
|
|
||
| Con esta mejora, junto al [anti-abuse bond](https://mostro.network/blog/es/anti-abuse-bond/), consideramos que Mostro está listo para ser utilizado en producción. Siempre teniendo en cuenta que es software experimental y seguramente con bugs por arreglar, pero confiamos en que tenemos un producto estable que brinde soluciones a quienes requieran poder comprar y vender Bitcoin libremente, sin miedo a la censura, represalias o vigilancia. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| +++ | ||
| title = "A New Version of the Mostro Protocol" | ||
| date = "2026-06-18T12:00:00Z" | ||
|
|
||
| [extra] | ||
| author = "negrunch" | ||
| img = "/img/vesion2.jpg" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for image files in the static/img directory
fd -e jpg -e png -e webp 'vesion|version' --search-path static/img 2>/dev/null || echo "No static/img directory found or no matching images"
# Also check the PR diff for the actual filename
git diff HEAD~1 --name-only | grep -i "vesion\|version.*jpg" || echo "No image file changes in diff"Repository: MostroP2P/blog Length of output: 316 Correct the image filename from The static file currently exists as 🤖 Prompt for AI Agents |
||
| summary = "Version 2 of the Mostro protocol leaves gift wraps (NIP-59) behind for messaging between Mostro and clients, adopting instead kind 14 events with content encrypted via NIP-44. This change closes the attack window we nicknamed the \"Gift Wrap Apocalypse\", a spam vector that, anyone could use to take down a Mostro node, without sacrificing privacy, since we keep rotating keys for every order. The improvement ships in version 0.18.0 of the Mostro node and, together with the anti-abuse bond, makes Mostro ready for production." | ||
| +++ | ||
|
|
||
| ## How we started | ||
|
|
||
| When we began working on Mostro, we had to decide how clients and the Mostro node would communicate. Our first experiments used NIP-04, which we used to encrypt data on Nostr; at that time NIP-04 was the standard. | ||
|
|
||
| NIP-04 had a problem: it leaked user information, and that information could help third parties deanonymize them. Since in Mostro's early days a user could publish orders using any private key, we started to notice that some users were using the same private key they posted with on clients like Amethyst, Damus, etc., which was far more terrible for their privacy. | ||
|
|
||
| We immediately started working on a solution that would keep the user protected without hurting the clients' UX. So we thought, implemented, rethought, and reimplemented the first version of the protocol. | ||
|
|
||
| ## The first version: gift wraps and key rotation | ||
|
|
||
| We decided to use gift wraps (NIP-59), which fit us like a glove since they hid data such as the origin of the message: each message is sent with an ephemeral key. Even so, we still had a problem. The messages Mostro sent to the client were addressed to a unique user pubkey, and if users were using the same pubkey they posted with on Damus, it would be very easy to link them to Mostro. | ||
|
|
||
| So we decided to create a key rotation system. Instead of letting the user enter a private key, we made the clients generate a seed (BIP-39) and, from there, the client would generate a key for every order the user created or took, in the purest Bitcoin wallet style (BIP-32). | ||
|
|
||
| The implementation wasn't simple, but the result was that the user obtained a high degree of privacy. | ||
|
|
||
| ## The "Gift Wrap Apocalypse" | ||
|
|
||
| In theory this works very well, but using gift wraps on Nostr opens an attack window against relays and Mostro nodes. I call this attack the "Gift Wrap Apocalypse". | ||
|
|
||
| Since gift wraps are sent with ephemeral keys and a modified timestamp, an attacker can send any number of these events with garbage inside, spamming, and until Mostro decrypts them it won't know whether they are legitimate events or not. This makes resisting these attacks very costly, because decrypting requires Mostro's resources. In theory it's very easy to take down a Mostro node by sending a large number of these events; now, with AI, any script kiddie with no technical knowledge can attack a Mostro node until it's left unable to respond. | ||
|
|
||
| So far we haven't received this dreaded attack, but before it happens we've gotten ahead of it and decided to drop gift wraps for messaging between Mostro and clients. Yes, we removed a layer of privacy, but, to be honest, by rotating keys for each order we still maintain a high degree of privacy when operating on Mostro. | ||
|
|
||
| ## The solution: kind 14 + NIP-44 | ||
|
|
||
| Instead we use kind 14 events with encrypted content (NIP-44). Just like that, as simple as that. We've gone from having encrypted content like this: | ||
|
|
||
| ```json | ||
| // external wrap layer | ||
| { | ||
| "id": "<id>", | ||
| "kind": 1059, | ||
| "pubkey": "<Buyer's ephemeral pubkey>", | ||
| "content": { | ||
| // seal | ||
| "id": "<seal's id>", | ||
| "pubkey": "<index 0 pubkey (identity key)>", | ||
| "content": { | ||
| // rumor | ||
| "id": "<rumor's id>", | ||
| "pubkey": "<Index 1 pubkey (trade key)>", | ||
| "kind": 1, | ||
| "content": [ | ||
| { | ||
| "order": { | ||
| "version": 1, | ||
| "id": "<Order Id>", | ||
| "trade_index": 1, | ||
| "action": "take-sell", | ||
| "payload": null | ||
| } | ||
| }, | ||
| "<index 1 signature of the sha256 hash of the serialized first element of content>" | ||
| ], | ||
| "created_at": 1691518405, | ||
| "tags": [] | ||
| }, | ||
| "kind": 13, | ||
| "created_at": 1686840217, | ||
| "tags": [], | ||
| "sig": "<index 0 pubkey (identity key) signature>" | ||
| }, | ||
| "tags": [["p", "<Mostro's pubkey>"]], | ||
| "created_at": 1234567890, | ||
| "sig": "<Buyer's ephemeral pubkey signature>" | ||
| } | ||
| ``` | ||
|
|
||
| To this: | ||
|
|
||
| ```json | ||
| [ | ||
| { | ||
| "order": { | ||
| "version": 2, | ||
| "id": "<Order Id>", | ||
| "trade_index": 1, | ||
| "action": "take-sell", | ||
| "payload": null | ||
| } | ||
| }, | ||
| "<index 1 signature of the sha256 hash of the serialized first element>", | ||
| ["<index 0 pubkey (identity key)>", "<index 0 identity proof signature>"] | ||
| ] | ||
| ``` | ||
|
|
||
| I won't dive into technical details, since you can see this in the [protocol documentation](https://mostro.network/protocol/key_management.html). | ||
|
|
||
| ## Versioning and availability | ||
|
|
||
| This improvement ships in version 0.18.0 of the Mostro node. From there, version 1 of the protocol is deprecated but can still be used. In version 0.19.0, Mostro's default protocol option will be "2", and every trace of version "1" will be removed: enough time for all Mostro clients to update. | ||
|
|
||
| With this improvement, together with the [anti-abuse bond](https://mostro.network/blog/anti-abuse-bond/), we consider Mostro ready to be used in production. Always keeping in mind that it's experimental software and surely has bugs to fix, but we trust we have a stable product that provides solutions to those who need to be able to buy and sell Bitcoin freely, without fear of censorship, retaliation, or surveillance. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Image filename typo affects the Spanish post too.
The Spanish post references the same image path
/img/vesion2.jpgon line 7. Ensure that once you correct the filename in the English post (line 7, filecontent/new-protocol-version.md), you also update it here.🤖 Prompt for AI Agents