アトミックスワップを実例を用いて紹介する

2017年も後半になり、アトミックスワップやインターオペラビリティがいよいよ盛り上がってきた感じがします。このブログでも度々DEX(分散型取引所)を取り上げているように、中央集権的な主体を介さない暗号通貨の交換は”いずれ必要になる”と思っており、強い関心を持っています。アトミックスワップは異なるブロックチェーン間(例えばビットコインとライトコイン)に存在するコインを取引所を介さずに直接交換する仕組みです(ただし現状どのペアでもアトミックスワップが実現できるわけではありません)。

アトミックスワップは、回転扉の対角線上に交換する品を一つずつ置き、半回転させることによって回転扉内に品物を固定し、更に同じ方向に回転させることで自分の品物と相手の品物の交換を、反対に回転させることで自分の品物の回収を行うようなイメージです(厳密性を捨てた説明です)。

例えばビットコイン保有者とライトコイン保有者が互いのコインを取引所を介さずに交換する場合、まず片方がビットコインを送り、ビットコインの受け取りが完了したら、他方がライトコインを送る方法が考えられますが、実際にライトコインを送ってもらえるかは相手次第で、逃げられる可能性もあります。これはエスクローと呼ばれる第三者を介在させる場合も同様で、エスクローサービスを提供する主体を信用する必要があります。

これらの問題を回避しつつ、直接コインの交換を実現させるのがアトミックスワップです。アトミックスワップに関する記事は日本語でも分かりやすい記事が提供されているのですが、私はアトミックスワップの肝となる「秘密情報のハッシュ値の管理とその秘密情報の公開(ブロードキャスト)」の部分で躓いてしまったため、こちらでも簡単にまとめたいと思います。

アトミックスワップの簡潔な手順は『Atomic cross-chain trading – Bitcoin Wiki』をご覧下さい。

BitcoinとDecredのアトミックスワップ実例

以下では実際に行われたビットコインとDecredのアトミックスワップの事例を用いて全体の流れを見ていきます。以下の図はアトミックスワップの一連の流れを示していますが、現時点で意味不明でも問題ありません。

GitHub – decred/atomicswap: On-chain atomic swaps for Decred and other cryptocurrencies.

必要なコマンド

DecredのGitHubの情報によれば、ビットコイン↔Decred間のアトミックスワップには以下のコマンドが用いられています。

Commands:
  initiate <participant address> <amount>
  participate <initiator address> <amount> <secret hash>
  redeem <contract> <contract transaction> <secret>
  refund <contract> <contract transaction>
  extractsecret <redemption transaction> <secret hash>
  auditcontract <contract> <contract transaction>

一つずつ見ていきましょう。

initiate <participant address> <amount>

アトミックスワップは、2つのコインをほぼ同時に交換するものですが、交換者はInitiatorとParticipantに分かれており、順番が決められています。最終的に所定の条件で交換がなされるので、結果的には順番は重要ではないのですが、手順として順番は重要です。

この例ではInitiatorのBTCとParticipantのDCRを交換します。

このコマンドはInitiatorによって実行され、コントラクトが48時間のロックタイム付きで生成されます。ロックタイムはアトミックスワップが何らかの理由で結果的に実行されなかった場合に、リファンドを行うために必要になります。

またこのコマンドは、片方のブロックチェーン(この例の場合はビットコインのブロックチェーン)上で実行されます。

実例を見てみましょう。

$ btcatomicswap --testnet --rpcuser=user --rpcpass=pass initiate n31og5QGuS28dmHpDH6PQD5wmVQ2K2spAG 1.0
Secret:      3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16
Secret hash: 29c36b8dd380e0426bdc1d834e74a630bfd5d111

Contract fee: 0.0000744 BTC (0.00020000 BTC/kB)
Refund fee:   0.00000281 BTC (0.00001018 BTC/kB)

Contract (2MwQAMPeRGdCzFzPy7DmCnQudDVGNBFJK8S):
63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a914ebcf822c4a2cdb5f6a6b9c4a59b74d66461da5816704d728bd59b17576a91406fb26221375b1cbe2c17c14f1bc2510b9f8f8ff6888ac

Contract transaction (346f4901dff1d69197850289b481f4331913126a8886861e7d5f27e837e0fe88):
010000000267864c7145e43c84d13b514518cfdc7ca5cf2b04764ed2672caa9c8f6338a3e3010000006b483045022100901602e523f25e9659951d186eec7e8b9df9d194e8013fb6d7a05e4eafdbb61602207b66e0179a42c54d4fcfca2b1ccd89d56253cc83724593187713f6befb37866201210288ef714849ce7735b64ed886d056b80d0a384ca299090f684820d31e7682825afeffffff3ac58ce49bcef3d047ea80281659a78cd7ef8537ca2bfce336abdce41450d2d7000000006b483045022100bd1246fc18d26a9cc85c14fb60655da2f2e845af906504b8ba3acbb1b0ebf08202201ec2cd5a0c94e9e6b971ec3198be0ff57e91115342cd98ccece98d8b18294d86012103406e35c37b3b85481db7b7f7807315720dd6486c25e4f3af93d5d5f21e743881feffffff0248957e01000000001976a914c1925e7398d325820bba18726c387e9d80047ef588ac00e1f5050000000017a9142d913627b881255c417787cc255ccad9a33ce48d8700000000

Refund transaction (45c7c175f333981508229f6fa637410fbbf4f086b657035c07adda6a49207e03):
000000000188fee037e8275f7d1e8686886a12131933f481b48902859791d6f1df01496f3401000000bf4830450221009344b17316054eae5d293b34683177fa5e7c7ba9b0001ebb2b3deca83bef552e022067088b7342bed0155b2ccef69d97cd293faa687f589d2a351aa6e154953c0c65012103a3a9f2c0492a40b134363e82959fa6132b86e0969e0b25109beb53b1debc4324004c5163a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a914ebcf822c4a2cdb5f6a6b9c4a59b74d66461da5816704d728bd59b17576a91406fb26221375b1cbe2c17c14f1bc2510b9f8f8ff6888ac0000000001e7dff505000000001976a914f5261c9e58aaa9461923c3f78f8f12f0eec22ed388acd728bd59

Publish contract transaction? [y/N] y
Published contract transaction (346f4901dff1d69197850289b481f4331913126a8886861e7d5f27e837e0fe88)

このコマンドはInitiatorによって実行されるコマンドであることを念頭に置いた上で、最初の行に注目して下さい。

initiate n31og5QGuS28dmHpDH6PQD5wmVQ2K2spAG 1.0

「n31og5QGuS28dmHpDH6PQD5wmVQ2K2spAG 」がInitiatorのアドレスではなく、Participantのアドレスであることに注意して下さい。Initiatorは自分のアドレスではなく、相手のアドレスをここで指定しています。もちろん、アトミックスワップを実行する前に、InitiatorとParticipantはそれぞれアドレスを用意しておく必要があります。

また二行目と三行目のSecretとSecret hashの存在を覚えておいて下さい。

 auditcontract <contract> <contract transaction>

次にParicipantはコントラクトとコントラクトトランザクションを監査する必要があります。そのためにauditcontractコマンドを実行します。実例を確認しましょう。

$ btcatomicswap --testnet auditcontract 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a914ebcf822c4a2cdb5f6a6b9c4a59b74d66461da5816704d728bd59b17576a91406fb26221375b1cbe2c17c14f1bc2510b9f8f8ff6888ac 010000000267864c7145e43c84d13b514518cfdc7ca5cf2b04764ed2672caa9c8f6338a3e3010000006b483045022100901602e523f25e9659951d186eec7e8b9df9d194e8013fb6d7a05e4eafdbb61602207b66e0179a42c54d4fcfca2b1ccd89d56253cc83724593187713f6befb37866201210288ef714849ce7735b64ed886d056b80d0a384ca299090f684820d31e7682825afeffffff3ac58ce49bcef3d047ea80281659a78cd7ef8537ca2bfce336abdce41450d2d7000000006b483045022100bd1246fc18d26a9cc85c14fb60655da2f2e845af906504b8ba3acbb1b0ebf08202201ec2cd5a0c94e9e6b971ec3198be0ff57e91115342cd98ccece98d8b18294d86012103406e35c37b3b85481db7b7f7807315720dd6486c25e4f3af93d5d5f21e743881feffffff0248957e01000000001976a914c1925e7398d325820bba18726c387e9d80047ef588ac00e1f5050000000017a9142d913627b881255c417787cc255ccad9a33ce48d8700000000
Contract address:        2MwQAMPeRGdCzFzPy7DmCnQudDVGNBFJK8S
Contract value:          1 BTC
Recipient address:       n31og5QGuS28dmHpDH6PQD5wmVQ2K2spAG
Author's refund address: mg9sDLhfByfAWFo4zq3JZ7nsLfsN59XPue

Secret hash: 29c36b8dd380e0426bdc1d834e74a630bfd5d111

Locktime: 2017-09-16 13:36:23 +0000 UTC
Locktime reached in 47h56m54s

これにより受付アドレス(Recipient address)にParticipant自身のアドレス「n31og5QGuS28dmHpDH6PQD5wmVQ2K2spAG」が指定されていること、BTCの総量が1であること、ロックタイムが適切に設定されていることなどを確認することが出来ます。またsecret hashも取得されています。問題がなければ次の手順に移ります。

participate <initiator address> <amount> <secret hash>

こちらはParticipantによって実行されるコマンドです。先程のブロックチェーンとは別のブロックチェーン(この例の場合、Decredのブロックチェーン)上で行われることに注意して下さい。initiateコマンド同様に、participateコマンドではinitiatorのアドレスとDecredの総量が指定されます。

最後にsecret hashなるものが指定されています。secret hashは先程のauditコマンドで取得しました。ここでは「secretからsecret hashを導くことはできるが、secret hashからsecretを導くことはできない」というように理解しておいて下さい。

こちらのコントラクトでは24時間のロックタイムが設定されます。

実例を確認しましょう。

$ dcratomicswap --testnet participate TsfWDVTAcsLaHUhHnLLKkGnZuJz2vkmM6Vr 1.0 29c36b8dd380e0426bdc1d834e74a630bfd5d111
Passphrase:

Contract fee: 0.000251 DCR (0.00100400 DCR/kB)
Refund fee:   0.000301 DCR (0.00100669 DCR/kB)

Contract (TcZpybEVDVTuoE3TCBxW3ui12YEZWrw5ccS):
63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac

Contract transaction (a51a7ebc178731016f897684e8e6fbbd65798a84d0a0bd78fe2b53b8384fd918):
010000000137afc6c25b027cb0a1db19a7aac365854796260c4c1077e3e8accae5e4c300e90300000001ffffffff02441455980100000000001976a9144d7c96b6d2360e48a07528332e537d81e068f8ba88ac00e1f50500000000000017a914195fb53333e61a415e9fda21bb991b38b5a4e1c387000000000000000001ffffffffffffffff00000000ffffffff6b483045022100b30971448c93be84c28b98ae159963e9521a84d0c3849821b6e8897d59cf4e6c0220228785cb8d1dba40752e4bd09d99b92b27bc3837b1c547f8b4ee8aba1dfec9310121035a12a086ecd1397f7f68146f4f251253b7c0092e167a1c92ff9e89cf96c68b5f

Refund transaction (836288fa26bbce52342c8569ca4e0db7dec81b2187eb453c1fd5c5d06838f60a):
000000000118d94f38b8532bfe78bda0d0848a7965bdfbe6e88476896f01318717bc7e1aa5010000000000000000016c6bf5050000000000001976a9140b4dae42b84dbad7b7e35f61602cb6a2393f0ae088ace6dabb590000000001ffffffffffffffff00000000ffffffffbe47304402201bd55803eae6de4ea19c618060f82c38e9ca04047c346dc7025f54d8276f13f602205cdf104db74563559e570f186cbc68549d623618b96c7ec971d1a996dab78fbd01210244e4e75a9318ac06656d145c3d3205b2f4f25615698f458e80233c4bb78c91ac004c5163a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac

Publish contract transaction? [y/N] y
Published contract transaction (a51a7ebc178731016f897684e8e6fbbd65798a84d0a0bd78fe2b53b8384fd918)

一行目でInitiatorのアドレス、DCRの総量、そしてsecret hashが指定されていることが確認できます。こちらはParticipantによって実行されるコマンドでした。

participate TsfWDVTAcsLaHUhHnLLKkGnZuJz2vkmM6Vr 1.0 29c36b8dd380e0426bdc1d834e74a630bfd5d111
Passphrase:

ParticipantがInitiatorのコントラクトを確認したように、InitiatorもParticipantのコントラクトをauditcontractコマンドを用いて確認します。

$ dcratomicswap --testnet auditcontract 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac 010000000137afc6c25b027cb0a1db19a7aac365854796260c4c1077e3e8accae5e4c300e90300000001ffffffff02441455980100000000001976a9144d7c96b6d2360e48a07528332e537d81e068f8ba88ac00e1f50500000000000017a914195fb53333e61a415e9fda21bb991b38b5a4e1c387000000000000000001ffffffffffffffff00000000ffffffff6b483045022100b30971448c93be84c28b98ae159963e9521a84d0c3849821b6e8897d59cf4e6c0220228785cb8d1dba40752e4bd09d99b92b27bc3837b1c547f8b4ee8aba1dfec9310121035a12a086ecd1397f7f68146f4f251253b7c0092e167a1c92ff9e89cf96c68b5f
Contract address:        TcZpybEVDVTuoE3TCBxW3ui12YEZWrw5ccS
Contract value:          1 DCR
Recipient address:       TsfWDVTAcsLaHUhHnLLKkGnZuJz2vkmM6Vr
Author's refund address: Tsh9c9aytRaDcbLLxDRcQDRx66aXATh28R3

Secret hash: 29c36b8dd380e0426bdc1d834e74a630bfd5d111

Locktime: 2017-09-15 13:51:34 +0000 UTC
Locktime reached in 23h58m10s

総量が1DCRであることやRecipient addressがInitiatorのアドレスになっていること、ロックタイムが適切に設定されていることが確認できます。

redeem <contract> <contract transaction> <secret>

redeemコマンドはロックされたコインを手に入れるために実行されます。InitiatorとParticipantの両方によって実行されますが、まずはInitiatorによって実行されます。redeemコマンドの実行にsecretが必要になっている点に注目して下さい。先述の通り「secretからはsecret hashが導ける」のでした。このsecretはInitiatorのみが知っており、Participantは知りません。しかしsecretを公開しなければ、Initiatorはredeemコマンドを実行することができず、DCRを手に入れることが出来ません。そしてParticipantは公開されたsecretを用いてBTCを手に入れることができます。

実例を見てみましょう。

$ dcratomicswap --testnet redeem 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac 010000000137afc6c25b027cb0a1db19a7aac365854796260c4c1077e3e8accae5e4c300e90300000001ffffffff02441455980100000000001976a9144d7c96b6d2360e48a07528332e537d81e068f8ba88ac00e1f50500000000000017a914195fb53333e61a415e9fda21bb991b38b5a4e1c387000000000000000001ffffffffffffffff00000000ffffffff6b483045022100b30971448c93be84c28b98ae159963e9521a84d0c3849821b6e8897d59cf4e6c0220228785cb8d1dba40752e4bd09d99b92b27bc3837b1c547f8b4ee8aba1dfec9310121035a12a086ecd1397f7f68146f4f251253b7c0092e167a1c92ff9e89cf96c68b5f 3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16
Passphrase:

Redeem fee: 0.000334 DCR (0.00100300 DCR/kB)

Redeem transaction (53c2e8bafb8fe36d54bbb1884141a39ea4da83db30bdf3c98ef420cdb332b0e7):
000000000118d94f38b8532bfe78bda0d0848a7965bdfbe6e88476896f01318717bc7e1aa50100000000ffffffff01885ef5050000000000001976a9149551ab760ba64b7e573f54d34c53506676e8145888ace6dabb590000000001ffffffffffffffff00000000ffffffffe0483045022100a1a3b37a67f3ed5d6445a0312e825299b54d91a09e0d1b59b5c0a8baa7c0642102201a0d53e9efe7db8dc47210b446fde6425be82761252ff0ebe620efc183788d86012103395a4a3c8c96ef5e5af6fd80ae42486b5d3d860bf3b41dafc415354de8c7ad80203e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16514c5163a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac

Publish redeem transaction? [y/N] y
Published redeem transaction (53c2e8bafb8fe36d54bbb1884141a39ea4da83db30bdf3c98ef420cdb332b0e7)

redeemコマンドの実行によってInitiatorはDCRを手に入れました。コマンドの実行によりsecretが公開され、Participantはsecretを手に入れられるようになりました。

実際のトランザクションはこちらをご覧下さい。
Decred Transaction 53c2e8b… | Decred Block Explorer

Detailの部分にsecretである「3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16」が公開されていることが確認できます。

extractsecret <redemption transaction> <secret hash>

extractsecretコマンドはParticipantがInitiatorのsecretを取得する際に用いられます。

$ dcratomicswap --testnet extractsecret 000000000118d94f38b8532bfe78bda0d0848a7965bdfbe6e88476896f01318717bc7e1aa50100000000ffffffff01885ef5050000000000001976a9149551ab760ba64b7e573f54d34c53506676e8145888ace6dabb590000000001ffffffffffffffff00000000ffffffffe0483045022100a1a3b37a67f3ed5d6445a0312e825299b54d91a09e0d1b59b5c0a8baa7c0642102201a0d53e9efe7db8dc47210b446fde6425be82761252ff0ebe620efc183788d86012103395a4a3c8c96ef5e5af6fd80ae42486b5d3d860bf3b41dafc415354de8c7ad80203e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16514c5163a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac 29c36b8dd380e0426bdc1d834e74a630bfd5d111
Secret: 3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16

secretが取得されます。取得したsecretを用いることによってParticipantもredeemコマンドを実行できるようになりました。

$ btcatomicswap --testnet --rpcuser=user --rpcpass=pass redeem 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a914ebcf822c4a2cdb5f6a6b9c4a59b74d66461da5816704d728bd59b17576a91406fb26221375b1cbe2c17c14f1bc2510b9f8f8ff6888ac 010000000267864c7145e43c84d13b514518cfdc7ca5cf2b04764ed2672caa9c8f6338a3e3010000006b483045022100901602e523f25e9659951d186eec7e8b9df9d194e8013fb6d7a05e4eafdbb61602207b66e0179a42c54d4fcfca2b1ccd89d56253cc83724593187713f6befb37866201210288ef714849ce7735b64ed886d056b80d0a384ca299090f684820d31e7682825afeffffff3ac58ce49bcef3d047ea80281659a78cd7ef8537ca2bfce336abdce41450d2d7000000006b483045022100bd1246fc18d26a9cc85c14fb60655da2f2e845af906504b8ba3acbb1b0ebf08202201ec2cd5a0c94e9e6b971ec3198be0ff57e91115342cd98ccece98d8b18294d86012103406e35c37b3b85481db7b7f7807315720dd6486c25e4f3af93d5d5f21e743881feffffff0248957e01000000001976a914c1925e7398d325820bba18726c387e9d80047ef588ac00e1f5050000000017a9142d913627b881255c417787cc255ccad9a33ce48d8700000000 3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16
Redeem fee: 0.00000314 BTC (0.00001016 BTC/kB)

Redeem transaction (c49e6fd0057b601dbb8856ad7b3fcb45df626696772f6901482b08df0333e5a0):
000000000188fee037e8275f7d1e8686886a12131933f481b48902859791d6f1df01496f3401000000e0483045022100f43430384ca5ecfc9ca31dd074d223836cef4801b3644c651c3a30d80fbf63b8022017dae9e7ec6f3f5ee0e0b60d146963ba85d9b31003d7f60852126f2a35492759012103b10e3690bcaf0eae7098ec794666963803bcec5acfbe6a112bc8cdc93797f002203e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16514c5163a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a914ebcf822c4a2cdb5f6a6b9c4a59b74d66461da5816704d728bd59b17576a91406fb26221375b1cbe2c17c14f1bc2510b9f8f8ff6888acffffffff01c6dff505000000001976a914e1fce397007bad3ce051f0b1c3c7587f016cd76a88acd728bd59

Publish redeem transaction? [y/N] y
Published redeem transaction (c49e6fd0057b601dbb8856ad7b3fcb45df626696772f6901482b08df0333e5a0)

一行目でsecret「3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16」が用いられていることは分かります。

これでアトミックスワップは完了です。この例はテストネット上で行われたものですが、Decredはライトコインとのアトミックスワップをメインネット上で成功させています。

redeemコマンドによって最初にコインを手に入れるのはInitiatorですが、Initiatorがコインを手に入れるためには、Participantがコインを手に入れるために必要なsecretを公開しなければならない点に再度注目して下さい。

またコントラクトのRecipient addressは既に固定されているため、誰かがコインを盗むためにsecretを用いてRecipient addressとして設定されていないアドレスにコントラクトのコインを移動させることはできません。Initiatorがsecretを公開しない場合、コントラクトのコインは一定時間経過後リファンドされます。

つまりアトミックスワップは、実行有効期限を設定した上で、送信先アドレスを固定したコントラクトを2つ用意し、2つのコントラクトの片方だけを実行することができないような仕組みになっています。言い換えれば、コインのリファンドか2つのコントラクトの実行かのいずれかしか実現しないような構造になっています。このAtomicityがアトミックスワップと言われる所以ですね。

アトミックスワップの今後

今回說明したアトミックスワップはオンチェーンで行われるものですが、オフチェーンでのクロスチェーントランザクションも実現可能で、先日Lightning Labsよりビットコインとライトコインのテストネット上でライトニングクロスチェーンアトミックスワップが成功したことが発表されました

アトミックスワップは脱中央集権的取引所や政府規制耐性のためには非常に重要で且つ技術的にも興味深い仕組みです。DEXシリーズ『これから「分散型取引所」の話をしよう』でも述べているように、今後スワップ部分のみならず、取引所における板情報を担うオラクルのようなものが出てくると、アトミックスワップの活用はますます現実味を帯びて来るでしょう。


    atomicswap/README.md at master · decred/atomicswap · GitHub

    Atomic cross-chain trading – Bitcoin Wiki