BIP79 — 送信者と受信者の間でCoinJoinを行うBustapay

2/17 追記: joemphilipsさんに指摘いただいた部分を追記しました。

こんにちは、Fressetsインターンのpjです。僕は最近引っ越しをしまして、その手続きや荷造りなどが面倒で仕方ない感じです。みなさんはどうお過ごしでしょうか。

さて、今日はタイトルにあるとおり送信者と受信者の間でCoinJoinを行うプロトコルであるBustapayを試していこうと思います。今回はBustapayについて書かれているBIP79の内容について紹介して、そのあとおまけとしてそのAuthorによるリファレンス実装を軽く弄っていきます。

Bustapayとは

Bitcoinのネットワーク上では多くの(CoinJoinなどを用いていない)場合、1つのトランザクションに入っているinputは一人のトランザクション作成者が管理しています。この特性とお釣り用のoutputの予測などを利用すれば、特定のアカウントの所有者が利用しているoutputを簡単に追跡できてしまいます。

2/17 追記: お釣り用のoutputは以下の情報から予測できる
1. 使用しているライブラリによっては、output 上のおつりの位置が固定されていることがある。
2. 定額の支払いが連続している場合、同じサービス/相手に対して支払っていると推測でき、残るoutputがおつりであるとバレてしまうことがある。
CoinJoin
複数のトランザクションを1つのトランザクションにまとめるというもの。こうすることによってinputとoutputの対応が分かりにくくなり、入出金先(誰が・誰に)を秘匿することができる。

これを防ぐために、送信者と受信者がCoinJoinを行うのがBustapayです。送信者のinputに受信者のinput(contributed inputと呼ばれる)が混ざることによってどちらがどちらに送信しているかが分かりにくくなる効果があります。また、外部からはBustapayが用いられたのかわからないので、行われていないトランザクションの追跡の妥当性を低下させる効果もあります。また、Bustapayでは受信者のUTXOが増加しない、というメリットもあります。

2/17 追記: 受信者のUTXOが増加しない、と述べましたが後に述べる手順3で自分自身へのoutputを複数追加した場合はUTXOが増加する場合もあります。
CoinJoinのイラスト

Bustapayの手順

1. テンプレートトランザクションの作成

まずsenderはそのままでもbroadcastのできる、全てのinputがsegwit inputであるトランザクションを作成します。これはテンプレートトランザクションと呼ばれます。

2. receiverにテンプレートトランザクションを送信

次に、作成したトランザクションをreceiverに送信します。これは通常、HTTPのPOSTリクエストで行われます。これはBIP21形式のアドレスにbpuというキーを用いることにします。

bitcoin:2NABbUr9yeRCp1oUCtVmgJF8HGRCo3ifpTT?bpu=https://bp.bustabit.com/submit

3. 受け取ったトランザクションの処理

トランザクションを受け取ったreceiverはそれを検証し、inputを追加して署名し、送信者に返します。この際、receiver自身に送信するoutputを追加することもできます。また、senderが作ったトランザクションに不満があり、拒否したい場合は422で拒否理由と一緒にレスポンスを返します。

追加するinputはcontributed inputと呼ばれ、そのほかのinputと似ているものを選択することが推奨されます。これがない場合は500でレスポンスを返します。(その場合、senderはテンプレートトランザクションをbroadcastするか、作り直す)

4. トランザクションのbroadcast

senderがトランザクションを受け取ったら、receiverなどに不正な処理をされていないか検証し、全てのinputに署名して、ネットワークにbroadcastします。

5. broadcastされたトランザクションを確認する。

receiverはトランザクションが正常にbroadcastされたか確認します。確認できない場合は、元のテンプレートトランザクションをbroadcastすることもできます。

まとめ

前回Grinを紹介したので、その関連で匿名技術であんまり知られていないものを取り上げました。本当はこれのリファレンス実装を弄って実際に動かそうと思っていたのですが、うまくいかなかったのでおまけとして最後に付け加えておきます。原因がわかる方はコメントで教えていただけると嬉しいです。


おまけ 実際に触ってみようとしたけどうまくいかなかった(macOS)

RHavar/bustapayはgolangで実装されているので、まずgolangをbrewでインストールします。また、

brew install go

また、depというパッケージや依存関係を管理するツールをインストールします。

go get -u github.com/golang/dep/cmd/dep

ソースコードをcloneしてinstallします

git clone git@github.com:RHavar/bustapay.git
cd bustapay
dep ensure
go install

bitcoindの準備

今回は引っ越しの関係でネットが開通前なので、regtestでやります。bitcoindとbitcoin-cliを各自インストールしておいてください。

bitcoindをregtest, segwit, jsonrpcを有効にして立て、ブロックを生成して受信側のアドレスを生成します。

> bitcoin-cli generate 101
(略)
> bitcoin-cli getnewaddress
bcrt1q8070mrsehanxh9xxjkh0a9zdaj0vmhptphjned
> bitcoin-cli sendtoaddress bcrt1q8070mrsehanxh9xxjkh0a9zdaj0vmhptphjned 10
dc0bc93ab8fdcfeef3aad120e6a3290930437747047bfee6efe8d5f2f8dacd94
> bitcoin-cli listaddressgroupings
[
[
[
"mhT13ZudHFAyioc8SSMfVqeZHyC4dCxLr3",
0.00000000
],
[
"bcrt1qmq6ygmk257lrzk8ceept6g5aemff0uts88pzf6",
39.99996300
]
],
[
[
"bcrt1q8070mrsehanxh9xxjkh0a9zdaj0vmhptphjned",
10.00000000,
""
]
]
]

こんな感じで受信側にも10btcほど送信しておきます。これで受信側と送信側のUTXOが準備できました。

> bitcoin-cli listunspent 0
[
{
"txid": "dc0bc93ab8fdcfeef3aad120e6a3290930437747047bfee6efe8d5f2f8dacd94",
"vout": 0,
"address": "bcrt1qmq6ygmk257lrzk8ceept6g5aemff0uts88pzf6",
"scriptPubKey": "0014d834446ecaa7be3158f8ce42bd229dced297f170",
"amount": 39.99996300,
"confirmations": 0,
"spendable": true,
"solvable": true,
"safe": true
},
{
"txid": "dc0bc93ab8fdcfeef3aad120e6a3290930437747047bfee6efe8d5f2f8dacd94",
"vout": 1,
"address": "bcrt1q8070mrsehanxh9xxjkh0a9zdaj0vmhptphjned",
"label": "",
"scriptPubKey": "00143bfcfd8e19bf666b94c695aefe944dec9ecddc2b",
"amount": 10.00000000,
"confirmations": 0,
"spendable": true,
"solvable": true,
"safe": true
}
]

送信する

受け取り側の準備をします。

> bustapay receive --bitcoind_port=8332 --bitcoind_user=pj --bitcoind_pass=jp --verbose
Verbose mode enabled!
2019/02/15 14:31:32 Listening on port: 8080

これでlocalhost:8080に受信用のサーバーができました。では、ついに送金してみます。

> bustapay send bcrt1q8070mrsehanxh9xxjkh0a9zdaj0vmhptphjned http://localhost:8080 5 --bitcoind_port=8332 --bitcoind_user=pj --bitcoind_pass=jp --verbose
Verbose mode enabled!
2019/02/15 19:34:48 Sending 500000000 satoshis to bcrt1qqzvhaxg20l4sg2da44rdlmh6k8uutjyzz44gdv via url http://localhost:8080
2019/02/15 19:34:48 Connecting to localhost:8332 with pj and using pass true
2019/02/15 19:34:48 Created unfunded transaction: 0200000000010065cd1d0000000016001400997e990a7feb0429bdad46dfeefab1f9c5c88200000000
2019/02/15 19:34:48 Funded transaction: 0200000001f5e0569ac8fc19f9d57b0b2d85a98e4e0c030ba1a0717a85676c7fff6d935cef0000000000feffffff0284c556fa0000000016001421081cd7c4f1c2b9be071c9eb009499ce9849a4e0065cd1d0000000016001400997e990a7feb0429bdad46dfeefab1f9c5c88200000000
2019/02/15 19:34:48 Template transaction: 02000000000101f5e0569ac8fc19f9d57b0b2d85a98e4e0c030ba1a0717a85676c7fff6d935cef0000000000feffffff0284c556fa0000000016001421081cd7c4f1c2b9be071c9eb009499ce9849a4e0065cd1d0000000016001400997e990a7feb0429bdad46dfeefab1f9c5c882024730440220504c26a5a12327469aeb3e5bbc5996a0c2c3662cfca44406684392629248ea9c0220568acac414bf137d71b504f97b56fe336d4701fc704adcad36142cf275109b1a012103e6551fdca4b0af4cadb80687d108154f3386203156a773c953a7c9fa9004998e00000000
2019/02/15 19:34:48 HTTP POSTing template transaction to http://localhost:8080
2019/02/15 19:34:48 Got http status code: 400
2019/02/15 19:34:48 Http response body: got an internal error
2019/02/15 19:34:48 got http error from server

みたいな感じでエラーになってしまいます。

存在しているaddressなのに、https://github.com/RHavar/bustapay/blob/b69a49d0b658c01c6cf133212d5505e62bdadef6/rpc-client/rpc-client.go#L344 のgetaddressinfoでInvalid addressがかえってきてしまいそれ以上先に進めませんでした… btcsuiteの作ったパッケージを使っているので、btcdじゃないとうまくできないのでしょうか…


お知らせ
■ブロックチェーンエンジニア集中講座開講中!
HashHubではブロックチェーンエンジニアを育成するための短期集中講座を開講しています。お申込み、詳細は下記のページをご覧ください。
ブロックチェーンエンジニア集中講座:https://www.blockchain-edu.jp/
■フレセッツ株式会社では仮想通貨の事業者向け BtoB ウォレットの開発をしていただけるエンジニアを募集しています!詳しくはこちら→https://fressets.com/career/
■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。
HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo