use crate::utils::chunks_count;
use ark_ff::PrimeField;
use ark_r1cs_std::{
fields::fp::FpVar,
prelude::{AllocVar, AllocationMode, Boolean, EqGadget},
ToBitsGadget,
};
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
use ark_std::vec::Vec;
#[derive(Clone)]
pub struct BitsizeCheckCircuit<F: PrimeField> {
pub required_bit_size: u8,
pub num_values: u8,
pub values: Option<Vec<F>>,
pub alloc_as_public: bool,
}
impl<F: PrimeField> BitsizeCheckCircuit<F> {
pub fn new(
required_bit_size: u8,
num_values: Option<u8>,
values: Option<Vec<F>>,
alloc_as_public: bool,
) -> Self {
let num_values = if num_values.is_some() {
num_values.unwrap()
} else {
chunks_count::<F>(required_bit_size)
};
Self {
required_bit_size,
num_values,
values,
alloc_as_public,
}
}
}
impl<ConstraintF: PrimeField> ConstraintSynthesizer<ConstraintF>
for BitsizeCheckCircuit<ConstraintF>
{
fn generate_constraints(
self,
cs: ConstraintSystemRef<ConstraintF>,
) -> Result<(), SynthesisError> {
let values = match self.values {
Some(vals) => vals.into_iter().map(|v| Some(v)).collect::<Vec<_>>(),
_ => (0..self.num_values).map(|_| None).collect::<Vec<_>>(),
};
let mut vars = Vec::with_capacity(values.len());
for value in values {
vars.push(FpVar::new_variable(
cs.clone(),
|| value.ok_or(SynthesisError::AssignmentMissing),
if self.alloc_as_public {
AllocationMode::Input
} else {
AllocationMode::Witness
},
)?);
}
for v in vars {
let bits = v.to_non_unique_bits_le()?;
let mut or_result = Boolean::constant(false);
for b in bits[self.required_bit_size as usize..].iter() {
or_result = or_result.or(b)?;
}
or_result.enforce_equal(&Boolean::constant(false))?;
}
Ok(())
}
}