紹介状という、ありふれた手続き

他機関が所蔵する資料を閲覧したいとき、所属機関が発行する紹介状を持っていくことがあります。受入先はその紙を見て、必要なら発行元に電話をかけて裏を取ります。

この運用には、地味ですが2つの性質があります。

ひとつは、受入先が発行元に問い合わせないと確認できないことです。夜間や休日には確認が取れず、発行元のサーバや電話が止まっていれば止まります。

もうひとつは、発行元が問い合わせを受けることで、誰がどこに申請したかを知ることです。紙の紹介状では起きにくいことですが、これをオンラインの照会 API に置き換えると、利用者の閲覧履歴が発行元に集まります。紙の時代には存在しなかった監視能力が、デジタル化の副作用として新設されることになります。

Verifiable Credentials(検証できる証明書。以下 VC)という規格は、この2点に手が届きます。1点目は素直に解けます。2点目は「解ける余地がある」が正確で、実際に作ってみると設計を誤ると解けませんでした。その顛末も含めて、第2章で確かめます。

3つの試作と、その間にある行き止まり

作ったのは3つの試作です。それぞれ、前の試作が答えられなかったことを引き受ける形になっています。

3つの試作の関係を示した図。上から下へ3段。1段目「試作1 所属を証明する(did:web / did:webvh)」は、答えたこととして「受入先が大学に問い合わせずに検証できる」、次へ渡した問題として「ログを丸ごと作り直されると、過去の所属証明を後から捏造できる」。2段目「試作2 資料の版に署名する(同じ鍵・同じ仕組み)」は、答えたこととして「この URI の、この版を公開したと言える。更新は drifted として区別する」、次へ渡した問題として「同じ限界をそのまま引き継ぐ。機関は版の履歴も作り直せる」。3段目「試作3 支払いを根拠にする(did:pkh)」は緑で強調され、答えたこととして「いつ・誰が・どの版に払ったかが機関の管理外に残る」、次へ渡した問題として「アドレスの名寄せ。改竄耐性と引き換えに観測可能性が上がる」。図の下部に「チェーンが効いているのは『機関が自分の過去を作り直せない』という一点だけ」と書かれている。

試作1 は、紹介状を VC に置き換えるものです。受入先は発行元に問い合わせずに検証できます。

ただし2つ目の性質(発行元が誰の申請かを知らない)は、作っただけでは手に入りませんでした。公開鍵を検証のたびに取りに行く実装にしていたため、そのアクセスログから「誰の証明書を、どこが検証したか」が分かってしまいます。第2章で実測した通信の記録とともに扱います。

ここまでにブロックチェーンは登場しません。必要なのは公開鍵の配布だけで、静的なファイルを1枚置けば足ります。

ところが、この試作には行き止まりがありました。公開鍵の履歴を自分でホストしている以上、その履歴を丸ごと作り直せるのです。過去の日付で発行したことにした証明書を、後から捏造できてしまいます。

試作2 は、証明の対象を人から資料に移したものです。「この人は本学の所属者だ」ではなく「この資料のこの版を、本学が確かに公開した」を言えるようにします。ここでは資料が更新されるという、人にはなかった問題が出てきます。ただし、履歴を作り直せるという限界は、試作1からそのまま引き継ぎます。

試作3 で、初めてブロックチェーンが入ります。日本円ステーブルコイン JPYC を使い、「いつ・誰が・どの版に対して支払ったか」を、機関の管理下にない場所に置きます。

この本の主張

先に結論を書いておきます。

ブロックチェーンが効いているのは、「機関が自分の過去を作り直せない」という一点だけです。

公開鍵の配布も、署名の検証も、証明書の流通も、すべてブロックチェーン抜きで実現できます。実際、試作1と試作2 はチェーンを一切使っていません。ヨーロッパの制度もそうなっていて、EU の電子 ID ウォレット(EUDI Wallet)や Gaia-X の信頼枠組みは、既存の公開鍵基盤(PKI)の上に組まれています。

それでも一点だけ、関係者を事前に決めずには埋められない穴があります。試作1の行き止まりがそれで、この本の後半はその穴に費やされます。

使ったもの

署名ECDSA P-256(ES256)。Node 標準の Web Crypto
証明書の形式VC Data Model 1.1 の JWT 表現
識別子did:key / did:web / did:webvh / did:pkh
資料の記述IIIF(画像を機関を越えて相互利用するための枠組み。第5章で説明)Presentation API 3.0
チェーンPolygon Amoy(テストネット)
通貨JPYC(日本円ステーブルコイン)、POL(手数料用)
コントラクトSolidity 0.8.28 + Foundry

試作1と2は依存パッケージがゼロです。暗号処理は Node の標準ライブラリだけで動きます。試作3も、残高の読み取りとログの検索はパッケージなしで書けました。ライブラリを入れないのは禁欲のためではなく、中で何が起きているかを隠さないためです。

読み方

順に積み上がる構成なので、頭から読むのが早いと思います。第4章「改竄してみる」と第6章「署名は正しい。では署名者は?」が2つの折り返し地点で、それぞれ手前の章の到達点をひっくり返します。

コードはすべて手元で動かしたものです。実行結果はそのまま貼っています。