From ff6e4d5ab5c8530b98adf46bc109d95272530fd2 Mon Sep 17 00:00:00 2001 From: Supragya Raj Date: Mon, 1 Jul 2024 20:42:49 +0530 Subject: [PATCH 1/2] add: primitives FF and PF --- Cargo.toml | 1 + primitives/Cargo.toml | 6 +++ primitives/src/finitefield.rs | 90 ++++++++++++++++++++++++++++++++++ primitives/src/lib.rs | 2 + primitives/src/primefield.rs | 91 +++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 primitives/Cargo.toml create mode 100644 primitives/src/finitefield.rs create mode 100644 primitives/src/lib.rs create mode 100644 primitives/src/primefield.rs diff --git a/Cargo.toml b/Cargo.toml index 0f0bf57..e2dda9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "primitives", "polynomial", "univariate-polynomial-iop-zerotest", "halo2-trials", diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml new file mode 100644 index 0000000..cc9a745 --- /dev/null +++ b/primitives/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2021" +name = "primitives" +version = "0.1.0" + +[dependencies] diff --git a/primitives/src/finitefield.rs b/primitives/src/finitefield.rs new file mode 100644 index 0000000..b999eac --- /dev/null +++ b/primitives/src/finitefield.rs @@ -0,0 +1,90 @@ +//! This module containt the definition of the trait `FiniteField` + +use std::{ + fmt::Debug, hash::Hash, iter::{Product, Sum}, ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign + } +}; + +/// A field is a set of elements on which the following operations are defined: +/// - Addition +/// - Subtraction +/// - Multiplication +/// - Division +/// +/// A "finite field" is a field with "finite" number of elements + +pub trait FiniteField: + Debug + + From // assumed that all fields in use will be build-able from + // `usize` + + Default + + Sized + + Copy + + Clone + // One should be able to compare two elements for equality + + PartialEq + + Eq + // Addition operations + + AddAssign + + Add + + Sum + // Subtraction operations + + SubAssign + + Sub + // Multiplication operations + + MulAssign + + Mul + + Product + // Division operationss + + DivAssign + + Div + + Rem // if you can divide, you can rem + // Unary operations + + Neg // required for additive identity + // Hashability is required + + Hash + + 'static + + { + /// The order of the field is the number of elements in the field + const ORDER: usize; + + /// The additive identity element + const ZERO: Self; + + /// The multiplicative identity element + const ONE: Self; + + /// Multiplicative generator of the group + /// also called the primitive element + const MULTIPLICATIVE_GENERATOR: Self; + + // REQUIRED IMPLEMENTATIONS + + /// Gets the multiplicative inverse of a field element if it exists. + fn multiplicative_inverse(&self) -> Option; + + /// Computes the power of a field element + fn pow(self, pow: usize) -> Self; + + /// Returns the primitive n-th root of unity in the field. + /// All fields of prime order have + /// - An Additive group + /// - A multiplicative subgroup generated by generator `g` + /// + /// According to Sylow's theorem, for existence of a non-trivial + /// multiplicative subgroup of prime order `n`, `p-1` should be divisible + /// by `n`. (-1) because `0` cannot be part of the multiplicative + /// subgroup. + fn primitive_root_of_unity(n: usize) -> Self { + // Check for divisibility of (p-1) + let remainder = (Self::ORDER - 1) % n; + assert!(remainder == 0, "n must divide (field_order - 1)"); + + // Multiply the generator by how small the subgroup is + // with respect to (p-1) + Self::MULTIPLICATIVE_GENERATOR.pow((Self::ORDER - 1) / n) + } + +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs new file mode 100644 index 0000000..415b205 --- /dev/null +++ b/primitives/src/lib.rs @@ -0,0 +1,2 @@ +pub mod finitefield; +pub mod primefield; diff --git a/primitives/src/primefield.rs b/primitives/src/primefield.rs new file mode 100644 index 0000000..1d7c599 --- /dev/null +++ b/primitives/src/primefield.rs @@ -0,0 +1,91 @@ +//! This module contains the definition of struct `PrimeField` + +use crate::finitefield::FiniteField; + +/// The `PrimeField` struct represents elements of a field of prime order. +/// This field is defined by a prime `P` and elements are integers mod `P`. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, PartialOrd)] +pub struct PrimeField { + pub(crate) value: usize, +} + +// ------ USEFUL COMPILE TIME FUNCTIONS ------ + +/// Useful utility function to check results at compile time. Checks whether +/// a number given is prime. `n` should be known at compile time. +const fn check_prime(n: usize) { + // Run-of-the-mill prime checking logic + let mut test_num = 2; + while test_num * test_num <= n { + if n % test_num == 0 { + panic!("not a prime"); + } + test_num += 1; + } +} + +/// Checks prime and only returns value if check passes +const fn ensure_prime(n: usize) -> usize { + check_prime(n); + n +} + +/// This function finds multiplicative generator given `P`. Weirdly, `P` is +/// needed as a const generic because we need to return `PrimeField

`. +/// +/// A multiplicative generator should be able to generate all the elements +/// in the multiplicative subgroup in the field. +const fn find_multiplicative_generator() -> PrimeField

{} + +impl FiniteField for PrimeField

{ + const MULTIPLICATIVE_GENERATOR: Self = if P == 2 { + Self::ONE + } else { + find_multiplicative_generator::

() + }; + const ONE: Self = Self { value: 1 }; + const ORDER: usize = ensure_prime(P); + const ZERO: Self = Self { value: 0 }; +} + +// Implement aspects of `PrimeField` +impl PrimeField

{ + // TODO: Check whether this should a const fn + pub const fn new(value: usize) -> Self { + is_prime(P); + Self { value: value % P } + } + + /// Checks whether the field element is a quadratic residue in field mod P + /// Returns `true` if it is a quadratic residue + /// + /// ## NOTES + /// We make use of something called the "euler's criterion". + /// By fermat's little theorem, (assume `is_congruent_to` is =) + /// x^(p-1) - 1 = 0 mod P + /// + /// All primes > 2 are odd, a.k.a P is odd, hence (p-1) is even. + /// So, we can split as follows: + /// (x^(p-1)/2 - 1)(x^(p-1)/2 + 1) = 0 mod P + /// or L * R = 0 mod P + /// + /// All quadratic residues are of the form (g^(2k)) where `g` is the + /// multiplicative generator and k is some natural number. All non-residues + /// on the other hand are of the form (g^(2k+1)). + /// + /// In case of QR, substitute x = g^2k + /// g^(2k)((p-1)/2) = 1 mod P + /// g^(p-1) = 1 mod P + /// which is true by fermat's little theorem + /// + /// In the other case, the same doesn't hold. + /// Hence, the case `L` should hold for all quadratic residues and is the + /// test for quadratic residuosity. + /// + /// More info here: https://www.youtube.com/watch?v=2IBPOI43jek + pub fn is_quadratic_residue(&self) -> bool { + self.pow((P - 1) / 2) + .value + == Self::ONE + } +} From 56444dc0fbe35b503f5a1231fc8c84b0e6a1a991 Mon Sep 17 00:00:00 2001 From: Supragya Raj Date: Tue, 2 Jul 2024 09:26:11 +0530 Subject: [PATCH 2/2] add: primefield --- primitives/src/primefield.rs | 65 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/primitives/src/primefield.rs b/primitives/src/primefield.rs index 1d7c599..4a32745 100644 --- a/primitives/src/primefield.rs +++ b/primitives/src/primefield.rs @@ -1,5 +1,7 @@ //! This module contains the definition of struct `PrimeField` +use std::fmt::{Display, Formatter}; + use crate::finitefield::FiniteField; /// The `PrimeField` struct represents elements of a field of prime order. @@ -35,7 +37,35 @@ const fn ensure_prime(n: usize) -> usize { /// /// A multiplicative generator should be able to generate all the elements /// in the multiplicative subgroup in the field. -const fn find_multiplicative_generator() -> PrimeField

{} +const fn find_multiplicative_generator() -> PrimeField

{ + const fn gcd(a: usize, b: usize) -> usize { + let mut a = a; + let mut b = b; + while b != 0 { + let temp = b; + b = a % b; + a = temp; + } + a + } + // This is wrong, through the run of the code below it would be + // hold values which are non-prime. But that's okay... it will only + // ever possibly pass for primes + let mut num = 2; + while num * num <= P { + if gcd(num, P) == 1 { + return PrimeField::

::new(num); + } + i += 1; + } + panic!("cannot find generator"); +} + +impl Display for PrimeField

{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} impl FiniteField for PrimeField

{ const MULTIPLICATIVE_GENERATOR: Self = if P == 2 { @@ -46,6 +76,35 @@ impl FiniteField for PrimeField

{ const ONE: Self = Self { value: 1 }; const ORDER: usize = ensure_prime(P); const ZERO: Self = Self { value: 0 }; + + fn multiplicative_inverse(&self) -> Option { + if self.value == 0 { + return None; + } + + // We know that within a prime field, due to fermat's little theorem + // any element `e` will have + // e^(p-1) = 1 mod P + // Hence, + // e^(p-2) = p^(-1) mod P + + Some(self.clone().pow(Self::ORDER - 2)) + } + + fn pow(self, pow: usize) -> Self { + let mut pow = pow; + let result = Self::ONE; + + while pow > 0 { + if pow & 1 == 1 { + result *= self; + } + self *= self; + pow >>= 1; + } + + result + } } // Implement aspects of `PrimeField` @@ -84,8 +143,6 @@ impl PrimeField

{ /// /// More info here: https://www.youtube.com/watch?v=2IBPOI43jek pub fn is_quadratic_residue(&self) -> bool { - self.pow((P - 1) / 2) - .value - == Self::ONE + self.pow((P - 1) / 2).value == Self::ONE } }