Skip to content

默认显示最新 1.1;也可查看历史 1.0。

ANP Profile 1:核心绑定(最终修订稿)

  • 文档编号:ANP-P1
  • 标题:核心绑定
  • 状态:Draft
  • 版本:0.2.0(最终修订稿)
  • 语言:中文
  • 适用范围:本 Profile 适用于所有 ANP 基础 Profile 与安全 Overlay Profile。

1. 目的

本 Profile 定义 ANP 的统一外层消息绑定、通用字段、能力协商、错误模型以及互操作约束。

本 Profile 的目标是:

  1. 为所有 ANP 方法提供统一的消息信封;
  2. 避免不同业务 Profile 重复发明请求、响应、通知和错误格式;
  3. 为 Direct Base、Group Base、Direct E2EE、Group E2EE、Attachment、Federation 等 Profile 提供共同基础;
  4. 在保留 JSON-RPC 2.0 基本兼容性的前提下,收紧可选自由度,降低跨实现歧义。

2. 术语与规范性约定

2.1 规范性关键字

本文中的 MUSTMUST NOTREQUIREDSHALLSHALL NOTSHOULDSHOULD NOTRECOMMENDEDNOT RECOMMENDEDMAYOPTIONAL 按照其大写形式解释为规范性要求。

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-protecteddirect-e2eegroup-e2ee
  • Operation:一次可被幂等识别的协议动作,例如发送消息、建群、加人、提交群状态变更。
  • Message-bearing Operation:携带应用层消息负载的操作,例如 direct.sendgroup.sendgroup.e2ee.send
  • Message-bearing Notification:作为 Notification 承载应用层消息负载的推送方法,例如 direct.incominggroup.incominggroup.e2ee.notice
  • Control Operation:不携带应用层业务消息,而是改变协议或业务状态的操作,例如 group.creategroup.addgroup.remove
  • Origin Proof:由业务主体私钥生成、并通过 auth.origin_proof 承载的应用层原发者证明。
  • Object Proof:通过对象内嵌 proof 对“移除 proof 后的整个对象”做出的可验证对象级断言。
  • Signed Request Object:由 methodmetabody 组成、用于计算 contentDigest 的共享规范化业务对象。

3. 设计原则

3.1 分层原则

ANP 采用如下分层:

  1. Transport 层:HTTP(S)、WebSocket Secure 等安全传输;
  2. Binding 层:本 Profile 定义的 JSON-RPC 2.0 绑定;
  3. Business 层:Direct Base、Group Base 等业务语义;
  4. Security Overlay 层:Direct E2EE、Group E2EE 等安全语义;
  5. Media/Object 层:Attachment 等大对象扩展。

为了帮助读者快速建立对 ANP 分层边界的整体心智模型,下图给出从传输层到媒体 / 对象层的总览。后续各 Profile 都是在这一分层框架上继续收紧自己的对象、流程与约束。

mermaid
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 --> M

图 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 用于以下场景:

  1. 对端主动推送的异步事件;
  2. 不要求确认、也不应返回错误详情的单向提示。

以下操作 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 NOTrpc. 开头;
  • 业务方法 SHOULD 使用 <domain>.<action> 风格。

推荐示例:

  • anp.get_capabilities
  • direct.send
  • group.create
  • group.add
  • group.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 采用如下结构:

json
{
  "meta": { "...": "..." },
  "auth": { "...": "..." },
  "body": { "...": "..." }
}

其中:

  • meta:通用元数据,承载解释 Profile、目标、幂等、安全模式等;
  • auth:可选的认证与证明对象;只有当具体 Profile 明确要求时才出现;
  • body:方法特定参数。

若某具体 Profile 未定义 auth,则调用方 MAY 省略它。
若某具体 Profile 明确要求 auth,则调用方 MUST 提供且接收方 MUST 验证。
metaauthbody 之外的顶层 params 成员,只有在对应 Profile 明确定义时才允许出现。

下面的图示把本 Profile 在文字中反复出现的外层 envelope 收敛成一个统一视图,便于读者理解 Request、Notification 与 Response 共享了哪些结构,以及 metaauthbody 分别承载什么职责。

mermaid
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]

图 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 用于声明“当前请求的 bodyresult、错误约束与方法语义由哪个 Profile 解释”;
    • profile MUST 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_did SHOULD 表示当前业务发起方;
    • 对服务端生成的 Notification,是否允许省略 sender_did 或改由其它字段表达逻辑签发者,由具体 Profile 定义;
    • sender_did MUST NOT 被自动等同于外层传输连接的一跳调用者身份。

6.2.5 target

  • 类型:对象
  • 要求:当方法存在协议级目标时 MUST
  • 结构:
json
{
  "kind": "agent | group | service",
  "did": "did:example:..."
}
  • 说明:
    • kind = "agent" 表示目标为单个 Agent;
    • kind = "group" 表示目标为单个群;
    • kind = "service" 表示目标为某个公开 ANPMessageService.serviceDid
    • target.did MUST NOT 直接承载传输层 URL;
    • 任何方法 Profile MUST 明确声明自己是 agent-addressedgroup-addressedservice-scoped 还是 endpoint-local
    • 是否允许省略 targetMUST 由具体 Profile 显式声明,调用方与接收方 MUST NOT 自行猜测。
    • 若某方法要求 auth.origin_proof,则 meta.target MUST 存在,且 meta.target.kind MUSTagentgroupservice 之一。

6.2.5.1 目标建模模式声明规则

为消除不同 Profile 对 target 的解释分叉,具体 Profile MUST 明确声明其方法属于以下哪一种目标建模模式:

  1. agent-addressed

    • meta.target.kind = "agent"
    • meta.target.did 指向目标 Agent DID
  2. group-addressed

    • meta.target.kind = "group"
    • meta.target.did 指向目标 Group DID
  3. service-scoped

    • meta.target.kind = "service"
    • meta.target.did 指向目标公开 ANPMessageService.serviceDid
  4. endpoint-local

    • 仅当对应 Profile 明确声明时,才允许省略 meta.target

若某方法未被其 Profile 明确声明为 endpoint-local,则接收方 MUST 按“需要显式 target”处理。

若某请求的 meta.target.kind 与该方法声明的目标建模模式不一致,接收方 MUST 返回 anp.invalid_target_binding

6.2.6 operation_id

  • 类型:字符串
  • 要求:所有会改变状态的操作 MUST
  • 语义:本次操作的幂等标识
  • 规则:
    • 同一发起方在同一语义上下文中重试时,operation_id MUST 保持不变;
    • 幂等作用域 MUST 由具体 Profile 明确定义;
    • 服务端 MUST 先进行幂等命中检查,再进行乐观并发或版本前置条件检查;
    • 对消息类操作,发送方 SHOULD 直接令 operation_id = message_id,除非其确实需要区分“消息标识”和“操作重试标识”。

6.2.7 message_id

  • 类型:字符串
  • 要求:Message-bearing Operation MUST
  • 语义:应用层消息标识
  • 说明:
    • message_id 用于消息级唯一识别或重复识别;
    • message_idoperation_id 可以相同,也可以不同;
    • 若实现没有独立的操作生命周期,SHOULD 直接复用 message_id 作为 operation_id
    • message_id MUST 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 将其纳入任何安全语义、授权判断或幂等判断。

6.2.10 content_type

  • 类型:字符串
  • 要求:Message-bearing Operation MUST
  • 语义:当前消息操作的主业务负载类型;若当前 Profile / Overlay 使用独立的外层 envelope,则表示该外层 envelope 的类型。

规则如下:

  1. 在 Base Profile 中,若 body 只是结构化承载容器(例如 text / payload / payload_b64u 互斥结构),则 meta.content_type MUST 描述该容器中的主业务负载类型,而不是 JSON 容器对象本身的类型;
  2. 在 Security Overlay 中,若 body 承载独立密文 envelope,则 meta.content_type MUST 表示该外层 envelope 的 wire object type;
  3. 原始应用内容类型若与外层 envelope 类型不同,MUST 由对应 Overlay 在其内部字段(如 application_content_type)中表达;
  4. 当具体方法是 message-bearing Notification 时,本条规则同样适用;
  5. 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 的内层原始业务类型是附件清单,则应在内层明文中写:

json
{
  "application_content_type": "application/anp-attachment-manifest+json"
}

不是 在外层 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_b64u
  • key_package_b64u
  • welcome_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 请求

json
{
  "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": {}
  }
}

说明:

  • anp.get_capabilities MAY 作为匿名公共发现能力调用;
  • 匿名调用时,meta.sender_did MAY 省略;
  • 若服务端基于身份返回不同能力子集,则调用方 MAY 在已认证上下文中再次调用。

8.2.2 成功响应

json
{
  "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"
    ]
  }
}

说明:

  • result.service_did 表示当前运行时能力结果所对应的服务身份 DID;
  • 静态 DID 文档只提供 hint,运行时能力以此结果为准;
  • supported_content_types 属于推荐扩展,但非常常见,服务端 SHOULD 尽量返回。

8.3 协商规则

  • DID 文档中的静态扩展字段仅表示可缓存的静态 hint;
  • anp.get_capabilities 的返回结果表示运行时权威能力(runtime authority);
  • 若静态 hint 与运行时能力冲突,调用方 MUST 以运行时能力结果为准并刷新缓存;
  • 调用方 SHOULD 在首次交互前,或在缓存过期后,获取目标服务能力;
  • 如果请求中的 profilesecurity_profile 不被支持,服务端 MUST 返回明确错误;
  • 调用方 MUST NOT 假定“对方支持 Base Profile 就一定支持 E2EE Overlay”。

静态 DID 文档里的 hint 与运行时能力返回之间容易被实现者混淆。下图把推荐的协商顺序固定下来,突出“静态信息用于发现,运行时结果用于裁决”的原则。

mermaid
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_profile

图 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_id MUST 保持不变;
  • 重试时 operation_id MUST 保持不变;
  • 若实现无独立操作语义,发送方 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 对象建议结构:

json
{
  "code": 1001,
  "message": "Unsupported profile",
  "data": {
    "anp_code": "anp.unsupported_profile",
    "retryable": false,
    "details": {}
  }
}

code 属于 ANP 自定义错误范围时,error.data.anp_code MUST 存在。

10.3 ANP 公共错误码

codeanp_code含义
1000anp.invalid_request_idid 非法
1001anp.unsupported_profile不支持所请求的 Profile
1002anp.unsupported_security_profile不支持所请求的安全模式
1003anp.invalid_params_shapeparams 结构不符合要求
1004anp.batch_not_supported不支持 batch
1005anp.unauthorized未通过认证
1006anp.forbidden已认证但无权限
1007anp.target_not_found目标 DID 不存在或不可达
1008anp.idempotency_conflict幂等键冲突
1009anp.unsupported_content_type不支持内容类型
1010anp.delivery_rejected目标服务拒绝接收
1011anp.rate_limited触发限流
1012anp.temporarily_unavailable服务暂时不可用
1013anp.invalid_security_binding安全模式与负载结构不匹配
1014anp.invalid_target_binding方法要求的目标建模模式与实际 meta.target 不匹配

10.4 错误返回要求

  • 对 ANP 自定义错误,服务端 MUST 返回可机器判定的 anp_code
  • message SHOULD 简短、可读;
  • data.retryable SHOULD 明确可否重试;
  • 任何错误 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.v1
  • anp.identity.discovery.v1
  • anp.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.payloadbody.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 支持:

  1. JSON-RPC 2.0;
  2. 对象形式 params
  3. 字符串 id
  4. anp.get_capabilities
  5. 公共错误码;
  6. 幂等 operation_id
  7. meta / body 顶层结构;
  8. 安全传输;
  9. 对匿名或已认证的 anp.get_capabilities 处理;
  10. 统一的 content_type 语义:外层永远表示当前 wire object type;
  11. 对每个方法显式声明目标建模模式:agent-addressedgroup-addressedservice-scopedendpoint-local
  12. service-scoped 方法强制校验 meta.target.kind = "service"target.did = serviceDid
  13. endpoint-local 方法显式声明可省略 target,并在未声明时拒绝模糊省略。

16. 示例

以下示例仅演示 Core Binding 外层 envelope;Overlay 方法(例如 group.e2ee.sendgroup.e2ee.notice)同样受本 Profile 的 Request / Notification、meta、目标建模与错误模型约束。

16.1 direct.send 请求示例

json
{
  "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"
    }
  }
}

16.2 成功响应示例

json
{
  "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"
  }
}

17. IANA / 注册表占位

本标准后续版本 SHOULD 建立以下注册表:

  1. ANP Profile 名称注册表;
  2. Security Profile 注册表;
  3. Content-Type 注册表;
  4. 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 9530Content-Digest 字段值格式
  • RFC 9421Signature-InputSignature、signature base 的构造与验证模型
  • RFC 3986:URI 百分号编码规则
  • did:wba 的 DID 解析、验证方法授权关系和路径指纹绑定校验,遵循对应 did:wba 方法规范

ANP 在本附录中只定义以下自定义部分:

  1. auth.origin_proof 的承载字段;
  2. 统一的 Signed Request Object
  3. 应用层 @method / @target-uri / content-digest 组件映射;
  4. 与 hop / service 认证、跨域转发之间的职责边界。

A.1 统一 auth.schemeauth.origin_proof

当某业务 Profile 使用应用层原发者证明时:

  • auth.scheme MUST 等于 anp-rfc9421-origin-proof-v1
  • auth.origin_proof MUST 存在
  • auth 本身 MUST NOT 进入摘要输入

推荐结构如下:

json
{
  "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:"
    }
  }
}

说明:

  • contentDigest 保存的是 RFC 9530 Content-Digest 的字段值
  • signatureInput 保存的是 RFC 9421 Signature-Input 的字段值
  • signature 保存的是 RFC 9421 Signature 的字段值

A.2 共享 origin_proof 对象结构

origin_proof MUST 至少包含以下字段:

  • contentDigest
  • signatureInput
  • signature

除非未来版本另有规定,v1 约定如下:

  • contentDigest MUST 使用 sha-256
  • signatureInput MUST 使用标签 sig1
  • signature MUST 使用标签 sig1
  • 覆盖组件集合 MUST 固定为:
text
("@method" "@target-uri" "content-digest")

关于这些字段值的具体语法、序列化与验证,发送方和验证方 MUST 直接遵循 RFC 9530 与 RFC 9421,而 MUST NOT 自行发明替代格式。

A.3 共享 Signed Request Object

contentDigest MUST 绑定一个不包含 auth 的标准业务对象,称为 Signed Request Object

通用结构如下:

json
{
  "method": "<jsonrpc method>",
  "meta": {
    "...": "..."
  },
  "body": {
    "...": "..."
  }
}

规则如下:

  • Signed Request Object MUST 只包含 methodmetabody
  • MUST NOT 包含 jsonrpcidauth
  • 发送方 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-encoded MUST 基于 meta.target.did 的 UTF-8 字节,并按 RFC 3986 百分号编码处理
  • 当某方法要求 auth.origin_proof 时,meta.target MUST 存在
  • meta.target.kind MUSTagentgroupservice 之一
  • endpoint-local 方法若未来需要引入 auth.origin_proofMUST 由对应 Profile 显式定义其目标建模与重建规则

说明性要求:

meta.target.kind 已经通过 Signed Request Object 进入 contentDigest@target-uri 继续显式携带 kind,是为了让目标类别在 signature base 中保持可读、可审计、可独立检查的稳定语义,而不是依赖验证者先展开整个摘要对象后才能知道目标类型。

P1 附录 A 是多个业务 Profile 共享的原发者证明基础。下图把 Signed Request ObjectcontentDigest@method / @target-uri / content-digest 三者之间的关系压缩到一张图里,便于后续文档直接复用。

mermaid
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 --> OP

图 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 至少执行以下步骤:

  1. 读取 auth.origin_proof
  2. 提取 contentDigestsignatureInputsignature
  3. 使用当前请求的 methodparams.metaparams.body 重建 Signed Request Object
  4. 使用 RFC 8785 JCS 对其规范化序列化
  5. 重算 contentDigest
  6. method 重建 @method
  7. meta.target.kindmeta.target.did 重建 @target-uri
  8. 按 RFC 9421 模型重建并验证 signature base
  9. 解析 keyid 指向的 DID 文档,并检查验证方法存在且被 authentication 关系授权
  10. 按对应 DID 方法规则验证签名、时间窗口与防重放策略

若任一步骤失败,验证方 MUST 拒绝该请求。

A.7 DID 与验证关系

  • keyid MUST 指向一个可解析的 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 数据模型。

更具体地说:

本附录不重复定义 Data Integrity、eddsa-jcs-2022、JCS、UTF-8、DID Core 或 DID 方法本身。
ANP 在本附录中只统一以下内容:

  1. 对象级 proof 的固定承载形状;
  2. 被保护文档(protected document)的确定规则;
  3. UTF-8 + RFC 8785 JCS 的规范化序列化要求;
  4. proofPurpose = "assertionMethod" 的默认统一语义;
  5. 共享验证步骤与对象特定约束的分工边界。

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 至少包含:

  • type
  • cryptosuite
  • verificationMethod
  • proofPurpose
  • created
  • proofValue

推荐结构如下:

json
{
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "did:example:issuer#key-1",
    "proofPurpose": "assertionMethod",
    "created": "2026-03-29T12:00:00Z",
    "proofValue": "z..."
  }
}

v1 统一要求如下:

  • proof.type MUST 等于 DataIntegrityProof
  • proof.cryptosuite MUST 等于 eddsa-jcs-2022
  • proof.proofPurpose MUST 等于 assertionMethod
  • proof.verificationMethod MUST 为完整 DID URL
  • proof.created MUST 为 RFC 3339 时间字符串
  • proof.proofValue MUST 使用 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 先进行:

  1. RFC 8785 JSON Canonicalization Scheme(JCS)规范化
  2. 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 DID
  • proof.verificationMethod MUST 存在于 issuer DID 文档中
  • proof.verificationMethod MUST 被 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 至少执行以下步骤:

  1. 读取对象 proof
  2. 检查 typecryptosuiteverificationMethodproofPurposecreatedproofValue 是否存在且满足本附录要求
  3. 按对应对象 Profile 确定 issuer DID
  4. 重建“移除顶层 proof 后的整个对象”作为被保护文档
  5. 使用 UTF-8 + RFC 8785 JCS 对被保护文档规范化序列化
  6. 解析 issuer DID 文档
  7. 检查 proof.verificationMethod 存在,且被 issuer DID 文档的 assertionMethod 授权
  8. DataIntegrityProof + eddsa-jcs-2022 验证 proof
  9. 执行对象 Profile 规定的字段完整性、时间窗口、状态引用与其它业务检查

若任一步骤失败,验证方 MUST 拒绝该对象。