Cedar ルールの記述

このページでは、マルチパーティ コンピューティング(MPC)Policy Engine でトランザクションを検証する Cedar ポリシールールを作成する方法について説明します。

Policy Engine は、安全な高信頼実行環境(TEE)内で受信トランザクション ペイロードをデコードし、トランザクション インテント属性を Cedar 評価コンテキストに投影します。

Cedar ルールの構造

Policy Engine の Cedar ルールを作成するときは、ネストされた条件セットを使用してルールを指定します。

  • プリンシパル: API を呼び出す Google Cloud IAM ID(ユーザーまたはサービス アカウント)ではなく、マルチパーティ コンピューティング ワークスペース(User::"alice" など)内のトランザクション リクエスト元(トランザクションの開始者)の論理 ID。
  • アクション: リクエストされた暗号オペレーション(Action::"sign_transaction" など)。
  • リソース: 操作対象のターゲット アセットまたはオペレーション クラス(例: Resource::"mpc_operation")。
  • コンテキスト: 解析されたトランザクション メタデータとパラメータ(context.transaction でアクセス可能)。

Ethereum トランザクション スキーマ リファレンス

プロトコルに依存しないフレームワークにより、ルールでスキーマ チェックを省略して、異なるブロックチェーン ネットワーク間で再利用できるようになります。ただし、ルールを Ethereum トランザクション ペイロードに明示的に制限するには、context.transaction.schema == "ethereum.transaction.v2" を確認します。

context.transaction レコード内では、次の属性がサポートされています。

属性 型 説明
schema 文字列 形式スキーマ。Ethereum トランザクションの場合、これは常に "ethereum.transaction.v2" です。
operation 文字列 トランザクション オペレーションのタイプ。サポートされている値:
  • "NATIVE_TRANSFER": メインチェーン通貨(ETH など)の直接転送。
  • "TOKEN_TRANSFER": ERC-20 トークンの送金(USDC、USDT、DAI など)。
  • "TOKEN_APPROVE": コントラクトがトークンを使用できるようにする ERC-20 トークンの承認。
  • "CONTRACT_CALL": 一般的なスマート コントラクトのインタラクション(ステーキングやスワップなど)。
chain_id 文字列 ターゲット ブロックチェーン ネットワーク ID(例: Ethereum Mainnet の場合は "1"、Sepolia Testnet の場合は "11155111")。
asset_symbol 文字列 転送されるトークンのティッカー シンボル("ETH"、"USDC"、"DAI"、"WBTC" など)。上場されていないトークンは "UNKNOWN" を返します。
asset_contract_address 文字列 ERC-20 トークンのスマート コントラクト アドレス(大文字と小文字が混在する EIP-55 チェックサム形式)。標準の ETH 転送の場合、これは空の文字列("")に解決されます。
recipient 文字列 宛先の受信者アドレス(大文字と小文字が混在する EIP-55 チェックサム形式)。トークンの承認の場合、これは支出者のアドレスを表します。
spend_amount_scaled 長い トークンの転送金額は、固定の 9 桁の精度(ナノコイン形式)に正規化されます。これにより、ルールを記述する際に、さまざまなトークンの小数点以下(6、8、18 など)を追跡する必要がなくなります。

計算方法: 人が読める形式のアセット量(例: 1.5 ETH または 5,000 USDC)に 1,000,000,000(109)を掛けて、ルールの値を取得します。
  • 0.1 ETH → 100000000(0.1 × 109)
  • 任意のアセットの 1.0 → 1000000000(1.0 × 109)
  • 5,000 USDC → 5000000000000(5,000 × 109)
spend_amount_dust 長い 小数点以下 9 桁の精度しきい値を下回る取引金額の残額。小数点以下が 9 桁を超えるアセット(18 桁の ETH など)の場合、このフィールドには、スケーリングされていない Gwei 未満の値(残りの Wei)が含まれます。小数点以下が 9 桁以下のアセット(USDC や WBTC など)の場合、これは常に 0 です。
max_fee_atomic 長い 取引手数料の合計の上限(109 でスケーリング、Gwei を表す)。
gas_limit 長い トランザクションの実行に割り当てられるガスの最大量。
destination_type 文字列 受信者アドレスの分類。サポートされている値: "EOA"(標準ユーザー ウォレット)、"CONTRACT"(スマート コントラクト)、"INTERNAL_TREASURY"(内部ボールト)。
temporal_validity 長い トランザクション アカウントのノンス(トランザクション リプレイ攻撃を防ぐために使用)。

ビットコイン トランザクション スキーマ リファレンス

ルールをビットコイン BIP 174 PSBT トランザクション ペイロードに明示的に制限するには、context.transaction.schema == "bitcoin.transaction.v2" を確認します。

context.transaction レコード内では、次の属性がサポートされています。

属性 型 説明
schema 文字列 形式スキーマ。ビットコイン トランザクションの場合、これは常に "bitcoin.transaction.v2" です。
operation 文字列 トランザクション オペレーションのタイプ。サポートされている値:
  • "NATIVE_TRANSFER": ビットコイン(BTC)の直接送金。
  • "OP_RETURN": 使用できないデータ アンカー / null データ出力。
chain_id 文字列 ターゲット ネットワークの Bech32 対人可読部分(HRP): "bc"(Bitcoin メインネット)、"tb"(テストネット / テストネット 4)、または "bcrt"(Regtest)。
asset_symbol 文字列 アセットのティッカー シンボル: "BTC"。
recipient 文字列 プライマリ宛先アドレス。OP_RETURN トランザクションの場合、これは "unaddressable" です。内部統合スイープ(100% の変更)の場合、これは最初の変更アドレスに解決されます。
spend_amount_scaled 長い 固定 9 桁の精度(10-9 単位)に正規化された純アウトバウンド転送量。1 サトシは 10 ナノコイン単位(1 sat = 10 単位、1 BTC = 109 単位)に相当するため、内部変更金額は除外されます。内部スイープ / 100% 変更トランザクションの場合、これは 0 と評価されます。
max_fee_atomic 長い 小数点以下 9 桁の精度に正規化された、計算されたマイナー手数料の上限:(∑ 入力 − ∑ 出力)× 10。
destination_type 文字列 受信者スクリプトの分類。サポートされている値: "P2WPKH"(ネイティブ SegWit)、"P2TR"(Taproot)、"P2PKH"(レガシー)、"P2SH"(ネストされた SegWit / スクリプト ハッシュ)、"TREASURY_CHANGE"(内部変更スイープ)、""。
temporal_validity 長い トランザクションの nLockTime フィールド。
outputs Set<Record> すべてのトランザクション出力の正規化されたセット: [{ address: String, amount_scaled: Long, is_change: Bool }]。

Bitcoin ポリシーの基本コンセプト

  1. ユニバーサル 9 桁スケーリング計算: ビットコイン ポリシーの金額は、正規化された 9 桁のナノコイン精度(1 sat = 10 単位、1 BTC = 109 単位)を使用します。

    Amountscaled = Satoshis × 10 = BTC × 109

    • 0.0005 BTC(50,000 サトシ)→ 500000(50,000 × 10)
    • 0.0025 BTC(250,000 サトシ)→ 2500000(250,000 × 10)
    • 1.0 BTC(100,000,000 サトシ)→ 1000000000(100,000,000 × 10)
  2. 変更出力の分離: パーサーは、BIP-32 派生パス(m/.../1/*)を検査し、入力スクリプトを関連付けて、内部変更出力を自動的に識別します。おつりの金額は spend_amount_scaled から除外されるため、費用上限ポリシーは、サードパーティに転送された純アウトバウンド値に対して厳密に評価されます。

  3. 単一の非変更受信者ルール: 曖昧な複数受信者ルーティング攻撃を防ぐため、複数の異なる外部サードパーティ受信者を含むトランザクションはフェイル クローズ(ErrUnsupportedTx)になります。


Cedar ルールの例

次の例は、Ethereum と Bitcoin のトランザクションに Cedar を使用して、許可リスト、制限ルール、リプレイ境界を構成する方法を示しています。

Ethereum の例

次のルールは、Ethereum トランザクションと ERC-20 トランザクションの一般的なポリシー パターンを示しています。

1. 直接 ETH 転送の上限

このルールは、Alice がベースチェーン ETH を転送することを許可し、スケーリングされた転送量が 1.0 ETH(1,000,000,000 スケーリングされた Gwei 単位)を超えないことを確認します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "NATIVE_TRANSFER" &&
    context.transaction.asset_symbol == "ETH" &&
    context.transaction.spend_amount_scaled <= 1000000000
};

2. ERC-20 トークンの許可リストルール

このルールでは、最大 5,000 USDC の USDC トークン転送が許可されます。許可リストに登録されている受信者アドレスへの転送を制限します。Cedar 文字列では大文字と小文字が区別されるため、受信者アドレスは、大文字と小文字が混在する EIP-55 形式と一致している必要があります。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "TOKEN_TRANSFER" &&
    context.transaction.asset_symbol == "USDC" &&
    context.transaction.recipient == "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" &&
    context.transaction.spend_amount_scaled <= 5000000000000
};

3. スマート コントラクトと DeFi コールのフォールバック

このルールでは、資産を消費する転送オペレーションでない限り、金額制限なしで一般的な契約インタラクション(ステーキングやスワップなど)が許可されます。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "CONTRACT_CALL"
};

4. 厳格なリプレイ保護(チェーン ID 境界)

テストネット チェーン用に署名されたペイロードが本番環境のメインネットで再送信されるトランザクション リプレイ攻撃を防ぐには、ルールを特定のチェーン ID(Sepolia の場合は 11155111 など)に限定します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.chain_id == "11155111"
};

ビットコインの例

次のルールは、ビットコイン PSBT トランザクションの一般的なポリシー パターンを示しています。

1. 利用限度額とマイナー手数料の上限

このルールでは、純アウトバウンド転送量が 0.0025 BTC(250,000 サトシ → 2,500,000 スケール単位)を超えず、マイナー手数料が 10,000 サトシ(100,000 アトミック単位)を超えない直接ビットコイン(BTC)転送を許可します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "NATIVE_TRANSFER" &&
    context.transaction.asset_symbol == "BTC" &&
    context.transaction.spend_amount_scaled <= 2500000 &&
    context.transaction.max_fee_atomic <= 100000
};

2. SegWit(P2WPKH)と Taproot(P2TR)のアドレス許可リスト

このルールは、ビットコインの送金を承認済みの SegWit または Taproot の宛先アドレスに制限します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    (context.transaction.destination_type == "P2WPKH" || context.transaction.destination_type == "P2TR") &&
    context.transaction.recipient == "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
};

3. UTXO の統合とトレジャリー スイープ

このルールは、すべての出力が内部のおつりアドレス(destination_type == "TREASURY_CHANGE" と spend_amount_scaled == 0)に戻る内部 UTXO 統合スイープを許可し、統合手数料を制限します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    context.transaction.destination_type == "TREASURY_CHANGE" &&
    context.transaction.spend_amount_scaled == 0 &&
    context.transaction.max_fee_atomic <= 50000
};

4. アウトプット セットの検査

このルールは、トランザクションのアウトプット セットに特定の宛先アウトプットと金額が含まれていることを検証します。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.outputs.contains({
        address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
        amount_scaled: 500000,
        is_change: false
    })
};

5. ネットワークのスコープ(メインネットとテストネット)

このルールは、承認の範囲をビットコイン テストネット(tb)トランザクションに限定し、ビットコイン メインネット(bc)での実行を防ぎます。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    context.transaction.chain_id == "tb"
};

6. OP_RETURN データのアンカリング

このルールでは、使用不可能な OP_RETURN データ アンカー トランザクション(spend_amount_scaled == 0 と recipient == "unaddressable")が許可され、厳格な手数料上限が適用されます。

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "OP_RETURN" &&
    context.transaction.recipient == "unaddressable" &&
    context.transaction.spend_amount_scaled == 0 &&
    context.transaction.max_fee_atomic <= 10000
};

パーサーの安全防御

本番環境でのトランザクション オペレーションを保護するため、Policy Engine はペイロードを厳密に解析し、Cedar ルールを評価する前にゲートウェイ レイヤで無効な構造を拒否します。

  • ゼロ値の基本通貨の適用: パーサーは、ゼロ以外の基本転送アセットをバンドルしようとする Ethereum トークン転送オペレーション(TOKEN_TRANSFER)を明示的に拒否します。これにより、悪意のあるペイロードが、トランザクションを標準のトークン転送として提示しながら、標準のベースアセット値を転送することを防ぎます。
  • UTXO とウィットネスの検証: ビットコイン PSBT トランザクションの場合、パーサーはすべての入力が有効な witness_utxo データを提供していることを検証し、手数料計算のなりすましや未検証の署名を防止します。
  • 変更出力スクリプトの検証: 内部変更出力は、入力スクリプトの公開鍵または既知の BIP-32 変更パス(m/.../1/*)と一致する必要があります。サードパーティのアドレスへの変更出力をなりすまそうとするペイロードは、フェイル クローズされます。
  • 単一の外部受信者の適用: 複数の外部の変更不可能な宛先アドレスを含むビットコイン ペイロードは、曖昧な複数受信者ポリシーの承認を防ぐために、フェイル クローズ(ErrUnsupportedTx)されます。
  • 整数オーバーフローとアンダーフローの保護: ナンス、ロックタイム、ガスまたは手数料の上限、安全な範囲(MaxInt64)を超える金額、アンダーフローを発生させる金額(合計出力値が合計入力値を超えるなど)は、直ちに拒否されます。
  • 手数料検証の欠如: 適切なマイナー手数料またはガス パラメータを定義できないトランザクションは、自動的に失敗します。