首页 > 其他分享 >Halo2简单应用-斐波那契示例

Halo2简单应用-斐波那契示例

时间:2023-12-21 18:25:07浏览次数:40  
标签:fib cur 示例 mut self 斐波 meta let Halo2

电路设计

Halo2是基于PLONK算法的零知识证明框架,使用Rust语言。
在Halo2中要证明你掌握斐波那契数列,例如Fib(10)=55。则需要将你的每一步计算过程(秘密的)罗列出来。并由程序(电路)来进行验证,生成证明。
在PLONK算法里,我们使用表格来进行计算跟踪,例如:

a b r
1 1 2
1 2 3
2 3 5
3 5 8
5 8 13
8 13 21
13 21 34
21 34 55

程序(电路)验证的约束为:

  • next_a = b, next_b = r (相等约束)
  • a + b - r = 0 (自定义门约束)

一般,我们还需要使用选择器列(约束是否启用的开关),以及最终的输入输出(目标结果)列,因此表格可以设计为v1

selector a b c target
1 1 1 2 55
1 1 2 3
1 2 3 5
1 3 5 8
1 5 8 13
1 8 13 21
1 13 21 34
1 21 34 55

程序(电路)验证的约束为:

  • selector * (a + b - c) = 0 (自定义门约束)
  • next_a = b, next_b = c (相等约束)

要输出(暴露)的最终结果是最后一行b的值55

因此电路要实现的步骤为

  1. 填写第一行a=1, b=1,返回当前b列和c列
  2. 循环(7次),填写下一行
    1. 拷贝上一行b列到当前a列
    2. 拷贝上一行c列到当前行b列
    3. 计算和并填写当前c列
    4. 返回当前b列和c列
  3. 暴露最后一行c列的值(结果)

在电路方法中,填写(分配)值、计算等函数之间一般通过单元格AssignedCell<F,F>来作为参数和返回值来进行传递。

我们使用一个名为FibChip的结构体来实现这些操作
FibChip

  • configure(): 实现芯片配置和(自定义门)约束
  • assign_first_row(): 填写第一行的值a=1, b=1, 计算c,返回分配的单元格b和c
  • assign_next_row(): 填写下一行,拷贝上一行的b和c到当前行的a和b,并计算填写c,返回当前单元格b和c
  • expose_public(): 将最后一行的c暴露为最终结果以供验证

实现方法

  1. 新建Cargo项目
cargo new halo2_fib --bin
  1. Cargo.toml添加halo2_proofs包依赖
[package]
name = "halo2_fib"
version = "0.1.0"
edition = "2021"

[dependencies]
halo2_proofs = { git = "https://github.com/zcash/halo2.git" }
  1. 修改src/main.rs为src/fib.rs,并新建src/lib.rs,内容为
mod fib;

项目结构如下

halo2_fib
├── src
|    ├── fib.rs
|    └── lib.rs
├── Cargo.lock
└── Cargo.toml
  1. fib.rs实现
    斐波那契芯片配置
#[derive(Clone, Debug, Copy)]
struct FibConfig {
    selector: Selector,
    a: Column<Advice>,
    b: Column<Advice>,
    c: Column<Advice>,
    target: Column<Instance>,
}

斐波那契芯片及功能实现

struct FibChip {
    config: FibConfig
}
impl FibChip {
    // 生成配置及实现约束
    fn configure<F: Field>(meta: &mut ConstraintSystem<F>) -> FibConfig {
        let selector = meta.selector();
        let a = meta.advice_column();
        let b = meta.advice_column();
        let c = meta.advice_column();
        let target = meta.instance_column();

        meta.enable_equality(a);
        meta.enable_equality(b);
        meta.enable_equality(c);
        meta.enable_equality(target);
        // 自定义门约束
        meta.create_gate("斐波那契(相加)", |meta| {
            let selector = meta.query_selector(selector);
            let num_a = meta.query_advice(a, Rotation::cur());
            let num_b = meta.query_advice(b, Rotation::cur());
            let num_c = meta.query_advice(c, Rotation::cur());
            vec![
                ("a + b = c", selector * (num_a + num_b - num_c)),
            ]
        });
        FibConfig { selector, a, b, c, target }
    }
    // 填写第一行,并返回当前单元格b和c
    fn assign_first_row<F: Field>(&self, mut layouter: impl Layouter<F>, a: Value<F>, b: Value<F>) -> Result<(AssignedCell<F, F>, AssignedCell<F, F>), Error> {
        layouter.assign_region(|| "填写第一行", |mut region| {
            self.config.selector.enable(&mut region, 0)?;
            region.assign_advice(|| "加载a", self.config.a,  0, || a).expect("加载a失败");
            let cur_b = region.assign_advice(|| "加载b", self.config.b,  0, || b).expect("加载b失败");
            let cur_c = region.assign_advice(|| "计算当前c", self.config.c,  0, || a+b).expect("填写c失败");
            Ok((cur_b, cur_c))  // 返回当前单元格b和单元格c
        })
    }
    // 填写下一行,并返回当前单元格b和c
    fn assign_next_row<F: Field>(&self, mut layouter: impl Layouter<F>, pre_b: &AssignedCell<F,F>, pre_c: &AssignedCell<F, F>) -> Result<(AssignedCell<F, F>, AssignedCell<F, F>), Error> {
        layouter.assign_region(|| "填写下一行", |mut region| {
            self.config.selector.enable(&mut region, 0)?;
            let cur_a = pre_b.copy_advice(|| "拷贝上一行b到当前a", &mut region, self.config.a, 0).expect("拷贝到a失败");
            let cur_b = pre_c.copy_advice(|| "拷贝上一行c到当前b", &mut region, self.config.b, 0).expect("拷贝到b失败");
            let value_c = cur_a.value_field().evaluate() + cur_b.value_field().evaluate();
            let cur_c = region.assign_advice(|| "计算当前c", self.config.c, 0, || value_c).expect("填写c失败");
            Ok((cur_b, cur_c))  // 返回当前单元格b和单元格c
        })
    }
    // 将某单元格暴露为最终结果
    fn expose_public<F:Field>( &self, mut layouter: impl Layouter<F>, cell: &AssignedCell<F,F>, row: usize ) -> Result<(), Error> {
        layouter.constrain_instance(cell.cell(), self.config.target, row)
    }
}

电路实现

#[derive(Default)]
struct FibCircuit<F: Field> {
    a: Value<F>, // 初始a=1
    b: Value<F>, // 初始b=1
}

impl<F: Field> Circuit<F> for FibCircuit<F> {
    type Config = FibConfig;
    type FloorPlanner = SimpleFloorPlanner;

    fn without_witnesses(&self) -> Self { Self::default() }

    fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config { FibChip::configure(meta) }

    fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<F>) -> Result<(), Error> {
        let fib = FibChip { config };
        // 初始化第一行
        let (mut b, mut c) = fib.assign_first_row(layouter.namespace(||"填写第一行"), self.a, self.b).expect("填写第一行失败");
        // 循环填写下一行(循环7次)
        for _i in 3..10 {
            let (next_b, next_c) = fib.assign_next_row(layouter.namespace(||"填写下一行"), &b, &c).expect("填写下一行失败");
            b = next_b;
            c = next_c;
        }
        // 暴露结果
        fib.expose_public(layouter, &c, 0)?;
        Ok(())
    }
}

测试电路

#[test]
fn test_fib() {
    let circuit = FibCircuit {a: Value::known(Fp::one()),b: Value::known(Fp::one())};
    let target = Fp::from(55);
    let public_input = vec![target];
    let prover = MockProver::run(4, &circuit, vec![public_input]).unwrap();  // 最大可用2^4=16行
    prover.assert_satisfied();
}

完整代码:https://github.com/hanzhichao/halo2-fib/blob/master/src/fib.rs

参考

标签:fib,cur,示例,mut,self,斐波,meta,let,Halo2
From: https://www.cnblogs.com/superhin/p/halo2-fibonacci.html

相关文章

  • libevent http-server示例
    wgethttps://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gztarxvzflibevent-2.1.12-stable.tar.gz-C.cdlibevent-2.1.12-stablemkdircmake-build-debugcdcmake-build-debugcmake../-DCMAKE_BUILD_TYPE......
  • CH582,CH583,CH32V208等IC低功耗蓝牙系列2.4G例程RF_PHY/RF_PHY_Hop配对示例
    RF_PHY和RF_PHY_Hop两个例程均可以采用这种思路,甚至可以组合使用,比如RF_PHY用来配对,RF_PHY_Hop用来数据通讯,思路简介:该例程只要收发双方的地址,跳频频道等基础配置项一致即可进行无线通讯,因此可以衍生出其中一种较简单的配对思路,即:1、初始化代码中使用默认地址,例如0x71764129,这样......
  • kaldi lesson教程示例(转载)
    转自:https://blog.csdn.net/q_xiami123/article/details/117019177?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170312043616800188564167%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170312043616800188564167&biz_......
  • 【Spring教程21】Spring框架实战:Spring事务简介、AOP事务管理、代码示例全面详解
    欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及IDEA配置Maven环境》,本文的上一篇为《AOP(面对切面编程)知识总结》1相关概念介绍事务作用:在数据层保障一系列的数据库操......
  • es使用示例
    记录是否存在res=es.exists(index="ncbi_gene",id=_id)插入记录es_res=self.es.index(index="ncbi_gene",id=my_data['GeneID'],body=my_data)ifes_res['result']in['created','updated']:logging.......
  • 正则表达式相关。示例:包含a和b,包含a不包含b
    普通字符普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。非打印字符非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列:字符描述\cx匹配由x指明的控制字符。......
  • Keepalived+Nginx+Tomcat配置高可用负载均衡系统示例
    前言目前生产环境的配置越来越多的使用云服务了,同时负载均衡也基本转向了云厂商提供的服务,但对于绝大多数应用来说,自建集群可能在费用上要更便宜一些,这篇文章也是之前整理的,再次新瓶装旧酒分享给各位。此示例演示在不使用docker的情况下配置负载均衡,内容keepalived+nginx+tomcat......
  • Python多线程应用于自动化测试操作示例
    本文实例讲述了Python多线程应用于自动化测试操作。分享给大家供大家参考,具体如下:多线程执行测试用例实例:importthreadingfromtimeimportsleep,ctimefromseleniumimportwebdriver#测试用例1deftest_baidu(browser,search):print("开始,现在时间是%s"%ctime())print("......
  • rdf-file:读、写、合并示例
    <dependency> <groupId>com.alipay.rdf.file</groupId> <artifactId>rdf-file-core</artifactId> <version>2.2.10</version></dependency>一:读1.1原始读原始文件读取就是不需要根据协议布局模板和数据定义模板来把数据转换成对象。1.readRow(Class<?>req......
  • 45、Flink 的指标体系介绍及验证(2)-指标的scope、报告、系统指标以及追踪、api集成示例
    文章目录Flink系列文章一、Flink指标体系2、Scope范围1)、用户范围2)、系统范围SystemScope3)、所有变量列表4)、用户变量3、Reporter4、Systemmetrics1)、CPU2)、Memory3)、Threads4)、GarbageCollection5)、ClassLoader6)、Network7)、Defaultshuffleservice8)、Cluster9)、Availabili......