From 20741cfb4a83869723d2e1ce03b28022f08e260e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 11 Jun 2021 13:45:51 +0200 Subject: [PATCH] Implement out-of-circuit `repeated_frobenius` using hardcoded constants --- src/field/crandall_field.rs | 13 ++++++- src/field/extension_field/mod.rs | 53 +++++++++++++++++++------- src/field/extension_field/quadratic.rs | 10 +++-- src/field/extension_field/quartic.rs | 17 ++++++--- src/field/field.rs | 11 +++--- src/fri/verifier.rs | 2 +- src/polynomial/commitment.rs | 2 +- 7 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 46dcb172..34d67b65 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -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; diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 525d8ecc..d9ae3387 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -13,12 +13,32 @@ pub mod target; pub trait OEF: FieldExtension { // 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 OEF<1> for F { + const W: Self::BaseField = F::ZERO; +} + +pub trait Frobenius: OEF { + /// 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: FieldExtension { 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 Frobenius for F { + fn frobenius(&self) -> Self { + *self + } + fn repeated_frobenius(&self, _k: usize) -> Self { + *self } } -impl 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: Field + Sized { - type Extension: Field + OEF + From; +pub trait Extendable: Frobeniable + Sized { + type Extension: Field + OEF + Frobenius + From; } -impl Extendable<1> for F { +impl> Extendable<1> for F { type Extension = F; } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 27fc33a1..f0fd2ac9 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -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 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(>::BaseField::ORDER), - OEF::<2>::frobenius(&x) + x.frobenius() ); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 2acac183..f0e8bed4 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -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 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(x: F, power: u128) -> F { @@ -295,7 +297,12 @@ mod tests { let x = F::rand(); assert_eq!( exp_naive(x, >::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() ); } diff --git a/src/field/field.rs b/src/field/field.rs index 44a20a58..8a652a0a 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -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 Iterator for Powers { impl Powers { /// Apply the Frobenius automorphism `k` times. - // TODO: Use `OEF::repeated_frobenius` when it is implemented. - pub fn repeated_frobenius(self, k: usize) -> Self + pub fn repeated_frobenius(self, k: usize) -> Self where - F: OEF, + F: Frobenius, { 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), } } } diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 27fdf53e..a3f3864a 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -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; diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 22fc4114..3607d794 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -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};