协议¶
LedgerFlow 协议定义了一种授权令格式和授权证明模型,通过 x402 扩展为代理级支付授权提供支持。协议有意保持精简:一个授权令格式、一个证明格式、一个 x402 扩展命名空间。
设计哲学¶
LedgerFlow 借鉴了 Zanzibar 和 SpiceDB 的设计经验,但没有采用它们的完整架构:
- 小的公开 API — 商户只问一个问题:"这个代理是否有权使用这个报价?"
- 类型化约束 — 无需通用表达式引擎即可进行上下文感知检查
- 时间绑定权限 — 过期是一等公民
- 未来扩展点 — 一致性令牌(Zookies/ZedTokens)为 v2 预留
LedgerFlow 明确避免:
- 通用关系图存储
- 递归用户集遍历
- Schema 编译
- 通用表达式求值
- 热路径上的多跳对象图遍历
授权令¶
授权令是一个自包含的、密码学签名的授权令牌。
结构¶
| 字段 | 描述 |
|---|---|
version |
协议版本,从第一天起就明确版本化 |
warrant_id |
授权令的唯一标识符 |
issuer |
发行者(签名身份) |
subject_signer |
代理的签名身份(验证密钥) |
payment_subjects |
代理可以使用的结算身份 |
audience |
授权令适用的商户范围 |
not_before_ms |
有效期开始(Unix 毫秒) |
expires_at_ms |
有效期结束(Unix 毫秒) |
delegation |
是否以及多深可以子委托 |
constraints |
类型化约束列表 |
metadata |
发行者定义的元数据 |
signature |
密码学签名(覆盖规范字节) |
身份模型¶
LedgerFlow 分离两层身份:
签名身份 — 用于密码学验证:
pub struct SignerRef {
pub alg: SigningAlgorithm, // Ed25519 或 Secp256k1
pub public_key: Vec<u8>,
pub key_id: Option<String>,
}
支付主体 — 用于结算,对商户不透明:
pub struct PaymentSubjectRef {
pub kind: PaymentSubjectKind, // Caip10, FacilitatorAccount, ExchangeAccount, Opaque
pub value: String,
}
示例:caip10:eip155:8453:0xabc...、binance:uid:12345678、okx:subacct:agent-alpha。
这种分离确保商户保持轨道无关。
受众范围¶
pub enum AudienceScope {
MerchantIds(Vec<String>), // 按稳定商户标识符
MerchantHosts(Vec<String>), // 按主机名后缀
Any, // 无限制(罕见)
}
优先使用商户 ID(当有稳定标识符时)。基于主机的范围是回退方案。
委托策略¶
深度足以满足 v1。不需要图式递归委托。
授权证明¶
授权证明表明代理持有授权令,并将其用于特定交易。
证明绑定¶
证明必须绑定到:
- LedgerFlow 挑战 ID
- 授权令摘要
- 精确选中的 x402
accepted对象 - 当前 HTTP 请求
- 签名身份
- 新鲜性元组(时间戳 + nonce)
规范请求哈希¶
request_hash = SHA256(
UPPER(method) || "\n" ||
LOWER(authority) || "\n" ||
path_and_query_exact || "\n" ||
SHA256(body_bytes)
)
有意保持简单。除非是 x402 负载或 LedgerFlow 扩展的一部分,否则不包含传输头部。
Accepted 哈希¶
accepted_hash 是选中的 x402 accepted 对象的规范 JSON 序列化的 SHA-256 摘要。
这是保持 LedgerFlow 与 x402 互补而非竞争的关键环节。商户报价仍然是 x402。LedgerFlow 只是授权该报价。
证明原像¶
proof_preimage = CBOR({
domain: "ledgerflow-pop/v1",
challenge_id: ...,
warrant_digest: ...,
accepted_hash: ...,
request_hash: ...,
created_at_ms: ...,
nonce: ...,
signer_key: ...
})
证明签名是对 SHA256(proof_preimage) 的 ED25519 签名。
重放保护¶
created_at_ms必须在 60 秒验证窗口内- 重放键:
challenge_id + nonce,使用原子 TTL 插入 - 存储语义:
SET key value NX PX ttl_ms(Redis) - 永远不要使用非原子的检查后设置流程
幂等重试¶
- 相同的证明 + 相同的支付标识符 → 返回缓存的结果
- 相同的 nonce 配合不同的请求哈希或 accepted 哈希 → 拒绝为重放
授权令传输¶
传输模式¶
- 内联 — 首次使用时发送授权令字节
- 摘要引用 — 商户缓存授权令后使用
规则:
- 存在
inline_b64→ 商户验证并缓存 - 仅存在
digest→ 商户查找缓存的授权令 - 未知摘要 → 商户拒绝,要求客户端重新发送内联版本
缓存键¶
按 warrant_digest 缓存,绝不要仅按签名者缓存。
精确、可移植、易于实现。
LedgerFlow 验证内容¶
商户端验证器检查:
- 授权令签名有效性
- 证明签名有效性
- 授权令有效期(not_before / expires_at)
- 受众范围符合受众约束
- 资源范围符合资源约束
- 工具范围符合工具约束
- 资产和金额约束
- 委托约束
- 证明绑定到精确选中的 x402
accepted对象 - 证明绑定到当前 HTTP 请求
- 证明未被重放
协议限制¶
| 限制 | 值 |
|---|---|
| 最大委托深度 | 64 |
| 最大授权令 TTL | 90 天 |
| 最大授权令大小 | 8 KB |
| 每个授权令最大约束数 | 32 |
| 证明新鲜性窗口 | 60 秒 |
| 推荐 nonce 长度 | 16 字节 |