条件付きトークンのアトミックスワップ
条件付きトークンのアトミックスワップ
Section titled “条件付きトークンのアトミックスワップ”本ドキュメントは、ECDH鍵合意とSchnorrアダプター署名を使用したCashu条件付きトークン(NUT-CTF)のピアツーピア取引プロトコルを規定します。このプロトコルにより、カストディアル仲介者なしにトラストレスなアトミック交換(例:YESアウトカムトークンとsatsの交換)が可能になります。
NUT-CTFは将来の結果に依存する条件付きトークンを定義しますが、ユーザーがそれらをどのように取引するかは規定していません。予測市場には2つのコンポーネントが必要です:(1) 買い手と売り手をペアリングするマッチングエンジン、(2) どちらの当事者も不正ができないようにトークンをアトミックに交換する決済メカニズム。
このプロトコルは、NUT-11 P2PK支出条件、ECDH導出共有シークレット、Schnorrアダプター署名からアトミックスワップを構築することで(2)に対処します。マッチングエンジン(1)は公開鍵交換と暗号化メッセージパッシングを促進する非カストディアルリレーです。
アダプター署名
Section titled “アダプター署名”アダプター署名スキームは、標準的な署名スキームを4つの操作で拡張します:
- PreSign(sk, m, T) → s’: シークレットキー
skとアダプターポイントT = t·Gを使用して、メッセージmのプリ署名s'を生成します。プリ署名は有効な署名ではありませんが、シークレットtにコミットします。 - PreVerify(pk, m, s’, T) → bool:
s'が公開鍵pk、メッセージm、アダプターポイントTに対して有効なプリ署名であることを検証します。 - Adapt(s’, t) → s: アダプターシークレット
tを与えて、プリ署名を有効なSchnorr署名s = s' + tに完成させます。 - Extract(s, s’) → t: 有効な署名
sと対応するプリ署名s'から、アダプターシークレットt = s - s'を復元します。
重要な特性は:プリ署名s'が公開され、後に完成した署名sが現れた場合(誰かがproofを使用したため)、s'を知っている人はtを抽出できることです。これにより、2つの独立した支出イベント間に暗号学的リンクが作成されます。
secp256k1上のSchnorr署名(NUT-11で使用)の場合、アダプター署名は簡単です:
標準Schnorr: s = r + e·x (where e = H(R, P, m))アダプタープリ署名: s' = r + e·x (but R' = R + T, so e = H(R+T, P, m)) s = s' + t (valid sig with nonce point R = R' - T)アダプター署名がP2PK層で動作しなければならない理由
Section titled “アダプター署名がP2PK層で動作しなければならない理由”Cashuのブラインド署名(BDHKE)は乗法構造を使用します:C_ = k · B_。アダプター署名は加法構造を必要とします(Schnorr: s = r + e·x + t)。ミント検証を壊したりNUT-12 DLEQ proofを無効にしたりせずに、乗法ブラインド署名にアダプターシークレットを埋め込むことはできません。
NUT-11 P2PK支出条件は既にsecp256k1上のSchnorr署名を使用しており、アダプター署名と完全に互換性があります。したがって、プロトコルはブラインド署名層ではなく、完全に支出条件層で動作します。
ECDH鍵合意
Section titled “ECDH鍵合意”キーペア(a, A = a·G)と(b, B = b·G)を持つ2つの当事者は、どちらも秘密鍵を明かさずに共有シークレットS = a·B = b·Aを計算できます。この共有シークレットは、信頼できないマッチングエンジンを介して通信が中継される場合でも、アダプターポイントとプリ署名を交換するための暗号化チャネルを確立します。
- Alice: YESトークンを売却(satsと交換したい条件付きトークンproofを保有)
- Bob: YESトークンを購入(条件付きトークンと交換したいsat proofを保有)
- マッチングエンジン(ME): 注文をペアリングし暗号化メッセージを転送する非カストディアルリレー
- ミント(M): P2PK支出条件を強制するCashuミント
- AliceとBobの両方が有効なDLEQ proof(NUT-12)を持つCashu proofを保有
- ミントがNUT-07(witness取得付きトークン状態チェック)、NUT-11(P2PK)、NUT-12(DLEQ)をサポート
- AliceのYESトークンproofとBobのsat proofが合意された取引に対して互換性のある額面を持つ
ステップ1:注文発注
Section titled “ステップ1:注文発注”AliceとBobはそれぞれエフェメラルキーペアを生成し、マッチングエンジンに注文を登録します。
Alice: (a, A = a·G)を生成、公開鍵Aで売り注文を登録Bob: (b, B = b·G)を生成、公開鍵Bで買い注文を登録マッチングエンジンは注文板に注文を保存します。エフェメラルキーにより取引間の非リンク性が保証されます。
鍵の衛生:個別のスワップごとに新しいキーペアを生成しなければなりません(MUST)。単一の注文が複数のカウンターパーティと約定する(部分約定)場合、実装は注文レベルのキーペアをそれらの約定間で再利用してもよい(MAY)が、これは既知のリンク可能性の弱点であり、将来的には約定ごとの鍵に移行すべきです。無関係なスワップ間での鍵の再利用はECDH共有シークレットのグラフを漏洩させるため、禁止されます。
ステップ2:マッチ
Section titled “ステップ2:マッチ”エンジンは価格と数量に基づいてAliceの売り注文とBobの買い注文をマッチングします。送信内容:
- AliceはBobの公開鍵
Bを受信 - BobはAliceの公開鍵
Aを受信
マッチした数量は条件付きトークンの額面です。決済メッセージには、支払う通常のsats金額も別フィールドとして含めます。たとえば、価格37で1,000額面satsのYESが約定した場合、Aliceは1,000額面satsのYESをロックし、Bobは370通常satsをロックします。実装は1つの金額を両方のスワップレグに使ってはなりません。
Mint マッチでは、注文板は取引開始をジャーナルへ記録した後、マッチした数量を消費します。公開注文ステータスでは、その行はtradeId付きのマッチ済みとして公開されます。両当事者がアトミックスワップを完了すると取引は confirmed になります。先に決済タイムアウトが過ぎた場合、エンジンは取引を失敗させますが、マッチした数量は注文板へ戻しません。これは、カウンターパーティがすでにスワップ素材を見た後に、注文レベルのエフェメラルキーのまま流動性を復元することを避けるためです。タイムアウトは売り手側ロックタイムに猶予時間を加えた後に設定しなければなりません。買い手側ロックタイムでタイムアウトさせると、プロトコル上まだ有効なスワップを中断してしまう可能性があります。
Mint マッチのメイカーになり得る板に残る買い注文では、クライアントは注文提出前に注文ローカルの事前 split を提供してもよい(MAY)です。メイカーは通常 sats を選択し、必要な one-vs-rest collection への CTF split を mint に送信し、生成されたアウトカム proof をローカルウォレット状態に保存します。これは信頼性のための選択肢であり、別のワイヤプロトコルではありません。
公開されるカテゴリカル市場の板は常にプリミティブです。市場ルートは{conditionId}-{outcomeName}であり、注文リクエストはtokenSide: "Outcome"またはtokenSide: "Complement"を選択します。たとえば、ユーザーはcondition-A上でAとNot Aを取引します。公開クライアントは複合補集合ルートへ遷移、購読、注文送信をしません。内部的には、mint 互換のペイロードを作るために、Not Aに対応する正規化された one-vs-rest collection id を決済で使う場合がありますが、それは公開 market id ではありません。ローカル在庫が足りない場合、メイカーはマッチ時に通常担保を split できます。売り手がアトミックスワップの opening message を公開する前に、すべてのロックレグの準備が成功しなければなりません。
Mint マッチが到着すると、メイカーは下記の売り手ブランチで Alice として振る舞います。事前 split proof を使う場合、メイカーはテイカー側のアウトカム proof をロックし、マッチした数量について補集合側をローカルに保持します。
ステップ3:ECDH共有シークレット
Section titled “ステップ3:ECDH共有シークレット”両当事者が独立して共有シークレットを計算します:
Alice: S = a · BBob: S = b · ASから対称暗号化鍵を導出し(例:key = SHA256(S))、エンジンを介した暗号化通信に使用します。エンジンは暗号文を中継しますが、復号はできません。
ステップ4:アダプターポイント生成
Section titled “ステップ4:アダプターポイント生成”Aliceがランダムなアダプターシークレットtを生成し、アダプターポイントTを計算します:
Alice: t ← ランダムスカラー T = t · GAliceはECDH暗号化チャネルを介してTをBobに送信します(エンジンが中継)。
ステップ5:AliceがYES Proofをロック
Section titled “ステップ5:AliceがYES Proofをロック”AliceはNUT-11 P2PKを使用してBobの公開鍵にロックされたYESトークンproofを作成します:
[ "P2PK", { "nonce": "<random>", "data": "<Bobの公開鍵B>", "tags": [ ["sigflag", "SIG_INPUTS"], ["locktime", "<unix_timestamp>"], ["refund", "<Aliceの公開鍵A>"] ] }]locktimeとrefundタグにより、Bobがスワップを完了しない場合にAliceがトークンを回収できます。
次に、各proofのsecretに対するアダプタープリ署名を作成します:
各proofのsecret x_iに対して: s'_A_i = PreSign(a, x_i, T)注記: プリ署名はBobが検証に使用するエフェメラルキーで作成され、アダプターポイント
Tを使用します。tで適応されるまで有効なSchnorr署名ではありません。
Aliceは暗号化チャネルを介して{proofs, s'_A, T}をBobに送信します。
ステップ6:BobがSat Proofをロック
Section titled “ステップ6:BobがSat Proofをロック”BobはAliceのロックされたproofを受信し、検証します:
- DLEQ検証(NUT-12):各proofが有効なミント署名を持つことを確認
- P2PK検証:proofが適切なlocktimeと
Aへの返金で公開鍵Bにロックされていることを確認 - PreVerify:各
s'_A_iがアダプターポイントTを持つ有効なアダプタープリ署名であることを確認
すべてのチェックに合格した場合、BobはAliceの公開鍵Aにロックされたsat proofを作成します:
[ "P2PK", { "nonce": "<random>", "data": "<Aliceの公開鍵A>", "tags": [ ["sigflag", "SIG_INPUTS"], ["locktime", "<unix_timestamp>"], ["refund", "<Bobの公開鍵B>"] ] }]Bobは同じアダプターポイントTを使用してproofのアダプタープリ署名を作成します:
各proofのsecret y_jに対して: s'_B_j = PreSign(b, y_j, T)Bobは暗号化チャネルを介して{proofs, s'_B}をAliceに送信します。
ステップ7:Aliceが請求(Adapt + Swap)
Section titled “ステップ7:Aliceが請求(Adapt + Swap)”AliceはBobのproofを検証します(DLEQ、AへのP2PKロック、s'_BのPreVerify)。
Aliceはtを知っているため、Bobのプリ署名を有効なSchnorr署名に適応できます:
Bobの各proofに対して: s_B_j = Adapt(s'_B_j, t) = s'_B_j + tAliceはs_B_jをNUT-11 witness署名として使用し、ミントにスワップリクエストを送信します:
POST /v1/swap{ "inputs": [<witness s_B_j付きBobのsat proof>], "outputs": [<新しいトークン用Aliceのブラインドメッセージ>]}ミントはP2PK署名を検証し、スワップを処理します。Aliceは新しいsatトークンを保有しています。
ステップ8:Bobがアダプターシークレットを抽出
Section titled “ステップ8:Bobがアダプターシークレットを抽出”BobはミントのNUT-07トークン状態チェックエンドポイントで使用済みsat proofを照会します。Bobはステップ6で構築したproofを保持しているため、各proofについてY_j = hash_to_curve(secret_j)をローカルで計算できます(hash_to_curveについてはNUT-00を参照):
POST /v1/checkstate{ "Ys": ["<BobがAliceにロックした各sat proofのY_j = hash_to_curve(secret_j)>"]}ミントはAliceが使用した有効なSchnorr署名s_B_jを含むwitnessデータを返します:
{ "states": [ { "Y": "...", "state": "SPENT", "witness": "{\"signatures\": [\"<s_B_j>\"]}" } ]}Bobは任意の署名ペアからアダプターシークレットを抽出します:
t = Extract(s_B_j, s'_B_j) = s_B_j - s'_B_jステップ9:Bobが請求(Adapt + Swap)
Section titled “ステップ9:Bobが請求(Adapt + Swap)”tを復元したBobは、Aliceのプリ署名を有効なSchnorr署名に適応します:
Aliceの各proofに対して: s_A_i = Adapt(s'_A_i, t) = s'_A_i + tBobはAliceのYES proofに対するスワップリクエストを送信します:
POST /v1/swap{ "inputs": [<witness s_A_i付きAliceのYES proof>], "outputs": [<新しい条件付きトークン用Bobのブラインドメッセージ>]}ミントが検証してスワップを処理します。Bobは新しいYES条件付きトークンを保有しています。
マーケット終了とポジション請求
Section titled “マーケット終了とポジション請求”上記の取引スワップは、マーケットがオープンな間に条件付きトークンをユーザー間で移動します。オラクルがマーケットを解決した後、勝ち側の条件付きトークンはマッチングエンジンではなくミントで償還します。
- 署名済みDLCオラクルattestationによりマーケットが終了します。リレーへの公開は任意であり、ユーザーは署名済みattestationを直接エンジンに送信できます。
- エンジンはattestationをマーケットに登録されたオラクルに対して検証し、その条件の検証済みオラクルwitnessをキャッシュします。
- ポートフォリオ表示は、ウォレットに見えているCTF proofをエンジンのマーケット状態と最終結果に結合して、ActiveまたはClosedに分類します。
- 勝ちポジションの請求では、ローカルのCTF proofとオラクルwitnessをミントの
POST /v1/redeem_outcomeエンドポイントに送信します。ミントはwitnessを検証し、通常のecash proofを返します。負けアウトカムのproofはゼロ価値として扱われ、Closedのままです。
カテゴリカルマーケットでは、プリミティブなアウトカムトークンは attested outcome と一致する場合に勝ちます。one-vs-rest の補集合は、attested outcome が選択されたプリミティブではない場合に勝ちます。たとえばアウトカムがA、B、Cで、オラクルがBをattestした場合、B、Not A、Not Cは勝ちポジションであり、A、C、Not Bは負けポジションです。
エンジンのキャッシュされたwitnessは支払い権限ではありません。バグのある、または悪意あるエンジン応答が負けトークンを償還可能にすることはできません。ミントがredeem_outcome中にオラクル署名と条件付きkeysetを再検証するためです。
セキュリティ分析
Section titled “セキュリティ分析”原子性には両方の要素が必要です — アダプター署名だけでは不十分です。アダプター署名はHTLCのハッシュプリイメージをECスカラーに置き換えますが、NUT-11のlocktime + refundタグは、カウンターパーティが消えた場合の安全フォールバックを引き続き提供します。どちらか一方を除くとプロトコルが壊れます:
- アダプター署名はAliceが使用すればBobも使用できることを保証します(ライブネス/リンク可能性)。
- Locktime返金はAliceが決して使用しない場合でも、Bobが資金を回収できることを保証します(安全性)。
両方を前提とすると、3つのケースがあります:
- Aliceが請求した場合(ステップ7):適応された署名
s_B = s'_B + tがミントに公開されます。BobはNUT-07を介してそれを取得しtを抽出でき、Aliceのproofを請求できます。両当事者がスワップを完了します。 - Aliceが請求しない場合:どちらの当事者のトークンも使用されません。各proofのlocktime期限後、両当事者は返金パスを介して自分のトークンを回収します。
- Bobが先に請求することはできない:Bobは
tを知らないため、Aliceのプリ署名を適応できません。Aliceが使用してtを明らかにするまで待つ必要があります。
Locktime制約
Section titled “Locktime制約”locktimeは慎重に選択する必要があります:
- 短すぎる場合:Aliceの返金ウィンドウが開く前にBobがNUT-07に問い合わせてスワップを送信する時間がなく、競合状態が発生する可能性があります。
- 長すぎる場合:カウンターパーティが消えた場合、トークンが長期間ロックされます。
このプロトコルはecashスワップのみを含むため(Lightningルーティング遅延なし)、locktimeは非常に短く(分ではなく秒のオーダー)設定できます。両当事者は注文マッチングフェーズ中にlocktimeに合意する必要があります。
重要 — locktime順序:AliceのYES proof locktime(T_YES)はBobのsat proof locktime(T_sat)より後でなければなりません(MUST):
T_YES > T_sat + ΔここでΔはBobがNUT-07を照会し、tを抽出し、自身のスワップを送信するのに必要な時間です。
Aliceが先にBobのsat proofを使用し(ステップ7)、T_satの直前まで待つ可能性があります。Bobはその使用を観察し、tを抽出し、T_YESが期限切れになる前にAliceのYES proofを使用しなければなりません。順序が逆(T_YES < T_sat)の場合、Aliceは自分のYES返金ウィンドウが開くまで待ち、YES proofを返金し、T_satが期限切れになる前にBobのsatsを請求することで、取引の両側を盗むことができます。これはP03(アトミックスワップ原子性)の中核的な不変条件であり、実装はカウンターパーティのプリ署名を受け入れる前にこの順序を検証しなければなりません(MUST)。
NUT-07依存性
Section titled “NUT-07依存性”このプロトコルはミントがNUT-07 witness取得をサポートすることを必要とします。いくつかの考慮事項があります:
- 可用性:ステップ7と8の間にミントがオフラインになった場合、Bobはwitnessを取得できません。locktime返金によりBobの元のsat proofは保護されますが、YES proofを請求する機会は失われます。
- プライバシー:NUT-07への問い合わせにより、Bobが特定の使用済みproofに関心を持っていることがミントに明らかになり、取引当事者の相関に役立つ可能性があります。
- 検閲:悪意のあるミントがwitnessデータの返却を拒否し、Bobが
tを抽出できなくする可能性があります。locktime返金によりBobの資金は保護されますが、原子性が壊れます。 - 競合状態:Aliceの使用(ステップ7)とBobの問い合わせ(ステップ8)の間に、ミントがオフラインまたは応答不能になる可能性のあるウィンドウがあります。
これらの制限はP2PK + NUT-07アプローチに固有のものです。より強い原子性保証のためには、アトミック決済エンドポイントバリアント(代替案を参照)を検討してください。
| エンティティ | 信頼要件 |
|---|---|
| マッチングエンジン | 非カストディアル。暗号化メッセージを中継。復号不可(ECDH)。資金窃取不可。サービス拒否は可能(中継拒否)。 |
| ミント | P2PK条件を正直に実行し、NUT-07 witnessデータを返す必要がある。トークン発行で既に信頼済み。 |
| カウンターパーティ | トラストレス。窃取不可 — 完了しないことによるグリーフのみ可能(locktime返金で保護)。 |
HTLCアプローチとの比較
Section titled “HTLCアプローチとの比較”NUT-14はCashu用のHash Time-Locked Contracts(HTLC)を定義しています。HTLCは理論的にアトミックスワップを可能にしますが、条件付きトークン取引には重大なデメリットがあります:
| プロパティ | HTLC(NUT-14) | アダプター署名(本プロトコル) |
|---|---|---|
| ロックタイプ | ハッシュプリイメージH(x) | ECポイントT = t·G |
| プリイメージ伝播 | NUT-07が必要(同じ依存性) | NUT-07が必要(同じ依存性) |
| ミントが知る情報 | プリイメージ値(両スワップレグを相関可能) | 通常のP2PK署名(2つのスワップをリンク不可) |
| プライバシー | 同じハッシュH(x)が両レグに現れる — 自明にリンク可能 | 異なる署名、オンチェーンリンクなし |
| 追加NUT | NUT-14(HTLCサポート) | NUT-11(P2PK)以外不要 |
| 暗号学的複雑性 | 低い(ハッシュ + プリイメージ) | 高い(アダプター署名数学) |
プライバシーの利点が主要な差別化要因です。HTLCでは、ミントは両スワップレグで同じハッシュロックを見るため、同じ取引の一部であることを自明に判断できます。アダプター署名では、ミントは無関係な署名を持つ2つの独立したP2PK使用を見ます。
既知の制限と緩和策
Section titled “既知の制限と緩和策”トークン額面粒度
Section titled “トークン額面粒度”Cashuは整数sats金額と2のべき乗のproof額面を使用します。bitCasterの初回リリースでは、指値注文の額面数量を100 satsで割り切れる値に制限します。これにより、整数セントの価格は常に正確な支払金額に変換できます。たとえば、価格37で1,000額面satsなら370通常satsです。小数satsの支払いが必要になる注文は、黙って丸めるのではなく拒否すべきです。
フロントランニング
Section titled “フロントランニング”マッチングエンジンは注文フローを見ることができ、ユーザーより先に取引する可能性があります。緩和策:頻繁なバッチオークションを使用し、時間ウィンドウ内のすべての注文を単一のクリアリング価格でマッチングし、フロントランニングの優位性を排除します。
注文スパムによるDoS
Section titled “注文スパムによるDoS”攻撃者が注文を出し、マッチングされ、完了しないことで、カウンターパーティのトークンをlocktime期限までロックする可能性があります。緩和策:
- 短いlocktimeと、エンジンが所有する決済タイムアウトリマインダー。タイムアウトした取引は失敗扱いになり、マッチした数量はエフェメラルキーを再利用したまま注文板へ戻されません。
- マッチングエンジンによるレピュテーション追跡
- 少額のアンチスパムデポジット(例:エンジンへのLightningインボイス支払い)
このプロトコルは各マッチングペアの完全約定を要求します。部分約定は複数のアトミックスワップへの分割が必要です。ミント運営の注文板は部分約定をより自然に処理でき、このプロトコルを補完する可能性があります。
流動性の断片化
Section titled “流動性の断片化”異なるミントからの条件付きトークンはファンジブルではありません。取引は同じミントのトークンに限定されます。
- sig4sats — 動作するCashuアダプター署名スワップ実装
- NIP-455 (draft) — Nostr用アトミック署名スワッププロトコル
- Conduition ecash-DLC — Cashuベット用アダプター署名(クローズ済みPR)
- Partially Blind Atomic Swap — ブラインドSchnorr + アダプター署名(Blockstream)
- Scriptless Scripts — 元のアダプター署名仕様(Poelstra)
- Blind Adaptor Signatures, Revisited — 正式なBASプリミティブ(Schnorrが必要、BDHKEではない)