Use constants API in simple-example

This commit is contained in:
Jack Grigg 2021-07-20 16:09:41 +01:00 committed by therealyingtong
parent 7adf695293
commit 4c5a830e5c
1 changed files with 58 additions and 9 deletions

View File

@ -5,7 +5,7 @@ use std::marker::PhantomData;
use halo2::{
arithmetic::FieldExt,
circuit::{Cell, Chip, Layouter, Region, SimpleFloorPlanner},
plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance, Selector},
plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector},
poly::Rotation,
};
@ -17,6 +17,9 @@ trait NumericInstructions<F: FieldExt>: Chip<F> {
/// Loads a number into the circuit as a private input.
fn load_private(&self, layouter: impl Layouter<F>, a: Option<F>) -> Result<Self::Num, Error>;
/// Loads a number into the circuit as a fixed constant.
fn load_constant(&self, layouter: impl Layouter<F>, constant: F) -> Result<Self::Num, Error>;
/// Returns `c = a * b`.
fn mul(
&self,
@ -62,6 +65,9 @@ struct FieldConfig {
// This is important when building larger circuits, where columns are used by
// multiple sets of instructions.
s_mul: Selector,
/// The fixed column used to load constants.
constant: Column<Fixed>,
}
impl<F: FieldExt> FieldChip<F> {
@ -76,8 +82,10 @@ impl<F: FieldExt> FieldChip<F> {
meta: &mut ConstraintSystem<F>,
advice: [Column<Advice>; 2],
instance: Column<Instance>,
constant: Column<Fixed>,
) -> <Self as Chip<F>>::Config {
meta.enable_equality(instance.into());
meta.enable_constant(constant);
for column in &advice {
meta.enable_equality((*column).into());
}
@ -117,6 +125,7 @@ impl<F: FieldExt> FieldChip<F> {
advice,
instance,
s_mul,
constant,
}
}
}
@ -172,6 +181,33 @@ impl<F: FieldExt> NumericInstructions<F> for FieldChip<F> {
Ok(num.unwrap())
}
fn load_constant(
&self,
mut layouter: impl Layouter<F>,
constant: F,
) -> Result<Self::Num, Error> {
let config = self.config();
let mut num = None;
layouter.assign_region(
|| "load constant",
|mut region| {
let cell = region.assign_advice_from_constant(
|| "constant value",
config.advice[0],
0,
constant,
)?;
num = Some(Number {
cell,
value: Some(constant),
});
Ok(())
},
)?;
Ok(num.unwrap())
}
fn mul(
&self,
mut layouter: impl Layouter<F>,
@ -248,6 +284,7 @@ impl<F: FieldExt> NumericInstructions<F> for FieldChip<F> {
/// were `None` we would get an error.
#[derive(Default)]
struct MyCircuit<F: FieldExt> {
constant: F,
a: Option<F>,
b: Option<F>,
}
@ -268,7 +305,10 @@ impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
// We also need an instance column to store public inputs.
let instance = meta.instance_column();
FieldChip::configure(meta, advice, instance)
// Create a fixed column to load constants.
let constant = meta.fixed_column();
FieldChip::configure(meta, advice, instance, constant)
}
fn synthesize(
@ -282,17 +322,24 @@ impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
let a = field_chip.load_private(layouter.namespace(|| "load a"), self.a)?;
let b = field_chip.load_private(layouter.namespace(|| "load b"), self.b)?;
// Load the constant factor into the circuit.
let constant =
field_chip.load_constant(layouter.namespace(|| "load constant"), self.constant)?;
// We only have access to plain multiplication.
// We could implement our circuit as:
// asq = a*a
// bsq = b*b
// c = asq*bsq
// asq = a*a
// bsq = b*b
// absq = asq*bsq
// c = constant*asq*bsq
//
// but it's more efficient to implement it as:
// ab = a*b
// c = ab^2
// ab = a*b
// absq = ab^2
// c = constant*absq
let ab = field_chip.mul(layouter.namespace(|| "a * b"), a, b)?;
let c = field_chip.mul(layouter.namespace(|| "ab * ab"), ab.clone(), ab)?;
let absq = field_chip.mul(layouter.namespace(|| "ab * ab"), ab.clone(), ab)?;
let c = field_chip.mul(layouter.namespace(|| "constant * absq"), constant, absq)?;
// Expose the result as a public input to the circuit.
field_chip.expose_public(layouter.namespace(|| "expose c"), c, 0)
@ -309,12 +356,14 @@ fn main() {
let k = 4;
// Prepare the private and public inputs to the circuit!
let constant = Fp::from(7);
let a = Fp::from(2);
let b = Fp::from(3);
let c = a.square() * b.square();
let c = constant * a.square() * b.square();
// Instantiate the circuit with the private inputs.
let circuit = MyCircuit {
constant,
a: Some(a),
b: Some(b),
};