Taro
何やらLN上でステーブルコインとNFTが発行できるらしい
Lightning Labsが開発中
News を読んだ感じだとLNと同様にセキュリティを担保しながら、カラードコインが扱えるようになっていそう。
Taprootを利用して実現しているらしい。
マルチホップトランザクションで機能するため、中間のノードが別のアセットしか持っていなかったとしても送金ができる。
https://scrapbox.io/files/625d3c548154f200236c5eb7.png
news を読んだだけでは詳しい部分が見えてこなかったのでBIPを見てみる
概要
この文書では、Bitcoin ブロックチェーンの上に構築された Taproot ネイティブアセットオーバーレイである Taro について説明します。Taro は、ベースチェーンを肥大化させることなく、ビットコインの上に任意の(通常および収集品)資産を表現することを可能にします。プロトコルは、Taro資産と相互作用するトランザクションが、BitcoinブロックチェーンのPoVから通常のトランザクションと区別されないように設計されています。Taroは基本的なTaprootスクリプトツリーを拡張し、ネストされたアセットスクリプトツリー(merkle-sum sparse merkle tree、MS-SMT)を用いて、有効な証人にコミットし、取引グラフ全体における資産の移動を証明できる構造化メタデータを提供する。Taro資産の移動の証明は、フラットファイルとして送信される密閉証明、または外部で管理されるユニバースの助けを借りて検証することができます。ユニバースは、オンチェーン資産の発行と移動をインデックス化するMS-SMTで、リザーブ証明/供給システムをネイティブでサポートしています。
Taroは、ライトニングチャンネル(BOLTプロトコルスイートベース)上のオフチェーンシングルホップおよびマルチホップ転送をサポートし、後者はTaro独自の組み込みアセットスクリプトシステムを使用して明示されます。Taroのオンチェーン送金のライトクライアント検証は、オンチェーンおよびオフチェーンの一連のマルクル証明によって促進され、アクティブなUniverseインスタンスに信頼関係を委任することで圧縮することができます。通常の資産のオフチェーン転送をサポートするために、オフチェーンマルチパーティチャネルのバリエーションが提案されています。さらに、ポケットユニバースと呼ばれる特殊なタイプのユニバースは、出口のみのコミットチェーン設計に基づいており、トラスト最小化された方法でオンチェーンでの転送を集約するために使用することができます。
動機
最初の分散型ブロックチェーンであるビットコインは、その初期に、ビットコインのシステム自体の制約の中で任意の資産を表現しようとするいくつかのシステムを実現しました。これらのシステムの中で最も初期のものは、Mastercoin(現在は OMNI として知られています)と Counterparty で、これらは、システム内の資産の生の表現と転送をコミットするために OP_RETURN を使用した Bitcoin の上に構築されたメタトークンプロトコルです。オムニやその他の関連システムの作成と展開から数年後、これらのシステム内で行われる活動はほとんどなく、代わりに、すべてを始めたチェーンであるビットコインに直接戻る系統のない何十もの新しいブロックチェーンに分散しています。
Taroの目標は、聖火を運び、ビットコイン上で任意の資産を表現し操作するシステムを実現することです。これは、現代のブロックチェーン設計原理を反映し、ビットコインの開発者が親しみやすい、Taprootから着想を得たデータ構造とプロトコルフローを提供するものです。重要なのは、このようなシステムは、ベースチェーンが拡張不可能なオーバーレイプロトコルによって肥大化しないように、オフチェーン設定で動作するようにゼロから設計されていなければならないということです。明確な仕様によって、私たちはこのシステムをエコシステムに広く採用させ、既存の十分に配分されていない開発者の興奮とリソースを活性化させることを目的としています。
ビットコインの開発者がプライベートでスケーラブルな方法で任意の資産を簡単に表現し操作できるようにすることで、ビットコインシステムの有用性を高めることを目指し、それによってブロック補助金がゼロに漸近する環境でシステムが繁栄できることを確実にするために必要なブロックスペースの追加需要を発生させることができるのです。
デザイン
このセクションでは、Taroプロトコルが構成する基本的なデータ構造と概念について、ハイレベルな概要を説明します。Taroは、タップルートのスクリプトツリー内の任意の非スクリプトデータにコミットするという単純なアイデアから始まり、このアイデアを基に、Bitcoinチェーンに固定された任意の資産のためのオーバーレイプロトコルを構築します。
Merkle-Sum Sparse Merkle Trees(マークルサムスパースマークルツリー
マークルツリーは、要素のリストに対する認証されたデータ構造である。ディレクトリの中身を取り出し、あるファイルがそのディレクトリに属していることを証明するためのルートハッシュを作成するようなことができる。各要素は下から順にペアハッシュ化され、1つのハッシュが存在するようになる。このハッシュをルートハッシュと呼ぶ。
マークルサムツリーはマークルツリーの変形であり、ハッシュ操作は与えられた属性の合計にもコミットする。上の例を拡張して、各ファイルのサイズをコミットすることができる。ルートハッシュは左のサブツリー、右のサブツリー、そして左と右のサブツリーのサイズの合計をコミットする。この新しい形式は、ファイルの存在とそのサイズの両方を証明することができるので、便利です。また、サブディレクトリの大きさの証明を生成するようなこともできる。
マークルサムツリーで簡単にできないことの1つは、非存在の証明である。項目が正準ソートされていない場合、非存在を証明するにはツリーのすべての葉を明らかにする必要があるからである。マークル木の葉の集合を並べ替えると、非存在をより簡単に証明できるようになるが、新しい項目が挿入されるたびに木のバランスを取り直す必要があるというオーバーヘッドが生じる。Taroの設定では、資産の売り手がもはやその資産にコミットしていないことを証明したい場合があるため、非存在の証明は有用である。
スパース・マークル・ツリーは、一連のキー・バリュー・ペアに対するマークル・ツリーの「シミュレーション」であり、非包含の証明を効率的に行うことができる。SMTは実際には鍵空間全体(256ビットの値すべて)から構成され、2^256の葉を持つ木である(つまり256のレベルを持つ)。この構造の表現は、空の要素のハッシュ、2つの空の部分木を持つ枝のハッシュ、などを知ることで扱いやすくなる。さらに、一連のキャッシュ戦略を用いることで、より効率的な表現が可能となる。また、証明の中間枝が空の部分木にコミットした場合に通知するビットマップを追加することで、証明をさらに圧縮することができる。
Merkle-Sum Sparse Merkle Treeは、SMTであり、sum-combinerの特徴も受け継いでいる。このデータ構造を用いて、可分資産の分割を簡単に検証したり、非包含の証明をサポートしたり、また、太郎資産の証明を簡単に検証するためのマークル化ルックアップテーブルとして使用します。
この文書で言及するMS-SMTは、BIP bip-taro-smt.mediawikiで完全に規定されています。
Taro資産ツリー
Taroは、Bitcoinブロックチェーンをベースにして、収集品や通常の資産を作成し、転送するために使用できるTaprootネイティブの資産オーバーレイです。アセットは、既存のTaprootスクリプトツリー内の構造化データへのコミットメントとして表示されます。この構造化データは、ベースチェーン自体にプレーンで書き込まれることはなく、代わりにTaroオーバーレイプロトコルによって上位レイヤーに維持されます。資産自体は、メイン資産ツリー内の一連のMS-SMT(各資産ID/タイプに1つずつ)で表されます。各アセットは(他の多くの属性に加えて)アセットスクリプトハッシュにコミットし、そのスクリプトは、TaroオーバーレイプロトコルのPoVからアセットを転送することを許可する方法を正確に制限するアセットスクリプトにコミットします。このシステムの初期バージョンでは、ビットコインスクリプトのサブセットを使用して、アセットの有効な転送に関する任意の条件を表現できるようにしています。
Taroのアセットリーフはそれによって、ベースとなるBitcoinブロックチェーン上のUTXOのプログラム上のミラーとなります。与えられたTaroアセットの検証者は、無効な状態遷移を拒否します。これは、ライトニング上でマルチホップのオフチェーン転送を促進するための重要な要件です(アセットスクリプトに埋め込まれたHTLCを経由して)。
アセット・プロベナンス
アセットの証明は、2つのメカニズムのうちの1つを使用して行われます。1つは、「フルプルーフ」と呼ばれるもので、最初の生成出力から連続した証明を含む構造化ファイルで、一連の有効な資産の証人が、タップルート出力間で資産の所有権を検証可能に転送するものです。フルプルーフは通常、Taroプロトコルで消費、検証、表示するためのフラットファイルとして表現される。
出所の証明・検証を行う2つ目の方法は、少し異なる構造のMS-SMTで、これもタップルートのスクリプトツリー内にコミットされる。このメタ構造は、追加の証明データとともにチェーン内のTaroコミットメントにコミットするため、ユニバースと呼ぶことにします。Universeは、実績検証のブートストラップとして使用できるKey-Valueストアです(対象アセットのセットを作成した人たちによって維持されます)。ユニバースは、最初の出所検証の他に、MS-SMT内のすべての有効なタロ資産の転送を記録し、資産識別子とその資産の最後の既知の有効な転送を対応付けることで、スケーラビリティ層として機能することも可能である。
マークルサムベースの埋蔵量証明
MS-SMTデータ構造の使用により、システムは効率的な供給/非インフレの証明をサポートし、参加者は与えられたタップルート出力内でコミットした資産の総量と、与えられたユニバースによる発行資産の総セットを容易に検証することができます。SMTのマークルサム拡張により、アセットは分割可能である一方、検証者は、通常のビットコイン取引と同様に、特別に作られたアセット生成取引以外の転送中に新しいアセットが生成されないことを主張することができるようになります。
分割、合併、収集品、通常の分割可能な資産
TAROは、収集品と通常の分割可能な資産を表現することができます。通常のアセットでは、保有するアセットの合計値をコミットし、通常のビットコインUTXOと同様のツリー内で分割したり、トップレベルのTaproot出力にまたがって分割したりすることが可能です。これを内部分割、外部分割と呼ぶ。通常のアセットも、ベースレイヤーでのUTXOの統合と同様のプロセスで、統合することが可能です。アセットを譲渡する際、アセット所有者は有効な分割を保持していることを(マークルサム証明によって)証明し、作成された各アセットは新しいマークルサム出力分割セットにコミットして、譲渡時の非インフレを強制する。
一方、コレクターズアイテムは分割も統合もできません。通常、一括して作成され、チェーンレベルまたは実世界のアセット/機能(既存の信頼関係を前提とする)に対するクレーム/クレデンシャルを表現するものです。コレクションの例としては、野球カードやトレーディングカードゲームなどの限定版デジタルコレクティブルのシリーズが挙げられます。
通常のアセットはライトニングネットワークを使用してマルチホップ方式でオフチェーンに転送できますが、コレクターズアセットはオフチェーンに転送するか、マルチパーティチャネルにリフトして既知の参加者の間で転送を許可する必要があります。
仕様
アセットツリー表現
アセットルートのコミットメント
Taroのアセットツリーは、システムの中核をなす要素である。アセット・ツリーは、一連の資産識別子に対するMS-SMTのコミットメントであり、その起源となる資産IDによってグループ化されています。あるTaro資産ツリーは、2つのネストしたMS-SMTインスタンスで構成されています。
最初のレベルは、asset_idまたはasset_key_familyを、与えられたアセットのサブツリールートハッシュにマッピングします。
2番目のレベルは、asset_script_keyまたはasset_id || asset_script_keyを、シリアライズされたTaro資産のリーフにマッピングします。
BIP-341を観察すると、アセットツリーのルートハッシュは、1つのリーフを持つTapscriptツリーとして表現されています。
tagged_hash("TapLeaf", leaf_version || taro_version || asset_tree_root)。
leaf_versionの「?」が選択される。BitcoinシステムのPoVからすると、単にパース不能なScriptを持つtapscriptの葉にコミットしたことになります。将来的に、BitcoinシステムがTaro特有のコミットを意識してソフトフォークされた場合、同じまたは異なるリーフバージョンを使用して新しい動作の検証をゲートすることができます。
asset_idは、32バイトのハッシュ値です。
sha256(genesis_outpoint || asset_tag || asset_meta) のハッシュです。
ここで
genesis_outpoint は、Bitcoin wire 形式でシリアライズされたアセットジェネシストランザクションで使用された最初の前の入力 outpoint です。
asset_tagは、与えられた資産を表すランダムな32バイトの値であり、一連の個別の資産を単一の資産ファミリーにリンクさせるために使用することができます。実際には、これは通常、人間が読める資産名のハッシュとなります。
asset_metaは不透明な32バイトの値で、外部リンク、ドキュメント、統計情報、属性、画像など、さまざまなメタデータにコミットするために使用されます。重要なのは、このフィールドは不変であると考えられていることです。
上記の構造を考えると、asset_idは、BIP34のおかげで、ブロックチェーン内で一度シリアライズされたアウトポイントは決して繰り返すことができないので、チェーンのPoVからグローバルに一意であることが保証されています。
さらに、我々は、与えられた出力は単一のルートTaro資産のコミットメントを持たなければならないというルールを強制します(資産の証人が入力アウトポイントにバインドする方法によって、他の重複は使用することができません)。
asset_tagフィールドは、グローバルに一意であることを強制することはできません。その代わり、最初のアセット作成時にローカルで一意なasset_idインスタンスを確保するために、各asset_tagとasset_meta値はアセット作成時に一度だけ出現しなければなりません(MUST)。
トップレベルのMS-SMTは、保持されているすべての定義済みアセットの集合にコミットします。このMS-SMTのツリーのルートハッシュはasset_tree_rootと呼ばれる。MS-SMTは以下のような構造になっている。
キー:asset_idまたはasset_key_family
値: taro_version || asset_id_tree_root || asset_sum
sum_value:asset_sum(アセットサム
asset_idと同様に、asset_key_familyは、システム内での一意性を確保するために、一種の連鎖的ランダム性として、最初の入力アウトポイントを使用して導出されます。genesis_outpointと公開鍵asset_key_internalが与えられると、asset_key_familyは次のように導出されます。
asset_key_family = asset_key_internal + sha256(asset_key_internal||genesis_outpoint)となります。
トップレベルツリーは、与えられた資産の集合の存在、保有する資産単位の総量、保有する資産の総和を簡単に証明することができる。
asset_id_tree_rootの値は、それ自体が以下の構造を持つ別のネストされたMS-SMTである。
キー:asset_script_keyまたはasset_id|asset_script_key
値: asset_leaf || leaf_sum
sum_value: leaf_sum
与えられたasset_id_tree_rootをルートとするツリーが持つMS-SMTの中で、asset_idまたはasset_key_familyが持つ出力ごとに新しいTaro MS-SMTが作成される。MS-SMTの葉は、asset_script_keyまたはasset_id || asset_script_keyのロック解除スクリプトによってキーが設定されています。アセットツリーのルートハッシュは、次のどちらかで計算されます。
asset_tree_root = sha256(asset_id|left_hash|right_hash||sum_value)のいずれかです。
または
asset_tree_root = sha256(asset_key_family || left_hash || right_hash || sum_value)
ここで
asset_key_family は、genesis outpoint から派生した公開鍵の 32 バイトのハッシュで、互いに融通し合うことを意図した資産(同じ資産の複数のトランシェを発行)または収集品を配置するために使用されることができます。
asset_id は、上記で指定した32バイトのアセットIDです。
left_hash は、左側のサブツリーのハッシュです。
right_hashは右のサブツリーのハッシュである。
amt_sum は、各アセットリーフの amt 値の合計です (基本的にはアセットの UTXO です)。
-------------------------
ある資産に対して、ある資産サブツリー内の資産価値の合計をコミットすることで、資産保有者は自分がどれだけ資産を所有しているかを簡単に証明することができます。これは、資産の作成と「ユニバース」の概念と組み合わせると、埋蔵量の証明のメカニズムを組み込むことができます。
asset_key_familyの使用により、発行者は同じassetサブツリー内で互いに互換性のある資産を配置することができます(後述)。asset_key_familyの導出は、asset_idと同様に、この値がチェーン内でグローバルにユニークであることを保証しています。asset_key_familyを指定しないアセットでは、メインのMS-SMTにキーを入れるために若干異なるスキーマを使用し、単一のバッチでのみ発行することができます。
asset_key_familyが指定された場合、トップレベルSMTと同様に、内部MS-SMTは内部キーを変更し、各アセットの派生asset_idも考慮されます。その結果、最下位レベルの鍵はasset_idとasset_script_keyを考慮することになる。これにより、すべてのアセットとスクリプトのキーがMS-SMt内で一意の場所に配置されることが保証されます。
ツリーの構造上、有効なタップルート出力内の特定のタロ資産のサブツリーでは、すべてのasset_script_keyの値は一意でなければならないことに注意してください。
アセットリーフのフォーマット
アセットリーフはシリアル化されたTLVブロブで、次のようなキーと値のマッピングがあります。
type: 0 (taro_version)
value:
[u8:version]
type: 1 (asset_id)
value:
[32*byte:id_bytes]
type: 2 (asset_type)
value:
[u8:type]
type: 3 (amt)
value:
[BigSize:amt]
type: 3 (lock_time)
value:
[BigSize:block_height]
type: 4 (prev_asset_witnesses)
value:
[u16:num_inputs][asset_witnesses...], where:
[...*byte:asset_witnesses]:
[asset_witness]:
type: 0 (prev_asset_id)
value: [prev_outpoint || asset_id || asset_script_key]
type: 1 (asset_witness)
value: [...*byte:asset_witness]
type: 2 (split_commitment_proof)
value: [...*byte:split_proof]
type: 5 (split_commitment)
value: [32*byte:split_commitment_root]
type: 6 (asset_script_version)
value:
[u16:script_version]
type: 7 (asset_script_key)
value:
[33*byte:pub_key]
type: 8 (asset_family_key)
value:
[96*byte:pub_key || schnorr_sig]
ここで
taro_version: 使用されているTaroのバージョンを示す1バイトで、これによりクライアントは以下のTLV値のどれを期待するかを決定することができる。
asset_id: 上記で定義されたasset_idです。
asset_type:アセットタイプを表す1バイトで、2つの開始アセットタイプが定義されています。
0: 通常のアセット
1: 収集可能なアセット
amt: この葉の位置で保持されているアセットの量です。
lock_time:含まれるブロックの高さに基づき、アセットが移動できるタイミングを制限するフィールドです。
prev_asset_witnesses: ネストされたTLVで、ターゲットアセットリーフへのマージを確認するために必要なアセットの証人が含まれています。
prev_asset_id: トランザクション内の入力位置、以前のアセットツリーのアセットID、およびアセットスクリプトハッシュによって、以前のアセット入力を参照する。
この値は、バニラビットコインにおける以前のアウトポイントに類似した目的を果たす、アセットウィットネス自体の中で生成されたすべての署名に含まれます。
このフィールドがすべてゼロである場合、新しいアセットが作成されることを示します。
内部分割の検証のために、このフィールドは、他のすべての新しい分割をカバーする単一の署名/証人だけを含めることによってスペースを節約するために使用することができます。
このタイプが存在しない場合、split_commitment が存在しなければなりません(MUST)。
split_commitment_proof:アセット分割の結果として作成されたアセットUTXOの支出を許可するために使用されます。アセットが分割されると、非変更UTXOはMS-SMTツリー内の他のすべての分割位置にコミットされます。アセット分割の結果の変更UTXOを使用する場合、通常のasset_witnessは必要ありません。代わりに、変更アセットUTXOの所有者は、メイン転送トランザクションで承認された有効な分割を保持していることを証明する必要があります。
同じsplit_commitmentを持つ出力は、新しいアセット分割の結果であるため、1つのasset_witnessを共有すると言われています。したがって、転送を検証するために必要なのは、1人の証人とその結果のメルクルサム資産ツリーだけです。
asset_witness: は、BitcoinのSegwit witnessフィールドと同じフォーマットでシリアライズされた証人です。このフィールドは、prev_asset_idが空白の場合のみ、空白にすることができます。
split_commitment:通常のアセットに対する新しい出力スプリット分布にコミットし、その検証を許可するために使用されます。split_commitment_rootは、sha256(output_index || asset_id || asset_script_key)のキーを持つMS-SMTで、その値は新しいTaroアセットリーフとなります。これはオプションのフィールドで、転送中にアセット値が分割された場合にのみ指定されます。
同じsplit_commitmentを持つ出力は、新しいアセット分割の結果であるため、単一のasset_witnessを共有すると言われています。したがって、転送を検証するために必要なのは、単一のウィットネスとその結果のメルクルサムアセットツリーだけです。
asset_script_version: 2バイトのアセットスクリプトバージョンで、次のTLV値をどのように検証するかを指定します。
asset_script_key:このアセットリーフを包含するアセットスクリプトにコミットすることができるBIP 341の方法で得られた外部公開鍵である。
asset_family_key:BIP-340で定義される32バイトの公開鍵であり、asset_idに対する64バイトのBIP340署名が続く。このキーを使って、asset_idで識別される別個のアセットを関連付けることができ、ベースアセットをさらに発行することが効果的にできます。同じasset_family_keyを参照するアセットは、同じアセットとみなされます。これはオプションフィールドで、このフィールドを含まないアセットは事実上一回限りの発行イベントとみなされ、派生したasset_idに関連する更なるアセットを作成することはできないことを意味します。
(TODO(roasbeef): 入力セットに対するmerkle sumのコミットメントも同様に?)
asset_script_versionは、資産リーフのロック/アンロックに使用されるスクリプトシステムの将来のアップグレードを可能にするため、Taro資産リーフの重要な設計要素です。初期状態では、バージョン0のアセットリーフが使用され、BIP341およびBIP342で指定されているように、asset_script_keyが有効なoutput_keyであることを意味します。その結果、バージョン0のTaro VMは、アウターインスタンス内のTaprootのインスタンスとなります。asset_script_versionの検証ロジックは、BIP ?で完全に定義されています。将来的には、新しいアセットスクリプトのバージョンを導入して、埋め込まれたアセットスクリプトの表現力をさらに高めることができます。
この予約範囲以上の数値を持つ型は使用可能 2^16-1 以下の TLV 型は、追加の taro_version 反復で使用するために予約されている。この予約範囲以上の数値を持つ型は、アセットに任意の属性を保存するために使用することができます。このような属性の例としては、ゲーム内アセットの _mutable_ ステータスを格納することが挙げられます。ノーマルアセットやコレクティブルアセットの immutable フィールドは、代わりに asset_meta 内にコミットして、ゲーム内アセットの mutable stats を格納する必要があります。通常のアセットやユニークアセットのimmutableフィールドは、代わりにasset_metaフィールドにコミットされるべきです。
code:typo
Types with a numerical value above this reserved range can be used TLV types below 2^16-1 are reserved for use by additional taro_version iterations. Types with a numerical value above this reserved range can be used to store arbitrary attributes to assets. An eaxmple of such an attribute would be storing the _mutable_ stats of an in-game asset. Any immutable fields for normal or collectible assets should be instead committed to within the asset_meta be storing the mutable stats of an in-game asset. Any immutable fields for normal or unique assets should be instead committed to within the asset_meta field. Taroの資産ツリー自体にMS-SMTを使用することで、入力の参照時に新しい資産が作成されないこと、また、新しい分割/マージが有効な分割セットになることを簡単に検証できる(計算されたwitness sighashに含まれるsplit_commitment_rootを介して行われる)。
アセットクリエーション
アセットの作成は、他のビットコイン取引と似ていますが、通常は1入力1出力の取引になります。アセット作成トランザクションは任意のインプットセットを費やし、1つまたは複数のアウトプットを生成し、それは新しく作成されたアセットのセットにコミットする可能性があります。単純化したメカニズムとして、あるタロ・トランザクションは新しい資産を作成するか、既存の資産を転送するかだけで、両方はできないことを要求している。
(TODO(roasbeef):転送と作成を許可しないことは、実際に何かをより単純化するのでしょうか?)
次の関数は、新しい有効なtaproot公開鍵スクリプトを作成し、その内部tapscriptツリーは新しいアセットの表現にコミットします。
code:asset creation
create_new_asset_output(total_units: uint64, asset_tag: 32byte, genesis_point: 36byte, asset_meta: 32byte, asset_type: uint8, asset_script_key: 32byte, taro_attrs: TLV) -> PkScript: asset_id = sha256(genesis_point || asset_tag || asset_meta)
tlv_leaf = new_taro_tlv_leaf(
taro_version=0, asset_id, asset_type, total_units, asset_script_version=0,
asset_script_key, attrs=taro_attrs,
)
inner_smt_leaf = new_ms_smt_leaf(
key=asset_script_key, value=tlv_encode(tlv_leaf), sum_val=total_units,
)
inner_smt_root = ms_smt_root_hash(new_ms_smt(inner_smt_leaf))
outer_smt_leaf = new_ms_smt_leaf(
key=asset_id, value=inner_smt_root, sum_val=total_units,
)
outer_smt_root = mew_smt_root_hash(new_ms_smt(outer_smt_leaf))
internal_key = new_internal_key()
asset_idが定義されているように、一意性制約を強制するために、genesis_pointを事前に知っている必要があることに注意してください。
taro_attrsフィールドは、アセットに関連する任意の、そして潜在的に変更可能なフィールドのセットにコミットするために使用することができます。
上記の例では、作成されたタップルートツリーは単一のリーフにのみコミットされます。実際には、tapscript ツリー内に他の通常の script-path スクリプトが存在する可能性があります。
上記の例では、アセットを1つだけ作成しました。1つの出力で複数のアセットを作成することも可能で、それによってアセット作成をバッチ処理することができます。
アセットトランスファー
ノーマルとアセット・コレクティブの間では、スワップとノーマルセンドの2種類の転送が定義されています。
資産スワップは、PSBT拡張機能(bip-taro-psbt.mediawikiで定義)を使って、複数入力-複数出力(MIMO)トランザクションを共同で作成し、入力として一つまたは複数の異なる資産を使い、出力として一つまたは複数の新しい資産所有者を作り出すことで、複数ラウンドにわたって行われます。
一方、通常の送金は、一方の当事者だけが相手の財布にアセットを支出するため、1ラウンドのみのやり取りとなる。双方向の送受信と比較すると、Taro資産の証人は1人しか指定する必要がありません。
アセットコレクションのアイテムの転送を構築し、検証するには、アセットの所有者が、その入力から、受信者が制御する新しい出力に所有権を転送する必要があります。資産の譲渡を検証し、認証するために、資産の証人の有効性と同様に、メルクルサムコミットメントのセットが使用されます。
通常の資産の交換では、双方が不用意に新しい資産を作らないようにする必要があるため、追加の検証ステップが必要になる(結果として、無効な取引が発生する)。これを達成するためには、第三者検証機関がスプリット(単一のアセットを複数のインスタンスにUTXO分割すること)とマージ(同じアセットタイプの出力を一つにまとめること)の両方を検証できるような方法でトランザクションを形成する必要があります。これを実現するためにsplit_commitmentフィールドを使用し、(Taroドメインで)変更出力とみなされるものを、他の作成された分割のmerkle-sumツリーにコミットするよう効果的に強制する。
アセットスワップ取引
このセクションでは、2つ以上の当事者が協力して、参加当事者間で1つ以上の資産を転送するMIMO取引を作成する、インタラクティブな資産転送を指定します。この設定における核となる相互作用、交換された証明の検証について説明する。このようなプロトコルがPSBTベースの署名式にどのようにマッピングされるかに関するさらなる詳細は、BIP bip-taro-psbt-mediawiki に委ねる。
コレクターズアセットの譲渡
アセット・コレクタブルの譲渡は、通常のアセット譲渡に比べ、複数のアセットUTXOSの分割・統合の検証を必要としない分、シンプルなものとなっています。アセット・コレクタブルの譲渡は、2つのレイヤーで行われます。
まず、アセットウィットネスとスクリプトハッシュ情報を交換し、受信側(各入力アセットの受信側)が入力アセットの出所を確認できるようにし、送信側は受信側のスクリプトハッシュに所有権を委譲します。
これを内部転送プロセスと呼ぶ。
次に、下位レイヤーで通常のビットコイン署名/証人のセットが交換され、すべての入力資産を消費し(効果的に破壊し)、結果として生じるMIMOトランザクションの新しいコミットメントとして資産を再作成する。
これを外部送金プロセスと呼ぶ。
すべての入力がTaro資産を保有する入力である必要はないことに注意。これは当然、多数の当事者間で単一のトランザクションでバッチ式MIMOアトミック・スワップを実行する新しいサブプロトコルに適しています。
検証はTaroプロトコルの基礎であるため、インタラクティブな転送プロセスにおいて、各パーティは以下の検証アサーションを実行します。
入力資産の出所を検証する。
各アセットについて、パーティが有効な入力アセット証人を生成できることを検証する。
作成された新しい Taro アセット スクリプト出力のセットが、転送されたアセットにコミットしなくなったか、または新しく受け取ったアセットに正しくコミットするようになったかを検証する。
最初の検証ステップは、アセットが有効な血統を持っていることを確認します。第二段階では、資産の所有者が実際にその資 産を使用できるかどうかを確認します。最後のステップでは、新しいアセットが作成されないようにし、代わりに出所が確認された既存のアセットのみが転送されるように検証します。
転送は次のように指定されます。
各入力(転送される1つ以上の資産収集物を保持することができる)について、所有者は送信する。
各入力の前の出力に格納されたMS-SMTコミットメントのオープン、ユニバース(圧縮された証明を抽出するため)または完全な証明ファイルの識別子として送信されます。
これを使用して、資産収集物の受信者(複数可)は以下を検証します。
各プルーフはアセットツリーコミットメントの有効なオープニングであり、転送されるアセットまでの有効なリーフパスがあること。
転送する各資産のメルクルサムコミットメントは、希望する資産のamt(すべてのアセットコレクティブルで1である必要があります)が与えられたときに有効である。
asset_idが与えられると、genesisOutpoint、assetTag、assetMetaを明らかにする有効なオープニングが行われます。
与えられたgenesisOutpointは、ユニークなアセットコレクティブルのセットに対して維持されるユニバースに存在します。Universeの現在のMS-SMTのmerkle証明、または完全な証明が使用されるかもしれません。
初期検証が完了すると、内部転送処理が開始される。
各アセットコレクションについて、交換するi。
受信者は新しいアセットスクリプトキーのコミットメント、asset_script_key_i(入力アセットの所有権を委任するために使用される)を作成し、これを所有者に送信します。
所有者は、シリアライズされた生のアセットスクリプトを受け取り、asset_script_key_i スクリプト上で新しいアセットウィットネスを閉じます(シリアライズされたアセットリーフの一部となります)。このウィットネスは、受信者に送信されます。
受信側は、新しい有効なリーフ (所有権を委任する有効なウィットネス) を構築し、 (アセットコレクションの系統のインスタンスを所有していない場合) 新しいルート付きアセットツリーを作成するか、既存のツリーに追加することができるようになりました。これをasset_leaf_iと呼びます。この新しいリーフは、有効な証人であるために、有効な prev_asset_id を適切に参照しなければなりません。
内部転送が完了すると、最後の外部転送が実行されます。
入力のセット(資産の種類によって異種である可能性がある)は、新しいバージョン2ビットコイン取引に追加される。
新しい所有権の出力セットは交換され、MIMO転送トランザクションに追加される。最低限、各パーティはトランザクションに新しい所有権出力が存在しなければならない(MUST)。
各タロタグ付きアウトプットiについて、アセットを転送する。
送信者は受信者に、新しい出力をルートとする非包含証明を送信し、問題の資産がもはや自分のアセットツリー内にコミットされていないことを証明する。
送信者は、更新されたアセットツリールートを含む新しい有効なタップルート出力スクリプトを構築し、検証のために受信者にこれを送信します。
アセットを受信する各所有権出力について。
受信者は、新しいasset_leaf_iフラグメントに証明可能にコミットする、有効な新しいタップルート出力スクリプトを構築します。
外部転送は、各入力に対して有効なビットコイン入力証人のセットを交換することで承認されます。
最終ステップが実行された後、一方または双方がメインチェーン内でトランザクションを承認するブロードキャストを行うことができる。さらに、各当事者はそれぞれのアセット証明ファイル(検証プロセスで完全に送信された)に追記したり、アセットを転送した場合はそれを削除したりすることもできる。
アクティブなユニバースが転送に使用されている場合、内部転送プロセスのみが行われる必要があり、新しい証明はチェーン内でスタンプを押すためにユニバースにアップロードされます。
上記の転送処理は、アリスとボブの二者が所有する一連の資産の転送(フルスワップ)を指定する以下の擬似コードの断片によって代替的に表現することができる。
code:transfer
verify_asset_input_proofs(asset_proofs: mapAssetPrevIDAssetLeafProof) -> bool for prev_asset_id, asset_leaf in asset_proofs
prev_outpoint, asset_id, asset_script_key = prev_asset_id
match asset_leaf.proof_type:
case FullProof:
for i in range(len(asset_leaf.inclusion_proofs)):
asset_leaf_tlv = asset_leaf.raw_leafi leaf_merkle_proof = asset_leaf.inclusion_proof2i if i != 0 and asset_leaf_tlv.prev_input.prev_outpoint !=
asset_leafi-1.leaf_merkle_proof.outpoint: fail
if not verify_inclusion_proof(leaf_merkle_proof, asset_leaf):
fail
if not verify_witness(asset_leaf.asset_witness, asset_leaf):
fail
case CompactProof:
if not verify_universe_proof(asset_leaf.inclusion_proofs, asset_id):
fail
transfer_assets(sender_assets: mapAssetIDAssetLeaf, receiver_scripts: [32byte]) -> mapAssetIDAssetLeaf new_assets = {}
for prev_asset_id, asset_leaf in sender_assets:
asset_script_key = asset_script_keyesi new_leaf = clone_unique_leaf(asset_leaf)
new_leaf.asset_script_key = asset_script_key
new_leaf.prev_asset_id = prev_asset_id
new_leaf.asset_witness = gen_witness(tlv_encode(new_leaf))
return new_assets
taro_interactive_transfer(bob_inputs_assets: mapAssetIDAssetLeafProof, alice_input_assets: mapAssetIDAssetLeafProof, alice_internal_key: PublicKey, bob_internal_key: PublicKey, alice_asset_script_keyes: [32byte], bob_asset_script_keyes: [32byte]) -> Tx: if !verify_asset_input_proofs(list(chain(alice_new_assets, bob_input_assets))):
fail
bob_new_assets = transfer_assets(alice_input_assets, bob_asset_script_keyes)
alice_new_assets = transfer_assets(bob_input_assets, alice_asset_script_keyes)
alice_new_taro_root = alice_compute_root(remove=alice_input_assets)
if not verify_non_inclusion(alice_new_taro_root, bob_new_assets):
fail
bob_new_taro_root = bob_compute_root(remove=bob_input_assets)
if not verify_non_inclusion(bob_new_taro_root, alice_new_assets):
fail
transfer_tx = new_tx()
for prev_asset_id, _ in list(chain(alice_input_assets, bob_inputs_assets)):
transfer_tx.add_txin(prev_asset_id.prev_outpoint)
transfer_tx.add_output(taproot_output_script(key=alice_internal_key, leaves=alice_new_taro_root)) transfer_tx.add_output(taproot_output_script(key=bob_internal_key, leaves=bob_new_taro_root)) return transfer_tx
上記の方法は、完全に署名されたビットコイン取引を生成し、それをブロードキャストすると、アリスの収集可能な資産のセットとボブの収集可能な資産のセットをアトミックに取引し、アリスはその転送条件を満たすためにボブに追加の1BTCを支払います。