← 研究を読む

TWO BRAIN RESEARCH · AINTERNET GENESIS · IMPLEMENTATION 0.1

AINET Language / ID / Object ワイヤ仕様1

参照:RFC 8949、RFC 8032、SHA-256。 MUST相当の規則を以下に定める。製品0.1とワイヤ形式1は異なるバージョン番号である。

CBORプロファイル

RFC 8949 §4.2.1 Core Deterministic Encodingを使う。整数・長さは最短表現、mapキーは 符号化したキーのバイト列で辞書順とする。mapキーは非負整数だけを許可する。 整数(64ビット範囲)、byte string、正しいUTF-8 text string、array、map、boolean、nullを許可し、 浮動小数点・tag・未確定長・重複キー・未知のフィールドを拒否する。 nullはローカル管理APIの未使用値など、スキーマが許す場合のみ。公開Objectの配列は空arrayを使う。 最大ネスト16、array最大256要素、map最大64項目。個別スキーマの制限も適用する。 自然言語の正規化は行わない。異なる改行やUnicode列は異なるデータである。

すべての構造は整数キーmapである。下表でoptionalとした項目は、空なら送信しない。 必須項目の欠落、optional項目の不要な空値表現も拒否する。 正準な構造を復号・再符号化したバイト列が元と一致することを確認する。

ID

PUBは生のEd25519公開鍵32バイト、HはSHA-256、hexは小文字・区切りなしとする。

AINET ID = "ainet:node:1:" || hex(H(ASCII("AINET-ID-v1") || 00 || PUB))

ID文字列はUTF-8 text stringで伝送する(0.1では短縮バイナリIDにしない)。 秘密鍵をネットワークに送ってはならない。

libp2p側では同じ公開鍵を標準Ed25519公開鍵protobuf(08 01 12 20 || PUB)にし、 identity multihash(00 24 || protobuf)から標準Peer IDを導出する。 接続登録時にPeer IDから公開鍵を取り出し、AINET IDとの対応を検証する。 Noiseが認証した実際の接続鍵でも同じ検証を行う。名乗りだけで認証しない。

鍵変更は別AINET IDになる。鍵移行・失効・人や企業への身元証明は0.1の対象外。

Manifest

キー 型 意味・制限
0 uint 形式バージョン。1
1 bytes32 Content Hash = SHA-256(元のファイル全体)
2 uint Content Type:1=UTF-8文章、2=PNG、3=JPEG
3 uint 本体の正確なバイト数。種類ごとの上限を適用
4 text Author ID
5 bytes32 Author Public Key。キー4を導出できること
6 uint Created At。正のUnixミリ秒。発行者の申告であり認証された時刻ではない
7 array(text) Provenance。最大16件、各2048バイト。有効なUTF-8。主張として保存
8 array(text) References。最大64件の正しいObject ID
9 uint Access Policy:0=Private(配布不可)、1=Public(明示公開時に配布・再配布可)

全項目必須。Object IDと署名はManifestに含めない。

M = CoreDetCBOR(Manifest)
Object ID = "ainet:object:1:" || hex(H(ASCII("AINET-OBJECT-ID-v1") || 00 || M))
Signature input = ASCII("AINET-OBJECT-SIGN-v1") || 00 || ASCII(Object ID)
Signature = Ed25519.Sign(author_private_key, Signature input)

標準Ed25519の署名であり、Ed25519phではない。固定接頭辞は用途の混同を避けるためのもの。 Recordは{0: Manifest, 1: Object ID(text), 2: Signature(bytes64)}。 受信側は作者IDと鍵の対応、IDの再計算、署名、本体のサイズ・ハッシュ・形式をすべて検証する。 署名が証明するのは鍵の主体と改ざん有無であり、出典の事実性や著作権ではない。

本文の上限と境界

種類 最大バイト数(上限を含む) 追加条件
UTF-8文章 1,048,576(1 MiB) 有効なUTF-8、NULを含まない。空の文章を許可
PNG 16,777,216(16 MiB) 正の幅・高さ、幅×高さ ≤ 16,000,000画素、PNGとして復号可能
JPEG 16,777,216(16 MiB) 正の幅・高さ、幅×高さ ≤ 16,000,000画素、JPEGとして復号可能

例:1,048,576バイトの有効な文章はサイズ条件を満たし、1,048,577バイトは拒否する。 4000×4000画素は画素条件を満たし、4000×4001画素は拒否する。 これらは受理に必要な境界条件であり、署名・ハッシュ・形式の検証も通過する必要がある。 internal/object/object_test.goでは本文変異、文章上限超過、途中で切れたPNG/JPEG、 画素数を偽ったPNGを試験する。上記のすべての境界値を実デコード試験済みとは扱わない。

フレームとEnvelope

libp2pのプロトコル名は/ainet/0.1.0。TCP+Noise+Yamuxを使用する。 制御フレームはuint32 big-endian長 || CBOR Envelope。長さは1〜65536バイト。 長さを確認してからメモリ確保する。OBJECTの直後にだけ、署名されたSizeちょうどの生バイナリが続く。 本体をCBORやBase64で包まない。制御メッセージにJSONは使用しない。

Envelopeキー 型 規則
0 uint Version=1
1 text Message ID。暗号乱数16バイトを小文字hex32文字で表示
2 text From。認証済み接続相手のAINET IDと一致
3 uint 操作コード
4 text、optional Reply To。応答対象のMessage ID
5 map 下表の型付きBody

各操作コードは独立の名前空間を持ち、意味を変更・再利用しない。

操作コード 名前 Body
1 HELLO {0: 公開鍵bytes32}
2 GET_OBJECT {0: Object ID(text)}
3 OBJECT Recordそのもの。その後にSizeバイトの本体
4 RECEIPT {0: 保存済みObject IDまたはMessage ID(text)}
5 MESSAGE Meaning、下記
127 ERROR {0: エラーコード(uint)}

OBJECT・RECEIPTを独立した操作にし、要求・送信・保存済みを明確に区別する。 各応答のReply Toは、その応答を生じさせた直前の要求・送信のIDである。

意味、認証、権限のコード

Meaningは{0: Intent(uint), 1: References(array(text)), 2: In Reply To(text, optional)}。 Referencesは1〜16件のObject ID。送信前に、すべてそのノードで明示公開済みであることを確認する。 受信した参照は自動取得しない。参照先の存在や内容を受領通知で保証しない。

Intent 意味 解釈
1 NOTIFY 指定Objectを知らせる。In Reply Toなし
2 QUESTION 先頭の参照Objectが質問本文、残りは背景情報。In Reply Toなし
3 ANSWER 先頭の参照Objectが回答本文、残りは根拠。In Reply Toは質問のMessage IDで必須

ANSWERは、その相手との間に記録済みのQUESTIONを指定しなければならない。 人間がCLIで作ることができ、AIによる解釈や回答生成を必要としない。 「情報を参照する」は参照配列、「権限を確認する」は署名付きPolicyとローカル公開状態・相手の許可の 同時確認として定義する。機密Objectへの独立した存在照会・権限照会APIは作らない。

認証状態コードはローカル状態として0=未認証、1=鍵とIDの対応確認済み、2=手動登録済み参加者とする。 これはアプリケーションが遷移させる状態であり、受信側に信用させる自己申告フィールドではない。 身元提示はHELLO、鍵の保有証明はNoise、IDの対応・許可確認は通信アダプターが担当する。

状態遷移

  1. 双方で相手を手動登録。Noise相互認証とID対応検証。許可されない接続はここで拒否。
  2. 新しいAINETストリームごとにHELLO要求とHELLO応答。応答は要求IDを参照。
  3. GET_OBJECTまたはMESSAGEを一つ送る。他の順序は拒否。
  4. GET_OBJECTなら、公開・権限を確認してOBJECTと本体を送る。
  5. 取得側が検証・正式保存し、OBJECTのMessage IDをReply ToにしたRECEIPTを返す。
  6. MESSAGEなら、構造・質問回答の対応・重複IDを検査して保存し、MESSAGEへのRECEIPTを返す。
  7. その要求用ストリームを閉じる。新しい要求は新しいストリームでHELLOから行う。

メッセージの認証・暗号化はNoise接続で保証する。制御Envelopeに独立した署名は付けない。 保存・転送後にも検証するObjectは独立署名を持つ。履歴やRECEIPTは第三者向けの署名付き証明ではない。

受領通知・再送・保存の範囲

RECEIPTは、受信側が検証とローカル保存処理を完了した後に送る。Objectは一時ファイルを 検証し、ファイルのsync、本文のrenameとディレクトリsync、Recordの原子的な書き込みと ディレクトリsync、検証ログのsyncを行う。MESSAGEは記録ファイルのsync・rename・ ディレクトリsync後に応答する。OS・ファイルシステム・記憶装置がこれらの操作を正しく 提供することを前提とする。受領通知を受け取れない場合でも保存済みの可能性がある。

MESSAGEの重複判定キーは「認証した送信者のAINET ID+Message ID」。同じ宛先と同一の Meaningを同じIDで再送した場合、保存件数を増やさずRECEIPTを返す。同じキーで宛先や Meaningが異なる場合はINVALIDとする。Envelopeの応答対応は要求ごとに検証する。 履歴には自動期限切れ・自動削除を設けず、保存領域が維持される限り再起動後も判定する。 新しい履歴は最大1024件。既存の同一内容への再送は件数上限到達後も扱う。管理者が保存領域を 消去・巻き戻しした後の重複排除は保証しない。CLIは送信ごとに新しいIDを生成し、 同じIDを指定する再送APIや自動再試行は現時点では提供しない。

GET_OBJECTの再試行は同じObject IDを指定できる。検証済みの同一Objectは同じ識別子で保存し、 別の論理Objectを追加しないが、本文や検証ログへの再書き込みは起こり得る。 同じObject IDに対する異なるRecord・本文も通常のID・署名・本文検証を必須とする。 受領通知がないことを理由に取得済みのObjectを自動再公開しない。

確認済みの障害範囲は単一Linuxでのプロセス再起動・SIGKILLであり、電源断やOS停止時の 実機耐久試験は未実施。本文の配置後・Record保存前の停止では参照されない本文が残り得る。 分散複製完了、永久保存、厳密に一度限りの配送、受信側の善意をRECEIPTは保証しない。

0.1参照実装の資源制限(セキュリティ修正後)

ノード全体の処理枠は4。同じ認証済み相手から受け入れる処理は同時2件までとする。 受信本文を待つ間は保存領域全体のロックを保持せず、容量を事前予約して検証後に確定する。 保存容量は1 GiB、Objectは4096件、MESSAGE履歴は1024件。容量予約は一時ファイル分を 保守的に数えるため、物理上限に達する前に拒否する場合がある。 HELLOには5秒、後続操作には30秒の期限を設け、Go APIの呼び出し側が指定した短い期限と キャンセルは通信I/Oにも反映する。CLI切断によるキャンセル伝播やCPU処理の割り込みとは別である。

この相手別上限は1台による処理枠の独占を制限する。複数の許可済み相手による共謀、 一般的な公平性、無制限の接続元からのDoSを解決する方式ではない。待機キューと BUSYに基づく再試行は未実装。ワイヤの符号化とID計算は修正前後で変更していない。

エラーと互換性

エラー 意味
1 NOT_AVAILABLE。存在しない・非公開・停止済み・提供時検証失敗を区別しない
2 INVALID。形式、参照、順序、保存失敗など。内部事情は相手に返さない
3 UNSUPPORTED。非対応バージョン・操作コード
4 BUSY。将来の明示応答用に予約。現実装の資源超過はストリームを拒否する

HELLOを解釈できない場合は切断し、後続要求の不正では可能ならERRORを返して閉じる。 フレーム破損・長さ超過・時間超過では、ERRORまたは切断による拒否を許す。 認証前に機密情報や詳細な内部エラーを返してはならない。 形式1は厳密な互換性を優先し、未知のフィールド・操作・バージョンを無視しない。 将来版は別のプロトコル識別子と能力交渉を設計する。形式1の意味を変更しない。

設計のみの拡張

予約操作 将来のBody案・意味
16 DISCOVER 種別、要求ID、上限。許可済みのノード・公開Objectの候補を返す
17 QUERY 検索プロファイル番号、型付き条件、上限。結果はObject参照と根拠
18 SHARE 公開Object ID、サイズ、形式を提示。受信側が明示的にGETする
19 VERIFY 対象Object ID、検証種別。将来は検証者署名付きの別Objectを返す

上記は予約・設計段階であり、形式1の実装はUNSUPPORTEDを返す。発見・検索・共有・検証の 自動処理を実装済みとして広告しない。入力制限・権限・検証範囲は将来の仕様確定が必要。

独立した試験例

test-vectors.jsonはPythonの小さな別CBOR実装と標準Ed25519ライブラリで生成した。 Go実装と、公開鍵・ID・正準バイト列・署名・本文の一致をテストする。 tests/vectors.pyで再生成できる。これは全面的な第2互換実装ではなく、符号化・暗号の試験例である。