#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::constraint::Constraint;
use crate::expression::{BooleanExpression, Expression};
use crate::field::{Element, Field};
use crate::gadget::Gadget;
use crate::wire::{BinaryWire, BooleanWire, Wire};
use crate::wire_values::WireValues;
use crate::witness_generator::WitnessGenerator;
pub struct GadgetBuilder<F: Field> {
next_wire_index: u32,
constraints: Vec<Constraint<F>>,
witness_generators: Vec<WitnessGenerator<F>>,
}
#[allow(clippy::new_without_default)]
impl<F: Field> GadgetBuilder<F> {
pub fn new() -> Self {
GadgetBuilder {
next_wire_index: 1,
constraints: Vec::new(),
witness_generators: Vec::new(),
}
}
pub fn wire(&mut self) -> Wire {
let index = self.next_wire_index;
self.next_wire_index += 1;
Wire { index }
}
pub fn boolean_wire(&mut self) -> BooleanWire {
let w = self.wire();
self.assert_boolean(&Expression::from(w));
BooleanWire::new_unsafe(w)
}
pub fn wires(&mut self, n: usize) -> Vec<Wire> {
(0..n).map(|_i| self.wire()).collect()
}
pub fn binary_wire(&mut self, n: usize) -> BinaryWire {
BinaryWire { bits: (0..n).map(|_i| self.boolean_wire()).collect() }
}
pub fn generator<T>(&mut self, dependencies: Vec<Wire>, generate: T)
where T: Fn(&mut WireValues<F>) + 'static {
self.witness_generators.push(WitnessGenerator::new(dependencies, generate));
}
pub fn equal(&mut self, x: &Expression<F>, y: &Expression<F>) -> BooleanExpression<F> {
self.zero(&(x - y))
}
pub fn zero(&mut self, x: &Expression<F>) -> BooleanExpression<F> {
let nonzero = self.nonzero(x);
self.not(&nonzero)
}
pub fn nonzero(&mut self, x: &Expression<F>) -> BooleanExpression<F> {
let (y, m) = (self.wire(), self.wire());
let (y_exp, m_exp) = (Expression::from(y), Expression::from(m));
self.assert_product(x, &m_exp, &y_exp);
self.assert_product(&(Expression::one() - &y_exp), x, &Expression::zero());
let x = x.clone();
self.generator(
x.dependencies(),
move |values: &mut WireValues<F>| {
let x_value = x.evaluate(values);
let y_value = if x_value.is_nonzero() {
Element::one()
} else {
Element::zero()
};
let m_value: Element<F> = if x_value.is_nonzero() {
&y_value / x_value
} else {
Element::one()
};
values.set(m, m_value);
values.set(y, y_value);
},
);
BooleanExpression::new_unsafe(y_exp)
}
pub fn selection(
&mut self, c: &BooleanExpression<F>, x: &Expression<F>, y: &Expression<F>,
) -> Expression<F> {
y + self.product(c.expression(), &(x - y))
}
pub fn assert_product(&mut self, x: &Expression<F>, y: &Expression<F>, z: &Expression<F>) {
self.constraints.push(Constraint {
a: x.clone(),
b: y.clone(),
c: z.clone(),
});
}
pub fn assert_boolean(&mut self, x: &Expression<F>) -> BooleanExpression<F> {
self.assert_product(x, &(x - Expression::one()), &Expression::zero());
BooleanExpression::new_unsafe(x.clone())
}
pub fn assert_equal(&mut self, x: &Expression<F>, y: &Expression<F>) {
self.assert_product(x, &Expression::one(), y);
}
pub fn assert_nonequal(&mut self, x: &Expression<F>, y: &Expression<F>) {
let difference = x - y;
self.assert_nonzero(&difference);
}
pub fn assert_zero(&mut self, x: &Expression<F>) {
self.assert_equal(x, &Expression::zero());
}
pub fn assert_nonzero(&mut self, x: &Expression<F>) {
self.inverse(x);
}
pub fn assert_true(&mut self, x: &BooleanExpression<F>) {
self.assert_equal(x.expression(), &Expression::one());
}
pub fn assert_false(&mut self, x: &BooleanExpression<F>) {
self.assert_equal(x.expression(), &Expression::zero());
}
pub fn build(self) -> Gadget<F> {
Gadget {
constraints: self.constraints,
witness_generators: self.witness_generators,
}
}
}
#[cfg(test)]
mod tests {
use crate::expression::{BooleanExpression, Expression};
use crate::field::Element;
use crate::gadget_builder::GadgetBuilder;
use crate::test_util::{assert_eq_false, assert_eq_true, F257};
#[test]
fn assert_binary_0_1() {
let mut builder = GadgetBuilder::<F257>::new();
let x = builder.wire();
builder.assert_boolean(&Expression::from(x));
let gadget = builder.build();
let mut values0 = values!(x => 0u8.into());
assert!(gadget.execute(&mut values0));
let mut values1 = values!(x => 1u8.into());
assert!(gadget.execute(&mut values1));
}
#[test]
fn assert_binary_2() {
let mut builder = GadgetBuilder::<F257>::new();
let x = builder.wire();
builder.assert_boolean(&Expression::from(x));
let gadget = builder.build();
let mut values2 = values!(x => 2u8.into());
assert!(!gadget.execute(&mut values2));
}
#[test]
fn selection() {
let mut builder = GadgetBuilder::<F257>::new();
let (c, x, y) = (builder.boolean_wire(), builder.wire(), builder.wire());
let selection = builder.selection(
&BooleanExpression::from(c), &Expression::from(x), &Expression::from(y));
let gadget = builder.build();
let values_3_5 = values!(x => 3u8.into(), y => 5u8.into());
let mut values_0_3_5 = values_3_5.clone();
values_0_3_5.set_boolean(c, false);
assert!(gadget.execute(&mut values_0_3_5));
assert_eq!(Element::from(5u8), selection.evaluate(&values_0_3_5));
let mut values_1_3_5 = values_3_5.clone();
values_1_3_5.set_boolean(c, true);
assert!(gadget.execute(&mut values_1_3_5));
assert_eq!(Element::from(3u8), selection.evaluate(&values_1_3_5));
}
#[test]
fn equal() {
let mut builder = GadgetBuilder::<F257>::new();
let (x, y) = (builder.wire(), builder.wire());
let equal = builder.equal(&Expression::from(x), &Expression::from(y));
let gadget = builder.build();
let mut values_7_7 = values!(x => 7u8.into(), y => 7u8.into());
assert!(gadget.execute(&mut values_7_7));
assert_eq_true(&equal, &values_7_7);
let mut values_6_7 = values!(x => 6u8.into(), y => 7u8.into());
assert!(gadget.execute(&mut values_6_7));
assert_eq_false(&equal, &values_6_7);
let mut values_7_13 = values!(x => 7u8.into(), y => 13u8.into());
assert!(gadget.execute(&mut values_7_13));
assert_eq_false(&equal, &values_7_13);
}
}