线路协议

ANetCore 是一个 Go 模块,包含 ANet 中必须在每个程序里保持一致的部分:对象如何编码、哈希、签名和密封,以及身份如何派生和验证。anet 守护进程、hub 和 ANetLink 桥接程序都导入它,而不互相导入,因此线路类型只定义一次。本页描述 ANetCore v0.16(ANet 0.3)的协议。键编号、标签、路由和原因码的完整登记表是 ANetCore 仓库中的文件 docs/wire-keys.md,由 wire/registry.json 生成;本页的表格由同一文件生成。

分层

层

包

内容

编码

coredet, anetcid

确定性 CBOR 和内容标识。

身份

identity

自证明标识符(AID)和密钥事件日志(KEL)。

密封

seal

签名的加密密钥集、两层密封信封、投递凭据和送达确认。

hub 访问

relayauth, regpow, dirbox

签名请求和首次联系会话、注册用的工作量证明,以及密封目录。

卡片

a2acard

A2A agent 卡片的签名与验证。

对象

delegation, evidence, ael, tsir, effect, payment

任务消息、回执和评价、事件账本、任务文档和效果,以及支付对象。

0.3 引入的版本列于本页末尾。

编码:CoreDet-CBOR

每个参与哈希或签名的对象都编码为 CoreDet-CBOR,即 RFC 8949 第 4.2 节(核心确定性编码)的规范,另加两条规则。

  • 整数和长度采用最短形式,各项具有确定长度,映射键按其编码的字节序排序。不使用较早的 RFC 7049 规范形式中先比长度的排序。

  • 值不得为 NaN 或无穷大,也不得出现任何 CBOR 标签。

解码器拒绝重复的映射键。协议中所有对象所用的严格解码器,还会拒绝目标类型未命名的映射键。对象是以整数为键的映射。键编号、标签和原因码从不重用:已移除的键被 淘汰,出现时被拒绝;从未分配的键被 保留,同样被拒绝。带有说明 keys 0 to 63 must be understood 的对象,忽略从 64 起的未知键,但仍将其计入摘要。时间为 Unix 毫秒。签名正文以字节串形式传递,字节串中是它的 CoreDet 编码,因此签名覆盖的是确切的字节。

内容标识符(CID)为 CIDv1,编码为 dag-cbor,哈希为 sha2-256。二进制前缀为 0x01 0x71 0x12 0x20,文本形式使用 multibase 前缀 b(base32,小写),得到以 bafyrei 开头的标识符。

已签名的对象使用针对原像的分离式 Ed25519 签名(COSE 算法 -8),原像以域分隔标签开头,使为一种用途生成的签名不能被用于另一种用途。标签列于 标签与类型标记。

身份:AID 与密钥事件日志

AID 是密钥事件日志起始事件原像的 CID。该日志经签名且只追加,有三种事件类型:icp(起始)、rot(轮换)和 dip(停用)。AID 在轮换前后保持不变。

预先承诺轮换。每次起始和轮换都承诺下一个公钥的 SHA-256。随后的 rot 或 dip 必须恰好披露该密钥,并由它签名。被替换的密钥不参与其中,因此盗取了它的一方既不能轮换也不能停用该身份。下一个密钥由恢复种子派生(HKDF-SHA256),正常运行时恢复种子不保存在数据目录中;它存放在以口令加密的恢复文件中(Argon2id,t = 3,m = 64 MiB,p = 4),对于在没有终端的情况下建立的身份,则以数据目录中的一个密钥加密。

每个事件在键 0 中带有类型标记 anet.kel/2,并带有一个时间戳,该时间戳沿日志严格递增,且与验证方时钟相差不超过 5 分钟。没有该标记的日志无法重放,也没有 0.2 格式的解码路径。

见证方。起始事件固定见证模式:hub 身份没有见证方,agent 身份恰有一个,即它注册所在的 hub,由其第一次轮换指定。见证方签署 密钥状态通知(anet.ksn/1):一条简短的声明,说明某个 AID 的当前密钥是特定序号和链头处的密钥。消息随密钥历史携带一个通知。接收方要求通知不超过 6 小时,这限定了持有已轮换掉的密钥的一方,在尚未得知轮换的节点面前冒充该身份的最长时间。

轮换。定期轮换之后,以旧密钥签名的消息在 1 小时内仍被接受,从接收方的 hub 接受它们的时刻算起。紧急轮换(rot 事件中设置 emergency)和停用没有宽限期:得知该事件的接收方会立即拒绝旧密钥。

加密密钥

身份发布一个签名的 加密密钥集(anet.enckeys/2),其中最多包含 32 个密钥,以及一个 信箱签名密钥(mbox)。每个加密密钥都是 纪元钥,在一个 UTC 日内有效。节点提前 14 天发布其密钥,因此持有缓存密钥集的发送方在这段时间内无需询问 hub 即可密封。密钥集由当前的身份密钥签名。

纪元钥在其所属的日期结束之后,在信箱已完整读取且各方时钟一致的情况下,由持有者删除;投递截止时间是该日结束后 1 小时,密钥最迟在该日结束后 15 天删除。删除之后,密封给该密钥的信封无法再被打开。这就是 ANet 的前向保密(参见 安全模型)。交互中的消息还有第二层,由 交互密钥 保护,该密钥在交互于本地一侧结束时删除。

密封信封

节点之间的每条消息都是密封信封。外层是 hub 唯一能看到的部分。

部分

内容

外层信封

版本 v = 2、接收方 AID to、套件、接收方某个纪元钥的密钥标识符 kid、HPKE 封装 enc、密文 ct、投递凭据 access,以及一次性信封的有效期 exp。

第一层明文(Wrap)

要么是签名的内层消息;要么在交互有第二层时,是交互密钥标识符、第二个封装和第二个密文,其后是填充到 Padmé 长度的零填充。

内层消息

发送方、密钥状态、接收方、类型、交互、消息标识符、时间、有效期、正文、发送方的密钥历史和 witness notice、其密钥集、可选的授予、其交互密钥以及签名。

套件 1 的密码学为基础模式的 HPKE(RFC 9180),使用 DHKEM(X25519, HKDF-SHA256)、HKDF-SHA256 和 ChaCha20-Poly1305。HPKE info 在标签 anet-seal/v2(第一层)或 anet-ix/v2(第二层)之下绑定接收方 AID、套件和密钥标识符;关联数据为空。

先签名,后加密。 内层消息在加密之前,用发送方的身份密钥签名。签名覆盖按发送形式的内层字段(正文以其 SHA-256 代替),以及外层的封装、密钥标识符和套件,连同第二层的标识符和封装。因此,接收方无法重新加密一条消息并把它作为发给第三方的消息出示,任何人也无法在不使签名失效的情况下移除、添加或替换某一层。

只有第一层明文被填充,因此密文的大小只暴露一个大小类别,而不暴露确切长度。

接收方检查的内容包括:外层版本、密钥标识符、第一层的解密、wrap 的结构、投递凭据的有效性、时间(不晚于 exp;ts 最多比当前时间晚 5 分钟;exp - ts 最多 15 天)、witness notice 与密钥历史是否相符、在到达时刻有效的密钥状态之下的内层签名,以及所附的密钥集。每次失败都带有稳定的原因字符串;原因描述的是输入,且是永久性的:相同的字节每次重试都以相同方式失败。对于每一对发送方和消息标识符,消息至多被接受一次。

投递凭据

信封在外层键 access 中携带凭据,位于 HPKE info 和内层签名之外。其中没有任何内容指明发送方。

  • kind = 0 是 首次联系。发送方通过一个签名请求(POST /relay/session)在 hub 上打开会话。hub 返回一个密封给发送方一次性密钥的会话密钥。每次发送都带有以该密钥对请求计算的 MAC(标签 anet-sess-mac/v1)。hub 在该会话期间知道发送方,并且不保存这一信息,也不持有任何相关的签名证据。

  • kind = 1 是接收方签发并以其信箱密钥签名的 能力(anet.cap/1)。它写明所有者、信箱纪元、一个随机标识符、一个类别(contact 或 stranger)、有效期,以及持有者的公钥。发送方随能力一起交出持有者的私钥种子,并通过对该信封摘要的签名来证明持有。能力至多有效 31 天。新的信箱纪元会使之前纪元下签发的所有能力失效,接收方也可以在 hub 上撤销单个能力。

接收方在密封消息内把能力交给对端(即 授予)。类别为 contact 的能力可以携带接收方的直接地址。一次性能力绑定到一次交互。

送达确认

接收方对信封作出最终决定后,以 80 字节的 送达确认(dack)应答:一个 16 字节的令牌,说明消息已被处理还是被拒绝,以及一个 64 字节的加密备注,带有可选的原因码和等待时间。两者都由只有双方才能计算的密钥派生(第一层上下文的 HPKE 导出),因此中间的任何一方都无法创建或更改它。该确认具有可否认性:发送方同样能够计算它,因此它对第三方不能证明任何事情。发送方通过由同一密钥派生的 句柄 以及随机的 rid,向 hub 询问已排队的信封。该确认证明接收方的节点作出了决定;它不证明有 agent 或个人读过这条消息。

直接连接

节点之间也可以直接交换信封,方式是在两个 anetpeer 进程之间的 TCP 连接上交换 JSON 行。每个帧带有 v: 3。操作有 hello、send(带应答)、recv、ack、nack 和 error。其中的信封与 hub 路径上的密封信封相同。连接为明文 TCP;内容经过加密,但观察者可以看到信封的大小、接收方和凭据标识符。直接地址只提供给联系人。

发往 hub 的签名请求

为已注册 agent 发往 hub 的请求,以标签 anet-relay/v2/ 签名。文本见 hub HTTP API。文本中的动作是那里所列动作之一,hub AID 是文本的一部分,时间则对照 hub 的时钟,在偏差限度内检查。hub 为每个签名方保存最近接受的时间和一个近期签名的窗口,以拒绝重放;窗口大小取决于签名方的类别(见习期账户较小,agent 较大,对端 hub 最大)。

注册受工作量证明保护。hub 给出一个由密钥和小时派生的种子;客户端找到一个不超过 32 字节的 nonce,使 anet-regpow/v1、一个零字节、hub AID、一个零字节、其 AID、一个零字节、种子和 nonce 的 SHA-256 至少有 22 个前导零位。难度在每个 hub 上都相同。

目录条目

目录中的条目经过密封,只有已知某个 AID 的一方才能找到并打开它。查找键是哈希 SHA-256("anet-dir-hash/v1" || 0x00 || aid)。条目以 ChaCha20-Poly1305 加密,密钥由 HKDF-SHA256 从 AID 派生,哈希作为关联数据。客户端请求一个 分桶,即哈希以最多 10 位的前缀开头的条目集合,因此 hub 只能得知需要的是某个分桶中的一个条目,而不知道是哪一个。

Agent 卡片

agent 卡片是一个 A2A AgentCard,由该 agent 的密钥事件日志指定为当前的 Ed25519 密钥签名。签名遵循 A2A 第 8.4 节:载荷是规范形式的卡片(RFC 8785,JSON Canonicalization Scheme),签名是分离式 JWS(EdDSA),其受保护头包含 alg、jku、kid 和 typ。jku 指向 hub 在 /agents/{aid}/jwks.json 提供的密钥集。验证卡片时检查密钥状态、绑定到该 AID 的 anet-card 扩展、寻址到该 AID 的中继接口、有效期、必需成员和大小限制。

ANet 在 A2A 卡片中登记的扩展和绑定如下:

URI

用途

https://agentnetwork.org.cn/a2a/bindings/anet-relay/v2

公开卡片的协议绑定:消息被中继到该 AID。

https://agentnetwork.org.cn/a2a/ext/anet-card/v1

将卡片绑定到 AID,带序号和有效期。公开卡片和扩展卡片均有。

https://agentnetwork.org.cn/a2a/ext/anet-evidence/v1

已完成的任务带有提供方签名的回执。公开卡片。

https://agentnetwork.org.cn/a2a/ext/anet-price/v1

每项技能的价格。仅在提供方为调用方签名的扩展卡片中;hub 拒绝带有它的公开卡片。

https://agentnetwork.org.cn/a2a/ext/anet-origin/v1

标记本地 A2A 接口为远端 agent 提供的卡片,带 originExtendedCard 和 keyState。

https://agentnetwork.org.cn/a2a/ext/anet-preview/v1

提供方发送预览。stream_preview 不为 off 时声明;从不是必需的,无参数。

https://github.com/google-agentic-commerce/a2a-x402/blob/main/spec/v0.2

使用 a2a-x402 支付。

0.2 的中继绑定(anet-relay/v1)、直接绑定(anet-p2p/v1)和公开价格扩展(anet-pricing/v1)已移除。

任务消息与元数据

内层消息的正文是 delegation 包中的任务消息之一:签名的请求(DelegateReq)、聊天消息、结果、回复、状态消息,以及卡片请求和响应。请求携带任务文档(TaskDoc),回执绑定其 CID。带前缀 anet. 的元数据键携带端到端传递的信息(例如 anet.reason 和 anet.retry_after_ms),或由本地接口添加的信息(例如 anet.delivery、anet.payment_note 和 anet.receipt_verified)。登记表列出每个键及其适用范围。

标签与类型标记

A 类是类型化的 CoreDet 映射,其键 0 为标记;B 类是形如 label || 0x00 || fields 的前缀字符串;C 类是 KDF、HPKE 或 MAC 上下文;text 是 relayauth 文本原像。标签是不带长度前缀、不带结尾零字节的 ASCII 字节。

编号

标签或标记

类

构造

密钥

L1

anet-seal/v2

C

layer-1 HPKE info = coredet({1: "anet-seal/v2", 2: to, 3: suite, 4: kid}); aad empty

接收方的加密纪元密钥

L2

anet-ix/v2

C

layer-2 HPKE info = coredet({1: "anet-ix/v2", 2: to, 3: suite2, 4: ikid}); aad empty

接收方的交互密钥

L3

anet-relay-sig/v2

A

内层签名原像 v2(InnerSigPreimage)

发送方身份的当前密钥

L4

anet-env/v2

B

env_digest = SHA-256("anet-env/v2" || 0x00 || coredet(outer field map without key 7)), field values as received

L5

anet-access/v2

B

proof = Ed25519(holder_sk, "anet-access/v2" || 0x00 || cap_id(16) || env_digest(32))

持有者密钥

L6

anet.cap/1

A

Cap.sig = Ed25519(mbox_sk, coredet(CapBody))

信箱签名密钥

L7

anet-sess-key/v1

C

session key delivery: HPKE base, suite 1, pkR = epk, info = "anet-sess-key/v1" || 0x00 || hubAID || 0x00 || sid(16); aad empty; plaintext k_sess(32)

一次性 epk

L8

anet-sess-mac/v1

B

MAC = HMAC-SHA256(k_sess, "anet-sess-mac/v1" || 0x00 || sid(16) || 0x00 || ts(decimal) || 0x00 || method || 0x00 || pathAndQuery || 0x00 || X-ANet-Home or empty || 0x00 || SHA-256(body))

k_sess

L9

anet-dir-hash/v1

B

h = SHA-256("anet-dir-hash/v1" || 0x00 || UTF-8(aid))

L10

anet-dir-box/v1

C

K = HKDF-SHA256(ikm = UTF-8(aid), salt = empty, info = "anet-dir-box/v1", L = 32); box = nonce(12) || ChaCha20-Poly1305(K, nonce, aad = h, pt = coredet(DirEntry))

由 AID 派生

L11

anet-dack/v1

C

ack_key = HPKE.Export(layer-1 context, exporter_context = "anet-dack/v1", L = 32)

第一层 HPKE

L12

anet-dack-handle/v1

C

handle = HMAC-SHA256(ack_key, "anet-dack-handle/v1")[0:16]

ack_key

L13

anet-dack-tok/v1

C

tok(o) = HMAC-SHA256(ack_key, "anet-dack-tok/v1" || u8(o))[0:16]

ack_key

L14

anet-dack-note/v1

C

note_key = HMAC-SHA256(ack_key, "anet-dack-note/v1"); the note AEAD aad is tok(o)

ack_key

L15

anet-enc-kid/v1

B

KID = SHA-256("anet-enc-kid/v1" || u8(suite) || pub)[0:16] (no 0x00; epoch and interaction keys alike)

L16

anet.enckeys/2

A

SignedEncKeySet.sig = Ed25519(identity key, coredet(EncKeySet))

身份当前密钥

L17

anet.kel/2

A

SignedEvent.sig = Ed25519(k, coredet(KeyEvent)); icp by k0, rot and dip by the key the event reveals

身份密钥

L18

anet.ksn/1

A

aobj envelope signature over coredet(NoticeBody)

见证 hub 身份密钥

L19

anet-kel-next/v1

C

seed(aid, seq) = HKDF-SHA256(ikm = RS, salt = "anet-kel-next/v1", info = UTF-8(aid) || 0x00 || u64be(seq), L = 32)

恢复种子 RS

L20

anet.recovery/1

A

ct = XChaCha20-Poly1305(key, nonce, RS, aad = coredet(RecoveryBlob without key 7));kdf = argon2id 时,key = argon2id(NFC(passphrase), salt, t = 3, m = 64 MiB, p = 4, 32);kdf = {1: "local"} 时,key 为 recovery_local.key 的 32 个字节;kdf 位于 aad 之内,因此两种模式不能互相冒充

由口令派生的密钥;本地恢复密钥

L21

anet.identity/2; anet.mbox/1

文件

本地文件类型标记;不签名

L22

anet-relay/v2/

文本

"anet-relay/v2/" + action + "/" + aid + "/" + hubAID + "/" + decimal(ts) + "/" + base64url(SHA-256(method || 0x00 || pathAndQuery || 0x00 || body));agent 和对端 hub 相同

签名方身份的当前密钥

L23

anet-regpow/v1

B

pow_hash = SHA-256("anet-regpow/v1" || 0x00 || hub_aid || 0x00 || aid || 0x00 || seed(32) || nonce(<= 32)); >= 22 leading zero bits

L24

anet-regpow-seed/v1

C

seed = HMAC-SHA256(pow_key, "anet-regpow-seed/v1" || u64be(floor(ms / 3 600 000)))

pow_key(仅存在于 hub 进程内存中)

L25

anet-liab-leaf/v1

B

leaf = SHA-256("anet-liab-leaf/v1" || 0x00 || salt(32) || coredet(LiabLeafContent))

L26

anet-liab-node/v1

B

node = SHA-256("anet-liab-node/v1" || 0x00 || L.h || u64be(L.sum) || R.h || u64be(R.sum))

L27

anet-receipt-ix/v2

B

ix_commit = SHA-256("anet-receipt-ix/v2" || 0x00 || ix || 0x00 || anet.nonce);二者均不含 U+0000

L28

anet-receipt-requester/v2

B

requester_commit = SHA-256("anet-receipt-requester/v2" || 0x00 || requester_aid || 0x00 || rsalt(32))

L29

anet.receipt/2

A

提供方对 coredet(ReceiptBody) 的 aobj 信封签名

提供方身份的当前密钥

L30

anet.review/2

A

ReviewWire.sig = Ed25519(review_sk, coredet(ReviewBody))

一次性评价密钥

L31

anet-review-tag/v1

C

tag = HMAC-SHA256(hub_tag_key, "anet-review-tag/v1" || 0x00 || reviewer_aid || 0x00 || subject_aid)[0:16]

hub_tag_key

L32

anet.review-att/1

A

hub 对 coredet(ReviewAttBody) 的 aobj 信封签名

hub 身份密钥

L33

anet-settle-guard/v1

B

h = SHA-256("anet-settle-guard/v1" || 0x00 || payer || 0x00 || pay_bind) (hub local)

L34

anet/x402-bind/v1

B

PayBind = hex(SHA-256("anet/x402-bind/v1" || 0x00 || ix || 0x00 || taskNonce));含有 0x00 的 ix 或 taskNonce 属于错误

L35

anet-local/v1

C

本地加密字段:0x01 || nonce(12) || AES-256-GCM(aead_key, nonce, plaintext, aad = coredet({1: "anet-local/v1", 2: ix, 3: "<table>.<column>"}))

由 ix_dek 派生的 aead_key(L36)

L36

anet-local-aead/v1; anet-local-mac/v1

C

aead_key = HKDF-SHA256(ikm = ix_dek, salt = empty, info = "anet-local-aead/v1", L = 32); mac_key = HKDF-SHA256(ikm = ix_dek, salt = empty, info = "anet-local-mac/v1", L = 32)

ix_dek

L37

anet-client-key/v1

B

client_key = SHA-256("anet-client-key/v1" || 0x00 || messageId)

L38

anet-client-msg/v1

B

client_digest = HMAC-SHA256(mac_key, "anet-client-msg/v1" || 0x00 || canon(normalized content));canon:成员排序(RFC 8785 3.2.3),字符串转义(3.2.2.2),无空白,数字保持客户端所写的形式

由 ix_dek 派生的 mac_key

L39

anet.delegate/1; anet.message/1; anet.status/1; anet.result/1; anet.card.get/1; anet.card/1

类型

内层类型(键 4);不是签名标签;位于签名原像之内

L40

anet/localpeer-key/v1; anet-release/1; anet-release/2; anet-official/1; anet-suite-identity-v1/cur; anet-suite-identity-v1/nxt; anet-suite-test-key-v1

已携带

不变

L41

anet.org-genesis/1

A

org_id = CID(coredet(OrgGenesis));不签名

L42

anet.org-cred/1

A

SignedCredential.env 对 coredet(OrgCredBody) 签名

签发方身份的当前密钥

L43

anet.cogunit/1

A

CogUnitWire.env 对 coredet(CogUnitBody) 签名

作者身份的当前密钥

对象

主要对象的键表。Presence 取 required(必需)、optional(可选)或 conditional(有条件);有条件成员的说明写明其条件。标为 reserved 的行从未分配;retired 行曾被早先版本使用,现被拒绝。

SealedEnvelope

外层密封信封 v2,hub 唯一能看到的部分。键 0-63 必须理解;>= 64 的键予以保留并计入摘要。

键空间:键 0 至 63 必须理解,从 64 起的键予以保留并计入摘要。

密钥

名称

类型

是否出现

说明

0

reserved

1

v

uint = 2

required

外层版本;除 2 以外一律为 bad-version

2

to

tstr

required

接收方 AID

3

suite

uint

required

1 = DHKEM-X25519 / HKDF-SHA256 / ChaCha20-Poly1305;2 保留给后量子套件

4

kid

bstr (16 bytes)

required

接收方某个加密纪元密钥的 kid;从不是交互密钥

5

enc

bstr

required

第一层 HPKE enc,Nenc 字节

6

ct

bstr

required

第一层密文;明文为 Wrap

7

access

<Access>

required

投递凭据;位于 HPKE info、内层签名和 env_digest 之外

8

exp

uint

optional

一次性信封的有效期;存在时等于内层键 8(否则为 exp-mismatch);排队的信封从不携带它

9 to 63

reserved

unknown-critical-field;hub 以 400 bad_envelope 应答

Access

外层键 7 中的投递凭据。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

kind

uint

required

0 = 首次联系会话;1 = 能力;2 保留给匿名首次联系令牌(0.3.0 中被拒绝)

2

cap

<Cap>

conditional

kind = 1;kind = 0 时禁止。

3

proof

bstr (64 bytes)

conditional

kind = 1;kind = 0 时禁止。持有证明,由持有者密钥作 Ed25519 签名(L5)

Cap

线路上携带的能力。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

body

bstr<CapBody>

required

coredet(CapBody)

2

sig

bstr (64 bytes)

required

信箱签名密钥对正文的 Ed25519 签名

CapBody

接收方签发的能力的签名正文。

类型标记 anet.cap/1。键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

0

t

tstr = anet.cap/1

required

类型标记

1

owner

tstr

required

签发方 AID;必须等于外层 to

2

epoch

uint

required

必须等于所有者当前的 mbox.epoch(>= 1)

3

cap_id

bstr (16 bytes)

required

随机

4

class

uint

required

1 = contact;2 = stranger

5

cap_exp

uint

required

有效期;接受窗口 now - 5 min <= cap_exp <= now + 31 days

6

holder

bstr (32 bytes)

required

持有者 Ed25519 公钥,每个能力各用新的

Wrap

第一层明文。键 0-63 中的未知键为 bad-wrap;>= 64 的键被忽略。

键空间:键 0 至 63 必须理解,从 64 起的键予以保留并计入摘要。

密钥

名称

类型

是否出现

说明

0

reserved

1

ikid

bstr (16 bytes)

conditional

恰好在存在第二层时出现,与键 2 一起。KID(suite2, rk.pub)

2

enc2

bstr

conditional

与键 1 一起。第二层 HPKE enc

3

body

bstr

required

第二层密文;无第二层时为 coredet(SealedInner)

4 to 20

reserved

21

pad

bstr

required

全零 Padme 填充:len(coredet(Wrap)) 落在 Padme 的某一步长上

22 to 63

reserved

SealedInner

内层签名消息 v2(无版本字段;随外层 v = 2 生效)。

键空间:键 0 至 63 必须理解,从 64 起的键予以保留并计入摘要。

密钥

名称

类型

是否出现

说明

0

forbidden

仅用于原像(标签)

1

from

tstr

required

发送方 AID;不含 U+0000

2

key_state_seq

uint

required

签名所用的密钥状态

3

to

tstr

required

必须等于外层 to;不含 U+0000

4

type

tstr

required

内层类型(L39)

5

ix

tstr

required

交互标识符;不含 U+0000

6

mid

bstr (16 bytes)

required

消息标识符;(from, mid) 是重放键

7

ts

uint

required

发送时间

8

exp

uint

required

exp - ts <= 15 days

9

body

bstr

required

正文;签名原像包含其 SHA-256

10

kel

bstr

conditional

预览帧中禁止,其他每种类型中必需。发送方 KEL v2,<= 256 个事件,<= 64 KiB

11

notice

[bstr<NoticeWire>]

conditional

恰好在键 10 存在时出现。witness notice;0.3.0 中恰好一个;每个 <= 1024 字节

12

keys

bstr<SignedEncKeySet>

conditional

预览帧中禁止,其他每种类型中必需。

13

reserved

为见证 KEL 提出过一次;未采用

14

grant

<Grant>

optional

预览帧、事后拒绝通知和 anet.card/1 中禁止

15

rk

<RK>

conditional

当发送方仍持有该交互的交互密钥时。发送方的交互公钥

16 to 19

reserved

20

sig

bstr (64 bytes)

required

对 v2 签名原像的 Ed25519 签名(L3)

21

retired

原为 pad。unknown-critical-field

22 to 29

reserved

30 to 34

forbidden

仅用于原像(enc1, kid, suite, ikid, enc2)

35 to 63

reserved

Grant

在密封消息内交给接收方的能力(内层键 14)。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

cap

<Cap>

required

2

holder_seed

bstr (32 bytes)

required

持有者 Ed25519 私钥种子

3

home

tstr

required

签发方的 hub AID(路由提示,不是 URL)

4

ix

tstr

optional

存在:仅用于此交互的一次性能力;必须等于内层 ix

5

p2p

tstr

optional

签发方的直接地址 host:port;仅与 class = 1 且无键 4 同时使用

6

pay

bool

optional

true:签发方对能力定价;仅在无键 4 时

EncKeySet

加密密钥集 anet.enckeys/2。

类型标记 anet.enckeys/2。键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

0

t

tstr = anet.enckeys/2

required

类型标记

1

aid

tstr

required

2

seq

uint

required

发布序号,Unix 毫秒量级;hub 的 prev_seq 比较并交换使用它

3

keys

[<EncKey>]

required

1..32 个密钥,not_before 升序

4

issued_at

uint

required

5

mbox

<Mbox>

required

信箱签名密钥

EncKey

一个加密密钥;not_after - not_before <= 2 天。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

kid

bstr (16 bytes)

required

2

suite

uint

required

3

pub

bstr

required

4

not_before

uint

required

5

not_after

uint

required

Mbox

密钥集中的信箱签名密钥。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

epoch

uint

required

>= 1;仅在密钥改变时 +1

2

pub

bstr (32 bytes)

required

Ed25519 公钥

SignedEncKeySet

一个密钥集及身份对它的签名。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

set

bstr<EncKeySet>

required

2

key_state_seq

uint

required

必须是 KEL 的活动尖端

3

sig

bstr (64 bytes)

required

KeyEvent

KEL v2 事件。AID = CID(icp 原像);icp 原像和存储形式不含键 1。

类型标记 anet.kel/2。键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

0

t_obj

tstr = anet.kel/2

required

v2 标记和域分隔;缺失或错误的键 0 会使 KEL 无法重放

1

aid

tstr

conditional

icp 原像中不存在,其余情况必需。

2

seq

uint

required

3

prev

tstr

conditional

icp 中不存在,其余情况必需。前一事件标识符

4

t

tstr

required

icp, rot or dip

5

keys

[bstr]

required

恰好一个 32 字节的密钥:icp 为 k0,rot 和 dip 为所披露的密钥

6

next

bstr (32 bytes)

conditional

icp 和 rot;dip 中禁止。下一个公钥的 SHA-256

7

kt

uint = 1

required

8

ts

uint

required

> 0

9

witnesses

[tstr]

conditional

icp 和 rot 可以携带;dip 中禁止。0 或 1 个见证 hub AID

10

retired

原为 revoked_since。从未使用

11

toad

uint

conditional

icp 和 rot,即使为 0 也写入;dip 中禁止。hub 为 0,agent 为 1

12

emergency

bool

conditional

仅 rot,且仅为 true。紧急轮换:无宽限期

13 to 63

reserved

SignedEvent

带签名的 KEL 事件。原始事件字节必须等于 coredet(解码后的事件)。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

event

<KeyEvent>

required

2

sig

bstr (64 bytes)

required

3

event_id

tstr

required

原像的 CID

4

reserved

为多见证回执保留

NoticeBody

Witness notice(密钥状态通知)正文。

类型标记 anet.ksn/1。键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

0

t

tstr = anet.ksn/1

required

类型标记

1

aid

tstr

required

通知所涉及的 AID

2

seq

uint

required

见证方所持 KEL 的尖端序号

3

head

tstr

required

尖端事件标识符

4

observed_at

uint

required

见证 hub 的时钟

5

witness

tstr

required

签名的见证 hub AID

NoticeWire

线路上的 witness notice。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

body

bstr<NoticeBody>

required

2

env

<aobj.Envelope>

required

signer_aid 必须等于 witness

DirEntry

目录盒的明文。含未知键或无法打开的条目会被跳过。

键空间:封闭,所有未登记的键均被拒绝。

密钥

名称

类型

是否出现

说明

1

aid

tstr

required

2

home

tstr

required

hub AID

3

kel

bstr

required

4

keys

bstr<SignedEncKeySet>

required

5

card

bstr

optional

A2A 卡片字节

6

notice

bstr<NoticeWire>

optional

版本

层

0.2

0.3

发布版本

ANetCore 0.15, anet 0.2.1

ANetCore 0.16, anet 0.3.0, ANetHub 0.3.0, ANetLink 0.2.0

Hub 线路

X-ANet-Wire: 2

X-ANet-Wire: 3

外层信封

v = 1

v = 2;凭据 access 必需,exp 可选

HPKE 标签

anet-relay/v1

anet-seal/v2,第二层为 anet-ix/v2

内层签名

anet-relay-sig/v1

anet-relay-sig/v2

加密密钥集

anet.enckeys/1,最多 4 个密钥,每个 30 天

anet.enckeys/2,最多 32 个密钥,每个 2 天,带信箱密钥

密钥事件日志

icp, rot, dip, ixn, drt

anet.kel/2;仅 icp、rot、dip

身份文件

identity.kel

anet.identity/2

直接帧

v: 2

v: 3;增加 dack 和 addr

C1(ANet 到 ANetLink)

JSON, /v0

仅 CBOR,/v1

证据与支付

回执和评价 v1、凭证

anet.receipt/2、anet.review/2、供应纪元;凭证已移除

本地数据

无模式版本

user_version = 3; enc_keys.cbor v = 2

0.3 程序会以稳定的原因拒绝早先版本的数据和消息;没有迁移路径(参见 升级到 0.3)。