编写 Cedar 规则

本页面介绍了如何编写 Cedar 政策规则,以在多方计算 (MPC) 政策引擎中验证交易。

政策引擎会在安全的可信执行环境 (TEE) 中解码传入的交易载荷,并将交易 intent 属性投影到 Cedar 评估上下文中。

Cedar 规则结构

为政策引擎编写 Cedar 规则时,您需要使用一组嵌套条件来指定规则:

  • 主账号:多方计算工作区中交易请求者(交易发起者)的逻辑身份(例如 User::"alice"),而不是调用 API 的 Google Cloud IAM 身份(用户或服务账号)。
  • 操作:请求的加密操作(例如 Action::"sign_transaction")。
  • 资源:操作的目标资产或操作类(例如 Resource::"mpc_operation")。
  • Context:解析后的交易元数据和参数(可在 context.transaction 下访问)。

以太坊交易架构参考

该框架不依赖于特定协议,因此规则可以省略架构检查,从而在不同的区块链网络中重复使用。不过,如需明确将规则限制为以太坊交易载荷,请勾选:context.transaction.schema == "ethereum.transaction.v2"。

context.transaction 记录中支持以下属性:

属性 类型 说明
schema 字符串 格式架构。对于以太坊交易,此值始终为 "ethereum.transaction.v2"。
operation 字符串 交易操作类型。支持的值:
  • "NATIVE_TRANSFER":主链货币(例如 ETH)的直接转账。
  • "TOKEN_TRANSFER":ERC-20 代币转账(例如 USDC、USDT、DAI)。
  • "TOKEN_APPROVE":允许合约支出代币的 ERC-20 代币批准。
  • "CONTRACT_CALL":常规智能合约互动(例如质押或交换)。
chain_id 字符串 目标区块链网络 ID(例如,以太坊主网为 "1",Sepolia 测试网为 "11155111")。
asset_symbol 字符串 所转移代币的股票代码(例如 "ETH"、"USDC"、"DAI" 或 "WBTC")。未上市的代币会返回 "UNKNOWN"。
asset_contract_address 字符串 ERC-20 代币的智能合约地址(采用大小写混合的 EIP-55 校验和格式)。对于标准 ETH 转账,此字段会解析为空字符串 ("")。
recipient 字符串 目标收款人地址(采用大小写混合的 EIP-55 校验和格式)。对于代币批准,这表示支出者地址。
spend_amount_scaled Long 代币转移金额已标准化为固定的 9 位小数精度(nanocoin 格式),因此在编写规则时无需跟踪不同的代币小数位数(例如 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 Long 交易金额中低于 9 位小数精度阈值的剩余部分。对于小数位数超过 9 位的资产(例如 ETH,有 18 位小数),此字段包含未缩放的 sub-Gwei 值(剩余的 Wei)。对于小数位数不超过 9 位的资产(例如 USDC 或 WBTC),此值始终为 0。
max_fee_atomic Long 交易费用总额上限(按 109 缩放,表示 Gwei)。
gas_limit Long 为执行交易而分配的最大 gas 量。
destination_type 字符串 收件人地址的分类。支持的值:"EOA"(标准用户钱包)、"CONTRACT"(智能合约)或 "INTERNAL_TREASURY"(内部保险柜)。
temporal_validity Long 交易账号 Nonce(用于防范交易重放攻击)。

比特币交易架构参考

如需明确将规则限制为比特币 BIP 174 PSBT 交易载荷,请勾选:context.transaction.schema == "bitcoin.transaction.v2"。

context.transaction 记录中支持以下属性:

属性 类型 说明
schema 字符串 格式架构。对于比特币交易,此值始终为 "bitcoin.transaction.v2"。
operation 字符串 交易操作类型。支持的值:
  • "NATIVE_TRANSFER":直接转账比特币 (BTC)。
  • "OP_RETURN":不可花费的数据锚定 / 空数据输出。
chain_id 字符串 目标网络 Bech32 人类可读部分 (HRP):"bc"(比特币主网)、"tb"(测试网 / 测试网 4)或 "bcrt" (Regtest)。
asset_symbol 字符串 资产股票代码:"BTC"。
recipient 字符串 主要目的地地址。对于 OP_RETURN 交易,此值为 "unaddressable"。对于内部合并清扫(100% 找零),此地址会解析为第一个找零地址。
spend_amount_scaled Long 净转出金额,已标准化为固定的 9 位小数精度(10-9 单位)。由于 1 聪等于 10 个纳币单位(1 聪 = 10 个单位,1 BTC = 109 个单位),因此内部找零金额会被排除。对于内部清扫 / 100% 找零交易,此字段的计算结果为 0。
max_fee_atomic Long 计算出的矿工费上限,已标准化为 9 位小数精度:(∑ 输入 − ∑ 输出) × 10。
destination_type 字符串 接收方脚本的分类。支持的值:"P2WPKH"(原生隔离见证)、"P2TR" (Taproot)、"P2PKH"(旧版)、"P2SH"(嵌套隔离见证 / 脚本哈希)、"TREASURY_CHANGE"(内部找零清扫)或 ""。
temporal_validity Long 交易 nLockTime 字段。
outputs Set<Record> 所有交易输出的标准化集合:[{ address: String, amount_scaled: Long, is_change: Bool }]。

核心比特币政策概念

  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 规则示例

以下示例演示了如何使用 Cedar 为以太坊和比特币交易配置许可清单、限制规则和重放边界。

以太坊示例

以下规则说明了以太坊和 ERC-20 交易的常见政策模式。

1. 直接 ETH 转账限额

此规则允许 Alice 转移 Base 链 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. 支出限额和矿工费上限

此规则允许直接进行比特币 (BTC) 转账,前提是净出站转账金额不超过 0.0025 BTC(250,000 聪 → 2,500,000 缩放单位),且矿工费不超过 10,000 聪(100,000 原子单位)。

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 整合和资金归集

此规则允许内部 UTXO 整合扫描,其中所有输出都返回到内部找零地址(destination_type == "TREASURY_CHANGE" 和 spend_amount_scaled == 0),同时限制整合费用。

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
};

解析器安全防御

为了保护生产环境中的交易操作,政策引擎会严格解析载荷,并在评估任何 Cedar 规则之前在网关层拒绝无效结构:

  • 零值基础货币强制执行:解析器会明确拒绝同时尝试捆绑非零基础转移资产的以太坊代币转移操作 (TOKEN_TRANSFER)。这可以防止恶意载荷在将交易呈现为标准代币转移的同时,转移标准基础资产价值。
  • UTXO 和见证验证:对于比特币 PSBT 交易,解析器会验证所有输入是否都提供了有效的 witness_utxo 数据,从而防止费用计算欺骗或未经验证的签名。
  • 找零输出脚本验证:内部找零输出必须与输入脚本公钥或已知的 BIP-32 找零路径 (m/.../1/*) 匹配。如果载荷试图将找零输出伪装成第三方地址,则会失败并关闭。
  • 单一外部接收方强制执行:包含多个外部非找零目标地址的比特币载荷会失败并关闭 (ErrUnsupportedTx),以防止出现不明确的多接收方政策授权。
  • 整数溢出和下溢保护:如果随机数、锁定时间、gas 费或费用上限以及金额超出安全边界 (MaxInt64) 或产生下溢(例如总输出值超过总输入值),则会立即被拒绝。
  • 缺少费用验证:如果交易未能定义适当的矿工费或 gas 参数,则会自动失败。