公開検証

あなたのバックアップを自分の手で解く

このページの復号手順はブラックボックスではありません:同じ暗号プリミティブ(鍵を包む鍵(KEK)、Argon2id/PBKDF2 鍵導出、AES-GCM)が github.com/tacet-ink/journal-core でオープンソース(MIT)として公開され、このページのソースも丸ごと読めます。一行ずつ確かめても、自分で動かしても構いません。

アプリ内の「バックアップと持ち出し」から書き出した暗号化バックアップを下の枠に貼り付けて、そのパスフレーズを入力してください。バックアップがそれで本文が現れれば、証明は完了です:この文字列の鍵はパスフレーズだけで決まり、その過程に私たちは一切関わりません。

このページが出したネットワーク要求:0 件。すべての計算はあなたのブラウザの中で完結します。

検証しているもの

このページは、暗号化バックアップ自身の復号手順を再現します(PBKDF2 60 万回で鍵を導出し、AES-GCM で鍵の包みと本文を開く)。コードはこのページのソースと下の説明の中にあり、使う前に確かめられます。復号が成功するということは、二つのことを意味します:

  1. あなたのパスフレーズこそが、このデータを開けられる唯一の鍵であり、サーバーなしであなたの端末上で働く。
  2. サーバーの保管層にある jr1b. で始まる本文(旧形 jr1./純ローカル時代の jr1u. は同義)は、あなたのパスフレーズがなければただのノイズだということ。

ゼロネットワークの証明

このページのカウンターは、ブラウザが出すすべての要求を数えます。パスフレーズの送信も、テレメトリーも、外部スクリプトもありません。開発者ツールのネットワークパネルで自分で確かめても、このページをオフラインで開いて実行しても、結果は同じです。

形式の説明

暗号化バックアップファイルの中身:各本文の暗号文(jr1b. 接頭辞、旧ファイルは jr1./jr1u.。AES-GCM、AAD は日記 ID に紐づく)、ソルト、パスフレーズで包んだ鍵(jr1w. 接頭辞)。v2 形式は画像添付も持ちます:各画像の暗号文は jr1c. 接頭辞で、AAD は日記と添付の番号(jr1a:)に紐づき、本文と同じ鍵で暗号化されています。解いた後の画像は blob: URL でブラウザ内に表示され、やはりネットワーク要求ゼロです。復号の順序:パスフレーズとソルトを PBKDF2(600,000 回、SHA-256)に通して鍵を包む鍵(KEK)を導出 → 鍵の包みを解いて noteKey を取り出す → noteKey で各本文と各画像を解く。接頭辞はバージョンの取り決めです:将来 KDF のパラメーターが上がるときは新しい接頭辞になり、旧ファイルは旧規則のままで解け続けます。

補足説明:バックアップ書き出し形式は初版から jr1w.(PBKDF2)で、このページはその契約と一致し、旧バックアップは永遠に解けます。アプリ内の「アカウントのログイン包み」は 2026-09 からメモリハードな Argon2id にアップグレード済み(旧アカウントは次回ログインで自動アップグレード)で、バックアップ形式とは別系統として並存します。詳しくは〈脅威モデル〉。

同じコードがアプリ本体(React)とこのページ(素の JavaScript)で動いています。検証環境とアプリ環境の挙動が一致すること、それこそがこのページの目的です。

この方法の限界

検証できるのは「暗号文と包みは、パスフレーズが正しければ開き、違えば開かない」、つまり保管層の読めなさです。サーバーが改ざん済みのコードを届けないことの証明にはなりません(〈脅威モデル〉の正直な限界参照)。パスフレーズを覚えておいてくれるわけでもありません。間違ったパスフレーズを入れると、ここには「解けない」とだけ表示され、それ以上の再試行の助けはありません。次の段階であるデプロイの検証は、下の「再現可能ビルド」の節へ。

なぜ再現可能ビルドなのか

脅威モデルの正直な限界に書いたとおりです:運営者が悪意を持てば、鍵を吸い取る改ざん済みコード(毒入りの JS)を届けられる可能性は理論上あります。これまでの緩和策は「暗号化層のコードは公開している。これは緩和であって根絶ではない」。再現可能ビルドはこの緩和に実質的な証拠を与えます。コードが公開されているだけでなく、実際にオンラインで動いているコードそのものを、誰でもソースから再現できます。再現結果がオンラインのファイルと 1 バイトも違わなければ、オンラインのファイルはそのソースからビルドされたものです。運営者がデプロイ時に細工をして 1 バイトでも入れ替えれば、照合は失敗します。それでも緩和であって根絶ではありません(限界はこの節の末尾)。ただ、「運営者の良心を信じるか」が「自分の手で出せるハッシュを信じるか」に置き換わります。

オンラインの現行版

現在オンラインの主プログラムのファイル名 index-D3DGhNVl.js そのファイルの SHA-256 ハッシュ f71ac791c36a3eaea791b2cd4e8112b328b35baa436b86b0848966819c119dca

この 2 行は、ビルドとデプロイのときにデプロイパイプラインが自動で刻印するもので、手書きではありません。このページを開いたときに見える値が、あなたがダウンロードしている主プログラムのファイル名とその SHA-256 です。自分で再現したあと、この 2 行と比べてください。版の刻印は v0.1.0+<7 桁の git リビジョン> の形(作業ツリーに未コミットの変更があるときは .d を付す)で、ビルドパイプラインが git から自動生成し、プログラムに刻み込みます。

自分の手で再現する手順

以下の手順は、REPRODUCING.md(リポジトリのルート)を実行可能な形に整理したものです。実測済み:同一リビジョン・同一ロックファイルで、別のディレクトリーでの新規ビルドが、オンラインと 1 バイトも違わない成果物になります。必要な環境と版:node 26.8.1、npm 11.19.0(engines は正確に固定、.nvmrc と同期)。依存は package-lock.json で全固定し、npm ci で入れる(npm install は使わない。^ の範囲で浮動します)。

  1. 単一の clone で足ります:暗号コアは依存の一つとして npm ci で入ります(パッケージ @tacet-ink/journal-core、版は package-lock.json で固定)。特別なディレクトリー構成は不要です。コアは公開済み(MIT):github.com/tacet-ink/journal-core。
  2. tacet のディレクトリーで:nvm use(.nvmrc を読み 26.8.1 を取る)。
  3. npm ci:package-lock.json に厳密に従って依存を復元。
  4. npm run build。
  5. ハッシュの照合:dist/assets/index-*.js の sha256 を算出。次にオンラインの主プログラム(上の「オンラインの現行版」のファイル名)を取得して 1 バイトずつ照合。2 つの SHA-256 が同じなら、再現は成功です。
mkdir tacet-build && cd tacet-build
git clone <tacet-repo-url> tacet
git clone https://github.com/tacet-ink/journal-core.git core
cd tacet
nvm use
npm ci
npm run build
find dist -type f | sort | xargs sha256sum > dist.sha256
# 上の「オンラインの現行版」のファイル名と SHA-256 と照合

正直な限界(再現可能ビルド)

正直な開示

この仕組みは緩和できても、根絶はできません。このページに書かれた手順と数値は、依然として信頼を前提にしています。このページ自体、そのデプロイも、やはり運営者のサーバーから来ます。悪意ある運営者は理論上、ページに偽のハッシュを表示できます。再帰的な限界が存在します。徹底した第三者検証は、このページを読むだけで終わりにできず、手順どおりに自分で一度走らせ、自分の算出したハッシュをオンラインのファイルと照合することです。独立した第三者の再現があって、この信頼は初めて地に足がつきます。さらに、tacet のアプリ層のソースはまだ公開していません(tacet-ink/journal-core の暗号コアは公開済み。このページ自体がブラウザ内で暗号化バックアップの復号を再現できます)。node/vite のメジャー版をまたぐ再現と OS をまたぐ再現は未検証で、現在の基準は Linux x64 です。

書きはじめる