1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! A simple chip to compare two words for equality.

use eth_types::Field;
use eyre::Result;
use gadgets::{
    is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction},
    util::and,
};
use halo2_proofs::{
    circuit::{Region, Value},
    plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
    poly::Rotation,
};
use zkevm_circuits::util::word::WordLoHi;

#[derive(Clone, Debug)]
pub struct EqualWordsConfig<F: Field>(WordLoHi<IsZeroConfig<F>>);
impl<F: Field> EqualWordsConfig<F> {
    pub fn configure(
        meta: &mut ConstraintSystem<F>,
        q_enable: Selector,
        first: (WordLoHi<Column<Advice>>, Rotation),
        second: (WordLoHi<Column<Advice>>, Rotation),
    ) -> Self {
        let lo_inv = meta.advice_column();
        let lo = IsZeroChip::configure(
            meta,
            |meta| meta.query_selector(q_enable),
            |meta| {
                meta.query_advice(first.0.lo(), first.1)
                    - meta.query_advice(second.0.lo(), second.1)
            },
            lo_inv,
        );

        let hi_inv = meta.advice_column();
        let hi = IsZeroChip::configure(
            meta,
            |meta| meta.query_selector(q_enable),
            |meta| {
                meta.query_advice(first.0.hi(), first.1)
                    - meta.query_advice(second.0.hi(), second.1)
            },
            hi_inv,
        );

        Self(WordLoHi::new([lo, hi]))
    }

    pub fn expr(&self) -> Expression<F> {
        and::expr([self.0.hi().expr(), self.0.lo().expr()])
    }

    pub fn assign(
        &self,
        region: &mut Region<'_, F>,
        offset: usize,
        name: &str,
        first: &WordLoHi<F>,
        second: &WordLoHi<F>,
    ) -> Result<(), Error> {
        region.name_column(|| format!("{}_lo_inv", name), self.0.lo().value_inv);
        region.name_column(|| format!("{}_hi_inv", name), self.0.hi().value_inv);

        let lo = IsZeroChip::construct(self.0.lo());
        let hi = IsZeroChip::construct(self.0.hi());

        lo.assign(region, offset, Value::known(first.lo() - second.lo()))?;
        hi.assign(region, offset, Value::known(first.hi() - second.hi()))?;

        Ok(())
    }
}