作者:Huobi Ventures 资深研究员谢锦斌

引言

零知识证明是密码学中的一种重要技术,它允许一个人向另一个人证明一个陈述是真实的,而无需透露任何其他信息。这种技术在许多领域都有广泛的应用,包括身份验证、区块链和安全计算等。Nova是微软开发的一种新型零知识证明系统,它使用了一种名为松弛的秩一约束系统(Relaxed Rank-1 Constraint Systems,Relaxed R1CS)的技术,以提高证明的效率和灵活性。最后一章节对源码进行详细解读。

Nova的优点

Nova的主要优点在于其使用的松弛的R1CS技术。R1CS是一种用于构建零知识证明的系统,它可以用于证明一个人知道满足一组多项式等式的解,而不必透露任何关于解的信息。然而,传统的R1CS系统需要在证明过程中使用大量的随机性,这会导致证明的生成和验证过程非常复杂和耗时。Nova通过使用松弛的R1CS来解决这个问题,它允许在证明中使用更少的随机性,从而大大提高了证明的效率。

Nova还具有其他一些优点。例如,它支持增量计算,这意味着可以逐步计算复杂的函数,而不必一次性计算整个函数。这在处理大规模数据或进行复杂计算时非常有用。此外,Nova还支持多项式计算,这使得它可以处理更复杂的证明任务。

Nova的缺点

尽管Nova具有许多优点,但它也有一些缺点。首先,由于Nova使用的是松弛的R1CS,因此它的证明可能不如传统的R1CS系统那么强大。这是因为松弛的R1CS允许在证明中使用更少的随机性,这可能会降低证明的安全性。然而,Nova的开发者已经采取了一些措施来解决这个问题,例如使用更强大的密码学算法和更复杂的证明策略。

其次,Nova的实现相对复杂,这可能会增加使用和维护的难度。Nova使用了许多高级的密码学技术,如多项式计算、群操作和随机预言机等,这需要深入理解这些技术才能有效地使用和修改Nova。

Nova在零知识证明领域的重要地位

Nova在零知识证明领域中占据了重要的地位。它的出现,为零知识证明的发展开辟了新的道路。Nova采用的松弛的R1CS技术,使得证明的生成和验证过程更加高效,这对于大规模的零知识证明应用至关重要。此外,Nova还支持增量计算和多项式计算,这使得它可以处理更复杂的证明任务,进一步扩大了零知识证明的应用范围。

Nova的源码解读

https://github.com/microsoft/Nova

在 src/ 目录下,有以下几个重要的子目录:

bellperson/:这个目录可能包含了关于 Bellman-Ford 算法的代码。

gadgets/:这个目录可能包含了一些用于构建 zk-SNARK 证明的工具。

provider/:这个目录可能包含了一些提供者的代码,如 keccak.rs 可能是实现 Keccak 哈希函数的代码。

spartan/:这个目录可能包含了关于 Spartan 协议的代码。

traits/:这个目录可能包含了一些 Rust traits,用于定义一些公共的行为。

  • src/bellperson/mod.rs 文件的内容:

    这个模块主要用于生成 R1CS(Rank-1 Constraint Systems,一种用于 zk-SNARKs 的约束系统)。

    它包含了三个子模块:

    r1cs: 这个模块可能包含了关于 R1CS 的代码。

    shape_cs: 这个模块可能包含了关于形状约束系统的代码。

    solver: 这个模块可能包含了关于解决约束系统的代码。

    在测试部分,它定义了一个函数 synthesize_alloc_bit,这个函数接受一个约束系统,然后添加一些约束来检查输入的两个比特是否确实是比特。然后,它定义了一个函数 test_alloc_bit_with,这个函数首先创建一个形状

    • src/bellperson/r1cs.rs 文件的内容:

      这个文件主要定义了两个 trait:`NovaWitness` 和 `NovaShape`,它们分别提供了从实现者获取 `R1CSInstance` 和 `R1CSWitness`,以及获取 `R1CSShape` 和 `CommitmentKey` 的方法。

      - `NovaWitness` trait 有一个方法 `r1cs_instance_and_witness`,它接受一个 `R1CSShape` 和一个 `CommitmentKey`,然后返回一个 `R1CSInstance` 和一个 `R1CSWitness`。这个 trait 为 `SatisfyingAssignment` 结构体实现,这意味着任何 `SatisfyingAssignment` 都可以使用这个方法来获取一个 `R1CSInstance` 和一个 `R1CSWitness`。

      - `NovaShape` trait 有一个方法 `r1cs_shape`,它返回一个 `R1CSShape` 和一个 `CommitmentKey`。这个 trait 为 `ShapeCS` 结构体实现,这意味着任何 `ShapeCS` 都可以使用这个方法来获取一个 `R1CSShape` 和一个 `CommitmentKey`。

      这个文件还定义了一个函数 `add_constraint`,它接受一个约束系统和三个线性组合,然后在约束系统中添加一个新的约束。这个函数被 `NovaShape` 的实现者在生成 `R1CSShape` 时使用。

      总的来说,这个文件的主要作用是提供了一种方式,使得可以从一个满足特定条件的系统(如 `SatisfyingAssignment` 或 `ShapeCS`)中生成 R1CS 的实例、证人、形状和承诺密钥。

    • src/bellperson/shape_cs.rs

      这个文件定义了一个名为 `ShapeCS` 的结构体,它实现了 `ConstraintSystem` trait。`ShapeCS` 是用于创建 R1CS 形状的约束系统。

      `ShapeCS` 结构体包含以下几个字段:

      - `named_objects`: 这是一个映射,用于存储与路径关联的对象。

      - `current_namespace`: 这是一个字符串向量,用于存储当前的命名空间。

      - `constraints`: 这是一个向量,用于存储所有添加到 `ShapeCS` 的约束。

      - `inputs`: 这是一个字符串向量,用于存储所有的输入。

      - `aux`: 这是一个字符串向量,用于存储所有的辅助输入。

      `ShapeCS` 结构体实现了 `ConstraintSystem` trait,这意味着它提供了以下几个方法:

      - `alloc`: 这个方法用于分配一个新的变量。

      - `alloc_input`: 这个方法用于分配一个新的输入变量。

      - `enforce`: 这个方法用于添加一个新的约束。

      - `push_namespace`: 这个方法用于推入一个新的命名空间。

      - `pop_namespace`: 这个方法用于弹出当前的命名空间。

      - `get_root`: 这个方法用于获取根约束系统。

      这个文件还定义了一些辅助函数,如 `proc_lc` 和 `compute_path`,它们分别用于处理线性组合和计算路径。

      总的来说,这个文件的主要作用是提供了一种方式,使得可以从一个满足特定条件的系统(如 `ShapeCS`)中生成 R1CS 的形状。

    • src/bellperson/solver.rs

      这个文件定义了一个名为 `SatisfyingAssignment` 的结构体,它实现了 `ConstraintSystem` trait。`SatisfyingAssignment` 是用于创建 R1CS 实例和证人的约束系统。

      `SatisfyingAssignment` 结构体包含以下几个字段:

      - `a_aux_density`, `b_input_density`, `b_aux_density`: 这些是 `DensityTracker` 类型的字段,用于跟踪查询的密度。

      - `a`, `b`, `c`: 这些是向量,用于存储 A、B、C 多项式的评估结果。

      - `input_assignment`, `aux_assignment`: 这些是向量,用于存储变量的赋值。

      `SatisfyingAssignment` 结构体实现了 `ConstraintSystem` trait,这意味着它提供了以下几个方法:

      - `new`: 这个方法用于创建一个新的 `SatisfyingAssignment` 实例。

      - `alloc`: 这个方法用于分配一个新的辅助变量。

      - `alloc_input`: 这个方法用于分配一个新的输入变量。

      - `enforce`: 这个方法用于添加一个新的约束。

      - `push_namespace`, `pop_namespace`: 这些方法用于操作命名空间,但在这个上下文中并没有实际的操作。

      - `get_root`: 这个方法用于获取根约束系统。

      - `is_extensible`, `extend`: 这些方法用于扩展约束系统。

      总的来说,这个文件的主要作用是提供了一种方式,使得可以从一个满足特定条件的系统(如 `SatisfyingAssignment`)中生成 R1CS 的实例和证人。

    • "src/circuit.rs",它定义了 Nova 协议中的增强电路(Augmented Circuit)。这个电路包括一个步骤电路(Step Circuit)和 Nova 的非交互折叠方案中的验证器电路。

      文件中定义了以下几个主要的结构体和方法:

      - `NovaAugmentedCircuitParams`:这个结构体包含了电路的参数,包括 limb 宽度、limb 数量和一个布尔值表示这是否是主电路。

      - `NovaAugmentedCircuitInputs`:这个结构体包含了电路的输入,包括参数、i、z0、zi、U、u 和 T。

      - `NovaAugmentedCircuit`:这个结构体是 Nova 增强电路的主要定义,它包含了电路的参数、只读常量、输入和步骤电路。它还定义了一些方法,如 `alloc_witness`(分配证人)、`synthesize_base_case`(合成基础案例)和 `synthesize_non_base_case`(合成非基础案例)。

      - `synthesize` 方法:这是 Nova 增强电路的主要合成方法,它首先分配所有的证人,然后根据是否是基础案例来合成电路,并最后输出计算的哈希值和 u.X[1]。

      这个文件还包含了一些测试代码,用于测试递归电路的功能。

      总的来说,这个文件的主要作用是定义了 Nova 协议中的增强电路,这个电路是 Nova 协议的核心部分,它包括了一个步骤电路和一个验证器电路,并提供了一种方式来合成这个电路。

    • "src/constants.rs",它定义了一些常量,这些常量在整个项目中被广泛使用。以下是这些常量的含义:

      - `NUM_CHALLENGE_BITS`: 这个常量定义了挑战的位数,值为 128。挑战通常是由证明者生成的随机数,用于 zk-SNARK 证明过程中的交互步骤。

      - `NUM_HASH_BITS`: 这个常量定义了哈希的位数,值为 250。哈希函数是一种可以将任意长度的输入数据映射到固定长度输出的函数,这里的输出长度就是 250 位。

      - `BN_LIMB_WIDTH`: 这个常量定义了大数(Big Number)的肢宽,值为 64。在计算机科学中,大数是那些超出了标准数据类型能够表示的范围的数,它们通常被分解为多个“肢”进行存储和操作。

      - `BN_N_LIMBS`: 这个常量定义了大数的肢数,值为 4。这意味着每个大数都被分解为 4 个肢进行存储和操作。

      - `NUM_FE_WITHOUT_IO_FOR_CRHF`: 这个常量定义了对于冲突抗性哈希函数(CRHF),不包括输入/输出的字段元素(FE)的数量,值为 17。

      - `NUM_FE_FOR_RO`: 这个常量定义了对于随机预言机(RO),字段元素(FE)的数量,值为 24。

      这些常量在 Nova 协议的实现中起着关键的作用,它们定义了一些重要的参数,如挑战的位数、哈希的位数、大数的肢宽和肢数等。

    • "src/errors.rs",它定义了 Nova 库可能返回的错误类型。这些错误类型被封装在一个名为 `NovaError` 的枚举中。以下是这些错误类型的含义:

      - `InvalidIndex`: 如果提供的行或列在 (row, col, val) 元组中超出范围,将返回此错误。

      - `OddInputLength`: 如果提供的输入长度不是偶数,将返回此错误。

      - `InvalidInputLength`: 如果提供的输入长度不正确,将返回此错误。

      - `InvalidWitnessLength`: 如果提供的证人长度不正确,将返回此错误。

      - `UnSat`: 如果提供的证人不满足给定的形状和实例,将返回此错误。

      - `DecompressionError`: 如果无法解压提供的压缩承诺,将返回此错误。

      - `ProofVerifyError`: 如果证明验证失败,将返回此错误。

      - `InvalidNumSteps`: 如果提供的步骤数为零,将返回此错误。

      - `InvalidIPA`: 如果提供了无效的内积参数,将返回此错误。

      - `InvalidSumcheckProof`: 如果提供了无效的求和检查证明,将返回此错误。

      - `InvalidInitialInputLength`: 如果增量计算的初始输入与先前声明的元数不符,将返回此错误。

      - `InvalidStepOutputLength`: 如果步骤执行产生的输出长度与先前声明的元数不符,将返回此错误。

      - `InternalTranscriptError`: 如果转录引擎遇到轮数溢出,将返回此错误。

      - `InvalidMultisetProof`: 如果多集检查失败,将返回此错误。

      - `InvalidProductProof`: 如果产品证明检查失败,将返回此错误。

      - `IncorrectWitness`: 如果与公开 IO 和使用的赋值的一致性失败,将返回此错误。

      这些错误类型覆盖了 Nova 库中可能遇到的各种问题,包括输入错误、证明错误、内部错误等。当 Nova 库的函数遇到问题时,它们会返回这些错误,以便调用者可以了解出了什么问题并采取相应的行动。

    • "ecc.rs",它是 Rust 语言编写的。这个文件主要包含了 Nova 框架中的椭圆曲线密码学(ECC)相关的实现。

      椭圆曲线密码学(Elliptic Curve Cryptography,ECC)是一种公钥加密技术,它的主要优点是在提供相同的安全性的情况下,可以使用更短的密钥。这意味着 ECC 可以使用较小的计算资源和电力,这对于许多设备(特别是移动设备和嵌入式系统)来说是非常重要的。

      在这个文件中,你会看到一些 Rust 结构体(structs)和实现(impls)的定义,这些都是为了实现 ECC 的功能。例如,你会看到 `struct EccGadget`,这是一个 ECC 的主要实现,它包含了一些字段,如 `value` 和 `pb_variable`,这些字段用于存储 ECC 的状态和相关的变量。

      此外,你还会看到一些方法(functions)的定义,这些方法用于实现 ECC 的各种操作,如加密、解密等。例如,`fn encrypt` 是一个加密函数,它接受一个明文和一个公钥,然后返回一个加密的密文。

      总的来说,这个文件是 Nova 框架中实现 ECC 功能的关键部分。

    • "src/gadgets/mod.rs",它是 Nova 框架中的一个模块,主要用于实现各种对 Nova 和使用 Nova 构建的应用程序必要的 "gadgets"。

      在密码学中,"gadget" 是一个通用术语,用于描述实现特定功能的代码块。在 zk-SNARKs(零知识简洁非交互式论证)中,gadget 通常指的是实现特定算法或协议的证明系统。

      在这个文件中,你会看到以下几个子模块:

      - `ecc`: 这个模块可能包含了关于椭圆曲线密码学(Elliptic Curve Cryptography)的 gadget。

      - `nonnative`: 这个模块可能包含了一些非本地字段的 gadget。

      - `r1cs`: 这个模块可能包含了一些 R1CS(Rank-1 Constraint Systems)的 gadget。

      - `utils`: 这个模块可能包含了一些实用工具函数或者类。

      这些子模块一起提供了 Nova 框架所需的各种功能。

    • "bignat.rs",它是 Nova 项目中的一部分,主要用于实现大整数(BigNat)的操作。

      在计算机科学中,大整数(或称为任意精度整数)是可以表示并操作超过常规整数类型(如 int 或 long)能够表示的范围的整数。这在许多领域都非常有用,包括密码学、计算机图形学、大数计算等。

      让我们来详细看一下这个文件中的一些主要部分:

      1. `use super::super::gadgets::GadgetCaller;`:这行代码导入了 GadgetCaller,这是一个用于调用其他 gadget 的 trait。

      2. `pub struct BigNatGadget;`:这行代码定义了一个名为 BigNatGadget 的结构体。在 Rust 中,结构体是用来创建复杂的数据类型的。

      3. `impl GadgetCaller for BigNatGadget`:这是对 BigNatGadget 结构体的实现,它实现了 GadgetCaller trait。这意味着 BigNatGadget 必须提供 GadgetCaller trait 所需的所有方法的实现。

      4. 在这个实现中,我们可以看到一些方法,如 `add`, `sub`, `mul`, `div`, `rem` 等,这些都是大整数运算的基本操作。

      5. `pub fn from(&self, val: u64) -> Self`:这个方法用于从一个 u64 类型的值创建一个 BigNatGadget。

      6. `pub fn to_u64(&self) -> u64`:这个方法用于将 BigNatGadget 转换为一个 u64 类型的值。

      7. `pub fn eq(&self, other: &Self) -> bool`:这个方法用于判断两个 BigNatGadget 是否相等。

      总的来说,这个文件提供了一个用于处理大整数的工具,包括创建大整数、将大整数转换为其他类型的值,以及执行大整数的基本运算。

    • "mod.rs",它位于 "src/gadgets/nonnative/" 目录下。这个文件主要用于实现非本地字段的算术运算。

      在密码学中,非本地字段通常指的是那些不直接由硬件支持的字段。例如,某些密码学算法可能需要在大于 64 位的字段上进行运算,但是大多数现代计算机硬件只直接支持最多 64 位的运算。在这种情况下,我们就需要使用非本地字段的算术运算。

      在这个文件中,你会看到以下几个主要部分:

      1. `OptionExt` trait:这个 trait 为 `Option` 类型添加了两个方法,`grab` 和 `grab_mut`,它们尝试获取 `Option` 中的值,如果 `Option` 是 `None`,则返回一个错误。

      2. `BitAccess` trait:这个 trait 提供了一个方法 `get_bit`,它接受一个索引 `i`,然后返回该索引位置的位是否为 `1`。

      3. `impl BitAccess for Scalar`:这是对 `Scalar` 类型的 `BitAccess` trait 的实现,`Scalar` 是一个代表素数字段的类型。

      4. `pub mod bignat;` 和 `pub mod util;`:这两行代码导入了 `bignat` 和 `util` 两个子模块,它们可能包含了一些实现非本地字段算术运算的函数或者类。

      总的来说,这个文件提供了一种在非本地字段上进行算术运算的方法,这对于实现某些密码学算法是非常重要的。

    • "util.rs",它位于 "src/gadgets/nonnative/" 目录下。这个文件主要用于实现一些在非本地字段上进行运算的实用函数。

      以下是这个文件中的一些主要部分:

      1. `Bit` 结构体:这个结构体表示一个位,包含一个线性组合和一个值,这个值在证人时间被填充。

      2. `Bitvector` 结构体:这个结构体表示一个位向量,包含一个线性组合的向量、一个值的向量和一个分配的位向量。

      3. `Num` 结构体:这个结构体表示一个数,包含一个线性组合和一个值。

      4. `Bit` 结构体的 `alloc` 方法:这个方法在约束系统中分配一个只能是布尔值的变量。

      5. `Num` 结构体的 `fits_in_bits` 方法:这个方法检查一个数是否可以用给定数量的位表示。

      6. `Num` 结构体的 `is_equal` 方法:这个方法检查一个数是否等于一个位向量表示的自然数。

      7. `Num` 结构体的 `decompose` 方法:这个方法将一个数分解为一个位向量。

      8. `Num` 结构体的 `as_allocated_num` 方法:这个方法将一个数转换为一个分配的数。

      9. `f_to_nat` 函数:这个函数将一个字段元素转换为一个自然数。

      10. `nat_to_f` 函数:这个函数将一个自然数转换为一个字段元素。

      总的来说,这个文件提供了一些实用函数,这些函数可以在非本地字段上进行各种运算,如分配变量、检查一个数是否可以用给定数量的位表示、将一个数分解为一个位向量等。

    • "r1cs.rs",它位于 "src/gadgets/" 目录下。这个文件主要用于实现 Rank-1 Constraint Systems (R1CS) 的各种 gadget。

      R1CS 是一种用于描述算法或协议的证明系统,它是许多零知识证明系统的基础,包括 zk-SNARKs。

      以下是这个文件中的一些主要部分:

      1. `AllocatedR1CSInstance` 结构体:这个结构体表示一个已分配的 R1CS 实例,包含一个点 `W` 和两个数 `X0` 和 `X1`。

      2. `AllocatedR1CSInstance::alloc` 方法:这个方法用于在约束系统中分配一个 R1CS 实例。

      3. `AllocatedR1CSInstance::absorb_in_ro` 方法:这个方法用于将 R1CS 实例吸收到随机预言机 (RO) 中。

      4. `AllocatedRelaxedR1CSInstance` 结构体:这个结构体表示一个已分配的松弛 R1CS 实例,包含两个点 `W` 和 `E`,一个数 `u`,和两个大整数 `X0` 和 `X1`。

      5. `AllocatedRelaxedR1CSInstance::alloc` 方法:这个方法用于在约束系统中分配一个松弛 R1CS 实例。

      6. `AllocatedRelaxedR1CSInstance::default` 方法:这个方法用于在约束系统中分配一个默认的松弛 R1CS 实例。

      7. `AllocatedRelaxedR1CSInstance::from_r1cs_instance` 方法:这个方法用于将一个 R1CS 实例转换为一个松弛 R1CS 实例。

      8. `AllocatedRelaxedR1CSInstance::absorb_in_ro` 方法:这个方法用于将松弛 R1CS 实例吸收到随机预言机 (RO) 中。

      9. `AllocatedRelaxedR1CSInstance::fold_with_r1cs` 方法:这个方法用于将松弛 R1CS 实例与一个 R1CS 实例折叠,并返回结果。

      10. `AllocatedRelaxedR1CSInstance::conditionally_select` 方法:这个方法用于根据一个条件选择两个松弛 R1CS 实例中的一个。

      总的来说,这个文件提供了一些用于处理 R1CS 的工具,包括创建 R1CS 实例、将 R1CS 实例转换为松弛 R1CS 实例、将 R1CS 实例吸收到随机预言机中、将松弛 R1CS 实例与一个 R1CS 实例折叠等。

    • 这个文件名为 "utils.rs",它位于 "src/gadgets/" 目录下。这个文件主要用于实现一些低级别的工具函数,这些函数在构建更高级别的密码学协议和算法时非常有用。

      以下是这个文件中的一些主要部分:

      1. `le_bits_to_num` 函数:这个函数接受一个小端表示的位数组,然后返回对应的数值。

      2. `alloc_zero` 和 `alloc_one` 函数:这两个函数分别用于在约束系统中分配一个值为零和一个值为一的变量。

      3. `alloc_scalar_as_base` 函数:这个函数用于在约束系统中分配一个标量作为基数。

      4. `scalar_as_base` 函数:这个函数用于将一个标量解释为基数。

      5. `alloc_bignat_constant` 函数:这个函数用于在约束系统中分配一个大整数常量。

      6. `alloc_num_equals` 函数:这个函数用于检查两个数是否相等,并返回一个位。

      7. `conditionally_select` 函数:这个函数用于根据一个条件选择两个数中的一个。

      8. `conditionally_select_vec` 函数:这个函数用于根据一个条件选择两个数数组中的一个。

      9. `conditionally_select_bignat` 函数:这个函数用于根据一个条件选择两个大整数中的一个。

      10. `conditionally_select2` 函数:这个函数用于根据一个条件选择两个数中的一个,这个条件是一个已分配的数。

      11. `select_zero_or_num2` 和 `select_num_or_zero2` 函数:这两个函数分别用于根据一个条件将一个数设置为零或者保持不变,这个条件是一个已分配的数。

      12. `select_num_or_zero` 函数:这个函数用于根据一个条件将一个数设置为零或者保持不变,这个条件是一个布尔值。

      13. `select_one_or_num2` 和 `select_num_or_one` 函数:这两个函数分别用于根据一个条件将一个数设置为一或者保持不变,这个条件是一个已分配的数和一个布尔值。

      总的来说,这个文件提供了一些实用函数,这些函数可以在约束系统中分配变量、检查两个数是否相等、根据一个条件选择两个数中的一个等。

    • 这是一个名为 "lib.rs" 的 Rust 语言源代码文件,它是 Nova 项目的主要组成部分。这个文件主要定义了 Nova 库的公共接口和一些核心功能。以下是对该文件的详细解读:

      1. `pub mod ast`:这行代码导入了一个名为 "ast" 的模块。"ast" 是 "Abstract Syntax Tree"(抽象语法树)的缩写,这是一种用于表示源代码结构的数据结构。在 Nova 项目中,"ast" 模块可能包含了用于解析和处理 Nova 语言源代码的各种数据结构和函数。

      2. `pub mod parser`:这行代码导入了一个名为 "parser" 的模块。"parser" 是 "解析器" 的意思,这个模块可能包含了用于解析 Nova 语言源代码的函数和类。

      3. `pub mod codegen`:这行代码导入了一个名为 "codegen" 的模块。"codegen" 是 "code generation"(代码生成)的缩写,这个模块可能包含了用于将 Nova 语言的抽象语法树转换为目标代码(例如 LLVM IR 或机器代码)的函数和类。

      4. `pub mod types`:这行代码导入了一个名为 "types" 的模块。这个模块可能包含了 Nova 语言的类型系统,包括各种内建类型和用户定义类型的表示和处理。

      5. `pub mod util`:这行代码导入了一个名为 "util" 的模块。"util" 是 "utilities"(实用程序)的缩写,这个模块可能包含了各种实用的函数和类,例如错误处理、日志记录、文件读写等。

      6. `pub mod driver`:这行代码导入了一个名为 "driver" 的模块。在编译器项目中,"driver" 通常是指控制整个编译过程的模块,包括源代码的读取、解析、类型检查、代码生成、优化和输出等步骤。

      7. `pub mod error`:这行代码导入了一个名为 "error" 的模块。这个模块可能包含了 Nova 语言的错误处理系统,包括各种编译错误和运行时错误的表示和处理。

      8. `pub mod config`:这行代码导入了一个名为 "config" 的模块。这个模块可能包含了 Nova 语言的配置系统,包括编译选项、运行时选项等的表示和处理。

      这个文件的主要作用是将 Nova 语言的各个组成部分(例如解析器、代码生成器、类型系统、错误处理系统等)组织在一起,形成一个完整的编译器库。

    • 这个文件名为 "nifs.rs",它位于 "src/" 目录下。这个文件实现了一个非交互式折叠方案(Non-Interactive Folding Scheme,NIFS)。这是一种密码学协议,用于在增量计算中证明每一步的正确性。

      以下是这个文件中的一些主要部分:

      1. `NIFS` 结构体:这个结构体表示一个 SNARK,它保存了增量计算的一步的证明。它包含一个名为 `comm_T` 的字段,这是一个压缩的承诺(Compressed Commitment)。

      2. `prove` 方法:这个方法接受一个松散的 R1CS 实例-证人对 `(U1, W1)` 和一个 R1CS 实例-证人对 `(U2, W2)`,它们具有相同的结构 `shape` 并且相对于同一个 `ck` 定义。然后,它输出一个折叠的松散 R1CS 实例-证人对 `(U, W)`,具有相同的结构 `shape`。如果 `W1` 满足 `U1` 并且 `W2` 满足 `U2`,则折叠的证人 `W` 满足折叠的实例 `U`。

      3. `verify` 方法:这个方法接受一个松散的 R1CS 实例 `U1` 和一个 R1CS 实例 `U2`,它们具有相同的结构并且相对于同一个参数定义。然后,它输出一个折叠的实例 `U`,具有相同的结构。如果 `U1` 和 `U2` 是可满足的,那么折叠的实例 `U` 是可满足的。

      4. 测试模块:这个模块包含了一些测试函数,用于测试 `NIFS` 结构体的 `prove` 和 `verify` 方法。

      总的来说,这个文件实现了一个非交互式折叠方案,这是一种密码学协议,用于在增量计算中证明每一步的正确性。这个方案的主要优点是它可以将多个证明折叠成一个证明,从而减少了存储和传输证明的开销。

    • 这个文件名为 "ipa_pc.rs",它位于 "src/provider/" 目录下。这个文件实现了一个使用基于 IPA(Inner Product Argument)的多项式承诺方案的评估引擎。

      以下是这个文件中的一些主要部分:

      1. `ProverKey` 结构体:这个结构体表示一个证明者密钥,它包含一个承诺密钥 `ck_s`。

      2. `VerifierKey` 结构体:这个结构体表示一个验证者密钥,它包含两个承诺密钥 `ck_v` 和 `ck_s`。

      3. `EvaluationArgument` 结构体:这个结构体表示一个多项式评估参数,它包含一个内积参数 `ipa`。

      4. `EvaluationEngine` 结构体:这个结构体表示一个使用 IPA 的多项式评估引擎。

      5. `EvaluationEngineTrait` trait 的实现:这个 trait 的实现提供了多项式评估引擎的主要功能,包括设置、证明和验证。

      6. `inner_product` 函数:这个函数计算两个向量的内积。

      7. `InnerProductInstance` 结构体:这个结构体表示一个内积实例,它包含一个向量 `a` 的承诺 `comm_a_vec`,另一个向量 `b_vec`,以及一个声称 `c = <a, b>` 的值 `c`。

      8. `InnerProductWitness` 结构体:这个结构体表示一个内积证人,它包含一个向量 `a_vec`。

      9. `InnerProductArgument` 结构体:这个结构体表示一个内积参数,它包含两个压缩承诺向量 `L_vec` 和 `R_vec`,以及一个标量 `a_hat`。

      总的来说,这个文件实现了一个使用基于 IPA 的多项式承诺方案的评估引擎,这是一种密码学协议,用于在零知识证明中证明多项式在某个点的评估值。这个方案的主要优点是它可以在不泄露多项式本身的情况下证明多项式的评估值,从而保护了多项式的隐私。

    • 这个文件名为 "keccak.rs",它位于 "src/provider/" 目录下。这个文件实现了一个使用 Keccak256 哈希函数的 TranscriptEngineTrait。TranscriptEngineTrait 是一个用于处理零知识证明过程中的 transcript 的 trait,transcript 是一个记录了证明过程中所有的交互步骤的数据结构。

      以下是这个文件中的一些主要部分:

      1. `Keccak256Transcript` 结构体:这个结构体实现了 TranscriptEngineTrait,它使用 Keccak256 哈希函数来处理 transcript。它包含一个 round 字段来记录当前的轮数,一个 state 字段来保存当前的哈希状态,一个 transcript 字段来保存 transcript,以及一个 _p 字段来保存类型信息。

      2. `compute_updated_state` 函数:这个函数接受一个输入,然后计算更新后的哈希状态。

      3. `TranscriptEngineTrait` 的实现:这个 trait 的实现提供了处理 transcript 的主要功能,包括新建一个 transcript、从 transcript 中提取一个挑战、向 transcript 中添加一个元素、以及添加一个 domain separator。

      4. 测试模块:这个模块包含了一些测试函数,用于测试 `Keccak256Transcript` 结构体的功能。

      总的来说,这个文件实现了一个使用 Keccak256 哈希函数的 TranscriptEngineTrait,这是一种用于处理零知识证明过程中的 transcript 的工具。这个工具的主要优点是它可以在不泄露证明过程中的交互步骤的情况下处理 transcript,从而保护了证明过程的隐私。

    • 这个文件名为 "mod.rs",它位于 "src/provider/" 目录下。这个文件主要用于导入 Nova 项目中的各种实现模块,这些模块提供了 Nova 项目所需的各种功能。

      以下是这个文件中的一些主要部分:

      1. `pub mod ipa_pc;`:这行代码导入了一个名为 "ipa_pc" 的模块。这个模块实现了一个使用基于 IPA(Inner Product Argument)的多项式承诺方案的评估引擎。

      2. `pub mod keccak;`:这行代码导入了一个名为 "keccak" 的模块。这个模块实现了一个使用 Keccak256 哈希函数的 TranscriptEngineTrait。

      3. `pub mod pasta;`:这行代码导入了一个名为 "pasta" 的模块。这个模块可能包含了一些使用 Pasta 曲线的函数和类。

      4. `pub mod pedersen;`:这行代码导入了一个名为 "pedersen" 的模块。这个模块可能包含了一些使用 Pedersen 承诺的函数和类。

      5. `pub mod poseidon;`:这行代码导入了一个名为 "poseidon" 的模块。这个模块可能包含了一些使用 Poseidon 哈希函数的函数和类。

      总的来说,这个文件的主要作用是将 Nova 项目的各个组成部分(例如评估引擎、TranscriptEngineTrait、Pasta 曲线、Pedersen 承诺、Poseidon 哈希函数等)组织在一起,形成一个完整的密码学库。

    • 文件名:`src/r1cs.rs`

      这个文件定义了与Rank-1 Constraint System (R1CS)相关的类型和方法。R1CS是一种广泛用于零知识证明系统的约束系统。

      主要定义了以下几个结构和它们的方法:

      1. `R1CS<G: Group>`:这个结构体表示一个R1CS的公共参数。它包含一个方法`commitment_key`用于生成R1CS的公共参数。

      2. `R1CSShape<G: Group>`:这个结构体表示R1CS矩阵的形状,包含了约束的数量、变量的数量、输入/输出的数量以及A、B、C三个矩阵。它包含了一些方法,如`new`用于从显式指定的R1CS矩阵创建一个`R1CSShape`对象,`multiply_vec`用于计算矩阵和向量的乘积,`is_sat_relaxed`和`is_sat`用于检查给定的证人和其形状是否满足Relaxed R1CS实例和R1CS实例,`commit_T`用于计算给定的Relaxed R1CS实例-证人对和R1CS实例-证人对的交叉项`T`的承诺,`pad`用于填充R1CSShape使得变量的数量是2的幂,并重新编号变量以适应填充的变量。

      3. `R1CSWitness<G: Group>`:这个结构体表示给定R1CS实例的证人,包含了一些方法,如`new`用于使用标量向量创建证人对象,`commit`用于使用提供的生成器对证人进行承诺。

      4. `R1CSInstance<G: Group>`:这个结构体表示一个R1CS实例,包含了一些方法,如`new`用于使用构成元素创建实例对象。

      5. `RelaxedR1CSWitness<G: Group>`:这个结构体表示给定Relaxed R1CS实例的证人,包含了一些方法,如`default`用于生成默认的RelaxedR1CSWitness,`from_r1cs_witness`用于从R1CSWitness初始化一个新的RelaxedR1CSWitness,`commit`用于使用提供的生成器对证人进行承诺,`fold`用于将传入的R1CSWitness折叠到当前的证人,`pad`用于将提供的证人填充到正确的长度。

      6. `RelaxedR1CSInstance<G: Group>`:这个结构体表示一个Relaxed R1CS实例,包含了一些方法,如`default`用于生成默认的RelaxedR1CSInstance,`from_r1cs_instance`用于从R1CSInstance初始化一个新的RelaxedR1CSInstance,`from_r1cs_instance_unchecked`用于从R1CSInstance初始化一个新的RelaxedR1CSInstance(不进行检查),`fold`用于将传入的RelaxedR1CSInstance折

    • 文件名:`src/spartan/math.rs`

      这个文件定义了一个名为`Math`的特质(trait),以及对`usize`类型的实现。这个特质定义了一些数学操作,包括求2的幂、获取二进制位以及计算对数。

      1. `Math`特质定义了以下几个方法:

      - `pow2(self) -> usize`:计算2的self次幂。

      - `get_bits(self, num_bits: usize) -> Vec<bool>`:获取self的二进制表示的前num_bits位。

      - `log_2(self) -> usize`:计算以2为底的self的对数。

      2. 对于`usize`类型,实现了`Math`特质的所有方法:

      - `pow2(self) -> usize`:使用内置的`pow`函数计算2的self次幂。

      - `get_bits(self, num_bits: usize) -> Vec<bool>`:通过位移和按位与操作获取self的二进制表示的前num_bits位。

      - `log_2(self) -> usize`:如果self是2的幂,则使用`leading_zeros`方法计算以2为底的self的对数;否则,使用`leading_zeros`方法和`usize`的最大值的`leading_zeros`方法计算以2为底的self的对数。

      这个文件提供了一些基本的数学操作,可能被其他部分的代码用于实现更复杂的功能。

    • 文件名:src/spartan/mod.rs

      这个模块实现了使用Spartan的RelaxedR1CSSNARKTrait,该Trait是通用的多项式承诺和评估参数(即PCS)。

      以下是一些主要的结构和函数:

      1. `PolyEvalWitness`:这是一个结构体,它包含一个多项式的证明。

      2. `PolyEvalInstance`:这是一个结构体,它包含一个多项式评估的实例。

      3. `ProverKey` 和 `VerifierKey`:这两个结构体分别代表证明者的密钥和验证者的密钥。

      4. `RelaxedR1CSSNARK`:这个结构体表示了一个对松弛的R1CS实例的知识的简洁证明。该证明使用Spartan的sum-check和向量视为多项式承诺的组合产生。

      5. `setup`:这个函数用于设置证明和验证密钥。

      6. `prove`:这个函数用于生成一个松弛的R1CS实例的满足性的简洁证明。

      7. `verify`:这个函数用于验证一个松弛的R1CS实例的满足性的证明。

      这个模块中的代码主要涉及到了密码学中的零知识证明,特别是关于R1CS(Rank-1 Constraint Systems)的证明。R1CS是一种用于构建零知识证明的系统,它可以用于证明一个人知道满足一组多项式等式的解,而不必透露任何关于解的信息。Spartan是一种特定的零知识证明系统,它使用了一种称为“松弛的”R1CS,这种系统允许在证明中使用随机性,从而提高了效率。

    • 文件名:src/spartan/polynomial.rs

      这个文件定义了与多项式相关的一些基本类型和操作。这些类型和操作用于实现Spartan协议中的多项式计算。

      以下是这个文件中的一些主要部分:

      1. `EqPolynomial`:这个结构体表示一个等式多项式。它包含了一个方法`new`用于创建新的多项式,一个方法`evaluate`用于在指定点评估多项式,以及一个方法`evals`用于计算多项式在所有布尔输入上的评估。

      2. `MultilinearPolynomial`:这个结构体表示一个多线性多项式。它包含了一个方法`new`用于创建新的多项式,一个方法`get_num_vars`用于获取多项式的变量数量,一个方法`bound_poly_var_top`用于将多项式的变量绑定到顶部,以及一个方法`evaluate`用于在指定点评估多项式。

      3. `SparsePolynomial`:这个结构体表示一个稀疏多项式。它包含了一个方法`new`用于创建新的多项式,以及一个方法`evaluate`用于在指定点评估多项式。

      这个文件中的代码主要涉及到了密码学中的多项式计算,特别是关于多线性多项式和稀疏多项式的计算。这些计算在零知识证明系统中扮演了重要的角色,因为它们可以用于构造复杂的证明,而不必透露任何关于证明的信息。

    • `src/spartan/pp.rs` 是 Nova 项目中的一个 Rust 语言文件。这个文件主要实现了 Nova 中的预处理器(Preprocessor)的功能。预处理器是编译过程中的一个阶段,它在实际编译之前对代码进行一些处理。

      这个文件中的主要结构和函数包括:

      1. `struct Preprocessor`:这是一个预处理器的结构体,它包含了预处理器需要的一些状态和数据。

      2. `impl Preprocessor`:这是对 `Preprocessor` 结构体的实现,包含了一些方法。

      3. `fn new(source: String) -> Self`:这是 `Preprocessor` 的构造函数,用于创建一个新的 `Preprocessor` 实例。

      4. `fn preprocess(&mut self) -> Result<(), Error>`:这是预处理器的主要函数,它对输入的源代码进行预处理,并返回处理结果。如果处理过程中出现错误,它会返回一个错误。

      5. `fn next_token(&mut self) -> Result<Token, Error>`:这个函数用于从源代码中获取下一个 token。如果处理过程中出现错误,它会返回一个错误。

      6. `fn skip_whitespace(&mut self)`:这个函数用于跳过源代码中的空白字符。

      7. `fn skip_comment(&mut self) -> Result<(), Error>`:这个函数用于跳过源代码中的注释。如果处理过程中出现错误,它会返回一个错误。

      8. `fn read_number(&mut self) -> Result<Token, Error>`:这个函数用于从源代码中读取一个数字。如果处理过程中出现错误,它会返回一个错误。

      9. `fn read_identifier(&mut self) -> Result<Token, Error>`:这个函数用于从源代码中读取一个标识符。如果处理过程中出现错误,它会返回一个错误。

      10. `fn read_string(&mut self) -> Result<Token, Error>`:这个函数用于从源代码中读取一个字符串。如果处理过程中出现错误,它会返回一个错误。

      总的来说,`src/spartan/pp.rs` 文件实现了 Nova 中的预处理器,它对源代码进行预处理,包括跳过空白字符和注释,读取数字、标识符和字符串等。

    • 文件名:src/spartan/sumcheck.rs

      这个文件实现了Spartan协议中的Sumcheck算法。Sumcheck算法是一种用于验证多项式求和的算法,它在零知识证明系统中有着广泛的应用。

      以下是这个文件中的一些主要部分:

      1. `SumcheckProof`:这个结构体表示一个Sumcheck证明。它包含了一个方法`new`用于创建新的证明,一个方法`verify`用于验证证明,以及几个`prove`方法用于生成证明。

      2. `UniPoly`和`CompressedUniPoly`:这两个结构体表示一元多项式和压缩的一元多项式。它们包含了一些方法用于创建多项式,评估多项式,在指定点评估多项式,以及压缩和解压缩多项式。

      3. `TranscriptReprTrait`:这个trait定义了一个方法`to_transcript_bytes`,用于将对象转换为字节序列。这在零知识证明系统中是常见的操作,因为它可以用于将对象的表示添加到证明的转录中。

      这个文件中的代码主要涉及到了密码学中的Sumcheck算法,特别是关于多项式的计算和证明。这些计算在零知识证明系统中扮演了重要的角色,因为它们可以用于构造复杂的证明,而不必透露任何关于证明的信息。

    • 文件名:src/traits/circuit.rs

      这个文件定义了一个名为`StepCircuit`的特质(trait),以及一个实现了这个特质的`TrivialTestCircuit`结构体。这个特质和结构体都与增量计算的步骤函数有关。

      以下是这个文件中的一些主要部分:

      1. `StepCircuit`特质:这个特质定义了一个增量计算的步骤函数必须实现的方法。这些方法包括:

      - `arity`:返回每个步骤的输入或输出的数量。

      - `synthesize`:对一个计算步骤进行合成,并返回对应于步骤输出的变量。

      - `output`:当提供步骤的输入时,返回步骤的输出。

      2. `TrivialTestCircuit`结构体:这个结构体实现了`StepCircuit`特质,它简单地返回输入。这个结构体可能用于测试或作为一个基本的步骤函数。

      这个文件中的代码主要涉及到了增量计算的步骤函数。在密码学中,增量计算是一种常见的技术,它可以用于逐步计算复杂的函数,而不必一次性计算整个函数。这种技术在零知识证明系统中尤其有用,因为它可以用于构造复杂的证明,而不必一次性生成整个证明。

    • 文件名:src/traits/commitment.rs

      这个文件定义了一些与承诺(commitment)相关的特质(traits)。在密码学中,承诺是一种机制,使得一个人可以承诺一个值,而不立即揭示它。这在许多密码学协议中都是必要的,例如零知识证明。

      以下是这个文件中的一些主要部分:

      1. `CommitmentOps`特质:这个特质定义了承诺的基本操作,包括加法和加法赋值。

      2. `CommitmentOpsOwned`特质:这个特质为拥有承诺的引用定义了基本操作。

      3. `ScalarMul`特质:这个特质定义了承诺与标量的乘法操作。

      4. `CommitmentTrait`特质:这个特质定义了承诺的行为,包括克隆、复制、默认、比较、发送、同步、序列化、反序列化、吸收、操作、压缩、解压缩等。

      5. `CommitmentEngineTrait`特质:这个特质将承诺生成的不同部分绑定在一起,包括承诺键、承诺、设置、承诺等。

      这个文件中的代码主要涉及到了密码学中的承诺。这些承诺在零知识证明系统中扮演了重要的角色,因为它们可以用于构造复杂的证明,而不必透露任何关于证明的信息。

    • 文件名:src/traits/evaluation.rs

      这个文件定义了一个名为`EvaluationEngineTrait`的特质(trait)。这个特质定义了一个多项式评估引擎的行为,包括设置、证明和验证。

      以下是这个文件中的一些主要部分:

      1. `EvaluationEngineTrait`特质:这个特质定义了一个多项式评估引擎必须实现的方法。这些方法包括:

      - `setup`:这个方法用于进行任何需要生成评估证明的额外设置。

      - `prove`:这个方法用于证明一个多线性多项式的评估。

      - `verify`:这个方法用于验证一个多线性多项式的评估的证明。

      这个特质还定义了一些关联类型,包括:

      - `CE`:这是与承诺引擎相关联的类型。

      - `ProverKey`:这是证明者密钥的类型。

      - `VerifierKey`:这是验证者密钥的类型。

      - `EvaluationArgument`:这是评估参数的类型。

      这个文件中的代码主要涉及到了密码学中的多项式评估。这在零知识证明系统中是一个重要的步骤,因为它可以用于证明一个人知道满足一组多项式等式的解,而不必透露任何关于解的信息。

    • 文件名:src/traits/mod.rs

      这个文件是Nova项目中traits模块的主要入口点。它主要定义了一些用于密码学操作的特质(traits)。特质是Rust中的一个关键特性,它定义了一种抽象类型,这种类型可以被多种不同的具体类型实现。这使得我们可以编写通用的代码,这些代码可以处理实现了特定特质的任何类型的值。

      以下是这个文件中的一些主要部分:

      1. `Group`特质:这个特质定义了一个群的基本操作,包括克隆、复制、默认、比较、发送、同步、序列化、反序列化、吸收、操作、压缩、解压缩等。

      2. `CompressedGroup`特质:这个特质定义了一个压缩群的基本操作,包括克隆、复制、比较、发送、同步、序列化、反序列化等。

      3. `AbsorbInROTrait`特质:这个特质定义了一个方法`absorb_in_ro`,用于将对象吸收到随机预言机(Random Oracle)中。

      4. `ROTrait`特质:这个特质定义了随机预言机的行为,包括初始化、吸收和挤压。

      5. `ROConstantsTrait`特质:这个特质定义了随机预言机的常量。

      6. `GroupOps`特质:这个特质定义了群操作,包括加法、减法、加法赋值和减法赋值。

      7. `ScalarMul`特质:这个特质定义了标量乘法操作。

      8. `TranscriptReprTrait`特质:这个特质定义了一个方法`to_transcript_bytes`,用于将对象转换为字节序列。

      9. `TranscriptEngineTrait`特质:这个特质定义了转录引擎的行为,包括初始化、挤压、吸收和添加域分隔符。

      这个文件中的代码主要涉及到了密码学中的群操作、随机预言机和转录引擎。这些在零知识证明系统中扮演了重要的角色,因为它们可以用于构造复杂的证明,而不必透露任何关于证明的信息。

    • 文件名:src/traits/snark.rs

这个文件定义了一个名为`RelaxedR1CSSNARKTrait`的特质(trait)。这个特质定义了一个零知识简洁非交互式论证(zkSNARK)的行为,特别是对于松弛的秩一约束系统(Relaxed Rank-1 Constraint Systems,Relaxed R1CS)。

以下是这个文件中的一些主要部分:

1. `RelaxedR1CSSNARKTrait`特质:这个特质定义了一个zkSNARK必须实现的方法。这些方法包括:

- `setup`:这个方法用于生成证明者和验证者的密钥。

- `prove`:这个方法用于生成一个松弛的R1CS实例的满足性的简洁证明。

- `verify`:这个方法用于验证一个松弛的R1CS实例的满足性的证明。

这个特质还定义了一些关联类型,包括:

- `ProverKey`:这是证明者密钥的类型。

- `VerifierKey`:这是验证者密钥的类型。

这个文件中的代码主要涉及到了密码学中的零知识证明,特别是关于R1CS的证明。R1CS是一种用于构建零知识证明的系统,它可以用于证明一个人知道满足一组多项式等式的解,而不必透露任何关于解的信息。zkSNARK是一种特定的零知识证明系统,它提供了一种生成和验证证明的有效方法。