秘密鍵からマルチシグアドレスそしてP2SHまで

冨澤 宝斗 (Takato Tomizawa)
GBEC Tech Blog
Published in
10 min readJul 19, 2019

HashHubインターンのたかてぃ(冨澤)です。
今回の記事のネタを考えていた所、HashHubエンジニアの藤田氏がTwitterで「Mastering Bitcoin半年に一回は読むべき」と呟いてて、これを見て「ああ確かになぁ、、わかったつもりになってる部分多分沢山あるもんなぁ」と思い、Mastering Bitcoinからネタを探しました!

前回scriptやトランザクションに関する記事を作成したので、今回は標準的なトランザクションとして紹介されるマルチシグやP2SHについてのまとめました。

目次
*秘密鍵を生成
*秘密鍵から公開鍵を生成
*公開鍵を配列にセットし、マルチシグアドレスを作成
*マルチシグアドレスの紹介
*P2SHの紹介
*最後に

*秘密鍵を生成
今回は、「bitcoinjs-lib」を使って秘密鍵を生成していきます。

$> npm install bitcoinjs-libconst bitcoin = require('bitcoinjs-lib');let keyPair = bitcoin.ECPair.makeRandom();
let privateKey = keyPair.toWIF();
console.log (privateKey);

まず最初に変数keyPairに、シード無しで作られたキーペアを代入し、その値をWIF形式に変換します。
(今回はWIFの復習と思ってこの形式にしてみました)
WIFとは、Base58Checkでエンコードした秘密鍵のフォーマットです。16進数と同じ256bitの数値です。

コンソールでの結果を見てみると、

L4rjkeEpW5ptcefviyJmR1MSxKT9bvZwswX2ZGZdFSQWoxzLqnLs

この様にWIF形式を判断する基準の、Base58で出力された文字列の先頭に付けられるプレフィックスの5,KまたはLの内、Lから始まっています。
続けて秘密鍵から公開鍵を生成していきます。

*秘密鍵から公開鍵を生成
先ほどのkeyPairを使って公開鍵を生成します。

let publicKey = keyPair.publicKey.toString('hex');
console.log (publicKey);
0396c5c0b9241700284217043a44aca8c2ebb577b90ab46c2fa236dd0d3a896d95

keyPairを公開鍵にする為のメソッドと16進数で表示される様に、処理を書きます。

*公開鍵を配列にセットし、マルチシグアドレスを作成
今回は、2 of 3のマルチシグアドレスを作成していきます。
こちらのbitcoinjs-libのページ

can generate a P2SH, pay-to-multisig (2-of-3) address

と書かれた箇所(33行目あたり)があるので、今回はそちらを使用します。

const pubkeys = [
'0228c49499b2e09344da901fd0b1114c0f98fd10b42b0218a010cc8ac965d8de80',
'0306c86c4517cd38ef8fbed8944833078c4b08db2353f337169a1aab461673a9f5',
'02e532bdc68acb178b77930325b394bd6d601b724d1c69a817f51c6a20d79425fc'
].map((hex) => Buffer.from(hex, 'hex'))
const address = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2ms({ m: 2, pubkeys })
})

先ほどの処理で公開鍵を3つ生成し、配列に渡します。そしてその配列を基にバッファのデータとして格納していきます。その際、渡された値をhexでエンコーディングしています。

次に変数addressの部分を、説明していきます。

*マルチシグアドレスの紹介

const address = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2ms({ m: 2, pubkeys })
})

マルチシグでは、locking scriptの中に3つの公開鍵をセットしなくてはいけません。そしてunlocking scriptでセットした公開鍵に紐づく2つのデジタル署名がなければ解除出来ない仕組みになっています。(今回は、m=2 of n=3)

1行目から見慣れない文字があるのに気付きましたか?p2shの部分です。P2SHを説明する前にP2PKHを確認すると、使うメリットがわかるので先にP2PKHの説明を少しします。

Bitcoinネットワークで伝播されているトランザクションの多くは、P2PKHトランザクションです。P2PKHでは、unlocking script + locking scriptを実行しTRUEが返ってこれば有効となり、資金の利用が可能になります。

しかしこのP2PKHをマルチシグで使用するといくつかの問題が発生します。
例えば、P2KHと同様にunlocking script + locking scriptの組み合わせでマルチシグの処理を行うと、3つ公開鍵分データサイズが大きくなりトランザクション手数料が多くかかる事や、使用されるまで全てのフルノードのUTXOプールに保持されてメモリを圧迫してしまうなどの問題があります。

*P2SHの紹介
そこで登場するのが、P2SHというscriptです。
P2SHでは上記の問題を解決する為に、2012年頃から導入されました。

このP2SHを利用する事で、P2PKHと同じくらい簡単にややこしいscriptを扱える様になりました。

P2PKHと同様にlocking scriptに、3つの公開鍵をセットすると

2 <PublicKey1, PublicKey2, PublicKey3> 3 OP_CHECKMULTISIG

となり、とても長くなります。
これをP2SHでは、

1–1. SHA256とRIPEMD160を実行し上記のscriptを20bytesのハッシュ値にする

1–2. locking scriptに作成したハッシュ値とOP_HASH160(SHA256とRIPEMD160を組み合わせたもの)とOP_EQUALを入れて、このUTXOをロックする。

<OP_HASH160 (ハッシュ値) OP_EQUAL >
//locking script

2. 続いて、2つのデジタル署名を持ったunlocking scriptと1でハッシュ化した元のscriptをreddem scriptと名付けて用意します。

< 1つ目のデジタル署名 2つ目のデジタル署名 reddem script>
//unlocking script
<2 <PublicKey1, PublicKey2, PublicKey3> 3 OP_CHECKMULTISIG>
//reddem script

3. 用意が出来たら、reddem script(元の長いscript)をHASH160でハッシュ化し、locking scriptの中にあるハッシュ値と同じか検証する

4. 有効であれば、unlocking scriptとreddem scriptを実行しTRUEが返ってこれば成功です!

そしてこのP2SHを使うと、

・locking scriptを短くする事で、トランザクション作成が楽になる
・トランザクションデータを小さく出来るので、上記で紹介した問題を解決出来る
・locking scriptハッシュをBase58でエンコードして、P2SHアドレスとして使える
・scriptがアドレスとして実装されるので双方のウォレットをP2SHに関連する複雑な実装を行う必要がない

などのメリットがあります。

加えて、P2MSはビットコインを複数の公開鍵でロックでき、そのロックを解除するためには、それらの公開鍵に紐づくデジタル署名が必要だと要求するscriptです。

この2つが組み合わさると、
・lockする時には、公開鍵を含むlocking scritpをHash化してデータサイズを小さくするP2SH
・unlockする時に、Hash化した中身にある公開鍵に紐づくデジタル署名を要求するP2MS

const address = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2ms({ m: 2, pubkeys })
})

というコードになるのではないでしょうか。

*最後に
この記事では、秘密鍵の生成からマルチシグアドレス、P2SHそしてP2MSの紹介をしました。記事を書きながら自分の理解が曖昧な部分があり、エンジニアの方達に助けられました。もし間違っている箇所があれば教えて下さい。
これからも定期的に読み返して理解深めます!

参考文献及び引用元
・ハッタリからはじめよ:https://www.etarou.work/posts/4894540
・Yenomさん作成のスライド:https://speakerdeck.com/usatie/lets-write-bitcoin-script-number-tokyobitcoinhackathon?slide=75
・Bitcoinjs-libサイト:https://github.com/bitcoinjs/bitcoinjs-lib
・learn me a bitcoin:https://learnmeabitcoin.com/
・Mastering Bitcoin:https://bitcoinbook.info/wp-content/translations/ja/book.pdf

お知らせ

■ステーキング事業の提供を始めました!
7月からHashHubでは、Cosmos,Tezos,IOSTの3つのトークンをステーキング出来るサービス「Sanka Network」を提供し始めました。本サービスのご利用をご検討の方は、下記のWEBサイトからお問い合わせください。

Sanke Network:https://www.sanka.network/

■HashHubでは下記のポジションを積極採用中です!
・コミュニティマネージャー
・ブロックチェーン技術者・開発者
・ビジネスディベロップメント
詳細は下記Wantedlyのページをご覧ください。

Wantedly:https://www.wantedly.com/companies/hashhub/projects

■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。

HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo

--

--

冨澤 宝斗 (Takato Tomizawa)
GBEC Tech Blog

琉球大学4年次 物理専攻 | Node.js | Ruby | Ruby on Rails | インフラ | 休学を終え、東京から沖縄に帰ってきました