try ai
科普
编辑
分享
反馈
  • 默克尔有向无环图

默克尔有向无环图

SciencePedia玻尔百科
核心要点
  • 默克尔有向无环图通过使用加密哈希作为唯一标识符(内容寻址)来创建不可变的数据结构,任何更改都会创建一个新的对象。
  • 这种结构支持高效、可验证的版本控制和分支历史,构成了像 Git 版本控制系统等系统的基础。
  • 像 IPFS 这样的应用使用默克尔有向无环图来构建一个去中心化网络,其中数据的完整性可以通过紧凑的默克尔证明进行验证,而无需下载整个数据集。
  • 在科学研究中,默克尔有向无环图为计算溯源提供了一个框架,为整个分析过程创建了可验证的审计追踪,以确保可复现性。

引言

在我们的数字世界中,如何能确定数据随时间推移保持不变,或者协作的历史被准确记录?从科学研究到去中心化网络,维持数据完整性和可验证的溯源性这一挑战至关重要。一个强大而又出奇简单的数据结构优雅地解决了这个挑战:默克尔有向无环图(Merkle Directed Acyclic Graph,简称 Merkle DAG)。它为构建信任并非预设、而是由密码学保证的系统提供了基础。

本文深入探讨默克尔有向无环图的世界,探索其工作原理及其革命性的原因。首先,在“原理与机制”部分,我们将分解内容寻址、加密哈希以及赋予默克尔有向无环图独特性质的不可变、递归的本质等核心概念。随后,“应用与跨学科联系”部分将展示其在现实世界中的影响,从驱动数百万开发者使用的 Git 版本控制系统,到实现星际文件系统(IPFS)的去中心化愿景,再到确保现代科学的可复现性。

原理与机制

想象一下,你正在用一种特殊的乐高积木搭建东西。这些不是普通的塑料块。每块积木的唯一序列号并非在工厂里印上去的;相反,这个数字是一个神奇的、源自积木本身物质的密码学指纹。如果你用两堆完全相同的分子组成一块积木,它们将拥有完全相同的序列号。如果你哪怕只改变一个分子,这个序列号就会完全且不可预测地改变。这就是​​内容寻址​​的精髓:一个对象的身份不是一个任意的标签,而是其“本质”的指纹。

现在,让我们为这套神奇的乐高积木添加另一条规则。当你连接积木时,最终成品的序列号是其自身组件以及它所连接的积木序列号的指纹。这就创造了一个优美的、级联的身份链。整体的身份依赖于其部分的身份,一直向下追溯。简而言之,这就是默克尔有向无环图的世界。它是一种不基于任意指针和位置,而是基于内在的、可验证的真实性构建的数据结构。

默克尔节点的剖析:内容为王

让我们从魔法积木转向数字数据。我们所说的“序列号”就是​​加密哈希​​。哈希函数,如广泛使用的 SHA-256,是一种数学算法,它能接收任意量的数据——无论是《战争与和平》的全文、一张图片,还是一个文件目录——并将其压缩成一个固定大小的字符串,即哈希值。对于给定的输入,输出的哈希值总是相同的。但是,只要输入改变一个比特位,输出的哈希值就会变得完全不同。而且至关重要的是,几乎不可能找到两个不同的输入产生相同的哈希值。

那么,我们如何构建我们的结构呢?我们从叶子节点开始。对于一个简单的文件,其内容地址或标识符就是其数据的哈希值:id=H(file_data)id = H(\text{file\_data})id=H(file_data)。这已经给了我们一个非凡的特性:​​去重​​。如果你在一个系统中有十个相同文件的副本,它们都有完全相同的哈希值。在一个内容寻址的世界里,只有一个文件,被引用了十次。

但是文件夹或目录呢?目录不仅仅是数据;它是其他对象的集合,每个对象都有一个名字。这正是名称中“默克尔”部分的真正闪光点。目录的标识符不是其文件内容的哈希,而是其自身“列表”的哈希。这个列表包含了其条目的名称,以及至关重要的,其子节点的哈希值。

为了确保两个具有相同内容的目录总能得到相同的哈希值,我们必须精确。我们不能随便把条目以任意顺序扔进哈希函数。我们必须首先创建一个规范化(或标准)的表示。一个简单有效的方法是将所有条目表示为 (名称, 子哈希) 对,然后按名称的字典序对该列表进行排序。目录的标识符就是这个排序后、序列化列表的哈希值。

iddirectory=H(sorted_list_of[(n1,id1),(n2,id2),… ])id_{\text{directory}} = H(\text{sorted\_list\_of}[ (n_1, id_1), (n_2, id_2), \dots ])iddirectory​=H(sorted_list_of[(n1​,id1​),(n2​,id2​),…])

注意这里优美的递归。目录的身份依赖于其子节点的身份。如果这些子节点也是目录,它们的身份又依赖于它们子节点的身份,依此类推。这就创建了一条从我们结构的顶端——“根”——一直延伸到每个叶子文件中每一个字节的密码学链。在任何地方改变任何东西,一波新的哈希值就会一直向上传播到根。因此,根哈希是一个单一、紧凑的指纹,它唯一地标识并保证了整个复杂数据结构的完整性。

用不可变积木构建:历史的流动

这种递归哈希带来一个深刻且常常令人惊讶的后果:默克尔有向无环图中的每个对象都是​​不可变的​​。你无法改变它。想一想:如果一个对象的身份是它的哈希,而改变对象的内容会改变它的哈希,那么改变一个对象并不会修改它——它会创造一个具有新身份的全新对象。

这个原则是像 Git 这样被数百万开发者使用的版本控制软件的基石。一个 Git 仓库就是一个默克尔有向无环图,其中每个节点都是一个​​提交 (commit)​​。一个提交对象包含(除其他外)一个指向项目文件状态的指针(一个目录节点的哈希),以及至关重要的,其​​父提交​​的哈希。每个提交都向后指向它所基于的提交,形成了一个历史的有向无环图 (DAG)。

这引出了一个关于所谓“历史重写”命令(如 git rebase)的有趣见解。假设你有一个工作分支,你想让它从主历史的一个更新的点开始。感觉上你像是在编辑过去。但你没有。你不能。当你执行 rebase 时,Git 会创建一系列新的提交。第一个新提交有不同的父哈希,这意味着它自己的哈希也必须不同。第二个新提交现在有了一个不同的父提交(第一个新提交),所以它的哈希也必须不同,依此类推。最终你会得到一个全新的提交链,它反映了旧链的变更,但根植于别处。旧的提交并没有被销毁;它们仍然在数据库中,不可变且未被触动,只有在没有任何东西引用它们时才最终被清理掉。你不是在编辑历史,而是在创造一个替代的历史。

编织时间线:合并的艺术

名称中的“DAG”部分使得丰富的、分支的历史成为可能。当两个开发者从同一个父提交开始独立工作时会发生什么?历史图会分叉,产生两个分支。为了将他们的工作重新整合在一起,我们执行一次​​合并 (merge)​​。

一次合并就是一个有两个父节点的新提交。这个新节点将两条分叉的时间线重新编织成一条。构建这个合并提交是一门以 DAG 原理为指导的艺术。为合并创建一个新的目录节点。对于每个文件:

  • 如果文件在两个分支自共同祖先以来都未发生变化,则合并提交只需重用原始文件的哈希。没有数据被复制。
  • 如果文件只在一个分支中被更改,则合并提交指向那个分支的版本。
  • 如果文件在两个分支中都被更改,我们就遇到了冲突。系统可以通过创建一个特殊的“冲突标记”来标记这一点,或者要求用户手动创建一个新的、已解决版本的文件。然后,这个已解决文件的哈希被放入合并提交中。

这个过程保留了所有组成部分的完整性和历史。对于某些类型的数据,这个过程可以更加优雅。在一些先进的系统中,数据的状态被设计成一个称为​​并半格 (join-semilattice)​​ 的数学结构的一部分。在这个世界里,合并两个分叉的状态就像用一个代数连接算子 smerged=sA⊔sBs_{\text{merged}} = s_A \sqcup s_Bsmerged​=sA​⊔sB​ 找到它们的“最小上界”一样简单和确定,自动产生一个合理的、无冲突的结果。这揭示了数据结构与抽象代数之间深刻而美丽的统一。

证明与溯源:哈希链的力量

那么,我们已经构建了这个优雅、不可变且可验证的数据结构。它有什么用呢?答案在于它提供紧凑的、密码学证明的能力。

首先,是​​包含证明 (proof of inclusion)​​。想象一个公共机构发布了代表一个城市所有财产记录的默克尔根哈希——一个单一的、64个字符的字符串。你想证明你的房产契约是该官方记录的一部分。你需要下载并搜索数百万条记录吗?不需要。你只需要你自己的记录和从你的记录到根路径上的一小串兄弟哈希。这就是​​默克尔证明 (Merkle proof)​​。有了这个小小的证明,任何人都可以重新计算链上的哈希。如果他们计算出的最终哈希与公开的根哈希匹配,你的所有权就得到了密码学验证。验证过程极其高效,相对于记录总数,只需要对数级别的步骤,O(log⁡n)O(\log n)O(logn)。如果任何人,包括你,试图篡改数据,验证会立即失败。

其次,DAG 结构为我们提供了一个强大的​​溯源证明 (proof of provenance)​​ 工具。考虑一个电子健康记录,其中一条数据经过一系列处理步骤。每一步都会在默克尔有向无环图中创建一个新节点,指向其前驱。要审计某个特定实验室结果的整个历史,审计员不需要信任一个中心化的日志本。他们可以得到从最终结果回溯到其源头的节点路径。通过简单地重新哈希链中的每个节点,他们可以验证整个转换历史是完整且未经篡改的,并锚定在一个可信的链上根哈希。所需的工作量仅与历史路径的长度成正比,对于长度为 LLL 的路径,需要 L+1L+1L+1 次哈希计算。

从确保数据不会神秘地改变,到跟踪复杂项目的演变,再到提供无可辩驳的存在和历史证明,默克尔有向无环图证明了简单、优雅规则的力量。通过将身份根植于内容,它为构建去中心化、可验证和持久的系统提供了一个统一的框架。

应用与跨学科联系

我们花了一些时间来理解默克尔有向无环图的机制,这些由内容寻址、相互连接的数据构成的优雅结构。你可能会留下一个完全合理的问题:“这一切是为了什么?” 这是一个公平的问题。一个优美的智力机器是一回事,但一个有用的机器是另一回事。事实证明,这个特殊的想法不仅仅是一个理论上的奇珍;它是一个极其有用的想法。它的应用从计算机科学的深奥角落泛起涟漪,触及了协同软件开发、去中心化网络、公共卫生,甚至科学方法的基石等多个不同领域。

默克尔有向无环图的历程极好地说明了一个强大概念如何在最意想不到的地方找到归宿。这是一个关于构建基于信任的系统的故事,在这些系统中,完整性不是事后添加的补丁,而是架构本身的原生属性。让我们开始一次对这些应用的巡礼,不将其作为枯燥的目录,而是作为对这个结构所巧妙解决的问题的探索。

思想史:版本控制与协作

默克尔有向无环图最熟悉和最直接的应用或许是在版本控制领域。如果你曾使用过像 Git 这样的系统来协作一个软件项目,那么无论你是否意识到,你都一直在与一个默克尔有向无环图进行交互。

想象一个项目的历史。它始于一组初始文件。一个开发者做出更改并“提交 (commit)”它。另一个开发者做出不同的更改。历史不是一条直线;它会产生分支。每一次提交都代表了项目在某个时间点的完整快照。至关重要的是,每次提交也记录了它的“父节点”——即紧随其前的提交。这种提交指向其父节点的结构形成了一个有向无环图 (DAG)。图中没有环路,因为在这个模型中,时间只向前移动;一个提交不可能是它自己的祖先。

那么,“默克尔”部分体现在哪里呢?这个系统中的每一个对象——每一个文件、每一个目录、每一次提交——都不是通过名称来标识,而是通过其内容的加密哈希来标识。一次提交的标识符是其元数据(如作者和时间戳)以及最重要地,其父提交的哈希和项目根目录的哈希的哈希值。这意味着,即使项目历史中只有一个比特位发生变化,最新提交的哈希也会改变。当前状态的标识符与其全部历史紧密相连。

这种结构不仅仅是为了记账;它支持强大的操作。当一个项目的两个分叉的分支需要合并时,系统必须找到一个共同的起点。这相当于在图中找到一个“最近公共祖先”(LCA),即两个分支分叉出来的共同父提交。一旦找到这个共同的“合并基 (merge base)”,系统就可以执行一次合理的三方合并:它比较左分支相对于基准的变化,右分支的变化,并尝试将它们组合起来。

此外,哈希的普遍使用使得比较两个版本异常高效。要确定两个复杂的目录是否相同,系统不需要检查每个文件。它只需比较它们的哈希值。如果哈希值匹配,内容就是相同的。这使得极其快速的“差异比较 (diffing)”操作成为可能,系统可以快速遍历代表两个版本的两个 DAG,并跳过整个根哈希匹配的子树,只关注实际发生变化的部分。这就是默克尔有向无环图的简单天才之处:它为思想构建了一个可验证的、防篡改的历史,并实现了复杂、高效的协作。

构建一个永久和去中心化的网络

从对单个项目的文件进行版本控制,很自然地会想到一个问题:我们能否对整个互联网的数据进行版本控制?这就是像星际文件系统 (IPFS) 这样的系统的宏伟目标,它完全建立在默克尔有向无环图的基础之上。

在传统的网络中,内容是位置寻址的。你通过 URL 找到一个网页,这个 URL 指向一个特定的服务器。如果那个服务器宕机,或者所有者更改了那个位置的内容,原始数据就消失了。IPFS 提出了一个不同的模型:内容寻址。任何数据,无论是文本文件、图像还是海量数据集,都被分割成更小的块。这些块被组织成一个默克尔有向无环图,整个对象由其根节点的单一加密哈希——其内容标识符 (Content Identifier, or CID)——来标识。

这具有深远的影响。首先,数据的地址源于数据本身。CID QmXo... 将永远指向同一个文件,无论它存储在哪里。这可以防止“内容漂移”,即数据在稳定位置被悄悄更改的问题,这对于长期数据归档至关重要,尤其是在科学和医学领域,例如,基因组数据的完整性必须在几十年内得到保证。

其次,它提供了粒度化的完整性和效率。想象一个存储在区块链上的数GB大小的科学报告,为了节省空间,只有它的哈希被存储在链上。如果这是一个单一的整文件哈希,你需要下载整个文件来验证其完整性。但如果它是一个默克尔有向无环图的根 CID,你只需下载报告的一小块以及它的“默克尔证明”——即通向根路径上的兄弟哈希列表。有了这点少量数据,你就可以重新计算根哈希并与链上记录进行核对,从而证明你的数据块是真实的,并且是原始数据集的一部分。这使你能够信任并使用海量数据集的片段,而无需拥有整个数据集。默克尔有向无环图将数据完整性从一个单一的、全有或全无的属性,转变为一个粒度化的、可验证的、且更有用的属性。

可复现科学的基石:计算溯源

我们现在来到了这个结构最深刻、最深远的应用。我们已经看到默克尔有向无环图如何对文件和数据集进行版本控制。但是,如果我们能够对计算本身进行版本控制呢?如果我们能为计算机产生的任何结果创建一个无可指摘、可验证的审计追踪呢?这就是“计算溯源”领域,而默克尔有向无环图是其基石。

考虑一个复杂的科学分析,比如一个识别生物样本中蛋白质的蛋白质组学工作流,或者一个模拟药物反应的计算机模拟临床试验 (in-silico clinical trial)。最终的结果——一份蛋白质列表或一个统计摘要——是一长串转换的产物。它当然依赖于原始数据,但也依赖于一系列令人眼花缭乱的其他输入:每个软件工具使用的特定参数、参考数据库的版本、运行的确切软件二进制文件、底层的操作系统和数值库,甚至随机模拟中使用的随机数种子。

未能控制这些输入中的任何一个,都可能使结果无法复现。计算溯源的思想是将整个工作流视为一个巨大的默克尔有向无环图。每一个输入——每一个数据文件、每一个参数、每一份软件(以容器镜像摘要的形式捕获)、每一个随机数种子——都是一个由其内容哈希标识的工件。每一步的输出都有一个哈希,该哈希依赖于其输入的哈希。因此,最终结果有一个单一的根哈希,作为整个计算过程的唯一、可验证的指纹。如果有人质疑结果,你可以把 DAG 交给他们。他们可以重新执行工作流,看看是否能产生相同的最终哈希。这将科学可复现性从一个信任和手动记录的问题,转变为一个密码学确定性的领域。

这个概念超越了基本的可复现性,触及了科学发现的核心:因果关系。例如,在一个自动化电池设计平台中,科学家想知道改变一个微小的组件——比如说,一个特征工程算法——是否导致了性能的提升。问题在于存在大量的混淆因素:是新算法的功劳,还是输入数据分布发生了变化?是另一个软件库的改变吗?通过使用一个建立在默克尔有向无环图上的严格溯源框架,我们可以进行一次完美的“计算机模拟实验 (in-silico experiment)”。我们可以创建两个在各方面都逐比特相同的计算 DAG——相同的数据、相同的代码版本、相同的随机数种子——除了被测试的那一个组件。结果的任何差异都可以因果归因于那一个单一的变化。默克尔有向无环图为古老的科学原则 ceteris paribus(控制其他条件不变)提供了技术基础。

这是一个强大的思想,其应用延伸到任何需要可审计、可验证决策的关键领域,从金融建模到公共卫生政策分析。

最初一种巧妙的文件组织方式,如今已 blossoming 成构建可信系统的基本工具。从确保合作者不会意外覆盖你的工作,到构建一个永久的知识网络,再到保证拯救生命的临床试验的可复现性,默克尔有向无环图提供了一种通用语言。这是一种关于不可变真实的语言,其中事物的身份与其历史密不可分,其完整性可以被任何人、在任何地方验证。这就是这个思想简单、优美且极其有用的本质。