🎃

DIDKit(Node)でVerifiable Credentialsの発行と署名をやってみる

2023/01/10に公開約4,800字

DIDKitを使ってローカル環境でVCの発行と検証を試してみます。

やること

  • DIDKitのビルド
  • DIDKitを使ってVCの発行
  • DIDKitを使ってVCの検証

やらないこと

  • DIDKitの説明
  • Verifiable Credentialsの説明

環境用意

DIDKitのnpmパッケージがあるのですが、バージョンが古い(0.2.1)ので手元でビルドしたものを今回は使います。

使うバージョンはTagがついてないのですが、
https://github.com/spruceid/didkit/commit/b4491bf607eed12b2a21a8fab9a0f3fa89c1c70b
の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コンテナで用意します。
Dockerfileとdocker-compose.ymlを作成してwasm-pack buildします。

Dockerfile
FROM rust
WORKDIR /myapp

RUN rustup target add wasm32-unknown-unknown
RUN cargo install wasm-pack
docker-compose.yml
version: '3'
services:
  app:
    build: .
    volumes:
     - .:/myapp

docker-compose run --rm app wasm-pack build didkit/lib/web --target nodejs --out-dir /myapp/didkit-wasm-node

これで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.jsonissuanceDateが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

ログインするとコメントできます