Skip to content

Commit fea88c8

Browse files
Add enable flag chip
1 parent 4b0ea0b commit fea88c8

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed

src/circuit/gadget/utilities.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use halo2::{
55
use pasta_curves::arithmetic::FieldExt;
66

77
mod cond_swap;
8+
mod enable_flag;
89
mod plonk;
910

1011
/// A variable representing a number.
+285
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
use super::{copy, CellValue, UtilitiesInstructions, Var};
2+
use halo2::{
3+
circuit::{Cell, Chip, Layouter},
4+
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Permutation, Selector},
5+
poly::Rotation,
6+
};
7+
use pasta_curves::arithmetic::FieldExt;
8+
use std::marker::PhantomData;
9+
10+
pub trait EnableFlagInstructions<F: FieldExt>: UtilitiesInstructions<F> {
11+
/// Variable representing cell with a certain value in the circuit.
12+
type Var: Var<F>;
13+
14+
/// Variable representing an `enable` boolean flag.
15+
type Flag: From<<Self as EnableFlagInstructions<F>>::Var>;
16+
17+
/// Given a `value` and an `enable_flag`, check that either `value = 0`
18+
/// or `enable_flag = 1`.
19+
fn enable_flag(
20+
&self,
21+
layouter: impl Layouter<F>,
22+
value: <Self as EnableFlagInstructions<F>>::Var,
23+
enable_flag: <Self as EnableFlagInstructions<F>>::Flag,
24+
) -> Result<(), Error>;
25+
}
26+
27+
#[derive(Clone, Debug)]
28+
pub struct EnableFlagConfig {
29+
q_enable: Selector,
30+
value: Column<Advice>,
31+
enable_flag: Column<Advice>,
32+
perm: Permutation,
33+
}
34+
35+
/// A chip implementing an enable flag.
36+
#[derive(Clone, Debug)]
37+
pub struct EnableFlagChip<F> {
38+
config: EnableFlagConfig,
39+
_marker: PhantomData<F>,
40+
}
41+
42+
impl<F: FieldExt> Chip<F> for EnableFlagChip<F> {
43+
type Config = EnableFlagConfig;
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+
55+
/// A variable representing an `enable` boolean flag.
56+
#[derive(Copy, Clone)]
57+
pub struct Flag {
58+
cell: Cell,
59+
value: Option<bool>,
60+
}
61+
62+
impl<F: FieldExt> From<CellValue<F>> for Flag {
63+
fn from(var: CellValue<F>) -> Self {
64+
let value = var.value.map(|value| {
65+
let zero = value == F::zero();
66+
let one = value == F::one();
67+
if zero {
68+
false
69+
} else if one {
70+
true
71+
} else {
72+
panic!("Value must be boolean.")
73+
}
74+
});
75+
Flag {
76+
cell: var.cell,
77+
value,
78+
}
79+
}
80+
}
81+
82+
impl<F: FieldExt> UtilitiesInstructions<F> for EnableFlagChip<F> {
83+
type Var = CellValue<F>;
84+
}
85+
86+
impl<F: FieldExt> EnableFlagInstructions<F> for EnableFlagChip<F> {
87+
type Var = CellValue<F>;
88+
type Flag = Flag;
89+
90+
fn enable_flag(
91+
&self,
92+
mut layouter: impl Layouter<F>,
93+
value: <Self as EnableFlagInstructions<F>>::Var,
94+
enable_flag: <Self as EnableFlagInstructions<F>>::Flag,
95+
) -> Result<(), Error> {
96+
let config = self.config().clone();
97+
layouter.assign_region(
98+
|| "enable flag",
99+
|mut region| {
100+
// Enable `q_enable` selector
101+
config.q_enable.enable(&mut region, 0)?;
102+
103+
// Copy in `enable_flag` value
104+
let enable_flag_val = enable_flag.value;
105+
let enable_flag_cell = region.assign_advice(
106+
|| "enable_flag",
107+
config.enable_flag,
108+
0,
109+
|| {
110+
enable_flag_val
111+
.map(|enable_flag| F::from_u64(enable_flag as u64))
112+
.ok_or(Error::SynthesisError)
113+
},
114+
)?;
115+
region.constrain_equal(&config.perm, enable_flag_cell, enable_flag.cell)?;
116+
117+
// Copy `value`
118+
copy(
119+
&mut region,
120+
|| "copy value",
121+
config.value,
122+
0,
123+
&value,
124+
&config.perm,
125+
)?;
126+
127+
Ok(())
128+
},
129+
)
130+
}
131+
}
132+
133+
impl<F: FieldExt> EnableFlagChip<F> {
134+
/// Configures this chip for use in a circuit.
135+
pub fn configure(
136+
meta: &mut ConstraintSystem<F>,
137+
advices: [Column<Advice>; 2],
138+
perm: Permutation,
139+
) -> EnableFlagConfig {
140+
let q_enable = meta.selector();
141+
142+
let config = EnableFlagConfig {
143+
q_enable,
144+
value: advices[0],
145+
enable_flag: advices[1],
146+
perm,
147+
};
148+
149+
meta.create_gate("Enable flag", |meta| {
150+
let q_enable = meta.query_selector(config.q_enable, Rotation::cur());
151+
let value = meta.query_advice(config.value, Rotation::cur());
152+
let enable_flag = meta.query_advice(config.enable_flag, Rotation::cur());
153+
154+
vec![q_enable * (Expression::Constant(F::one()) - enable_flag) * value]
155+
});
156+
157+
config
158+
}
159+
160+
pub fn construct(config: EnableFlagConfig) -> Self {
161+
EnableFlagChip {
162+
config,
163+
_marker: PhantomData,
164+
}
165+
}
166+
}
167+
168+
#[cfg(test)]
169+
mod tests {
170+
use super::super::UtilitiesInstructions;
171+
use super::{EnableFlagChip, EnableFlagConfig, EnableFlagInstructions};
172+
use halo2::{
173+
circuit::{layouter::SingleChipLayouter, Layouter},
174+
dev::{MockProver, VerifyFailure},
175+
plonk::{Any, Assignment, Circuit, Column, ConstraintSystem, Error},
176+
};
177+
use pasta_curves::{arithmetic::FieldExt, pallas::Base};
178+
179+
#[test]
180+
fn enable_flag() {
181+
struct MyCircuit<F: FieldExt> {
182+
value: Option<F>,
183+
enable_flag: Option<F>,
184+
}
185+
186+
impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
187+
type Config = EnableFlagConfig;
188+
189+
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
190+
let advices = [meta.advice_column(), meta.advice_column()];
191+
192+
let perm = meta.permutation(
193+
&advices
194+
.iter()
195+
.map(|advice| (*advice).into())
196+
.collect::<Vec<Column<Any>>>(),
197+
);
198+
199+
EnableFlagChip::<F>::configure(meta, advices, perm)
200+
}
201+
202+
fn synthesize(
203+
&self,
204+
cs: &mut impl Assignment<F>,
205+
config: Self::Config,
206+
) -> Result<(), Error> {
207+
let mut layouter = SingleChipLayouter::new(cs)?;
208+
let chip = EnableFlagChip::<F>::construct(config.clone());
209+
210+
// Load the value and the enable flag into the circuit.
211+
let value =
212+
chip.load_private(layouter.namespace(|| "value"), config.value, self.value)?;
213+
let enable_flag = chip.load_private(
214+
layouter.namespace(|| "enable_flag"),
215+
config.enable_flag,
216+
self.enable_flag,
217+
)?;
218+
219+
// Run the enable flag logic.
220+
chip.enable_flag(layouter.namespace(|| "swap"), value, enable_flag.into())?;
221+
222+
Ok(())
223+
}
224+
}
225+
226+
// Test value = 1, flag = 1 case (success)
227+
{
228+
let circuit: MyCircuit<Base> = MyCircuit {
229+
value: Some(Base::one()),
230+
enable_flag: Some(Base::one()),
231+
};
232+
let prover = match MockProver::<Base>::run(1, &circuit, vec![]) {
233+
Ok(prover) => prover,
234+
Err(e) => panic!("{:?}", e),
235+
};
236+
assert_eq!(prover.verify(), Ok(()));
237+
}
238+
239+
// Test value = 0, flag = 0 case (success)
240+
{
241+
let circuit: MyCircuit<Base> = MyCircuit {
242+
value: Some(Base::zero()),
243+
enable_flag: Some(Base::zero()),
244+
};
245+
let prover = match MockProver::<Base>::run(1, &circuit, vec![]) {
246+
Ok(prover) => prover,
247+
Err(e) => panic!("{:?}", e),
248+
};
249+
assert_eq!(prover.verify(), Ok(()));
250+
}
251+
252+
// Test value = 0, flag = 1 case (success)
253+
{
254+
let circuit: MyCircuit<Base> = MyCircuit {
255+
value: Some(Base::zero()),
256+
enable_flag: Some(Base::one()),
257+
};
258+
let prover = match MockProver::<Base>::run(1, &circuit, vec![]) {
259+
Ok(prover) => prover,
260+
Err(e) => panic!("{:?}", e),
261+
};
262+
assert_eq!(prover.verify(), Ok(()));
263+
}
264+
265+
// Test value = 1, flag = 0 case (error)
266+
{
267+
let circuit: MyCircuit<Base> = MyCircuit {
268+
value: Some(Base::one()),
269+
enable_flag: Some(Base::zero()),
270+
};
271+
let prover = match MockProver::<Base>::run(1, &circuit, vec![]) {
272+
Ok(prover) => prover,
273+
Err(e) => panic!("{:?}", e),
274+
};
275+
assert_eq!(
276+
prover.verify(),
277+
Err(vec![VerifyFailure::Gate {
278+
gate_index: 0,
279+
gate_name: "Enable flag",
280+
row: 1,
281+
}])
282+
);
283+
}
284+
}
285+
}

0 commit comments

Comments
 (0)