Skip to content

Add Stark101 tutorial's prime field #875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions math/src/field/fields/fft_friendly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pub mod babybear;
/// Implemenation of the quadratic extension of the babybear field
pub mod quadratic_babybear;
/// Implementation of the prime field used in [Stark101](https://starkware.co/stark-101/) tutorial, p = 3 * 2^30 + 1
pub mod stark_101_prime_field;
/// Implementation of two-adic prime field over 256 bit unsigned integers.
pub mod stark_252_prime_field;
/// Implemenation of the Goldilocks Prime Field p = 2^64 - 2^32 + 1
Expand Down
113 changes: 113 additions & 0 deletions math/src/field/fields/fft_friendly/stark_101_prime_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use crate::{
field::{
element::FieldElement,
fields::montgomery_backed_prime_fields::{IsModulus, U64PrimeField},
traits::IsFFTField,
},
unsigned_integer::element::{UnsignedInteger, U64},
};

#[derive(Clone, Debug, Hash, Copy)]
pub struct MontgomeryConfigStark101PrimeField;
impl IsModulus<U64> for MontgomeryConfigStark101PrimeField {
/// 3 * 2^30 + 1
const MODULUS: U64 = U64::from_hex_unchecked("c0000001");
}

pub type Stark101PrimeField = U64PrimeField<MontgomeryConfigStark101PrimeField>;

impl IsFFTField for Stark101PrimeField {
const TWO_ADICITY: u64 = 30;

const TWO_ADIC_PRIMITVE_ROOT_OF_UNITY: U64 = UnsignedInteger::from_hex_unchecked("bb6e79d");

fn field_name() -> &'static str {
"stark101"
}
}

impl FieldElement<Stark101PrimeField> {
pub fn to_bytes_le(&self) -> [u8; 8] {
let limbs = self.representative().limbs;
limbs[0].to_le_bytes()
}

pub fn to_bytes_be(&self) -> [u8; 8] {
let limbs = self.representative().limbs;
limbs[0].to_be_bytes()
}
}

#[allow(clippy::non_canonical_partial_ord_impl)]
impl PartialOrd for FieldElement<Stark101PrimeField> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.representative().partial_cmp(&other.representative())
}
}

impl Ord for FieldElement<Stark101PrimeField> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.representative().cmp(&other.representative())
}
}

#[cfg(test)]
mod test_stark101_prime_field {
use super::Stark101PrimeField;
use crate::{
field::{element::FieldElement, traits::IsFFTField},
traits::ByteConversion,
};

#[test]
fn two_adic_order() {
let w = FieldElement::<Stark101PrimeField>::from(
Stark101PrimeField::TWO_ADIC_PRIMITVE_ROOT_OF_UNITY.limbs[0],
);

assert_eq!(
w.pow(1u64 << Stark101PrimeField::TWO_ADICITY),
FieldElement::one()
);
assert_ne!(
w.pow(1u64 << (Stark101PrimeField::TWO_ADICITY >> 1)),
FieldElement::one()
);
}

#[test]
#[cfg(feature = "alloc")]
fn byte_serialization_for_a_number_matches_with_byte_conversion_implementation_le() {
let element = FieldElement::<Stark101PrimeField>::from_hex_unchecked("0123456701234567");
let bytes = element.to_bytes_le();
let expected_bytes: [u8; 8] = ByteConversion::to_bytes_le(&element).try_into().unwrap();
assert_eq!(bytes, expected_bytes);
}

#[test]
#[cfg(feature = "alloc")]
fn byte_serialization_for_a_number_matches_with_byte_conversion_implementation_be() {
let element = FieldElement::<Stark101PrimeField>::from_hex_unchecked("0123456701234567");
let bytes = element.to_bytes_be();
let expected_bytes: [u8; 8] = ByteConversion::to_bytes_be(&element).try_into().unwrap();
assert_eq!(bytes, expected_bytes);
}

#[test]

fn byte_serialization_and_deserialization_works_le() {
let element = FieldElement::<Stark101PrimeField>::from_hex_unchecked("7654321076543210");
let bytes = element.to_bytes_le();
let from_bytes = FieldElement::<Stark101PrimeField>::from_bytes_le(&bytes).unwrap();
assert_eq!(element, from_bytes);
}

#[test]

fn byte_serialization_and_deserialization_works_be() {
let element = FieldElement::<Stark101PrimeField>::from_hex_unchecked("7654321076543210");
let bytes = element.to_bytes_be();
let from_bytes = FieldElement::<Stark101PrimeField>::from_bytes_be(&bytes).unwrap();
assert_eq!(element, from_bytes);
}
}
Loading