is_zero.rs
1 /* This file is part of DarkFi (https://dark.fi) 2 * 3 * Copyright (C) 2020-2025 Dyne.org foundation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 use halo2_proofs::{ 20 circuit::{Region, Value}, 21 pasta::group::ff::WithSmallOrderMulGroup, 22 plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, 23 poly::Rotation, 24 }; 25 26 #[derive(Clone, Debug)] 27 pub struct IsZeroConfig<F> { 28 pub value_inv: Column<Advice>, 29 pub is_zero_expr: Expression<F>, 30 } 31 32 impl<F: WithSmallOrderMulGroup<3> + Ord> IsZeroConfig<F> { 33 pub fn expr(&self) -> Expression<F> { 34 self.is_zero_expr.clone() 35 } 36 } 37 38 pub struct IsZeroChip<F: WithSmallOrderMulGroup<3> + Ord> { 39 config: IsZeroConfig<F>, 40 } 41 42 impl<F: WithSmallOrderMulGroup<3> + Ord> IsZeroChip<F> { 43 pub fn construct(config: IsZeroConfig<F>) -> Self { 44 Self { config } 45 } 46 47 pub fn configure( 48 meta: &mut ConstraintSystem<F>, 49 q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F>, 50 value: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F>, 51 value_inv: Column<Advice>, 52 ) -> IsZeroConfig<F> { 53 let mut is_zero_expr = Expression::Constant(F::ZERO); 54 55 meta.create_gate("is_zero", |meta| { 56 // 57 // valid | value | value_inv | 1 - value * value_inv | value * (1 - value* value_inv) 58 // ------+-------+------------+------------------------+------------------------------- 59 // yes | x | 1/x | 0 | 0 60 // no | x | 0 | 1 | x 61 // yes | 0 | 0 | 1 | 0 62 // yes | 0 | y | 1 | 0 63 // 64 let value = value(meta); 65 let q_enable = q_enable(meta); 66 let value_inv = meta.query_advice(value_inv, Rotation::cur()); 67 68 is_zero_expr = Expression::Constant(F::ONE) - value.clone() * value_inv; 69 vec![q_enable * value * is_zero_expr.clone()] 70 }); 71 72 IsZeroConfig { value_inv, is_zero_expr } 73 } 74 75 pub fn assign( 76 &self, 77 region: &mut Region<'_, F>, 78 offset: usize, 79 value: Value<F>, 80 ) -> Result<(), Error> { 81 let value_inv = value.map(|value| value.invert().unwrap_or(F::ZERO)); 82 region.assign_advice(|| "value inv", self.config.value_inv, offset, || value_inv)?; 83 Ok(()) 84 } 85 }