is_zero.rs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. use halo2_proofs::{
  2. arithmetic::FieldExt,
  3. circuit::{Region, Value},
  4. plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells},
  5. poly::Rotation,
  6. };
  7. #[derive(Clone, Debug)]
  8. pub struct IsZeroConfig<F> {
  9. pub value_inv: Column<Advice>,
  10. pub is_zero_expr: Expression<F>,
  11. }
  12. impl<F: FieldExt> IsZeroConfig<F> {
  13. pub fn expr(&self) -> Expression<F> {
  14. self.is_zero_expr.clone()
  15. }
  16. }
  17. pub struct IsZeroChip<F: FieldExt> {
  18. config: IsZeroConfig<F>,
  19. }
  20. impl<F: FieldExt> IsZeroChip<F> {
  21. pub fn construct(config: IsZeroConfig<F>) -> Self {
  22. Self { config }
  23. }
  24. pub fn configure(
  25. meta: &mut ConstraintSystem<F>,
  26. q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F>,
  27. value: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F>,
  28. value_inv: Column<Advice>,
  29. ) -> IsZeroConfig<F> {
  30. let mut is_zero_expr = Expression::Constant(F::zero());
  31. meta.create_gate("is_zero", |meta| {
  32. //
  33. // valid | value | value_inv | 1 - value * value_inv | value * (1 - value* value_inv)
  34. // ------+-------+------------+------------------------+-------------------------------
  35. // yes | x | 1/x | 0 | 0
  36. // no | x | 0 | 1 | x
  37. // yes | 0 | 0 | 1 | 0
  38. // yes | 0 | y | 1 | 0
  39. //
  40. let value = value(meta);
  41. let q_enable = q_enable(meta);
  42. let value_inv = meta.query_advice(value_inv, Rotation::cur());
  43. is_zero_expr = Expression::Constant(F::one()) - value.clone() * value_inv.clone();
  44. vec![q_enable * value * is_zero_expr.clone()]
  45. });
  46. IsZeroConfig { value_inv, is_zero_expr }
  47. }
  48. pub fn assign(
  49. &self,
  50. region: &mut Region<'_, F>,
  51. offset: usize,
  52. value: Value<F>,
  53. ) -> Result<(), Error> {
  54. let value_inv = value.map(|value| value.invert().unwrap_or(F::zero()));
  55. region.assign_advice(|| "value inv", self.config.value_inv, offset, || value_inv)?;
  56. Ok(())
  57. }
  58. }