Implement out-of-circuit repeated_frobenius using hardcoded constants

This commit is contained in:
wborgeaud 2021-06-11 13:45:51 +02:00
parent 1ebeab2c3a
commit 20741cfb4a
7 changed files with 76 additions and 32 deletions

View File

@ -6,7 +6,7 @@ use num::Integer;
use crate::field::extension_field::quadratic::QuadraticCrandallField;
use crate::field::extension_field::quartic::QuarticCrandallField;
use crate::field::extension_field::Extendable;
use crate::field::extension_field::{Extendable, Frobeniable};
use crate::field::field::Field;
use std::hash::{Hash, Hasher};
use std::iter::{Product, Sum};
@ -444,6 +444,17 @@ fn split(x: u128) -> (u64, u64) {
(x as u64, (x >> 64) as u64)
}
impl Frobeniable for CrandallField {
const FROBENIUS_CONSTANTS_2: [u64; 1] = [9223372035646816256];
/// Placeholder since there's no OEF of degree 3 for `CrandallField`.
const FROBENIUS_CONSTANTS_3: [u64; 2] = [0, 0];
const FROBENIUS_CONSTANTS_4: [u64; 3] = [
4611686017823408128,
9223372035646816256,
13835058053470224384,
];
}
#[cfg(test)]
mod tests {
use crate::test_arithmetic;

View File

@ -13,12 +13,32 @@ pub mod target;
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.
impl<F: Field> OEF<1> for F {
const W: Self::BaseField = F::ZERO;
}
pub trait Frobenius<BF: Frobeniable, const D: usize>: OEF<D, BaseField = BF> {
/// FrobeniusField automorphisms: x -> x^p, where p is the order of BaseField.
fn frobenius(&self) -> Self {
self.repeated_frobenius(1)
}
/// Repeated Frobenius automorphisms: x -> x^(p^k).
fn repeated_frobenius(&self, k: usize) -> Self {
if k == 0 {
return *self;
} else if k >= D {
return self.repeated_frobenius(k % D);
}
let arr = self.to_basefield_array();
let k = (Self::BaseField::ORDER - 1) / (D as u64);
let z0 = Self::W.exp(k);
let z0 = match D {
2 => Self::W.exp(BF::FROBENIUS_CONSTANTS_2[k - 1]),
3 => Self::W.exp(BF::FROBENIUS_CONSTANTS_3[k - 1]),
4 => Self::W.exp(BF::FROBENIUS_CONSTANTS_4[k - 1]),
_ => unimplemented!("Only extensions of degree 2, 3, or 4 are allowed for now."),
};
let mut z = Self::BaseField::ONE;
let mut res = [Self::BaseField::ZERO; D];
for i in 0..D {
@ -28,25 +48,30 @@ pub trait OEF<const D: usize>: FieldExtension<D> {
Self::from_basefield_array(res)
}
}
/// Repeated Frobenius automorphisms: x -> x^(p^k).
// TODO: Implement this. Is basically the same as `frobenius` above, but using
// `z = W^floor(j*p^k/D)`. I'm not sure there is a closed form for these so
// might require to hardcode them.
fn repeated_frobenius(&self, k: usize) -> Self {
todo!()
impl<F: Frobeniable> Frobenius<F, 1> for F {
fn frobenius(&self) -> Self {
*self
}
fn repeated_frobenius(&self, _k: usize) -> Self {
*self
}
}
impl<F: Field> OEF<1> for F {
const W: Self::BaseField = F::ZERO;
/// Trait to hardcode constants used in the Frobenius automorphism.
pub trait Frobeniable: Field {
//! `FROBENIUS_CONSTANTS_D[i-1] = floor( p^i / D) mod p-1`
const FROBENIUS_CONSTANTS_2: [u64; 1];
const FROBENIUS_CONSTANTS_3: [u64; 2];
const FROBENIUS_CONSTANTS_4: [u64; 3];
}
pub trait Extendable<const D: usize>: Field + Sized {
type Extension: Field + OEF<D, BaseField = Self> + From<Self>;
pub trait Extendable<const D: usize>: Frobeniable + Sized {
type Extension: Field + OEF<D, BaseField = Self> + Frobenius<Self, D> + From<Self>;
}
impl<F: Field> Extendable<1> for F {
impl<F: Frobeniable + Frobenius<F, 1>> Extendable<1> for F {
type Extension = F;
}

View File

@ -1,5 +1,5 @@
use crate::field::crandall_field::CrandallField;
use crate::field::extension_field::{FieldExtension, OEF};
use crate::field::extension_field::{FieldExtension, Frobenius, OEF};
use crate::field::field::Field;
use rand::Rng;
use std::fmt::{Debug, Display, Formatter};
@ -16,6 +16,8 @@ impl OEF<2> for QuadraticCrandallField {
const W: CrandallField = CrandallField(3);
}
impl Frobenius<CrandallField, 2> for QuadraticCrandallField {}
impl FieldExtension<2> for QuadraticCrandallField {
type BaseField = CrandallField;
@ -63,7 +65,7 @@ impl Field for QuadraticCrandallField {
return None;
}
let a_pow_r_minus_1 = OEF::<2>::frobenius(self);
let a_pow_r_minus_1 = self.frobenius();
let a_pow_r = a_pow_r_minus_1 * *self;
debug_assert!(FieldExtension::<2>::is_in_basefield(&a_pow_r));
@ -190,7 +192,7 @@ impl DivAssign for QuadraticCrandallField {
#[cfg(test)]
mod tests {
use crate::field::extension_field::quadratic::QuadraticCrandallField;
use crate::field::extension_field::{FieldExtension, OEF};
use crate::field::extension_field::{FieldExtension, Frobenius, OEF};
use crate::field::field::Field;
#[test]
@ -231,7 +233,7 @@ mod tests {
let x = F::rand();
assert_eq!(
x.exp(<F as FieldExtension<2>>::BaseField::ORDER),
OEF::<2>::frobenius(&x)
x.frobenius()
);
}

View File

@ -6,7 +6,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi
use rand::Rng;
use crate::field::crandall_field::CrandallField;
use crate::field::extension_field::{FieldExtension, OEF};
use crate::field::extension_field::{FieldExtension, Frobenius, OEF};
use crate::field::field::Field;
/// A quartic extension of `CrandallField`.
@ -20,6 +20,8 @@ impl OEF<4> for QuarticCrandallField {
const W: CrandallField = CrandallField(3);
}
impl Frobenius<CrandallField, 4> for QuarticCrandallField {}
impl FieldExtension<4> for QuarticCrandallField {
type BaseField = CrandallField;
@ -93,9 +95,9 @@ impl Field for QuarticCrandallField {
return None;
}
let a_pow_p = OEF::<4>::frobenius(self);
let a_pow_p = self.frobenius();
let a_pow_p_plus_1 = a_pow_p * *self;
let a_pow_p3_plus_p2 = OEF::<4>::frobenius(&OEF::<4>::frobenius(&a_pow_p_plus_1));
let a_pow_p3_plus_p2 = a_pow_p_plus_1.repeated_frobenius(2);
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!(FieldExtension::<4>::is_in_basefield(&a_pow_r));
@ -241,7 +243,7 @@ impl DivAssign for QuarticCrandallField {
#[cfg(test)]
mod tests {
use crate::field::extension_field::quartic::QuarticCrandallField;
use crate::field::extension_field::{FieldExtension, OEF};
use crate::field::extension_field::{FieldExtension, Frobenius, OEF};
use crate::field::field::Field;
fn exp_naive<F: Field>(x: F, power: u128) -> F {
@ -295,7 +297,12 @@ mod tests {
let x = F::rand();
assert_eq!(
exp_naive(x, <F as FieldExtension<4>>::BaseField::ORDER as u128),
OEF::<4>::frobenius(&x)
x.frobenius()
);
assert_eq!(x.repeated_frobenius(2), x.frobenius().frobenius());
assert_eq!(
x.repeated_frobenius(3),
x.frobenius().frobenius().frobenius()
);
}

View File

@ -7,7 +7,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi
use num::Integer;
use rand::Rng;
use crate::field::extension_field::OEF;
use crate::field::extension_field::{Extendable, FieldExtension, Frobeniable, Frobenius, OEF};
use crate::util::bits_u64;
/// A finite field with prime order less than 2^64.
@ -287,15 +287,14 @@ impl<F: Field> Iterator for Powers<F> {
impl<F: Field> Powers<F> {
/// Apply the Frobenius automorphism `k` times.
// TODO: Use `OEF::repeated_frobenius` when it is implemented.
pub fn repeated_frobenius<const D: usize>(self, k: usize) -> Self
pub fn repeated_frobenius<BF: Frobeniable, const D: usize>(self, k: usize) -> Self
where
F: OEF<D>,
F: Frobenius<BF, D>,
{
let Self { base, current } = self;
Self {
base: (0..k).fold(base, |acc, _| acc.frobenius()),
current: (0..k).fold(current, |acc, _| acc.frobenius()),
base: base.repeated_frobenius(k),
current: base.repeated_frobenius(k),
}
}
}

View File

@ -1,7 +1,7 @@
use anyhow::{ensure, Result};
use itertools::izip;
use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF};
use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius, OEF};
use crate::field::field::Field;
use crate::field::lagrange::{barycentric_weights, interpolant, interpolate};
use crate::fri::FriConfig;

View File

@ -1,8 +1,8 @@
use anyhow::Result;
use rayon::prelude::*;
use crate::field::extension_field::FieldExtension;
use crate::field::extension_field::{Extendable, OEF};
use crate::field::extension_field::{FieldExtension, Frobenius};
use crate::field::field::Field;
use crate::field::lagrange::interpolant;
use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig};