A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>nostr - Notes and Other Stuff Transmitted by Relays (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://github.com/fiatjaf/nostr">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>nostr - Notes and Other Stuff Transmitted by Relays</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://github.com/fiatjaf/nostr" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>The simplest open protocol that is able to create a censorship-resistant global "social" network once and for all.</p>
  71. <p>It doesn't rely on any trusted central server, hence it is resilient; it is based on cryptographic keys and signatures, so it is tamperproof; it does not rely on P2P techniques, therefore it works.</p>
  72. <p>This is a work-in-progress. <a href="https://t.me/nostr_protocol">Join the Telegram group!</a></p>
  73. <h2>Very short summary of how it works, if you don't plan to read anything else:</h2>
  74. <p>Everybody runs a client. It can be a native client, a web client, etc. To publish something, you write a post, sign it with your key and send it to multiple relays (servers hosted by someone else, or yourself). To get updates from other people, you ask multiple relays if they know anything about these other people. Anyone can run a relay. A relay is very simple and dumb. It does nothing besides accepting posts from some people and forwarding to others. Relays don't have to be trusted. Signatures are verified on the client side.</p>
  75. <h2>This is needed because other solutions are broken:</h2>
  76. <h3>The problem with Twitter</h3>
  77. <ul>
  78. <li>Twitter has ads;</li>
  79. <li>Twitter uses bizarre techniques to keep you addicted;</li>
  80. <li>Twitter doesn't show an actual historical feed from people you follow;</li>
  81. <li>Twitter bans people;</li>
  82. <li>Twitter shadowbans people.</li>
  83. <li>Twitter has a lot of spam.</li>
  84. </ul>
  85. <h3>The problem with Mastodon and similar programs</h3>
  86. <ul>
  87. <li>User identities are attached to domain names controlled by third-parties;</li>
  88. <li>Server owners can ban you, just like Twitter;</li>
  89. <li>Migration between servers is an afterthought and can only be accomplished if servers cooperate. It doesn't work in an adversarial environment (all followers are lost);</li>
  90. <li>There are no clear incentives to run servers, therefore they tend to be run by enthusiasts and people who want to have their name attached to a cool domain. Then, users are subject to the despotism of a single person, which is often worse than that of a big company like Twitter, and they can't migrate out;</li>
  91. <li>Since servers tend to be run amateurishly, they are often abandoned after a while — which is effectively the same as banning everybody;</li>
  92. <li>It doesn't make sense to have a ton of servers if updates from every server will have to be painfully pushed (and saved!) to a ton of other servers. This point is exacerbated by the fact that servers tend to exist in huge numbers, therefore more data has to be passed to more places more often;</li>
  93. <li>For the specific example of video sharing, ActivityPub enthusiasts realized it would be completely impossible to transmit video from server to server the way text notes are, so they decided to keep the video hosted only from the single instance where it was posted to, which is similar to the Nostr approach.</li>
  94. </ul>
  95. <h3>The problem with SSB (Secure Scuttlebutt)</h3>
  96. <ul>
  97. <li>It doesn't have many problems. I think it's great. In fact, I was going to use it as a basis for this, but</li>
  98. <li>its protocol is too complicated because it wasn't thought about being an open protocol at all. It was just written in JavaScript in probably a quick way to solve a specific problem and grew from that, therefore it has weird and unnecessary quirks like signing a JSON string which must strictly follow the rules of <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-json.stringify"><em>ECMA-262 6th Edition</em></a>;</li>
  99. <li>It insists on having a chain of updates from a single user, which feels unnecessary to me and something that adds bloat and rigidity to the thing — each server/user needs to store all the chain of posts to be sure the new one is valid. Why? (Maybe they have a good reason);</li>
  100. <li>It is not as simple as Nostr, as it was primarily made for P2P syncing, with "pubs" being an afterthought;</li>
  101. <li>Still, it may be worth considering using SSB instead of this custom protocol and just adapting it to the client-relay server model, because reusing a standard is always better than trying to get people in a new one.</li>
  102. </ul>
  103. <h3>The problem with other solutions that require everybody to run their own server</h3>
  104. <ul>
  105. <li>They require everybody to run their own server;</li>
  106. <li>Sometimes people can still be censored in these because domain names can be censored.</li>
  107. </ul>
  108. <h2>How does Nostr work?</h2>
  109. <ul>
  110. <li>There are two components: <strong>clients</strong> and <strong>relays</strong>. Each user runs a client. Anyone can run a relay.</li>
  111. <li>Every user is identified by a public key. Every post is signed. Every client validates these signatures.</li>
  112. <li>Clients fetch data from relays of their choice and publish data to other relays of their choice. A relay doesn't talk to another relay, only directly to users.</li>
  113. <li>For example, to "follow" someone a user just instructs their client to query the relays it knows for posts from that public key.</li>
  114. <li>On startup, a client queries data from all relays it knows for all users it follows (for example, all updates from the last day), then displays that data to the user chronologically.</li>
  115. <li>A "post" can contain any kind of structured data, but the most used ones are going to find their way into the standard so all clients and relays can handle them seamlessly.</li>
  116. </ul>
  117. <h2>How does it solve the problems the networks above can't?</h2>
  118. <ul>
  119. <li><strong>Users getting banned and servers being closed</strong></li>
  120. <li>A relay can block a user from publishing anything there, but that has no effect on them as they can still publish to other relays. Since users are identified by a public key, they don't lose their identities and their follower base when they get banned.</li>
  121. <li>Instead of requiring users to manually type new relay addresses (although this should also be supported), whenever someone you're following posts a server recommendation, the client should automatically add that to the list of relays it will query.</li>
  122. <li>If someone is using a relay to publish their data but wants to migrate to another one, they can publish a server recommendation to that previous relay and go;</li>
  123. <li>If someone gets banned from many relays such that they can't get their server recommendations broadcasted, they may still let some close friends know through other means with which relay they are publishing now. Then, these close friends can publish server recommendations to that new server, and slowly, the old follower base of the banned user will begin finding their posts again from the new relay.</li>
  124. <li>
  125. <p>All of the above is valid too for when a relay ceases its operations.</p>
  126. </li>
  127. <li>
  128. <p><strong>Censorship-resistance</strong></p>
  129. </li>
  130. <li>Each user can publish their updates to any number of relays.</li>
  131. <li>
  132. <p>A relay can charge a fee (the negotiation of that fee is outside of the protocol for now) from users to publish there, which ensures censorship-resistance (there will always be some Russian server willing to take your money in exchange for serving your posts).</p>
  133. </li>
  134. <li>
  135. <p><strong>Spam</strong></p>
  136. </li>
  137. <li>
  138. <p>If spam is a concern for a relay, it can require payment for publication or some other form of authentication, such as an email address or phone, and associate these internally with a pubkey that then gets to publish to that relay — or other anti-spam techniques, like hashcash or captchas. If a relay is being used as a spam vector, it can easily be unlisted by clients, which can continue to fetch updates from other relays.</p>
  139. </li>
  140. <li>
  141. <p><strong>Data storage</strong></p>
  142. </li>
  143. <li>For the network to stay healthy, there is no need for hundreds of active relays. In fact, it can work just fine with just a handful, given the fact that new relays can be created and spread through the network easily in case the existing relays start misbehaving. Therefore, the amount of data storage required, in general, is relatively less than Mastodon or similar software.</li>
  144. <li>
  145. <p>Or considering a different outcome: one in which there exist hundreds of niche relays run by amateurs, each relaying updates from a small group of users. The architecture scales just as well: data is sent from users to a single server, and from that server directly to the users who will consume that. It doesn't have to be stored by anyone else. In this situation, it is not a big burden for any single server to process updates from others and having amateur servers is not a problem.</p>
  146. </li>
  147. <li>
  148. <p><strong>Video and other heavy content</strong></p>
  149. </li>
  150. <li>
  151. <p>It's easy for a relay to reject large content, or to charge for accepting and hosting large content. When information and incentives are clear, it's easy for the market forces to solve the problem.</p>
  152. </li>
  153. <li>
  154. <p><strong>Techniques to trick the user</strong></p>
  155. </li>
  156. <li>Each client can decide how to best show posts to users, so there is always the option of just consuming what you want in the manner you want — from using an AI to decide the order of the updates you'll see to just reading them in chronological order.</li>
  157. </ul>
  158. <h2>FAQ</h2>
  159. <ul>
  160. <li><strong>This is very simple. Why hasn't anyone done it before?</strong></li>
  161. </ul>
  162. <p>I don't know, but I imagine it has to do with the fact that people making social networks are either companies wanting to make money or P2P activists who want to make a thing completely without servers. They both fail to see the specific mix of both worlds that Nostr uses.</p>
  163. <ul>
  164. <li><strong>Can I know how many people are following me?</strong></li>
  165. </ul>
  166. <p>No, but you can get some estimates if relays cooperate in an extra-protocol way.</p>
  167. <h2>Protocol specification</h2>
  168. <p>See the <a href="nips">NIPs</a> and especially <a href="nips/01.md">NIP-01</a> for a reasonably-detailed explanation of the protocol spec (hint: it is very short and simple).</p>
  169. <h2>Small list of software that implement the Nostr protocol somehow</h2>
  170. <h3>Relays</h3>
  171. <ul>
  172. <li><a href="https://github.com/Kukks/NNostr">NNostr</a>, a C# Nostr relay.</li>
  173. <li><a href="https://sr.ht/~gheartsfield/nostr-rs-relay/">nostr-rs-relay</a>, a minimalistic relay written in Rust that saves data on SQLite.</li>
  174. <li><a href="https://github.com/fiatjaf/relayer/tree/master/basic">Relayer Basic</a>, a simple relay based on <em>relayer</em> backed by Postgres.</li>
  175. <li><a href="https://github.com/fiatjaf/rsslay">rsslay</a>, a bridge that puts RSS feeds into Nostr.</li>
  176. <li><a href="https://github.com/Dolu89/nodestr-relay">nodestr</a>, A Node.js implementation.</li>
  177. </ul>
  178. <h3>Clients</h3>
  179. <ul>
  180. <li><a href="https://github.com/fiatjaf/branle">branle</a>, a Twitter-like client also with chat.</li>
  181. <li><a href="https://github.com/fiatjaf/noscli">noscl</a>, a basic command-line client written in Go.</li>
  182. <li><a href="https://github.com/emeceve/nostr-chat">nostr-chat</a>, a desktop app written in Rust for direct encrypted chat.</li>
  183. <li><a href="https://github.com/dolu89/chastr">chastr</a>, a mobile directed encrypted chat app written in Xamarin.</li>
  184. <li><a href="https://github.com/arcbtc/nostr">nostr-twitter</a>, a Twitter-like UI that also implements private direct messages.</li>
  185. </ul>
  186. <h3>Libraries</h3>
  187. <ul>
  188. <li><a href="https://github.com/Kukks/NNostr">NNostr.Client</a>, a C# Nostr library for use by clients.</li>
  189. <li><a href="https://github.com/fiatjaf/nostr-tools">nostr-tools</a>, a JavaScript client that abstracts the relay management code for use by clients.</li>
  190. <li><a href="https://github.com/fiatjaf/go-nostr">go-nostr</a>, a Go library that implements relay management, plus event encoding and signing utils.</li>
  191. <li><a href="https://github.com/futurepaul/nostr-rs">nostr-rs</a>, a Rust implementation of the nostr protocol.</li>
  192. <li><a href="https://github.com/fiatjaf/relayer">relayer</a>, a server framework for writing custom relays.</li>
  193. </ul>
  194. <h3>Tools</h3>
  195. <ul>
  196. <li><a href="https://nostr-registry.netlify.app/">nostr relay registry</a>, real-time checking of status of some known relays.</li>
  197. <li><a href="https://codeberg.org/rsbondi/nostr-registry">nostr registry</a>, a database of known relays with their uptime and NIP support tables.</li>
  198. <li><a href="https://codeberg.org/rsbondi/nostr-launch">nostr-launch</a>, a tool for launching a bunch of relays and clients locally for development and testing.</li>
  199. </ul>
  200. <h2>License</h2>
  201. <p>Public domain.</p>
  202. </article>
  203. <hr>
  204. <footer>
  205. <p>
  206. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  207. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  208. </svg> Accueil</a> •
  209. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  210. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  211. </svg> Suivre</a> •
  212. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  213. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  214. </svg> Pro</a> •
  215. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  216. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  217. </svg> Email</a> •
  218. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  219. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  220. </svg> Légal</abbr>
  221. </p>
  222. <template id="theme-selector">
  223. <form>
  224. <fieldset>
  225. <legend><svg class="icon icon-brightness-contrast">
  226. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  227. </svg> Thème</legend>
  228. <label>
  229. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  230. </label>
  231. <label>
  232. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  233. </label>
  234. <label>
  235. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  236. </label>
  237. </fieldset>
  238. </form>
  239. </template>
  240. </footer>
  241. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  242. <script>
  243. function loadThemeForm(templateName) {
  244. const themeSelectorTemplate = document.querySelector(templateName)
  245. const form = themeSelectorTemplate.content.firstElementChild
  246. themeSelectorTemplate.replaceWith(form)
  247. form.addEventListener('change', (e) => {
  248. const chosenColorScheme = e.target.value
  249. localStorage.setItem('theme', chosenColorScheme)
  250. toggleTheme(chosenColorScheme)
  251. })
  252. const selectedTheme = localStorage.getItem('theme')
  253. if (selectedTheme && selectedTheme !== 'undefined') {
  254. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  255. }
  256. }
  257. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  258. window.addEventListener('load', () => {
  259. let hasDarkRules = false
  260. for (const styleSheet of Array.from(document.styleSheets)) {
  261. let mediaRules = []
  262. for (const cssRule of styleSheet.cssRules) {
  263. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  264. continue
  265. }
  266. // WARNING: Safari does not have/supports `conditionText`.
  267. if (cssRule.conditionText) {
  268. if (cssRule.conditionText !== prefersColorSchemeDark) {
  269. continue
  270. }
  271. } else {
  272. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  273. continue
  274. }
  275. }
  276. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  277. }
  278. // WARNING: do not try to insert a Rule to a styleSheet you are
  279. // currently iterating on, otherwise the browser will be stuck
  280. // in a infinite loop…
  281. for (const mediaRule of mediaRules) {
  282. styleSheet.insertRule(mediaRule.cssText)
  283. hasDarkRules = true
  284. }
  285. }
  286. if (hasDarkRules) {
  287. loadThemeForm('#theme-selector')
  288. }
  289. })
  290. </script>
  291. </body>
  292. </html>