Develop with pleasure!

福岡でCloudとかBlockchainとか。

IONのDIDを更新してみる

前回の記事でIONのDIDを登録したので↓

techmedia-think.hatenablog.com

今回は、登録したDIDの鍵を更新するUpdate操作をアンカリングしてみる。

Update操作

Update操作は、現在DIDに紐付けられているUpdate Keyを使ってDID Documentの更新(署名鍵やserviceの追加、削除など)を行う操作になる。更新の対象や内容は、DID State Patchesで定義する。

今回は、DIDに署名鍵として登録した公開鍵を新しい公開鍵に更新するreplaceアクションを行うことにする(Patchは複数設定することも可能)。

今回のUpdate操作に必要な手順は↓

  1. 新しい署名用の鍵ペアを生成する。
  2. 1の公開鍵のデータを元に、replaceを行うDID State Patcheを生成する。
  3. DIDに紐付ける新しいUpdate Keyを生成する(このUpdate Keyは、この更新後のDIDのステートを更新する際に使用されるUpdate Keyになる)。なので、更新用の鍵はワンタイムの鍵ということになる。
  4. 3の新しいUpdate Keyのコミットメントを生成する。
  5. 2と4のデータからUpdate Operation Delta Objectを生成する。
  6. 現在のUpdate Keyを使って、JWSデータを生成する。
    • ヘッダーはalg: ES256Kのみ指定。
    • JWSのペイロードは、以下の2つの要素で構成される。
      • 現在のUpdate KeyのデータであるupdateKey
      • 5のUpdate Operation Delta Objectのハッシュ値であるdeltaHash
    • ↑のデータに対して、現在のUpdate Keyで署名した署名値をセットする。
  7. 6のJWSのデータを使って、(Create操作では不要だった)Provisional Proof Fileを生成して、IPFSにアンカリングする。
  8. 5のdeltaファイルからChunk Fileを生成して、IPFSにアンカリングする。
  9. 以下のデータからProvisional Index Fileを生成して、IPFSにアンカリングする。
    • 7のProvisional Proof FileのURI
    • 8のChunk FileのURI
    • 更新対象のDID Suffix(Short-Form形式のDID)
    • 現在のDIDにコミットされているUpdate Keyのコミットメントに対応するReveal Value(JWKのSHA-256 Multihash。コミットメントはdoubule-SHA-256されてる)。
  10. 9のProvisional Index FileのURIを指定して、Core Index Fileを生成し、IPFSにアンカリングする。
  11. 10のCore Index FileのURIからAnchor Stringを生成し、それをBitcoinにアンカリングする。

前回のCreate操作と違うのは、Update操作が可能なことを暗号学的に証明するためのJWSの生成と、それをCASにアンカリングするためのProvisional Proof Fileの作成。

実際に操作を実行

前回登録したDIDを更新しようとしたんだけど、いろいろ試行錯誤して試してたら、

{
code: "canonicalized_object_hash_mismatch",
message: "Canonicalized update request update key object hash does not match expected hash 'EiDBQ56irlBskr7ZawFLcoH131ZvSLbfa2jK1MOny-feIQ'."
}

というエラー以降、更新できなくなってしまったので、新しいDIDを作成して(did:ion:test:EiBRrmEha_Q30GieEwLB-XM8CZd_b49dQ7znhaBxfAHTsQ)↓

こちらを更新することにする。Update処理のサポートをsidetreerbに実装して、↓を実行

require 'sidetree'

Sidetree::Params.network = Sidetree::Params::Network::TESTNET

did = generate_did # ↑で新規作成したSidetree::DIDオブジェクト(作成方法は前回の記事参照)

# DID新規作成時に設定したUpdate Key
update_key =
  Sidetree::Key.new(
    private_key:
      30_922_012_418_511_471_117_584_821_339_133_667_644_396_117_517_409_218_592_473_694_736_410_013_586_765
  )

# 新しい署名鍵を生成
new_signing_key = Sidetree::Key.generate(id: "signing-key")

# 置き換えるDID Documentを生成
document = Sidetree::Model::Document.new(public_keys: [new_signing_key])

# 次のUpdate Keyを生成
next_update_key = Sidetree::Key.generate

# Update delta objectを生成
delta =
  Sidetree::Model::Delta.new(
    [document.to_replace_patch],
    next_update_key.to_commitment
  )

# JWSを生成して署名
claim = { updateKey: update_key.to_jwk.normalize, deltaHash: delta.to_hash }
jws = Sidetree::Util::JWS.sign(claim, update_key)

ipfs = Sidetree::CAS::IPFS.new

# Provisional Proof Fileを作成
provisional_proof = Sidetree::Model::ProvisionalProofFile.new([jws])
provisional_proof_uri = ipfs.write(provisional_proof.to_compress)

# Update operationを作成
update_op =
  Sidetree::OP::Update.new(did.suffix, delta, jws, update_key.to_reveal_value)

# Chunk Fileを作成
chunk_file =
  Sidetree::Model::ChunkFile.create_from_ops(update_ops: [update_op])
chunk_file_uri = ipfs.write(chunk_file.to_compress)

# Provisional Index Fileを作成
provisional_index_file =
  Sidetree::Model::ProvisionalIndexFile.new(
    proof_file_uri: provisional_proof_uri,
    chunks: [Sidetree::Model::Chunk.new(chunk_file_uri)],
    operations: [update_op]
  )
provisional_index_file_uri = ipfs.write(provisional_index_file.to_compress)

# Core Index Fileを作成
core_index_file =
  Sidetree::Model::CoreIndexFile.new(
    provisional_index_file_uri: provisional_index_file_uri
  )
core_index_file_uri = ipfs.write(core_index_file.to_compress)

anchor_str =
  Sidetree::Util::AnchoredDataSerializer.serialize(1, core_index_file_uri)

最終的なAnchor Stringは、

ion:1.QmVKryfVemjT3Nxnea4aJpJRXFJkLpFjNfti1tJngJwBWs

Bitcoinにアンカリングしたトランザクション40ba3f1d10456be725ac176a333e42b0ef9fdf47cb9f325f8f5c4f69b2e931df

ブロックが承認され、IONで取り込まれると、先程のDIDを解決すると、↓のようにdid:ion:test:EiBRrmEha_Q30GieEwLB-XM8CZd_b49dQ7znhaBxfAHTsQの署名鍵が新しく生成した鍵で更新されていることが分かる。