設計と実装

Pixelmine はこうして作られている。

アプリの下には、それぞれが明確な一つの役割を担う少数の部品があります。すべての暗号化を行うアプリ、それを保存するノードのネットワーク、全体をつなぐ軽量なサービス、そしてリアルタイム動画のための独立した経路です。あえて分離されたこれらが組み合わさることで、あなたのプライベートなコンテンツとそれを読むための鍵の両方を、どの部品も同時には持たない仕組みが生まれます。

システムの全体像

四つの部品、
明確な役割。

各部品はそれぞれ一つの仕事だけを担います。封じられたコンテンツを読めるのはアプリだけであり、それ以外はすべて、保存し、運び、配信するために存在します。プライベートなものは、開くことのできない形のまま扱われます。

アプリ

あなたのデバイス上のアプリは、システム全体の信頼の起点です。鍵を生成して保持し、すべての暗号化と復号をデバイス上で直接行います。プライベートなコンテンツが読める形でサーバーに渡されることはありません。

フィード、チャット、通話、ライブ動画——実際にあなたが使うのはこのアプリです。そして、封じられたデータを読めるコンテンツに戻せるのは、Pixelmine の中でアプリだけです。

鍵を保持デバイス上で暗号化コンテンツを読む

ストレージネットワーク

独立して運用される複数のノードが、ネットワークの記憶として働きます。各ノードは投稿とファイルのコピーを自ら保持し、変更を他のノードへ伝えることで、全員が最新の状態を保ちます。チャットとコミュニティの投稿は、それをホストするノードにとどまります。

ノードは誰でも運用でき、調整サービスに登録します。ノードが保持するプライベートなものはすでに封じられているため、ノードは自身のデータベースに完全にアクセスできても、その内容を読むことなく保存・配信・複製します。公開投稿は見られることを前提としているため、そのまま公開して配信します。

暗号化データを保存ピアへ複製プライベートな内容は読めない

調整サービス

一つの軽量なサービスがネットワーク全体をつなぎます。ノードの一覧を管理し、アプリの接続時にアカウントの鍵を確認し、チャットのイベントや通知を中継し、グループ招待のための封じられた鍵を受け渡します。

このサービスはあえて小さく保たれており、メッセージや投稿の読める内容を持つことはありません。ただし、プロフィール項目やグループ名など一部のアカウント情報は保持しており、封じられたグループ招待は、招待された人が受け取ると削除されます。

ノードを登録封じられた鍵を配送メッセージの内容は持たない

ライブメディア経路

ライブ配信と通話はリアルタイムで届く必要があるため、遅延を可能な限り抑えるよう調整された独自の経路を通ります。保存されたコンテンツのある場所とは切り離されています。

1対1の通話は2台の端末の間を直接行き来し、グループ通話は中継サーバーを経由し、ライブ配信は配信者の端末から各視聴者へ送られます。

リアルタイム動画低遅延独立した経路
アイデンティティとアカウント

あなたは鍵そのもの、
データベースの一行ではない。

盗まれるのを待つパスワードはサーバーにありません。そもそもパスワードが存在しないからです。あなたのアイデンティティはあなた自身が持つものであり、公開するものすべてにあなたの署名が付きます。

  • 登録すると、あなただけのものである鍵ファイルを受け取ります。これは、あなたしか知らない 12 語のリカバリーフレーズで開きます。フレーズがなければファイルは役に立ちません。
  • あなたの公開アイデンティティは鍵から導き出されるため、鍵を持たない者があなたになりすますことはできません。
  • パスワードを集めた中央の保管庫が存在しないため、攻撃者が一箇所で破れるようなものはありません。
  • ノードも同じ方法で識別されます。ノードの ID はそのノード自身の鍵から導き出されるため、別のノードになりすますことはできません。表示名は運用者が決めます。
  • トレードオフは現実にあります。あなたの鍵ファイルとフレーズを持つ者は、あなた自身になります。それらを失えばアカウントを失うことになります。誰も代わりに復元することはできないからです。
暗号化のモデル

一度だけ設定する鍵、
そしてメッセージごとの鍵。

投稿ごとに保護を一から用意するのは、遅く無駄も多い方法です。そこで Pixelmine は、負荷の大きい処理を相手ごとに一度だけ行い、その後は個々の投稿やメッセージを、それぞれ専用の軽快な鍵で保護します。

一度だけ確立

相手ごとの共有鍵

誰かと初めてつながるとき——フォローが承認されたり、チャットが始まったりしたとき——あなたたち二つのデバイスは、共有鍵をひそかに取り決めます。この取り決めはその二人につき一度だけ行われ、繰り返す必要はありません。

投稿・メッセージごと

毎回新しい鍵

すべての投稿やメッセージは、それぞれ真新しい鍵で施錠されます。フォロワー限定投稿ではその鍵がフォロワーごとに個別に封じられ、チャットでは会話の共有鍵で封じられます。鍵はコンテンツと一緒に届くため、正しい相手だけが開くことができます。

グループの会話では、誰かが参加または退出するたびに共有鍵が更新されます。内容は封じられていますが、その周りのラベルはそうではありません。誰が会話に属するか、誰が各メッセージを送ったか、誰が読んだかは平文のアカウント ID とともに保存されるため、ノードは内容を知ることなく、メッセージが誰に関わるものかを知ることができます。

相手ごとに一度だけ設定 メッセージごとに新しい鍵 相手に合わせて封じる 将来のコンピューターにも耐える設計
投稿と公開範囲

選べば公開、
標準では封じる。

Pixelmine のすべてが秘密というわけではありません。公開投稿は読まれるためのものです。大切なのは、公開範囲をあなたが選ぶこと。そして、限られた相手に向けたものは封じられ、その相手だけが開けるようになっています。

公開投稿

あえて公開されています。公開投稿は誰に向けたものでもあるため、ネットワークは自由に運び、表示します。それこそが公開で投稿する目的です。

フォロワー限定の投稿

封じられています。一つひとつが専用の鍵で施錠され、その鍵は閲覧を許可されたフォロワーごとに個別に包まれます。

メッセージとグループ

メッセージの内容は常に封じられ、会話に参加している人だけに向けられます。どんな設定であっても、それ以外の誰にも開かれません。

  • 公開範囲は、あなたが投稿した瞬間に決まります。フォロワーを外せば、その人が新しいものを受け取ることはなくなりますが、すでに開けた投稿はその人にとって読める状態のまま残ります。あとから共有を取り消すことは、どんなシステムも本当には約束できないのです。
封じられたフィードを開く

封じられていても、
スクロールは一瞬。

投稿ごとに固有の鍵があるなら、フィードを開くのは、一文字が現れるまでに山のような処理が必要になりそうに思えます。実際はそうではありません。負荷の大きい処理は投稿ごとではなく相手ごとに一度だけ行われ、鍵は1ページ分ずつ届くからです。

  • 投稿者との共有鍵は、その人の投稿を初めて開いたときに計算されます。フォローしている全員の分をあらかじめ用意するわけではありません。
  • これは投稿者ごとに一度だけ行われます。その後は鍵があなたのために保管され、サインインしたどのデバイスでも取り戻せます。
  • フィードの1ページが読み込まれるとき、アプリは投稿ごとに要求するのではなく、そのページ全体の鍵を一度の要求でまとめて求めます。
  • あとは解錠があなたのデバイス上で行う高速なローカル処理となるため、通信路上で読める形のものが一切なかったにもかかわらず、スクロールは滑らかなまま保たれます。
メッセージとチャンネル

内容を封じた
会話。

ダイレクトメッセージとグループチャットは、一つの設計を共有しています。封じられた内容が、会話をホストするノードに、誰が参加しているかを示す平文の記録とともに保存されます。

  • メッセージそのものは封じられています。誰が会話に属するか、各メッセージを誰が送ったか、誰が読んだかは、平文のアカウント ID とともに保存されます。
  • グループチャットでは、誰かが参加または退出するたびに共有鍵が更新されます。そのため、新しく加わった人は自分より前のやり取りを読めず、誰かが退出した後のメッセージには新しい鍵が使われます。
  • 1対1のチャットは、単一の安定した鍵を保ちます。関わるのは常に二人だけで、メンバーが変わることはないからです。
  • 既読の通知や未読の件数は、ノードから見える既読の目印から計算されます。
ファイルとメディア

写真も動画も、
同じ扱い。

メディアはテキストとまったく同じ規則に従います。封じられた投稿に添付されたファイルはその投稿の鍵で施錠され、実際に見る瞬間に、閲覧者のデバイス上でのみ開かれます。

  • ファイルは端末上で一度に封じられます。封じられるのはチャットとフォロワー限定投稿のファイルだけで、公開投稿のメディアは公開されます。
  • ノードは、封じられたこれらのファイルを他の記録とまったく同じように保存し複製します。中身を見ることはできないまま、バイト列を保持します。
  • ファイルは、すべてを前もって解錠するのではなく、たどり着いたときにダウンロードされて開かれます。
  • 運用者はノードのダッシュボード用にストレージ量を設定できますが、ノードはまだそれを厳密な上限として適用していません。
共有ネットワークでの削除

コピーだらけのネットワークから、
どう削除するか。

一つの企業のデータベースでは、単一の所有者が唯一のコピーを管理しているため、削除とは一行が消えることを意味します。独立したノードのネットワークには、そのようなてこはありません。すべてのマシンに手を伸ばして何かを消せる者は誰もいないのです。だからこそ削除は、当然のものと見なすのではなく、設計されなければなりません。

  • 削除はそれ自体が一つの記録です。アカウントが消えたことを示す署名付きの通知であり、他のどの記録ともまったく同じようにネットワークを巡ります。
  • それにはあなたの署名が付いているため、他の誰かがあなたのアカウントの削除を偽造することはできません。そしてノードは、それを自ら検証できます。
  • ノードはそれが広まるにつれて受け取り、そのアカウントのデータを表示しなくなります(消去ではなく非表示)。中央の権威が命令する必要はありません。
  • トレードオフは率直で、本質的なものです。独立したコピーからなるネットワークは削除を広めることはできますが、単一の管理されたデータベースのような完全な消去を約束することはできません。
ライブ動画と通話

リアルタイムは、
独自の経路で。

保存された投稿は、ネットワーク全体に行き渡るまで少し時間がかかっても構いません。ライブ配信や通話はそうはいきません。0.5秒の遅延が、会話になるか混乱になるかの分かれ目です。だからこそリアルタイム動画は、永続性よりも即時性のために作られた、独立した経路を通ります。

できる限り直接に

1対1の通話は2台の端末の間を直接行き来するため、すぐに届くように感じられます。グループ通話は中継サーバーを経由します。通話はエンドツーエンドで暗号化されています。

視聴者へ配信

ライブ配信は配信者の端末から各視聴者へ送られ、その接続は Pixelmine のメディアサーバーを通じて確立されます。

閉じていても着信

着信は、独自の通知システムを通じてあなたの端末に届きます。そのため、アプリが起動しているかどうかに関わらず着信音が鳴ります。

  • ライブ動画は、保管されるのではなくその場で運ばれます。投稿のように保存し複製するのではなく、リアルタイムの経路をたどります。通話はエンドツーエンドで暗号化されますが、ライブ配信は暗号化されません。仕事が違えば、トレードオフも違うのです。
ゴシップと交換

ノードはどう互いを見つけ、
新しいものを交換するか。

ノードは二つの方法で互いを知ります。調整サービスのノード一覧と、各ノードが知っているピアの一覧を互いに共有することです。ノードはそれぞれ自分のタイマーでやり取りを続けます。そのためネットワークは、ある一つのメッセージが適切な瞬間に届くことに頼るのではなく、自ら回復します。

ステップ 01

自分の存在を知らせる

ノードは調整サービスに登録し、数分ごとに、知っているピアへ自分がここにいると伝えます。ピアどうしが一覧を受け渡すため、存在は口づてにも広まります。

ステップ 02

タイマーで照合する

各ノードは1分ごとにピアと照合します。今取りこぼしたメッセージも次の巡回で拾われるため、完璧なタイミングに左右されるものは何もありません。

ステップ 03

変化があれば促す

ノードは新しいものを取り込むと、ピアに次の順番を待たせるのではなく、見に来るよう促すことができます。

ステップ 04

プッシュして、確認する

新しい記録は書き込まれた時点でピアへもプッシュされます。プッシュでもプルでも、ノードは受け入れる前にすべての記録を確認するため、何を保存するかはノード自身が決めます。

ネットワークを同期させ続ける

ノードはどうやって
同じデータに合意するか。

各ノードは同じ暗号化コンテンツのコピーを保持しているため、データベース全体をやり取りせずに同一の状態を保つ方法が必要です。ノードはコンパクトな指紋を比較し、本当の差分だけが残るまで絞り込みを続け、その差分だけを交換します。新しいノードも同じ方法で追いつき、また各ノードは複数のピアと比較し、多数派が持つものを優先します。

ステップ 01

データの指紋を取る

すべての記録は短い指紋を持ち、コレクション全体も一つの指紋を持ちます。それらは、物事が届いた順序が問題にならないように組み合わされます。

ステップ 02

比較して分割する

二つの指紋が異なるとき、そのコレクションの 256 個のバケットの指紋が比較され、二つのノードが食い違う箇所へ素早く絞り込まれます。

ステップ 03

該当する記録を特定する

差のあるグループの中で、個々の指紋を突き合わせ、どの記録が欠けているのかを正確に突き止めます。

ステップ 04

差分だけを交換する

送られるのはその記録だけです。膨大な蓄積を同期しても、実際に変わった分しか動きません。そして各記録は、届いた時点で確認されます。

届いたものを検証する

届いたというだけで
信じられるものは何もない。

見知らぬ相手からデータを受け取るノードは、その言い分をそのまま信じるわけにはいきません。だからこそ、すべての記録は自らを証明しなければなりません。そしてその証明は、誰の権威による裏づけも必要としない何かにたどり着くまで、下へと連鎖していきます。

  • 複製される記録には、その記録自身の指紋に対して作られた、作成者の署名が付いています。たった一文字でも変えれば、署名はもう合わなくなります。
  • 作成者の鍵もまた、鵜呑みにされることはありません。それは、他のすべてと同じようにネットワークを巡ってきた、その作成者自身の記録に由来します。
  • そしてその記録は、自らを証明します。アイデンティティとは、まさにそれ自身の鍵の指紋であるため、自分のものではない鍵を主張することはできません。連鎖は、誰かが信頼しなければならない権威ではなく、自明な何かで終わります。
  • これらのいずれかを満たさない記録は、標準で即座に拒否されます。まず保存してから後で選別するのではありません。
  • そして、ノードがまだ知らない作成者から記録が届いた場合、それは推測で処理されることはありません。いったん取り込まれずに、その作成者自身の記録が追いついたのち、後の巡回で改めて取得されます。
ずれがないことを証明する

コレクションごとの、
一つの指紋。

変更がわずかなら記録を一つずつ比較すれば十分ですが、ノードにはまず、もっと大まかな問いを安価に投げかける方法が必要です。このコレクションは同一なのか、と。そこで、すべてのコレクションが一つの指紋を持ち、ファイルにも独自の指紋があります。

  • 各コレクションはそれぞれの指紋を持ち、その中の何かが変わった瞬間に再計算されます。
  • ファイルは、それ専用の別の指紋で管理されます。
  • ノードは同期の際、まずそれらのコレクションの指紋を比較します。一致すればそのコレクションは同一であり、ほかにすることはありません。
  • 一致しなければ、階層を下りていきます——バケットへ、そして記録へ——すべてを交換することなく、正確な差分が浮かび上がるまで。
ネットワークに加わる

新しいノードはどうオンラインになり、
信頼を得るか。

ノードは誰でも追加できます。新しいノードは調整サービスに登録し、他のノードを見つけ、自己紹介をし、共有された記録(すべてのノードが複製する公開データとフォロワー限定データ)に追いつきます。そして、負荷を分担し始めます。

ステップ 01

見つけて知らせる

新しいノードは登録し、調整サービスと最初のピア一覧を通じて既存のノードを見つけ、自分の存在を知らせます。

ステップ 02

追いつく

同じ指紋の比較を使って共有された記録を埋めていき、欠けているものだけを引き込んで、完全に最新の状態になるまで続けます。

ステップ 03

信頼せず、突き合わせる

ノードは、一つのピアを信じるのではなく、複数と比較して多数派が持つものを優先します。そして、どの記録にも正当な署名が必要です。

ロジックを一歩ずつ

二つのノードの照合、
端から端まで。

どの同期も同じ道筋をたどります。ノードは一つの指紋から始め、どの記録が異なるのかを正確に突き止めるまで絞り込みを続けます。そして、正当な署名の裏づけがないものは、記録に受け入れられることはありません。

二つのノードがコレクションを比較 指紋は一致するか? はい すでに同一——完了 いいえ 256個のバケット指紋を比較 異なるバケットを切り分ける 記録の指紋を比較 欠けているものだけを要求 署名は正当か? いいえ 記録を拒否 はい 保存し、指紋を更新 両ノードが一致
照合ループの一巡
各部品はどう連携するか

一つの投稿を
システムを通して追う。

各部品はそれぞれの持ち場にとどまり、封じられたデータを次から次へと受け渡します。ここでは同じ道のりを、あなたの側からではなく、各構成要素の側から説明します。

ステップ 01

アプリが封じる

あなたのアプリはプライベートなコンテンツを施錠し、その鍵を、受け取るべき相手のために封じます——そのすべてが、何かがデバイスを離れる前に行われます。

ステップ 02

ネットワークが保存する

封じられたコンテンツはストレージネットワークに渡され、そこでノードがそれを保持し、投稿は他のノードへ複製されて利用できる状態に保たれます。

ステップ 03

鍵が届けられる

受信者に必要な鍵は、封じられた状態でノードに保存されます。グループ招待の場合は、調整サービスが封じられた鍵を受け渡し、受け取られたら削除します。

ステップ 04

受信者が開く

受信者それぞれのアプリが、自分の鍵を使ってコンテンツを開きます。その間のどの部品も、読むことのできない封じられた状態のものしか扱っていません。