Skip to main content

voting_circuits/circuit/
mul_chip.rs

1use halo2_proofs::{
2    circuit::{AssignedCell, Chip, Layouter},
3    plonk::{self, Advice, Column, ConstraintSystem, Constraints, Selector},
4    poly::Rotation,
5};
6use ff::Field;
7use pasta_curves::pallas;
8
9/// An instruction set for multiplying two circuit words (field elements).
10pub trait MulInstruction<F: Field>: Chip<F> {
11    /// Constraints `a * b` and returns the product.
12    fn mul(
13        &self,
14        layouter: impl Layouter<F>,
15        a: &AssignedCell<F, F>,
16        b: &AssignedCell<F, F>,
17    ) -> Result<AssignedCell<F, F>, plonk::Error>;
18}
19
20/// Configuration for the multiplication chip.
21#[derive(Clone, Debug)]
22pub struct MulConfig {
23    a: Column<Advice>,
24    b: Column<Advice>,
25    c: Column<Advice>,
26    q_mul: Selector,
27}
28
29/// A chip implementing a single multiplication constraint `c = a * b` on a single row.
30#[derive(Debug)]
31pub struct MulChip {
32    config: MulConfig,
33}
34
35impl Chip<pallas::Base> for MulChip {
36    type Config = MulConfig;
37    type Loaded = ();
38
39    fn config(&self) -> &Self::Config {
40        &self.config
41    }
42
43    fn loaded(&self) -> &Self::Loaded {
44        &()
45    }
46}
47
48impl MulChip {
49    /// Configures the multiplication chip with the given advice columns.
50    pub fn configure(
51        meta: &mut ConstraintSystem<pallas::Base>,
52        a: Column<Advice>,
53        b: Column<Advice>,
54        c: Column<Advice>,
55    ) -> MulConfig {
56        let q_mul = meta.selector();
57        meta.create_gate("Field element multiplication: c = a * b", |meta| {
58            let q_mul = meta.query_selector(q_mul);
59            let a = meta.query_advice(a, Rotation::cur());
60            let b = meta.query_advice(b, Rotation::cur());
61            let c = meta.query_advice(c, Rotation::cur());
62
63            Constraints::with_selector(q_mul, Some(a * b - c))
64        });
65
66        MulConfig { a, b, c, q_mul }
67    }
68
69    /// Constructs a multiplication chip from the given config.
70    pub fn construct(config: MulConfig) -> Self {
71        Self { config }
72    }
73}
74
75impl MulInstruction<pallas::Base> for MulChip {
76    fn mul(
77        &self,
78        mut layouter: impl Layouter<pallas::Base>,
79        a: &AssignedCell<pallas::Base, pallas::Base>,
80        b: &AssignedCell<pallas::Base, pallas::Base>,
81    ) -> Result<AssignedCell<pallas::Base, pallas::Base>, plonk::Error> {
82        layouter.assign_region(
83            || "c = a * b",
84            |mut region| {
85                self.config.q_mul.enable(&mut region, 0)?;
86
87                a.copy_advice(|| "copy a", &mut region, self.config.a, 0)?;
88                b.copy_advice(|| "copy b", &mut region, self.config.b, 0)?;
89
90                let scalar_val = a.value().zip(b.value()).map(|(a, b)| *a * *b);
91                region.assign_advice(|| "c", self.config.c, 0, || scalar_val)
92            },
93        )
94    }
95}