voting_circuits/circuit/
mul_chip.rs1use 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
9pub trait MulInstruction<F: Field>: Chip<F> {
11 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#[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#[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 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 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}