🎃
DIDKit(Node)でVerifiable Credentialsの発行と署名をやってみる
DIDKitを使ってローカル環境でVCの発行と検証を試してみます。
やること
- DIDKitのビルド
- DIDKitを使ってVCの発行
- DIDKitを使ってVCの検証
やらないこと
- DIDKitの説明
- Verifiable Credentialsの説明
環境用意
DIDKitのnpmパッケージがあるのですが、バージョンが古い(0.2.1)ので手元でビルドしたものを今回は使います。
使うバージョンはTagがついてないのですが、
のcommitが反映されているバージョンを使います。git clone
でソースを落としてきます。
git clone git@github.com:spruceid/didkit.git
DIDKitのリポジトリの他にspruceid/ssi
のリポジトリも必要なので落としてきます。
参考: https://github.com/spruceid/didkit#manual
git clone https://github.com/spruceid/ssi --recurse-submodules
Node用にビルドします。
参考: https://github.com/spruceid/didkit/tree/main/lib/web#readme
今回はRustの環境はDockerコンテナで用意します。
build用のスクリプトを作成してwasm-pack build
します。
build.sh
docker run -v $PWD:/app -it --rm rust bash -c "cargo install wasm-pack && cd /app/didkit/lib/web && wasm-pack build --out-dir /app/didkit-wasm-node --target nodejs"
sh build.sh
これでDIDKitのNodeパッケージが生成されて、ディレクトリとしては以下の状態になっています。
VCの発行
JWK生成
最初にJWKファイルを生成しておきます。
index.js
const DIDKit = require("./didkit-wasm-node");
const fs = require("fs");
async function main() {
generateKey()
}
function generateKey() {
const key = DIDKit.generateEd25519Key()
fs.writeFileSync("issuer_key.jwk", key)
}
main().then((res) => {
}).catch((err) => {
console.log("err", err)
})
node index.js
以下のような、JWKが生成されます。
issuer_key.jwk
{"kty":"OKP","crv":"Ed25519","x":"52_9TqZnoF9CC-QjMh1RoVMg4hQNC4rvvvJi0dNNhBE","d":"qP8nGCOrYJ4J4mTzcA--oM8iTPzV_cImhEiR1Zy3f3k"}
VC署名
署名前のVCのJSONを用意した後に、issuer_key.jwk
で署名します。
参考: https://www.spruceid.dev/quickstart
index.js
const DIDKit = require("./didkit-wasm-node");
const fs = require("fs");
const crypto = require("crypto")
async function main() {
// generateKey()
const key = fs.readFileSync("issuer_key.jwk").toString()
const issuerDid = DIDKit.keyToDID("key", key)
const unsignedVc = {
"@context": "https://www.w3.org/2018/credentials/v1",
"id": `urn:uuid:${crypto.randomUUID()}`,
"type": ["VerifiableCredential"],
"issuer": issuerDid,
"issuanceDate": "2023-01-08T18:23:56Z",
"credentialSubject": {
"id": "did:example:my-data-subject-identifier"
}
}
const proofOptions = {};
const signedVc = await DIDKit.issueCredential(
JSON.stringify(unsignedVc),
JSON.stringify(proofOptions),
key
)
fs.writeFileSync("signed-vc.json", signedVc)
}
function generateKey() {
const key = DIDKit.generateEd25519Key()
fs.writeFileSync("issuer_key.jwk", key)
}
main().then((res) => {
}).catch((err) => {
console.log("err", err)
})
以下のようなjsonファイルが出力されます。
これでVCの発行に成功しました。
signed-vc.json
{
"@context": "https://www.w3.org/2018/credentials/v1",
"id": "urn:uuid:86a109aa-a3f6-4374-b46f-92c58fcb16a1",
"type": [
"VerifiableCredential"
],
"credentialSubject": {
"id": "did:example:my-data-subject-identifier"
},
"issuer": "did:key:z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2",
"issuanceDate": "2023-01-08T18:23:56Z",
"proof": {
"type": "Ed25519Signature2018",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:key:z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2#z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2",
"created": "2023-01-08T07:43:50.818Z",
"jws": "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..jyR9O8nb-ino0TXSCAhUdP2Z9iBc0E-aX7tyTHcFuOzOGd_uWpwHhA4gTOX961SUHB0un34e2YV41qc2lk0nCw"
}
}
VCの検証
先程生成したsigned-vc.json
を検証します。
verify.js
const DIDKit = require("./didkit-wasm-node");
const fs = require("fs");
async function main() {
const signedVc = fs.readFileSync("signed-vc.json").toString()
const proofOptions = {};
const result = await DIDKit.verifyCredential(
signedVc,
JSON.stringify(proofOptions)
)
console.log("result", result)
}
main().then((res) => {
}).catch((err) => {
console.log("err", err)
})
これで検証に成功しました。
hide@hidenoMacBook-Pro didkit_vc % node verify.js
result {"checks":["proof"],"warnings":[],"errors":[]}
試しに、signed-vc.json
を改ざんして検証をしてみます。
signed-vc.json
のissuanceDate
が2023-01-08だったのを2023-01-09に変更してみます。
"issuanceDate": "2023-01-08T18:23:56Z",
↓
"issuanceDate": "2023-01-09T18:23:56Z",
すると、以下のように検証に失敗することが確認できました。
hide@hidenoMacBook-Pro didkit_vc % node verify.js
result {"checks":["proof"],"warnings":[],"errors":["signature error: Verification equation was not satisfied"]}
Discussion
初めまして、記事を閲覧させていただきました。私は現在VCを用いた、DAppの開発をしており、本記事を参考にさせていただいております。同じようにフォルダも作って見ました。コマンドライン上では、上手く動き、unsigned-vcの作成から、署名、認証まで同じように行うことができました。このプログラムをベースにし、Javascriptで、このVCの認証システムをブラウザ上で動かしたいと思ったのですが、上手くいきません(VCの情報を投げると認証するようなシステムです)。具体的にはそもそも、コンソールでエラーが出ており、認証以前の段階です(requireがダメだったり、Failed to resolve module specifier "util"だったりです。)。いろいろ調べて見たのですが、キーワードとしては、ES Modules、CommonJS、Node.js上でビルドしているから動かない、など様々な情報が出てきました。プログラムの経験は浅く、Web3.0の勉強は3ヶ月ほどであり、分からないところが多いです。少しでもお力添えいただけると嬉しいです。
コメントありがとうございます。
確かにこの記事ではNode.jsで動かす用に書いているので、ブラウザで使用しようとするとエラーがでるかと思います。
なので、didkitでブラウザで検証できるようにするためには、ES Modules形式でJSを書いたり、wasmなのでJSとはまた少し違った対処が必要だったりします。
Next.jsを使っていますが、一応ブラウザでVCを検証できるような記事を書いてみました。
もし少しでも役に立てば幸いです。