# 系统架构

> 远地虚拟机的端到端全貌。一份证明陈述什么、从客户程序二进制到合约调用的路径、各大组件如何衔接，以及塑造它们的设计决策。

远地虚拟机证明 RV32IMAC 程序的执行。本节在大组件的层面描述这个系统：每个组件做什么、为什么这样构建，以及它如何把工作交给下一个组件。[审计专区](https://apogee.gweb3networks.com/docs/auditors)则在每一列、每一个门的层面呈现同一个系统。

## 一份证明陈述什么

验证者持有三样不凭证明者一面之词获得的东西：

- **程序身份**，一个域元素，是程序的指令表、初始内存映像、入口 pc 和配置的摘要；
- 仪式的 **SRS 摘要**，验证密钥必须带有这个摘要；
- 一个**验证密钥**，它可以来自任何人，因为加载它时会根据其自身内容重新计算程序身份和 SRS 摘要，并要求其中的电路与验证者的注册表一致。

证明的陈述带有公开输入、**公开输出**（journal）、退出状态，以及这次执行的形状记录：分片数、内存窗口、最终的寄存器和 pc，以及每个分片的内存承诺和根。一份通过验证的证明确立的是：具有该身份的程序，在其映像上从入口 pc 启动，输入窗口中存放该公开输入，并带有某份由证明者选择的证明者提示（advice），逐条指令执行直至以该状态调用 `EXIT`，且已写出该公开输出。对证明者提示不作任何断言，也没有任何东西被隐藏：没有任何承诺或证明经过盲化。

## 从二进制到合约调用

> Figure: 四个阶段。程序在任何东西运行之前就已固定；执行被切分为分片；除内存论证在所有分片上统一闭合一次之外，每个分片都各自独立证明；结算把块压缩成合约可以检查的形式。

1. **程序。** 加载器把 ELF 读入一个 `ProgramImage`，并在原位展开压缩指令。解码器把每条指令路由到七个指令电路族之一，为每个电路族构建解码表（代码的每个半字一行），然后把这一切承诺为程序身份。[程序与身份](https://apogee.gweb3networks.com/docs/architecture/program)。
2. **执行。** 模拟器在单个 hart 上运行客户程序（guest）。一个周期就是其指令所属电路族中的一行，记录对 pc、寄存器和 RAM 带时间戳的读写。哈希和大整数运算被委托出去：一个 `ecall` 指明 RAM 中的一个帧，由某个委托电路族的一行在这个帧上完成计算。[执行、电路族与分片](https://apogee.gweb3networks.com/docs/architecture/execution)。
3. **分片。** 一个电路族的行被切分为若干分片，每片的行数等于该电路族的高度，即 `2^8` 到 `2^22` 之间的某个 2 的幂。一次执行所触及的内存由窗口电路族的分片覆盖，它们给出每个字的初始值和最终值。分片是证明的单位；一个块（block）有数百个分片。
4. **分片的证明。** 它的各列用 [Mercury](https://apogee.gweb3networks.com/docs/architecture/mercury) 承诺。[GKR 引擎](https://apogee.gweb3networks.com/docs/architecture/gkr)把电路族的电路从输出反向运行到这些列，每层一次求和校验（sumcheck）；所有列都在这一过程终止的那个点上打开，合为一次批量打开。
5. **块。** `BlockProof` 由陈述及其分片证明组成。验证时运行一次全局 transcript，逐一运行每个分片的检查，再在所有分片的根上做一次[内存核对](https://apogee.gweb3networks.com/docs/architecture/memory-lookups)。
6. **递归与结算。** 由远地虚拟机自己证明的验证者程序，逐段验证连续的分片，并折叠它们被延迟的配对。这些程序构成的树终止于一个根节点，一个 Groth16 电路重新验证根节点，`ApogeeVerifier.sol` 则检查这份证明以及折叠后的配对。[递归与结算](https://apogee.gweb3networks.com/docs/architecture/recursion)。

证明者把客户程序执行两遍：第一遍承诺每个分片的内存列，从而固定陈述及其挑战；第二遍在每个分片填满时证明它。它的内存以同时处理中的分片为界，而不取决于执行的长度。[流式证明者](https://apogee.gweb3networks.com/docs/architecture/streaming)。

## 塑造它的设计决策

**一个域，一条曲线。** 一切都建立在 BN254 的标量域上：电路、transcript、承诺和递归。正因如此，递归树的节点才能用自身的算术验证基础分片，整棵树也才能终结于一份由以太坊用其配对预编译合约检查的 Groth16 证明。

**用分层 GKR 电路，而不是已承诺的约束表。** 电路族的电路是叠在其已承诺列之上的一摞 2 次门层。只有最底层被承诺；其上的每一层都在一次反向过程中由求和校验证明，从不承诺。这一过程结束时，每个已承诺列都在同一个点上有一个断言，所以一个分片恰好只需一次打开。[GKR 引擎](https://apogee.gweb3networks.com/docs/architecture/gkr)解释了为什么这是该引擎最核心的节省。

**常数大小的打开。** Mercury 用八个曲线点和六个域元素打开一个多线性承诺，共 704 字节，与多项式的大小无关，也与有多少列共享这个点无关。它的检查形如 `e(A, [1]_2) = e(B, [x]_2)`，递归可以折叠这种检查，而不必计算配对。

**整个执行只有一个内存论证。** 每个电路族的每个分片中的每次访问，都是同一个读/写多重集中的一个元组，验证者对每个陈述只核对一次各个乘积。pc 是这个多重集中的一个单元，所以跨分片的顺序、连续性和周期唯一性都不需要别的论证，也没有哪个分片需要与相邻分片衔接。

**委托是电路族，而不是指令。** 昂贵的函数拥有自己的电路族，通过一个作用于 RAM 帧的 `ecall` 调用，并经由同一个多重集与其请求一一配对。指令电路因此保持精简，客户程序只为它实际调用的委托付费。

**流式处理，而不是物化。** 按每个周期约 300 字节计算，执行轨迹会是系统中最大的对象，所以它从不存在。证明者执行两遍，只持有正在处理的分片。

**不借用外部密码学。** 域、曲线、配对、MSM、哈希、多项式承诺、GKR 和 Groth16 都在仓库内实现，并逐页写成规范。arkworks、Plonky3 和 zkhash 只作为测试参照（oracle）出现。

## 可靠性如何组合

每个分片的 GKR 过程和打开，把其电路的输出与已承诺列联系起来。在此之上，以下论证贯穿整个执行：

| 断言 | 承载它的论证 |
| --- | --- |
| 每一行都遵循其指令 | 电路族电路的约束门，在每一行上均为零 |
| 一行的指令就是程序在该行 pc 处的指令 | 以该行的 pc 和各字段在电路族的解码表中查找，而解码表由程序身份承诺 |
| 每次读取都返回最近一次写入 | 覆盖所有分片的单一多重集；验证者把每个分片的读根和写根连乘，并乘上寄存器与 pc 的边界因子 |
| 各行按程序顺序构成一条从入口 pc 到退出的路径 | pc 是该多重集中的一个单元，写入它的时间戳至少比读取它的晚四个 |
| 一个值是一个字节、一个字、一个符号位、一个 XOR 结果 | 基于范围表、字节表和通用表的 LogUp 通道 |
| 公开输入和公开输出就是所声称的字节 | 两个公开窗口的初始列与最终列，被约束为这些字节的多线性扩展 |
| 委托出去的计算就是该函数的计算 | 通过同一个多重集读写帧的调用行，与各自的 `ecall` 一一配对 |

挑战来自 Poseidon2 双工 transcript。全局 transcript 在内存挑战产生之前吸收整个陈述，包括每个分片的内存承诺；每个分片的 transcript 都以全局 transcript 的最终状态为种子。[可靠性地图](https://apogee.gweb3networks.com/docs/auditors/soundness-map)把每一行断言一直追溯到证明它的章节。

## 代码，按层划分

| 层 | Crate | 作用 |
| --- | --- | --- |
| 算术 | `field`、`curve`、`poly`、`sumcheck` | `Fr`；`Fq` 扩域塔、G1、G2、配对、MSM；多线性多项式；零校验（zerocheck） |
| Fiat–Shamir 与设置 | `transcript`、`srs` | Poseidon2 与双工 transcript；仪式文件导入、KZG、Groth16 的第一阶段 |
| 承诺 | `pcs`、`pcs-verify` | Mercury 及其延迟验证 |
| 程序 | `loader`、`isa`、`program` | 从 ELF 到映像、解码器、解码表、`VmConfig` 与程序身份 |
| 执行 | `emulator`、`trace` | 执行器及其追踪器；行、内存状态、列构建器 |
| 电路 | `constraints`、`gkr-verify`、`gkr` | 以数据形式表示的全部电路；GKR 验证者与证明者 |
| 证明与验证 | `verifier-core`、`verifier`、`prover` | 陈述、transcript、密钥、每一项检查；流式证明者 |
| 结算 | `host`、`groth16`、`contracts/` | 宿主程序（host）SDK、递归树与判定器；`ApogeeVerifier.sol` |
| 保障 | `checker`、`tools/` | 独立校验器、篡改测试套件、基准测试、周期分析器、参照 |

验证者是唯一受信任的一方：证明者不做任何校验，错误的输入只会让诚实的证明者得到一份无法通过验证的证明。[安全模型](https://apogee.gweb3networks.com/docs/architecture/security)确切列出了可靠性依赖哪些 crate。
