本文深入介绍了Rialo区块链的证明携带计算(proof-carrying computation)模型。
证明携带计算基于一个简单的理念:执行和验证是两个不同的问题。执行是昂贵的、有状态的,有时还是私密的。它需要计算资源,需要访问共享状态,并且在某些情况下必须隐藏某些输入或中间输出。
相比之下,密码学(基于证明的)验证通常比通过复制执行进行验证要便宜得多,而且只依赖于约定的公共输入。验证者可以通过检查密码学证明来验证声称结果的正确性,而无需重新执行底层计算或访问私有执行数据,例如机密输入或中间值。
密码学验证用证明检查取代了通过重新执行进行的复制验证。这一洞见使得区块链能够将执行与验证解耦,并依赖密码学证明来验证交易输出的正确性。我们将这种模型称为证明携带计算。在证明携带计算中,计算伴随着证明其正确性的证明,并且在结果被接受并反映到链的状态之前,必须验证这些证明。
证明携带计算可以采取两种形式:
当使用证明携带计算时,执行可以在链上或链下进行。在链上执行模型中,提议者将交易排列成区块,执行程序指令,计算新状态,并生成一个密码学证明,证明程序被正确执行且结果状态根有效。验证者验证该证明,如果通过,则接受该区块并完成状态转换,而无需重新执行该区块。
在链下执行模型中,执行完全在链下进行。只有最终的状态更新和相应的正确执行证明被提交到链上进行验证。验证者在此处扮演相同角色。他们验证提交的证明,如果验证通过,则接受提议的更新。
在这种模型下,当相应的证明在链上被接受时,链下执行的结果被视为已结算。此外,证明可以证明完整的状态转换(例如,在ZK-rollup中),或者证明中间执行结果,这些结果在被链上程序消耗时会触发状态更新(例如,一个预言机在链下计算指数价格并提交交易以在链上更新指数)。
证明由证明者生成,证明者可能与执行程序是同一实体,也可能不是。当角色分离时(即执行者执行程序并计算交易结果),证明者接收公共输出、程序输入和执行轨迹(交易执行的逐步指令记录)。这些输入被送入一个证明电路,该电路遍历程序的执行轨迹,检查执行是否遵循了正确的指令路径并产生了声称的输出。如果执行轨迹有效,证明者生成一个证明,执行者将其提交到链上进行验证。
当角色合并时,证明者直接执行程序,并在执行结束时生成两个产物:
如果证明系统是零知识的,则证明电路的私密输入以及程序执行期间生成的执行轨迹构成见证,永远不会被泄露。这就是为什么证明携带计算能够在需要时保护隐私:程序可以在私密数据上操作,同时仍然允许通过密码学证明验证其执行。
Rialo计划在启动时支持最小可行实现的证明携带计算。从高层来看,系统运作如下:
系统涉及三个不同的参与者:链下证明者、验证者和应用程序。链下证明者在ZK-VM(零知识虚拟机)中运行程序,生成执行轨迹,并生成一个密码学证明,证明执行的正确性和产生的输出。证明者可以由客户端应用程序、Rialo合作伙伴或第三方证明服务运行,该服务代表应用程序生成证明。
客户端应用程序是一个普通的Rialo合约,它定义了计算和要证明的陈述。它消费来自已验证的证明携带计算的输出,并在证明验证后执行状态更新(例如,触发转账或更新存储变量)。当Rialo接受客户端应用程序在证明验证后发送的交易时,链下结果和相应的链上状态更新即被结算。
验证者是一个普通的Rialo程序(或预编译),它根据陈述验证有效性证明。这样一个程序的最小接口如下:
verify(
proof_bytes,
public_outputs,
statement_id
) -> ok
验证者通过检查唯一标识正在被证明的程序的陈述标识符,来确认证明是针对正确计算生成的。它验证证明与提供的公共输出一致,并对证明大小和输入结构施加严格限制,以确保验证保持有界。验证者不访问私密输入,也不执行结算。结算由应用程序逻辑处理,并由链最终确定。
一个考虑相关参与者的更简单的工作流程如下:
通过使用密码学证明验证计算,将执行与共识解耦,极大地扩展了链上应用的设计空间。
首先,它使Rialo能够支持需要计算密集型执行或频繁链下重新计算结果(随后在链上结算)的应用程序。此类应用在传统状态机复制模型下是不可行的,因为该模型要求所有验证者进行复制执行。证明携带计算使这种逻辑重新变得可行。计算可以在高度优化的执行环境中连续且廉价地在链下运行,而结果则由Rialo的去中心化验证者集在链上安全验证并结算。
这使得构建以下系统成为可能:状态在链下快速演变并定期在链上检查点的实时游戏、依赖重复链下计算的模拟驱动协议(例如,蒙特卡洛模拟、优化循环或基于代理的模型)、高频更新头寸并稍后结算净结果的做市或交易引擎,以及其他链下连续执行与密码学链上结算自然结合的系统。并非所有事情都需要在链上进行。通过证明携带计算,应该保留在链下的内容可以这样做,而不会牺牲可验证性或安全性。
其次,证明携带计算使得需要输入机密性的应用成为可能。应用可以证明执行满足特定条件或约束,而无需揭示用于推导该结论的底层数据。例如,一个应用可以验证用户满足资格标准(如信用度、声誉阈值或合规检查),而无需揭示用户的私密财务历史或活动日志。这在传统模型下是不可能的,因为验证者必须重新执行交易,因此需要完全访问交易输入。
第三,证明携带计算使得在低信任环境中进行协调成为可能,而无需依赖可信操作者或可信执行环境(TEE)。虽然TEE在许多情况下功能强大且有用,但某些应用可能需要更强的去信任化保证。这些应用可以使用Rialo的证明携带计算原语来构建去信任化工作流,将链下连续执行与链上验证和结算相结合。
计算指数价格
考虑一个根据多个数据源按照公布的聚合规则计算的指数价格。原始输入可能处理成本高昂或属于数据提供商的专有信息,使得该计算无法在链上实际运行。然而,在没有验证保证的情况下在链下运行计算则需要信任操作者。
证明携带计算消除了这种权衡。操作者可以在ZK-VM中在链下计算指数价格,通过对原始数据集执行聚合逻辑并生成一个证明,证明价格是根据公布的规则正确计算的。该证明将结果绑定到正在被证明的特定计算,而无需揭示原始输入或中间值。
如果需要时效性,操作者可以将时效性参数(如随机数或时间窗口)作为公共输出的一部分。Rialo验证该证明,如果有效,客户端应用程序可以安全地更新链上指数价格。这既保护了数据机密性,又最大限度地减少了链上的计算负担。
资格和规则满足的私密验证
考虑一个奖励满足特定资格规则(例如,在给定时间窗口内完成一组定义的动作)的用户的应用程序。底层活动数据可能敏感或私密,不适合在链上发布。在传统模型下,验证者需要访问这些数据来验证资格,迫使应用程序要么披露私密信息,要么依赖可信操作者。
证明携带计算消除了这种权衡。链下证明者可以在zkVM中针对私密活动日志评估资格规则,并生成一个证明,证明规则被正确应用。证明者只提交最小的公共输出,例如符合条件的用户标识符列表或聚合奖励承诺,以及证明。私密活动数据永远不会被披露。
Rialo验证该证明,如果有效,应用程序可以在链上执行支付逻辑。验证者不需要信任操作者或假设链下基础设施的完整性——正确性是通过密码学验证而非信任来确立的。
在这两种情况下,应用程序逻辑遵循相同的模式:验证证明 → 应用状态更新。这结合了链下执行的优点与链上验证和结算,使得更灵活和更复杂的加密应用成为可能。接下来,我们将考虑使Rialo处于引领支持证明携带计算并释放区块链开发者创造力和才智的独特优势地位。
Rialo对证明携带计算的适用性直接源于其执行架构中已做出的决策。如之前的文章所述,Rialo使用RISC-V作为其智能合约执行目标和指令集架构(ISA)。这一选择允许在指令集级别定义执行正确性,而不是针对特定的虚拟机实现(例如EVM、SVM或Move VM)。在实践中,这意味着正确性可以独立于任何特定运行时来指定,并通过执行前的确定性预处理步骤来强制执行。
这种区别很重要,因为证明携带计算在基础层只需要一件东西:一个稳定的、确定性的正确性定义,可以在不重放执行的情况下进行检查。只有当系统已经就程序正确执行的含义达成一致时,密码学证明才能取代重新执行。
Rialo的执行模型提供了这一基础。在执行之前,程序从其编译形式(例如,RISC-V ELF二进制文件)转换为确定性的、规范的字节码表示,并分配明确的资源限制。这种转换在任何代码运行之前发生,并确保所有验证者在相同的执行规则和资源约束下推理相同的程序,无论编译器版本、二进制布局或主机环境如何。
具体来说,Rialo强制执行:
一旦这些属性存在,密码学证明就成为可行的替代强制执行机制。执行不再需要由每个验证者重放来强制执行正确性。程序可能仍在链上执行,但正确性可以通过检查针对共享指令级规则的证明来验证,而不是重新执行计算。
在这种链上模型中,证明携带计算用基于证明的验证取代了冗余执行,而不改变执行发生的地点或状态转换的定义方式。关键在于,相同的验证模型也扩展到链下执行,只要执行遵循相同的指令级正确性定义。在这种情况下,计算在链下进行,证明在链上验证,然后结果被接受。
Rialo在这种链下执行加链上结算模型中处于有利地位,因为它使用RISC-V作为其执行目标。这一选择使Rialo与更广泛的零知识生态系统保持一致,特别是与生成执行证明的证明系统保持一致。大多数现代zkVM,如SP1、RISC Zero和其他基于RISC-V的证明系统,将用高级语言编写的程序编译成RISC-V指令,并生成证明以证明该指令级执行的正确性。
由于Rialo已经使用RISC-V作为其执行目标,并在指令集级别定义正确性,因此它能够以自己已经理解的语言验证关于执行的证明。如果没有这种对齐,Rialo将需要推理在外部指令模型(例如,ZK-VM的自定义字节码或领域特定语言)下执行的程序的正确性,而不是其本地支持的RISC-V执行模型。在实践中,Rialo根据协议承诺的标准化RISC-V执行配置文件验证证明,确保在本地程序和基于证明的验证之间有一个单一的、明确的正确执行定义。
当证明证明了在具有自身正确性定义的不同执行模型下产生的输出时,链只能在该证明验证期间能够解释和验证这些语义的情况下才能验证该证明。这迫使链要么在其共识逻辑中直接支持多个执行模型,要么在应用层将外部执行模型实现为本地验证者逻辑。这两种方法都引入了额外的复杂性,我们将在下面讨论。
验证外部程序(即在不同的执行模型下执行的程序)的一种方法是在协议级别支持多个执行模型,要么通过维护单独的正确性规则,要么通过使用根据执行模型应用不同规则的统一状态转换函数。例如,一个链可能支持本地RISC-V执行,同时也支持EVM操作码、WASM字节码或ZK-VM/DSL 执行模型。这就是多虚拟机区块链(例如,在单个运行时中同时支持EVM和SVM的系统)的工作方式。
这种设计支持两种不同的用例。首先,它允许为不同执行模型编写的程序直接在同一个链上运行。针对不同指令集的合约可以在共享运行时中共存,协议为每个执行模型分别强制执行正确性。
其次,它允许链验证证明了在不同执行模型下产生的输出的密码学证明,即使这些程序是在链下执行的。在这种情况下,链本身并不执行外部程序,但它必须足够理解外部执行语义,以便验证正确执行的证明。
虽然支持这两个用例非常强大,但也是有代价的。链必须推理多个正确执行的定义,要么通过维护并行的状态转换规则,要么通过将条件逻辑嵌入统一的状态转换函数。这极大地复杂化了验证逻辑,扩大了bug的暴露面,并使状态转换规则更难强制执行和可靠审计。
验证外部程序的另一种方法是在沙盒环境(例如链上合约或预编译)中实现外部执行模型,并针对该嵌入的逻辑验证证明。在这种设计中,外部指令集及其正确性规则被编码为用链的本地指令集(在Rialo的情况下是RISC-V)编写的迷你VM,并仅用于证明验证。链本身不执行外部程序。相反,它执行本地验证者逻辑,该逻辑验证证明以及声称的公共输出的一致性。
一个有效的证明证明了未披露执行轨迹的每一步都遵守了外部执行模型的状态转换规则。例如,一个面向EVM的证明系统将操作码语义(如ADD和MUL的栈行为,以及SSTORE的存储更新)编码为证明电路中的约束,而一个面向WASM的系统则编码操作数栈、控制流和内存规则。当这样的证明被成功验证时,其有效性意味着计算过程中所有必要的执行规则都得到了尊重。
虽然这种方法避免了在协议级别添加新的执行模型,但它引入了有意义的成本。每个外部执行模型都需要定制的验证者逻辑,这些逻辑必须被实现、审计和维护,从而扩大了可信代码的暴露面。验证还会产生额外的执行成本,因为证明验证作为计量的链上逻辑运行,而不是作为本地的状态转换规则。
将外部执行语义翻译成本地验证者逻辑会产生更大、更复杂且优化不佳的代码。外部执行模型是为与验证者链不同的指令集和成本模型设计的。因此,外部模型中的简单操作会扩展为许多本地指令,每个指令都必须执行并计量。例如,像SSTORE这样的EVM操作码在EVM执行模型中是一个单独的指令,但在非EVM链上验证EVM证明需要执行本地逻辑来检查栈行为、内存访问规则、Gas费核算和状态更新。所有这些都会产生单独的gas费用。
相比之下,当证明是关于RISC-V执行时,验证者在链的本地指令模型中检查执行,从而消除了大部分这种翻译开销。由于Rialo在RISC-V上运行,它非常适合高效验证来自基于RISC-V的zkVM的证明,这些zkVM生成关于正确指令级执行的证明,无需定制的验证逻辑或在不同执行模型或语义表示之间进行翻译。
状态机复制(SMR)赋予了区块链核心优势:去中心化、容错性、安全性和去信任化。但它也是限制因素。复制存储和执行限制了区块链能做什么,使得支持具有复杂逻辑、繁重计算或强隐私要求的应用程序变得困难。
证明携带计算通过将执行与验证分离来解决这一限制。它不要求每个验证者重新执行相同的计算,而是可以任何地方执行一次,同时通过任何人都可以验证的密码学证明来强制执行正确性。区块链的角色从重新执行计算转变为验证声称的结果是否根据约定的规则正确产生。
Rialo非常适合这种模型,因为正确性是在指令集级别定义的,而不是在特定虚拟机级别。通过使用RISC-V作为其执行目标,链将正确性锚定到一个单一的、稳定的执行模型上,该模型具有精确和定义明确的语义。这自然地支持了Rialo当前设计的链下执行、链上结算模型。程序在链下执行,并提交其输出以及密码学证明。Rialo根据其RISC-V指令语义验证该证明,如果有效,则授权相应的状态转换。执行不在链上重放,也不需要模拟外部执行模型。
相同的架构也支持未来的链上执行、基于证明的验证模型。在这种设置中,程序仍可能在链内执行,但验证者验证正确执行的证明,而不是自己重新执行计算。在这两种情况下,证明都表明RISC-V指令在链的规则下正确执行。变化的是执行发生的地点,而不是正确性的含义。
关键在于,Rialo不需要自己生成证明。执行和证明生成发生在链下,由应用程序、外部证明者或专门的ZK-VM处理。Rialo的角色是验证这些证明,并使用单一的确定性正确性定义来授权状态转换。结果是一个清晰的职责分离:链下系统处理执行和证明,而链验证证明并最终确定状态转换。
证明携带计算改变了执行发生的位置,而不改变被视为正确执行的内容。从这个意义上说,Rialo并不取代ZK-VM。它通过作为证明携带计算的安全结算层,并将基于zkVM生成的证明的应用的安全性锚定,从而补充了它们。
虽然证明携带计算扩展了链上可能实现的功能,但它引入了系统必须明确处理的新约束。这些约束塑造了证明如何被验证、结果如何被应用程序消耗,以及验证如何在大规模下保持安全和经济。
系统必须将证明绑定到正在被证明的陈述(由陈述或程序标识符标识)以及相关的公共输出。这通常通过验证者生成的验证结果来实现,链上程序可以解释并使用该结果来驱动应用程序逻辑。生成和使用此验证结果有两种方法。
在第一种方法中,验证者在成功验证证明后生成一个验证收据。收据引用陈述标识符和公共输出的哈希,并存储在链上。应用程序在执行状态更新和发起结算时可以稍后引用此收据。这种模式将验证与结算分离,允许验证结果在交易之间持久且可重用。
在第二种方法中,验证者返回一个验证结果,而不在链上存储任何内容。应用程序在证明验证后立即消费验证结果,并在同一笔交易中应用状态更新。验证和结算是原子性的。应用程序的状态更新仅在证明有效时最终确定,并且不持久化收据。
第一种机制使验证结果持久且可重用,这在结算稍后发生或跨多个交易时很有用,但代价是额外的链上状态。第二种机制通过保持验证和结算原子性来最小化复杂性和链上足迹,但验证结果不能被重用。
在这两种情况下,结算都明确绑定到特定的陈述和输出集。在验证的证明被链上应用程序消耗且相应的状态更新被应用后,生成的状态与本地执行产生的状态同等对待。
验证消耗计算资源,证明携带计算系统在设计时必须考虑这一约束。为了防止滥用并确保性能可预测,证明必须受到严格的大小限制,并且验证交易必须支付补偿验证者验证计算成本的费用。
因此,客户端应用程序和证明服务应优化证明大小和验证成本。常见建议包括设计程序以最小化证明开销,并实施以下技术:
这些实践确保验证在大规模下保持有界且经济可行。
密码学证明保证了在提供的输入和程序下计算被正确执行,但它们本身并不能保证这些输入反映事实真相。除非输入真实性被显式强制执行,否则证明只证明了内部一致性。
例如,如果一个预测市场基于五个值的平均值计算结果,证明可以验证报告的结果是正确的平均值。但它不能证明这五个值来自经批准的数据提供者,除非这些来源在证明过程中被认证或承诺。
因此,建立在Rialo证明携带计算原语之上的应用程序必须仔细推理输入验证。可以使用多种输入验证技术,例如数据源承诺、签名输入或链上引用检查。尽管如此,确保输入有意义且可信是应用程序级(或证明者级)的责任,而不是由验证和结算证明的链(Rialo)强制执行的事情。
- 原文链接: x.com/rialohq/status/205...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
作者暂未设置收款二维码