diff --git a/fp/src/_doctest_support.rs b/fp/src/_doctest_support.rs index b4503da..2b8be6b 100644 --- a/fp/src/_doctest_support.rs +++ b/fp/src/_doctest_support.rs @@ -65,3 +65,22 @@ pub mod _doctest_field_ops { pub type F19_2 = FpExt; } + +pub mod _doctest_f2_ext { + use crate::f2_ext::{BinaryIrreducible, F2Ext}; + use crypto_bigint::Uint; + + pub struct F4Poly; + + impl BinaryIrreducible<1> for F4Poly { + fn modulus() -> Uint<1> { + Uint::<1>::from_u64(0b111) // x^2 + x + 1 + } + + fn degree() -> usize { + 2usize + } + } + + pub type F4 = F2Ext<1, F4Poly>; +} diff --git a/fp/src/f2_element.rs b/fp/src/f2_element.rs index 2acc063..28f54af 100644 --- a/fp/src/f2_element.rs +++ b/fp/src/f2_element.rs @@ -1,4 +1,18 @@ //! The binary field $\mathbb{F}_2 = \mathbb{Z} / 2\mathbb{Z}$ +//! +//! # Examples +//! +//! ``` +//! use fp::f2_element::F2Element; +//! use fp::field_ops::FieldOps; +//! use crypto_bigint::Uint; +//! +//! let x = F2Element::from_u64(0); +//! let y = F2Element::from_u64(1); +//! assert!(bool::from(x.is_zero())); +//! assert!(bool::from(y.is_one())); +//! assert_eq!(F2Element::characteristic(), [2]); +//! ``` use crate::field_ops::FieldFromRepr; use crate::field_ops::{FieldOps, FieldRandom}; @@ -28,15 +42,6 @@ impl F2Element { }; /// Create a new element of $\mathbb{F}_2$ from a `Uint<1>` - /// - /// # Arguments - /// - /// * `x` - An integer (type: `Uint<1>`) - /// - /// # Returns - /// - /// An element of $\mathbb{F}_2$, the reduction of `x` mod 2 - /// (type: `Self`) fn new(x: Uint<1>) -> Self { Self { value: x & Uint::<1>::ONE, @@ -53,11 +58,22 @@ impl F2Element { /// /// An element of $\mathbb{F}_2$, the reduction of `x` mod 2 /// (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::f2_element::F2Element; + /// # use fp::field_ops::FieldOps; + /// # use crypto_bigint::Uint; + /// let x = F2Element::from_u64(1); + /// let y = F2Element::from_u64(7); + /// assert_eq!(x, y); + /// ``` pub fn from_u64(x: u64) -> Self { Self::new(Uint::from(x & 1)) } - /// Get the `Uint<1>` from an element of $\mathbb{F}_2$ + /// Get the `Uint<1>` from an element of $\mathbb{F}_2$ i.e., /// /// # Arguments /// @@ -67,6 +83,15 @@ impl F2Element { /// /// The integer in $\{ 0, 1 \}$ reducing to `x` mod 2 (type: /// `Uint<1>`) + /// + /// ``` + /// # use fp::f2_element::F2Element; + /// # use fp::field_ops::FieldOps; + /// # use crypto_bigint::Uint; + /// let x = F2Element::from_u64(7); + /// let my_int = x.value(); + /// assert_eq!(my_int, Uint::<1>::from_u64(1)); + /// ``` pub fn value(&self) -> Uint<1> { self.value } @@ -80,7 +105,16 @@ impl F2Element { /// # Returns /// /// The integer in $\{ 0, 1 \}$ reducing to `x` mod 2 (type: - /// `u8`) + /// `Uint<1>`) + /// + /// ``` + /// # use fp::f2_element::F2Element; + /// # use fp::field_ops::FieldOps; + /// # use crypto_bigint::Uint; + /// let x = F2Element::from_u64(45); + /// let my_int = x.as_u8(); + /// assert_eq!(my_int, 1_u8); + /// ``` pub fn as_u8(&self) -> u8 { self.value.to_words()[0] as u8 } diff --git a/fp/src/f2_ext.rs b/fp/src/f2_ext.rs index 62cc15d..a00a818 100644 --- a/fp/src/f2_ext.rs +++ b/fp/src/f2_ext.rs @@ -1,4 +1,38 @@ //! Generic binary fields $\mathbb{F}\_{2^m} = \mathbb{F}\_2\[x\] / (f(x))$ +//! +//! # Examples +//! +//! ``` +//! use crypto_bigint::Uint; +//! use fp::f2_element::F2Element; +//! use fp::f2_ext::{BinaryIrreducible, F2Ext}; +//! use fp::field_ops::FieldOps; +//! +//! /* Make the finite field F_4 */ +//! struct F4Poly; +//! impl BinaryIrreducible<1> for F4Poly { +//! fn modulus() -> Uint<1> { +//! Uint::<1>::from_u64(0b111) // x^2 + x + 1 +//! } +//! +//! fn degree() -> usize { +//! 2usize +//! } +//! } +//! type F4 = F2Ext<1, F4Poly>; +//! +//! /* Elements are written down by binary integers */ +//! let zero = F4::from_u64(0); +//! let one = F4::from_u64(1); +//! let a = F4::from_u64(0b11); +//! let b = F4::from_u64(0b10); +//! +//! let also_zero = F4::from_u64(0b111); // x^2 + x + 1 = 0 +//! let also_one = F4::from_u64(0b1000); // x^3 = x*x^2 = x^2 + x = 1 +//! assert_eq!(also_zero, zero); +//! assert_eq!(also_one, one); +//! assert_eq!(a.mul(&b), one); +//! ``` use crate::field_ops::{FieldFromRepr, FieldOps, FieldRandom}; use core::ops::{Add, Mul, Neg, Sub}; @@ -21,9 +55,10 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// # Examples /// /// ``` -/// # use crypto_bigint::Uint; -/// # use fp::f2_element::F2Element; -/// # use fp::f2_ext::{BinaryIrreducible, F2Ext}; +/// use crypto_bigint::Uint; +/// use fp::f2_element::F2Element; +/// use fp::f2_ext::{BinaryIrreducible, F2Ext}; +/// /// struct MyPoly; /// /// impl BinaryIrreducible<1> for MyPoly { @@ -63,11 +98,25 @@ pub trait BinaryIrreducible: 'static { /// # Examples /// /// ``` -/// # use crypto_bigint::Uint; -/// # use fp::f2_element::F2Element; -/// # use fp::f2_ext::{BinaryIrreducible, F2Ext}; -/// struct F2511Poly; +/// use crypto_bigint::Uint; +/// use fp::f2_element::F2Element; +/// use fp::f2_ext::{BinaryIrreducible, F2Ext}; +/// +/// /* Make the finite field F_4 */ +/// struct F4Poly; +/// impl BinaryIrreducible<1> for F4Poly { +/// fn modulus() -> Uint<1> { +/// Uint::<1>::from_u64(0b111) // x^2 + x + 1 +/// } /// +/// fn degree() -> usize { +/// 2usize +/// } +/// } +/// type F4 = F2Ext<1, F4Poly>; +/// +/// /* Make the finite field F_{2^511} */ +/// struct F2511Poly; /// impl BinaryIrreducible<8> for F2511Poly { /// fn modulus() -> Uint<8> { /// let one = Uint::<8>::from_u64(1); @@ -78,8 +127,7 @@ pub trait BinaryIrreducible: 'static { /// 511 /// } /// } -/// -/// type GF2_511 = F2Ext<8, F2511Poly>; +/// type F2_511 = F2Ext<8, F2511Poly>; /// ``` pub struct F2Ext where @@ -98,30 +146,145 @@ impl F2Ext where P: BinaryIrreducible, { - /// Make an element from the limbs - pub fn new(x: Uint) -> Self { + /// Make an element of the extension from the limbs + /// + /// # Arguments + /// + /// * `a` - An integer written in binary as $a_0 \dots a_{64 * + /// \texttt{LIMBS}}$ and padded with 0s if nessicary (type: + /// `Uint`). + /// + /// # Returns + /// + /// The element $\sum_{i=0}^M a_i x^i \in \mathbb{F}\_{2}\[x\] / + /// (f(x)) = \mathbb{F}\_{2^M}$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_f2_ext::*; + /// # use crypto_bigint::Uint; + /// # use fp::field_ops::FieldOps; + /// let a = F4::new(Uint::<1>::from_u64(0b111)); // x^2 + x + 1 should be zero + /// let b = F4::new(Uint::<1>::from_u64(0b11)); // x + 1 = x^2 + /// let c = F4::new(Uint::<1>::from_u64(0b100)); // x^2 = x + 1 + /// let d = F4::new(Uint::<1>::from_u64(0b1000)); // x^3 = x^2 * x = x^2 + x = 1 + /// assert!(bool::from(a.is_zero())); + /// assert_eq!(b, c); + /// assert!(bool::from(d.is_one())); + /// ``` + pub fn new(a: Uint) -> Self { Self { - value: reduce::(x), + value: reduce::(a), _phantom: PhantomData, } } - /// Make an element from a `u64` + /// Make an element of the extension from a `u64` + /// + /// # Arguments + /// + /// * `a` - An integer written in binary as $a_0 \dots a_{64}$ and + /// padded with 0s to 64 bits if nessicary (type: `u64`). + /// + /// # Returns + /// + /// The element $\sum_{i=0}^{64} a_i x^i \in \mathbb{F}\_{2}\[x\] / + /// (f(x)) = \mathbb{F}\_{2^M}$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_f2_ext::*; + /// # use crypto_bigint::Uint; + /// # use fp::field_ops::FieldOps; + /// let a = F4::from_u64(0b111); // x^2 + x + 1 should be zero + /// let b = F4::from_u64(0b11); // x + 1 should be x^2 + /// let c = F4::from_u64(0b100); // x + 1 should be x^2 + /// let d = F4::from_u64(0b1000); // x^3 = x^2 * x = x^2 + x = 1 + /// assert!(bool::from(a.is_zero())); + /// assert_eq!(b, c); + /// assert!(bool::from(d.is_one())); + /// ``` pub fn from_u64(x: u64) -> Self { Self::new(Uint::from(x)) } - /// Make an element from a `Uint` + /// Make an element of the extension from the limbs + /// + /// # Arguments + /// + /// * `a` - An integer written in binary as $a_0 a_1 a_2 \dots + /// a_{M}$ and then padded to the nearest 64 bits (type: + /// `Uint`). + /// + /// # Returns + /// + /// The element $\sum_{i=0}^M a_i x^i \in \mathbb{F}\_{2}\[x\] / + /// (f(x)) = \mathbb{F}\_{2^M}$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_f2_ext::*; + /// # use crypto_bigint::Uint; + /// # use fp::field_ops::FieldOps; + /// let a = F4::from_uint(Uint::<1>::from_u64(0b111)); // x^2 + x + 1 should be zero + /// let b = F4::from_uint(Uint::<1>::from_u64(0b11)); // x + 1 = x^2 + /// let c = F4::from_uint(Uint::<1>::from_u64(0b100)); // x^2 = x + 1 + /// let d = F4::from_uint(Uint::<1>::from_u64(0b1000)); // x^3 = x^2 * x = x^2 + x = 1 + /// assert!(bool::from(a.is_zero())); + /// assert_eq!(b, c); + /// assert!(bool::from(d.is_one())); + /// ``` + /// + /// # Note + /// + /// This is just an alias for [`F2Ext::new`] pub fn from_uint(x: Uint) -> Self { Self::new(x) } - /// Get a `Unit` from an element + /// Get a `Uint` from an element, inverting [`F2Ext::new`]. + /// + /// # Returns + /// + /// The integer $a$ of at most $M$ bits such that applying `new` + /// gives `self`. That is, if $a$ is written in binary as $a_0 + /// \dots a_M$ then $\texttt{self} = \sum_{i=0}^M a_i x^i \in + /// \mathbb{F}\_{2}\[x\] / (f(x)) = \mathbb{F}\_{2^M}$ (type: + /// `Uint`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_f2_ext::*; + /// # use crypto_bigint::Uint; + /// # use fp::field_ops::FieldOps; + /// let a = F4::from_uint(Uint::<1>::from_u64(0b11)); // x + 1 + /// let b = F4::from_uint(Uint::<1>::from_u64(0b1000)); // x^3 = x^2 * x = x^2 + x = 1 + /// assert_eq!(a.as_uint(), Uint::<1>::from_u64(0b11)); + /// assert_eq!(b.as_uint(), Uint::<1>::from_u64(0b1)); + /// ``` pub fn as_uint(&self) -> Uint { self.value } /// Get the degree of the field extension + /// + /// # Returns + /// + /// The degree of the field extension (type: `usize`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_f2_ext::*; + /// # use crypto_bigint::Uint; + /// # use fp::field_ops::FieldOps; + /// let d = F4::degree(); + /// assert_eq!(d, 2_usize); + /// ``` pub fn degree() -> usize { P::degree() } diff --git a/fp/src/field_ops.rs b/fp/src/field_ops.rs index f78d95e..bac7ec1 100644 --- a/fp/src/field_ops.rs +++ b/fp/src/field_ops.rs @@ -7,8 +7,49 @@ use subtle::{Choice, ConditionallySelectable, CtOption}; /// /// Separated from [`FieldOps`] so that downstream code that doesn't /// need randomness is free of the `rand` dependency. +/// +/// # Required Methods +/// +/// * `random` - Generate a random field element. +/// +/// # Examples +/// +/// ``` +/// use crypto_bigint::{const_prime_monty_params, Uint}; +/// use fp::fp_element::FpElement; +/// use fp::field_ops::{FieldOps, FieldRandom}; +/// +/// /* +/// We will set up the field F_19 using FpElement, see the docs +/// of fp_element::FpElement. +/// */ +/// +/// const_prime_monty_params!(Fp19Modulus, Uint<1>, "0000000000000013", 2); +/// type F19 = FpElement; +/// +/// let mut rng = rand::rng(); +/// let a = F19::random(&mut rng); +/// ``` pub trait FieldRandom: Sized { - /// Sample a uniformly random element using a cryptographic RNG. + /// Sample a uniformly random element using a cryptographic random + /// number generator. + /// + /// # Arguments + /// + /// * `rng` a cryptographic rng (type: `&mut (impl rand::CryptoRng + rand::Rng)`) + /// + /// # Returns + /// + /// A random element of $\mathbb{F}\_{q}$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::{FieldOps, FieldRandom}; + /// let mut rng = rand::rng(); + /// let a = F19::random(&mut rng); + /// ``` fn random(rng: &mut (impl rand::CryptoRng + rand::Rng)) -> Self; } diff --git a/fp/src/fp_element.rs b/fp/src/fp_element.rs index 3e10a3b..e6bf528 100644 --- a/fp/src/fp_element.rs +++ b/fp/src/fp_element.rs @@ -408,7 +408,7 @@ impl FieldRandom for FpElement where MOD: ConstPrimeMontyParams, { - /// Sample a uniformly random element of Fp using a CSPRNG. + /// Sample a uniformly random element of $\mathbb{F}\_p$ using a CSPRNG. fn random(rng: &mut (impl rand::CryptoRng + rand::Rng)) -> Self { let minus_one = ConstMontyForm::::ZERO - ConstMontyForm::::ONE; let p_minus_1: Uint = minus_one.retrieve();