LoginSignup
1
1

jwkからdid:key を作ってみる

Posted at

単純なdid記述としてdid:keyというmethodがある。その仕様書はThe did:key Method v0.7にあり、具体的には、以下のように書けるそうだ。

did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N

これが何を意味しているかは、universal resolverに放り込むとわかるそうで、放り込んだ結果は以下のとおりである。

EcdsaSecp256k1VerificationKey2019
{
 "kty":"EC",
 "crv":"secp256k1",
  "x":"tS0TJpT9-UUpJvjMZUyA0C0oI9l7VW8d2ADptYRJVdM",
   "y":"RQEb5Z7oO52oHNpYk9lbbuwZmA_GFNenqSjX4joDh-A"
}

この変換に関する理論的な解説は、以下の記事に詳しいものの、具体的にsecp256k1 jwkからdid:keyを算出方法が知りたかったので調べてみた。
  DID Method 探訪:The did:key Method

上記記事によると、base58を使う場合のkey formatは下記の通りになるとのこと。

"did:key:" + "z" + base58(multicodec + pubKey)

step1 multicodeを決定

 まずsecp256k1 jwkから、did:keyを算出するためには、The did:key Method v0.7仕様に従って、multicodeを決める必要がある。下記の表に従えば、secp256k1は、0xe7である。これをunsigned variant表記にすると0xe701となる。
multicode.png

step2 pubkeyを決定

 0xe7の定義にあるように、pukeyには、compressedのkey formatを記載すればいいことがわかる。compressedのkey formatに関しては、「learn me a bitcoin」に詳しいが、簡単にいえばy値がoddのときは0x03+x値, y値がevenのときは、0x02+x値となる。
 上記のsecp256k1 jwkをhex表記に変更

 "x":"tS0TJpT9-UUpJvjMZUyA0C0oI9l7VW8d2ADptYRJVdM"
  "y":"RQEb5Z7oO52oHNpYk9lbbuwZmA_GFNenqSjX4joDh-A"
→ 
  "x": 0xB52D132694FDF9452926F8CC654C80D02D2823D97B556F1DD800E9B5844955D3 
  "y": 0x45011BE59EE83B9DA81CDA5893D95B6EEC19980FC614D7A7A928D7E23A0387E0

"y"値が偶数なので、compressed なkey formatは次のようになる

   0x02 B52D132694FDF9452926F8CC654C80D02D2823D97B556F1DD800E9B5844955D3

step3 did:keyを作る

secp256k1のdid:key formatにstep1, step2の結果を入れると以下のようになる

  did:key: + "z" + base58("E701"+ 
       "02B52D132694FDF9452926F8CC654C80D02D2823D97B556F1DD800E9B5844955D3")

base58エンコードすると以下のようになり、仕様書に書かれていたsample値(did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N)と一致する

did:key: + "z" + Q3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N

サンプルコード

上記ステップをコーディングし、動作を確認してみた

実行

node server.js
→
--------generate key for did -------------------
d : XoxqzQ/r9P/XCu/RdL8cx/x94boZuoFf0izq//RevN4=
x (b64): BzYnIwfodS6WVAIc3JTbNfPOqNUxz9s3d+JpdEBVckM=
y (b64): OOaOapbUUCEzQJaXhF9CBovBB3pLkQIGUE1/W4Gkyzk=
-----------------------------

did -> did:key:zQ3shf8FsfJSvDGmM4GNmhgNocBQfUkEZwAAHTCNb7Kkicpw4
server.js
const crypto = require('crypto');
const elliptic = require('elliptic');
const base58 = require('bs58');

let did = createId();
console.log("did -> "+did)


function createId(){
 const key = crypto.randomBytes(32).toString("hex");
 const ec = new elliptic.ec('secp256k1');
 const prv = ec.keyFromPrivate(key, 'hex');
 const pub = prv.getPublic();
 const ecjwk = {
   kty:"EC", 
   crv:"secp256k1", 
   "x":pub.x.toBuffer().toString('base64'),
   "y":pub.y.toBuffer().toString('base64')
 };
 const ecjwkpri = {
   kty:"EC", 
   crv:"secp256k1", 
   "x":pub.x.toBuffer().toString('base64'),
   "y":pub.y.toBuffer().toString('base64'),
   "d":prv.getPrivate().toBuffer().toString('base64')
 };
 console.log("--------generate key for did -------------------")
 console.log(` d : ${prv.getPrivate().toBuffer().toString('base64')}`);
 console.log(` x (b64): ${pub.x.toBuffer().toString('base64')}`);
 console.log(` y (b64): ${pub.y.toBuffer().toString('base64')}`);
 console.log("-----------------------------\n")
 let _key={"publicJwk":ecjwk,"privateJwk":ecjwkpri};
 let yhex = pub.y.toBuffer().toString('hex')
 if ((parseInt(yhex.slice( -1 ), 16) %2)==1){
   parity_flag = "03";
 }else{
   parity_flag = "02";
 }
 let tmp = "E701"+parity_flag+pub.x.toBuffer().toString('hex');
 let _did = "did:key:z"+base58.encode(Buffer.from(tmp, 'hex'));
 return _did;
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1