mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 07:13:08 +00:00
Merge pull request #48 from mir-protocol/target_field_extension
Clean extension code + Recursive interpolation gate
This commit is contained in:
commit
5a261332d9
@ -1,16 +1,43 @@
|
||||
use crate::field::extension_field::quadratic::QuadraticFieldExtension;
|
||||
use crate::field::extension_field::quartic::QuarticFieldExtension;
|
||||
use crate::field::field::Field;
|
||||
|
||||
pub mod quadratic;
|
||||
pub mod quartic;
|
||||
pub mod target;
|
||||
|
||||
/// Optimal extension field trait.
|
||||
/// A degree `d` field extension is optimal if there exists a base field element `W`,
|
||||
/// such that the extension is `F[X]/(X^d-W)`.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait OEF<const D: usize>: FieldExtension<D> {
|
||||
// Element W of BaseField, such that `X^d - W` is irreducible over BaseField.
|
||||
const W: Self::BaseField;
|
||||
|
||||
/// Frobenius automorphisms: x -> x^p, where p is the order of BaseField.
|
||||
fn frobenius(&self) -> Self {
|
||||
let arr = self.to_basefield_array();
|
||||
let k = (Self::BaseField::ORDER - 1) / (D as u64);
|
||||
let z0 = Self::W.exp(k);
|
||||
let mut z = Self::BaseField::ONE;
|
||||
let mut res = [Self::BaseField::ZERO; D];
|
||||
for i in 0..D {
|
||||
res[i] = arr[i] * z;
|
||||
z *= z0;
|
||||
}
|
||||
|
||||
Self::from_basefield_array(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> OEF<1> for F {
|
||||
const W: Self::BaseField = F::ZERO;
|
||||
}
|
||||
|
||||
pub trait Extendable<const D: usize>: Sized {
|
||||
type Extension: Field + FieldExtension<D, BaseField = Self> + From<Self>;
|
||||
type Extension: Field + OEF<D, BaseField = Self> + From<Self>;
|
||||
}
|
||||
|
||||
impl<F: Field> Extendable<1> for F {
|
||||
type Extension = Self;
|
||||
type Extension = F;
|
||||
}
|
||||
|
||||
pub trait FieldExtension<const D: usize>: Field {
|
||||
@ -21,6 +48,10 @@ pub trait FieldExtension<const D: usize>: Field {
|
||||
fn from_basefield_array(arr: [Self::BaseField; D]) -> Self;
|
||||
|
||||
fn from_basefield(x: Self::BaseField) -> Self;
|
||||
|
||||
fn is_in_basefield(&self) -> bool {
|
||||
self.to_basefield_array()[1..].iter().all(|x| x.is_zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> FieldExtension<1> for F {
|
||||
@ -39,38 +70,6 @@ impl<F: Field> FieldExtension<1> for F {
|
||||
}
|
||||
}
|
||||
|
||||
impl<FE: QuadraticFieldExtension> FieldExtension<2> for FE {
|
||||
type BaseField = FE::BaseField;
|
||||
|
||||
fn to_basefield_array(&self) -> [Self::BaseField; 2] {
|
||||
self.to_canonical_representation()
|
||||
}
|
||||
|
||||
fn from_basefield_array(arr: [Self::BaseField; 2]) -> Self {
|
||||
Self::from_canonical_representation(arr)
|
||||
}
|
||||
|
||||
fn from_basefield(x: Self::BaseField) -> Self {
|
||||
x.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<FE: QuarticFieldExtension> FieldExtension<4> for FE {
|
||||
type BaseField = FE::BaseField;
|
||||
|
||||
fn to_basefield_array(&self) -> [Self::BaseField; 4] {
|
||||
self.to_canonical_representation()
|
||||
}
|
||||
|
||||
fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self {
|
||||
Self::from_canonical_representation(arr)
|
||||
}
|
||||
|
||||
fn from_basefield(x: Self::BaseField) -> Self {
|
||||
x.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Flatten the slice by sending every extension field element to its D-sized canonical representation.
|
||||
pub fn flatten<F: Field, const D: usize>(l: &[F::Extension]) -> Vec<F>
|
||||
where
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::field::crandall_field::CrandallField;
|
||||
use crate::field::extension_field::{FieldExtension, OEF};
|
||||
use crate::field::field::Field;
|
||||
use rand::Rng;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
@ -6,61 +7,41 @@ use std::hash::{Hash, Hasher};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
pub trait QuadraticFieldExtension:
|
||||
Field + From<<Self as QuadraticFieldExtension>::BaseField>
|
||||
{
|
||||
type BaseField: Field;
|
||||
|
||||
// Element W of BaseField, such that `X^2 - W` is irreducible over BaseField.
|
||||
const W: Self::BaseField;
|
||||
|
||||
fn to_canonical_representation(&self) -> [Self::BaseField; 2];
|
||||
|
||||
fn from_canonical_representation(v: [Self::BaseField; 2]) -> Self;
|
||||
|
||||
fn is_in_basefield(&self) -> bool {
|
||||
self.to_canonical_representation()[1..]
|
||||
.iter()
|
||||
.all(|x| x.is_zero())
|
||||
}
|
||||
|
||||
/// Frobenius automorphisms: x -> x^p, where p is the order of BaseField.
|
||||
fn frobenius(&self) -> Self {
|
||||
let [a0, a1] = self.to_canonical_representation();
|
||||
let k = (Self::BaseField::ORDER - 1) / 2;
|
||||
let z = Self::W.exp(k);
|
||||
|
||||
Self::from_canonical_representation([a0, a1 * z])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct QuadraticCrandallField([CrandallField; 2]);
|
||||
|
||||
impl QuadraticFieldExtension for QuadraticCrandallField {
|
||||
type BaseField = CrandallField;
|
||||
impl OEF<2> for QuadraticCrandallField {
|
||||
// Verifiable in Sage with
|
||||
// ``R.<x> = GF(p)[]; assert (x^2 -3).is_irreducible()`.
|
||||
const W: Self::BaseField = CrandallField(3);
|
||||
const W: CrandallField = CrandallField(3);
|
||||
}
|
||||
|
||||
fn to_canonical_representation(&self) -> [Self::BaseField; 2] {
|
||||
impl FieldExtension<2> for QuadraticCrandallField {
|
||||
type BaseField = CrandallField;
|
||||
|
||||
fn to_basefield_array(&self) -> [Self::BaseField; 2] {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn from_canonical_representation(v: [Self::BaseField; 2]) -> Self {
|
||||
Self(v)
|
||||
fn from_basefield_array(arr: [Self::BaseField; 2]) -> Self {
|
||||
Self(arr)
|
||||
}
|
||||
|
||||
fn from_basefield(x: Self::BaseField) -> Self {
|
||||
x.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<<Self as QuadraticFieldExtension>::BaseField> for QuadraticCrandallField {
|
||||
fn from(x: <Self as QuadraticFieldExtension>::BaseField) -> Self {
|
||||
Self([x, <Self as QuadraticFieldExtension>::BaseField::ZERO])
|
||||
impl From<<Self as FieldExtension<2>>::BaseField> for QuadraticCrandallField {
|
||||
fn from(x: <Self as FieldExtension<2>>::BaseField) -> Self {
|
||||
Self([x, <Self as FieldExtension<2>>::BaseField::ZERO])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for QuadraticCrandallField {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.to_canonical_representation() == other.to_canonical_representation()
|
||||
FieldExtension::<2>::to_basefield_array(self)
|
||||
== FieldExtension::<2>::to_basefield_array(other)
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +49,7 @@ impl Eq for QuadraticCrandallField {}
|
||||
|
||||
impl Hash for QuadraticCrandallField {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
for l in &self.to_canonical_representation() {
|
||||
for l in &FieldExtension::<2>::to_basefield_array(self) {
|
||||
Hash::hash(l, state);
|
||||
}
|
||||
}
|
||||
@ -99,9 +80,9 @@ impl Field for QuadraticCrandallField {
|
||||
return None;
|
||||
}
|
||||
|
||||
let a_pow_r_minus_1 = self.frobenius();
|
||||
let a_pow_r_minus_1 = OEF::<2>::frobenius(self);
|
||||
let a_pow_r = a_pow_r_minus_1 * *self;
|
||||
debug_assert!(a_pow_r.is_in_basefield());
|
||||
debug_assert!(FieldExtension::<2>::is_in_basefield(&a_pow_r));
|
||||
|
||||
Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into())
|
||||
}
|
||||
@ -111,16 +92,13 @@ impl Field for QuadraticCrandallField {
|
||||
}
|
||||
|
||||
fn from_canonical_u64(n: u64) -> Self {
|
||||
Self([
|
||||
<Self as QuadraticFieldExtension>::BaseField::from_canonical_u64(n),
|
||||
<Self as QuadraticFieldExtension>::BaseField::ZERO,
|
||||
])
|
||||
<Self as FieldExtension<2>>::BaseField::from_canonical_u64(n).into()
|
||||
}
|
||||
|
||||
fn rand_from_rng<R: Rng>(rng: &mut R) -> Self {
|
||||
Self([
|
||||
<Self as QuadraticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as QuadraticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<2>>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<2>>::BaseField::rand_from_rng(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
@ -191,7 +169,7 @@ impl Mul for QuadraticCrandallField {
|
||||
let Self([a0, a1]) = self;
|
||||
let Self([b0, b1]) = rhs;
|
||||
|
||||
let c0 = a0 * b0 + Self::W * a1 * b1;
|
||||
let c0 = a0 * b0 + <Self as OEF<2>>::W * a1 * b1;
|
||||
let c1 = a0 * b1 + a1 * b0;
|
||||
|
||||
Self([c0, c1])
|
||||
@ -228,9 +206,8 @@ impl DivAssign for QuadraticCrandallField {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::field::extension_field::quadratic::{
|
||||
QuadraticCrandallField, QuadraticFieldExtension,
|
||||
};
|
||||
use crate::field::extension_field::quadratic::QuadraticCrandallField;
|
||||
use crate::field::extension_field::{FieldExtension, OEF};
|
||||
use crate::field::field::Field;
|
||||
|
||||
#[test]
|
||||
@ -241,10 +218,7 @@ mod tests {
|
||||
let z = F::rand();
|
||||
assert_eq!(x + (-x), F::ZERO);
|
||||
assert_eq!(-x, F::ZERO - x);
|
||||
assert_eq!(
|
||||
x + x,
|
||||
x * <F as QuadraticFieldExtension>::BaseField::TWO.into()
|
||||
);
|
||||
assert_eq!(x + x, x * <F as FieldExtension<2>>::BaseField::TWO.into());
|
||||
assert_eq!(x * (-x), -x.square());
|
||||
assert_eq!(x + y, y + x);
|
||||
assert_eq!(x * y, y * x);
|
||||
@ -273,8 +247,8 @@ mod tests {
|
||||
type F = QuadraticCrandallField;
|
||||
let x = F::rand();
|
||||
assert_eq!(
|
||||
x.exp(<F as QuadraticFieldExtension>::BaseField::ORDER),
|
||||
x.frobenius()
|
||||
x.exp(<F as FieldExtension<2>>::BaseField::ORDER),
|
||||
OEF::<2>::frobenius(&x)
|
||||
);
|
||||
}
|
||||
|
||||
@ -300,10 +274,9 @@ mod tests {
|
||||
F::POWER_OF_TWO_GENERATOR
|
||||
);
|
||||
assert_eq!(
|
||||
F::POWER_OF_TWO_GENERATOR.exp(
|
||||
1 << (F::TWO_ADICITY - <F as QuadraticFieldExtension>::BaseField::TWO_ADICITY)
|
||||
),
|
||||
<F as QuadraticFieldExtension>::BaseField::POWER_OF_TWO_GENERATOR.into()
|
||||
F::POWER_OF_TWO_GENERATOR
|
||||
.exp(1 << (F::TWO_ADICITY - <F as FieldExtension<2>>::BaseField::TWO_ADICITY)),
|
||||
<F as FieldExtension<2>>::BaseField::POWER_OF_TWO_GENERATOR.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::field::crandall_field::CrandallField;
|
||||
use crate::field::extension_field::{FieldExtension, OEF};
|
||||
use crate::field::field::Field;
|
||||
use rand::Rng;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
@ -6,72 +7,46 @@ use std::hash::{Hash, Hasher};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
pub trait QuarticFieldExtension: Field + From<<Self as QuarticFieldExtension>::BaseField> {
|
||||
type BaseField: Field;
|
||||
|
||||
// Element W of BaseField, such that `X^4 - W` is irreducible over BaseField.
|
||||
const W: Self::BaseField;
|
||||
|
||||
fn to_canonical_representation(&self) -> [Self::BaseField; 4];
|
||||
|
||||
fn from_canonical_representation(v: [Self::BaseField; 4]) -> Self;
|
||||
|
||||
fn is_in_basefield(&self) -> bool {
|
||||
self.to_canonical_representation()[1..]
|
||||
.iter()
|
||||
.all(|x| x.is_zero())
|
||||
}
|
||||
|
||||
/// Frobenius automorphisms: x -> x^p, where p is the order of BaseField.
|
||||
fn frobenius(&self) -> Self {
|
||||
let [a0, a1, a2, a3] = self.to_canonical_representation();
|
||||
let k = (Self::BaseField::ORDER - 1) / 4;
|
||||
let z0 = Self::W.exp(k);
|
||||
let mut z = Self::BaseField::ONE;
|
||||
let b0 = a0 * z;
|
||||
z *= z0;
|
||||
let b1 = a1 * z;
|
||||
z *= z0;
|
||||
let b2 = a2 * z;
|
||||
z *= z0;
|
||||
let b3 = a3 * z;
|
||||
|
||||
Self::from_canonical_representation([b0, b1, b2, b3])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct QuarticCrandallField([CrandallField; 4]);
|
||||
|
||||
impl QuarticFieldExtension for QuarticCrandallField {
|
||||
type BaseField = CrandallField;
|
||||
impl OEF<4> for QuarticCrandallField {
|
||||
// Verifiable in Sage with
|
||||
// ``R.<x> = GF(p)[]; assert (x^4 -3).is_irreducible()`.
|
||||
const W: Self::BaseField = CrandallField(3);
|
||||
const W: CrandallField = CrandallField(3);
|
||||
}
|
||||
|
||||
fn to_canonical_representation(&self) -> [Self::BaseField; 4] {
|
||||
impl FieldExtension<4> for QuarticCrandallField {
|
||||
type BaseField = CrandallField;
|
||||
|
||||
fn to_basefield_array(&self) -> [Self::BaseField; 4] {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn from_canonical_representation(v: [Self::BaseField; 4]) -> Self {
|
||||
Self(v)
|
||||
fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self {
|
||||
Self(arr)
|
||||
}
|
||||
|
||||
fn from_basefield(x: Self::BaseField) -> Self {
|
||||
x.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<<Self as QuarticFieldExtension>::BaseField> for QuarticCrandallField {
|
||||
fn from(x: <Self as QuarticFieldExtension>::BaseField) -> Self {
|
||||
impl From<<Self as FieldExtension<4>>::BaseField> for QuarticCrandallField {
|
||||
fn from(x: <Self as FieldExtension<4>>::BaseField) -> Self {
|
||||
Self([
|
||||
x,
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for QuarticCrandallField {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.to_canonical_representation() == other.to_canonical_representation()
|
||||
FieldExtension::<4>::to_basefield_array(self)
|
||||
== FieldExtension::<4>::to_basefield_array(other)
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +54,7 @@ impl Eq for QuarticCrandallField {}
|
||||
|
||||
impl Hash for QuarticCrandallField {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
for l in &self.to_canonical_representation() {
|
||||
for l in &FieldExtension::<4>::to_basefield_array(self) {
|
||||
Hash::hash(l, state);
|
||||
}
|
||||
}
|
||||
@ -131,12 +106,12 @@ impl Field for QuarticCrandallField {
|
||||
return None;
|
||||
}
|
||||
|
||||
let a_pow_p = self.frobenius();
|
||||
let a_pow_p = OEF::<4>::frobenius(self);
|
||||
let a_pow_p_plus_1 = a_pow_p * *self;
|
||||
let a_pow_p3_plus_p2 = a_pow_p_plus_1.frobenius().frobenius();
|
||||
let a_pow_p3_plus_p2 = OEF::<4>::frobenius(&OEF::<4>::frobenius(&a_pow_p_plus_1));
|
||||
let a_pow_r_minus_1 = a_pow_p3_plus_p2 * a_pow_p;
|
||||
let a_pow_r = a_pow_r_minus_1 * *self;
|
||||
debug_assert!(a_pow_r.is_in_basefield());
|
||||
debug_assert!(FieldExtension::<4>::is_in_basefield(&a_pow_r));
|
||||
|
||||
Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into())
|
||||
}
|
||||
@ -146,20 +121,15 @@ impl Field for QuarticCrandallField {
|
||||
}
|
||||
|
||||
fn from_canonical_u64(n: u64) -> Self {
|
||||
Self([
|
||||
<Self as QuarticFieldExtension>::BaseField::from_canonical_u64(n),
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
<Self as QuarticFieldExtension>::BaseField::ZERO,
|
||||
])
|
||||
<Self as FieldExtension<4>>::BaseField::from_canonical_u64(n).into()
|
||||
}
|
||||
|
||||
fn rand_from_rng<R: Rng>(rng: &mut R) -> Self {
|
||||
Self([
|
||||
<Self as QuarticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as QuarticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as QuarticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as QuarticFieldExtension>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
@ -244,9 +214,9 @@ impl Mul for QuarticCrandallField {
|
||||
let Self([a0, a1, a2, a3]) = self;
|
||||
let Self([b0, b1, b2, b3]) = rhs;
|
||||
|
||||
let c0 = a0 * b0 + Self::W * (a1 * b3 + a2 * b2 + a3 * b1);
|
||||
let c1 = a0 * b1 + a1 * b0 + Self::W * (a2 * b3 + a3 * b2);
|
||||
let c2 = a0 * b2 + a1 * b1 + a2 * b0 + Self::W * a3 * b3;
|
||||
let c0 = a0 * b0 + <Self as OEF<4>>::W * (a1 * b3 + a2 * b2 + a3 * b1);
|
||||
let c1 = a0 * b1 + a1 * b0 + <Self as OEF<4>>::W * (a2 * b3 + a3 * b2);
|
||||
let c2 = a0 * b2 + a1 * b1 + a2 * b0 + <Self as OEF<4>>::W * a3 * b3;
|
||||
let c3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
|
||||
Self([c0, c1, c2, c3])
|
||||
@ -283,7 +253,8 @@ impl DivAssign for QuarticCrandallField {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::field::extension_field::quartic::{QuarticCrandallField, QuarticFieldExtension};
|
||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||
use crate::field::extension_field::{FieldExtension, OEF};
|
||||
use crate::field::field::Field;
|
||||
|
||||
fn exp_naive<F: Field>(x: F, power: u128) -> F {
|
||||
@ -307,10 +278,7 @@ mod tests {
|
||||
let z = F::rand();
|
||||
assert_eq!(x + (-x), F::ZERO);
|
||||
assert_eq!(-x, F::ZERO - x);
|
||||
assert_eq!(
|
||||
x + x,
|
||||
x * <F as QuarticFieldExtension>::BaseField::TWO.into()
|
||||
);
|
||||
assert_eq!(x + x, x * <F as FieldExtension<4>>::BaseField::TWO.into());
|
||||
assert_eq!(x * (-x), -x.square());
|
||||
assert_eq!(x + y, y + x);
|
||||
assert_eq!(x * y, y * x);
|
||||
@ -339,8 +307,8 @@ mod tests {
|
||||
type F = QuarticCrandallField;
|
||||
let x = F::rand();
|
||||
assert_eq!(
|
||||
exp_naive(x, <F as QuarticFieldExtension>::BaseField::ORDER as u128),
|
||||
x.frobenius()
|
||||
exp_naive(x, <F as FieldExtension<4>>::BaseField::ORDER as u128),
|
||||
OEF::<4>::frobenius(&x)
|
||||
);
|
||||
}
|
||||
|
||||
@ -374,8 +342,8 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
F::POWER_OF_TWO_GENERATOR
|
||||
.exp(1 << (F::TWO_ADICITY - <F as QuarticFieldExtension>::BaseField::TWO_ADICITY)),
|
||||
<F as QuarticFieldExtension>::BaseField::POWER_OF_TWO_GENERATOR.into()
|
||||
.exp(1 << (F::TWO_ADICITY - <F as FieldExtension<4>>::BaseField::TWO_ADICITY)),
|
||||
<F as FieldExtension<4>>::BaseField::POWER_OF_TWO_GENERATOR.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
88
src/field/extension_field/target.rs
Normal file
88
src/field/extension_field/target.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use crate::circuit_builder::CircuitBuilder;
|
||||
use crate::field::extension_field::{Extendable, FieldExtension, OEF};
|
||||
use crate::field::field::Field;
|
||||
use crate::target::Target;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ExtensionTarget<const D: usize>(pub [Target; D]);
|
||||
|
||||
impl<const D: usize> ExtensionTarget<D> {
|
||||
pub fn to_target_array(&self) -> [Target; D] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> CircuitBuilder<F> {
|
||||
pub fn zero_extension<const D: usize>(&mut self) -> ExtensionTarget<D>
|
||||
where
|
||||
F: Extendable<D>,
|
||||
{
|
||||
ExtensionTarget([self.zero(); D])
|
||||
}
|
||||
|
||||
pub fn add_extension<const D: usize>(
|
||||
&mut self,
|
||||
mut a: ExtensionTarget<D>,
|
||||
b: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D>
|
||||
where
|
||||
F: Extendable<D>,
|
||||
{
|
||||
for i in 0..D {
|
||||
a.0[i] = self.add(a.0[i], b.0[i]);
|
||||
}
|
||||
a
|
||||
}
|
||||
|
||||
pub fn sub_extension<const D: usize>(
|
||||
&mut self,
|
||||
mut a: ExtensionTarget<D>,
|
||||
b: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D>
|
||||
where
|
||||
F: Extendable<D>,
|
||||
{
|
||||
for i in 0..D {
|
||||
a.0[i] = self.sub(a.0[i], b.0[i]);
|
||||
}
|
||||
a
|
||||
}
|
||||
|
||||
pub fn mul_extension<const D: usize>(
|
||||
&mut self,
|
||||
a: ExtensionTarget<D>,
|
||||
b: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D>
|
||||
where
|
||||
F: Extendable<D>,
|
||||
{
|
||||
let w = self.constant(F::Extension::W);
|
||||
let mut res = [self.zero(); D];
|
||||
for i in 0..D {
|
||||
for j in 0..D {
|
||||
res[(i + j) % D] = if i + j < D {
|
||||
self.mul_add(a.0[i], b.0[j], res[(i + j) % D])
|
||||
} else {
|
||||
let tmp = self.mul(a.0[i], b.0[j]);
|
||||
self.mul_add(w, tmp, res[(i + j) % D])
|
||||
}
|
||||
}
|
||||
}
|
||||
ExtensionTarget(res)
|
||||
}
|
||||
|
||||
/// Returns a*b where `b` is in the extension field and `a` is in the base field.
|
||||
pub fn scalar_mul<const D: usize>(
|
||||
&mut self,
|
||||
a: Target,
|
||||
mut b: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D>
|
||||
where
|
||||
F: Extendable<D>,
|
||||
{
|
||||
for i in 0..D {
|
||||
b.0[i] = self.mul(a, b.0[i]);
|
||||
}
|
||||
b
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod arithmetic;
|
||||
pub mod hash;
|
||||
pub mod polynomial;
|
||||
pub(crate) mod split_join;
|
||||
|
||||
35
src/gadgets/polynomial.rs
Normal file
35
src/gadgets/polynomial.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use crate::circuit_builder::CircuitBuilder;
|
||||
use crate::field::extension_field::target::ExtensionTarget;
|
||||
use crate::field::extension_field::Extendable;
|
||||
use crate::field::field::Field;
|
||||
use crate::target::Target;
|
||||
|
||||
pub struct PolynomialCoeffsTarget<const D: usize>(pub Vec<ExtensionTarget<D>>);
|
||||
|
||||
impl<const D: usize> PolynomialCoeffsTarget<D> {
|
||||
pub fn eval_scalar<F: Field + Extendable<D>>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F>,
|
||||
point: Target,
|
||||
) -> ExtensionTarget<D> {
|
||||
let mut acc = builder.zero_extension();
|
||||
for &c in self.0.iter().rev() {
|
||||
let tmp = builder.scalar_mul(point, acc);
|
||||
acc = builder.add_extension(tmp, c);
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
pub fn eval<F: Field + Extendable<D>>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F>,
|
||||
point: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D> {
|
||||
let mut acc = builder.zero_extension();
|
||||
for &c in self.0.iter().rev() {
|
||||
let tmp = builder.mul_extension(point, acc);
|
||||
acc = builder.add_extension(tmp, c);
|
||||
}
|
||||
acc
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ use crate::circuit_builder::CircuitBuilder;
|
||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||
use crate::field::field::Field;
|
||||
use crate::field::lagrange::interpolant;
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsTarget;
|
||||
use crate::gates::gate::{Gate, GateRef};
|
||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||
@ -125,7 +126,34 @@ impl<F: Field + Extendable<D>, const D: usize> Gate<F> for InterpolationGate<F,
|
||||
builder: &mut CircuitBuilder<F>,
|
||||
vars: EvaluationTargets,
|
||||
) -> Vec<Target> {
|
||||
todo!()
|
||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
||||
|
||||
let coeffs = (0..self.num_points)
|
||||
.map(|i| vars.get_local_ext(self.wires_coeff(i)))
|
||||
.collect();
|
||||
let interpolant = PolynomialCoeffsTarget(coeffs);
|
||||
|
||||
for i in 0..self.num_points {
|
||||
let point = vars.local_wires[self.wire_point(i)];
|
||||
let value = vars.get_local_ext(self.wires_value(i));
|
||||
let computed_value = interpolant.eval_scalar(builder, point);
|
||||
constraints.extend(
|
||||
&builder
|
||||
.sub_extension(value, computed_value)
|
||||
.to_target_array(),
|
||||
);
|
||||
}
|
||||
|
||||
let evaluation_point = vars.get_local_ext(self.wires_evaluation_point());
|
||||
let evaluation_value = vars.get_local_ext(self.wires_evaluation_value());
|
||||
let computed_evaluation_value = interpolant.eval(builder, evaluation_point);
|
||||
constraints.extend(
|
||||
&builder
|
||||
.sub_extension(evaluation_value, computed_evaluation_value)
|
||||
.to_target_array(),
|
||||
);
|
||||
|
||||
constraints
|
||||
}
|
||||
|
||||
fn generators(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::convert::TryInto;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::field::extension_field::target::ExtensionTarget;
|
||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||
use crate::field::field::Field;
|
||||
use crate::target::Target;
|
||||
@ -27,3 +28,11 @@ pub struct EvaluationTargets<'a> {
|
||||
pub(crate) local_constants: &'a [Target],
|
||||
pub(crate) local_wires: &'a [Target],
|
||||
}
|
||||
|
||||
impl<'a> EvaluationTargets<'a> {
|
||||
pub fn get_local_ext<const D: usize>(&self, wire_range: Range<usize>) -> ExtensionTarget<D> {
|
||||
debug_assert_eq!(wire_range.len(), D);
|
||||
let arr = self.local_wires[wire_range].try_into().unwrap();
|
||||
ExtensionTarget(arr)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user