技术探秘:在RISC Zero中验证FHE——RISC Zero应用的DevOps(2)

1. 引言

前序博客:

  • 技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)

技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1) 中,深入研究了RISC Zero中Fully Homomorphic Encryption(FHE)的bootstrapping步骤。基于此,本文专注于性能优化。

人们在对RISC Zero中应用做优化时,最重要的一点就是:

  • 专注于解决主要性能瓶颈问题

为此,首先需知道主要性能瓶颈在哪,因此:

  • 需profile 应用程序 每一部分 所贡献的 “ZK-proving”开销。

本文致力于通过RISC Zero上的理论和实验相结合来计算这种证明开销。

2. ZK proving开销贡献因子

从理论角度来说,RISC Zero中的“ZK-proving”开销,是以“cycles”来计量的——与CPU的cycles类似。与常规RISC-V CPU类似,RISC Zero中的cycles有2大来源:

  • 1)compute
  • 2)paging

2.1 compute开销

根据RISC Zero zkVM guest程序优化技巧 及其 与物理CPU的关键差异,当执行每个RISC-V指令时,都将引起RISC Zero内的某些CPU compute cycles:

  • one cycle指令有:LUI, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, SLLI, ADD, SUB, SLL, SLTU, MUL, MULH, MULHSU, MULHU。
  • two cycles指令有:XORI, ORI, ANDI, SRLI, SRAI, XOR, SRL, SRA, OR, AND, DIV, DIVU, REM, REMU。
  • 76 cycles per 64 bytes指令有:syscall for SHA-256。
  • 10 cycles指令有:syscall for 256-bit modular multiplication

大多数常规指令,如32位数字加法和乘法,均引发一个cycle。某些bitwise运算和触发运算,需要2个cycles。调用密码学accelerator的syscalls,需要更多cycles。这在本质上类似于现代CPU的SHA扩展,它添加了专门用于SHA256的指令,这些指令只需要几个cycles即可执行。

需注意,RISC Zero的cycle counts,是专门针对RISC Zero的。真实的RISC-V CPU芯片,大概率有不同的cycle count,因计算开销通常高于验证开销。未来的RISC Zero版本,每个指令也可能会有不同的cycle counts。

2.2 paging开销

由于paging,指令也可能引发non-compute cycles。paging也是ZK-proving开销的重要来源。

为理解RISC Zero中的paging开销,首先需了解现代CPU的数据访问原理,具体取决于待访问的数据在哪:

  • 1)待访问的数据在L1/L2 caches:可 以few cycles来访问该数据。
  • 2)待访问的数据在main memory:该数据访问具有数百cycles延迟。
  • 3)待访问的数据在external storage:
    • 首先需将该数据加载进main memory,该过程称为“paged-in”。在此期间,CPU需等待,“paged-in”需消耗数万个cycles,即使external storage是高端SSD。
    • 数据可能还需要从main memory “paged-out” 回该external storage。

称为“paged-in”和“paged-out”的原因在于,现代操作系统管理内存为,使得程序可访问“pages”。不同的操作系统,page size各不相同:

  • M2芯片的Mac Studio操作系统:每个page为16KB
  • RISC-V标准:每个page为4KB
  • RISC Zero:每个page更小,为1KB

RISC Zero中,程序可使用约192MB的空间,寻址范围从0x0400到0x0c000000。该空间切分为pages,每个page 1KB。这些pages由page tables索引,这些page tables需要约6.7MB的空间,page tables空间的起始地址为0x0d000000。与现代操作系统类似,RISC Zero的这些page tables是multi-level的,具体如下图所示,展示了RIS Zero中guest程序内存空间的Multi-level page tables:
在这里插入图片描述

在RISC Zero guest程序中,当某page被首次访问时,RISC Zero需要“zk-load”该page,使得其数据被置入ZK电路可使用的authenticated format。执行结束时,RISC Zero将“zk-unload”该page——会验证该page以 与ZK电路执行一致的方式被修改。

注意,为load或unload某page,RISC Zero需load或unload其page table。换句话说,整个程序的首个指令,将load 5个page:

  • 1)Page A:该指令所位于的page。
  • 2)Page B:对A的4-th level page table。
  • 3)Page C:对B的3-rd level page table。
  • 4)Page D:对C的2-nd level page table。
  • 5)Page E:top-level page table。

load或unload 每个page,将贡献约1094个cycles,除外情况为,top-level page table需要的更少——为754个cycles。可通过一个即将开放的工具来站看——整个执行过程中,load或unload的page数是如何变化的。如 Standalone VM and GDB stub for RISC Zero guest programs
——https://github.com/l2iterative/gdb0 中展示了相应的cycles输出:
在这里插入图片描述
对于运行在RISC Zero内的RISC-V程序,所需page cycles数量,取决于其执行过程中,需访问或修改的memory pages数量——也称为“memory footprint”。因此,优化时,有必要,避免在特定时间使用太多的内存。即,降低RISC Zero的peak memory。

3. From cycles to ZK proof

接下来,将解释cycles为何与ZK proving开销直接相关。这与RISC Zero的ZKP原理有关。RISC Zero的ZK电路文档不多,但代码是开源的。为理解其ZK proving 开销,首先理解RISC Zero的ZK。

简单来说,RISC Zero的证明系统可总结为:

  • 1)UltraPlonk(或Halo2):算术化中包含了定制gates、高degree多项式relations、很多witness wires,以及lookup arguments。
  • 2)FRI:使用FRI(fast Reed-Solomon interactive proof of proximity)来做polynomial evaluation和commitment。
  • 3)BabyBear:其计算基于BabyBear域(模 15 ∗ 2 27 + 1 15*2^{27}+1 15227+1)定义。在algebraic holographic证明时,使用了BabyBear的degree-four extension 域。每个BabyBear元素存储了一个字节的数据。换句话说,对于32位整数,其使用4个BabyBear域。
  • 4)Memory checking:尽管使用Merkle tree来authenticate pages,但main memory使用algebraic memory checking技术,使得每次对main memory的访问,仅引起一个常量的开销。
  • 5)SHARK from Groth16:STARK proof可进一步,在不泄露信息和trustless的方式下,通过Groth16压缩为very succinct SNARK proofs。预计RISC Zero将通过Privacy Scaling Exploration(PSE)的public ceremony平台——P0tion为其SNARK电路举行setup ceremony。

当前,有RISC Zero的完整电路——但是编译器(Zirgen)将其高级描述编译的电路,目前Zirgen编译器暂未公开。Zirgen相关视频资料有:

  • 2022年11月 cirgen: MLIR based compiler for zk-STARK circuit generation - Frank Laub (RISC Zero)
  • 2023年12月 (Almost) effortless formal verification of ZK-circuits by Julian Sutherland (Nethermind Security)

通过这些Zirgen相关视频,有助于理解:

  • 电路从何而来
  • 为何需要Cirgen编译器,来实现效率、硬件不可知以及形式化验证

同时需注意,以上RISC Zero证明系统仅为当前情况,未来可能会很不相同。随着递归的开发(之前称为continuations),RISC Zero将更像某种“Plonk”,人们可定制其特定应用的RISC Zero变种。

想像一下未来,RISC Zero将成为不同ZK协议的hub,像Minecraft有多达15万+ 社区项目的大量改装/插件生态系统。此时,RISC Zero提供通用支持和公共特性——以RISC-V和SHA256/BigInt syscalls形式,以及作为电路生成(Zirgen)、远程proof委托和压缩(Bonsai)、派生自Zirgen的不同高效后端实现(包括CPU、Metal和CUDA)的基础设施。
其它目标平台的可执行文件——如WASM,可通过just-in-time编译器(JIT)转换为RISC-V。所谓just-in-time编译器(JIT),与Solana的JIT for VM——rbpf类似。

如下图所示,展示了基于RISC Zero 的proof系统潜在未来:
在这里插入图片描述
之前,人们“Rolling Your Own Crypto”的2大挑战在于:

  • 1)挑战一:创建证明系统的技术和知识壁垒
  • 2)挑战二:安全性方面信息不足

Zirgen可解决挑战一,(Almost) effortless formal verification of ZK-circuits by Julian Sutherland (Nethermind Security) 中Nethermind已讨论了其如何利用形式化验证。外行人可以创建一个特定于应用程序的、经过正式验证的、社区构建的证明系统——可能在GPT的帮助下——并不遥远,这可能是ZK证明系统的真正去中心化,它消除了ZK的“精英主义”风险。

RISC Zero中,约有6个ZK电路,其编码了RISC-V程序执行的约束,每个ZK电路具有不同size:

  • 1)电路一:验证最多 32768 ( = 2 15 ) 32768 (=2^{15}) 32768(=215)个execution cycles。
  • 2)电路二:验证最多 65536 ( = 2 16 ) 65536 (=2^{16}) 65536(=216)个execution cycles。
  • 3)电路三:验证最多 131072 ( = 2 17 ) 131072 (=2^{17}) 131072(=217)个execution cycles。
  • 4)电路四:验证最多 262144 ( = 2 18 ) 262144 (=2^{18}) 262144(=218)个execution cycles。
  • 5)电路五:验证最多 524288 ( = 2 19 ) 524288 (=2^{19}) 524288(=219)个execution cycles。
  • 6)电路六:验证最多 1048576 ( = 2 20 ) 1048576 (=2^{20}) 1048576(=220)个execution cycles。

为给指定RISC-V程序选择电路,RISC Zero:

  • 首先运行该程序,并找出其完成需要多少个cycles。
  • 然后,选择可处理该cycle数量的最小电路。
    • 若程序执行需要多于 2 20 2^{20} 220个cycles,则整个执行将切分为segments,每个segment最多有 2 20 2^{20} 220个cycles。
    • segment proof会通过递归证明进行合并。

所有这些电路都遵循很简单的结构:

  • 1)Pre-loading sub-circuit:验证执行环境的初始化:【Pre-loading sub-circuit占用的空间,约为电路中的 N p r e = ∼ 1592 N_{pre}=\sim 1592 Npre=∼1592个cycles。】
    • 1.1)对byte formality checking和RAM的lookup tables做初始化。
    • 1.2)加载初始数据到RAM。
    • 1.3)最后且最重要的是,禁用pre-loading特权。这类似于x86-64的"real mode"——booters以特权模式运行,然后,移除特权,切换到实际操作系统的“protected mode”。
  • 2)Boby sub-circuit:对于后续的 ∼ 2 k − N p r e − N p o s t \sim 2^k-N_{pre} - N_{post} 2kNpreNpost cycles,验证每个cycle符合RISC-V CPU行为。
    • 为高度重复电路,每个cycle都相互等价。
    • page loading和page unloading均是在body sub-circuit中完成的。类似于操作系统需注意虚拟内存和分页管理。
  • 3)Post-loading sub-circuit:
    • 验证计算合理关闭
    • 关闭对byte formality checking和RAM的lookup tables。
    • Post-loading sub-circuit位于整个电路的末尾,其所需空间约为电路中的 N p o s t = ∼ 6 N_{post}=\sim 6 Npost=∼6 cycles。
    • 可将其想象为是机器关机。

RISC Zero代码库中,body sub-circuit的定义见:【展示了RISC Zero zkVM的body阶段的约束系统构建】
在这里插入图片描述
可以看出,body sub-circuit非常简单,其重复向底层ZK电路的body wire写 1 1 1,直到post-loading。

与其它FRI证明系统类似,由于FRI不关心电路的稀疏,证明生成开销完全取决于电路size,或更准确来说,取决于使用以上6种电路中的哪一个。

换句话说,cycles数,是影响FRI证明系统的唯一因素。

需注意的是,最近也有利用稀疏性的证明系统,如:

  • 1)a16z crypto的 Lasso+Jolt:其依赖于对,结构化的同态承诺方案的multilinear扩展,进行承诺
  • 2)Ulvetanna的 Binius:为硬件友好编码的binary证明系统。

二者都与RISC Zero相关。个人认为Lasso+Jolt和Binius是两棵独立的樱桃树,它们包含非常不同的互补技术,未来版本的RISC Zero或其社区变体可以进行樱桃采摘。

由于周期是cycles需要考虑的全部,现在将注意力转向可以帮助研究特定程序的cycles的工具。

4. 深入RISC Zero cycles的profiler

深入RISC Zero cycles的profiler,开源代码见:

  • https://github.com/l2iterative/profiler0

牢记,代码优化,首先应识别主要瓶颈。profile0工具可在代码中添加一些定时器:如“start_timer!”、 “stop_start_timer!” 和 “stop_timer!”,来验证RISC Zero中的FHE。

start_timer!("Total");

start_timer!("Load the bootstrapping key");

let bsk = black_box(unsafe {
    std::mem::transmute::<&u8, &[GgswCiphertext; 16]>(&BSK_BYTES[0])
});

stop_start_timer!("Load the ciphertext to be bootstrapped");

let c = black_box(unsafe {
    std::mem::transmute::<&u8, &LweCiphertext>(&C_BYTES[0])
});

stop_start_timer!("Perform trivial encryption and rotation");

let lut = black_box(GlweCiphertext::trivial_encrypt_lut_poly());
let mut c_prime = lut.clone();
c_prime.rotate_trivial((2 * N as u64) - c.body);

stop_start_timer!("Perform one step of the bootstrapping");

// set to one step
for i in 0..1 {
    start_timer!("Rotate");
    let rotated = c_prime.rotate(c.mask[i]);

    stop_start_timer!("Cmux");
    c_prime = cmux(&bsk[i], &c_prime, &rotated);

    stop_timer!();
}

stop_timer!();
stop_timer!();

从而可看出不同的代码片段所贡献的cycles数。该profiler会跟随guest程序的执行,并统计相应cycles。具体cycles统计结果见:

  • https://gist.github.com/weikengchen/59aabee17de6803927e594d9b56681ca

根据该profiler结果,总结如下:

  • 1)加载bootstrapping key:15条指令,3297个cycles。
  • 2)加载待bootstrapped密文:11条指令,11个cycles。
  • 3)执行trivial encryption和rotation:66096条指令,123982个cycles。
  • 4)执行bootstrapping 1024个步骤中的一步:151619979条指令,159597740个cycles:
    • rotate:55930条指令,75670个cycles。
    • cmux:151564031条指令,159520958个cycles。

总共有151686471条指令和159726565个cycles。

由此可看出,cmux占用了约99%的指令和约99%的cycles。注意,这仅是整个bootstrapping流程中的一个步骤,整个TFHE bootstrapping例子中有1024个类似的步骤。

接下来,自然是对cmux函数内部进行profile,并在TFHE库中添加如下profiling代码:

pub fn cmux(ctb: &GgswCiphertext, ct1: &GlweCiphertext, ct2: &GlweCiphertext) -> GlweCiphertext {
    start_timer!("subtract the ciphertext");
    let mut res = ct2.sub(ct1);
    stop_start_timer!("external product");
    res = ctb.external_product(&res);
    stop_start_timer!("add the result");
    res = res.add(ct1);
    stop_timer!();
    res
}

同时在external_product函数内添加profiling代码,external_product函数为性能关键所在。profiler0支持静态消息,也支持运行时生成的动态消息:

impl GgswCiphertext {
    /// Performs a product (GGSW x GLWE) -> GLWE.
    pub fn external_product(&self, ct: &GlweCiphertext) -> GlweCiphertext {
        start_timer!("apply g inverse");
        let g_inverse_ct = apply_g_inverse(ct);
        stop_start_timer!("multiply");

        let mut res = GlweCiphertext::default();
        for i in 0..(k + 1) * ELL {
            start_timer!(format!("i = {}", i));
            for j in 0..k {
                res.mask[j].add_assign(&g_inverse_ct[i].mul(&self.z_m_gt[i].mask[j]));
            }
            res.body
                .add_assign(&g_inverse_ct[i].mul(&self.z_m_gt[i].body));
            stop_timer!();
        }
        stop_timer!();
        res
    }
}

从而,cmux内部profile的数据信息为:【注意,添加profiler会注入少量指令,因此cmux cycle数会小幅增加。】

  • 1)subtract the ciphertext:38495条指令,46163个cycles。
  • 2)apply g inverse:79991条指令,167498个cycles。
  • 3)multiply with i = 0:37840587条指令,39875485个cycles。
  • 4)multiply with i = 1:37840584条指令,39759520个cycles。
  • 5)multiply with i = 2:37840584条指令,39802186个cycles。
  • 6)add the result:50816条指令,70525个cycles。

cmux中,总共有151565973条指令,159619414个cycles。
具体的profilier输出见:

  • https://gist.github.com/weikengchen/aca15c4c9243299824ed3c7635d9ce1e

其中会给出触发大量cycles的指令位置,如下位置出现额外频繁:

0x200d18, 0x200d20, 0x200d74, 0x200d78, 0x200d7c

即表示这些位置在loop内。这些地址相互很近,提示其可能是单个函数的汇编代码,且该函数被重复调用,贡献了大多数cycles。尽管该profiler未显示具体的指令,如额外频繁的0x200d74,对应指令“lw s10, t5, 0”,但需要具体上下文来理解指令行为。

拥有上下文的最佳方式为:

  • 返回具体场景

5. 使用GDB来做动态代码分析

之前提到,理解指令行为,需要具体的上下文,而拥有上下文的最佳方式为:

  • 返回具体场景

因此,需要工具来返回具体场景,并查看代码情况,为此引入了GDB工具gdb0来匹配RISC Zero:

  • https://github.com/l2iterative/gdb0

首先,以debug信息来编译程序,具体实现方式为:

  • 1)在“guest”目录下的Cargo.toml中,添加如下信息:【若不添加,Rust程序可能会慢得莫名其妙。添加后,即使在debug模式下,也可对程序做必要的优化。】
[profile.dev] 
opt-level = 3 

[profile.dev.build-override] 
opt-level = 3
  • 2)以环境变量来编译guest,以启用RISC Zero debug模式:
RISC0_BUILD_DEBUG=1 cargo run
  • 3)编译后的guest程序,为对RISC-V代码的标准的ELF文件,将其复制拷贝到gdb0目录。注意,一定拷贝“debug”目录下的已编译程序,而不是“release”目录下的。
cp ../vfhe0/target/riscv-guest/riscv32im-risc0-zkvm-elf/debug/method code
  • 4)再次运行profiler,因该函数可能在不同的位置。该profiler的新结果见:【可看出地址0x200db0, 0x200db4, 0x200db8, 0x200dbc处的指令经常会(因读/写)引起大量cycles。】
    • https://gist.github.com/weikengchen/b6ed8b2db86f555e45731ce3c92c4974
  • 5)启动GDB,基于以上profiler输出,在0x200db0设置软件断点,然后请求GDB继续执行,结果输出如下界面:【运行至贡献大量开销的loop】
    在这里插入图片描述
    从而可看出:
  • 为何0x200db0被频繁调用
  • 以及0x200db0属于哪里:在多项式乘法函数的inner loop中。

在设置断点时,GDB已尝试告知其对应src/ttfhe/poly.rs文件的Line 42。

接下来,看Rust源码是如何转换为RISC-V指令的。如,该inner loop中是做64位整数乘法和累加的,其看起来像:
在这里插入图片描述
此处,“bne”通常是指loop结束。

RISC Zero使用32位RISC-V,通过32位整数运算来模拟64位整数乘法。具体的32位整数运算由mul、mulhu、add等。这由Rust在编译过程完成,也可通过Godbolt来检查一致性。

6. 代码诊断

首先,正如VFHE库所否认的那样,当前执行negacyclic卷积的算法很native的,需要时间为 O ( n 2 ) O(n^2) O(n2)。换句话说,当对大小为1024的两个向量执行此操作时,代码将需要执行1048576个64位整数乘法,以及同时中间还有加载/保存数据的开销。

其他算法:

  • 首先,排除了NTT,因为模是2^64,l2ivresearch不想改变它(为了与Zama兼容),所以整数NTT没有太大希望。然而,可像Zama一样,在复数上使用浮点NTT。Zama之所以采用这种看起来很重的方法——使用浮点——原因很简单:浮点在现代CPU上一点也不贵,因为它(像整数乘法那样)只需要几个周期,比整数除法便宜得多。
    然而,RISC-V或RISC Zero的情况并非如此。官方文件提到,“浮点运算可能需要60-140个周期才能完成加法、减法、乘法和除法等基本运算。”在RISC Zero中,浮点运算的成本要高得多。基于与Zama Rand Hindi的对话,l2ivresearch得出结论,具有浮点的复数NTT可能不是ZK的解。
  • 剩下的选项是non-NTT efficient的多项式乘法(或者,更具体和准确地说,negacyclic卷积)。l2ivresearch计划使用Karatsuba算法,该算法使用分治方式来执行计算,从而产生subquadratic开销。
    这应该已经带来了两个数量级的加速。

另一个优化空间是找到特定于应用程序的优化机会。在TFHE中,当进行自举时,将GGSW密文乘以GLWE密文,关于这种乘法,一个非常有趣的事情是,GLWE将被分解为所有数字都很小的格式(即,应用逆G变换)。
这意味着实际上不必进行64位整数计算。在l2ivresearch的配置中,逆G变换的输出仅为8位。Karatsuba算法可以在这里和那里添加数字,因此只要Karatsubb的深度不太大,16位表示就应该是舒适的,以适应由于Karatsubo引起的中间结果。在32位数字中,可对其中两个数字进行编码,这将节省内存空间和加载/保存,并且可根据需要对其进行解码。

最后再回顾下64位整数乘法和累加 inner loop及其汇编代码:
在这里插入图片描述
inner loop中每次迭代具有约20条指令。若采用上面的压缩表示,可节约少量指令。然后剩余的指令有:

  • 0x200da4 - 0x200dac:为sanity check,用于探测代码是否正在访问超过slice边界的位置。为rust safety相关指令。可能不能移除这些指令。
  • 0x200db4 - 0x200dc4:t4用于存储rhs.coefs[N-j+1]的地址。其看起来非常可能可简化计算,如,使用“slli”来左移3位以实现乘以8的操作。有2个指针交叠移动,一个加8,另一个减8。所实现代码在 0x200df0 - 0x200df4。
  • 若使用上面提及的压缩表示,有助于在一次迭代中做2个steps。

平均每个乘法贡献 36 ( = 37840587 / 1024 / 1024 ) 36(=37840587/1024/1024) 36(=37840587/1024/1024)个cycles。可通过以上优化进一步降低该值,且,由于Karatsuba可降低乘法次数,可降低总的乘法开销。

一个有趣的思想在于:

  • 若可使用RISC Zero bigint syscall来模拟3个16位乘以64位乘法运算,但不确定其效率是否更优,因这有pack和unpack开销。

最后,若想在合理时间内,构建整个proof(共1024个steps),需要加速:

  • 硬件加速
  • 软件加速

l2ivresearch将测试RISC Zero的Metal GPU优化,其看起来似乎很强大,同时将了解RISC Zero continuation,以及如何并行为整个计算生成proof,从而可线性扩展以降低延迟。

l2ivresearch对RISC Zero的Zirgen工具很感兴趣,将开启定制化证明系统的新可能,尤其是添加有助于negacyclic卷积的向量化指令。
同时,还对RISC Zero Jeremy Bruestle在Discord中提及的具有 O ( n ) O(n) O(n)复杂度的probabilistic checking protocol感兴趣,不过这还在内部开发中。

参考资料

[1] l2ivresearch 2023年12月博客 Tech Deep Dive: Verifying FHE in RISC Zero, Part II

FHE系列博客

  • 技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)
  • 基于[Discretized] Torus的全同态加密指引(1)
  • 基于[Discretized] Torus的全同态加密指引(2)
  • TFHE——基于[Discretized] Torus的全同态加密 代码解析

RISC Zero系列博客

  • RISC0:Towards a Unified Compilation Framework for Zero Knowledge
  • Risc Zero ZKVM:zk-STARKs + RISC-V
  • 2023年 ZK Hack以及ZK Summit 9 亮点记
  • RISC Zero zkVM 白皮书
  • Risc0:使用Continunations来证明任意EVM交易
  • Zeth:首个Type 0 zkEVM
  • RISC Zero项目简介
  • RISC Zero zkVM性能指标
  • Continuations:扩展RISC Zero zkVM支持(无限)大计算
  • A summary on the FRI low degree test前2页导读
  • Reed-Solomon Codes及其与RISC Zero zkVM的关系
  • RISC Zero zkVM架构
  • RISC-V与RISC Zero zkVM的关系
  • 有限域的Fast Multiplication和Modular Reduction算法实现
  • RISC Zero的Bonsai证明服务
  • RISC Zero ZKP协议中的商多项式
  • FRI的Commit、Query以及FRI Batching内部机制
  • RISC Zero的手撕STARK
  • RISC Zero zkVM guest程序优化技巧 及其 与物理CPU的关键差异
  • ZK*FM:RISC Zero zkVM的形式化验证
  • Zirgen MLIR:RISC-Zero的ZK-circuits形式化验证
  • 以RISC Zero ZK Fraud Proof赋能Optimistic Rollups
  • zkSummit10 亮点记
  • 技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/280121.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue : 监视属性

目录 一个案例 监听属性 handler immediate vm.$watch(xxx) 深度监视 监视的简写 computed和watch之间的区别 一个案例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"…

【LeetCode】修炼之路-0001-Two Sum(两数之和)【python】【简单】

前言 计算机科学作为一门实践性极强的学科,代码能力的培养尤为重要。当前网络上有非常多优秀的前辈分享了LeetCode的最佳算法题解,这对于我们这些初学者来说提供了莫大的帮助,但对于我这种缺乏编程直觉的学习者而言,这往往难以消化吸收。&#xff08;为什么别人就能想出这么优雅…

Note: Wildlife Protection

wildlife protection protection wildlife Dinosaurs died out because of an unexpected incident. unexpected dinosaurs But wildlife today disappears or is in danger just because humans do harm to it. 但是&#xff0c;今天的野生动植物因为人类的伤害而消失了或…

计算机网络——计算大题(七)

前言&#xff1a; 最近也是在准备计算机考试&#xff0c;我们的考试形式是上机考试&#xff0c;所以可能有些计算题是会给提供思路的&#xff0c;前面已经对本学期的计算机网络知识有了一个简单的认识与了解&#xff0c;现在我们就来对计算大题进行一个学习吧&#xff0c;这里的…

西班牙语中关于时间的相关表达-柯桥 外贸西语学习

今天来为大家介绍一下询问时间和被别人询问时间西语相关表达。 如何向他人询问时间&#xff1f; Qu hora es? 几点了&#xff1f; Tienes hora? 你知道时间吗&#xff1f; Me puede decir la hora? 你可以告诉我时间吗&#xff1f; 如何表达时间&#xff1f;我…

【JavaEE】多线程(7) -- 线程池的概念和简单实现

目录 1.线程池是什么 2.标准库中的线程池 2.1ThreadPoolExecutor 2.2构造方法参数介绍 2.3拒绝策略(面试易考) 2.4Executor的使用 3.实现线程池 1.线程池是什么 线程池是一种用来管理线程的机制&#xff0c;它可以有效地控制线程的创建、复用和销毁&#xff0c;从而提高程…

UG装配-添加组件

添加组件命令位置在如下位置&#xff1a;菜单-装配-组件-添加组件 添加组件命令位置在如下位置&#xff1a;菜单-装配-组件-添加组件

【BERT】深入BERT模型2——模型中的重点内容,两个任务

前言 BERT出自论文&#xff1a;《BERT&#xff1a;Pre-training of Deep Bidirectional Transformers for Language Understanding》 2019年 近年来&#xff0c;在自然语言处理领域&#xff0c;BERT模型受到了极为广泛的关注&#xff0c;很多模型中都用到了BERT-base或者是BE…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

音频、视频插座

音频、视频插座 常用电子元器件类型 DC电源插座 文章目录 音频、视频插座前言一、音频、视频插座二、DC电源插座1. 镀铜锡DC插座2. 镀镍DC插座总结前言 音频和视频插座在设计上具有特定的接口类型和标准,以确保兼容性和信号传输的质量。在选择插座时,需要根据设备的接口类…

vlc 查看音频有没有声音

播放文件或者实时流 播放文件 选择音频文件 打开网络流 输入实时流地址 查看音频是否有声音

『番外篇七』SwiftUI 获取视图全局位置在 NavigationStack 中失效的解决方法

概览 在 番外篇六』SwiftUI 取得任意视图全局位置的三种方法 这篇博文里,我们详细讨论了在 SwiftUI 中获取任意视图全局坐标的几种方法。 不过,我们也从中提到了某些方法无法适用于 NavigationStack 视图,本篇博文由此应运而生。 在本篇博文种,您将学到如下内容: 概览1.…

YOLOv5算法进阶改进(9)— 引入ASPP | 空洞空间金字塔池化

前言:Hello大家好,我是小哥谈。ASPP是空洞空间金字塔池化(Atrous Spatial Pyramid Pooling)的缩写。它是一种用于图像语义分割任务的特征提取方法。ASPP通过在不同尺度上进行空洞卷积操作,从而捕捉到图像中不同尺度的上下文信息。ASPP的主要思想是在输入特征图上应用多个不…

【JavaWeb学习笔记】17 - ThreadLocal

项目代码 https://github.com/yinhai1114/JavaWeb_LearningCode/tree/main/threadlocal/src/com/yinhai/thread 目录 项目代码 一、什么是ThreadLocal? 二、ThreadLocal快速入门 三、源码解读 一、什么是ThreadLocal? 1. ThreadLocal的作用&#xff0c;可以实现在同一个线…

24、Web攻防-通用漏洞SQL注入MYSQL跨库ACCESS偏移

文章目录 一、SQL注入原理   脚本代码在与数据库进行数据通讯时&#xff08;从数据库取出相关数据进行页面显示&#xff09;&#xff0c;使用预定义的SQL查询语句进行数据查询。能通过参数传递自定义值来实现SQL语句的控制&#xff0c;执行恶意的查询操作&#xff0c;例如查询…

Windows下配置GCC(MinGW)环境

一、下载并安装MinGW 步骤1&#xff1a;下载MinGW安装器 前往MinGW的官方下载源&#xff0c;通过以下链接可以获取到最新版的MinGW安装程序&#xff1a; 网页地址&#xff1a;https://sourceforge.net/projects/mingw/files/ [MinGW 下载地址](https://sourceforge.net/proj…

【计算机毕业设计】SSM游戏点评网站

项目介绍 本项目分为前后台&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,管理员管理,网站用户管理,游戏资讯管理,游戏类型管理,城市信息管理,竞技场管理,游戏信息管理,游戏评价信息管理等功能。…

gradle下载太慢不用再烦恼了

编辑gradle-wrapper文件 使用腾讯镜像 https://mirrors.cloud.tencent.com/gradle/gradle-7.5-all.zip 来代替原来的 https\://services.gradle.org/distributions/gradle-7.5-all.zip

【设计模式】状态模式

文章目录 引例状态模式理论状态模式代码优化结合享元模式并发问题解决 策略模式 VS 状态模式 引例 交通信号灯系统的设计与实现 方案一 传统设计方案 定义交通灯颜色的枚举 public enum LightColor { Green,Red,Yellow }交通灯类TrafficLight&#xff0c;处理颜色转换等业务…

RIS 系列 See-Through-Text Grouping for Referring Image Segmentation 论文阅读笔记

RIS 系列 See-Through-Text Grouping for Referring Image Segmentation 论文阅读笔记 一、Abstract二、引言三、相关工作3.1 Semantic Segmentation and Embeddings3.2 Referring Expression Comprehension3.3 Referring Image Segmentation 四、方法4.1 视觉表示4.2 文本表示…