全部文章

阅读约 9 分钟

Label 309 是如何工作的

Label 309 把一份存在性证明写入 Cardano 交易元数据:以内容哈希为先,再附带可选的签名、封存载荷、接收方密钥槽和 Merkle 批处理。本文逐层讲清每一层的工作原理,以及任何人如何对其进行验证。

Label 309 定义了一份存在性证明记录如何写入 Cardano 交易元数据。其核心在于:一份记录会把一个或多个内容哈希以元数据 label 309 承诺到 Cardano 上。那笔交易的区块时间就成为公开见证,证明这些确切的字节不晚于那一刻就已存在。记录还能携带的其他一切——签名、存储 URI、加密载荷、接收方密钥槽、Merkle 根、指向更早记录的指针——都只是围绕这一项主张的可选元数据。

设计目标一句话就能说清:一份证明应当可被独立验证。验证这项基本主张时,不需要信任 CardanoWall、不需要信任发布者的网站、不需要信任某个私有数据库,也不需要信任某个证书颁发机构——只需要公开链,以及在涉及内容主张时的原始字节。

Label 309 是一项开放标准。它已经提交到 Cardano CIP 流程,作为元数据类别的提案,目前正由 CIP 编辑审阅;元数据 label 本身才是持久的链上标识符,而 Web 应用、CLI 和 SDK 都是它的参考实现,而非标准本身。如果你想先了解全局,可以从存在性证明到底是什么开始。

label 309 下在区块链上存了什么?

一条 Label 309 记录存放于 Cardano 交易元数据中,挂在整数 label 309 下。每笔交易恰好一条记录;验证方会忽略其他所有元数据 label。

记录主体以 canonical CBOR 编码——这是一种确定性的二进制格式,因此两个实现表达同一条逻辑记录时,会产出逐字节完全一致的字节序列。Cardano 把任何单条元数据字符串限制在 64 字节以内,而序列化后的记录通常会超过这个长度。于是记录主体会被拆成一个由若干小字节串块组成的 CBOR 数组来传输,把这些块按顺序拼接起来,得到的正是记录主体。验证方在校验任何东西之前,会先把这些块重新拼回完整主体。这是该格式执行的唯一一次分块。

这个传输细节对实现者很重要,但底层思路其实很朴素:

  1. 交易携带元数据 label 309
  2. 该 label 下的值重组为一条 Label 309 记录。
  3. 该记录承诺一批内容哈希、Merkle 根,或两者皆有。
  4. 可选字段再补上签名、加密载荷材料、存储 URI,以及一个替换指针。

这不是一个自由填写的备注字段。记录有严格而封闭的结构,正是这一点让不同实现能产出并验证相同的字节。

为什么内容哈希是首要主张?

因为存在性证明是关于确切字节的主张,而哈希正是确切字节的指纹。

在 Label 309 中,内容哈希是首要主张;其他所有字段都是围绕它的元数据。对于一份简单的文件证明,一个 item 会携带一个 hashes 映射,把一个具名哈希算法——例如 sha2-256blake2b-256——与一个 32 字节的原始摘要配对。要校验这份证明,验证方会从原始文件重新计算摘要,再与记录中的摘要进行比对。

字节匹配,证明就通过。改动哪怕一个字节,摘要就会改变,证明随之失败。

正因如此,即便内容很大或属于私密内容,这项主张依然很小。记录从来不需要文件本身,它只需要那枚指纹。

items、uris 和 enc 是什么?

items 是一条记录中按内容划分的各项承诺。每个 item 就是一项内容主张。唯一必填的部分是一个非空的 hashes 映射,其余皆为可选。

一个 item 可以携带:

  • hashes——必填的映射,把哈希算法对应到原始摘要;
  • uris——可选的内容寻址位置,例如 ar://…(Arweave)或 ipfs://…(IPFS);
  • enc——可选的加密信封,用于封存(已加密)的记录。

关键之处在于:uris 不是证明,哈希才是证明。URI 只是一个检索提示,或一项存储承诺,帮助验证方找到要校验的字节。一条只有哈希、没有 URI 的记录,本身就是一份完整、有效的证明。带 URI 的记录可以帮助取回公开内容或密文。而封存记录会把明文加密保存在链下,同时仍然证明它存在的时间。

为什么只允许 ar://ipfs://

Label 309 v1 把存储 URI 限定为内容寻址方案——Arweave 和 IPFS——并拒绝其他一切,包括 https://。这条限制是刻意为之,而非权宜之计。

一个普通的 https:// URL 依赖 DNS、TLS、服务器行为、重定向,以及日后恰好托管在那个地址上的任何东西。内容寻址 URI 则不同:地址本身由内容派生而来(IPFS CID 是字节的 multihash;Arweave 交易 id 在 Arweave 共识下对数据作出承诺)。因此验证方无需信任存储网关、DNS 或某个证书颁发机构,就能确认「我取回的字节,正是生产者所承诺的字节」。取回的字节仍然必须与链上承诺相符;存储层本身从来不是事实的来源。

签名能证明什么——又不能证明什么?

一条 Label 309 记录可以携带一个可选的顶层 sigs 数组。每一项都是一个分离式 COSE_Sign1 签名,签的是移除了 sigs 字段后的记录主体。说得直白些:签名者一次性为整条记录背书——每个 item、每个哈希、每个 URI、每个封存信封、每个 Merkle 根、那个替换指针,以及任何扩展字段。

签名是附加性的。没有签名的记录依然能证明存在性。带有效签名的记录则额外表明:有一把特定的密钥为这条记录背书:

  • 仅哈希:这些字节在这个公开时间之前已存在;
  • 已签名:这些字节在这个公开时间之前已存在,且这把密钥为这条记录背书。

这种精确性很重要,因为签名能证明的,往往比人们以为的要少。一个已验证的签名并不证明同一把密钥为那笔 Cardano 交易付了费或提交了交易,不证明它选定了区块时间,也不证明它属于任何具名的现实世界个人。它只证明这把密钥签署了记录主体——仅此而已。请把它表述为「由这把密钥签名」,绝不要表述为「由这把密钥发布」。正是这种克制而诚实的含义,才让一份已签名的证明能在不同应用和网关之间通用。作者身份始终是可选的;而验证方无法校验的签名(不支持的算法、无法解析的密钥)从不会使存在性主张失效——签名失败是软性的,存在性则不会失败。

什么是封存记录?

封存记录在证明内容存在时间的同时,仍能让内容保持机密。

在一条封存的 Label 309 记录中,item 承诺的始终是明文哈希——绝不是密文。明文被加密,密文存放在一个内容寻址 URI(ar://…ipfs://…)处,从不上链。链上记录携带一个加密信封,其中存放着指定的密钥持有者恢复内容加密密钥所需的材料。链上既不包含明文,也不发布接收方名单。

对接收方而言,验证会多出几步:

  1. 从 Cardano 取回记录。
  2. 从内容寻址存储取回密文。
  3. 在本地尝试打开一个匹配的密钥槽。
  4. 若有密钥槽被打开,则解密密文。
  5. 重新计算明文哈希,并与链上承诺进行比对。

由于链上摘要绑定的是明文,封存证明既保全了那份确切的原始文件,让它保持私密。随之而来有几条诚实的限制:封存记录证明的是时间和完整性,不是匿名性;而能够解密的接收方,事后随时可以选择泄露明文。

没有接收方字段,接收方是怎么工作的?

接收方依靠接收密钥和试探解密来工作,而非依靠一个可读的收件人字段。

如果发送方知道某个接收方的接收地址(一把 X25519 公钥,也可以是混合后量子公钥),发送方就能构建一条带密钥槽的封存记录,让该接收方能够打开。接收方的公钥从不会作为可读字段出现在记录中。接收方的软件会监听 Label 309 记录的公开数据流,并在本地尝试解密候选密钥槽;只要有一个密钥槽被打开,这条记录就归入该接收方的收件箱。

正因如此,CardanoWall 的收件箱并不是一个普通的服务器端邮箱。网关暴露的是一份接收方无关的记录数据流;由客户端找出自己能解密的那些。服务器永远不需要知道接收方是谁,也不需要替谁解密任何东西。(关于接收方一侧的实际操作,参见如何接收封存记录。)

仍有一些值得讲清楚的元数据层面的限制。记录从不发布明文,也没有接收方这一列,而且密钥槽的顺序在发布前会被打乱,因此不携带任何信号。但密钥槽的数量是可见的;此外,时间、付款痕迹和操作失误都可能泄露记录格式本身无法隐藏的信息。

一条记录怎么覆盖成千上万个文件?

如果你需要证明一千个文件曾经存在,那就不应该需要一千笔 Cardano 交易。Label 309 支持 Merkle 批处理:对这些文件计算哈希,在这串有序的哈希列表之上构建一棵 Merkle 树,然后在记录的 merkle 数组中发布单个 32 字节的根。记录会在根的旁边携带一个叶子计数,把链上的根绑定到链下列表的确切大小。

之后,你可以通过出示以下内容,来证明某个特定文件或事件曾在这一批之内:

  • 该文件(或它的叶子哈希);
  • 一份包含证明——沿着通往根的路径上的各个兄弟哈希;
  • 锚定在 Label 309 记录中的那个 Merkle 根。

验证方把这份包含证明逐层折叠回一个根,只有当重新计算出的根与已发布的根逐字节相等时才接受。每一片未披露的叶子都保持私密——根不会泄露它所承诺的那些叶子的任何信息。

这是面向 CI/CD 制品、合规日志、AI 输出、数据集清单、发布文件夹和证据包的扩展层。它在一条记录覆盖成千上万个文件中有专门讲解。

supersedes 指针有什么用?

supersedes 是一个可选的 32 字节指针,通过交易哈希指向一条更早的 Label 309 记录。它让一条更新的记录得以声明「这条替换或更新了那条更早的记录」。

那条更早的记录既不会被删除,也不会被作废。Cardano 只能追加,因此两条记录将永远各自独立可验证。这个指针只是一个链接,它不携带任何原因字段。替换在人类语义上的含义——一处更正、一份修订后的清单、一个更新过的证据包——应当存放在新的内容或应用层中,而不是元数据里。这个指针的价值在于:它无需任何厂商数据库行、也无需任何专有记录 id 就能工作。

验证是怎么工作的?

验证是分层的。Label 309 定义了三种验证角色,每一种都是前一种的严格扩展:

  • 结构验证器——一个作用于记录字节的纯函数。它确认 canonical CBOR、schema 结构、字段类型、必填字段、算法标识符以及 URI 规则。它不执行任何网络 I/O,不校验任何签名,也不解密任何东西。
  • 公开验证方——从一个 Cardano 交易引用出发。它从验证方自己选定的区块浏览器取回原始交易,把这些字节绑定到所请求的交易哈希,确认 label 309 存在,重组记录,运行结构校验,检查确认深度,并校验它所支持的签名。如果有内容字节可用,它还能重新计算公开内容哈希。它不解密。
  • 接收方验证器——公开验证方所做的一切,再加上它自己的私钥,用以打开封存载荷并重新计算明文哈希。

有一处微妙之处让验证保持诚实:公开验证方读取的是原始交易 CBOR,而不是区块浏览器对元数据的 JSON 视图。JSON 投影是有损的——它会丢弃映射键的顺序,以及字节与文本之间的区分——因此从它重新编码会破坏一条符合规范的记录上的每一个签名。而且由于 Cardano 上的结算是概率性的,一条只有一两个区块深度的记录会被报告为 pending 而非 valid,直到它身后积累了足够多的确认数。

这种结构让信任模型保持干净。一个基本验证方不需要 CardanoWall 账户;一份公开证明无需发布者服务器即可校验;一份封存证明在密钥持有者手中、于本地完成解密。验证一条 Label 309 记录这篇实操从头到尾演示了公开验证方的路径。

网关处在什么位置?

网关负责发布记录。它不是信任的根。

Label 309 网关处理那些自己运行起来确实很难的部分:它给出报价,把密文上传到存储,构建并提交 Cardano 交易,等待确认,索引记录,管理余额,并暴露一个 API。CardanoWall 采用这种网关模式,让普通用户和开发者都能切实地完成发布。

但一份证明之所以被信任,并不是因为某个网关说它存在。它被信任,是因为记录在链上、字节通过校验、签名通过核对、哈希可以重新算出。这正是托管服务与证明标准之间的分界线:服务帮你发布;标准让任何人都能验证,而网关完全处在信任路径之外。

最精简的心智模型

把 Label 309 想成一条小而分层的记录:

  1. items 证明确切的内容字节在某个公开时间之前已存在。
  2. sigs 让密钥为记录背书,可选。
  3. enc 让加密内容既保持私密,又可被恢复。
  4. 接收方密钥槽让特定的密钥持有者打开封存内容。
  5. merkle 让一条记录得以代表一个超大批次。
  6. 验证只跑在公开数据和本地密钥之上——从不依赖对厂商的信任。

正是这种分层,让 CardanoWall 既可以是一个 Web 应用、一个 API、一个 CLI、一个桌面应用,也可以是一个自托管网关——而证明格式始终不变。产品可以变;证明依旧可验证。

有一点值得自始至终诚实相告:一份 Label 309 证明表明特定字节在某个公开时间之前已存在,且自那以后未曾改变。它不证明内容由谁创作、归谁所有,也不证明其中所述是否属实。关于这条界线落在何处,参见一份证明不能证明什么

延伸阅读

label-309proof-of-existenceguides