darkfi/zk/gadget/
is_equal.rs1use std::marker::PhantomData;
21
22use halo2_proofs::{
23 circuit::{AssignedCell, Chip, Layouter, Region},
24 pasta::group::ff::WithSmallOrderMulGroup,
25 plonk::{self, Advice, Column, ConstraintSystem, Expression, Selector},
26 poly::Rotation,
27};
28
29const NUM_OF_UTILITY_ADVICE_COLUMNS: usize = 4;
30
31#[derive(Clone, Debug)]
32pub struct IsEqualConfig<F: WithSmallOrderMulGroup<3> + Ord> {
33 s_is_eq: Selector,
34 advices: [Column<Advice>; NUM_OF_UTILITY_ADVICE_COLUMNS],
35 _marker: PhantomData<F>,
36}
37
38pub struct IsEqualChip<F: WithSmallOrderMulGroup<3> + Ord> {
39 config: IsEqualConfig<F>,
40}
41
42impl<F: WithSmallOrderMulGroup<3> + Ord> Chip<F> for IsEqualChip<F> {
43 type Config = IsEqualConfig<F>;
44 type Loaded = ();
45
46 fn config(&self) -> &Self::Config {
47 &self.config
48 }
49
50 fn loaded(&self) -> &Self::Loaded {
51 &()
52 }
53}
54
55impl<F: WithSmallOrderMulGroup<3> + Ord> IsEqualChip<F> {
56 pub fn construct(config: <Self as Chip<F>>::Config) -> Self {
57 Self { config }
58 }
59
60 pub fn configure(
61 meta: &mut ConstraintSystem<F>,
62 advices: [Column<Advice>; NUM_OF_UTILITY_ADVICE_COLUMNS],
63 ) -> <Self as Chip<F>>::Config {
64 let s_is_eq = meta.selector();
65 meta.create_gate("is_eq", |meta| {
66 let lhs = meta.query_advice(advices[0], Rotation::cur());
67 let rhs = meta.query_advice(advices[1], Rotation::cur());
68 let out = meta.query_advice(advices[2], Rotation::cur());
69 let delta_invert = meta.query_advice(advices[3], Rotation::cur());
70 let s_is_eq = meta.query_selector(s_is_eq);
71 let one = Expression::Constant(F::ONE);
72
73 vec![
74 s_is_eq.clone() * (out.clone() * (one.clone() - out.clone())),
76 s_is_eq.clone() *
79 ((lhs.clone() - rhs.clone()) * delta_invert.clone() + (out - one.clone())),
80 s_is_eq * (lhs.clone() - rhs.clone()) * ((lhs - rhs) * delta_invert - one),
82 ]
83 });
84
85 IsEqualConfig { s_is_eq, advices, _marker: PhantomData }
86 }
87
88 pub fn is_eq_with_output(
89 &self,
90 layouter: &mut impl Layouter<F>,
91 a: AssignedCell<F, F>,
92 b: AssignedCell<F, F>,
93 ) -> Result<AssignedCell<F, F>, plonk::Error> {
94 let config = self.config();
95
96 let out = layouter.assign_region(
97 || "is_eq",
98 |mut region: Region<'_, F>| {
99 config.s_is_eq.enable(&mut region, 0)?;
100
101 a.copy_advice(|| "copy a", &mut region, config.advices[0], 0)?;
102 b.copy_advice(|| "copy b", &mut region, config.advices[1], 0)?;
103
104 let delta_invert = a.value().copied().to_field().zip(b.value()).map(|(a, b)| {
105 if a == b.into() {
106 F::ONE.into()
107 } else {
108 let delta = a - *b;
109 delta.invert()
110 }
111 });
112
113 region.assign_advice(|| "delta invert", config.advices[3], 0, || delta_invert)?;
114
115 let is_eq =
116 a.value_field().evaluate().zip(b.value_field().evaluate()).map(|(lhs, rhs)| {
117 if lhs == rhs {
118 F::ONE
119 } else {
120 F::ZERO
121 }
122 });
123
124 let cell = region.assign_advice(|| "is_eq", config.advices[2], 0, || is_eq)?;
125 Ok(cell)
126 },
127 )?;
128
129 Ok(out)
130 }
131}
132
133#[derive(Clone, Debug)]
134pub struct AssertEqualConfig<F: WithSmallOrderMulGroup<3> + Ord> {
135 s_eq: Selector,
136 advices: [Column<Advice>; 2],
137 _marker: PhantomData<F>,
138}
139
140pub struct AssertEqualChip<F: WithSmallOrderMulGroup<3> + Ord> {
141 config: AssertEqualConfig<F>,
142}
143
144impl<F: WithSmallOrderMulGroup<3> + Ord> Chip<F> for AssertEqualChip<F> {
145 type Config = AssertEqualConfig<F>;
146 type Loaded = ();
147
148 fn config(&self) -> &Self::Config {
149 &self.config
150 }
151
152 fn loaded(&self) -> &Self::Loaded {
153 &()
154 }
155}
156
157impl<F: WithSmallOrderMulGroup<3> + Ord> AssertEqualChip<F> {
158 pub fn construct(config: <Self as Chip<F>>::Config) -> Self {
159 Self { config }
160 }
161
162 pub fn configure(
163 meta: &mut ConstraintSystem<F>,
164 advices: [Column<Advice>; 2],
165 ) -> <Self as Chip<F>>::Config {
166 let s_eq = meta.selector();
167 meta.create_gate("assert_eq", |meta| {
168 let lhs = meta.query_advice(advices[0], Rotation::cur());
169 let rhs = meta.query_advice(advices[1], Rotation::cur());
170 let s_eq = meta.query_selector(s_eq);
171
172 vec![s_eq * (lhs - rhs)]
173 });
174
175 AssertEqualConfig { s_eq, advices, _marker: PhantomData }
176 }
177
178 pub fn assert_equal(
179 &self,
180 layouter: &mut impl Layouter<F>,
181 a: AssignedCell<F, F>,
182 b: AssignedCell<F, F>,
183 ) -> Result<(), plonk::Error> {
184 let config = self.config();
185
186 layouter.assign_region(
187 || "assert_eq",
188 |mut region: Region<'_, F>| {
189 config.s_eq.enable(&mut region, 0)?;
190
191 a.copy_advice(|| "copy a", &mut region, config.advices[0], 0)?;
192 b.copy_advice(|| "copy b", &mut region, config.advices[1], 0)?;
193 Ok(())
194 },
195 )?;
196
197 Ok(())
198 }
199}