arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/poly/domain/mod.rs
src/poly/domain/mod.rsRaw
  1use crate::boolean::Boolean;
  2use crate::eq::EqGadget;
  3use crate::fields::fp::FpVar;
  4use crate::fields::FieldVar;
  5use ark_ff::PrimeField;
  6use ark_relations::r1cs::SynthesisError;
  7use ark_std::vec::Vec;
  8
  9pub mod vanishing_poly;
 10
 11#[derive(Clone, Debug)]
 12/// Defines an evaluation domain over a prime field. The domain is a coset of size `1<<dim`.
 13///
 14/// Native code corresponds to `ark-poly::univariate::domain::radix2`, but `ark-poly` only supports
 15/// subgroup for now.
 16///
 17// TODO: support cosets in `ark-poly`.
 18pub struct Radix2DomainVar<F: PrimeField> {
 19    /// generator of subgroup g
 20    pub gen: F,
 21    /// index of the quotient group (i.e. the `offset`)
 22    offset: FpVar<F>,
 23    /// dimension of evaluation domain
 24    pub dim: u64,
 25}
 26impl<F: PrimeField> Radix2DomainVar<F> {
 27    /// Construct an evaluation domain with the given offset.
 28    pub fn new(gen: F, dimension: u64, offset: FpVar<F>) -> Result<Self, SynthesisError> {
 29        offset.enforce_not_equal(&FpVar::zero())?;
 30        Ok(Self {
 31            gen,
 32            offset,
 33            dim: dimension,
 34        })
 35    }
 36
 37    /// What is the offset of `self`?
 38    pub fn offset(&self) -> &FpVar<F> {
 39        &self.offset
 40    }
 41}
 42
 43impl<F: PrimeField> EqGadget<F> for Radix2DomainVar<F> {
 44    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 45        if self.gen != other.gen || self.dim != other.dim {
 46            Ok(Boolean::constant(false))
 47        } else {
 48            self.offset.is_eq(&other.offset)
 49        }
 50    }
 51}
 52
 53impl<F: PrimeField> Radix2DomainVar<F> {
 54    /// order of the domain
 55    pub fn order(&self) -> usize {
 56        1 << self.dim
 57    }
 58
 59    /// Returns g, g^2, ..., g^{dim}
 60    fn powers_of_gen(&self, dim: usize) -> Vec<F> {
 61        let mut result = Vec::new();
 62        let mut cur = self.gen;
 63        for _ in 0..dim {
 64            result.push(cur);
 65            cur = cur * cur;
 66        }
 67        result
 68    }
 69
 70    /// Size of the domain
 71    pub fn size(&self) -> u64 {
 72        1 << self.dim
 73    }
 74
 75    /// For domain `h<g>` with dimension `n`, `position` represented by `query_pos` in big endian form,
 76    /// returns `h*g^{position}<g^{n-query_pos.len()}>`
 77    pub fn query_position_to_coset(
 78        &self,
 79        query_pos: &[Boolean<F>],
 80        coset_dim: u64,
 81    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 82        let mut coset_index = query_pos;
 83        assert!(
 84            query_pos.len() == self.dim as usize
 85                || query_pos.len() == (self.dim - coset_dim) as usize
 86        );
 87        if query_pos.len() == self.dim as usize {
 88            coset_index = &coset_index[0..(coset_index.len() - coset_dim as usize)];
 89        }
 90        let mut coset = Vec::new();
 91        let powers_of_g = &self.powers_of_gen(self.dim as usize)[(coset_dim as usize)..];
 92
 93        let mut first_point_in_coset: FpVar<F> = FpVar::zero();
 94        for i in 0..coset_index.len() {
 95            let term = coset_index[i].select(&FpVar::constant(powers_of_g[i]), &FpVar::zero())?;
 96            first_point_in_coset += &term;
 97        }
 98
 99        first_point_in_coset *= &self.offset;
100
101        coset.push(first_point_in_coset);
102        for i in 1..(1 << (coset_dim as usize)) {
103            let new_elem = &coset[i - 1] * &FpVar::Constant(self.gen);
104            coset.push(new_elem);
105        }
106
107        Ok(coset)
108    }
109}