Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

掲示板の見え方を照合する

自分の票が掲示板に残っていても、ほかの人が同じ掲示板を見ているとは限りません。サーバーが、ある人には 64 票の掲示板、別の人には特定の票を外した 63 票の掲示板を見せたとします。それぞれについて包含証明を作れても、二人が見ている結果は食い違います。これをスプリットビューと呼びます。

この食い違いを探すには、掲示板の状態をほかの記録源と比較します。その照合用の短い値が STH ダイジェストです。どの掲示板かを示すログ ID、票数、時刻、ルートをハッシュでまとめます。

STH は Signed Tree Head に由来する名前ですが、この実装が行うのはダイジェストの一致確認であり、署名検証ではありません。また、同じサーバーの応答同士が一致しても、独立した証人の確認にはなりません。スプリットビューを検出するには、比較先が別の観測を保持していることが必要です。

締切時の状態を証明に結びつける

ゲストは入力のログ ID、票数、時刻、ルートからダイジェストを計算し、公開出力の sthDigest に記録します。サーバーは同じ締切状態を close-statement.json にまとめます。

flowchart TB
  C[締切時の掲示板状態] --> G[ゲストがハッシュ計算]
  G --> J[証明に結びついた sthDigest]
  C --> S[close-statement.json]
  J --> CMP[値を照合]
  S --> CMP
  T[別の記録源の STH] --> CMP

締切記録とジャーナルの一致は、集計がどの掲示板状態を参照したかを確かめる必須条件です。外部ソースとの一致は、その状態を別の記録と照合する追加の確認です。前者が成功したことを、後者も実施したこととして扱いません。

ダイジェストフォーマット

sth_digest = SHA-256(
    log_id           // 32 バイト
    || tree_size     // u32 LE、4 バイト
    || timestamp     // u64 LE、8 バイト、Unix 時刻ミリ秒
    || bulletin_root // 32 バイト
)

入力は合計 76 バイトです。LE はリトルエンディアン、すなわち整数の下位バイトから並べる方式です。ダイジェストには専用タグを付けず、次のログ ID と固定の並びで対象を区別します。

ログ ID

log_id = SHA-256(UTF-8("stark-ballot:bulletin-log|v1.0") || seed)

ログ ID は掲示板の存続中に変わらない識別子です。これをダイジェストに含めることで、票数やルートが同じでも、別の掲示板の締切状態と区別できます。

合意ロジック

検証 API は設定済みソースから応答を取得し、ジャーナルの値と照合します。「合意」とはこの照合の結果を指し、分散合意プロトコルを実行する意味ではありません。

応答フィールド照合方法
sthDigest必須。ジャーナルと一致を要求
bulletinRoot指定された場合、ジャーナルと一致を要求
treeSize指定された場合、ジャーナルと一致を要求
timestamp / logId指定された場合は型・形式を検査。合意判定で直接比較する値ではない

外部応答はこの 5 フィールドだけからなる平坦なレコードです。sthDigest 以外は省略できますが、未知のキー、別名、ラッパーで包んだ応答は受け付けません。

成功には、必要な最小一致数に達し、比較した全レコードが一致することが必要です。設定済みソースに取得失敗、不正な応答、利用不能があった場合も成功にしません。多数の一致で一つの不一致を打ち消す仕組みではありません。判定の詳細は recorded_sth_third_partyに定義しています。

設定

環境変数意味未指定時
VITE_STH_SOURCESカンマ区切りのソース URL または同一サーバー用テンプレート照合しない
VITE_STH_MIN_MATCHES必要な最小一致数2

ソース未設定では recorded_sth_third_party は任意チェックの not_run です。設定した場合は必須になり、必要な一致を得られなければ Verified を表示できません。署名検証や外部への自動公開を、この設定によって追加するわけではありません。

同一オリジンと外部 HTTPS の照合先

同一サーバー用の相対ソースとして使えるのは /api/sessions/:sessionId/bulletin/sth です。任意で auditorId クエリを一つ付けられます。API は現在のセッションから直接 STH の値を取り出すため、この内部照合のために HTTP 通信や認証ヘッダー転送は行いません。

このパスを通常の HTTP API として呼ぶ場合は X-Session-Capability が必要です。集計成功済みのセッションについて { data: { sth: { ... } }, meta } の応答を返します。この応答形式は、外部ソースに要求する平坦なレコードとは異なります。

絶対 HTTPS URL は、アプリと同じオリジンを指していても外部ソースとして取得します。セッションの認証情報を送らないので、その取得先はセッション認証なしで照合用レコードを返す必要があります。

同一サーバーが返す timestamp は session.voting.lastActivityMs で、ジャーナルのダイジェスト生成に使った時刻とは限りません。このため、応答の任意フィールドをすべて再連結してダイジェストを作り直すのではなく、上表の条件で照合します。

.env.local.example のコメント例は、相対テンプレートと最小一致数 1 の組です。これは照合の動作を試す構成です。同じサーバーしか観測していない以上、成功しても独立した外部監査を受けたとは言えません。