Nostrプロトコル(damus)を触ってみた

# はじめに
Twitterの動乱に巻き込まれている皆様、いかがお過ごしでしょうか。
私も例外なく巻き込まれており、特にAPI利用していたアプリケーションを停止することになって非常に残念です。

そこでTwitter代替サービスを探すわけですが

+ Mastodon
+ Misskey

とActivityPub系が来て、何か新たに面白そうなものが現れました。

Damus、そしてそのプロトコルのNostrです。
今回、こちらをちょっと触ってみたので紹介します。

---

とりあえず触ってみたい人はこちら

https://qiita.com/gpsnmeajp/items/2f95d4adf188276146d8

https://welcome.nostr-jp.org/

---

**[AT Protocolも書きました。こちら](https://qiita.com/gpsnmeajp/items/eb665d639f088b85454e
)**

:::note warn
注意
**Nostr Assets Protocol**および**Nostrトークン**は、Nostrの名前を勝手に使用している無関係の(おそらく詐欺)通貨です。混同しないようにご注意ください。
:::


# 最近の動向含めた最新情報(2023/12)
こちらの記事が参考になります

https://zenn.dev/mattn/articles/cf43423178d65c


▽それ、1個のアカウントで全部できるよ。そう、Nostrならね。 - godzhigella
※このサイト自体もnostrで実装されています。

https://yakihonne.com/article/naddr1qq25kumc2vuryj2nd4r4vvmddye52vjjdfs5zq3q6lrdq99ng2q4hg5ufre5f8j0qpealp8544vq4ctn2wqyrf4tk6uqxpqqqp65wzpqg78

# youtube動画作りました
こちらからどうぞ

https://www.youtube.com/watch?v=vB905DhX9nQ

# どんな人がいるの？
ここを見てください

https://nostr.hoku.in

# 結論
『「Nostrはおすすめか？」と聞くような人にはまだおすすめではないです』というのが自分の結論です。

# 注意
いろいろな意味でにわかユーザーが書いてますので、原典を当たってください。間違いがあれば編集リクエストをください。

何がいいのかとか、そういった話は以下の記事のようにブロガーの人たちがたくさん書くと思うので、本記事では技術的な側面にフォーカスして書きます。

https://hitoxu.com/030112

# 本記事の勉強会スライド版

https://speakerdeck.com/gpsnmeajp/nostrgai-shuo

https://speakerdeck.com/gpsnmeajp/fen-san-xing-sns-nostr-shi-zu-mijie-shuo

# 特徴と違いについて
まず私の理解を図に表します。

## 中央集権型(Twitterなど)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/c613df7b-3fd3-aab2-1029-e79a7d5f3ed7.png)

## 連合型分散(地方分権型) (ActivityPubのMastodon, Misskeyなど)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/38ccc119-fc34-e615-d8a5-ee05dd2261d6.png)

## リレー型分散(無責任中継型) (Nostr)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/922901ea-4d92-f67c-3f38-ac245a1413c5.png)

## おまけ: AT Protocol(地方分権型) (ATP:BlueSky)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/1a9d75da-4f09-1949-10cf-bb3901265da3.png)

https://qiita.com/gpsnmeajp/items/eb665d639f088b85454e

参考

https://educatedguesswork.org/posts/atproto-firstlook/

# Nostrの仕組み
Nostrの仕組みはかなりシンプルです。
リレーです。P2Pでもなければブロックチェーンでもありません。
超シンプルなWebsocketのクライアント-サーバーモデル。サーバーがシンプルなリレー。

ほぼ"電子署名前提になったIRC"とも言えるかも。
Twitter風かどうかはクライアントのUI(見た目)の問題です。

https://github.com/nostr-protocol/nips/blob/master/01.md

## 登場人物
まず、登場人物としては2つです。

+ クライアント: WebSocketクライアントです。鍵ペアを持ち、リレーに情報を投稿します。
情報の配信とフィルタをリレーに要求し、受け取ってユーザーに表示します。
+ リレー: WebSocketサーバーです。投稿をフィルタに基づいてクライアントに配信します。
投稿をすべて保存し、要求があった時に再配信もします。(オプションですが認証も可能です)

## 情報
投稿される情報としては主に以下です。

+ ユーザーメタデータ(プロフィール)
+ テキスト
+ 推奨リレー一覧
+ 連絡先リスト
+ 暗号化DM
+ 削除情報
+ リアクション
+ チャンネル

## 秘密鍵の役目
さて、これらの情報をクライアント-リレー間でやり取りすることになります。

Nostrにはログインという概念はありません。セッションもありません。(有料リレーを使うための認証を除く)
情報の署名を行うための秘密鍵を持っているか、居ないか、それだけです。

署名が必要なのは、送信と暗号化DMの読み取りだけです。
ので、公開された情報(公開鍵がわかっている情報)を読むためには特に何も要りません。

逆に、送信される情報はすべてクライアント側で署名されることになります。
リレーがその情報を加工したりした場合、署名検証で弾かれることになります。
リレーがそこに携わることはなく、クライアント主導の仕組みとなります。

そのため、秘密鍵の所有が、アカウントの所有に相当することになります。
逆に、秘密鍵以外の情報はリレーに保存されることになります。

(そうすることで複数クライアントの間で自然に同期できるようになり、モバイルデバイスにおいて有利です)

## リレーの役目
リレーの役目は、中継と、保存・再配信です。(あとオプションで認証)

具体的に言うと主に以下の役割があります。

+ **ユーザーメタデータ(プロフィール)を保持します。更新があったときはリアルタイムに中継します。**
これにより、各ユーザーの公開鍵からプロフィール情報(名前やWebサイトNIP-05識別子など)を表示できるようになります。
さらにここには、そのユーザーが使用しているリレーの一覧も含まれています。
(Damusを使っているとデフォアイコン&公開鍵の名前になることがありますが、これはこのメタデータをダウンロードできていないタイミングです)
+ **テキスト投稿を保持・中継します**
SNSの基本機能です。

他にも諸々役目がありますし、増えていくんだと思いますが省略。

## 基本的な動作
これにより以下のような動作が実現されます。

+ クライアントは投稿を同時に接続している書込み可能なすべてのリレーに送信します。
+ またクライアントは読み込み可能なすべてのリレーから配信を受けます。
+ そのため、同じリレーに属してる人が同じものを見れます。
+ リレー自体はあまり賢くはなく情報の中継に特化しています。
これにより、複数のリレーのうちどれかに属していれば同じ動作が期待できるため、リレーを変えると何かが失われるといった心配をしなくて済みます。
+ リレーには多数属しておくことでより冗長化できます。
+ リレーが突然死したり、ブロックしてきたりしても他のリレーが生きていれば特に何をすることもなく使用し続けられます。
+ すべてのリレーが突然死しても、新しいリレーを登録することで、過去の投稿は消えるかもしれませんがアカウント(秘密鍵)はそのまま使い続けられます。

クライアントの作りによりますがあなたの手元で7つのリレー先を全部消して別のリレーに変えたとしても、クライアントからプロフィール更新すれば新しいリレーにあなたのプロフィールが伝わります。
あなたの発言を見たい人は、あなたが属しているリレーのどれか1つさえ知れれば、アクセスして残りのリレーの情報を知ることができます。

※追記: リレー同士の横連携は、strfryなどでは行われるようです。

https://github.com/hoytech/strfry#syncing


## 動作の流れ
実際に使用する時の流れは以下になります。

1. **リレーサーバーに接続します。**
最低1つですが、複数接続するのが普通です。Damusの場合は7つあります。
1. **自分自身(ユーザー)の公開鍵から、リレーに自分のプロフィールを取得し、フォローリスト(公開鍵一覧)を取得します。**
※もちろんクライアントがローカルに保持していてもOKです。
1. **公開鍵リストをフィルタとして設定し、フォローしている人のプロフィールを要求します。**
これをキャッシュしておくことで名前やアイコンをUIに表示できます。
※もちろんクライアントがローカルに保持していてもOKです。
1. **公開鍵リストをフィルタとして設定し、テキスト投稿を要求します。**
これにより、タイムラインが表示できます。
1. **以降、プロフィールの更新やテキスト投稿が増えると逐次配信されるため、UIに反映します。**

実際にはさらに、特定の人のTLを見に行った場合は、上記のような動作を特定の公開鍵に対して実施する。

上記をDartで簡易的に実装したサンプルを最後に置きました。


# 容易に考えられる問題点
さて、ここまで仕組みを説明しましたがいくつかの疑問が生まれてきます。

## 治安・スパム
リレーの機能から見てもわかるように、抑止が全然できません。
中央サーバーに依存しないため、回復力が強く、それゆえに困った利用者を排除するのが難しいです。

Q. リレーは各ユーザーの公開鍵をもとに中継しないとかそうった対処はできないか？
A. できますが、それはあくまで1リレーだけです。他のリレーは中継してしまいます。

Q. リレー間でグローバルBAN連携する仕組みがあったらどうでしょう。MCBansみたいな。
A. それは機能します。では平和になったかと思いきや、そもそものユーザーってなんでしたっけというのを思い出してみましょう。
そう、ユーザーとは秘密鍵のことです。秘密鍵はどこに登録されるわけでもありません。勝手にクライアントが生成します。
究極的に言えば、1投稿に付き1鍵ペアを作ることも可能で、そうするとBANの意味がぜんぜんありません。

リレーをもっと高機能化すればいいかもしれません。
例えばNIP-05によるドメイン認証してる人だけにするとか、
定型文スパムが多いならその文言を弾きましょうか
リレーをホワイトリスト制にするとか、電話番号認証するとか
そもそもリレーの使用を有料化するとか
問題があるリレーに属するのが悪いのなら、安全なリレーに絞ってしまえばいいでしょう。

これはNostrの仕様にも書いています。
メールサーバーでやってる処理とかなり似ている気がしますね。

...でも、あれ？そこまでやる意味って？
とはいえ、それが必要とされる時代が来れば実装されるかもしれません。

秘密鍵を保持する限り、接続先を変えれば一瞬で囲いの外に出られる利点はあります。

ちなみに、NIP-13にはPoWによるスパム防止がありました。
ちょっとブロックチェーン的な雰囲気が出てきますが、単に計算量によるスパム防止らしいです。
(元はPoW自体スパムメール対策で考案された仕組みらしい？)

## データ保持期間
リレーはどのくらいデータを保持してくれるんでしょうか？
特に取り決めはありません。

大して重くはないデータかもしれませんが、それでも人数や、鍵ペア使い捨てスパムなんかが現れればなおのこと、データ量を持ち続けられなくなるかもしれません。

そうすると、投稿が残る保証はなくなります。
クライアント側で保存しておいて再配信する事もできるかと思いますが、それを皆が繰り返すともっとひどいことになりますし。

困るのはプロフィールデータも同じ扱いということで、何年か後には投稿どころか名前まで消えているかもしれません。
これに関しては長期保存してくれるリレーにお金を払うなり、あるいは自分用のリレーを立てるなり...となるでしょう。

なお逆に、今すぐ消したいというのも叶いません。削除要求はできますが、論理削除にとどまります。
各クライアントには残りますし、リレーにも残るでしょう。(これはNostrに限った話ではありませんが)

実際の無料有料のリレーたち

https://scrapbox.io/nostr/ROBO358


## トラフィック
複数のリレーにまとめてぶん投げて、複数のリレーから配信を受けます。
Damusで見ていると、100以上のリレーに投げている人も見かけます。(メタデータに含まれるためタップして確認できます)

現在はテキストのみですが、増えていくとリレーの負荷がすごいことになりそうです。
このトラフィックは誰が捌くのでしょうか？

## globalはやめておけ
現在のNostrクライアントは、フィルタなしの配信を受け取って表示する機能がついています。
これはリレーに属しているすべての人の投稿が見える状態です。

すごく治安が悪い上にリレーとクライアント双方に負荷がかかりますので、もしクライアントを作る場合は絶対やめておいたほうがいいと思います。

## なりすまし
保証できるのは鍵ペアだけで、表示名などは好きに名乗れます。

有名人の名前とか見て飛びつかないように。通報しても多分消えません。そもそも上記の通り通報システムが機能するとは思えません。
独自ドメインやレンタルサーバー、github pagesをお持ちの方は、NIP-05による本人認証表示ができますので、設定しておくことをおすすめします。

# Tips

## これはSNSなのか？
SNSを意図してるようですが、保存期間の長めで分散型のチャットと考えたほうが正解な気がします。

※IRCやネットニュースの構成の再来という話もあり。

あまりにシンプルなプロトコル故、チャットやコメント欄、その他様々な用途の応用が期待できます。鍵ペア作ってストレージに入れたらアカウントになっちゃいますからね。

むしろTwitterみたいな見た目に期待しすぎない方が良いかもしれません。鍵を紛失・漏出した時の保証が一切ないため、そこら辺のクライアントを気軽に試すのはやめましょう。

※Webサイトのコメント欄に使っている例

https://fiatjaf.com/nostr.html

## おすすめなのか？
一般受けは(現時点で)しないと思うので技術的な興味を持つ人だけやればいいと思います。

めちゃくちゃ強い生命力があると思うので、他サービス崩壊時や通信障害時といった場合の非常時の通信用にはいいかもしれません。


常用には向かない気がしています。(スパムの温床になりそう)

また将来、リレーがリッチになり、クライアントがより洗練されたら、Nostrが基礎プロトコルとして多用される未来は来るかもしれません。

私は現時点では普段はActivityPub系のサービスを使うことにします。
でも技術的には面白いのでちょいちょい覗こうと思います。

## 日本語話者を探すには？

+ #japan タグを探してフォロー
+ twitterなどで公開鍵出してる人を探してフォロー
+ フォローした人のフォロー一覧を見る
+ (上級者向け)スパムに埋もれたglobalから日本語を探す

## クライアントは何を使えばいい？
+ damus
+ iris
+ Amethyst

注意: クライアントを変えるときはリレーサーバーリストが既存のフォロワーと合ってるか要確認。1つも一致しない場合は会えなくなります。


## とりあえずROMりたいんだけど
そこらへんの人の公開鍵でログインしてみてください。
秘密鍵がないと見れない情報(DM)以外は全部その人になりきって見れます。
(もちろん署名できないので投稿失敗します)

https://zenn.dev/tkithrta/articles/d403f84a40fe63

日本フォロー1000人のひとの公開鍵でログインすると実質日本Local Timelineみたいになります。

秘密鍵を漏らすと大変なことになるので、適当なクライアントにログインする場合は公開鍵でログインするのもありかも入れません。

## 文字数制限は？
リレーサーバー次第。現在は名前も無限に入れられる。

## 認証バッチの意味は？
NIP-05に基づく認証情報を設定しており正常に確認できている状態。
つまり、その人用のWebサーバーがあって、そのWebサーバーも認めている状態。

その人が本物か？Webサーバーやドメインの所有者がまともかを確認してください。
Nostr自体はそことの関連付けの正しさまでしか保証しません。

本人かどうかを知る一番手っ取り早い方法は、TwtitterやMastodonその他本人確認が取れている手段で公開鍵を出してもらうことです。

## アイコンはどう設定するの？
自分のサーバーかGravatarあたりにアイコンを置いて、そこをアイコンURLに設定します。
Nostr自体にアイコン画像データを保持する仕組みはなく、メタデータのURLでクライアントが読みに行きます。

## 画像とか動画は貼れるの？
現状テキストのみ。
OGP対応したURLか、画像の生URLを貼ると実質画像投稿みたいに見えますのでそれで代用する仕組みです。

## 匿名性は？
ないよ。署名が付いてるので全部検証されますし、なによりクライアントのIPアドレスがあちこちで漏れていきます。画像読み込みとかアイコン読み込みとかリレー接続とか

## 日本のリレーサーバーは？
現時点で3つくらいあります。
接続先をここだけに絞るとSAPMはぼほいなくなりますが、交流できる相手もぐっと減ります。

https://scrapbox.io/nostr/日本語リレー

## プロフィールが消えちゃうんだけど
リレーを切り替えたときとか、ある程度のタイミングでプロフィールを更新してメタ情報を配信しましょう。

## 実際のところどのくらいログ残るの？
わからないけど最短2日くらいで見えなくなる時がある。
しかもバラバラと。

クライアントのフィルタの仕様かもしれないし、リレーが忘れてしまったのかもしれないし、わかりません。
(クライアント次第でまた見えたり見えなかったりします)

ID指定すると取得できたりするので、消えるとも限りません。

## リレーの種類は？
+ 公開リレー
+ 私設リレー
+ 有料リレー
+ ホワイトリストリレー
+ アプリケーション特化リレー

があるらしい。

https://thebitcoinmanual.com/articles/types-nostr-relays/

## Wikiみたいなところはある？
以下

https://scrapbox.io/nostr/

## 通信量食わない？
めっちゃ食います。リレーの数には注意。
外出先ではリレーの数を絞ったほうがいいかも

## Discord的なクライアントある？
ある(使ったことはないです)

## 掲示板的な実装ある？
ある

https://bbs-on-nostr.vercel.app


## 秘密鍵をクライアントに入れたくないんだけど
NIP-07に基づいたブラウザ拡張(nos2x等)を使えばいいです。iris.to はサポートしている。
ハードウェアウォレット的なものも実現できるはずです。

以下のように確認してくるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/9304de93-a2a3-586f-9b22-88ecee47f792.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/f68a184e-16d7-23af-57e1-e6aa48725b41.png)

https://scrapbox.io/nostr/nos2xのセットアップと使い方

## フォロワーってどうやって取得してるの
フィルタに「自分の公開鍵をフォローしている連絡先リスト」を設定してリレーに問い合わせしてそこから算出するようです。

## アカウントどうやって消すの？
アカウントの削除という概念はない。なんなら、作成という概念もない。
あるのは秘密鍵で署名された情報、ただそれだけです。

## 秘密鍵を漏らしてしまった
残念ですが、他人があなたになりすますことができるようになってしまいました。
一方で、あなたの署名が阻害されるわけではありません。
パスワード変更に該当するものがないため、あなたが対処するすべはない代わりに、他人が奪うこともできません。

なりすまそうとする人と書き込みバトルを始めることもできますが、
落ち着いて、以下を行いましょう

+ プロフィールとフォローを空にします
+ NIP-05で認証している場合は認証元サーバーから削除します
+ 新しい鍵ペアを作ります
+ 新しい公開鍵をフォロワーや大切な人に伝えます
+ フォロワーに詫びを入れ、「以後一切このアカウントの情報は信用しないように」書き残しましょう
+ 将来に備えて古い秘密鍵は取っておいて、新しい秘密鍵を使いましょう
+ あとは悪用されないことを願います


# 仕様等の参考記事(比較対象の他プロトコル含む)
Nostr使い方と技術概要

https://numpad0.com/texts/crash_course_nostr

Nostrプロトコル概要

https://txt.murakmii.dev/posts/hello-nostr

Nostrプロトコル概要

https://dev.to/melvincarvalho/the-nostr-protocol-nip01-5ach

Nostrプロトコルの概要とビジョン

https://github.com/rajarshimaitra/rust-nostr/blob/main/VISION.md

Nostrプロトコル斜め読み

https://qiita.com/gpsnmeajp/items/5f22b7a96422fecc7ece

Nostr全体概要

https://fumi.medium.com/nostr-f8e6636b5724

Nostr解説

https://zenn.dev/amane/articles/599d6789adbd17

Nostr公式

https://github.com/nostr-protocol/nostr

Nostr公式プロトコル仕様

https://github.com/nostr-protocol/nips

Nostrクライアントの機能対応状況一覧

https://github.com/vishalxl/Nostr-Clients-Features-List/blob/main/Readme.md

リレーおためし

https://qiita.com/koteitan/items/921fcd6a6034aae4a9a4

Nostrパーマリンク

https://chalow.net/2023-02-05-1.html

Nostrほかいろいろ

https://www.nostr.net

シュノア署名解説

https://blog.visvirial.com/articles/721

ActivityPubプロトコル概要

https://qiita.com/nullkal/items/accc5d62836a930b3cd9



# DartによるTL閲覧クライアントのお試し実装
仕様を読みながら適当に書き散らしたものなので実用には耐えません。
1つのリレーに接続し、公開鍵からフォロー一覧を取得、そこから各人のプロフィールを取得、その後TLを受信して表示しつづけるという動作をします。

https://gist.github.com/gpsnmeajp/09f2ff0bd0c9167fb335aed79311cb26

# NIP-07のお試し実装
ブラウザ拡張機能などでwindowを拡張し、Webページに秘密鍵を渡すことなく安全に署名する仕組みのお試し実装。
なお、お試しすぎて機密性がないので実利用は禁止です。使い捨てのアカウントなどで試してください。

https://gist.github.com/gpsnmeajp/23a2563ec39d4db43f0f922e5f08de87

# NIP-07のお試し実装 その2

https://github.com/gpsnmeajp/nip07ex