ブロックチェーンベースの証明書を検証するblockcerts-verifierの紹介
PitPa のリードエンジニアをしている @shoito です。
本記事では、ブロックチェーンベースの証明書を発行できる Blockcerts、その表示・検証用コンポーネントである blockcerts-verifier を紹介します。
Blockcerts.org で表示されている入力フォーム部分をレンダリングしているのが、今回紹介する blockcerts-verifier コンポーネントです。Web Components として提供されていて、HTML の中で <blockcerts-verifier></blockcerts-verifier>
のようにタグを指定して使います。
ブロックチェーンベースの証明書?検証?
例えば、ある人の大学の卒業証明書を見せられて、そこに記載されている氏名や大学名、卒業年度などが正しいものかをどうやって確認するでしょうか?本人に確認?大学に問い合わせ?
Blockcerts では、証明書発行時に、証明書に署名し、証明書のハッシュ値を算出して、Bitcoin や Ethereum のブロックチェーンに書き込みます(下記図3の部分)。
blockcerts-verifier では受け取った証明書からハッシュ値を復号し、ブロックチェーンに書き込まれたハッシュ値と一致することを検証します(図6の部分)。
証明書の内容が改ざんされていれば、ここでハッシュ値が一致しないため検証失敗となり、証明書が正当なものではないことが分かります。
この一連の流れは Blockcerts のガイドページで図解されています。
※ https://www.blockcerts.org/guide/ より引用
そもそも Blockcerts とは
ブロックチェーンベースの証明書を発行、表示、検証するサービスを構築するためのオープンスタンダードです。2016年にマサチューセッツ工科大学(MIT)で始まった OSS プロジェクトで、現在も GitHub やフォーラムを利用して開発が進められています。
どんな証明書が作れるのか、こちらのサンプルリストページを見ると想像しやすいかと思います。セキュリティエキスパート認定や教育トレーニング修了認定証が例としてあります。
以下の画像は、セキュリティエキスパート認定証明書の例ですが、左側に証明書の検証結果が表示され、右側に証明書が表示されています。
右側の証明書部分は、HTML か PNG, JPEG 画像などでデザイン可能です。
blockcerts-verifier とは
Blockcerts では卒業証明書や学習履歴などの証明書を発行し、表示、検証する仕組みを提供しています。blockcerts-verifier は、証明書の表示・検証をするためのコンポーネントです。Blockcerts の一連の流れの図にある VERIFIER(employer) がユーザーになります。例えば、RECIPIENT(student)の学生を採用する企業の人事担当者がユーザーとして考えられます。
使い方をデモコードで確認してみる
GitHub リポジトリにはデモ用途のコードがあります。もっとも簡単なものはこちらになります。Web Components の形で提供されているので、使い方はだいぶシンプルになってます。
ローカル環境でデモを動かしてみる
GitHub リポジトリを git clone
してから、npm ci
で依存ライブラリをインストールし、npm run start
でローカル環境でデモ用サーバを起動します。
$ git clone https://github.com/blockchain-certificates/blockcerts-verifier
$ cd blockcerts-verifier
$ npm ci
$ npm run start
上記コマンドを実行すると、自動的にブラウザで https://0.0.0.0:8081
が開きます。以下のようなページが表示されます。
もし Chrome で、 NET::ERR_CERT_INVALID
が表示され、デモページにアクセスできない場合は、詳細設定
を開いた状態で thisisunsafe
とタイプしてみてください。
こちらの記事で、そのやり方がスクリーンショット付き(英語表記)で紹介されていますので、ご覧ください。
デモリストから Certificate passed directly to component
を実際に開いて、証明書の検証が実行されるとこのようになります。
コードを見るとフォームをユーザーが操作するのではなく、 blockerts-verifier
コンポーネントの src
属性に証明書の JSON ファイルパスを直接指定しているのが分かります。
検証で何が行われているのか
blockcerts-verifier では、証明書が改ざんされていないことを検証します。
この検証では何にって改ざんがされていないことを確認しているのでしょうか。
検証プロセスの詳細は cert-verifier-js ライブラリ側にドキュメンテーションされています。
ここで検証対象となる証明書の例として、サンプルの JSON ファイルを見てみましょう。
proof
部分が検証に用いられる属性になります。
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/blockcerts/v3.0-beta"
],
"id": "urn:uuid:bbba8553-8ec1-445f-82c9-a57251dd731c",
"type": [
"VerifiableCredential",
"BlockcertsCredential"
],
"issuer": "https://raw.githubusercontent.com/blockchain-certificates/cert-issuer/master/examples/issuer/profile.json",
"issuanceDate": "2010-01-01T19:33:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
},
"metadata": "{\"classOf\":\"2021\"}",
"display": {
"contentMediaType": "text/html",
"content": "<b>hello world</b>"
},
"proof": {
"type": "MerkleProof2019",
"created": "2021-05-06T16:19:52.203831",
"proofValue": "z4zvrPUULnHmaio8hk6bUGzF57JJoPdTmCHK8s8HdJiDAFRqAN46cx1xKyWGFe1fQmBtaRSpuGr21s1b8U9zYUwWLLvM7KeaQ248CCFjFNNYGmumJiMjhM6z49SdHVC4rAPYFMXu4kMr6ufMG5fpB2H9ZxXa9uDBqwvbA1xmxUymUPgskWZe8Yp9cF3KspThUZpZej6q2n1Vx1pM66LZxr8aZ6ERfYipZchxC3Qbnmb8mSRZapJ5t318TQwwjAVYvSj7sptStJJJn5GKujdvS9M2XgM1kfBPeB9a6DCVufLoqyfCP63KUmPnK7df38rx3gHTwBKi9P1ALCWfyrzwtFZ5YchJmmY8TVEEw8fGEKEbcN5q4jF3Cyki2C2Jmjr3LwKREvmaZmCcVSMEsWt",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:example:23adb1f712ebc6f1c276eba4dfa#key-1"
}
}
proof.proofValue
(レシートと呼ばれる)については、Base58エンコードされていて値の想像が付かないと思いますのでデコードして、どんな値を持っているのか確認してみます。
以下のような簡易的な JavaScript コードで、Base58エンコードされている proof.proofValue
の値をデコードします。
const { Decoder } = require('@vaultie/lds-merkle-proof-2019');
const proofValueBase58 = "z4zvrPUULnHmaio8hk6bUGzF57JJoPdTmCHK8s8HdJiDAFRqAN46cx1xKyWGFe1fQmBtaRSpuGr21s1b8U9zYUwWLLvM7KeaQ248CCFjFNNYGmumJiMjhM6z49SdHVC4rAPYFMXu4kMr6ufMG5fpB2H9ZxXa9uDBqwvbA1xmxUymUPgskWZe8Yp9cF3KspThUZpZej6q2n1Vx1pM66LZxr8aZ6ERfYipZchxC3Qbnmb8mSRZapJ5t318TQwwjAVYvSj7sptStJJJn5GKujdvS9M2XgM1kfBPeB9a6DCVufLoqyfCP63KUmPnK7df38rx3gHTwBKi9P1ALCWfyrzwtFZ5YchJmmY8TVEEw8fGEKEbcN5q4jF3Cyki2C2Jmjr3LwKREvmaZmCcVSMEsWt";
const decoder = new Decoder(proofValueBase58);
console.log(decoder.decode());
すると、proof.proofValue
は以下のように path
, merkleRoot
, targetHash
, anchors
を持つオブジェクトであることが分かります。
{
path: [
{
left: 'e1b59fcf59c7a11d725935dd72520268ca715b754accccb896a0cc1f765056db'
}
],
merkleRoot: '2c7afa4f8192bd8d0e243da2044306b2183527270ef6fd76854c34a1288756ba',
targetHash: '5c1fbed6d7d1bc2652c94a319140e42c47a154cd770ae20c7ef16bb59bc6654d',
anchors: [
'blink:btc:testnet:1e956a31736ad3bddf6302ba56050a3a36983610afeb9919256fd4d82e5dc175'
]
}
proof.proofValue
が分かると、以下の一連の検証プロセスが分かりやすくなります。
なお、検証プロセスの前半では証明の検証(Proof Verification)が行われ、後半では失効してないか、有効期限が切れてないかなどの確認(Status Check)が行われています。
- 証明書のマークル証明の検証 (Proof Verification)
- ローカル証明書のハッシュとレシートの targetHash 値の一致 (Proof Verification)
- 証明書のマークルルート値とブロックチェーン上のトランザクション(anchors が指すトランザクション)の値の一致 (Proof Verification)
- 証明書が証明書に記載の発行者によって作成されたことの検証 (Proof Verification)
- 証明書が失効(取り消し)していないことの確認 (Status Check)
- 証明書の有効期限が切れていないことの確認 (Status Check)
参考: マークル証明(マークルプルーフ)とマークルルート、マークルツリーについて
Blockcerts では、このようなプロセスにより証明書が改ざんされていないこと、有効期限内であることなどが検証されています。
最後に
今回は、ブロックチェーンベースの証明書を発行できる Blockcerts の検証用コンポーネントである blockcerts-verifier と、証明書の検証プロセスについて紹介しました。
Blockcerts には blockcerts-verifier 以外にも証明書の作成モジュール cert-issuer や blockcerts-verifier の内部で用いている証明書の検証ライブラリ cert-verifier-js などもあります。
これらについても、別の機会で紹介したいと思います。
PitPaでは web3やメディア事業に興味のあるエンジニアの方とお話できればと考えてます。まだ発表できていないプロジェクトもあるので、ぜひお気軽に代表の石部にご連絡いただけたら幸いです。
▼石部のTwitterアカウントはこちらです。DMでお気軽にご連絡ください!
▼【ポッドキャスト公開中!〜PitPaの創業から現在まで〜】
代表の石部より、PitPa創業の話から現在取り組んでいるポッドキャスト事業・Web3事業の現在とこれからについてトークしました。ぜひこちらもご拝聴いただけますと幸いです。
Discussion
素晴らしい記事ありがとうございます、とても勉強になりました。貴社の nft-vc のおかげで無事にブロックチェーン証明書が発行ができて cert-issuer に関する下記の記事をまとめることができました。
上記の記事で千葉工業大学の事例に触れさせてもらいましたので報告がてらお礼申し上げます。
参考にしていただきありがとうございます!
スクラップと記事と拝見しました。試行錯誤とその結果から整理された情報が素晴らしいです。
私も VC 発行をはじめてやるときに薄田さんの記事があれば、どれだけ時間を溶かさずに済んだことでしょう...。
スクラップまで見ていただきありがとうございます!お言葉を頂けてとても励みになります。情報がほとんどない状態から nft-vc を完成させた技術力と粘り強さに敬服いたします。千葉工業大学さんの NFT 発行の舞台裏にエンジニアの方々の苦労があったと思うと感慨深いです。