Kaynağa Gözat

halo2 examples

narodnik 5 yıl önce
ebeveyn
işleme
cd11a1e55f

+ 22 - 0
examples/halo2/Cargo.toml

@@ -0,0 +1,22 @@
+[package]
+name = "halo2-examples"
+version = "0.1.0"
+authors = ["narodnik <x@x.org>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+group = "0.10"
+
+[dependencies.halo2]
+git = "https://github.com/zcash/halo2.git"
+rev = "93aabf26c67fcc7a1d5439c350afcf00f1399aa5"
+
+[[bin]]
+name = "simple3"
+path = "simple3.rs"
+
+[[bin]]
+name = "simple4"
+path = "simple4.rs"

+ 6 - 0
examples/halo2/README.md

@@ -0,0 +1,6 @@
+Always use the --release flag otherwise it's too slow:
+
+```
+cargo run --release --bin simple3
+```
+

+ 130 - 0
examples/halo2/simple3.rs

@@ -0,0 +1,130 @@
+use halo2::{
+    circuit::{SimpleFloorPlanner, Chip, Layouter},
+    pasta::{EqAffine, Fp},
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk},
+    poly::{commitment::Params, Rotation},
+    transcript::{Blake2bRead, Blake2bWrite, Challenge255},
+};
+use std::time::Instant;
+
+#[derive(Clone, Debug)]
+struct CoolConfig {
+    a_col: Column<Advice>,
+    s_range: Selector,
+}
+
+struct CoolChip {
+    config: CoolConfig
+}
+
+impl Chip<Fp> for CoolChip {
+    type Config = CoolConfig;
+    type Loaded = ();
+
+    fn config(&self) -> &Self::Config {
+        &self.config
+    }
+
+    fn loaded(&self) -> &Self::Loaded {
+        &()
+    }
+}
+
+impl CoolChip {
+    fn construct(config: CoolConfig) -> Self {
+        Self { config }
+    }
+
+    fn configure(cs: &mut ConstraintSystem<Fp>) -> CoolConfig {
+        let a_col = cs.advice_column();
+        let s_range = cs.selector();
+
+        cs.create_gate("check", |cs| {
+            let a = cs.query_advice(a_col, Rotation::cur());
+            let s_range = cs.query_selector(s_range);
+            vec![s_range * (a - Expression::Constant(Fp::from(2)))]
+        });
+
+        CoolConfig { a_col, s_range }
+    }
+
+    fn alloc_and_check(
+        &self,
+        layouter: &mut impl Layouter<Fp>,
+        a: Option<Fp>,
+    ) -> Result<(), Error> {
+        layouter.assign_region(
+            || "load private inputs",
+            |mut region| {
+                let row_offset = 0;
+                self.config.s_range.enable(&mut region, row_offset)?;
+                region.assign_advice(
+                    || "private input 'a'",
+                    self.config.a_col,
+                    row_offset,
+                    || a.ok_or(Error::SynthesisError),
+                )?;
+                Ok(())
+            },
+        )
+    }
+}
+
+#[derive(Clone)]
+struct CoolCircuit {
+    // Private input.
+    a: Option<Fp>,
+}
+
+impl Circuit<Fp> for CoolCircuit {
+    type Config = CoolConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self { a: None }
+    }
+
+    fn configure(cs: &mut ConstraintSystem<Fp>) -> Self::Config {
+        CoolChip::configure(cs)
+    }
+
+    fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<Fp>) -> Result<(), Error> {
+        let chip = CoolChip::construct(config);
+        chip.alloc_and_check(&mut layouter, self.a)
+    }
+}
+
+fn main() {
+    let start = Instant::now();
+    let params: Params<EqAffine> = Params::new(4);
+
+    let empty_circuit = CoolCircuit { a: None };
+    let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
+    let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
+    println!("Setup: [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    let circuit = CoolCircuit {
+        a: Some(Fp::from(2)),
+    };
+
+    // Create a proof
+    let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
+    create_proof(&params, &pk, &[circuit], &[&[]], &mut transcript)
+        .expect("proof generation should not fail");
+    let proof = transcript.finalize();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    let msm = params.empty_msm();
+    let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
+    let verification = verify_proof(&params, pk.get_vk(), msm, &[&[]], &mut transcript);
+    if let Err(err) = verification {
+        panic!("error {:?}", err);
+    }
+    let guard = verification.unwrap();
+    let msm = guard.clone().use_challenges();
+    assert!(msm.eval());
+    println!("Verify: [{:?}]", start.elapsed());
+}
+

+ 267 - 0
examples/halo2/simple4.rs

@@ -0,0 +1,267 @@
+use halo2::{
+    circuit::{SimpleFloorPlanner, Cell, Chip, Layouter},
+    pasta::{EqAffine, Fp},
+    plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk, Permutation},
+    poly::{commitment::{Blind, Params}, Rotation},
+    transcript::{Blake2bRead, Blake2bWrite, Challenge255},
+};
+use group::Curve;
+use std::time::Instant;
+
+#[derive(Clone, Debug)]
+struct CoolConfig {
+    a_col: Column<Advice>,
+    b_col: Column<Advice>,
+    permute: Permutation,
+    s_range: Selector,
+    s_mul: Selector,
+    s_pub: Selector,
+}
+
+struct CoolChip {
+    config: CoolConfig
+}
+
+impl Chip<Fp> for CoolChip {
+    type Config = CoolConfig;
+    type Loaded = ();
+
+    fn config(&self) -> &Self::Config {
+        &self.config
+    }
+
+    fn loaded(&self) -> &Self::Loaded {
+        &()
+    }
+}
+
+#[derive(Clone, Debug)]
+struct Number {
+    cell: Cell,
+    value: Option<Fp>,
+}
+
+impl CoolChip {
+    fn construct(config: CoolConfig) -> Self {
+        Self { config }
+    }
+
+    fn configure(cs: &mut ConstraintSystem<Fp>) -> CoolConfig {
+        let a_col = cs.advice_column();
+        let b_col = cs.advice_column();
+
+        let instance = cs.instance_column();
+
+        let permute = {
+            // Convert advice columns into an "any" columns.
+            let cols: [Column<Any>; 2] = [a_col.into(), b_col.into()];
+            Permutation::new(cs, &cols)
+        };
+
+        let s_range = cs.selector();
+        let s_mul = cs.selector();
+        let s_pub = cs.selector();
+
+        cs.create_gate("check", |cs| {
+            let a = cs.query_advice(a_col, Rotation::cur());
+            let s_range = cs.query_selector(s_range);
+            vec![s_range * (a - Expression::Constant(Fp::from(2)))]
+        });
+
+        cs.create_gate("mul", |cs| {
+            let lhs = cs.query_advice(a_col, Rotation::cur());
+            let rhs = cs.query_advice(b_col, Rotation::cur());
+            let out = cs.query_advice(a_col, Rotation::next());
+            let s_mul = cs.query_selector(s_mul);
+
+            vec![s_mul * (lhs * rhs + out * -Fp::one())]
+        });
+
+        cs.create_gate("public input", |cs| {
+            let a = cs.query_advice(b_col, Rotation::cur());
+            let p = cs.query_instance(instance, Rotation::cur());
+            let s = cs.query_selector(s_pub);
+
+            vec![s * (p + a * -Fp::one())]
+        });
+
+        CoolConfig { a_col, b_col, permute, s_range, s_mul, s_pub }
+    }
+
+    fn alloc_left(
+        &self,
+        layouter: &mut impl Layouter<Fp>,
+        value: Option<Fp>
+    ) -> Result<Number, Error> {
+        layouter.assign_region(
+            || "load left private input",
+            |mut region| {
+                let cell = region.assign_advice(
+                    || "private input 'a'",
+                    self.config.a_col,
+                    0,
+                    || value.ok_or(Error::SynthesisError),
+                )?;
+                Ok(Number { cell, value })
+            }
+        )
+    }
+
+    fn check(
+        &self,
+        layouter: &mut impl Layouter<Fp>,
+        number: Number
+    ) -> Result<(), Error> {
+        layouter.assign_region(
+            || "load private inputs",
+            |mut region| {
+                self.config.s_range.enable(&mut region, 0)?;
+
+                let a = region.assign_advice(
+                    || "lhs",
+                    self.config.a_col,
+                    0,
+                    || number.value.ok_or(Error::SynthesisError),
+                )?;
+                region.constrain_equal(&self.config.permute, number.cell, a)?;
+
+                Ok(())
+            },
+        )
+    }
+
+    fn mul(
+        &self,
+        layouter: &mut impl Layouter<Fp>,
+        a: Number,
+        b: Number
+    ) -> Result<Number, Error> {
+        let mut out = None;
+        layouter.assign_region(
+            || "mul",
+            |mut region| {
+                self.config.s_mul.enable(&mut region, 0)?;
+
+                let lhs = region.assign_advice(
+                    || "lhs",
+                    self.config.a_col,
+                    0,
+                    || a.value.ok_or(Error::SynthesisError),
+                )?;
+                let rhs = region.assign_advice(
+                    || "rhs",
+                    self.config.b_col,
+                    0,
+                    || b.value.ok_or(Error::SynthesisError),
+                )?;
+                region.constrain_equal(&self.config.permute, a.cell, lhs)?;
+                region.constrain_equal(&self.config.permute, b.cell, rhs)?;
+
+                let value = a.value.and_then(|a| b.value.map(|b| a * b));
+                let cell = region.assign_advice(
+                    || "lhs * rhs",
+                    self.config.a_col,
+                    1,
+                    || value.ok_or(Error::SynthesisError),
+                )?;
+
+                out = Some(Number { cell, value });
+                Ok(())
+            },
+        )?;
+
+        Ok(out.unwrap())
+    }
+
+    fn expose_public(&self, layouter: &mut impl Layouter<Fp>, num: Number) -> Result<(), Error> {
+        layouter.assign_region(
+            || "expose public",
+            |mut region| {
+                self.config.s_pub.enable(&mut region, 0)?;
+
+                let out = region.assign_advice(
+                    || "public advice",
+                    self.config.b_col,
+                    0,
+                    || num.value.ok_or(Error::SynthesisError),
+                )?;
+                region.constrain_equal(&self.config.permute, num.cell, out)?;
+
+                Ok(())
+            },
+        )
+    }
+}
+
+#[derive(Clone)]
+struct CoolCircuit {
+    // Private input.
+    a: Option<Fp>,
+}
+
+impl Circuit<Fp> for CoolCircuit {
+    type Config = CoolConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self { a: None }
+    }
+
+    fn configure(cs: &mut ConstraintSystem<Fp>) -> Self::Config {
+        CoolChip::configure(cs)
+    }
+
+    fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<Fp>) -> Result<(), Error> {
+        let chip = CoolChip::construct(config);
+        let a = chip.alloc_left(&mut layouter, self.a)?;
+        chip.check(&mut layouter, a.clone())?;
+        let a2 = chip.mul(&mut layouter, a.clone(), a)?;
+        chip.expose_public(&mut layouter, a2)?;
+        Ok(())
+    }
+}
+
+fn main() {
+    let k = 6;
+
+    let start = Instant::now();
+    let params: Params<EqAffine> = Params::new(k);
+
+    let empty_circuit = CoolCircuit { a: None };
+    let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
+    let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
+    println!("Setup: [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    let circuit = CoolCircuit {
+        a: Some(Fp::from(2)),
+    };
+
+    let mut public_inputs = pk.get_vk().get_domain().empty_lagrange();
+    public_inputs[4] = Fp::from(4);
+
+    // Create a proof
+    let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
+    create_proof(&params, &pk, &[circuit], &[&[public_inputs.clone()]], &mut transcript)
+        .expect("proof generation should not fail");
+    let proof = transcript.finalize();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let pubinput = params
+        .commit_lagrange(&public_inputs, Blind::default())
+        .to_affine();
+    let pubinput_slice = &[pubinput];
+
+    let start = Instant::now();
+    let msm = params.empty_msm();
+    let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
+    let verification = verify_proof(&params, pk.get_vk(), msm, &[pubinput_slice], &mut transcript);
+    if let Err(err) = verification {
+        panic!("error {:?}", err);
+    }
+    let guard = verification.unwrap();
+    let msm = guard.clone().use_challenges();
+    assert!(msm.eval());
+    println!("Verify: [{:?}]", start.elapsed());
+}
+