<rss
      xmlns:atom="http://www.w3.org/2005/Atom"
      xmlns:media="http://search.yahoo.com/mrss/"
      xmlns:content="http://purl.org/rss/1.0/modules/content/"
      xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
      xmlns:dc="http://purl.org/dc/elements/1.1/"
      version="2.0"
    >
      <channel>
        <title><![CDATA[hodlbod]]></title>
        <description><![CDATA[Christian Bitcoiner and developer of the coracle.social nostr client.
Learn more at https://coracle.tools]]></description>
        <link>https://hodlbod.npub.pro/tag/nip44/</link>
        <atom:link href="https://hodlbod.npub.pro/tag/nip44/rss/" rel="self" type="application/rss+xml"/>
        <itunes:new-feed-url>https://hodlbod.npub.pro/tag/nip44/rss/</itunes:new-feed-url>
        <itunes:author><![CDATA[ hodlbod]]></itunes:author>
        <itunes:subtitle><![CDATA[Christian Bitcoiner and developer of the coracle.social nostr client.
Learn more at https://coracle.tools]]></itunes:subtitle>
        <itunes:type>episodic</itunes:type>
        <itunes:owner>
          <itunes:name><![CDATA[ hodlbod]]></itunes:name>
          <itunes:email><![CDATA[ hodlbod]]></itunes:email>
        </itunes:owner>
            
      <pubDate>Fri, 05 Jan 2024 22:03:37 GMT</pubDate>
      <lastBuildDate>Fri, 05 Jan 2024 22:03:37 GMT</lastBuildDate>
      
      <itunes:image href="https://i.nostr.build/AZ0L.jpg" />
      <image>
        <title><![CDATA[hodlbod]]></title>
        <link>https://hodlbod.npub.pro/tag/nip44/</link>
        <url>https://i.nostr.build/AZ0L.jpg</url>
      </image>
      <item>
      <title><![CDATA[Groups on Coracle — finally!]]></title>
      <description><![CDATA[Coracle now has closed groups! Read about why I built them the way I did, what's possible, and what's coming.]]></description>
             <itunes:subtitle><![CDATA[Coracle now has closed groups! Read about why I built them the way I did, what's possible, and what's coming.]]></itunes:subtitle>
      <pubDate>Fri, 05 Jan 2024 22:03:37 GMT</pubDate>
      <link>https://hodlbod.npub.pro/post/1704491208030/</link>
      <comments>https://hodlbod.npub.pro/post/1704491208030/</comments>
      <guid isPermaLink="false">naddr1qqxnzdesxs6rjvfjxqurqvesqgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa28zalvec</guid>
      <category>nostr</category>
      
        <media:content url="https://i.nostr.build/rEoG.jpg" medium="image"/>
        <enclosure 
          url="https://i.nostr.build/rEoG.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qqxnzdesxs6rjvfjxqurqvesqgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa28zalvec</noteId>
      <npub>npub1jlrs53pkdfjnts29kveljul2sm0actt6n8dxrrzqcersttvcuv3qdjynqn</npub>
      <dc:creator><![CDATA[ hodlbod]]></dc:creator>
      <content:encoded><![CDATA[<p>Today marks the biggest release so far in Coracle's history. There have been many good days, like when I introduced Coracle to the nostr telegram group, or when I got my fellowship with FUTO, or when I got my grant from OpenSats, or when I got to speak at Nostrasia. But in terms of realizing the vision I've had for the software - for over two years - today is the day.</p>
<p>Coracle now has private groups.</p>
<p>This means you can now send almost any nostr event over an encrypted channel to the rest of the group's members. This is substantially different from group chats, in that it uses rotating shared keys to provide weak forward secrecy, better scaling, and dynamic member access. This more closely approximates one of the most popular social media products in existence - The Nostr is now a direct competitor of The Facebook.</p>
<p>I built this for my community. I wanted something "good enough" to entice people to leave the advertising-fueled surveillance honeypot that is Facebook. In order to work, it needed to at least support notes, events, and marketplace listings. Although support is still quite basic, Coracle has checked all three of these boxes.</p>
<p>Before I get into the details though, it's important to mention that these groups should not be considered "private" any more than Facebook groups or Mastodon servers are (although privacy is substantially better). A better analog might be WeChat, which uses encryption with the same set of trade-offs. So don't post anything to private groups that might get you in trouble!</p>
<p>With that said, it's possible to run a highly private group. The backbone of this spec is e2e encryption, but relay selection can play an important part in hiding metadata from the rest of the network. If you have a relay you trust to protect notes and not share metadata, your security is significantly increased.</p>
<h1>Prior art</h1>
<p>Nostr-compatible group products aren't a totally novel thing, as it turns out. In fact draft <a href="https://github.com/nostr-protocol/nips/pull/580/files">NIP 112</a> has been around since June, and is already implemented in <a href="https://arcade.city/">ArcadeCity</a>. So why am I creating a new standard? I'l get into the positive benefits of my approach more below, but the quick answers are:</p>
<ul>
<li>The new <a href="https://github.com/nostr-protocol/nips/pull/746">encryption standard</a> is going to break compatibility anyway. If we can end up with a better spec, now is the time.</li>
<li>ArcadeCity development seems to have stalled.</li>
<li>NIP-72 communities already have a ton of traction, and match what I'm trying to achieve with encrypted channels.</li>
</ul>
<p>Of course I'm highly indebted to the project, the design of which is still visible in my final design.</p>
<p>Another product that exists to do something similar in a nostr-compatible way is Soapbox by Alex Gleason. This is a great project, particularly since his Mostr project bridges the ActivityPub world and Nostr. ActivityPub works well for highly centralized communities, but the architecture suffers from this centralization too. In particular, not even DMs are e2e encrypted, and just like regular notes are protected only by authentication enforced by servers.</p>
<p>Finally, there's NIP 29, which is fiatjaf's competing groups project. This has some interesting properties, for example the ability to "fork" a group by linking events together. However, similar to ActivityPub it relies exclusively on relays to protect user privacy, and in a fairly non-standard way. You do get to take advantage of nostr's multi-master architecture though, and signatures are also stripped from events in order to discourage propagation through the network.</p>
<p>None of these solutions quite satisfied me, so I built my own.</p>
<h1>How it works</h1>
<p>One of the coolest things about a NIP 72 community-based group spec is that is supports a spectrum of privacy requirements. A group admin might choose to publish group metadata privately so that it's only visible to the group, publicly so that other people can find the group and ask to join, or leave off a private component entirely.</p>
<p>Likewise, since private groups are backwards-compatible with public communities, it's easy to add a private component to existing groups. This can be useful especially for groups run by a business or content publisher, since public exposure is a good thing but certain group members might have more or less access. This could be used to support a patreon-type model, automating group membership based on subscription tier, for example.</p>
<p>An important aspect of the design that makes automation possible is the concept of a dedicated administration key. By decoupling this key from the original creator of the group, ownership can be shared as simply as sharing the key. This allows multiple admins to manage the group simultaneously either manually or using automations built into the group relays or special purpose bot-clients.</p>
<p>This of course raises the issue of admin access revocation, which isn't possible - that is, until we have a solution for key rotation for normal accounts. Once that's in place, the same process can be used to rotate group admin keys.</p>
<p>In the meantime, it's also trivial to reduce the exposure an admin key gets. You wouldn't generally want to simply paste the key wherever it's needed, but luckily that problem has already been solved as well. Instead of giving every admin or admin bot the key, it's trivial to set up an nsecbunker that authorizes each admin client - and can revoke access as needed.</p>
<p>This level of administration is of course fairly complex, but I think it's important to think through the requirements businesses and other advanced users will eventually impose and anticipate them as we're able, not through over-engineering, but through simple concepts that can be reused.</p>
<p>One other neat feature of this NIP is the definition of invite codes, which are essential for running a private group at any kind of scale. When requesting access to a group, a user can send along a "claim", which can be anything - for example a static invite code, a payment receipt, or an explanation of why they want to join. This claim can be validated by hand by a human, or processed by a bot to instantly admit the new member to the group.</p>
<p>When a new member is admitted to the group, the admin can either share an existing access key with them, or they can rotate the key for the entire group. If relays expire access keys after a certain amount of time, this can create a weak form of forward secrecy, where attackers won't be able to access old content, even if they gain access to the admin key.</p>
<h1>Limitations and Future Work</h1>
<p>The bar for new nostr clients has risen significantly since I first put Coracle out there. The new groups component is far more mature than Coracle was for much of its early life, but it has its rough edges. Many of these just need to be smoothed out through further UX work, but some are more technical in nature.</p>
<ul>
<li>The groups spec relies on NIP 44, which isn't yet available in most signer extensions. That means that unless you log in with your private key (please don't), you won't be able to create or gain access to any private groups.</li>
<li>Hybrid groups (public groups with a private area) aren't really tested yet, or fully supported in Coracle's UI. It's an open question whether this is even a good idea, since it becomes pretty hard for users to know if they're posting publicly or privately in every context.</li>
<li>Moderation is not implemented, so if you're creating a public group there is currently no way in Coracle to approve posts. Also, groups created in Coracle don't show up in Satellite for some reason —&nbsp;this is something I'll be working on improving.</li>
<li>Whether this approach actually scales is another question. It's very hard to build member lists of hundreds of thousands of people, and without a relay helping to filter events, it might become prohibitively expensive to download and analyze all the events posted to a group. We'll see what develops as the design matures and the implementation undergoes stress testing.</li>
</ul>
<h1>Conclusion</h1>
<p>Something I like about both nostr and bitcoin is that it empowers the users of the software. The corollary of this of course is that it's important to exercise this power with care - real damage can be done with this group spec, just as real damage can be done to bitcoin holders through low entropy key generation or poor key handling practices. So please, if you're going to implement this spec, communicate clearly with your users its limitations, and encourage them to run their own relays.</p>
<p>Nevertheless, I am stoked to be another 1% closer to my goal of helping my community - and anyone else who uses nostr - to exercise individual sovereignty and protect their freedom and privacy. Let's keep at it.</p>
]]></content:encoded>
      <itunes:author><![CDATA[ hodlbod]]></itunes:author>
      <itunes:summary><![CDATA[<p>Today marks the biggest release so far in Coracle's history. There have been many good days, like when I introduced Coracle to the nostr telegram group, or when I got my fellowship with FUTO, or when I got my grant from OpenSats, or when I got to speak at Nostrasia. But in terms of realizing the vision I've had for the software - for over two years - today is the day.</p>
<p>Coracle now has private groups.</p>
<p>This means you can now send almost any nostr event over an encrypted channel to the rest of the group's members. This is substantially different from group chats, in that it uses rotating shared keys to provide weak forward secrecy, better scaling, and dynamic member access. This more closely approximates one of the most popular social media products in existence - The Nostr is now a direct competitor of The Facebook.</p>
<p>I built this for my community. I wanted something "good enough" to entice people to leave the advertising-fueled surveillance honeypot that is Facebook. In order to work, it needed to at least support notes, events, and marketplace listings. Although support is still quite basic, Coracle has checked all three of these boxes.</p>
<p>Before I get into the details though, it's important to mention that these groups should not be considered "private" any more than Facebook groups or Mastodon servers are (although privacy is substantially better). A better analog might be WeChat, which uses encryption with the same set of trade-offs. So don't post anything to private groups that might get you in trouble!</p>
<p>With that said, it's possible to run a highly private group. The backbone of this spec is e2e encryption, but relay selection can play an important part in hiding metadata from the rest of the network. If you have a relay you trust to protect notes and not share metadata, your security is significantly increased.</p>
<h1>Prior art</h1>
<p>Nostr-compatible group products aren't a totally novel thing, as it turns out. In fact draft <a href="https://github.com/nostr-protocol/nips/pull/580/files">NIP 112</a> has been around since June, and is already implemented in <a href="https://arcade.city/">ArcadeCity</a>. So why am I creating a new standard? I'l get into the positive benefits of my approach more below, but the quick answers are:</p>
<ul>
<li>The new <a href="https://github.com/nostr-protocol/nips/pull/746">encryption standard</a> is going to break compatibility anyway. If we can end up with a better spec, now is the time.</li>
<li>ArcadeCity development seems to have stalled.</li>
<li>NIP-72 communities already have a ton of traction, and match what I'm trying to achieve with encrypted channels.</li>
</ul>
<p>Of course I'm highly indebted to the project, the design of which is still visible in my final design.</p>
<p>Another product that exists to do something similar in a nostr-compatible way is Soapbox by Alex Gleason. This is a great project, particularly since his Mostr project bridges the ActivityPub world and Nostr. ActivityPub works well for highly centralized communities, but the architecture suffers from this centralization too. In particular, not even DMs are e2e encrypted, and just like regular notes are protected only by authentication enforced by servers.</p>
<p>Finally, there's NIP 29, which is fiatjaf's competing groups project. This has some interesting properties, for example the ability to "fork" a group by linking events together. However, similar to ActivityPub it relies exclusively on relays to protect user privacy, and in a fairly non-standard way. You do get to take advantage of nostr's multi-master architecture though, and signatures are also stripped from events in order to discourage propagation through the network.</p>
<p>None of these solutions quite satisfied me, so I built my own.</p>
<h1>How it works</h1>
<p>One of the coolest things about a NIP 72 community-based group spec is that is supports a spectrum of privacy requirements. A group admin might choose to publish group metadata privately so that it's only visible to the group, publicly so that other people can find the group and ask to join, or leave off a private component entirely.</p>
<p>Likewise, since private groups are backwards-compatible with public communities, it's easy to add a private component to existing groups. This can be useful especially for groups run by a business or content publisher, since public exposure is a good thing but certain group members might have more or less access. This could be used to support a patreon-type model, automating group membership based on subscription tier, for example.</p>
<p>An important aspect of the design that makes automation possible is the concept of a dedicated administration key. By decoupling this key from the original creator of the group, ownership can be shared as simply as sharing the key. This allows multiple admins to manage the group simultaneously either manually or using automations built into the group relays or special purpose bot-clients.</p>
<p>This of course raises the issue of admin access revocation, which isn't possible - that is, until we have a solution for key rotation for normal accounts. Once that's in place, the same process can be used to rotate group admin keys.</p>
<p>In the meantime, it's also trivial to reduce the exposure an admin key gets. You wouldn't generally want to simply paste the key wherever it's needed, but luckily that problem has already been solved as well. Instead of giving every admin or admin bot the key, it's trivial to set up an nsecbunker that authorizes each admin client - and can revoke access as needed.</p>
<p>This level of administration is of course fairly complex, but I think it's important to think through the requirements businesses and other advanced users will eventually impose and anticipate them as we're able, not through over-engineering, but through simple concepts that can be reused.</p>
<p>One other neat feature of this NIP is the definition of invite codes, which are essential for running a private group at any kind of scale. When requesting access to a group, a user can send along a "claim", which can be anything - for example a static invite code, a payment receipt, or an explanation of why they want to join. This claim can be validated by hand by a human, or processed by a bot to instantly admit the new member to the group.</p>
<p>When a new member is admitted to the group, the admin can either share an existing access key with them, or they can rotate the key for the entire group. If relays expire access keys after a certain amount of time, this can create a weak form of forward secrecy, where attackers won't be able to access old content, even if they gain access to the admin key.</p>
<h1>Limitations and Future Work</h1>
<p>The bar for new nostr clients has risen significantly since I first put Coracle out there. The new groups component is far more mature than Coracle was for much of its early life, but it has its rough edges. Many of these just need to be smoothed out through further UX work, but some are more technical in nature.</p>
<ul>
<li>The groups spec relies on NIP 44, which isn't yet available in most signer extensions. That means that unless you log in with your private key (please don't), you won't be able to create or gain access to any private groups.</li>
<li>Hybrid groups (public groups with a private area) aren't really tested yet, or fully supported in Coracle's UI. It's an open question whether this is even a good idea, since it becomes pretty hard for users to know if they're posting publicly or privately in every context.</li>
<li>Moderation is not implemented, so if you're creating a public group there is currently no way in Coracle to approve posts. Also, groups created in Coracle don't show up in Satellite for some reason —&nbsp;this is something I'll be working on improving.</li>
<li>Whether this approach actually scales is another question. It's very hard to build member lists of hundreds of thousands of people, and without a relay helping to filter events, it might become prohibitively expensive to download and analyze all the events posted to a group. We'll see what develops as the design matures and the implementation undergoes stress testing.</li>
</ul>
<h1>Conclusion</h1>
<p>Something I like about both nostr and bitcoin is that it empowers the users of the software. The corollary of this of course is that it's important to exercise this power with care - real damage can be done with this group spec, just as real damage can be done to bitcoin holders through low entropy key generation or poor key handling practices. So please, if you're going to implement this spec, communicate clearly with your users its limitations, and encourage them to run their own relays.</p>
<p>Nevertheless, I am stoked to be another 1% closer to my goal of helping my community - and anyone else who uses nostr - to exercise individual sovereignty and protect their freedom and privacy. Let's keep at it.</p>
]]></itunes:summary>
      <itunes:image href="https://i.nostr.build/rEoG.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[NIP 44 Update]]></title>
      <description><![CDATA[A summary of Cure53's audit of the NIP 44 encryption standard. A report on a report, if you will.]]></description>
             <itunes:subtitle><![CDATA[A summary of Cure53's audit of the NIP 44 encryption standard. A report on a report, if you will.]]></itunes:subtitle>
      <pubDate>Tue, 12 Dec 2023 22:27:46 GMT</pubDate>
      <link>https://hodlbod.npub.pro/post/1702414575183/</link>
      <comments>https://hodlbod.npub.pro/post/1702414575183/</comments>
      <guid isPermaLink="false">naddr1qqxnzdesxg6rzdp4xu6nzwpnqgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa280a30ar</guid>
      <category>nostr</category>
      
        <media:content url="https://image.nostr.build/7d3257372d4d3e5bf45572bc200ad22d0e63771bd5a60abe17b733fd5ee84813.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/7d3257372d4d3e5bf45572bc200ad22d0e63771bd5a60abe17b733fd5ee84813.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qqxnzdesxg6rzdp4xu6nzwpnqgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa280a30ar</noteId>
      <npub>npub1jlrs53pkdfjnts29kveljul2sm0actt6n8dxrrzqcersttvcuv3qdjynqn</npub>
      <dc:creator><![CDATA[ hodlbod]]></dc:creator>
      <content:encoded><![CDATA[<p>By this time, many of you may have either given up on a new standard for encrypting notes to emerge, or entirely forgotten that there was one. Well, I have good news — we've received the <a href="https://cure53.de/audit-report_nip44-implementations.pdf">audit report</a> from <a href="https://cure53.de/">Cure53</a> on the NIP 44 encryption spec, and the results are good! This post will be a summary of the findings, and some hints on what lies ahead.</p>
<h1>The results</h1>
<p>The assets in scope for the audit can be found on Paul Miller's <a href="https://github.com/paulmillr/nip44">NIP 44 repository</a>. Included is the full text of the spec, as well as implementations in Typescript, Rust, and Go.</p>
<p>Overall, here's what Cure53 had to say:</p>
<blockquote>
<p>The Cure53 team succeeded in achieving very good coverage of the WP1-WP4 targets. All<br>ten findings spotted by the testers were classified as general weaknesses with limited<br>exploitation potential. In other words, no vulnerabilities were detected within the inspected<br>components.</p>
</blockquote>
<p>In other words, no vulnerabilities were found, but there are things we can do to harden the implementations. Cure53 elaborates:</p>
<blockquote>
<p>The fact that Cure53 was not able to identify any exploitable vulnerabilities can be<br>interpreted as a positive sign in regard to the security of the NIP44 specification and<br>implementations. Nevertheless, even though the spotted problem can all be seen as general<br>weaknesses and hardening advice, they should not be ignored. It is known that weaknesses<br>may serve as entry points for more severe vulnerabilities in the future. Cure53 strongly<br>recommends swift resolution of all reported flaws.</p>
</blockquote>
<p>These weaknesses and recommendations each have their own code, prefixed by "NOS-01", which is our audit number. Here's a quick summary of the individual points:</p>
<ul>
<li>NOS-01-001 describes a weakness related to naive secp256k1 implementations, which may accept public keys with both x and y coordinates instead of just x and a sign-bit. This can result in the compromise of a sender's private key if the sender can be tricked into encrypting a message with an invalid public key. This is known as a "twist attack". Cure53 recommends some additional test vectors to make sure that uncompressed keys are not accepted.</li>
<li>NOS-01-002 includes a handful of minor recommendations, including specifying the initial counter for ChaCha20, nailing down key formats, and a few other things which they go into more depth on elsewhere.</li>
<li>NOS-01-003 provides some additional test vectors to prevent twist attacks and out of bound errors.</li>
<li>NOS-01-004 suggests using a constant time equality function to prevent timing side-channel attacks, along with some code samples.</li>
<li>NOS-01-005 identifies missing range checks in the Go implementation which should be addressed in order to avoid crashes.</li>
<li>NOS-01-006 addresses the lack of provisions for forward secrecy in the NIP 44 spec. They suggest introducing sender-side forward secrecy by deriving the session key using ephemeral keys and a KDF.</li>
<li>NOS-01-007 explains that using the same key for multiple purposes can lead to unexpected compromises when taken together. Best practice is to use a different key for signing and for encryption, which nostr violates. While the particular curves we use aren't vulnerable to this exploit, Cure53 recommends deriving an encryption key from a user's main key using a KDF in order to reduce the impact of a leaked encryption key.</li>
<li>NOS-01-008 identifies an incorrect use of the salt parameter in calls to HKDF (an HMAC-based Key Derivation Function allows us to prove that an encrypted payload was not forged). Currently, the salt is generated randomly every time, but the security definition of HKDF specifies that it be static. This is likely not exploitable, but should be fixed. Cure53 suggests switching the nonce and salt when calling the HKDF, and deriving a static salt using something like <code>SHA256(pubA, pubB, "nip-44-v2")</code>.</li>
<li>NOS-01-009 demonstrates that the Message Authentication Code (MAC) tag is currently computed without a nonce. This doesn't compromise the encryption, and authentication is covered by event signatures as specified in NIP 01, but it does prevent the MAC from being useful on its own.</li>
<li>NOS-01-010 suggests using clearer boundaries when constructing the HMAC payload.</li>
</ul>
<p>The takeaway here is that with a few minor changes, the spec itself is sufficient to "provide a simple way for the users to communicate privately". There are, however, a number of edge cases which can compromise implementations, so for any developers out there porting the spec to new languages, be sure to take a look at Paul's test vectors.</p>
<blockquote>
<p>In the end, the NIP44 specification and implementations appear to have already achieved the security goal of providing users with a way to communicate privately. Miscellaneous issues identified by Cure53 during NOS-01 correspond to further hardening of the current version and/or suggestions for future versions. Following these suggestions could provide more advanced security guarantees.</p>
</blockquote>
<p>They also clarify that:</p>
<blockquote>
<p> Importantly, the lack of certain security guarantees, such as forward secrecy, post-compromise security, deniability, and post-quantum, had been known to the development team prior to NOS-01.</p>
</blockquote>
<p>Since this is the case, it's important that client developers be absolutely clear with their users about what NIP 44 is good for, and what it's not. This is a "simple" way to communicate privately — users with more advanced privacy requirements should use something like MLS or SimpleX.</p>
<h1>What's next?</h1>
<p>NIP 44 isn't quite ready for widespread use just yet, but it shouldn't take long to incorporate all the adjustments mentioned in the audit. Then there are several NIPs which rely on the encryption in NIP 04 which should eventually be migrated individually. Beyond that, a whole world of affordances for encrypted data becomes available on nostr.</p>
<p>First and most anticipated, we can finally deprecate NIP 04 and stop leaking DM metadata. Vitor's <a href="https://github.com/nostr-protocol/nips/pull/686">Sealed Gift Wraps</a> are an excellent alternative to NIP 04 DMs, and add support for small group chats, which will be a big improvement to client UX.</p>
<p>Other more ambitious specifications targeting larger groups exist as well, including my <a href="https://github.com/nostr-protocol/nips/pull/875">Closed Communities</a> draft spec. This NIP makes it possible to extend NIP 72 communities with a private component, which can be useful for publishers or real-life communities.</p>
<p>There are lots of other things NIP 44 might be used for as well, for example:</p>
<ul>
<li>The ability to share your location only with certain people</li>
<li>Private calendar events, product listings, or streams</li>
<li>Private tags — instead of encrypting an entire event, it should be possible to encrypt only a single tag's value. This allows senders to attach private data to public events.</li>
</ul>
<h1>Conclusion</h1>
<p>There's lots of work still to be done, but I think this marks a huge milestone for nostr. So thank you to Paul Miller for his work on the spec and the audit, and to OpenSats for funding the audit!</p>
]]></content:encoded>
      <itunes:author><![CDATA[ hodlbod]]></itunes:author>
      <itunes:summary><![CDATA[<p>By this time, many of you may have either given up on a new standard for encrypting notes to emerge, or entirely forgotten that there was one. Well, I have good news — we've received the <a href="https://cure53.de/audit-report_nip44-implementations.pdf">audit report</a> from <a href="https://cure53.de/">Cure53</a> on the NIP 44 encryption spec, and the results are good! This post will be a summary of the findings, and some hints on what lies ahead.</p>
<h1>The results</h1>
<p>The assets in scope for the audit can be found on Paul Miller's <a href="https://github.com/paulmillr/nip44">NIP 44 repository</a>. Included is the full text of the spec, as well as implementations in Typescript, Rust, and Go.</p>
<p>Overall, here's what Cure53 had to say:</p>
<blockquote>
<p>The Cure53 team succeeded in achieving very good coverage of the WP1-WP4 targets. All<br>ten findings spotted by the testers were classified as general weaknesses with limited<br>exploitation potential. In other words, no vulnerabilities were detected within the inspected<br>components.</p>
</blockquote>
<p>In other words, no vulnerabilities were found, but there are things we can do to harden the implementations. Cure53 elaborates:</p>
<blockquote>
<p>The fact that Cure53 was not able to identify any exploitable vulnerabilities can be<br>interpreted as a positive sign in regard to the security of the NIP44 specification and<br>implementations. Nevertheless, even though the spotted problem can all be seen as general<br>weaknesses and hardening advice, they should not be ignored. It is known that weaknesses<br>may serve as entry points for more severe vulnerabilities in the future. Cure53 strongly<br>recommends swift resolution of all reported flaws.</p>
</blockquote>
<p>These weaknesses and recommendations each have their own code, prefixed by "NOS-01", which is our audit number. Here's a quick summary of the individual points:</p>
<ul>
<li>NOS-01-001 describes a weakness related to naive secp256k1 implementations, which may accept public keys with both x and y coordinates instead of just x and a sign-bit. This can result in the compromise of a sender's private key if the sender can be tricked into encrypting a message with an invalid public key. This is known as a "twist attack". Cure53 recommends some additional test vectors to make sure that uncompressed keys are not accepted.</li>
<li>NOS-01-002 includes a handful of minor recommendations, including specifying the initial counter for ChaCha20, nailing down key formats, and a few other things which they go into more depth on elsewhere.</li>
<li>NOS-01-003 provides some additional test vectors to prevent twist attacks and out of bound errors.</li>
<li>NOS-01-004 suggests using a constant time equality function to prevent timing side-channel attacks, along with some code samples.</li>
<li>NOS-01-005 identifies missing range checks in the Go implementation which should be addressed in order to avoid crashes.</li>
<li>NOS-01-006 addresses the lack of provisions for forward secrecy in the NIP 44 spec. They suggest introducing sender-side forward secrecy by deriving the session key using ephemeral keys and a KDF.</li>
<li>NOS-01-007 explains that using the same key for multiple purposes can lead to unexpected compromises when taken together. Best practice is to use a different key for signing and for encryption, which nostr violates. While the particular curves we use aren't vulnerable to this exploit, Cure53 recommends deriving an encryption key from a user's main key using a KDF in order to reduce the impact of a leaked encryption key.</li>
<li>NOS-01-008 identifies an incorrect use of the salt parameter in calls to HKDF (an HMAC-based Key Derivation Function allows us to prove that an encrypted payload was not forged). Currently, the salt is generated randomly every time, but the security definition of HKDF specifies that it be static. This is likely not exploitable, but should be fixed. Cure53 suggests switching the nonce and salt when calling the HKDF, and deriving a static salt using something like <code>SHA256(pubA, pubB, "nip-44-v2")</code>.</li>
<li>NOS-01-009 demonstrates that the Message Authentication Code (MAC) tag is currently computed without a nonce. This doesn't compromise the encryption, and authentication is covered by event signatures as specified in NIP 01, but it does prevent the MAC from being useful on its own.</li>
<li>NOS-01-010 suggests using clearer boundaries when constructing the HMAC payload.</li>
</ul>
<p>The takeaway here is that with a few minor changes, the spec itself is sufficient to "provide a simple way for the users to communicate privately". There are, however, a number of edge cases which can compromise implementations, so for any developers out there porting the spec to new languages, be sure to take a look at Paul's test vectors.</p>
<blockquote>
<p>In the end, the NIP44 specification and implementations appear to have already achieved the security goal of providing users with a way to communicate privately. Miscellaneous issues identified by Cure53 during NOS-01 correspond to further hardening of the current version and/or suggestions for future versions. Following these suggestions could provide more advanced security guarantees.</p>
</blockquote>
<p>They also clarify that:</p>
<blockquote>
<p> Importantly, the lack of certain security guarantees, such as forward secrecy, post-compromise security, deniability, and post-quantum, had been known to the development team prior to NOS-01.</p>
</blockquote>
<p>Since this is the case, it's important that client developers be absolutely clear with their users about what NIP 44 is good for, and what it's not. This is a "simple" way to communicate privately — users with more advanced privacy requirements should use something like MLS or SimpleX.</p>
<h1>What's next?</h1>
<p>NIP 44 isn't quite ready for widespread use just yet, but it shouldn't take long to incorporate all the adjustments mentioned in the audit. Then there are several NIPs which rely on the encryption in NIP 04 which should eventually be migrated individually. Beyond that, a whole world of affordances for encrypted data becomes available on nostr.</p>
<p>First and most anticipated, we can finally deprecate NIP 04 and stop leaking DM metadata. Vitor's <a href="https://github.com/nostr-protocol/nips/pull/686">Sealed Gift Wraps</a> are an excellent alternative to NIP 04 DMs, and add support for small group chats, which will be a big improvement to client UX.</p>
<p>Other more ambitious specifications targeting larger groups exist as well, including my <a href="https://github.com/nostr-protocol/nips/pull/875">Closed Communities</a> draft spec. This NIP makes it possible to extend NIP 72 communities with a private component, which can be useful for publishers or real-life communities.</p>
<p>There are lots of other things NIP 44 might be used for as well, for example:</p>
<ul>
<li>The ability to share your location only with certain people</li>
<li>Private calendar events, product listings, or streams</li>
<li>Private tags — instead of encrypting an entire event, it should be possible to encrypt only a single tag's value. This allows senders to attach private data to public events.</li>
</ul>
<h1>Conclusion</h1>
<p>There's lots of work still to be done, but I think this marks a huge milestone for nostr. So thank you to Paul Miller for his work on the spec and the audit, and to OpenSats for funding the audit!</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/7d3257372d4d3e5bf45572bc200ad22d0e63771bd5a60abe17b733fd5ee84813.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[Relays, Encryption, and Groups]]></title>
      <description><![CDATA[On relays, encryption, and how they work together to create a "good enough" private group solution.]]></description>
             <itunes:subtitle><![CDATA[On relays, encryption, and how they work together to create a "good enough" private group solution.]]></itunes:subtitle>
      <pubDate>Thu, 16 Nov 2023 17:45:27 GMT</pubDate>
      <link>https://hodlbod.npub.pro/post/1700155417145/</link>
      <comments>https://hodlbod.npub.pro/post/1700155417145/</comments>
      <guid isPermaLink="false">naddr1qqxnzdesxqcn2df5xymnzdp4qgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa28q3wd45</guid>
      <category>nostr</category>
      
        <media:content url="https://coracle.us-southeast-1.linodeobjects.com/juniperphoton-lAQRH4mCyl4-unsplash.jpeg" medium="image"/>
        <enclosure 
          url="https://coracle.us-southeast-1.linodeobjects.com/juniperphoton-lAQRH4mCyl4-unsplash.jpeg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qqxnzdesxqcn2df5xymnzdp4qgsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgsrqsqqqa28q3wd45</noteId>
      <npub>npub1jlrs53pkdfjnts29kveljul2sm0actt6n8dxrrzqcersttvcuv3qdjynqn</npub>
      <dc:creator><![CDATA[ hodlbod]]></dc:creator>
      <content:encoded><![CDATA[<p>As everyone knows by now, I am working on adding private groups to Coracle using the new NIP-44 encryption standard currently being audited. I wanted to share why I think this is a viable approach, and how combining relays and encryption can help make it happen.</p>
<p>This discussion gets complicated very quickly, so to begin, I thought I'd cover the two components that everyone <em>thinks</em> they understand first (relays and encryption), and move on to the one that combines the existing primitives in new and exciting ways (groups).</p>
<h1>What even are relays, anyway?</h1>
<p>If you saw <a href="https://www.youtube.com/live/Nz15SyiwQFk?si=FmLCoTWL1ZFhnY3K&amp;t=2751">my talk at Nostrasia</a>, this section is just a re-iteration of it. In fact, I wrote this blog post before the conference to help me with my presentation. So hello, from the past.</p>
<p>Relays are dumb. They're just servers, which speak a particular protocol, and which implement some minimal logic to support that protocol. Relays have to be interoperable, which is why it's important to design new parts of the nostr protocol in such a way as to be backwards-compatible, and simple to implement.</p>
<p>As a result, relay development has historically focused on performance to the exclusion of new functionality. You can see this with the success of strfry and Will's adaptation of the underlying technique to nostrdb.</p>
<p>One of my favorite programming talks is <a href="https://www.youtube.com/watch?v=SxdOUGdseq4">Simple Made Easy</a> by Rich Hickey, the author of Clojure. One of the points he makes in that talk is that object-oriented programming is such a mess because it "complects" behavior and state. Hickey's solution to this problem is to use functions and values rather than methods and state.</p>
<p>I think that this same mistake is one we are at risk of making with nostr relays. I'll come back to this in a bit, but keep that distinction in the back of your mind: separating data and behavior can lead to a much simpler and more robust system.</p>
<p>Despite the emphasis on interoperability, relays shouldn't all be exact clones. There are a few different ways relays can differentiate themselves, either by providing specific functionality, by storing different sets of events, or by exposing a different interface.</p>
<h2>Added functionality</h2>
<p>Some implementations have pushed features forward, for example rbr.bio which implemented the COUNT verb from NIP 45 early on. However, these efforts are usually either supported by special clients (like nostr.band or primal's caching service), or fail to gain wide adoption and are eventually abandoned. The result is that NIPs specifying optional functionality tend to die without sufficient user demand.</p>
<p>The reason for this is that if you're building a client that selects relays based on user preferences, it can't rely on functionality that doesn't exist on the majority of relays. Without widespread support, search results or feeds requested based on Primal's special syntax will be incomplete or fail entirely. As a result, clients often build proprietary solutions to these problems, increasing centralization risk.</p>
<h2>Subtracted functionality</h2>
<p>Relays are able to helpfully differentiate themselves however, by offering a <em>subset</em> of protocol functionality. For example, purplepag.es is a reliable source for profile data and relay preferences, but it doesn't require clients to do anything different in order to be useful. Instead, users can simply add purplepag.es to their relay list and instantly get a better experience. A similar approach many commodity relays take is blocking certain event kinds, for example 1059 gift wraps or NIP 94 image headers. This fortifies their particular purpose, which is to <em>not</em> support more exotic protocol features.</p>
<p>Other kinds of relays don't support this guarantee, for example relay.noswhere.com only supports search if the search term is not accompanied by a filter, responding to standard requests with "filters: not planned (non-search queries)". This can still be useful, but it is <em>not</em> a relay, because it requires clients to special case how it's used.</p>
<h2>Data relevance</h2>
<p>There is a different kind of differentiation relays can implement, based not on functionality, but on content. This is what I mean when I talk about "relay de-commodification". The value proposition this type of relay offers is not "we can do something no one else does", but "we have the information you're looking for".</p>
<p>There are two ways to accomplish this: content curation and access controls. The difference being that content curation is context-independent, and might be based on topic, keyword, or LLM analysis, while access controls only accepts content published by certain accounts. Several relay implementations and hosting providers (for example relay.tools) support both of these approaches, and of course it's easy to combine them.</p>
<p>Likewise, there are two ways for a relay to gain access to the desired data, leading to two different value propositions.</p>
<p>A relay that focuses on topical data might scrape the wider nostr network in order to ensure it is able to reliably serve everything relevant to its niche. This might be done using any number of heuristics, including filtering by pubkey, topic, or sentiment, but in any case the relay is not intended primarily to be written to, but to be read from. This is primarily an additive model, focusing on offering a complete view of the given topic.</p>
<p>Another approach is to let the data come to you instead of scraping it from the wider network by only accepting events published by certain people, or being the go-to relay for a certain topic. In order for this model to work though, there needs to be some way for the relay to keep this data to itself by preventing scraper-powered relays from harvesting its data. This effectively means that these relays will not only have policies for who can write to them, but also who can read from them. These might be the same set of people (for example with a community relay), or more people might be allowed to read from the relay than are able to write to it, as in the case of content producers who want a paywalled private social media enclave.</p>
<h2>Keep relays weird</h2>
<p>Most relay implementations expose their data over websockets in line with the spec, but this isn't actually inherent to the function of a relay. We've already seen several projects implement relays in-app for caching purposes. These relays don't usually go through the ceremony of spec adherence, but some (e.g. nostrdb) do.</p>
<p>Different transport mechanisms and hosting options are possible for relays, and would only require clients to use a specific adapter to get at them. Some examples:</p>
<ul>
<li>A relay running on your phone as a service that other nostr clients can share to reduce data storage requirements</li>
<li>A relay running on a LAN, only accessible from a particular location</li>
<li>A relay running via any other transport, for example radio or carrier pigeon</li>
</ul>
<p>The idea I'm trying to get across here is that relays aren't necessarily websocket servers. More abstractly, they are a name attached to a set of events that can be accessed in a standard way.</p>
<h2>So, what are relays?</h2>
<p>To recap, here's my definition of a relay:</p>
<ol>
<li>They correctly support standard functionality</li>
<li>They should only support additional functionality related to curating their data set</li>
<li>They may restrict the data types they accept and serve</li>
<li>They may restrict the data they accept and serve based on content or pubkey</li>
</ol>
<p>One additional feature that isn't currently standard but ought to be is strfry's negentropy synchronization feature. This is the opposite of AUTH, which protects a relay's own dataset, in that it allows relays to more efficiently share their data with peers. A nice bonus is that it also allows clients to use their local cache more effectively as well.</p>
<h2>Simple Made Easy</h2>
<p>Going back to Rich Hickey's talk, separating behavior and state allows you to work directly with your data, freely implementing new behavior whenever you need to. This applies to sets of events stored on relays just as much as it applies to in-memory data.</p>
<p>One thing that makes this possible is cryptographic hash functions, which cleanly transform state into values - the difference being that "state" couples a name with data that may change, while a hash is a compact representation of immutable data. If two hashes of event ids don't match, they're not the same set of events.</p>
<p>How does this apply to relays? Instead of adding new behavior to relays directly ("methods"), we can instead call "functions" on a relay's data.</p>
<p>This function can be anything - a centralized server, client code, or a DVM - that takes REQ filters as input. The function gathers the needed data (maybe from a cache, maybe using a sync command, maybe from multiple relays for completeness), performs the transformation, and returns it. The result is that relays become simple, interoperable repositories for data, without limiting what server-side computation can be applied to events.</p>
<p>While huge search indexes and centralized servers have a cost in terms of centralization, I think DVMs solve this problem brilliantly - the common interface for this augmented behavior is open, and can admit anyone who wants to start competing for search, counting, recommendations, or anything else you might want to do with events.</p>
<p>As Alan Perlis said, "It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures."</p>
<h1>Encrypted Messages</h1>
<p>Nostr DMs were a huge mistake, and I want to do it again.</p>
<p>NIP 04 has some obvious problems, most notably metadata leakage. The cryptography also hasn't been audited, and has some potential theoretical attack vectors. I've been working with some other nostr devs on a new cryptographic primitive, which will be audited and hopefully result in a better foundation for future work.</p>
<p>But fixing the cryptography still doesn't fix DMs. Nostr is not really the right architecture for secure private messaging, because ratchets require state. Nostr is designed such that there are no hard dependencies between events, which are replicated across multiple relays. This makes it very hard to manage the kind of state that protocols like SimpleX or Signal require.</p>
<p>Even apart from the difficulty of implementing stateful messaging protocols on nostr, we have two other problems to contend with: metadata leaks and spotty deliverability. Both of these problems come from the reliance of nostr on relays, which generally are not trustworthy or reliable.</p>
<h2>Metadata Leakage</h2>
<p>NIP 04 is really bad. Anyone can see who you corresponded with, when, how frequently, and how much you said just by looking at the event. Vitor's NIP 24 chat proposal aims to fix this with gift wraps, which use ephemeral keys to obscure the sender, padding to obscure message size, timestamp randomization to obscure timing, and double-wrapping to prevent leakage of the signed message.</p>
<p>This is a big improvement, but there are other forms of metadata that are still visible. To start, the recipient is still visible, along with how many messages they have received and their general size. So you can tell if someone sends lots of messages, or not a lot, but that's about it.</p>
<p>If we don't assume relays are trustworthy though, there are all kinds of implicit metadata that can be used to infer information about the sender, including:</p>
<ul>
<li>Client fingerprinting</li>
<li>Relay selection for publishing and queries</li>
<li>IP address collection</li>
<li>First seen timestamp</li>
<li>Identification of users by AUTH</li>
<li>Correlation of the event with other messages sent/received during a session</li>
</ul>
<p>These issues are much harder to solve, because they are part of the process of delivering the message, rather than just constructing it.</p>
<h2>Transport and deliverability</h2>
<p>The key feature of nostr that makes it work is relays. Relays provide storage redundancy and heterogeneity of purpose with a common interface shared by all instances. This is great for censorship resistance, but everything comes with a tradeoff.</p>
<p>Completeness and consistency are not guaranteed on nostr. This is ok in a social media context, because there's no way to keep up with everything everyone you follow says anyway, and you can rely on interactions and algorithmic tools to catch you up on anything important you missed.</p>
<p>But with private messages, every payload counts. Receiving messages out of order, with a delay, or not at all can severely disrupt conversations between two people, leading to misunderstandings and worse. This is a common experience on nostr; even fiatjaf has expressed skepticism about the viability of private messages on nostr.</p>
<p>This flakiness comes from a combination of low relay quality and poor relay selection on the part of clients. Relays can't deliver messages if they can't keep up with clients, go offline, or drop messages (accidentally or deliberately). Likewise, clients can't find messages if they look for them in the wrong place.</p>
<h2>Relays fixes this</h2>
<p>Let me just put things into perspective really quick. Twitter DMs are not e2e encrypted, and weren't encrypted at all until earlier this year. Mastodon messages are not encrypted - instance admins can read everything. Facebook has e2ee messages, but only between normal users, not in communities, groups, business chats, or marketplace chats.</p>
<p>So while nostr's architecture is not sufficient to make secure encrypted communication a value proposition of the protocol in itself, there is a lot we can do to improve on the status quo. Because nostr has no admins, the only option for privacy of any kind is end-to-end encryption. Metadata leakage notwithstanding, nostr messages can be "good enough" for some definition of that phrase.</p>
<p>It's important to not just punt on making DMs available in a standard way, because there is an expectation that a complete social media solution will have a way to establish a private communication channel with someone else in the network. Otherwise you're stuck with public correspondence and link sharing in order to hop to another protocol.</p>
<p>Let's just assume that you agree with me at this point, and that until there is a javascript SDK for SimpleX or MLS, we're stuck with nostr DMs of some kind. So how can we reduce metadata leakage and improve deliverability?</p>
<h2>Fixing Flakiness</h2>
<p>Let's start with deliverability first. NIP 65's inbox/outbox model is great. While it doesn't fix deliverability on its own, if every relay recommended was in fact reliable, and reliably followed by clients, there would be a very clear indication of where a particular user's messages could be found. Neither of these things is really true right now, but I do think clients are moving in this direction. Hopefully we can educate users better on how to pick good relays.</p>
<p>There are some limits to this model of course. For example, if you want to read notes from 1000 pubkeys at once, your client will likely end up connecting to hundreds of relays unless it has a cap, in which case it will miss a lot of notes.</p>
<p>One clean solution to this problem is relay proxies. There are a few implementations, but the one I run at mux.coracle.social is a stateless proxy that uses a wrapper protocol so clients can still select and dispatch to relays. I originally built this to improve mobile data use by deduplicating events on the server, and it does that pretty well, although it currently does it in the most naive way possible.</p>
<p>Multiplextr currently does not qualify as a "real" relay based on my four rules, since it uses a wrapper protocol. However, a smarter implementation would be able to route requests and events effectively by relying on client authentication and filter analysis, without changing the protocol. This would also allow clients to completely offload the complex business of relay selection to its proxy. Clients would also be able to combine multiple proxies just like they combine relays - because proxies are relays!</p>
<h2>Proxying Privacy</h2>
<p>Another downside of NIP 65 is that it encourages clients to connect indiscriminately to hundreds of different relays based on tag hints, other users' preferences, and relays baked into bech32 identifiers. This is not only bad for battery life and performance, but also allows attackers to easily trick your client into to connecting to their relay so they can start analyzing your traffic.</p>
<p>The best way to defend yourself against nosy relays is to not connect to them at all. And the easiest way to do that is to only connect to relays you control (or trust), and let them do the dirty work for you.</p>
<p>With a proxy, even if you don't control it, you can reduce the number of parties who can snoop on your traffic by orders of magnitude. And since other people use the proxy too, your traffic gets mixed with theirs, making it much harder to analyze. Of course, the downside of using a public proxy is that the proxy sees all messages you send and receive, and the relays you select for each request. Even worse, an untrusted multiplexer can hijack an authenticated session, exfiltrating private data from protected relays.</p>
<p>A proxy you control (or trust, either via social relationships or economic ones) is the best of both worlds. This proxy could also do some smart things for you to improve privacy as well, for example:</p>
<ul>
<li>Delayed publishing of gift wrapped messages so relays can't guess as easily when the event was first seen.</li>
<li>Closing and re-opening connections to reduce the number of messages sent over an AUTH'd session.</li>
<li>It could block suspicious messages on the fly, for example spam or notes with phishing links.</li>
<li>If an abundance of options are available for relay selections, it could randomize which relays are used, or avoid using less reputable ones.</li>
</ul>
<p>So I guess what I'm saying here, is "run a node". But not just any node - in the early days of nostr there were a lot of people spinning up relays because they thought it helped decentralization. Well, as it turns out, just like in bitcoin you have to <em>use</em> your node in order for it to be useful.</p>
<h1>Beyond DMs</h1>
<p>I'm not done yet, though. What's the point of all this? Why put all this effort into "good enough" DMs when we could spend the effort adopting SimpleX or MLS (said Semisol, who lives rent free in my head)?</p>
<p>Well, because there isn't a single "best" DM option. As I've dug into the topic, I've discovered that a ton of tradeoffs exist between complexity, privacy, and scale. The way I understand it, there are three basic options here:</p>
<ul>
<li>One-to-one encryption. This is how both SimpleX and Vitor's group message draft works. It allows for things like ratchets to be added on top, and is fairly simple - but fails to scale because every message has to be encrypted separately for every group member, resulting in <code>n*m</code> messages, where <code>n</code> is the number of group members, and <code>m</code> is the number of messages sent.</li>
<li>Encryption via shared key. This is how WhatsApp works, and it scales really well because messages don't have to be duplicated. And while it does support forward secrecy, it does not support post-compromise security, so it is significantly less secure.</li>
<li>MLS has a unique hierarchical approach to managing keys, which improves the complexity of one-to-one encryption so that it's logarithmic rather than exponential. However, MLS is highly stateful and still has scaling limitations.</li>
</ul>
<p>My takeaway is that there is no perfect solution. Ratchets are the gold standard, but can't really be implemented using nostr relays, since they frequently require servers to have very specific characteristics, like the ability to deliver messages in order.</p>
<p>The fact remains though, that social media needs encrypted messaging of some kind, even if we encourage users to bail to a more complete solution if they want to be truly private. And encryption is useful beyond small group chats - think of Facebook groups, which scale to millions of people and whose users have a much lower expectation of privacy. This is what nostr is good at - social data, whether encrypted or in plaintext.</p>
<h2>Belt and Suspenders</h2>
<p>For a long time I have waffled between two visions of how private groups ought to work. Should they be encrypted messages sprinkled across the nostr network like confetti? Or should they live on one or two relays in plaintext, protected by AUTH?</p>
<p>Both of these options have issues. Sprinkling encrypted messages across the network almost guarantees deliverability problems, since already many commodity relays block gift wraps. And that's ok! They have no obligation to store your encrypted messages.</p>
<p>Storing group messages in plaintext is also sub-optimal, even if it's on a dedicated relay. Of course we're not going for military-grade secrecy here, but it would be trivially easy through a bug, or even a client that doesn't know how to deal with groups, to re-broadcast events that should stay private. We could do something wacky, like strip the signature from events hosted on a relay, but if we're going to do something non-standard, we might as well do the best we can.</p>
<p>So why not both? Group messages should be encrypted, and they should be stored on a particular set of relays. Again, assuming the relays used are trustworthy, this fixes both privacy and deliverability problems, because it's very clear where messages posted to the group should go.</p>
<p>Promoting relays to trusted status has some nice, unintended benefits too. One common objection to using encrypted content is that it becomes hard to filter. But if a relay is trusted to store a group's messages, it can also be trusted to be admitted as a member to the group. This would allow the relay to decrypt events and filter them to respond to requests by authenticated group members.</p>
<p>Of course, this would violate rule <a href='/tag/1/'>#1</a> for relays, since they would no longer be supporting standard functionality, but a guy can dream, can't he?</p>
<h1>Conclusion</h1>
<p>When I started working on nostr I had no idea it would end up being this complex to accomplish what I set out to do. Building a twitter clone was only a first step to an MVP, but I always had my eye on the prize of serving my local church community, which doesn't give a sat about social media per se.</p>
<p>Private groups are important to me not because I'm setting out to support political dissidents or journalists (although I hope they find nostr useful too), but because I want to get my friends off of Facebook, and the only way to do that is to create private marketplaces, calendars, communties, and more.</p>
]]></content:encoded>
      <itunes:author><![CDATA[ hodlbod]]></itunes:author>
      <itunes:summary><![CDATA[<p>As everyone knows by now, I am working on adding private groups to Coracle using the new NIP-44 encryption standard currently being audited. I wanted to share why I think this is a viable approach, and how combining relays and encryption can help make it happen.</p>
<p>This discussion gets complicated very quickly, so to begin, I thought I'd cover the two components that everyone <em>thinks</em> they understand first (relays and encryption), and move on to the one that combines the existing primitives in new and exciting ways (groups).</p>
<h1>What even are relays, anyway?</h1>
<p>If you saw <a href="https://www.youtube.com/live/Nz15SyiwQFk?si=FmLCoTWL1ZFhnY3K&amp;t=2751">my talk at Nostrasia</a>, this section is just a re-iteration of it. In fact, I wrote this blog post before the conference to help me with my presentation. So hello, from the past.</p>
<p>Relays are dumb. They're just servers, which speak a particular protocol, and which implement some minimal logic to support that protocol. Relays have to be interoperable, which is why it's important to design new parts of the nostr protocol in such a way as to be backwards-compatible, and simple to implement.</p>
<p>As a result, relay development has historically focused on performance to the exclusion of new functionality. You can see this with the success of strfry and Will's adaptation of the underlying technique to nostrdb.</p>
<p>One of my favorite programming talks is <a href="https://www.youtube.com/watch?v=SxdOUGdseq4">Simple Made Easy</a> by Rich Hickey, the author of Clojure. One of the points he makes in that talk is that object-oriented programming is such a mess because it "complects" behavior and state. Hickey's solution to this problem is to use functions and values rather than methods and state.</p>
<p>I think that this same mistake is one we are at risk of making with nostr relays. I'll come back to this in a bit, but keep that distinction in the back of your mind: separating data and behavior can lead to a much simpler and more robust system.</p>
<p>Despite the emphasis on interoperability, relays shouldn't all be exact clones. There are a few different ways relays can differentiate themselves, either by providing specific functionality, by storing different sets of events, or by exposing a different interface.</p>
<h2>Added functionality</h2>
<p>Some implementations have pushed features forward, for example rbr.bio which implemented the COUNT verb from NIP 45 early on. However, these efforts are usually either supported by special clients (like nostr.band or primal's caching service), or fail to gain wide adoption and are eventually abandoned. The result is that NIPs specifying optional functionality tend to die without sufficient user demand.</p>
<p>The reason for this is that if you're building a client that selects relays based on user preferences, it can't rely on functionality that doesn't exist on the majority of relays. Without widespread support, search results or feeds requested based on Primal's special syntax will be incomplete or fail entirely. As a result, clients often build proprietary solutions to these problems, increasing centralization risk.</p>
<h2>Subtracted functionality</h2>
<p>Relays are able to helpfully differentiate themselves however, by offering a <em>subset</em> of protocol functionality. For example, purplepag.es is a reliable source for profile data and relay preferences, but it doesn't require clients to do anything different in order to be useful. Instead, users can simply add purplepag.es to their relay list and instantly get a better experience. A similar approach many commodity relays take is blocking certain event kinds, for example 1059 gift wraps or NIP 94 image headers. This fortifies their particular purpose, which is to <em>not</em> support more exotic protocol features.</p>
<p>Other kinds of relays don't support this guarantee, for example relay.noswhere.com only supports search if the search term is not accompanied by a filter, responding to standard requests with "filters: not planned (non-search queries)". This can still be useful, but it is <em>not</em> a relay, because it requires clients to special case how it's used.</p>
<h2>Data relevance</h2>
<p>There is a different kind of differentiation relays can implement, based not on functionality, but on content. This is what I mean when I talk about "relay de-commodification". The value proposition this type of relay offers is not "we can do something no one else does", but "we have the information you're looking for".</p>
<p>There are two ways to accomplish this: content curation and access controls. The difference being that content curation is context-independent, and might be based on topic, keyword, or LLM analysis, while access controls only accepts content published by certain accounts. Several relay implementations and hosting providers (for example relay.tools) support both of these approaches, and of course it's easy to combine them.</p>
<p>Likewise, there are two ways for a relay to gain access to the desired data, leading to two different value propositions.</p>
<p>A relay that focuses on topical data might scrape the wider nostr network in order to ensure it is able to reliably serve everything relevant to its niche. This might be done using any number of heuristics, including filtering by pubkey, topic, or sentiment, but in any case the relay is not intended primarily to be written to, but to be read from. This is primarily an additive model, focusing on offering a complete view of the given topic.</p>
<p>Another approach is to let the data come to you instead of scraping it from the wider network by only accepting events published by certain people, or being the go-to relay for a certain topic. In order for this model to work though, there needs to be some way for the relay to keep this data to itself by preventing scraper-powered relays from harvesting its data. This effectively means that these relays will not only have policies for who can write to them, but also who can read from them. These might be the same set of people (for example with a community relay), or more people might be allowed to read from the relay than are able to write to it, as in the case of content producers who want a paywalled private social media enclave.</p>
<h2>Keep relays weird</h2>
<p>Most relay implementations expose their data over websockets in line with the spec, but this isn't actually inherent to the function of a relay. We've already seen several projects implement relays in-app for caching purposes. These relays don't usually go through the ceremony of spec adherence, but some (e.g. nostrdb) do.</p>
<p>Different transport mechanisms and hosting options are possible for relays, and would only require clients to use a specific adapter to get at them. Some examples:</p>
<ul>
<li>A relay running on your phone as a service that other nostr clients can share to reduce data storage requirements</li>
<li>A relay running on a LAN, only accessible from a particular location</li>
<li>A relay running via any other transport, for example radio or carrier pigeon</li>
</ul>
<p>The idea I'm trying to get across here is that relays aren't necessarily websocket servers. More abstractly, they are a name attached to a set of events that can be accessed in a standard way.</p>
<h2>So, what are relays?</h2>
<p>To recap, here's my definition of a relay:</p>
<ol>
<li>They correctly support standard functionality</li>
<li>They should only support additional functionality related to curating their data set</li>
<li>They may restrict the data types they accept and serve</li>
<li>They may restrict the data they accept and serve based on content or pubkey</li>
</ol>
<p>One additional feature that isn't currently standard but ought to be is strfry's negentropy synchronization feature. This is the opposite of AUTH, which protects a relay's own dataset, in that it allows relays to more efficiently share their data with peers. A nice bonus is that it also allows clients to use their local cache more effectively as well.</p>
<h2>Simple Made Easy</h2>
<p>Going back to Rich Hickey's talk, separating behavior and state allows you to work directly with your data, freely implementing new behavior whenever you need to. This applies to sets of events stored on relays just as much as it applies to in-memory data.</p>
<p>One thing that makes this possible is cryptographic hash functions, which cleanly transform state into values - the difference being that "state" couples a name with data that may change, while a hash is a compact representation of immutable data. If two hashes of event ids don't match, they're not the same set of events.</p>
<p>How does this apply to relays? Instead of adding new behavior to relays directly ("methods"), we can instead call "functions" on a relay's data.</p>
<p>This function can be anything - a centralized server, client code, or a DVM - that takes REQ filters as input. The function gathers the needed data (maybe from a cache, maybe using a sync command, maybe from multiple relays for completeness), performs the transformation, and returns it. The result is that relays become simple, interoperable repositories for data, without limiting what server-side computation can be applied to events.</p>
<p>While huge search indexes and centralized servers have a cost in terms of centralization, I think DVMs solve this problem brilliantly - the common interface for this augmented behavior is open, and can admit anyone who wants to start competing for search, counting, recommendations, or anything else you might want to do with events.</p>
<p>As Alan Perlis said, "It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures."</p>
<h1>Encrypted Messages</h1>
<p>Nostr DMs were a huge mistake, and I want to do it again.</p>
<p>NIP 04 has some obvious problems, most notably metadata leakage. The cryptography also hasn't been audited, and has some potential theoretical attack vectors. I've been working with some other nostr devs on a new cryptographic primitive, which will be audited and hopefully result in a better foundation for future work.</p>
<p>But fixing the cryptography still doesn't fix DMs. Nostr is not really the right architecture for secure private messaging, because ratchets require state. Nostr is designed such that there are no hard dependencies between events, which are replicated across multiple relays. This makes it very hard to manage the kind of state that protocols like SimpleX or Signal require.</p>
<p>Even apart from the difficulty of implementing stateful messaging protocols on nostr, we have two other problems to contend with: metadata leaks and spotty deliverability. Both of these problems come from the reliance of nostr on relays, which generally are not trustworthy or reliable.</p>
<h2>Metadata Leakage</h2>
<p>NIP 04 is really bad. Anyone can see who you corresponded with, when, how frequently, and how much you said just by looking at the event. Vitor's NIP 24 chat proposal aims to fix this with gift wraps, which use ephemeral keys to obscure the sender, padding to obscure message size, timestamp randomization to obscure timing, and double-wrapping to prevent leakage of the signed message.</p>
<p>This is a big improvement, but there are other forms of metadata that are still visible. To start, the recipient is still visible, along with how many messages they have received and their general size. So you can tell if someone sends lots of messages, or not a lot, but that's about it.</p>
<p>If we don't assume relays are trustworthy though, there are all kinds of implicit metadata that can be used to infer information about the sender, including:</p>
<ul>
<li>Client fingerprinting</li>
<li>Relay selection for publishing and queries</li>
<li>IP address collection</li>
<li>First seen timestamp</li>
<li>Identification of users by AUTH</li>
<li>Correlation of the event with other messages sent/received during a session</li>
</ul>
<p>These issues are much harder to solve, because they are part of the process of delivering the message, rather than just constructing it.</p>
<h2>Transport and deliverability</h2>
<p>The key feature of nostr that makes it work is relays. Relays provide storage redundancy and heterogeneity of purpose with a common interface shared by all instances. This is great for censorship resistance, but everything comes with a tradeoff.</p>
<p>Completeness and consistency are not guaranteed on nostr. This is ok in a social media context, because there's no way to keep up with everything everyone you follow says anyway, and you can rely on interactions and algorithmic tools to catch you up on anything important you missed.</p>
<p>But with private messages, every payload counts. Receiving messages out of order, with a delay, or not at all can severely disrupt conversations between two people, leading to misunderstandings and worse. This is a common experience on nostr; even fiatjaf has expressed skepticism about the viability of private messages on nostr.</p>
<p>This flakiness comes from a combination of low relay quality and poor relay selection on the part of clients. Relays can't deliver messages if they can't keep up with clients, go offline, or drop messages (accidentally or deliberately). Likewise, clients can't find messages if they look for them in the wrong place.</p>
<h2>Relays fixes this</h2>
<p>Let me just put things into perspective really quick. Twitter DMs are not e2e encrypted, and weren't encrypted at all until earlier this year. Mastodon messages are not encrypted - instance admins can read everything. Facebook has e2ee messages, but only between normal users, not in communities, groups, business chats, or marketplace chats.</p>
<p>So while nostr's architecture is not sufficient to make secure encrypted communication a value proposition of the protocol in itself, there is a lot we can do to improve on the status quo. Because nostr has no admins, the only option for privacy of any kind is end-to-end encryption. Metadata leakage notwithstanding, nostr messages can be "good enough" for some definition of that phrase.</p>
<p>It's important to not just punt on making DMs available in a standard way, because there is an expectation that a complete social media solution will have a way to establish a private communication channel with someone else in the network. Otherwise you're stuck with public correspondence and link sharing in order to hop to another protocol.</p>
<p>Let's just assume that you agree with me at this point, and that until there is a javascript SDK for SimpleX or MLS, we're stuck with nostr DMs of some kind. So how can we reduce metadata leakage and improve deliverability?</p>
<h2>Fixing Flakiness</h2>
<p>Let's start with deliverability first. NIP 65's inbox/outbox model is great. While it doesn't fix deliverability on its own, if every relay recommended was in fact reliable, and reliably followed by clients, there would be a very clear indication of where a particular user's messages could be found. Neither of these things is really true right now, but I do think clients are moving in this direction. Hopefully we can educate users better on how to pick good relays.</p>
<p>There are some limits to this model of course. For example, if you want to read notes from 1000 pubkeys at once, your client will likely end up connecting to hundreds of relays unless it has a cap, in which case it will miss a lot of notes.</p>
<p>One clean solution to this problem is relay proxies. There are a few implementations, but the one I run at mux.coracle.social is a stateless proxy that uses a wrapper protocol so clients can still select and dispatch to relays. I originally built this to improve mobile data use by deduplicating events on the server, and it does that pretty well, although it currently does it in the most naive way possible.</p>
<p>Multiplextr currently does not qualify as a "real" relay based on my four rules, since it uses a wrapper protocol. However, a smarter implementation would be able to route requests and events effectively by relying on client authentication and filter analysis, without changing the protocol. This would also allow clients to completely offload the complex business of relay selection to its proxy. Clients would also be able to combine multiple proxies just like they combine relays - because proxies are relays!</p>
<h2>Proxying Privacy</h2>
<p>Another downside of NIP 65 is that it encourages clients to connect indiscriminately to hundreds of different relays based on tag hints, other users' preferences, and relays baked into bech32 identifiers. This is not only bad for battery life and performance, but also allows attackers to easily trick your client into to connecting to their relay so they can start analyzing your traffic.</p>
<p>The best way to defend yourself against nosy relays is to not connect to them at all. And the easiest way to do that is to only connect to relays you control (or trust), and let them do the dirty work for you.</p>
<p>With a proxy, even if you don't control it, you can reduce the number of parties who can snoop on your traffic by orders of magnitude. And since other people use the proxy too, your traffic gets mixed with theirs, making it much harder to analyze. Of course, the downside of using a public proxy is that the proxy sees all messages you send and receive, and the relays you select for each request. Even worse, an untrusted multiplexer can hijack an authenticated session, exfiltrating private data from protected relays.</p>
<p>A proxy you control (or trust, either via social relationships or economic ones) is the best of both worlds. This proxy could also do some smart things for you to improve privacy as well, for example:</p>
<ul>
<li>Delayed publishing of gift wrapped messages so relays can't guess as easily when the event was first seen.</li>
<li>Closing and re-opening connections to reduce the number of messages sent over an AUTH'd session.</li>
<li>It could block suspicious messages on the fly, for example spam or notes with phishing links.</li>
<li>If an abundance of options are available for relay selections, it could randomize which relays are used, or avoid using less reputable ones.</li>
</ul>
<p>So I guess what I'm saying here, is "run a node". But not just any node - in the early days of nostr there were a lot of people spinning up relays because they thought it helped decentralization. Well, as it turns out, just like in bitcoin you have to <em>use</em> your node in order for it to be useful.</p>
<h1>Beyond DMs</h1>
<p>I'm not done yet, though. What's the point of all this? Why put all this effort into "good enough" DMs when we could spend the effort adopting SimpleX or MLS (said Semisol, who lives rent free in my head)?</p>
<p>Well, because there isn't a single "best" DM option. As I've dug into the topic, I've discovered that a ton of tradeoffs exist between complexity, privacy, and scale. The way I understand it, there are three basic options here:</p>
<ul>
<li>One-to-one encryption. This is how both SimpleX and Vitor's group message draft works. It allows for things like ratchets to be added on top, and is fairly simple - but fails to scale because every message has to be encrypted separately for every group member, resulting in <code>n*m</code> messages, where <code>n</code> is the number of group members, and <code>m</code> is the number of messages sent.</li>
<li>Encryption via shared key. This is how WhatsApp works, and it scales really well because messages don't have to be duplicated. And while it does support forward secrecy, it does not support post-compromise security, so it is significantly less secure.</li>
<li>MLS has a unique hierarchical approach to managing keys, which improves the complexity of one-to-one encryption so that it's logarithmic rather than exponential. However, MLS is highly stateful and still has scaling limitations.</li>
</ul>
<p>My takeaway is that there is no perfect solution. Ratchets are the gold standard, but can't really be implemented using nostr relays, since they frequently require servers to have very specific characteristics, like the ability to deliver messages in order.</p>
<p>The fact remains though, that social media needs encrypted messaging of some kind, even if we encourage users to bail to a more complete solution if they want to be truly private. And encryption is useful beyond small group chats - think of Facebook groups, which scale to millions of people and whose users have a much lower expectation of privacy. This is what nostr is good at - social data, whether encrypted or in plaintext.</p>
<h2>Belt and Suspenders</h2>
<p>For a long time I have waffled between two visions of how private groups ought to work. Should they be encrypted messages sprinkled across the nostr network like confetti? Or should they live on one or two relays in plaintext, protected by AUTH?</p>
<p>Both of these options have issues. Sprinkling encrypted messages across the network almost guarantees deliverability problems, since already many commodity relays block gift wraps. And that's ok! They have no obligation to store your encrypted messages.</p>
<p>Storing group messages in plaintext is also sub-optimal, even if it's on a dedicated relay. Of course we're not going for military-grade secrecy here, but it would be trivially easy through a bug, or even a client that doesn't know how to deal with groups, to re-broadcast events that should stay private. We could do something wacky, like strip the signature from events hosted on a relay, but if we're going to do something non-standard, we might as well do the best we can.</p>
<p>So why not both? Group messages should be encrypted, and they should be stored on a particular set of relays. Again, assuming the relays used are trustworthy, this fixes both privacy and deliverability problems, because it's very clear where messages posted to the group should go.</p>
<p>Promoting relays to trusted status has some nice, unintended benefits too. One common objection to using encrypted content is that it becomes hard to filter. But if a relay is trusted to store a group's messages, it can also be trusted to be admitted as a member to the group. This would allow the relay to decrypt events and filter them to respond to requests by authenticated group members.</p>
<p>Of course, this would violate rule <a href='/tag/1/'>#1</a> for relays, since they would no longer be supporting standard functionality, but a guy can dream, can't he?</p>
<h1>Conclusion</h1>
<p>When I started working on nostr I had no idea it would end up being this complex to accomplish what I set out to do. Building a twitter clone was only a first step to an MVP, but I always had my eye on the prize of serving my local church community, which doesn't give a sat about social media per se.</p>
<p>Private groups are important to me not because I'm setting out to support political dissidents or journalists (although I hope they find nostr useful too), but because I want to get my friends off of Facebook, and the only way to do that is to create private marketplaces, calendars, communties, and more.</p>
]]></itunes:summary>
      <itunes:image href="https://coracle.us-southeast-1.linodeobjects.com/juniperphoton-lAQRH4mCyl4-unsplash.jpeg"/>
      </item>
      
      </channel>
      </rss>
    