ark_r1cs_std/poly/domain/
mod.rsuse crate::{
boolean::Boolean,
eq::EqGadget,
fields::{fp::FpVar, FieldVar},
};
use ark_ff::PrimeField;
use ark_relations::r1cs::SynthesisError;
use ark_std::vec::Vec;
pub mod vanishing_poly;
#[derive(Clone, Debug)]
pub struct Radix2DomainVar<F: PrimeField> {
pub gen: F,
offset: FpVar<F>,
pub dim: u64,
}
impl<F: PrimeField> Radix2DomainVar<F> {
pub fn new(gen: F, dimension: u64, offset: FpVar<F>) -> Result<Self, SynthesisError> {
offset.enforce_not_equal(&FpVar::zero())?;
Ok(Self {
gen,
offset,
dim: dimension,
})
}
pub fn offset(&self) -> &FpVar<F> {
&self.offset
}
}
impl<F: PrimeField> EqGadget<F> for Radix2DomainVar<F> {
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
if self.gen != other.gen || self.dim != other.dim {
Ok(Boolean::FALSE)
} else {
self.offset.is_eq(&other.offset)
}
}
}
impl<F: PrimeField> Radix2DomainVar<F> {
pub fn order(&self) -> usize {
1 << self.dim
}
pub fn elements(&self) -> Vec<FpVar<F>> {
let mut result = Vec::new();
result.push(self.offset.clone());
for _ in 1..(1 << self.dim) {
let new_element = result.last().unwrap() * self.gen;
result.push(new_element);
}
result
}
pub fn size(&self) -> u64 {
1 << self.dim
}
pub fn query_position_to_coset_elements(
&self,
query_pos: &[Boolean<F>],
coset_dim: u64,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
Ok(self
.query_position_to_coset(query_pos, coset_dim)?
.elements())
}
pub fn query_position_to_coset(
&self,
query_pos: &[Boolean<F>],
coset_dim: u64,
) -> Result<Self, SynthesisError> {
let coset_index = truncate_to_coset_index(query_pos, self.dim, coset_dim);
let offset_var = &self.offset * FpVar::Constant(self.gen).pow_le(&coset_index)?;
Ok(Self {
gen: self.gen.pow(&[1 << (self.dim - coset_dim)]), offset: offset_var,
dim: coset_dim,
})
}
}
fn truncate_to_coset_index<F: PrimeField>(
query_pos: &[Boolean<F>],
codeword_dim: u64,
coset_dim: u64,
) -> Vec<Boolean<F>> {
let log2_num_cosets = (codeword_dim - coset_dim) as usize;
assert!(query_pos.len() >= log2_num_cosets);
query_pos[0..log2_num_cosets].to_vec()
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use ark_ff::PrimeField;
use ark_relations::r1cs::ConstraintSystem;
use ark_std::{rand::Rng, test_rng};
use crate::{
alloc::AllocVar, convert::ToBitsGadget, fields::fp::FpVar, poly::domain::Radix2DomainVar,
R1CSVar,
};
fn test_query_coset_template<F: PrimeField>() {
const COSET_DIM: u64 = 7;
const COSET_SIZE: u64 = 1 << COSET_DIM;
const LOCALIZATION: u64 = 3;
let cs = ConstraintSystem::new_ref();
let mut rng = test_rng();
let gen = F::get_root_of_unity(COSET_SIZE).unwrap();
let offset = F::rand(&mut rng);
let offset_var = FpVar::new_witness(cs.clone(), || Ok(offset)).unwrap();
let domain = Radix2DomainVar::new(gen, COSET_DIM, offset_var).unwrap();
let num_cosets = 1 << (COSET_DIM - LOCALIZATION);
let coset_index = rng.gen_range(0..num_cosets);
println!("{:0b}", coset_index);
let coset_index_var = UInt32::new_witness(cs.clone(), || Ok(coset_index))
.unwrap()
.to_bits_le()
.unwrap()
.into_iter()
.take(COSET_DIM as usize)
.collect::<Vec<_>>();
let elements_actual = domain
.query_position_to_coset(&coset_index_var, LOCALIZATION)
.unwrap()
.elements();
let elements_expected = domain
.elements()
.into_iter()
.skip(coset_index as usize)
.step_by(1 << (COSET_DIM - LOCALIZATION))
.collect::<Vec<_>>();
assert_eq!(elements_expected.len(), elements_actual.len());
elements_expected
.into_iter()
.zip(elements_actual.into_iter())
.for_each(|(left, right)| {
assert_eq!(left.value().unwrap(), right.value().unwrap());
});
}
#[test]
fn test_on_bls12_381() {
test_query_coset_template::<ark_bls12_381::Fr>();
}
#[test]
fn test_on_bls12_377() {
test_query_coset_template::<ark_bls12_377::Fr>();
}
}