Skip to main content

fp/
field_ops.rs

1//! Core trait that every field element in the tower must implement.
2
3use std::ops::{Add, Mul, Neg, Sub};
4use subtle::{Choice, ConditionallySelectable, CtOption};
5
6/// Trait for generating cryptographically secure random field elements.
7///
8/// Separated from [`FieldOps`] so that downstream code that doesn't
9/// need randomness is free of the `rand` dependency.
10pub trait FieldRandom: Sized {
11    /// Sample a uniformly random element using a cryptographic RNG.
12    fn random(rng: &mut (impl rand::CryptoRng + rand::Rng)) -> Self;
13}
14
15/// Core arithmetic interface for field elements used throughout the library.
16///
17/// This trait abstracts the operations needed by the prime-field layer,
18/// extension fields, and higher-level elliptic-curve code.
19///
20/// It combines:
21/// - basic ring-style operations (`+`, `-`, `*`, unary `-`);
22/// - distinguished constants `zero()` and `one()`;
23/// - predicates such as `is_zero()` and `is_one()`;
24/// - field-specific operations such as inversion, Frobenius, norm, trace,
25///   square roots, and Legendre-symbol-style square testing;
26/// - constant-time conditional selection via `subtle::ConditionallySelectable`.
27///
28/// The trait is intentionally separate from [`FieldRandom`], so downstream code
29/// that only needs deterministic arithmetic does not need to depend on `rand`.
30///
31/// Scalars used by exponentiation methods are encoded as little-endian `u64`
32/// limbs, matching the convention used elsewhere in the library.
33pub trait FieldOps:
34    Sized
35    + Clone
36    + PartialEq
37    + Eq
38    + Add<Output = Self>
39    + Sub<Output = Self>
40    + Mul<Output = Self>
41    + Neg<Output = Self>
42    + Default
43    + ConditionallySelectable
44{
45    /// Create the constant zero
46    fn zero() -> Self;
47
48    /// Create the constant one  
49    fn one() -> Self;
50
51    /// Check if element is zero
52    fn is_zero(&self) -> Choice;
53
54    /// Check if element is one
55    fn is_one(&self) -> Choice;
56
57    /// Negate `self` to `-self`
58    fn negate(&self) -> Self;
59
60    /// Add `rhs` to `self`
61    fn add(&self, rhs: &Self) -> Self;
62
63    /// Sub `rhs` from `self`
64    fn sub(&self, rhs: &Self) -> Self;
65
66    /// Multipliy `self` by `rhs`
67    fn mul(&self, rhs: &Self) -> Self;
68
69    /// Square `self`
70    fn square(&self) -> Self;
71
72    /// Double `self`
73    fn double(&self) -> Self;
74
75    /// Invert `self`
76    fn invert(&self) -> CtOption<Self>;
77
78    /// Divide `self` by `rhs`
79    fn div(&self, rhs: &Self) -> CtOption<Self> {
80        rhs.invert().map(|inv| self.mul(&inv))
81    }
82
83    /// `self^exp` using square-and multiply (litte-endian bit order)
84    ///
85    /// It is constant time for fixed `exp`
86    ///
87    /// # Arguments
88    ///
89    /// * `&self` - Finite field element (type: self)
90    /// * `exp` - Exponent (type: &[u64])
91    ///
92    /// # Returns
93    ///
94    /// `&self^exp` (type: Self)
95    ///
96    /// # Why `<Self as FieldOps>::mul` instead of `result.mul(&base)`
97    ///
98    /// `FieldOps` requires `Mul<Output = Self>` as a supertrait, so `Self`
99    /// exposes **two** methods named `mul`:
100    ///
101    ///   - `<Self as Mul>::mul(self, rhs: Self) -> Self`   ← operator, takes by value
102    ///   - `<Self as FieldOps>::mul(&self, rhs: &Self) -> Self` ← ours, takes by ref
103    ///
104    /// Writing `result.mul(&base)` triggers method resolution, which picks
105    /// `Mul::mul` (the operator) because it was declared first in the supertrait
106    /// list. `Mul::mul` expects `Self`, not `&Self` → E0308.
107    ///
108    /// Fully-qualified syntax `<Self as FieldOps>::mul(...)` bypasses method
109    /// resolution entirely and calls exactly the trait method we want.
110    fn pow_vartime(&self, exp: &[u64]) -> Self {
111        let mut result = Self::one();
112        let mut base = self.clone();
113
114        for &limb in exp {
115            let mut limb = limb;
116            for _ in 0..64 {
117                let mybit = limb & 1;
118                let tmp = <Self as FieldOps>::mul(&result, &base);
119                result = Self::conditional_select(&result, &tmp, (mybit as u8).into());
120                base = <Self as FieldOps>::square(&base);
121                limb >>= 1;
122            }
123        }
124        result
125    }
126
127    /// `self^pow` in constant time using a Montgomery ladder
128    ///
129    /// Uses a Montgomery ladder to compute `self^exp`
130    /// WARNING: Only constant time if the number of limbs of exp is
131    /// constant
132    ///
133    /// # Arguments
134    ///
135    /// * `&self` - Element of $\mathbb{F}_p$ (type: self)
136    /// * `exp` - Exponent (type: &[u64])
137    ///
138    /// # Returns
139    ///
140    /// The value `self^pow` (type: Self)
141    ///
142    /// # Todo
143    ///
144    /// Use `subtle` and `conditional_swap` to make true constant time
145    fn pow(&self, exp: &[u64]) -> Self {
146        let mut result = Self::one();
147        let mut base = self.clone();
148
149        for &limb in exp.iter().rev() {
150            let mut limb = limb.reverse_bits();
151            for _ in 0..64 {
152                let mybit = limb & 1;
153                Self::conditional_swap(&mut base, &mut result, (mybit as u8).into());
154                base = <Self as FieldOps>::mul(&result, &base);
155                result = <Self as FieldOps>::square(&result);
156                Self::conditional_swap(&mut base, &mut result, (mybit as u8).into());
157                limb >>= 1;
158            }
159        }
160        result
161    }
162
163    /// Compute `self^p` the frobenius acting on `self`
164    fn frobenius(&self) -> Self;
165
166    /// Compute `self^{p^k}` a power of the frobenius
167    fn frobenius_pow(&self, k: u32) -> Self {
168        let mut result = self.clone();
169        for _ in 0..k {
170            result = result.frobenius();
171        }
172        result
173    }
174
175    /// compute the norm of `self` down to $\mathbb{F}_p$ (as an
176    /// element of type `Self`)
177    fn norm(&self) -> Self;
178
179    /// compute the trace of `self` down to $\mathbb{F}_p$ (as an
180    /// element of type `Self`)
181    fn trace(&self) -> Self;
182
183    /// Returns a squareroot if it exists
184    ///
185    /// Returns a squareroof of `self` if it exists in the finite
186    /// field $\mathbb{F}_{p^M}$. The return type is `CtOption<Self>`
187    /// and it is not none if and only if the squareroot exists. This
188    /// is an implementation fo the Tonelli--Shanks algorithm in the
189    /// multiplicative group $\mathbb{F}_{p^M}^*$
190    ///
191    /// # Arguments
192    ///
193    /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: self)
194    ///
195    /// # Returns
196    ///
197    /// The square root of `self` (type: `CtOption<Self>`)
198    fn sqrt(&self) -> CtOption<Self>;
199
200    /// Computes the inverse and square root of `self`
201    ///
202    /// Computes simulaineously the inverse and square root of `self`.
203    ///
204    /// # Arguments
205    ///
206    /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: self)
207    ///
208    /// # Returns
209    ///
210    /// The inverse and square root of `self`. The former is none if
211    /// and only if nonzero and the latter is not none if and only if
212    /// there exists a squareroot in $\mathbb{F}_{p^M}$
213    /// (type: `(CtOption<Self>, CtOption<self>)`)
214    fn inverse_and_sqrt(&self) -> (CtOption<Self>, CtOption<Self>) {
215        (self.invert(), self.sqrt())
216    }
217
218    /// Computes the square root the inverse of `self`
219    ///
220    /// # Arguments
221    ///
222    /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: self)
223    ///
224    /// # Returns
225    ///
226    /// The square root of the inverse of `self`. The former is not
227    /// none if and only if it is both nonzero there exists a
228    /// squareroot in $\mathbb{F}_{p^M}$ (type: `CtOption<self>`)
229    fn inv_sqrt(&self) -> CtOption<Self> {
230        self.sqrt().and_then(|s| s.invert())
231    }
232
233    /// Computes the inverse of `self` and square root of `rhs`
234    ///
235    /// Computes simulaineously the inverse of `self` and square root
236    /// of `rhs`.
237    ///
238    /// # Arguments
239    ///
240    /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: self)
241    /// * `rhs` - Element of $\mathbb{F}_{p^M}$ (type: &Self)
242    ///
243    /// # Returns
244    ///
245    /// The inverse of `self` and square root fo `rhs`. Theq former is
246    /// none if and only if `self` is nonzero and the latter is not
247    /// none if and only if there exists a squareroot of `rhs` in $\mathbb{F}_{p^M}$
248    /// (type: `(CtOption<Self>, CtOption<self>)`)
249    fn invertme_sqrtother(&self, rhs: &Self) -> (CtOption<Self>, CtOption<Self>) {
250        (self.invert(), rhs.sqrt())
251    }
252
253    /// Computes the squareroot of a ratio `self/rhs`
254    ///
255    /// # Arguments
256    ///
257    /// * `&self` - Element of $\mathbb{F}_{p^M}$ (type: self)
258    /// * `rhs` - Element of $\mathbb{F}_{p^M}$ (type: &Self)
259    ///
260    /// # Returns
261    ///
262    /// The squareroot of the ratio `self/rhs` is not none if and only
263    /// if `rhs` is invertible and the ratio has an $\mathbb{F}_{p^M}$ squareroot
264    /// (type: `(CtOption<Self>, CtOption<self>))`
265    fn sqrt_ratio(&self, rhs: &Self) -> CtOption<Self> {
266        rhs.invert().and_then(|inv_rhs| self.mul(&inv_rhs).sqrt())
267    }
268
269    /// Computes the "Legendre symbol" i.e., if 0,1,-1 depending if
270    /// `self` is 0, a square or a nonsquare.
271    fn legendre(&self) -> i8;
272
273    /// Returns the characteristic of the field.
274    fn characteristic() -> Vec<u64>;
275
276    /// Returns the extension degree of the field.
277    fn degree() -> u32;
278
279    /// Convert u64 to the field.
280    fn from_u64(x: u64) -> Self;
281
282}
283/// Trait for field types that can be constructed from a field-specific
284/// representation.
285pub trait FieldFromRepr: FieldOps {
286    /// The representation type accepted by this field.
287    type Repr;
288
289    /// Constructs a field element from the given representation.
290    fn from_repr(x: Self::Repr) -> Self;
291}