Skip to content

Commit

Permalink
chore: reduce FiniteField trait + docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Autoparallel committed May 10, 2024
1 parent 35d7273 commit c3a821b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 54 deletions.
12 changes: 9 additions & 3 deletions src/field/gf_101.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
//! This module contains the implementation of the finite field GF(101) and its arithmetic
//! operations.
use rand::distributions::{Distribution, Standard};

use super::*;

const PLUTO_FIELD_PRIME: u32 = 101;
/// The prime number that defines the base prime-order finite field used throughout this crate.
pub const PLUTO_FIELD_PRIME: u32 = 101;

/// [`GF101`] represents the finite field GF(101) that has 101 elements and works with typical sum
/// and multiplication operations modulo 101.
#[derive(Copy, Clone, Default, Debug, Hash, PartialEq, Eq)]
pub struct GF101 {
value: u32,
Expand All @@ -14,6 +20,8 @@ impl fmt::Display for GF101 {
}

impl GF101 {
/// Create a new [`GF101`] element from the given value. The value is reduced modulo 101 to
/// ensure it is within the field.
pub const fn new(value: u32) -> Self { Self { value: value % PLUTO_FIELD_PRIME } }
}

Expand Down Expand Up @@ -47,8 +55,6 @@ impl FiniteField for GF101 {
}

fn generator() -> Self { Self::new(2) }

fn from_canonical_u32(n: u32) -> Self { Self::new(n) }
}

impl Add for GF101 {
Expand Down
65 changes: 29 additions & 36 deletions src/field/gf_101_2.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use super::*;
//! This module contains an implementation of the quadratic extension field GF(101^2).
//! Elements represented as coefficients of a [`Polynomial`] in the [`Monomial`] basis of degree 1
//! in form: `a_0 + a_1*t`` where {a_0, a_1} \in \mathhbb{F}. Uses irreducible poly of the form:
//! (X^2-K).
//!
//! The curve used in [`curves::g1_curve`] supports degree two extension field from GF(101) to have
//! points in GF(101^2). This can be verified by finding out embedding degree of the curve, i.e.
//! smallest k such that r|q^k-1.
/// Quadratic Extension field element represented as polynomial of degree 1 in form:
/// a_0 + a_1*t where {a_0, a_1} \in \mathhbb{F}. Uses irreducible poly of the form:
/// (X^2-K).
use super::*;

/// Pluto curve with modulus 101 supports two degree extension field. This can be verified
/// by finding out embedding degree of the curve, i.e. smallest k: r|q^k-1
const EXT_DEGREE: usize = 2;
const QUADRATIC_EXTENSION_FIELD_ORDER: u32 = 101 * 101;

impl ExtensionField<2, GF101> for Ext<2, GF101> {
Expand All @@ -15,7 +17,7 @@ impl ExtensionField<2, GF101> for Ext<2, GF101> {
const IRREDUCIBLE_POLYNOMIAL_COEFFS: [GF101; 3] = [GF101::TWO, GF101::ZERO, GF101::ONE];
}

impl FiniteField for Ext<EXT_DEGREE, GF101> {
impl FiniteField for Ext<2, GF101> {
type Storage = u32;

const NEG_ONE: Self = Self::new([GF101::NEG_ONE, GF101::ZERO]);
Expand All @@ -25,18 +27,17 @@ impl FiniteField for Ext<EXT_DEGREE, GF101> {
const TWO: Self = Self::new([GF101::TWO, GF101::ZERO]);
const ZERO: Self = Self::new([GF101::ZERO, GF101::ZERO]);

// field generator: can be verified using sage script
// ```sage
// F = GF(101)
// Ft.<t> = F[]
// P = Ft(t ^ 2 - 2)
// F_2 = GF(101 ^ 2, name="t", modulus=P)
// f_2_primitive_element = F_2([2, 1])
// assert f_2_primitive_element.multiplicative_order() == 101^2-1
// ```
fn generator() -> Self {
Self { coeffs: [GF101::from_canonical_u32(14), GF101::from_canonical_u32(9)] }
}
/// Retrieves a multiplicative generator for GF(101) inside of [`Ext<2, GF101>`].
/// This can be verified using sage script
/// ```sage
/// F = GF(101)
/// Ft.<t> = F[]
/// P = Ft(t ^ 2 - 2)
/// F_2 = GF(101 ^ 2, name="t", modulus=P)
/// f_2_primitive_element = F_2([2, 1])
/// assert f_2_primitive_element.multiplicative_order() == 101^2-1
/// ```
fn generator() -> Self { Self { coeffs: [GF101::from(14u32), GF101::from(9u32)] } }

/// Computes the multiplicative inverse of `a`, i.e. 1 / (a0 + a1 * t).
/// Multiply by `a0 - a1 * t` in numerator and denominator.
Expand All @@ -48,20 +49,15 @@ impl FiniteField for Ext<EXT_DEGREE, GF101> {

let mut res = Self::default();
let scalar =
(self.coeffs[0].square() + GF101::from(2u32) * self.coeffs[1].square()).inverse().unwrap();
(self.coeffs[0].pow(2) + GF101::from(2u32) * self.coeffs[1].pow(2)).inverse().unwrap();
res.coeffs[0] = self.coeffs[0] * scalar;
res.coeffs[1] = -self.coeffs[1] * scalar;
Some(res)
}

fn from_canonical_u32(n: u32) -> Self {
Self { coeffs: [GF101::from_canonical_u32(n), GF101::ZERO] }
}
}

// TODO: adjust this def
/// Returns the multiplication of `a` and `b` using the following equation:
/// (a0 + a1 * t) * (b0 + b1 * t) = a0 * b0 + a1 * b1 * irreducible() + (a0 * b1 + a1 * b0) * t
/// Returns the multiplication of two [`Ext<2, GF101>`] elements by reducing result modulo
/// irreducible polynomial.
impl Mul for Ext<2, GF101> {
type Output = Self;

Expand Down Expand Up @@ -183,7 +179,7 @@ mod tests {
assert_eq!(x, x.pow(1));

let res = x.pow(4);
assert_eq!(res, x.square().square());
assert_eq!(res, x * x * x * x);
}

#[test]
Expand Down Expand Up @@ -211,8 +207,8 @@ mod tests {
assert_eq!(x * x.inverse().unwrap(), <Ext<2, GF101>>::ONE);
assert_eq!(x.inverse().unwrap_or(<Ext<2, GF101>>::ONE) * x, <Ext<2, GF101>>::ONE);
assert_eq!(
x.square().inverse().unwrap_or(<Ext<2, GF101>>::ONE),
x.inverse().unwrap_or(<Ext<2, GF101>>::ONE).square()
(x * x).inverse().unwrap_or(<Ext<2, GF101>>::ONE),
x.inverse().unwrap_or(<Ext<2, GF101>>::ONE).pow(2)
);
assert_eq!((x / y) * y, x);
assert_eq!(x / (y * z), (x / y) / z);
Expand All @@ -221,10 +217,7 @@ mod tests {

#[test]
fn generator() {
assert_eq!(
<Ext<2, GF101>>::generator() * GF101::from_canonical_u32(GF101::ORDER),
<Ext<2, GF101>>::ZERO
);
assert_eq!(<Ext<2, GF101>>::generator() * GF101::from(GF101::ORDER), <Ext<2, GF101>>::ZERO);
}

#[test]
Expand All @@ -240,7 +233,7 @@ mod tests {

let mul1 = x * y;
let inv_mul = x * y.inverse().unwrap();
let res = x.square();
let res = x * x;
assert_eq!(mul1 * inv_mul, res);
}

Expand Down
50 changes: 35 additions & 15 deletions src/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod gf_101_2;
/// We restrict to finite fields, which are fields with a finite number of elements.
pub trait FiniteField:
std::fmt::Debug
+ From<u32>
+ Default
+ Sized
+ Copy
Expand All @@ -31,6 +32,7 @@ pub trait FiniteField:
+ Rem<Output = Self>
+ Hash
+ 'static {
/// The type used to store the field elements in memory.
type Storage: From<u32>
+ Into<u32>
+ Into<u64>
Expand All @@ -41,19 +43,26 @@ pub trait FiniteField:
+ Rem<Output = Self::Storage>
+ Mul<Output = Self::Storage>
+ Eq;
/// The order of the field, i.e., the number of elements in the field.
const ORDER: Self::Storage;
/// The additive identity element.
const ZERO: Self;
/// The multiplicative identity element.
const ONE: Self;
/// The number two in the field.
const TWO: Self;
/// The number negative one in the field (additive inverse of [`FiniteField::ONE`]).
const NEG_ONE: Self;
/// The number three in the field.
const THREE: Self;

/// Gets the multiplicative inverse of the field element (if it exists).
fn inverse(&self) -> Option<Self>;
fn from_canonical_u32(n: u32) -> Self;

/// Returns a multiplicative generator of the field.
fn generator() -> Self;
fn double(&self) -> Self { *self + *self }
fn square(&self) -> Self { *self * *self }

/// Computes the `power`-th power of the field element.
fn pow(&self, mut power: u64) -> Self {
let mut current = *self;
let mut product = Self::ONE;
Expand All @@ -69,15 +78,18 @@ pub trait FiniteField:
product
}

// In any field of prime order F_p:
// - There exists an additive group.
// - There exists a multiplicative subgroup generated by a primitive element 'a'.
//
// According to the Sylow theorems (https://en.wikipedia.org/wiki/Sylow_theorems):
// A non-trivial multiplicative subgroup of prime order 'n' exists if and only if
// 'p - 1' is divisible by 'n'.
// The primitive n-th root of unity 'w' is defined as: w = a^((p - 1) / n),
// and the roots of unity are generated by 'w', such that {w^i | i in [0, n - 1]}.
/// Returns the primitive n-th root of unity in the field.
///
/// ## Notes
/// In any field of prime order F_p:
/// - There exists an additive group.
/// - There exists a multiplicative subgroup generated by a primitive element 'a'.
///
/// According to the Sylow theorems (https://en.wikipedia.org/wiki/Sylow_theorems):
/// A non-trivial multiplicative subgroup of prime order 'n' exists if and only if
/// 'p - 1' is divisible by 'n'.
/// The primitive n-th root of unity 'w' is defined as: w = a^((p - 1) / n),
/// and the roots of unity are generated by 'w', such that {w^i | i in [0, n - 1]}.
fn primitive_root_of_unity(n: Self::Storage) -> Self {
let p_minus_one = Self::ORDER - Self::Storage::from(1);
assert!(p_minus_one % n == 0.into(), "n must divide p - 1");
Expand All @@ -86,6 +98,9 @@ pub trait FiniteField:
}
}

/// A field extension is a field that contains the original field and additional elements that are
/// not in the original field. The extension field is constructed by adjoining the roots of a
/// polynomial to the original field.
#[const_trait]
pub trait ExtensionField<const N: usize, B: FiniteField>:
FiniteField
Expand All @@ -97,12 +112,17 @@ pub trait ExtensionField<const N: usize, B: FiniteField>:
+ Mul<B, Output = Self>
+ MulAssign<B>
where [B; N + 1]: {
/// The coefficients of the irreducible polynomial used to reduce field polynomials to the
/// desired degree.
const IRREDUCIBLE_POLYNOMIAL_COEFFS: [B; N + 1];
}

/// A struct that represents an element of an extension field. The element is represented as
/// [`Monomial`] coefficients of a [`Polynomial`] of degree `N - 1` over the base [`FiniteField`]
/// `F`.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct Ext<const N: usize, F: FiniteField> {
pub coeffs: [F; N],
pub(crate) coeffs: [F; N],
}

impl<const N: usize, F: FiniteField> Default for Ext<N, F> {
Expand All @@ -128,12 +148,12 @@ impl<const N: usize, F: FiniteField> From<F> for Ext<N, F> {

/// Convert from a [`u32`] into the [`Ext`] field element in the natural way.
impl<const N: usize, F: FiniteField> From<u32> for Ext<N, F> {
fn from(val: u32) -> Self { Self::from(F::from_canonical_u32(val)) }
fn from(val: u32) -> Self { Self::from(F::from(val)) }
}

/// Convert from a [`u64`] into the [`Ext`] field element in the natural way.
impl<const N: usize, F: FiniteField> From<u64> for Ext<N, F> {
fn from(val: u64) -> Self { Self::from(F::from_canonical_u32(val as u32)) }
fn from(val: u64) -> Self { Self::from(F::from(val as u32)) }
}

/////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit c3a821b

Please sign in to comment.