AT Protocol (BlueSky Social)仕様解説 ～ W3C DID仕様を添えて ～

# 結論
まだMastodon以下の機能実現状況なので、SNS目的で参加するのはNostr以上に勧めしません。
API叩いて遊べる人や、自分で問題解決できる人向け

**※現在、基本機能も完成していないためクローズドβ中です。**

**公式サーバーの作成には、既存ユーザーに発行される招待コードが必要です(2週間に付き1個)**
**有志の非公式サーバーもそちら用の招待コードが必要になりました。**

**まだまだ仕様も未完成！！！破壊的変更も色々起きるぞ！**

※コードを買ってまで参加するものではないと思います。開発やフィードバックに協力できる人のみ参加すべき。

# はじめに
Twitterの動乱に巻き込まれ、移住先にMisskeyやMastodonなど選ばれつつある今日このごろ、皆様いかがお過ごしでしょうか。

つい先日、BlueSkyのクローズドベータが開始されました。
BlueSkyは、Nostr同様Twitter創設者のジャック・ドーシー氏の支援の元開発されている新しいSNSです。

Mastodon等のActivityPubにおける弱点を解決しようと開発されているものです。
Nostr開発者たちがこぞって注目している現在、私の理解している限りの説明を書いてみようと思います。

ATコマンドではないですよ


## 勉強会スライド版

https://speakerdeck.com/gpsnmeajp/at-protocol-bluesky-social-shi-yang-jie-shuo-w3c-didshi-yang-wotian-ete

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

https://atproto.com/

https://www.w3.org/TR/did-core/

https://identity.foundation/

https://qiita.com/kazuhideYS/items/2f533bf14e8587c7c131

http://www.asahi-net.or.jp/~ax2s-KMTN/internet/did/REC-did-core-20220719.html

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

https://netafull.net/tech/0126173.html

https://zenn.dev/kato_shinya/articles/lets-try-bluesky-social


# 関連情報
公式サイト

https://blueskyweb.xyz/

公式アプリ

https://apps.apple.com/jp/app/bluesky-social/id6444370199

Scrapbox(wiki)

https://scrapbox.io/Bluesky/

DID:PLCの実装周り

https://zenn.dev/teatwo/articles/cc08f5f9de9c55

非公式アプリたち(Web/Android等)

https://scrapbox.io/Bluesky/%E9%96%A2%E9%80%A3%E3%83%84%E3%83%BC%E3%83%AB

非公式ブラウザ閲覧ツール

https://blue.amazingca.dev/

↑@gpsnmeajp.achetaria.com を入れると私の投稿が見れます。


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

## 中央集権型(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)

https://qiita.com/gpsnmeajp/items/77eee9535fb1a092e286

## AT Protocol(地方分権型 + アカウントポータビリティ)  (ATP:BlueSky)
※どちらの図にも不正確な表現が含まれます。
具体的には

+ ネームサーバー(DID PLC)は複数の人が立てうるものです。(公式サーバーはある)
+ データリポジトリ(Repo)は、PDSのみが配信するとは限りません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/ee53441a-aea9-24ed-4498-ca3ebb89fdb3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/f8140a89-dbf8-4cba-f1a0-2ec2d12e9c8d.png)



# AT Protocol (Authenticated Transfer Protocol) の目指す姿
AT Protocolは、BlueSkyによって作成されたネットワークテクノロジーです。

+ スケーラブルな連合型ソーシャル: AT Protocolを使用している任意のサービス同士でやり取りが可能です。しかしながらローカルに閉じた会話ではなく、従来のような自然にグローバルな会話ができることを目指しています。
+ アルゴリズムの選択: オープンマーケットのアルゴリズムを任意に選ぶことで、世界の見え方を選ぶことができます。
+ ポータブルアカウント: ナンバーポータビリティのように、コンテンツ・フォロワー・IDを失わずに移動することができます。
+ トラスト: オープンなネットワークを構築し、透明で検証可能なシステムと、監査可能な仕組み・不満があれば乗り換えができるようにします。
+ 相互運用性: Lexicon(スキーマ)を用いて相互運用可能なAPIベースでの通信を実現します。
+ パフォーマンス: パフォーマンスを度外視しない高速性を重視した構造を作成します。

BlueSkyはAT Protocolにおけるアプリケーションであり、WWWにおけるブラウザのような立ち位置です。
新しいソーシャルアプリを作りたい場合、AT Protocolでのソーシャルグラフをそのまま活用できます。
また、サービスを跨いで関係性を保つことができるメールのようなプロトコルを目指しています。

APIやプロトコルは公開されているため、自分好みのクライアントを作ることができます。
また、自分のサーバーを立てることができます。
表示方法やモデレーションが気に入らない場合、サービスを引っ越したり、フィードやモデレータを変更することもできます。

BlueSkyは2019年にTwitter社で発表され、スタートしたコミュニティであり、また2021年末にTwitterから資金提供され設立された組織(Bluesky PBLCC)であり、プロジェクトです。
連合型と、P2P型のアーキテクチャの長所を合わせ、オープンなソーシャル環境を作るために開発が始まりました。

自己認証型ソーシャルプロトコルを採用し、公開鍵と暗号ハッシュを用いてデータが参照されるようにすることで、データそのものを信頼できるようにします。
これにより、ポータビリティ、ストアアンドフォワード・キャッシュによるスケーラビリティ、信頼性の確保を実現するものです。

https://blueskyweb.xyz/blog/2-7-2022-overview

https://blueskyweb.xyz/blog/2-28-2022-how-it-started

https://blueskyweb.xyz/blog/3-6-2022-a-self-authenticating-social-protocol

https://blueskyweb.xyz/blog/10-18-2022-the-at-protocol

https://blueskyweb.xyz/blog/3-2-2023-bluesky-beta-app

## DIDとHandleとDID Document (アイデンティティ)

細かい話はこの後の用語集、および公式資料を読んで下さい。

https://atproto.com/guides/identity

https://w3c-ccg.github.io/did-method-web/

https://identity.foundation/

下記も参考になります。

https://github.com/ngerakines/atproto-rs/blob/main/QUESTIONS.md

https://qiita.com/kazuhideYS/items/2f533bf14e8587c7c131

### DID
DIDは、BlueSky上での**貴方を表す分散型ID**です。
アプリケーションはあなたのことをこの形式で扱います。フォロー関係などもこのIDで扱われます。
**永続的であり、基本的に一切変化しません。変化した場合は別人です。**

DID:PLCでは、これはデータリポジトリのハッシュ(つまり貴方のデータそのもの)になります。
DID:Webでは、これはあなたのドメインです。

以下のような形をしています。

```
did:plc:ma37ez4i3gmwkvwpytsqeepp
at://did:plc:ma37ez4i3gmwkvwpytsqeepp

did:web:gpsnmeajp.achetaria.com
at://did:web:gpsnmeajp.achetaria.com
```

### Handle
Handleは、BlueSky上で貴方に容易にたどり着けるためのユーザー名です。**変更可能です**。
これは、他人に教えたりする場合に使う名前であり、ドメインへの所属を示すものでもあります。

・ホスティングサービスが提供する名前
・ドメインにより提供される名前
の2種類があります。

DIDを解決するために使用する名前であり、これ自体をアプリケーションが記憶・処理するべきものではありません。
**ただし、所属PDSの認証にはHandleとパスワードの組み合わせが必要であり、このHandleはdidでは代用できません。**

ホスティングサービスが提供する名前は、ホスティングサービスが許す限り変更できます。
ドメインにより提供される名前は、DNSレコードのTXTにdid:plcを記述することによってドメインの所有(および所属)を証明することで利用可能です。

以下のような形をしています。

```
@gpsnmeajp.bsky.social
at://gpsnmeajp.bsky.social

@gpsnmeajp.achetaria.com
at://gpsnmeajp.achetaria.com
```

**注意: Handleは変更すると、変更元が開放され他の人が使うことができるようになる(=同じHandleでも対象が変わることがある)性質を持ちます。**

具体例: gpsnmeajp.bsky.socialの人が、gpsnmeajp.achetaria.comにHandleを変更したので、gpsnmeajp.bsky.socialが開放される。
そのため、別の人がgpsnmeajp.bsky.socialを取得した。という事が起きます。

https://scrapbox.io/Bluesky/%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E3%83%8F%E3%83%B3%E3%83%89%E3%83%AB%E3%81%A8%E3%81%97%E3%81%A6%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B

### DID Document
DID Documentは、ホスティングサービスや、ユーザーの署名を検証するための公開鍵、その他DIDに紐づく様々な情報を格納するドキュメント(あるいはjsonファイル)です。

DID:PLCを使用する場合は、ホスティングサービスが所有します。
DID:Webを使用する場合は、/.well-known/did.jsonに配置されたjsonです。(例外あり)

### 関係性

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/cf58e77f-777c-8b03-b419-dadea1fa1386.png)

## 解決の流れ

### Handleの解決(DIDの取得)
まず、Handleがわかっている場合、そこからDIDを取得します。
取得方法のひとつはPDSに問い合わせること。(なおDIDで問い合わせても同じ結果が帰る)

```
https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=gpsnmeajp.achetaria.com
https://boobee.blue/xrpc/com.atproto.identity.resolveHandle?handle=gpsnmeajp.achetaria.com

または (所属ユーザーのみ。DID Document含む全部帰ってくる)
https://bsky.social/xrpc/com.atproto.repo.describeRepo?repo=gpsnmeajp.bsky.social
https://bsky.social/xrpc/com.atproto.repo.describeRepo?repo=did:plc:tdtkywxbgzdblalzur6eeqlv
https://boobee.blue/xrpc/com.atproto.repo.describeRepo?repo=gpsnmeajp.boobee.blue
https://boobee.blue/xrpc/com.atproto.repo.describeRepo?repo=did:plc:4xav2b3xeqcctyj3m3nlbgtk

または (DIDとプロフィールが帰ってくる。認証が必要)
https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=gpsnmeajp.bsky.social
https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=did:plc:tdtkywxbgzdblalzur6eeqlv
https://boobee.blue/xrpc/app.bsky.actor.getProfile?actor=gpsnmeajp.boobee.blue
https://boobee.blue/xrpc/app.bsky.actor.getProfile?actor=did:plc:4xav2b3xeqcctyj3m3nlbgtk
```

相手がカスタムドメインの場合、_atprotoのサブドメインのDNSレコードのTXTに以下のように記載があるのでそこから知ることもできる。

```
did=did:plc:tdtkywxbgzdblalzur6eeqlv
```

下記の形式でHTTPSで取得できる方法も検討されている模様？**(未実装?あるいは検討中?)** 
(内容はDNSレコードと同じくdid:plcに紐づくよう)

```
https://gpsnmeajp.achetaria.com/.well-known/_atproto.txt
```

### DIDの解決(DID Documentの取得)
DIDからDID Documentを取得します。
※一般的なアプリケーションでは、app.bsky.actor.getProfileで十分な情報が得られるはずです。
　殆どの場合これはPDSの役割のはずです。(PDSはエージェントとして動作することが期待されるため)

ひとつは、plc.directoryを使います。

https://github.com/bluesky-social/atproto/blob/5b20053e36b53ebd868badc93034622f5770f9b0/packages/did-resolver/src/plc-resolver.ts#L30

DNSサーバーに相当する存在であり、現状ハードコーディングされています。
これにより、未知のサーバーに所属している場合でも解決できるようになります。
(将来的にはコンソーシアムで運営するとのこと)

```
gpsnmeajp.achetaria.com
正式なDID Document形式
https://plc.directory/did:plc:ma37ez4i3gmwkvwpytsqeepp
生形式
https://plc.directory/did:plc:ma37ez4i3gmwkvwpytsqeepp/data
操作ログ
https://plc.directory/did:plc:ma37ez4i3gmwkvwpytsqeepp/log
(最新の)監査ログ
https://plc.directory/did:plc:ma37ez4i3gmwkvwpytsqeepp/log/audit
最新のログ
https://plc.directory/did:plc:ma37ez4i3gmwkvwpytsqeepp/log/last

gpsnmeajp.bsky.social
https://plc.directory/did:plc:tdtkywxbgzdblalzur6eeqlv
https://plc.directory/did:plc:tdtkywxbgzdblalzur6eeqlv/data
https://plc.directory/did:plc:tdtkywxbgzdblalzur6eeqlv/log
https://plc.directory/did:plc:tdtkywxbgzdblalzur6eeqlv/log/audit
https://plc.directory/did:plc:tdtkywxbgzdblalzur6eeqlv/log/last

gpsnmeajp.boobee.blue
https://plc.directory/did:plc:4xav2b3xeqcctyj3m3nlbgtk
https://plc.directory/did:plc:4xav2b3xeqcctyj3m3nlbgtk/data
https://plc.directory/did:plc:4xav2b3xeqcctyj3m3nlbgtk/log
https://plc.directory/did:plc:4xav2b3xeqcctyj3m3nlbgtk/log/audit
https://plc.directory/did:plc:4xav2b3xeqcctyj3m3nlbgtk/log/last

なお全体の変更履歴は以下のように問い合わせることができる(日時を指定しないと先頭から1000件が出てくる)
https://plc.directory/export?after=2023-03-16T00:00:00.000Z

バージョン情報とヘルスチェック
https://plc.directory/_health
```

ひとつは、PDSに問い合わせることです。(所属しているユーザーのみ)

```
https://bsky.social/xrpc/com.atproto.repo.describeRepo?repo=gpsnmeajp.bsky.social
https://boobee.blue/xrpc/com.atproto.repo.describeRepo?repo=gpsnmeajp.boobee.blue
```

もうひとつは、did:webを使う方法です。

```
https://gpsnmeajp.achetaria.com/.well-known/did.json
```

https://github.com/bluesky-social/atproto/blob/5b20053e36b53ebd868badc93034622f5770f9b0/packages/did-resolver/src/web-resolver.ts#L12

### アクセス
DID Documentがあれば、Handleや、公開鍵、DID、PDSのアドレスがわかるので、検証したりアクセスしたりできるようになります。

```json
{
	"@context": [
		"https://www.w3.org/ns/did/v1",
		"https://w3id.org/security/suites/secp256k1-2019/v1"
	],
	"id": "did:plc:tdtkywxbgzdblalzur6eeqlv",
	"alsoKnownAs": [
		"at://gpsnmeajp.bsky.social"
	],
	"verificationMethod": [
		{
			"id": "#atproto",
			"type": "EcdsaSecp256k1VerificationKey2019",
			"controller": "did:plc:tdtkywxbgzdblalzur6eeqlv",
			"publicKeyMultibase": "zQYEBzXeuTM9UR3rfvNag6L3RNAs5pQZyYPsomTsgQhsxLdEgCrPTLgFna8yqCnxPpNT7DBk6Ym3dgPKNu86vt9GR"
		}
	],
	"service": [
		{
			"id": "#atproto_pds",
			"type": "AtprotoPersonalDataServer",
			"serviceEndpoint": "https://bsky.social"
		}
	]
}
```

logの抜粋。あるタイミングで形式が変更されたようです。(新しいアカウントは下の方の形式しかありません。)
比較してみると、rotationKeysが署名鍵と回復鍵、verificationMethodsが署名鍵のようです。

```json
    {
        "sig": "tYA3niRLOB6NuzYDhCqiEiwIRUBJuS5sJw126_vvOjcHC3VzpOb_dUCWP0wjsFsQ-TKIo81Asfd0qRZ5X0w8cw",
        "prev": null,
        "type": "create",
        "handle": "gpsnmeajp.bsky.social",
        "service": "https://bsky.social",
        "signingKey": "did:key:zQ3shP5TBe1sQfSttXty15FAEHV1DZgcxRZNxvEWnPfLFwLxJ",
        "recoveryKey": "did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg"
    },
    {
        "sig": "0klAI1KcDP62fAEJJFes0ytfUm29kbP7PipnhvgubG1AzrUVoVaGnMtMywfyFioJItH35vJtjiJS9F6S2IttXg",
        "prev": "bafyreidag7zgpcgztfsvnt6e4ubbd35f4mirzhovdxh7grmstwbvqrqd2i",
        "type": "plc_operation",
        "services": {
            "atproto_pds": {
                "type": "AtprotoPersonalDataServer",
                "endpoint": "https://bsky.social"
            }
        },
        "alsoKnownAs": [
            "at://gpsnmeajp.achetaria.com"
        ],
        "rotationKeys": [
            "did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg",
            "did:key:zQ3shP5TBe1sQfSttXty15FAEHV1DZgcxRZNxvEWnPfLFwLxJ"
        ],
        "verificationMethods": {
            "atproto": "did:key:zQ3shP5TBe1sQfSttXty15FAEHV1DZgcxRZNxvEWnPfLFwLxJ"
        }
    },
```

## AT Protocolの登場人物(用語集)
### DID/ユーザー識別子 あるいは リポジトリ識別子

+ DID (Decentralized Identifier - 分散識別子/分権識別子/非中央集権型識別子)
W3Cの定義する識別子。AT Protocolではユーザーの **永続的なID** として使用する。リポジトリの識別子でもある。
人や組織、モノやその他なんでも識別したいもの(これをDID Subject(対象?)と言う)に割り振るグローバルにユニーク(唯一性のある)IDだが、従来のIDとは異なり集中管理を前提としていない。
UUIDとは異なり、公開鍵暗号/公開鍵署名の仕組みを用いて検証が可能である。
殆どの場合、分散型台帳技術(DLT:ブロックチェーン等)あるいはその他の分散型ネットワークを使う(AT Protocolのように)。

以下のような形をしている
```
did:example:11111111111111111111111111111
did:メソッド:メソッド特有の識別子
```

以下のような関係性を持つ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/627031d0-c7e8-88b0-979a-0b67a3707190.png)

https://www.publickey1.jp/blog/22/w3ciddecentralized_identifiers_dids.html

https://qiita.com/kazuhideYS/items/2f533bf14e8587c7c131

+ DID URL
DIDを含むURLで、DID Subject(対象)の情報や、DID Documentの情報、あるいは関連する外部リソースの情報を指す。クエリを含むこともできる。

+ DID Subject
人や組織、モノやその他なんでも識別したい対象もののこと。DIDが割り振られる対象。
AT Protocolではユーザのこと。
もっと言えば公開鍵で証明されるユーザのこと。

+ DID Document
DID Subjectと他のものの関係性を説明・証明するもの。JSONだったりバイナリだったりする。
有効期間中は1つのDIDを指し続ける。公開鍵やSubjectの認証方法なども提供する。X509証明書に相当する？役割をする。
DID Controllerのみが変更する権限を持つ。

+ DID Controller
DID Documentに変更を加える能力を持つ存在。すなわち、DIDに対する全権利を保持する存在。
1つのDID Documentには複数のDID Controllerが存在しうる。DID Subjectと同一の可能性がある。
AT Protocolにおいては(おそらく)ユーザ自身のこと。
もっと言えば署名キー・回復キーをきちんと管理できているユーザー自身のこと。

+ DID Delegate
DID Documentにもとづき、DID Controllerによって部分的にDIDに関連づく権限を利用許可(委譲)されている存在。

+ DID resolver / DID resolution
DIDを入力と適切な情報を入力すると、DID Documentと追加データを出力する存在(システム)およびその行為

+ DID URL dereferencer / DID URL dereference
DID URLまたはDID Documentに対して、リソース取得先を出力する存在(システム)およびその行為
リソースとしては、DID Documentと追加データであったり、その他のDID Document内の情報であったり、DID Documentに記載されている外部リソースだったりする．

### AT Protocol (スモールワールド)
+ Handle (DNS Name)
AT Protocol内で使われる分かりやすいサービス固有のユーザー識別子であり、アプリケーションが解決のために最初にアクセスする先となる。
ユーザーを探すのに使用できる分かりやすい識別子である。**永続性はない**。
アプリケーションはここからDIDに解決し、DIDを正規の識別子として使用する。
そしてDIDから公開鍵やDID Documentに解決する。

※ハンドルネームはホスティングサービスに依存するため、引っ越しで変わりうる。
　DIDはポータブルであり引っ越しても変化しない。

+ did:plc
DIDを公開・解決するためのAT Protocol独自の仕組み。
一時的な仕組みであり、今後数年以内に置き換えられる予定のためPlaceholderという名前がついている。

このDIDの識別子は、署名されたデータリポジトリの最初の操作のSHA256ハッシュのBASE32エンコードの24文字切り捨てであり、つまり生成時から変更を追跡するためのハッシュとなっている。

既存のDID提供方法では目的を達成できないためAT Protocol独自で用意したものであり、DID Documentには最小限かつ独自の要素を含んでいる。

具体的には

```
署名キー
回復キー
ユーザー名
PDSアドレス
```

のみを保持する。

より詳しくは

https://zenn.dev/teatwo/articles/cc08f5f9de9c55


+ did:web
DIDを実用上立ち上げるために、Webドメインの信用を利用したDID提供法およびそれ自体に依るDID。
ホストまたはドメインであり、TLS保護されている必要がある。
/.well-known/did.jsonに配置されたjsonで、DID Documentを提供する。(W3Cベース)
あるいは、
/.well-known/_atproto.txtに配置されたjsonで、DID PLCを提供する。(ATP独自)

did.jsonの方は、NostrのNIP-05に似ているがより密に結合されている。(あとからドメインとデータを切り離せない)
_atproto.txtは、DIDを提供するための仕組みのため、比較的疎結合。(あとから切り離し可能)

※did.jsonの場合、did:plcと違ってデータリポジトリのハッシュに紐づかないけどどうするんだろう？
 → DID Documentで紐づけされる。

https://w3c-ccg.github.io/did-method-web/

+ 署名キー
AT Protocolにて署名されたデータリポジトリに書き込むために必要な秘密鍵。
あるいは、DID Documentそのものへの書き込みに必要な秘密鍵。
Nostrで言えば秘密鍵に相当する。基本的にPDSに委託され、ユーザー自身が持つわけではない。

+ 回復キー
AT Protocolにて署名されたデータリポジトリのDID Documentそのものへの書き込みに使用できる必要な秘密鍵。
署名キーのように使用することはできないが、72時間以内の(DID Documentの)履歴の上書きという特別な機能を提供する。(MSTの)
これにより、悪意のある管理者や悪意のある人間に署名キーが渡ったときにも、キーのローテーションを可能にする。
基本的にPDSに委託されず、ユーザー自身が保持する。(紙などで)

また、これによりPDSがサービスを突然閉じたり凍結したりしても、回復キーで新しくキーを生成し、別のPDSにDID Documentを向け直して(PDSアドレスを書き換えて)更新することで、元のPDSの同意を得ることなく引っ越すことができます。

※現在のBlueSkyには回復キーを取り出す手段がないようにみえる。(というかPDSで統一されているっぽい)

※サービスダウン引っ越しの際、新しいDID Documentの場所をフォロワーはどうやって知るのか？Handleは無効になると思う。did:webなら良いが。
→ (追記)DID DocumentはPDSから独立したplc.directoryに保存される。　
　plc.directory を使うことでDIDからDID Documentを取得して新しい場所を知ることができる。

+ PDS パーソナルデータサーバー
スモールワールドネットワーキングを実現する要であり、スピーチ層を構成する。
またデータの保存・ユーザーの所属・フェデレーション(連合)の構成を実現する。
Mastodon等でのインスタンスに相当する存在である。
ユーザーの署名秘密鍵を預かる。
投稿や閲覧のためのAPIの提供を行う。
検索はクローリングインデクサーとの仲介で実現する。
データの保存のため、各ユーザごとの署名されたデータリポジトリを内包する。

+ 署名されたデータリポジトリ
Gitのようにハッシュの連鎖で表す決定論的に決まるハッシュ木構造 MST(Merkle Search Trees)によって保存されるデータ集合体。
1ユーザごとに1リポジトリが作成される。did:plcの識別子はこのリポジトリの最初の操作を表すSHA256となっている。
リポジトリにコミットするには署名が必要であり、これがDID Documentの公開鍵に基づくため本人の投稿であることが検証できる。
コミットの際にはルートノードが生成され、それが前のコミットを示すため、更新履歴の連鎖となる。
IPLD形式とのこと。PDSはこれを保持する一般的な存在だが、必ずしもPDSのみが配信するものではなく他のものでも良い。

https://ipld.io/

+ スモールワールドネットワーキング
投稿・メンション・DMなど特定のユーザーレベルの対人アクティビティイベントと、その関係性によるイベント配送

+ スピーチレイヤー
発言層。権限を分散し、誰でも発言できるようにすることを前提とする。

### AT Protocol(ビッグワールド)
+ クローリングインデクサー
大規模統計(いいね数の集計や、再投稿数の集計、フォロワー)、おすすめコンテンツ、おすすめユーザーなどアルゴリズム的選出や、ユーザー検索などを提供する存在。
検索エンジンに相当する。
これらをPDSにやらせると負荷が高いためスケーリングに問題が出る。
また、ユーザーが望まないアルゴリズムが使われているときに逃れられないなどの問題もある。
一方で、ないと非常に不便であり、ユーザーを探すことができなくなる。
そのため、PDSとは切り離した存在とし、別でPDSをクロールさせることで、スケーリングの問題を解消する。
なお、検索インターフェースやフィードはPDSから提供される。

+ アルゴリズム
いわゆるおすすめアルゴリズムや、検索アルゴリズム

+ ビッグワールドネットワーキング
クローリングインデクサーの担当する領域のこと。
複数PDSを横断する大きな領域という意味も持つと思われる。

+ リーチレイヤー
到達層。フレキシブルでスケーラブルなことを目指している。
キュレーションやモデレーションは現実的に必要になるが、それはスピーチレイヤーとリーチレイヤーの間で行われる想定である。

### AT Protocol
+ NSID (名前空間ID)
AT Protocol全体で、メソッドやレコードタイプ、その他を識別するための名前。
有効なドメイン名を使う必要があり、逆ドメイン名記法で書く。

以下のようになっている

```
com.atproto.account
app.bsky.actor
```

+ Lexicon (辞書, 語彙)
XRPCメソッドとリポジトリレコードタイプを定義するために用いられるJSONスキーマ。
どんな操作ができるか、どんな記録ができるかを定義したものであり、型定義。ある意味でプロトコルそのものの定義。
NSIDで名前がついており、相互運用性を保証する。
AT ProtocolのサイトにもLexiconが掲載されている。

+ bsky.app
アプリケーションセマンティックを担当する。BlueSky(SNS)として機能するための仕様やプロトコル
フィードやフォロー関係性、通知などを定義する。

+ @ Protocol (AT Protocol / Authenticated Transfer Protocol)
コアネットワークを担当する。相互通信を実現するための仕様やプロトコル。
アカウントやデータ保存、同期などを定義する。

+ XRPC
HTTPSの軽いラッパーであり、汎用通信レイヤー。
GET/POSTで通信する。

# AT Protocolの仕組み
TwitterみたいなSNSを作ることを目的としています。
連合分散型(非中央集権/分権型)のサーバー・クライアントモデルです。

Mastodon等でいうところのサーバー(インスタンス)のことを、PDS(個人データストア)と言います。

PDS同士は連合するため、やり取りが可能になることが期待されています。**(未実装)**
連合にはActivityPubの代わりに、ATProtocolが使用されます。
PDSとクライアントの間の通信にも、ATProtocolが使用されます。

ブロックチェーンは使用していません。

## ActivityPubによるFederationと何が違うのか？ (Mastodon、Misskeyとかとの違いは？)
**アカウントポータビリティ**, **スケーラビリティ**　この2点です。

### アカウントポータビリティ

従来のActivityPub連合型のシステムは、分権されていることによって所属の自由が生まれましたが、
サーバーの突然の管理放棄や、ダウン、管理者の方針変更などによってアカウント閉じ込めが発生します。

これが発生してしまうと、Mastodon等ではアカウントやフォロー関係、今までの投稿は捨てることになります。
また、サーバーが生きていれば引っ越し機能が使え、フォロワーを引っ越させることができますが、投稿は移行できません。

また、悪意のある管理者によってアカウントが乗っ取られる可能性もあります。

AT Protocolでは、
+ 永続的なDIDによるフォロー関係の維持 **(未実装?)**
+ 回復キーによるキーローテーション **(未実装?)**
+ クライアントのローカルリポジトリへのバックアップによる投稿含めた引っ越し **(未実装?)**
+ 公開鍵署名による保証

により、これらの問題を解決します。**(未実装?)**

**※現在、署名鍵も回復鍵も同一PDSでは全員同じになっているようです。また取り出す手段もありません。(暫定実装のため?)**

### スケーラビリティとユーザー到達制
AT Protocolではクローリングインデクサーというものが定義されています。

これは、大規模統計(いいね数の集計や、再投稿数の集計、フォロワー)、おすすめコンテンツ、おすすめユーザーなどアルゴリズム的選出や、ユーザー検索などを提供する存在であり、一般的に検索エンジンに相当するものです。

これらをPDSにやらせると負荷が高いためスケーリングに問題が出ます。
また、ユーザーが望まないアルゴリズムが使われているときに逃れられないなどの問題もあります。

一方で、ないと非常に不便であり、ユーザーを探せなかったり、検索がまともに機能しなかったりします。

そのため、PDSとは切り離した存在とし、別でPDSをクロールさせることで、スケーリングの問題を解消しながら到達性を確保しようというものです。**(未実装?)**

なお、検索インターフェースやフィードはPDSから提供されます。**(未実装?)**

## Nostrの何を解決し、何を解決しないのか？
Nostrは、公開鍵対が唯一をユーザー証明とすることで、アカウントのポータビリティを実現しました。
投稿は持ち運べませんが、接続するリレーを切り替えることで、フォロー関係を維持したまま一瞬で引っ越しが完了します。

また、複数のリレーに投稿することで多重化されており、サーバーひとつが落ちてもほとんど影響を受けないような仕組みになっています。
電子署名を使用することで、究極的にサーバーを信用しない仕組みができました。

一方で、

+ リレー一つ一つの責任が軽い
+ データの保持期間が不明確
+ 所属が不明確

など様々な問題点もあります。これらはトレードオフです。

AT Protcolでは、公開鍵対によってポータビリティを実現する機能と、Mastodon同様のサーバー所有によるデータ保持の両方を実現しようとしているということもできるかもしれません。

また、Nostrと違って秘密鍵や公開鍵が表に出てきません。API利用する際にもユーザー名とパスワードを使ってアクセスすることになります。

もちろんPDSの責任で投稿を削除できますし、画像の投稿もできますし、パスワードを忘れても大丈夫です。Nostrほどリテラシーが必要ありません。
もちろんPDSの責任でスパム対策もできますし、凍結やBANも発生します。

# 連合は？

**2023/05/10追記**
連合のアーキテクチャーに関する情報が公開されました。

https://blueskyweb.xyz/blog/5-5-2023-federation-architecture

+ パーソナル データ サーバー (PDS)
+ ビッググラフサービス(BGS)
+ アプリビュー

で構成されます。
PDSはエージェントして動作し、ユーザーのデータをホストし、アカウントを実現し、クライアントと対話します。(個人や小規模組織でも運用できるでしょう)

BGSは、PDSのデータをクロール・取得し、巨大な生データストリームとして提供する強力なリレーにあたります。(かなりのリソースを必要とし、大型資本や組織でないと運用できないほど重いものになると思います)

アプリビューは、BGSからのデータを取り込み、キュレーションや統計を実施します。

これらに更に、ラベルによるモデレーションなどが行われます。
(リプライなどはPDS同士で直接やり取りされる？ような気がしますが画像に記載なし)

このような構造の分離をすることで、個人のデータを維持保全することと、ソーシャルメディアとしての閲覧性・発見性を両立しようとしています。

画像を以下に引用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/fc54805b-6002-4a65-5066-20ee0603b468.png)


**以下は初稿の内容です***

リモートフォローに相当する仕組みはまだ見つけられていません。
ただ、全体的に「能動的に通知する」という指向ではないように見えます。
必要なタイミングでデータ同期をする仕組みなのかもしれません。

→ com.atproto.sync.subscribeReposを使うと、リアルタイムに取得することもできるようです。

データの同期には、com.atproto.sync Lexicon を使うように見えます。
指定したdidのリポジトリを返します。CIDを指定すれば差分も返してくれます。
これはおそらく、ローカルのリポジトリとの同期にも使用できそうです。

https://github.com/bluesky-social/atproto/blob/5b20053e36b53ebd868badc93034622f5770f9b0/packages/pds/src/api/com/atproto/sync/getRepo.ts#L8

形式はapplication/vnd.ipld.car形式です。IPLDのアーカイブ形式(DAG-CBORによるヘッダ + データ)。

https://ipld.io/specs/transport/car/carv1/

https://qiita.com/yoshii0110/items/d975610b4173043c77ca

https://ipld.io/specs/codecs/dag-cbor/spec/

現状でも、didさえ取得できてしまえば、所属PDSからリポジトリを取得してデータを読むことが可能です。

PDSは、所属外のユーザーの情報が欲しかったら、単にそのユーザーが所属するPDSに対してgetRepoするだけで取れますね。
差分が欲しければ最後のコミットのCIDをfromにつけて投げれば差分が届くことになります。

```
誰かの投稿を読むのには一見PDSの認証が必要なのだが
https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed?author=gpsnmeajp.achetaria.com
https://boobee.blue/xrpc/app.bsky.feed.getAuthorFeed?author=gpsnmeajp.boobee.blue

データリポジトリ(投稿その他含む活動のすべて)は特に認証なく取得できる
https://bsky.social/xrpc/com.atproto.sync.getRepo?did=did:plc:ma37ez4i3gmwkvwpytsqeepp
https://boobee.blue/xrpc/com.atproto.sync.getRepo?did=did:plc:4xav2b3xeqcctyj3m3nlbgtk
```

### 黒歴史抽出ツール
Handleを指定するとテキスト投稿を全部抽出してテキストファイルに出力するNodeJS用スクリプト。
初回の投稿から現在の投稿まで全部出るはずです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/a2bed179-c48e-1c38-f854-e60479f1eb09.png)

https://gist.github.com/gpsnmeajp/c549330dfdbc0a11643b0f0a52f5aa53

### com.atproto.sync.getRepo 生データ全ダンプコード

https://gist.github.com/gpsnmeajp/3038f4900b338cba99082dea59377e84

# アプリを作るには
ドキュメント化されていない情報がMatrixのBluesky Devにあります。要チェック。

https://twitter.com/bluesky/status/1521940679835881472?s=20

投稿やフォロー、リポスト、タイムラインの取得などは以下を参照してください。

https://atproto.com/guides/applications

プロトコル仕様は、Lexiconを参照してください。

https://github.com/bluesky-social/atproto/tree/main/lexicons

サーバー等のソースコードは以下のpackagesフォルダを参照してください。

https://github.com/bluesky-social/atproto

下記は参考にはなりますが、本実装ではないようです。

https://github.com/bluesky-social/indigo

https://github.com/bluesky-social/did-method-plc

その他の情報は、Scrapboxを見ると何かあるかもしれません。

https://scrapbox.io/Bluesky/

# 現在利用可能なサーバー
連合機能が現時点で未実装(?)のため、それぞれで独立したタイムラインになります。

+ bsky.social (公式)
+ boobee.blue (有志サーバー)

※アプリまたはWebアプリのサーバー欄に入力してアクセスしてください。ブラウザでアクセスしても使えません。

# データ保持

```
最後に誰がデータ保持の責任を持てるのか？
Twitterは管理者が持つ。
ActivityPubは各インスタンスの管理者が持つ。
Nostrは多分誰も持たないことにした。
ATProtocolは最後にユーザーに持たせることにした。
```

# ADX時代の資料
実験プロトコル自体のアーキテクチャ構想が書かれています。現在のドキュメントに欠けている情報や思想が書かれているようです。
(Bluesky/ATProtocol 勉強会#0 yamartenさんの発表で知りました。)

+ より公開鍵ベースの自己責任に近いシステムだったようです。
+ 子鍵によるパーミッションがあったようです
+ DIDコンソーシアムというものが書かれています(Matrixにて、plc.directoryがコンソーシアムで運営されると記載があったので同等かもしれません)
+ 連合がプッシュ/プル、リポジトリの同期様々な形で想定されていること書かれています。
+ リポジトリをクライアントが直接読み書きすることが想定されていたようです。
+ フルクライアント(PDS同等)、ライトクライアント、デリゲータクライアント(APIクライアント)などが定義されています。
+ モデレーションの仕組み(ラベリングとアクションの分離)
+ クローリングインデクサーの目的と仕組み(ActivityPubはローカルしか提供しない問題)
+ 削除やマージの考え方

https://github.com/bluesky-social/atproto/blob/9e57fafbfc5e22fe9297ada87b24f3461a6837e2/architecture.md

https://fission.codes/blog/auth-without-backend/

# APIの叩き方
REST Client形式で書きます。

https://qiita.com/toshi0607/items/c4440d3fbfa72eac840c

### 認証する。accessJwtが返ってくるのでメモする。

```http
POST https://bsky.social/xrpc/com.atproto.server.createSession HTTP/1.1
content-type: application/json

{
    "identifier": "gpsnmeajp.achetaria.com",
    "password": "パスワード"
}
```

### プロフィールを取得する

```http
GET https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=gpsnmeajp.bsky.social HTTP/1.1
Authorization: Bearer xXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

```

# 現時点のAPI(Lexicon)一覧

```

管理者操作(ATProtocol)
com.atproto.admin.defs
com.atproto.admin.disableAccountInvites
com.atproto.admin.disableInviteCodes
com.atproto.admin.enableAccountInvites
com.atproto.admin.getInviteCodes
com.atproto.admin.getModerationAction
com.atproto.admin.getModerationActions
com.atproto.admin.getModerationReport
com.atproto.admin.getModerationReports
com.atproto.admin.getRecord
com.atproto.admin.getRepo
com.atproto.admin.resolveModerationReports
com.atproto.admin.reverseModerationAction
com.atproto.admin.searchRepos
com.atproto.admin.takeModerationAction
com.atproto.admin.updateAccountEmail
com.atproto.admin.updateAccountHandle

ハンドル(ATProtocol)
com.atproto.identity.resolveHandle
com.atproto.identity.updateHandle

リポジトリ読み書き(ATProtocol) / blobアップロード(ATProtocol)
com.atproto.repo.applyWrites
com.atproto.repo.createRecord
com.atproto.repo.deleteRecord
com.atproto.repo.describeRepo
com.atproto.repo.getRecord
com.atproto.repo.listRecords
com.atproto.repo.putRecord
com.atproto.repo.rebaseRepo
com.atproto.repo.strongRef
com.atproto.repo.uploadBlob

モデレーション(ATProtocol)
com.atproto.moderation.createReport
com.atproto.moderation.defs

ラベル(ATProtocol)
com.atproto.label.defs
com.atproto.label.queryLabels
com.atproto.label.subscribeLabels

サーバー情報(ATProtocol) / アカウント(ATProtocol) / 認証セッション(ATProtocol)
com.atproto.server.createAccount
com.atproto.server.createAppPassword
com.atproto.server.createInviteCode
com.atproto.server.createInviteCodes
com.atproto.server.createSession
com.atproto.server.defs
com.atproto.server.deleteAccount
com.atproto.server.deleteSession
com.atproto.server.describeServer
com.atproto.server.getAccountInviteCodes
com.atproto.server.getSession
com.atproto.server.listAppPasswords
com.atproto.server.refreshSession
com.atproto.server.requestAccountDelete
com.atproto.server.requestPasswordReset
com.atproto.server.resetPassword
com.atproto.server.revokeAppPassword

連合・同期・リポジトリ取得(ATProtocol)
com.atproto.sync.getBlob
com.atproto.sync.getBlocks
com.atproto.sync.getCheckout
com.atproto.sync.getCommitPath
com.atproto.sync.getHead
com.atproto.sync.getRecord
com.atproto.sync.getRepo
com.atproto.sync.listBlobs
com.atproto.sync.listRepos
com.atproto.sync.notifyOfUpdate
com.atproto.sync.requestCrawl
com.atproto.sync.subscribeRepos

ユーザー情報(Bluesky)
app.bsky.actor.defs
app.bsky.actor.getProfile
app.bsky.actor.getProfiles
app.bsky.actor.getSuggestions
app.bsky.actor.profile
app.bsky.actor.searchActors
app.bsky.actor.searchActorsTypeahead

埋め込み情報(Bluesky)
app.bsky.embed.external
app.bsky.embed.images
app.bsky.embed.record
app.bsky.embed.recordWithMedia

フィード・タイムライン・投稿・投票(Bluesky)
app.bsky.feed.defs
app.bsky.feed.getAuthorFeed
app.bsky.feed.getLikes
app.bsky.feed.getPostThread
app.bsky.feed.getPosts
app.bsky.feed.getRepostedBy
app.bsky.feed.getTimeline
app.bsky.feed.like
app.bsky.feed.post
app.bsky.feed.repost

フォロー関係(Bluesky)
app.bsky.graph.block
app.bsky.graph.follow
app.bsky.graph.getBlocks
app.bsky.graph.getFollowers
app.bsky.graph.getFollows
app.bsky.graph.getMutes
app.bsky.graph.muteActor
app.bsky.graph.unmuteActor

通知(Bluesky)
app.bsky.notification.getUnreadCount
app.bsky.notification.listNotifications
app.bsky.notification.updateSeen

その他(Bluesky)
app.bsky.richtext.facet
app.bsky.unspecced.getPopular

```