Add Univariate Domain, Vanishing Polynomial, Lagrange Interpolation (#53)

* add domain and vp

* add lagrange interpolator

* add query position to coset

* nostd

* add test assertion

* fmt

* fix test

* add Add and Sub arithmetic

* add Add and Sub arithmetic

* add unit test for mul/div arithmetic

* add more doc for clarification

* add test for native interpolate

* add test for vp constraints

* fix lagrange interpolate bug

* comment cleanup + fmt

* add CHANGELOG

* fix a compile error

* Update CHANGELOG.md

* Update CHANGELOG.md

* fix comment

* doc fix

* doc update 2

* doc update 3

* pub lagrange_interpolator

* doc fix

* rename `EvaluationDomain` to `Radix2Domain`

* tweak

* tweak

Co-authored-by: weikeng <w.k@berkeley.edu>
This commit is contained in:
Tom Shen
2021-05-10 12:12:28 -07:00
committed by GitHub
parent d1be6d1d76
commit 989f579ca8
8 changed files with 624 additions and 1 deletions

77
src/poly/domain/mod.rs Normal file
View File

@@ -0,0 +1,77 @@
use crate::boolean::Boolean;
use crate::fields::fp::FpVar;
use crate::fields::FieldVar;
use ark_ff::PrimeField;
use ark_relations::r1cs::SynthesisError;
use ark_std::vec::Vec;
pub mod vanishing_poly;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
/// Defines an evaluation domain over a prime field. The domain is a coset of size `1<<dim`.
///
/// Native code corresponds to `ark-poly::univariate::domain::radix2`, but `ark-poly` only supports
/// subgroup for now.
///
/// TODO: support cosets in `ark-poly`.
pub struct Radix2Domain<F: PrimeField> {
/// generator of subgroup g
pub gen: F,
/// index of the quotient group (i.e. the `offset`)
pub offset: F,
/// dimension of evaluation domain
pub dim: u64,
}
impl<F: PrimeField> Radix2Domain<F> {
/// order of the domain
pub fn order(&self) -> usize {
1 << self.dim
}
/// Returns g, g^2, ..., g^{dim}
fn powers_of_gen(&self, dim: usize) -> Vec<F> {
let mut result = Vec::new();
let mut cur = self.gen;
for _ in 0..dim {
result.push(cur);
cur = cur * cur;
}
result
}
/// For domain `h<g>` with dimension `n`, `position` represented by `query_pos` in big endian form,
/// returns `h*g^{position}<g^{n-query_pos.len()}>`
pub fn query_position_to_coset(
&self,
query_pos: &[Boolean<F>],
coset_dim: u64,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
let mut coset_index = query_pos;
assert!(
query_pos.len() == self.dim as usize
|| query_pos.len() == (self.dim - coset_dim) as usize
);
if query_pos.len() == self.dim as usize {
coset_index = &coset_index[0..(coset_index.len() - coset_dim as usize)];
}
let mut coset = Vec::new();
let powers_of_g = &self.powers_of_gen(self.dim as usize)[(coset_dim as usize)..];
let mut first_point_in_coset: FpVar<F> = FpVar::zero();
for i in 0..coset_index.len() {
let term = coset_index[i].select(&FpVar::constant(powers_of_g[i]), &FpVar::zero())?;
first_point_in_coset += &term;
}
first_point_in_coset *= &FpVar::Constant(self.offset);
coset.push(first_point_in_coset);
for i in 1..(1 << (coset_dim as usize)) {
let new_elem = &coset[i - 1] * &FpVar::Constant(self.gen);
coset.push(new_elem);
}
Ok(coset)
}
}