默认显示最新 1.1;也可查看历史 1.0。
ANP Profile 1:核心绑定(最终修订稿)
- 文档编号:ANP-P1
- 标题:核心绑定
- 状态:Draft
- 版本:0.2.0(最终修订稿)
- 语言:中文
- 适用范围:本 Profile 适用于所有 ANP 基础 Profile 与安全 Overlay Profile。
1. 目的
本 Profile 定义 ANP 的统一外层消息绑定、通用字段、能力协商、错误模型以及互操作约束。
本 Profile 的目标是:
- 为所有 ANP 方法提供统一的消息信封;
- 避免不同业务 Profile 重复发明请求、响应、通知和错误格式;
- 为 Direct Base、Group Base、Direct E2EE、Group E2EE、Attachment、Federation 等 Profile 提供共同基础;
- 在保留 JSON-RPC 2.0 基本兼容性的前提下,收紧可选自由度,降低跨实现歧义。
2. 术语与规范性约定
2.1 规范性关键字
本文中的 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、RECOMMENDED、NOT RECOMMENDED、MAY、OPTIONAL 按照其大写形式解释为规范性要求。
2.2 术语
- ANP Endpoint:实现 ANP 的协议端点,通常是 Agent 所在域的入口服务、群 Host 服务或其它经声明的服务端点。
- Request:具有
id的 JSON-RPC 调用对象。 - Notification:不具有
id的 JSON-RPC 调用对象。 - Result:成功响应对象中的
result成员。 - Error:失败响应对象中的
error成员。 - Profile:ANP 的协议能力单元,例如
anp.direct.base.v1。 - Security Profile:ANP 的安全语义单元,例如
transport-protected、direct-e2ee、group-e2ee。 - Operation:一次可被幂等识别的协议动作,例如发送消息、建群、加人、提交群状态变更。
- Message-bearing Operation:携带应用层消息负载的操作,例如
direct.send、group.send、group.e2ee.send。 - Message-bearing Notification:作为 Notification 承载应用层消息负载的推送方法,例如
direct.incoming、group.incoming、group.e2ee.notice。 - Control Operation:不携带应用层业务消息,而是改变协议或业务状态的操作,例如
group.create、group.add、group.remove。 - Origin Proof:由业务主体私钥生成、并通过
auth.origin_proof承载的应用层原发者证明。 - Object Proof:通过对象内嵌
proof对“移除proof后的整个对象”做出的可验证对象级断言。 - Signed Request Object:由
method、meta、body组成、用于计算contentDigest的共享规范化业务对象。
3. 设计原则
3.1 分层原则
ANP 采用如下分层:
- Transport 层:HTTP(S)、WebSocket Secure 等安全传输;
- Binding 层:本 Profile 定义的 JSON-RPC 2.0 绑定;
- Business 层:Direct Base、Group Base 等业务语义;
- Security Overlay 层:Direct E2EE、Group E2EE 等安全语义;
- Media/Object 层:Attachment 等大对象扩展。
为了帮助读者快速建立对 ANP 分层边界的整体心智模型,下图给出从传输层到媒体 / 对象层的总览。后续各 Profile 都是在这一分层框架上继续收紧自己的对象、流程与约束。
flowchart TB
T[Transport 层<br/>HTTPS / WSS / 安全信道]
B[Binding 层<br/>anp.core.binding.v1<br/>JSON-RPC 2.0 / meta / auth / body]
D[Business 层<br/>Direct Base / Group Base]
S[Security Overlay 层<br/>Direct E2EE / Group E2EE]
M[Media / Object 层<br/>Attachment / 对象传输]
T --> B --> D --> S --> M2
3
4
5
6
7
8
图 P1-1:ANP 分层总览(非规范性)。
本图强调的是职责边界,而不是部署形态:某个实现可以把多层合并在同一服务中,但跨实现互通时仍应保持这些层的语义分离。
3.2 最小互通原则
不同实现只要满足本 Profile 约束,即可共享相同的:
- 请求 / 响应格式;
- 通知格式;
- 通用字段语义;
- 能力协商方式;
- 错误模型;
- 幂等处理原则。
3.3 非目标
本 Profile 不定义以下能力:
- 历史拉取;
- 已读状态;
- 设备同步;
- 在线状态;
- 内部副本一致性;
- 具体 E2EE 算法。
这些能力必须由其它 Profile 定义,或明确声明为超出 ANP 标准范围。
3.4 Profile 标识
本 Profile 的标准名称为:
anp.core.binding.v1
后续 Profile 在声明依赖关系时,MUST 使用该名称引用本 Profile。
4. 绑定基础
4.1 JSON-RPC 版本
ANP Core Binding MUST 使用 JSON-RPC 2.0。
每个请求对象和响应对象中的 jsonrpc 成员 MUST 精确等于字符串 "2.0"。
4.2 安全传输要求
所有 ANP 绑定 MUST 运行在经过认证的安全传输层之上,例如:
- HTTPS;
- WSS;
- 其它能够提供机密性、完整性与对端认证的安全信道。
本 Profile 不允许在未认证、未加密的裸传输上运行。
4.3 传输无关性
本 Profile 在逻辑上是传输无关的;HTTP(S) 与 WSS 是推荐绑定,但不是唯一允许的绑定。
任意新绑定只要不改变本 Profile 的消息对象语义,即 MAY 被定义为补充绑定文档。
5. JSON-RPC 互操作约束
5.1 params 形式
JSON-RPC 原规范允许 params 采用按位置数组或按名称对象。
ANP 中,params MUST 为对象;MUST NOT 使用数组形式。
若收到数组形式 params,接收方 MUST 返回 anp.invalid_params_shape 错误。
5.2 id 类型
JSON-RPC 原规范允许 id 为字符串、数字或 null。
ANP 中,Request 的 id MUST 为非空字符串。
ANP Request MUST NOT 使用数字 id。
ANP Request MUST NOT 使用 null 作为 id。
若收到不符合要求的 id,接收方 MUST 返回 anp.invalid_request_id。
5.3 Notification 使用范围
ANP 中,Notification 仅用于以下场景:
- 对端主动推送的异步事件;
- 不要求确认、也不应返回错误详情的单向提示。
以下操作 MUST NOT 使用 Notification:
- 改变持久状态的控制操作;
- 需要幂等确认的消息发送;
- 需要调用方感知成功或失败的任何操作。
5.4 Batch 禁止
JSON-RPC 的 batch 调用在 ANP 中 MUST NOT 使用。
客户端 MUST NOT 发送 batch。
服务端收到 batch 时 MUST 拒绝,并返回 anp.batch_not_supported。
5.5 方法名约束
方法名 MUST 为字符串,并遵循以下命名规则:
- 采用逻辑命名空间;
- 以小写字母开头;
- 段间使用
.分隔; - 方法名 MUST NOT 以
rpc.开头; - 业务方法 SHOULD 使用
<domain>.<action>风格。
推荐示例:
anp.get_capabilitiesdirect.sendgroup.creategroup.addgroup.send
5.6 响应约束
除 Notification 外,服务端 MUST 对每个 Request 返回一个 Response。
成功响应 MUST 含有 result,且 MUST NOT 含有 error。
失败响应 MUST 含有 error,且 MUST NOT 含有 result。
Response 的 id MUST 与对应 Request 的 id 完全一致。
6. 通用 params 结构
6.1 顶层对象
除某些明确例外的方法外,ANP 的 params MUST 采用如下结构:
{
"meta": { "...": "..." },
"auth": { "...": "..." },
"body": { "...": "..." }
}2
3
4
5
其中:
meta:通用元数据,承载解释 Profile、目标、幂等、安全模式等;auth:可选的认证与证明对象;只有当具体 Profile 明确要求时才出现;body:方法特定参数。
若某具体 Profile 未定义 auth,则调用方 MAY 省略它。
若某具体 Profile 明确要求 auth,则调用方 MUST 提供且接收方 MUST 验证。
除 meta、auth、body 之外的顶层 params 成员,只有在对应 Profile 明确定义时才允许出现。
下面的图示把本 Profile 在文字中反复出现的外层 envelope 收敛成一个统一视图,便于读者理解 Request、Notification 与 Response 共享了哪些结构,以及 meta、auth、body 分别承载什么职责。
flowchart TB
A[ANP JSON-RPC 对象]
A --> Req[Request<br/>有 id]
A --> Noti[Notification<br/>无 id]
A --> Resp[Response]
Req --> Params[params]
Noti --> Params
Params --> Meta[meta<br/>profile / security_profile / sender_did / target / operation_id / message_id / content_type]
Params --> Auth[auth<br/>按具体 Profile 决定是否出现]
Params --> Body[body<br/>方法特定参数]
Resp --> Ok[成功响应<br/>result]
Resp --> Err[失败响应<br/>error]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
图 P1-2:ANP JSON-RPC 信封结构(非规范性)。
后续各业务 Profile 与安全 Overlay 都只应在 body 和必要的 auth 约束上扩展,而不应重新发明另一套与本图冲突的顶层绑定结构。
6.2 meta 对象
meta 对象字段定义如下:
6.2.1 anp_version
- 类型:字符串
- 要求:MAY
- 语义:ANP 主版本提示
- 默认值:若省略,接收方 MUST 按
"1.0"解释 - 说明:
- 该字段保留用于显式调试或跨版本网关;
- v1 中优先以
profile决定解释规则; - 新实现 SHOULD 将其视为兼容字段,而不是主要协商字段。
6.2.2 profile
- 类型:字符串
- 要求:MUST
- 语义:本次请求的唯一解释 Profile
- 说明:
profile用于声明“当前请求的body、result、错误约束与方法语义由哪个 Profile 解释”;profileMUST NOT 同时表达多个 Profile 的并集语义;security_profile只表达安全模式,不替代profile。
- 示例:
"anp.direct.base.v1""anp.group.base.v1""anp.direct.e2ee.v1""anp.group.e2ee.v1"
6.2.3 security_profile
- 类型:字符串
- 要求:MUST
- 语义:本次调用的安全模式
- 允许值:
"transport-protected""direct-e2ee""group-e2ee"
- 说明:
security_profile表示当前请求要求采用的安全模式;- 它描述的是安全级别或安全语义,而不是
body的解释语法; - 若某
profile只允许某些security_profile组合,必须由对应 Profile 明确规定。
6.2.4 sender_did
- 类型:字符串(DID)
- 要求:除匿名公共发现能力外,MUST
- 语义:本次请求在业务语义上的发送主体 DID(business origin DID / logical sender DID)
- 说明:
- 对普通 Request,
sender_didSHOULD 表示当前业务发起方; - 对服务端生成的 Notification,是否允许省略
sender_did或改由其它字段表达逻辑签发者,由具体 Profile 定义; sender_didMUST NOT 被自动等同于外层传输连接的一跳调用者身份。
- 对普通 Request,
6.2.5 target
- 类型:对象
- 要求:当方法存在协议级目标时 MUST
- 结构:
{
"kind": "agent | group | service",
"did": "did:example:..."
}2
3
4
- 说明:
kind = "agent"表示目标为单个 Agent;kind = "group"表示目标为单个群;kind = "service"表示目标为某个公开ANPMessageService.serviceDid;target.didMUST NOT 直接承载传输层 URL;- 任何方法 Profile MUST 明确声明自己是
agent-addressed、group-addressed、service-scoped还是endpoint-local; - 是否允许省略
target,MUST 由具体 Profile 显式声明,调用方与接收方 MUST NOT 自行猜测。 - 若某方法要求
auth.origin_proof,则meta.targetMUST 存在,且meta.target.kindMUST 为agent、group、service之一。
6.2.5.1 目标建模模式声明规则
为消除不同 Profile 对 target 的解释分叉,具体 Profile MUST 明确声明其方法属于以下哪一种目标建模模式:
agent-addressed
meta.target.kind = "agent"meta.target.did指向目标 Agent DID
group-addressed
meta.target.kind = "group"meta.target.did指向目标 Group DID
service-scoped
meta.target.kind = "service"meta.target.did指向目标公开ANPMessageService.serviceDid
endpoint-local
- 仅当对应 Profile 明确声明时,才允许省略
meta.target
- 仅当对应 Profile 明确声明时,才允许省略
若某方法未被其 Profile 明确声明为 endpoint-local,则接收方 MUST 按“需要显式 target”处理。
若某请求的 meta.target.kind 与该方法声明的目标建模模式不一致,接收方 MUST 返回 anp.invalid_target_binding。
6.2.6 operation_id
- 类型:字符串
- 要求:所有会改变状态的操作 MUST
- 语义:本次操作的幂等标识
- 规则:
- 同一发起方在同一语义上下文中重试时,
operation_idMUST 保持不变; - 幂等作用域 MUST 由具体 Profile 明确定义;
- 服务端 MUST 先进行幂等命中检查,再进行乐观并发或版本前置条件检查;
- 对消息类操作,发送方 SHOULD 直接令
operation_id = message_id,除非其确实需要区分“消息标识”和“操作重试标识”。
- 同一发起方在同一语义上下文中重试时,
6.2.7 message_id
- 类型:字符串
- 要求:Message-bearing Operation MUST
- 语义:应用层消息标识
- 说明:
message_id用于消息级唯一识别或重复识别;message_id与operation_id可以相同,也可以不同;- 若实现没有独立的操作生命周期,SHOULD 直接复用
message_id作为operation_id; message_idMUST NOT 隐式替代operation_id的通用幂等语义,除非对应 Profile 明确允许二者相同;- 当具体方法是 message-bearing Notification 时,本条约束同样适用。
6.2.8 created_at
- 类型:字符串(RFC 3339 时间)
- 要求:SHOULD
- 语义:发起方创建该操作的时间戳
- 说明:除非后续 Profile 另有规定,
created_at不得作为唯一的防重放依据。
6.2.9 trace_id
- 类型:字符串
- 要求:不再作为标准互通字段
- 语义:实现内部追踪标识
- 说明:
- 若部署需要跨服务追踪,SHOULD 使用传输层元数据或私有扩展字段(例如
x_trace_id); - 接收方 MUST NOT 将其纳入任何安全语义、授权判断或幂等判断。
- 若部署需要跨服务追踪,SHOULD 使用传输层元数据或私有扩展字段(例如
6.2.10 content_type
- 类型:字符串
- 要求:Message-bearing Operation MUST
- 语义:当前消息操作的主业务负载类型;若当前 Profile / Overlay 使用独立的外层 envelope,则表示该外层 envelope 的类型。
规则如下:
- 在 Base Profile 中,若
body只是结构化承载容器(例如text/payload/payload_b64u互斥结构),则meta.content_typeMUST 描述该容器中的主业务负载类型,而不是 JSON 容器对象本身的类型; - 在 Security Overlay 中,若
body承载独立密文 envelope,则meta.content_typeMUST 表示该外层 envelope 的 wire object type; - 原始应用内容类型若与外层 envelope 类型不同,MUST 由对应 Overlay 在其内部字段(如
application_content_type)中表达; - 当具体方法是 message-bearing Notification 时,本条规则同样适用;
- 对
meta.content_type的基础解释权由本 Profile 唯一规定;其它业务 Profile 与安全 Overlay MUST NOT 重写其基础语义。
示例:
- Direct Base 文本消息:
text/plain - Group Base JSON 消息:
application/json - Direct E2EE 文本消息:外层
meta.content_type = "application/anp-direct-cipher+json",内层application_content_type = "text/plain" - Group E2EE 附件消息:外层
meta.content_type = "application/anp-group-cipher+json"
其中,若 Group E2EE 的内层原始业务类型是附件清单,则应在内层明文中写:
{
"application_content_type": "application/anp-attachment-manifest+json"
}2
3
而 不是 在外层 meta.content_type 中继续写附件清单类型。
6.3 body 对象
body 对象为方法特定参数集合:
- 业务 Profile MUST 定义其字段;
- 安全 Overlay Profile MUST 定义其密码学字段;
body中未识别字段是否可被忽略,MUST 由对应 Profile 明确说明;- 对影响安全、路由、权限、幂等或状态机语义的未知字段,接收方 MUST 拒绝。
7. 负载表示规则
7.1 JSON 对象优先
凡能够自然表达为 JSON 对象的业务对象,SHOULD 直接以 JSON 对象表示。
ANP MUST NOT 采用“在 JSON 字符串中再嵌 JSON”的双重序列化作为默认做法。
7.2 二进制表示
需要传输二进制负载时,字段 MUST 采用无填充 base64url 文本表示。
相关字段名 SHOULD 以 _b64u 结尾,例如:
ciphertext_b64ukey_package_b64uwelcome_b64u
7.3 数值表示
为避免不同语言对大整数、计数器、序号的表示差异,以下字段 MUST 采用十进制字符串表示:
- 计数器;
- 序列号;
- 逻辑时钟;
- epoch;
- generation;
- 大整数长度;
- 任何可能超过 IEEE 754 双精度安全整数范围的数值。
如果后续 Profile 需要对 JSON 做规范化签名,必须明确定义签名输入的序列化规则。
一旦某 Profile 定义了 Signed Payload 或等价的密码学绑定对象,该 Profile MUST 指定唯一的规范化算法;不同实现 MUST NOT 自行选择不同“稳定序列化”策略。
8. 能力协商
8.1 总则
ANP Endpoint MUST 暴露能力协商接口。
能力协商的结果 MUST 至少包括:
- 支持的 ANP Profile 列表;
- 支持的 Security Profile 列表;
- 运行时服务身份;
- 实现约束(如最大负载、最大对象大小、节流策略等)。
实现方 MAY 返回更细粒度扩展字段(如支持的内容类型、方法级能力、Notification 能力、认证 scheme 能力),但这些扩展字段不影响本节定义的最小标准响应结构。
8.2 标准方法:anp.get_capabilities
8.2.1 请求
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "anp.get_capabilities",
"params": {
"meta": {
"profile": "anp.core.binding.v1",
"security_profile": "transport-protected",
"operation_id": "op-cap-001",
"created_at": "2026-03-29T12:00:00Z"
},
"body": {}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
说明:
anp.get_capabilitiesMAY 作为匿名公共发现能力调用;- 匿名调用时,
meta.sender_didMAY 省略; - 若服务端基于身份返回不同能力子集,则调用方 MAY 在已认证上下文中再次调用。
8.2.2 成功响应
{
"jsonrpc": "2.0",
"id": "req-001",
"result": {
"service_did": "did:example:service",
"supported_profiles": [
"anp.core.binding.v1",
"anp.direct.base.v1",
"anp.group.base.v1",
"anp.direct.e2ee.v1"
],
"supported_security_profiles": [
"transport-protected",
"direct-e2ee"
],
"limits": {
"max_request_bytes": "1048576",
"max_message_bytes": "262144"
},
"supported_content_types": [
"text/plain",
"application/json",
"application/anp-attachment-manifest+json"
]
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
说明:
result.service_did表示当前运行时能力结果所对应的服务身份 DID;- 静态 DID 文档只提供 hint,运行时能力以此结果为准;
supported_content_types属于推荐扩展,但非常常见,服务端 SHOULD 尽量返回。
8.3 协商规则
- DID 文档中的静态扩展字段仅表示可缓存的静态 hint;
anp.get_capabilities的返回结果表示运行时权威能力(runtime authority);- 若静态 hint 与运行时能力冲突,调用方 MUST 以运行时能力结果为准并刷新缓存;
- 调用方 SHOULD 在首次交互前,或在缓存过期后,获取目标服务能力;
- 如果请求中的
profile或security_profile不被支持,服务端 MUST 返回明确错误; - 调用方 MUST NOT 假定“对方支持 Base Profile 就一定支持 E2EE Overlay”。
静态 DID 文档里的 hint 与运行时能力返回之间容易被实现者混淆。下图把推荐的协商顺序固定下来,突出“静态信息用于发现,运行时结果用于裁决”的原则。
sequenceDiagram
participant C as 调用方
participant D as DID 文档
participant S as ANPMessageService
C->>D: 解析目标 DID
D-->>C: serviceEndpoint + 静态 hint
C->>S: anp.get_capabilities
S-->>C: service_did + supported_profiles + supported_security_profiles + limits
Note over C,S: 运行时结果优先于静态 hint
C->>C: 刷新缓存并选择实际 profile / security_profile2
3
4
5
6
7
8
9
10
11
图 P1-3:能力协商与运行时权威(非规范性)。
实现方在静态 hint 与运行时能力冲突时,应以本图中的运行时结果为准,并把冲突视为需要更新本地缓存的信号。
9. 幂等与重试
9.1 幂等原则
所有状态改变型操作 MUST 支持幂等。
同一 (sender_did, target_scope, method, operation_id) 的重复请求:
- 若语义等价,服务端 MUST 返回同一结果或等价结果;
- 若语义冲突,服务端 MUST 返回
anp.idempotency_conflict。
其中:
target_scope的具体取值 MUST 由对应 Profile 定义;- 对 Direct 类方法,
target_scope通常为target.did; - 对 Group 类方法,
target_scope通常为group_did。
9.2 消息重试
对于消息发送类操作:
- 重试时
message_idMUST 保持不变; - 重试时
operation_idMUST 保持不变; - 若实现无独立操作语义,发送方 SHOULD 让两者直接相同;
- 服务端 MUST 先检查操作级幂等记录;
- 对消息级重复识别所使用的键(如是否包含
message_id),必须由对应消息 Profile 明确定义。
9.3 非幂等操作
如果某操作天生不可幂等,对应 Profile MUST 明确标注,并给出替代补救机制。
未明确标注者,一律视为必须可幂等。
10. 错误模型
10.1 总则
ANP 使用 JSON-RPC 的 error 对象承载错误。
ANP 保留 JSON-RPC 标准错误码原语义,同时定义 ANP 自身的应用错误编码。
对下列情形,服务端 SHOULD 优先使用 JSON-RPC 标准错误码:
| 场景 | 推荐 JSON-RPC 错误码 |
|---|---|
| 无法解析 JSON | -32700 Parse error |
| 非法 JSON-RPC 对象 | -32600 Invalid Request |
| 方法不存在 | -32601 Method not found |
| 参数形状不合法 | -32602 Invalid params |
| 服务端内部异常 | -32603 Internal error |
对 ANP 业务层错误,服务端 SHOULD 使用本文件定义的 1000+ 错误码,并同时在 error.data.anp_code 中提供机器可识别语义。
10.2 ANP 错误对象扩展
error 对象建议结构:
{
"code": 1001,
"message": "Unsupported profile",
"data": {
"anp_code": "anp.unsupported_profile",
"retryable": false,
"details": {}
}
}2
3
4
5
6
7
8
9
当 code 属于 ANP 自定义错误范围时,error.data.anp_code MUST 存在。
10.3 ANP 公共错误码
code | anp_code | 含义 |
|---|---|---|
| 1000 | anp.invalid_request_id | id 非法 |
| 1001 | anp.unsupported_profile | 不支持所请求的 Profile |
| 1002 | anp.unsupported_security_profile | 不支持所请求的安全模式 |
| 1003 | anp.invalid_params_shape | params 结构不符合要求 |
| 1004 | anp.batch_not_supported | 不支持 batch |
| 1005 | anp.unauthorized | 未通过认证 |
| 1006 | anp.forbidden | 已认证但无权限 |
| 1007 | anp.target_not_found | 目标 DID 不存在或不可达 |
| 1008 | anp.idempotency_conflict | 幂等键冲突 |
| 1009 | anp.unsupported_content_type | 不支持内容类型 |
| 1010 | anp.delivery_rejected | 目标服务拒绝接收 |
| 1011 | anp.rate_limited | 触发限流 |
| 1012 | anp.temporarily_unavailable | 服务暂时不可用 |
| 1013 | anp.invalid_security_binding | 安全模式与负载结构不匹配 |
| 1014 | anp.invalid_target_binding | 方法要求的目标建模模式与实际 meta.target 不匹配 |
10.4 错误返回要求
- 对 ANP 自定义错误,服务端 MUST 返回可机器判定的
anp_code; messageSHOULD 简短、可读;data.retryableSHOULD 明确可否重试;- 任何错误 MUST NOT 泄露不必要的敏感内部状态。
- 对目标绑定错误、service-scoped / endpoint-local 误用等情况,SHOULD 返回
anp.invalid_target_binding。
11. 方法注册与命名空间
11.1 命名空间
建议使用如下一级命名空间:
anp.*direct.*group.*attachment.*federation.*
11.2 版本管理
Profile 名称 MUST 显式带版本,例如:
anp.core.binding.v1anp.identity.discovery.v1anp.direct.base.v1
11.3 扩展方法
实现方 MAY 定义私有扩展方法,但:
- MUST NOT 与标准方法同名;
- SHOULD 使用私有前缀;
- MUST NOT 假定其它实现理解这些方法。
12. 兼容性与版本演进
12.1 前向兼容
接收方对于未知扩展字段的处理规则如下:
- 对未知核心
meta字段,接收方 MUST 拒绝; - 对以
x_开头的实现扩展meta字段,接收方 MAY 忽略; - 对未知
auth字段,接收方 MUST 拒绝,除非对应 Profile 显式声明可扩展; - 对未知
body字段,只有在对应 Profile 明确声明可忽略时,接收方才 MAY 忽略; - 若未知字段影响安全、路由、权限、幂等或状态机语义,接收方 MUST 拒绝。
12.2 破坏性变更
以下变更视为破坏性变更,必须升级 Profile 主版本:
meta字段含义变化;- 错误码语义变化;
- 方法名语义变化;
- 安全模式语义变化;
- 负载结构不再兼容。
13. 安全注意事项
13.1 安全模式固定
调用方与服务端 MUST NOT 在未明确协商的情况下,从高安全模式静默降级到低安全模式。
若目标不支持请求的 security_profile,服务端 MUST 明确返回 anp.unsupported_security_profile。
13.2 时间戳不是主防重放机制
created_at MUST NOT 作为唯一防重放机制。
防重放应由后续 Profile 在会话态、消息态或群态中定义。
13.3 追踪字段隔离
trace_id、日志标签、监控字段 MUST NOT 参与任何密码学绑定或业务授权判断。
13.4 负载互斥
若某 Profile 定义 body.payload 与 body.payload_b64u 为互斥字段,则发送方 MUST NOT 同时提供二者;接收方收到冲突输入时 MUST 拒绝。
14. 隐私注意事项
14.1 最小元数据原则
发送方 SHOULD 仅在 meta 中放置跨实现互通所必需的最小元数据。
14.2 不引入设备语义
本 Profile 只识别 Agent 与 Group,不定义设备、终端、副本或内部运行单元。
这些概念属于实现内部,不得作为 Core Binding 的标准字段强制出现。
14.3 能力缓存
调用方 SHOULD 缓存能力协商结果,但 MUST 在能力变化、验证失败、服务端点切换或缓存失效时重新协商。
15. 最小互通要求
一个 ANP Core Binding 合规实现至少 MUST 支持:
- JSON-RPC 2.0;
- 对象形式
params; - 字符串
id; anp.get_capabilities;- 公共错误码;
- 幂等
operation_id; meta/body顶层结构;- 安全传输;
- 对匿名或已认证的
anp.get_capabilities处理; - 统一的
content_type语义:外层永远表示当前 wire object type; - 对每个方法显式声明目标建模模式:
agent-addressed、group-addressed、service-scoped或endpoint-local; - 对
service-scoped方法强制校验meta.target.kind = "service"与target.did = serviceDid; - 对
endpoint-local方法显式声明可省略target,并在未声明时拒绝模糊省略。
16. 示例
以下示例仅演示 Core Binding 外层 envelope;Overlay 方法(例如 group.e2ee.send、group.e2ee.notice)同样受本 Profile 的 Request / Notification、meta、目标建模与错误模型约束。
16.1 direct.send 请求示例
{
"jsonrpc": "2.0",
"id": "req-10001",
"method": "direct.send",
"params": {
"meta": {
"profile": "anp.direct.base.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "agent",
"did": "did:example:agent-b"
},
"operation_id": "msg-10001",
"message_id": "msg-10001",
"created_at": "2026-03-29T12:00:00Z",
"content_type": "text/plain"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_SHA256_OF_SIGNED_DIRECT_PAYLOAD:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774785600;expires=1774785660;nonce=\"n-10001\";keyid=\"did:example:agent-a#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"text": "hello"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
16.2 成功响应示例
{
"jsonrpc": "2.0",
"id": "req-10001",
"result": {
"accepted": true,
"message_id": "msg-10001",
"operation_id": "msg-10001",
"target_did": "did:example:agent-b",
"accepted_at": "2026-03-29T12:00:01Z"
}
}2
3
4
5
6
7
8
9
10
11
17. IANA / 注册表占位
本标准后续版本 SHOULD 建立以下注册表:
- ANP Profile 名称注册表;
- Security Profile 注册表;
- Content-Type 注册表;
- ANP 错误码注册表。
18. 参考实现说明(非规范性)
实现方在落地本 Profile 时,宜采用如下原则:
- Core Binding 只保留真正跨实现必须一致的字段;
- DID 文档中的静态 hint 只做发现,不做运行时裁决;
- 业务层只关心业务语义,安全细节放在 Overlay 中;
- 追踪、路由和内部网关字段尽量放在私有扩展或传输层,不进入标准互通边界。
附录 A(规范性):共享 Origin Proof 承载约定
本附录定义 P3、P4、P6 以及未来业务 Profile 共享的应用层原发者证明(Origin Proof)承载约定。
本附录不重复定义通用签名算法、Structured Field 序列化或 JSON 规范化算法;这些内容由下列标准直接提供:
- RFC 8785:JSON Canonicalization Scheme(JCS)
- RFC 9530:
Content-Digest字段值格式 - RFC 9421:
Signature-Input、Signature、signature base 的构造与验证模型 - RFC 3986:URI 百分号编码规则
- 对
did:wba的 DID 解析、验证方法授权关系和路径指纹绑定校验,遵循对应 did:wba 方法规范
ANP 在本附录中只定义以下自定义部分:
auth.origin_proof的承载字段;- 统一的 Signed Request Object;
- 应用层
@method/@target-uri/content-digest组件映射; - 与 hop / service 认证、跨域转发之间的职责边界。
A.1 统一 auth.scheme 与 auth.origin_proof
当某业务 Profile 使用应用层原发者证明时:
auth.schemeMUST 等于anp-rfc9421-origin-proof-v1auth.origin_proofMUST 存在auth本身 MUST NOT 进入摘要输入
推荐结构如下:
{
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_SHA256_DIGEST:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1733402096;expires=1733402156;nonce=\"abc123\";keyid=\"did:wba:example.com:user:alice:e1_<fingerprint>#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
}
}2
3
4
5
6
7
8
9
10
说明:
contentDigest保存的是 RFC 9530Content-Digest的字段值signatureInput保存的是 RFC 9421Signature-Input的字段值signature保存的是 RFC 9421Signature的字段值
A.2 共享 origin_proof 对象结构
origin_proof MUST 至少包含以下字段:
contentDigestsignatureInputsignature
除非未来版本另有规定,v1 约定如下:
contentDigestMUST 使用sha-256signatureInputMUST 使用标签sig1signatureMUST 使用标签sig1- 覆盖组件集合 MUST 固定为:
("@method" "@target-uri" "content-digest")关于这些字段值的具体语法、序列化与验证,发送方和验证方 MUST 直接遵循 RFC 9530 与 RFC 9421,而 MUST NOT 自行发明替代格式。
A.3 共享 Signed Request Object
contentDigest MUST 绑定一个不包含 auth 的标准业务对象,称为 Signed Request Object。
通用结构如下:
{
"method": "<jsonrpc method>",
"meta": {
"...": "..."
},
"body": {
"...": "..."
}
}2
3
4
5
6
7
8
9
规则如下:
- Signed Request Object MUST 只包含
method、meta、body - 它 MUST NOT 包含
jsonrpc、id、auth - 发送方 MUST 使用 RFC 8785 JCS 对其规范化序列化后再计算
contentDigest - 缺省的可选字段 MUST 直接省略
- 上游服务路由信息、本地缓存字段、运维追踪字段 MUST NOT 纳入 Signed Request Object
说明:
- 业务 Profile MAY 继续约束
meta/body中的必选字段 - 但只要某方法要求
auth.origin_proof,其摘要对象一律是本附录定义的 Signed Request Object,而不是各 Profile 再定义新的通用签名外壳
A.4 全局组件映射
当 did:wba 认证信息承载在 ANP JSON-RPC 请求中时,为保证签名在跨服务转发下保持稳定,Signature-Input 中的关键组件 MUST 使用以下全局应用层映射:
@method:映射为Signed Request Object.method@target-uri:映射为anp://{meta.target.kind}/{pct-encoded meta.target.did}content-digest:映射为 Signed Request Object 的contentDigest值
其中:
pct-encodedMUST 基于meta.target.did的 UTF-8 字节,并按 RFC 3986 百分号编码处理- 当某方法要求
auth.origin_proof时,meta.targetMUST 存在 meta.target.kindMUST 取agent、group、service之一- endpoint-local 方法若未来需要引入
auth.origin_proof,MUST 由对应 Profile 显式定义其目标建模与重建规则
说明性要求:
meta.target.kind 已经通过 Signed Request Object 进入 contentDigest;@target-uri 继续显式携带 kind,是为了让目标类别在 signature base 中保持可读、可审计、可独立检查的稳定语义,而不是依赖验证者先展开整个摘要对象后才能知道目标类型。
P1 附录 A 是多个业务 Profile 共享的原发者证明基础。下图把 Signed Request Object、contentDigest 与 @method / @target-uri / content-digest 三者之间的关系压缩到一张图里,便于后续文档直接复用。
flowchart LR
M1[method]
M2[meta]
M3[body]
M1 --> SRO[Signed Request Object]
M2 --> SRO
M3 --> SRO
SRO --> JCS[RFC 8785 JCS]
JCS --> CD[contentDigest]
M1 --> HM[@method]
M2 --> TU[@target-uri<br/>anp://kind/pct-encoded-did]
HM --> SB[Signature Base]
TU --> SB
CD --> SB
SB --> SI[signatureInput]
SB --> SG[signature]
CD --> OP[auth.origin_proof]
SI --> OP
SG --> OP2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
图 P1-4:Signed Request Object 与 Origin Proof 绑定(非规范性)。
后续凡要求 auth.origin_proof 的业务方法,都应回到这张公共绑定图来理解摘要输入与签名组件来源,而不应在各自文档中再定义一套新的通用签名外壳。
A.5 与标准签名模型的关系
除本附录定义的应用层组件映射外,发送方和验证方 MUST 直接复用 RFC 9421 的签名模型:
signatureInput的字段值构造signature的字段值构造- signature base 的生成
- 覆盖组件顺序解释
@signature-params的构造与校验
也就是说:
- 发送方 MUST 对 RFC 9421 语义下的 signature base 进行签名
- MUST NOT 直接对原始 JSON 请求文本签名
- MUST NOT 直接对
signatureInput这个 JSON 字符串字段本身签名
本附录只替换“组件值从哪里来”这一层:
在标准 HTTP Message Signatures 中,组件通常来自 HTTP 消息;在 ANP 中,它们来自本附录定义的应用层映射。
A.6 最小验证要求
验证方 MUST 至少执行以下步骤:
- 读取
auth.origin_proof - 提取
contentDigest、signatureInput、signature - 使用当前请求的
method、params.meta、params.body重建 Signed Request Object - 使用 RFC 8785 JCS 对其规范化序列化
- 重算
contentDigest - 从
method重建@method - 从
meta.target.kind与meta.target.did重建@target-uri - 按 RFC 9421 模型重建并验证 signature base
- 解析
keyid指向的 DID 文档,并检查验证方法存在且被authentication关系授权 - 按对应 DID 方法规则验证签名、时间窗口与防重放策略
若任一步骤失败,验证方 MUST 拒绝该请求。
A.7 DID 与验证关系
keyidMUST 指向一个可解析的 DID URL- 验证方 MUST 解析
keyid所属 DID 文档,并检查该验证方法是否被authentication关系授权 keyid所属 DID MUST 与业务 Profile 要求的业务主体 DID 一致- 对 did:wba 路径型
e1_DID,验证方 MUST 额外执行路径指纹绑定校验
说明:
- 在当前 P3、P4、P6 的请求语义中,业务主体 DID 通常是
meta.sender_did - 若未来某个通知型或声明型 Profile 使用不同业务主体 DID,MUST 由该 Profile 单独说明
A.8 与跳级认证的关系
anp-rfc9421-origin-proof-v1 证明的是业务原发者身份,而不是当前网络一跳调用方身份。
因此:
- 任意一跳的 hop / service 认证 MAY 变化
- 中间服务 MUST NOT 把自己的服务级身份重写成新的业务 Origin Proof
- 目标接收方 MUST 独立验证业务 Origin Proof,而 MUST NOT 仅凭上游服务身份推定其成立
A.9 跨域转发
若原始业务请求携带 auth.origin_proof,则跨域发送方:
- MUST 保持其不变并随请求一起发送
- MUST NOT 重建新的业务 Origin Proof
- MUST NOT 用外层 HTTP
serviceDid签名替代auth.origin_proof
说明:
- 外层跨域 HTTP 认证用于证明“当前是哪一个服务在调用下一跳”
auth.origin_proof用于证明“哪个业务主体发起了该动作”- 两者职责不同,MUST NOT 互相替代
附录 B(规范性):共享 Object Proof Profile
本附录定义 P4、P5、P6 以及未来对象型 Profile 共享的“对象证明(Object Proof)”配置。凡某对象章节声明其 proof 使用本附录时,该 proof MUST 遵循本附录。
B.0 规范性参考与定位
本附录复用的是 W3C Data Integrity 证明框架及其相关密码套件,而不是整体采用 Verifiable Credentials 数据模型。
更具体地说:
DataIntegrityProof的通用 proof 框架,遵循 W3C Verifiable Credential Data Integrity 1.0;eddsa-jcs-2022cryptosuite 的生成与验证规则,遵循 W3C Data Integrity EdDSA Cryptosuites v1.0;- JSON 规范化算法,遵循 RFC 8785: JSON Canonicalization Scheme (JCS);
- 字节序列编码,遵循 RFC 3629: UTF-8, a transformation format of ISO 10646;
- DID 文档模型、验证关系与 DID URL 基本语义,遵循 W3C DID Core 1.0;
- 若部署使用
did:wba,则其方法特定解析、路径指纹绑定及其它附加校验,遵循对应的 DID 方法规范,例如 did:wba Method Specification。
本附录不重复定义 Data Integrity、eddsa-jcs-2022、JCS、UTF-8、DID Core 或 DID 方法本身。
ANP 在本附录中只统一以下内容:
- 对象级
proof的固定承载形状; - 被保护文档(protected document)的确定规则;
- UTF-8 + RFC 8785 JCS 的规范化序列化要求;
proofPurpose = "assertionMethod"的默认统一语义;- 共享验证步骤与对象特定约束的分工边界。
B.1 适用范围
当前 v1 中,以下对象 MUST 使用本附录:
- P4 的
group_receipt.proof - P5 的
prekey_bundle.proof - P6 的
did_wba_binding.proof
未来若其它 Profile 引入同类对象级 proof,且未显式定义不同 profile,则 SHOULD 复用本附录。
B.2 统一 proof 结构
使用本附录的对象,其 proof MUST 至少包含:
typecryptosuiteverificationMethodproofPurposecreatedproofValue
推荐结构如下:
{
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "did:example:issuer#key-1",
"proofPurpose": "assertionMethod",
"created": "2026-03-29T12:00:00Z",
"proofValue": "z..."
}
}2
3
4
5
6
7
8
9
10
v1 统一要求如下:
proof.typeMUST 等于DataIntegrityProofproof.cryptosuiteMUST 等于eddsa-jcs-2022proof.proofPurposeMUST 等于assertionMethodproof.verificationMethodMUST 为完整 DID URLproof.createdMUST 为 RFC 3339 时间字符串proof.proofValueMUST 使用 base58-btc multibase(z...)
除非对应对象 Profile 显式允许,否则实现 MUST NOT 为该共享 profile 重新解释这些公共字段的语义。
B.3 被保护文档
对使用本附录的任一对象,生成与验证 proof 时的被保护文档 MUST 是:
移除该对象顶层
proof成员后的整个对象
这意味着:
- 保护范围 MUST NOT 缩小为若干局部字段
- 也 MUST NOT 扩大到外层 JSON-RPC envelope、HTTP 头、传输层元数据或本地缓存字段
- 缺省可选字段 MUST 直接省略
- MUST NOT 使用
null、空字符串、空对象占位或其它哑值代替“字段不存在”
若未来某对象需要嵌套 proof、分离子对象 proof 或其它特殊覆盖模型,MUST 由对应 Profile 显式定义;未显式定义时,一律按本节处理。
B.4 规范化与序列化
使用本附录时,被保护文档 MUST 先进行:
- RFC 8785 JSON Canonicalization Scheme(JCS)规范化
- UTF-8 编码
随后再按 eddsa-jcs-2022 的要求生成或验证 proof。
除非对应对象 Profile 另有明确规定,验证方与生成方 MUST NOT 使用其它“稳定序列化”“实现自定义排序”“pretty-print JSON”或本地特定编码来替代本节要求。
B.5 签发主体 DID 与验证方法授权
使用本附录的每一种对象,MUST 由对应对象 Profile 明确声明其签发主体 DID(issuer DID)。
对任一对象 proof:
proof.verificationMethod所属 DID MUST 等于该对象 Profile 规定的 issuer DIDproof.verificationMethodMUST 存在于 issuer DID 文档中proof.verificationMethodMUST 被 issuer DID 文档的assertionMethod关系授权proofPurpose固定为assertionMethod,其默认语义是:issuer DID 正在对该对象整体做出断言
若对应 DID 方法还要求额外校验(例如 did:wba 路径型 e1_ DID 的路径指纹绑定),验证方 MUST 同时执行该 DID 方法规定的额外检查。
B.6 与对象特定业务约束的分工
本附录统一的是 proof 框架,不是对象语义。
因此:
共享部分统一规定
proof的语法、被保护文档、规范化方式和默认授权关系各对象 Profile MUST 单独规定:
- 该对象的 issuer DID 是谁
- 该对象至少必须有哪些安全关键字段
- proof 验证通过后还需要做哪些业务一致性检查
换言之,验证方在 proof 通过后,MUST 继续校验对应对象 Profile 规定的字段完整性、对象语义与状态约束,而 MUST NOT 因为 proof 验证通过就跳过业务层检查。
B.7 最小验证要求
对使用本附录的对象,验证方 MUST 至少执行以下步骤:
- 读取对象
proof - 检查
type、cryptosuite、verificationMethod、proofPurpose、created、proofValue是否存在且满足本附录要求 - 按对应对象 Profile 确定 issuer DID
- 重建“移除顶层
proof后的整个对象”作为被保护文档 - 使用 UTF-8 + RFC 8785 JCS 对被保护文档规范化序列化
- 解析 issuer DID 文档
- 检查
proof.verificationMethod存在,且被 issuer DID 文档的assertionMethod授权 - 按
DataIntegrityProof + eddsa-jcs-2022验证 proof - 执行对象 Profile 规定的字段完整性、时间窗口、状态引用与其它业务检查
若任一步骤失败,验证方 MUST 拒绝该对象。