use halo2_proofs::{
circuit::{AssignedCell, Chip, Layouter},
plonk::{self, Advice, Column, ConstraintSystem, Constraints, Selector},
poly::Rotation,
};
use ff::Field;
use pasta_curves::pallas;
pub trait MulInstruction<F: Field>: Chip<F> {
fn mul(
&self,
layouter: impl Layouter<F>,
a: &AssignedCell<F, F>,
b: &AssignedCell<F, F>,
) -> Result<AssignedCell<F, F>, plonk::Error>;
}
#[derive(Clone, Debug)]
pub struct MulConfig {
a: Column<Advice>,
b: Column<Advice>,
c: Column<Advice>,
q_mul: Selector,
}
#[derive(Debug)]
pub struct MulChip {
config: MulConfig,
}
impl Chip<pallas::Base> for MulChip {
type Config = MulConfig;
type Loaded = ();
fn config(&self) -> &Self::Config {
&self.config
}
fn loaded(&self) -> &Self::Loaded {
&()
}
}
impl MulChip {
pub fn configure(
meta: &mut ConstraintSystem<pallas::Base>,
a: Column<Advice>,
b: Column<Advice>,
c: Column<Advice>,
) -> MulConfig {
let q_mul = meta.selector();
meta.create_gate("Field element multiplication: c = a * b", |meta| {
let q_mul = meta.query_selector(q_mul);
let a = meta.query_advice(a, Rotation::cur());
let b = meta.query_advice(b, Rotation::cur());
let c = meta.query_advice(c, Rotation::cur());
Constraints::with_selector(q_mul, Some(a * b - c))
});
MulConfig { a, b, c, q_mul }
}
pub fn construct(config: MulConfig) -> Self {
Self { config }
}
}
impl MulInstruction<pallas::Base> for MulChip {
fn mul(
&self,
mut layouter: impl Layouter<pallas::Base>,
a: &AssignedCell<pallas::Base, pallas::Base>,
b: &AssignedCell<pallas::Base, pallas::Base>,
) -> Result<AssignedCell<pallas::Base, pallas::Base>, plonk::Error> {
layouter.assign_region(
|| "c = a * b",
|mut region| {
self.config.q_mul.enable(&mut region, 0)?;
a.copy_advice(|| "copy a", &mut region, self.config.a, 0)?;
b.copy_advice(|| "copy b", &mut region, self.config.b, 0)?;
let scalar_val = a.value().zip(b.value()).map(|(a, b)| *a * *b);
region.assign_advice(|| "c", self.config.c, 0, || scalar_val)
},
)
}
}