diff --git a/fp/src/_doctest_support.rs b/fp/src/_doctest_support.rs index 6a3238d..b4503da 100644 --- a/fp/src/_doctest_support.rs +++ b/fp/src/_doctest_support.rs @@ -32,3 +32,36 @@ pub mod _doctest_fp_ext { pub type F19_2 = FpExt; } + +pub mod _doctest_field_ops { + use crate::field_ops::FieldOps; + use crate::fp_element::FpElement; + use crate::fp_ext::{FpExt, IrreduciblePoly, TonelliShanksConstants}; + use crypto_bigint::{const_prime_monty_params, Uint}; + + const_prime_monty_params!(Fp19Modulus, Uint<1>, "0000000000000013", 2); + pub type F19 = FpElement; + + pub struct QuadPoly; + pub struct TSQuad; + + impl IrreduciblePoly for QuadPoly { + fn modulus() -> [F19; 2] { + [F19::one(), F19::zero()] + } + } + + impl TonelliShanksConstants for TSQuad { + const ORDER: Uint<1> = Uint::<1>::from_u64(360); + const HALF_ORDER: Uint<1> = Uint::<1>::from_u64(180); + const S: u64 = 3; + const T: Uint<1> = Uint::<1>::from_u64(45); + const PROJENATOR_EXP: Uint<1> = Uint::<1>::from_u64(22); + const TWOSM1: Uint<1> = Uint::<1>::from_u64(4); + fn root_of_unity() -> [FpElement; 2] { + [F19::from_u64(3), F19::from_u64(3)] + } + } + + pub type F19_2 = FpExt; +} diff --git a/fp/src/field_ops.rs b/fp/src/field_ops.rs index 3cf031e..f78d95e 100644 --- a/fp/src/field_ops.rs +++ b/fp/src/field_ops.rs @@ -1,4 +1,5 @@ -//! Core trait that every field element in the tower must implement. +//! The [`FieldOps`](self::field_ops::FieldOps) trait is the core +//! trait that every field must implement. use subtle::{Choice, ConditionallySelectable, CtOption}; @@ -16,76 +17,395 @@ pub trait FieldRandom: Sized { /// This trait abstracts the operations needed by the prime-field layer, /// extension fields, and higher-level elliptic-curve code. /// -/// It combines: -/// - basic ring-style operations (`+`, `-`, `*`, unary `-`); -/// - distinguished constants `zero()` and `one()`; -/// - predicates such as `is_zero()` and `is_one()`; -/// - field-specific operations such as inversion, Frobenius, norm, trace, -/// square roots, and Legendre-symbol-style square testing; -/// - constant-time conditional selection via `subtle::ConditionallySelectable`. +/// # Required Methods +/// +/// * `zero` - Returns the constant zero. +/// * `one` - Returns the constant one. +/// * `from_u64` - Coerces as `u64` into the field. +/// * `is_zero` - Checks if element is zero using constant time `Choice`. +/// * `is_one` - Checks if element is zero using constant time `Choice`. +/// * `negate` - Returns $-\texttt{self}$. +/// * `add` - Returns $\texttt{self} + \texttt{rhs}$. +/// * `sub` - Returns $\texttt{self} - \texttt{rhs}$. +/// * `mul` - Returns $\texttt{self} * \texttt{rhs}$. +/// * `square` - Returns $\texttt{self}^2$. +/// * `double` - Returns $2 * \texttt{self}$. +/// * `invert` - Returns $\texttt{self}^{-1}$. +/// * `frobenius` - Returns $\texttt{self}^{\mathrm{char} \mathbb{F}\_{q}}$. +/// * `norm` - Returns $\mathrm{Norm}\_{\mathbb{F}\_{q} / +/// \mathbb{F}\_{p}} \texttt{self}$. +/// * `trace` - Returns $\mathrm{Tr}\_{\mathbb{F}\_{q} / +/// \mathbb{F}\_{p}} \texttt{self}$. +/// * `sqrt` - Returns $\sqrt{\texttt{self}}$. +/// * `legendre` - Returns the "Legendre symbol" which is 1 if and +/// only if $\texttt{self}$ is square. +/// * `characteristic` - Returns the characteristic of the field. +/// * `degree` - Returns $[\mathbb{F}\_{p^M} : \mathbb{F}_p]$ +/// +/// # Provided Methods +/// +/// * `div` - Returns $\texttt{self} / \texttt{rhs}$. +/// * `pow_vartime` - Returns $\texttt{self}^\texttt{pow}$ using square and +/// multiply. +/// * `pow` - Computes $\texttt{self}^\texttt{pow}$ in constant time using a +/// Montgomery ladder. +/// * `frobenius_pow` - Computes $\texttt{self}^{p^k}$ +/// * `inverse_and_sqrt` - Computes $\texttt{self}^{-1}$ and $\sqrt{\texttt{self}}$. +/// * `inv_sqrt` - Computes $\sqrt{\texttt{self}^{-1}}$. +/// * `invertme_sqrtother` - Computes $\texttt{self}^{-1}$ and $\sqrt{\texttt{rhs}}$. +/// * `sqrt_ratio` - Computes $\sqrt{\texttt{self} / \texttt{rhs}}$. +/// +/// Scalars used by `pow_vartime` and `pow` are encoded as +/// little-endian `u64` limbs, matching the convention used elsewhere +/// in the library. +/// +/// # Note /// /// The trait is intentionally separate from [`FieldRandom`], so downstream code /// that only needs deterministic arithmetic does not need to depend on `rand`. /// -/// Scalars used by exponentiation methods are encoded as little-endian `u64` -/// limbs, matching the convention used elsewhere in the library. +/// # Examples +/// +/// ## The field $\mathbb{F}\_{19}$ +/// +/// ``` +/// use crypto_bigint::{const_prime_monty_params, Uint}; +/// use fp::fp_element::FpElement; +/// use fp::field_ops::FieldOps; +/// +/// /* +/// 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; +/// +/// /* Some standard tests */ +/// let a = F19::from_u64(17); +/// let b = F19::from_u64(5); +/// assert_eq!(a.add(&b), F19::from_u64(3)); +/// assert_eq!(a.sub(&b), F19::from_u64(12)); +/// assert_eq!(a.mul(&b), F19::from_u64(9)); +/// assert_eq!(a.invert().unwrap(), F19::from_u64(9)); +/// ``` +/// +/// ## The field $\mathbb{F}\_{19^2}$ +/// +/// ``` +/// # use crypto_bigint::{const_prime_monty_params, Uint}; +/// # use fp::fp_element::FpElement; +/// # use fp::field_ops::FieldOps; +/// # const_prime_monty_params!(Fp19Modulus, Uint<1>, "0000000000000013", 2); +/// # type F19 = FpElement; +/// /* Continuing from the above example */ +/// use fp::fp_ext::{FpExt, IrreduciblePoly, TonelliShanksConstants}; +/// +/// /* Setput the irreducible polynomial */ +/// struct QuadPoly; +/// impl IrreduciblePoly for QuadPoly { +/// fn modulus() -> [F19; 2] { +/// [F19::one(), F19::zero()] +/// } +/// } +/// +/// /* Setup the Tonelli--Shanks constants */ +/// struct TSQuad; +/// impl TonelliShanksConstants for TSQuad { +/// // p^2 - 1 +/// const ORDER: Uint<1> = Uint::<1>::from_u64(360); +/// // (p^2 - 1) / 2 +/// const HALF_ORDER: Uint<1> = Uint::<1>::from_u64(180); +/// // p^2 - 1 = 2^S * T with T odd +/// const S: u64 = 3; +/// const T: Uint<1> = Uint::<1>::from_u64(45); +/// // (T - 1) / 2 +/// const PROJENATOR_EXP: Uint<1> = Uint::<1>::from_u64(22); +/// // 2^(S - 1) +/// const TWOSM1: Uint<1> = Uint::<1>::from_u64(4); +/// // 2^S root of unity +/// fn root_of_unity() -> [FpElement; 2] { +/// [F19::from_u64(3), F19::from_u64(3)] +/// } +/// } +/// +/// /* Define the extension field */ +/// type F19_2 = FpExt; +/// +/// /* Some standard tests */ +/// /* Some standard tests */ +/// let a = F19_2::from_u64(17); +/// let b = F19_2::from_u64(5); +/// assert_eq!(a.add(&b), F19_2::from_u64(3)); +/// assert_eq!(a.sub(&b), F19_2::from_u64(12)); +/// assert_eq!(a.mul(&b), F19_2::from_u64(9)); +/// assert_eq!(a.invert().unwrap(), F19_2::from_u64(9)); +/// ``` pub trait FieldOps: Sized + Clone + PartialEq + Eq + Default + ConditionallySelectable { /// Create the constant zero + /// + /// # Returns + /// + /// The constant $0 \in \mathbb{F}\_q$ (type: `Self`). fn zero() -> Self; - /// Create the constant one + /// Create the constant one + /// + /// # Returns + /// + /// The constant $1 \in \mathbb{F}\_q$ (type: `Self`). fn one() -> Self; - /// Check if element is zero + /// Convert `u64` to the field. + /// + /// # Arguments + /// + /// * `x` an 64 bit integer (type: `u64`). + /// + /// # Returns + /// + /// The element $x \in \mathbb{F}\_p$ embedded in $\mathbb{F}\_q$ + /// (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let my_zero = F19::from_u64(0); + /// assert_eq!(my_zero, F19::zero()); + /// let my_one = F19::from_u64(1); + /// assert_eq!(my_one, F19::one()); + /// ``` + fn from_u64(x: u64) -> Self; + + /// Checks if an element is zero + /// + /// # Returns + /// + /// `true` if and only if `self` is zero (type: `Choice`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let x = F19::zero(); + /// assert!(bool::from(x.is_zero())); + /// ``` fn is_zero(&self) -> Choice; - /// Check if element is one + /// Checks if an element is one + /// + /// # Returns + /// + /// `true` if and only if `self` is one (type: `Choice`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let x = F19::one(); + /// assert!(bool::from(x.is_one())); + /// ``` fn is_one(&self) -> Choice; /// Negate `self` to `-self` + /// + /// # Returns + /// + /// $-\texttt{self}$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let x = F19::from_u64(17); + /// assert_eq!(x.negate(), F19::from_u64(2)); + /// ``` fn negate(&self) -> Self; - /// Add `rhs` to `self` + /// Returns $\texttt{self} + \texttt{rhs}$. + /// + /// # Arguments + /// + /// * `rhs` element of $\mathbb{F}\_{q}$ (type: `&Self`). + /// + /// # Returns + /// + /// $\texttt{self} + \texttt{rhs}$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(10); + /// let b = F19::from_u64(11); + /// let a_add_b = a.add(&b); + /// assert_eq!(a_add_b, F19::from_u64(2)); + /// ``` fn add(&self, rhs: &Self) -> Self; - /// Sub `rhs` from `self` + /// Returns $\texttt{self} - \texttt{rhs}$. + /// + /// # Arguments + /// + /// * `rhs` element of $\mathbb{F}\_{q}$ (type: `&Self`). + /// + /// # Returns + /// + /// $\texttt{self} - \texttt{rhs}$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(4); + /// let b = F19::from_u64(8); + /// let a_sub_b = a.sub(&b); + /// assert_eq!(a_sub_b, F19::from_u64(15)); + /// ``` fn sub(&self, rhs: &Self) -> Self; - /// Multipliy `self` by `rhs` + /// Returns $\texttt{self} * \texttt{rhs}$. + /// + /// # Arguments + /// + /// * `rhs` element of $\mathbb{F}\_{q}$ (type: `&Self`). + /// + /// # Returns + /// + /// $\texttt{self} * \texttt{rhs}$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(4); + /// let b = F19::from_u64(3); + /// let a_times_b = a.mul(&b); + /// assert_eq!(a_times_b, F19::from_u64(12)); + /// ``` fn mul(&self, rhs: &Self) -> Self; - /// Square `self` + /// Returns $\texttt{self}^2$. + /// + /// # Returns + /// + /// $\texttt{self}^2$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(4); + /// let a_sq = a.square(); + /// assert_eq!(a_sq, F19::from_u64(16)); + /// ``` fn square(&self) -> Self; - /// Double `self` + /// Returns $2 * \texttt{self}$. + /// + /// # Returns + /// + /// $2 * \texttt{self}$ (type: `Self`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(4); + /// let a_doub = a.double(); + /// assert_eq!(a_doub, F19::from_u64(8)); + /// ``` fn double(&self) -> Self; - /// Invert `self` + /// Returns $\texttt{self}^{-1}$. + /// + /// # Returns + /// + /// $\texttt{self}^{-1}$ which is none if and only if `self` is + /// nonzero (type: `CtOption`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(2); + /// let a_inv = a.invert().unwrap(); + /// assert_eq!(a_inv, F19::from_u64(10)); + /// let z = F19::zero(); + /// let z_inv = z.invert(); + /// assert!(bool::from(z_inv.is_none())); + /// ``` fn invert(&self) -> CtOption; - /// Divide `self` by `rhs` + /// Returns $\texttt{self} / \texttt{rhs}$. + /// + /// # Arguments + /// + /// * `rhs` element of $\mathbb{F}\_{q}$ (type: `&Self`). + /// + /// # Returns + /// + /// $\texttt{self} / \texttt{rhs}$ which is none if and only if + /// `rhs` is nonzero (type: `CtOption`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(4); + /// let b = F19::from_u64(2); + /// let a_div_b = a.div(&b).unwrap(); + /// assert_eq!(a_div_b, F19::from_u64(2)); + /// let z = F19::zero(); + /// let fail = a.div(&z); + /// assert!(bool::from(fail.is_none())); + /// ``` fn div(&self, rhs: &Self) -> CtOption { rhs.invert().map(|inv| self.mul(&inv)) } - /// `self^exp` using square-and multiply (litte-endian bit order) + /// Computes $\texttt{self}^\texttt{exp}$ in vartime. /// /// # Arguments /// - /// * `&self` - Finite field element (type: `Self`) - /// * `exp` - Exponent (type: &[u64]) + /// * `exp` - Exponent (type: `&[u64]`) /// /// # Returns /// - /// `&self^exp` (type: `Self`) + /// `self^exp` (type: `Self`) /// - /// # Warnings + /// # WARNING /// /// This function is constant time only if two exponents `exp1` /// and `exp2` are equal as [u64] (i.e., they are the same number /// AND the same number of limbs) - // - // # Notes + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(3); + /// let a_cubed = a.pow_vartime(&[3]); + /// assert_eq!(a_cubed, F19::from_u64(8)); + /// ``` + /// + /// # Notes + /// + /// The provided function is implemented using square-and + /// multiply (litte-endian bit order). // // `::mul` is used instead of // `result.mul(&base)` because `FieldOps` requires `Mul Self { let mut result = Self::one(); let mut base = self.clone(); @@ -157,10 +489,46 @@ pub trait FieldOps: Sized + Clone + PartialEq + Eq + Default + ConditionallySele result } - /// Compute `self^p` the frobenius acting on `self` + /// Compute $\texttt{self}^p$ the Frobenius endomorphism + /// + /// # Returns + /// + /// $\texttt{self}^p$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// assert_eq!(a.frobenius(), a); + /// let b = F19_2::from_u64_vec([0,1]); // The element i with i^2 = -1 + /// assert_eq!(b.frobenius(), b.negate()); + /// ``` fn frobenius(&self) -> Self; - /// Compute `self^{p^k}` a power of the frobenius + /// Compute $\texttt{self}^{p^k}$ a power of the Frobenius + /// endomorphism + /// + /// # Arguments + /// + /// * `k` a positive integer (type: `u32`). + /// + /// # Returns + /// + /// $\texttt{self}^{p^k}$ (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// assert_eq!(a.frobenius_pow(3), a); + /// let b = F19_2::from_u64_vec([0,1]); // The element i with i^2 = -1 + /// assert_eq!(b.frobenius_pow(2), b); + /// assert_eq!(b.frobenius_pow(3), b.frobenius()); + /// ``` fn frobenius_pow(&self, k: u32) -> Self { let mut result = self.clone(); for _ in 0..k { @@ -169,71 +537,161 @@ pub trait FieldOps: Sized + Clone + PartialEq + Eq + Default + ConditionallySele result } - /// Compute the norm of `self` down to $\mathbb{F}_p$ (as an - /// element of type `Self`) + /// Computes the norm of `self` to $\mathbb{F}\_{p}$ embedded as an element + /// of $\mathbb{F}\_{q}$. + /// + /// As a reminder the norm is defined as the product over all the + /// Galois conjugates that is + /// $$ N\_{\mathbb{F}\_{q}/\mathbb{F}\_p}(a) = \prod\_{\sigma \in \mathrm{Gal}} \sigma(a) $$ + /// + /// # Returns + /// + /// The norm of self (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19_2::from_u64_vec([3, 5]); + /// let nm_a = F19_2::from_u64_vec([15, 0]); + /// assert_eq!(a.norm(), nm_a); + /// ``` fn norm(&self) -> Self; - /// Compute the trace of `self` down to $\mathbb{F}_p$ (as an - /// element of type `Self`) + /// Computes the trace of `self` to $\mathbb{F}\_{p}$ embedded as an element + /// of $\mathbb{F}\_{q}$. + /// + /// As a reminder the trace is defined as the sum over all the + /// Galois conjugates that is + /// $$ \mathrm{tr}\_{\mathbb{F}\_{q}/\mathbb{F}\_p}(a) = \sum\_{\sigma \in \mathrm{Gal}} \sigma(a) $$ + /// + /// # Returns + /// + /// The trace of self (type: `Self`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19_2::from_u64_vec([3, 5]); + /// let tr_a = F19_2::from_u64_vec([6, 0]); + /// assert_eq!(a.trace(), tr_a); + /// ``` fn trace(&self) -> Self; - /// Returns a squareroot if it exists + /// Computes the square root of `self` /// - /// # Arguments + /// # Returns /// - /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: `Self`) + /// $\sqrt{\texttt{self}}$ a choice of squareroot which is not + /// `none` if the squareroot exists (type: `CtOption`) /// - /// # Returns + /// # Examples /// - /// * $\sqrt{\texttt{self}}$ which is not `none` if and only if - /// the square root of `self` exists (type: `CtOption`) + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let sqrt_a = a.sqrt().unwrap(); + /// assert_eq!(sqrt_a.mul(&sqrt_a), a); + /// ``` fn sqrt(&self) -> CtOption; - /// Computes the inverse and square root of `self` + /// Returns both the inverse and sqrt of `self` /// - /// # Arguments + /// # Returns /// - /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: `Self`) + /// $(1/\texttt{self}, \sqrt{\texttt{self}})$ which is + /// `self.invert()` and `self.sqrt()` (type: `CtOption`, + /// `CtOption`) /// - /// # Returns + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let (inv_a, sqrt_a) = a.inverse_and_sqrt(); + /// let inv_a = inv_a.unwrap(); + /// let sqrt_a = sqrt_a.unwrap(); + /// assert!(bool::from(inv_a.mul(&a).is_one())); + /// assert_eq!(sqrt_a.mul(&sqrt_a), a); + /// ``` + /// + /// # Note /// - /// * `(inv, sqrt)` the inverse and the square root of `self`. The - /// former is none if and only if nonzero and the latter is not - /// none if and only if there exists a squareroot in - /// $\mathbb{F}_{p^M}$ (type: `(CtOption, CtOption)`) + /// The default implementation just combines the `sqrt` and + /// `invert` methods. This is provided as a separate method so + /// that a motivated user can implement tricks such as those found + /// in Section 2 of . See e.g., + /// implementation in [`FpExt`](crate::fp_ext::FpExt). fn inverse_and_sqrt(&self) -> (CtOption, CtOption) { (self.invert(), self.sqrt()) } - /// Computes the square root the inverse of `self` + /// Computes the inverse and squareroot of `self`. /// - /// # Arguments + /// # Returns /// - /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: `Self`) + /// $1 / \sqrt{\texttt{self}}$, the inverse of the squareroot of + /// `self` (type: `CtOption`) /// - /// # Returns + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let inv_sqrt_a = a.inv_sqrt(); + /// let inv_sqrt_a = inv_sqrt_a.unwrap(); + /// assert_eq!(inv_sqrt_a.mul(&inv_sqrt_a), a.invert().unwrap()); + /// ``` /// - /// * $1 / \sqrt{\texttt{self}}$. The is not none if and only if - /// `self` is both nonzero there exists a squareroot in - /// $\mathbb{F}_{p^M}$ (type: `CtOption`) + /// # Note + /// + /// The default implementation just combines the `sqrt` and + /// `invert` methods. This is provided as a separate method so + /// that a motivated user can implement tricks such as those found + /// in Section 2 of . See e.g., + /// implementation in [`FpExt`](crate::fp_ext::FpExt). fn inv_sqrt(&self) -> CtOption { self.sqrt().and_then(|s| s.invert()) } - /// Computes the inverse of `self` and square root of `rhs` + /// Inverse of `self` and squareroot of `rhs`. /// /// # Arguments /// - /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: `Self`) - /// * `rhs` - Element of $\mathbb{F}_{p^M}$ (type: &Self) + /// * `rhs` - element of $\mathbb{F}\_{p^M}$ (type: `&Self`) /// /// # Returns /// - /// * `(inv, sqrt)` where `inv` is the inverse of `self` `sqrt` is - /// the square root fo `rhs`. `inv` is `none` if and only if - /// `self` is zero and the `sqrt` is not none if and only if - /// there exists a squareroot of `rhs` in $\mathbb{F}_{p^M}$ - /// (type: `(CtOption, CtOption)`) + /// $(1 / \texttt{self}, \sqrt{\texttt{rhs}})$, the former is none + /// if and only if `self` is nonzero and the latter is none if and + /// only if there is no squareroot of `rhs` in $\mathbb{F}\_{p^M}$ + /// (type: (`CtOption`, `CtOption`)) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let b = F19::from_u64(4); + /// let (inv_a, sqrt_b) = a.invertme_sqrtother(&b); + /// let inv_a = inv_a.unwrap(); + /// let sqrt_b = sqrt_b.unwrap(); + /// assert!(bool::from(inv_a.mul(&a).is_one())); + /// assert_eq!(sqrt_b.square(), b); + /// ``` + /// + /// # Note + /// + /// The default implementation just combines the `sqrt` and + /// `invert` methods. This is provided as a separate method so + /// that a motivated user can implement tricks such as those found + /// in Section 2 of . See e.g., + /// implementation in [`FpExt`](crate::fp_ext::FpExt). fn invertme_sqrtother(&self, rhs: &Self) -> (CtOption, CtOption) { (self.invert(), rhs.sqrt()) } @@ -241,31 +699,106 @@ pub trait FieldOps: Sized + Clone + PartialEq + Eq + Default + ConditionallySele /// Computes the squareroot of a ratio `self/rhs` /// /// # Arguments - /// - /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: `Self`) - /// * `rhs` - Element of $\mathbb{F}_{p^M}$ (type: `&Self`) + /// * `rhs` - Element of $\mathbb{F}\_{p^M}$ (type: `&Self`) /// /// # Returns /// - /// * $\sqrt{\texttt{self} / \texttt{rhs}}$ which is not `none` if and only - /// both `rhs` is invertible and the ratio has a rational squareroot - /// (type: `(CtOption, CtOption))` + /// $\sqrt{\texttt{self}/\texttt{rhs}}$, the squareroot of the + /// ratio which is not none if and only if `rhs` is invertible and + /// the ratio has an $\mathbb{F}\_{p^M}$ rational squareroot (type: + /// `CtOption`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let b = F19::from_u64(4); + /// let sqrt_a_over_b = a.sqrt_ratio(&b); + /// let sqrt_a_over_b = sqrt_a_over_b.unwrap(); + /// assert_eq!(sqrt_a_over_b.square().mul(&b), a); + /// ``` + /// + /// # Note + /// + /// The default implementation just combines the `sqrt` and + /// `invert` methods. This is provided as a separate method so + /// that a motivated user can implement tricks such as those found + /// in Section 2 of . See e.g., + /// implementation in [`FpExt`](crate::fp_ext::FpExt). fn sqrt_ratio(&self, rhs: &Self) -> CtOption { rhs.invert().and_then(|inv_rhs| self.mul(&inv_rhs).sqrt()) } - /// Computes the "Legendre symbol" i.e., if 0,1,-1 depending if - /// `self` is 0, a square or a nonsquare. + /// Implements the "Legendre symbol" which is 1 if and only if + /// `self` is a quadratic residue in $\mathbb{F}\_{q}$. + /// + /// As a reminder the "Legendre symbol" for $a \in \mathbb{F}\_{q}$ is defined as + /// $$ \begin{cases} 0 & \text{ if $a = 0$,} \\\\ 1 & \text{if $a$ + /// is a square,} \\\\ -1 & \text{if $a$ is not a square.} \end{cases} $$ + /// + /// # Returns + /// + /// The Legendre symbol of `self` (type: `i8`) + /// + /// # WARNING + /// + /// Not required to be constant time if `self` is zero + /// + /// # Examples + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let a = F19::from_u64(9); + /// let b = F19::from_u64(2); + /// let c = F19::zero(); + /// let ls_a = a.legendre(); + /// let ls_b = b.legendre(); + /// let ls_c = c.legendre(); + /// assert_eq!(ls_a, 1_i8); + /// assert_eq!(ls_b, -1_i8); + /// assert_eq!(ls_c, 0_i8); + /// ``` fn legendre(&self) -> i8; /// Returns the characteristic of the field. + /// + /// # Returns + /// + /// The characteristic of $\mathbb{F}\_{q}$ as 64 bit limbs (type: + /// `Vec`) + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let p = F19::characteristic(); + /// let p_2 = F19_2::characteristic(); + /// assert_eq!(p, p_2); + /// assert_eq!(p[0], 19_u64); + /// ``` fn characteristic() -> Vec; - /// Returns the extension degree of the field. + /// Returns the degree of the field over $\mathbb{F}_p$. + /// + /// # Returns + /// + /// The degree of $\mathbb{F}\_{q} / \mathbb{F}\_{p}$ (type: + /// `u32`). + /// + /// # Examples + /// + /// ``` + /// # use fp::_doctest_support::_doctest_field_ops::*; + /// # use fp::field_ops::FieldOps; + /// let d_1 = F19::degree(); + /// let d_2 = F19_2::degree(); + /// assert_eq!(d_1, 1_u32); + /// assert_eq!(d_2, 2_u32); + /// ``` fn degree() -> u32; - - /// Convert u64 to the field. - fn from_u64(x: u64) -> Self; } /// Trait for field types that can be constructed from a field-specific /// representation. @@ -313,10 +846,10 @@ macro_rules! ref_field_impl { impl<$F> $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -326,10 +859,10 @@ macro_rules! ref_field_impl { impl<$F: $First $(+ $Rest)*> $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -370,10 +903,10 @@ macro_rules! ref_field_trait_impl { impl<$F> $Trait for $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -383,10 +916,10 @@ macro_rules! ref_field_trait_impl { impl<$F: $First $(+ $Rest)*> $Trait for $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -434,10 +967,10 @@ macro_rules! ref_field_trait_impl_path { impl<$F> $Trait for $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -447,10 +980,10 @@ macro_rules! ref_field_trait_impl_path { impl<$F: $First $(+ $Rest)*> $Trait for $Ty where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, { $($body)* } @@ -477,10 +1010,10 @@ macro_rules! ref_field_fn { fn $name<$F>($($args)*) -> $Ret where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, $body }; @@ -488,10 +1021,10 @@ macro_rules! ref_field_fn { fn $name<$F: $First $(+ $Rest)*>($($args)*) -> $Ret where $F: $crate::field_ops::FieldOps, - for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, - for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, - for<'a> &'a $F: std::ops::Neg, + for<'a, 'b> &'a $F: std::ops::Add<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Sub<&'b $F, Output = $F>, + for<'a, 'b> &'a $F: std::ops::Mul<&'b $F, Output = $F>, + for<'a> &'a $F: std::ops::Neg, $body }; } @@ -521,24 +1054,24 @@ macro_rules! ref_field_fns { ( $(#[$meta:meta])* fn $name:ident<$F:ident> ( $($args:tt)* ) -> $Ret:ty $body:block - $($rest:tt)* + $($rest:tt)* ) => { $(#[$meta])* - $crate::ref_field_fn! { - fn $name<$F>($($args)*) -> $Ret $body - } + $crate::ref_field_fn! { + fn $name<$F>($($args)*) -> $Ret $body + } $crate::ref_field_fns! { $($rest)* } }; ( $(#[$meta:meta])* fn $name:ident<$F:ident : $First:ident $(+ $Rest:ident)*> ( $($args:tt)* ) -> $Ret:ty $body:block - $($rest:tt)* + $($rest:tt)* ) => { $(#[$meta])* - $crate::ref_field_fn! { - fn $name<$F: $First $(+ $Rest)*>($($args)*) -> $Ret $body - } + $crate::ref_field_fn! { + fn $name<$F: $First $(+ $Rest)*>($($args)*) -> $Ret $body + } $crate::ref_field_fns! { $($rest)* } }; } diff --git a/fp/src/fp_element.rs b/fp/src/fp_element.rs index 60e6b00..3e10a3b 100644 --- a/fp/src/fp_element.rs +++ b/fp/src/fp_element.rs @@ -1,5 +1,38 @@ //! Base prime-field element $\mathbb{F}_p = \mathbb{Z} / p\mathbb{Z}$ //! backed by `crypto-bigint`. +//! +//! # Overview +//! +//! Given an odd prime $p$ supplies $\mathbb{F}_p$ the finite field with +//! $p$ elements. +//! +//! This module provides a single generic type [`FpElement`](self::fp_element::FpElement). +//! +//! # Example +//! +//! ``` +//! use crypto_bigint::{const_prime_monty_params, Uint}; +//! use fp::fp_element::FpElement; +//! use fp::field_ops::FieldOps; +//! +//! /* +//! We will set up the field F_19 so note that 0000000000000013 is +//! equal to 19 in Hexadecimal and that 2 is a generator (primitive +//! root) of (Z/pZ)^* +//! */ +//! +//! const_prime_monty_params!(Fp19Modulus, Uint<1>, "0000000000000013", 2); +//! type F19 = FpElement; +//! +//! /* Some standard tests */ +//! let a = F19::from_u64(17); +//! let b = F19::from_u64(5); +//! assert_eq!((&a + &b).as_limbs()[0], 3); +//! assert_eq!((&a - &b).as_limbs()[0], 12); +//! assert_eq!((&a * &b).as_limbs()[0], 9); +//! assert_eq!((a.invert().unwrap()).as_limbs()[0], 9); +//! ``` use core::ops::{Add, Mul, Neg, Sub}; use std::fmt; @@ -14,6 +47,8 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; /// An element of the prime field $\mathbb{F}_p = /// \mathbb{Z}/p\mathbb{Z}$, stored in Montgomery form. /// +/// # Note +/// /// The internal value uses `crypto-bigint`'s [`ConstMontyForm`], so arithmetic /// is performed in Montgomery representation while the public constructors and /// accessors accept and return canonical integers. diff --git a/fp/src/fp_ext.rs b/fp/src/fp_ext.rs index 65913eb..0afb765 100644 --- a/fp/src/fp_ext.rs +++ b/fp/src/fp_ext.rs @@ -1235,7 +1235,8 @@ where /// /// # Returns /// - /// $\sqrt{\texttt{self}}$ a choice of squareroot (type: `Self`) + /// $\sqrt{\texttt{self}}$ a choice of squareroot which is not + /// `none` if the squareroot exists (type: `CtOption`) /// /// # Examples /// @@ -1363,11 +1364,10 @@ where /// /// # Returns /// - /// The pair $(1 / \texttt{self}, \sqrt{\texttt{rhs}})$. The - /// former is none if and only if `self` is nonzero and the latter - /// is none if and only if there is no squareroot of `rhs` in - /// $\mathbb{F}\_{p^M}$ (type: (`CtOption`, - /// `CtOption`)) + /// $(1 / \texttt{self}, \sqrt{\texttt{rhs}})$, the former is none + /// if and only if `self` is nonzero and the latter is none if and + /// only if there is no squareroot of `rhs` in $\mathbb{F}\_{p^M}$ + /// (type: (`CtOption`, `CtOption`)) /// /// # Examples ///