clock_curve_math/extensible/
generic_field.rs

1//! Generic field arithmetic implementation.
2//!
3//! This module provides generic field elements and operations that can work
4//! with different field parameters and moduli.
5
6use super::field_parameters::FieldParameters;
7use crate::bigint::BigInt;
8use crate::error::MathError;
9
10/// Generic field element with extensible parameters.
11///
12/// This struct provides a generic field element that can work with
13/// different moduli and limb configurations through the FieldParameters trait.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub struct GenericFieldElement<P: FieldParameters> {
16    /// The Montgomery representation of the field element
17    value: BigInt,
18    /// Phantom data to tie the element to its parameters
19    _params: core::marker::PhantomData<P>,
20}
21
22#[allow(dead_code)]
23impl<P: FieldParameters> GenericFieldElement<P> {
24    /// Create a new field element from a BigInt.
25    ///
26    /// The value is automatically converted to Montgomery form.
27    pub fn new(value: BigInt) -> Result<Self, MathError> {
28        // Validate the value is in range
29        if value.ct_cmp(&P::modulus()) != core::cmp::Ordering::Less {
30            return Err(MathError::InvalidInput);
31        }
32
33        // For simplicity in the extensible implementation, store values directly
34        // Full Montgomery optimization can be added later
35        Ok(Self {
36            value,
37            _params: core::marker::PhantomData,
38        })
39    }
40
41    /// Create a field element from raw Montgomery representation.
42    ///
43    /// This is unsafe because it doesn't validate the input.
44    pub unsafe fn from_montgomery_unchecked(value: BigInt) -> Self {
45        Self {
46            value,
47            _params: core::marker::PhantomData,
48        }
49    }
50
51    /// Create a field element from raw Montgomery representation with validation.
52    ///
53    /// This validates that the input is in the correct range [0, modulus).
54    pub fn from_montgomery_checked(value: BigInt) -> Result<Self, MathError> {
55        let modulus = P::modulus();
56        if value.ct_cmp(&BigInt::from_u64(0)) == core::cmp::Ordering::Less
57            || value.ct_cmp(&modulus) != core::cmp::Ordering::Less
58        {
59            return Err(MathError::InvalidFieldElement);
60        }
61        Ok(Self {
62            value,
63            _params: core::marker::PhantomData,
64        })
65    }
66
67    /// Get the Montgomery representation of this field element.
68    ///
69    /// Returns a reference to the internal Montgomery-form value.
70    /// Note: In this extensible implementation, values are stored directly
71    /// rather than in full Montgomery form for simplicity.
72    pub fn to_montgomery(&self) -> &BigInt {
73        &self.value
74    }
75
76    /// Convert this field element to regular (non-Montgomery) representation.
77    ///
78    /// Returns the field element value in standard form, not Montgomery form.
79    /// In this extensible implementation, values are stored directly,
80    /// so this simply returns a clone of the internal value.
81    pub fn to_regular(&self) -> BigInt {
82        // For simplicity, values are stored directly
83        self.value.clone()
84    }
85
86    /// Get the modulus for this field.
87    ///
88    /// Returns the prime modulus that defines this finite field.
89    /// This is a static method that delegates to the FieldParameters trait.
90    pub fn modulus() -> BigInt {
91        P::modulus()
92    }
93
94    /// Convert a value to Montgomery form (static version for extensible arithmetic).
95    ///
96    /// This function converts a regular integer value to its Montgomery representation.
97    /// The conversion is done using: value * R mod N = montgomery_mul(value, R²)
98    ///
99    /// # Arguments
100    /// * `value` - The value to convert to Montgomery form
101    /// * `modulus` - The field modulus N
102    /// * `r` - The Montgomery radix R (typically a power of 2)
103    /// * `r2` - R² mod N, the Montgomery constant
104    /// * `n_prime` - The Montgomery inverse of N modulo R
105    ///
106    /// # Returns
107    /// The value converted to Montgomery form
108    fn to_montgomery_static(
109        value: &BigInt,
110        modulus: &BigInt,
111        r: &BigInt,
112        r2: &BigInt,
113        n_prime: &BigInt,
114    ) -> BigInt {
115        // value * R mod N = montgomery_mul(value, R²)
116        Self::montgomery_mul_static(value, r2, modulus, r, n_prime)
117    }
118
119    /// Convert a value from Montgomery form to regular representation (static version).
120    ///
121    /// This function performs Montgomery reduction to convert a Montgomery-form
122    /// value back to its regular integer representation.
123    ///
124    /// # Arguments
125    /// * `value` - The Montgomery-form value to convert
126    /// * `modulus` - The field modulus N
127    /// * `r` - The Montgomery radix R (typically a power of 2)
128    /// * `n_prime` - The Montgomery inverse of N modulo R
129    ///
130    /// # Returns
131    /// The value converted from Montgomery form to regular representation
132    fn from_montgomery_static(
133        value: &BigInt,
134        modulus: &BigInt,
135        r: &BigInt,
136        n_prime: &BigInt,
137    ) -> BigInt {
138        // Montgomery reduction
139        let m = value.mul(n_prime).div_rem(r).1;
140        let u = value.add(&m.mul(modulus)).div_rem(r).1;
141
142        if u.ct_cmp(modulus) != core::cmp::Ordering::Less {
143            u.sub(modulus)
144        } else {
145            u
146        }
147    }
148
149    /// Perform Montgomery multiplication (static version for extensible arithmetic).
150    ///
151    /// Computes (a * b * R^(-1)) mod N using the Montgomery multiplication algorithm.
152    /// This is more efficient than regular modular multiplication for multiple operations.
153    ///
154    /// # Arguments
155    /// * `a` - First operand (in Montgomery form)
156    /// * `b` - Second operand (in Montgomery form)
157    /// * `modulus` - The field modulus N
158    /// * `r` - The Montgomery radix R (typically a power of 2)
159    /// * `n_prime` - The Montgomery inverse of N modulo R
160    ///
161    /// # Returns
162    /// The product (a * b * R^(-1)) mod N in Montgomery form
163    #[allow(clippy::many_single_char_names)]
164    fn montgomery_mul_static(
165        a: &BigInt,
166        b: &BigInt,
167        modulus: &BigInt,
168        r: &BigInt,
169        n_prime: &BigInt,
170    ) -> BigInt {
171        let t = a.mul(b);
172        let m = t.mul(n_prime).div_rem(r).1;
173        let u = t.add(&m.mul(modulus)).div_rem(r).1;
174
175        if u.ct_cmp(modulus) != core::cmp::Ordering::Less {
176            u.sub(modulus)
177        } else {
178            u
179        }
180    }
181
182    /// Perform Montgomery squaring (static version for extensible arithmetic).
183    ///
184    /// Computes (a * a * R^(-1)) mod N using the Montgomery multiplication algorithm.
185    /// This is optimized for squaring operations, which are common in cryptographic computations.
186    ///
187    /// # Arguments
188    /// * `a` - The operand to square (in Montgomery form)
189    /// * `modulus` - The field modulus N
190    /// * `r` - The Montgomery radix R (typically a power of 2)
191    /// * `n_prime` - The Montgomery inverse of N modulo R
192    ///
193    /// # Returns
194    /// The square (a * a * R^(-1)) mod N in Montgomery form
195    fn montgomery_square_static(
196        a: &BigInt,
197        modulus: &BigInt,
198        r: &BigInt,
199        n_prime: &BigInt,
200    ) -> BigInt {
201        Self::montgomery_mul_static(a, a, modulus, r, n_prime)
202    }
203
204    /// Perform Montgomery reduction (static version for extensible arithmetic).
205    ///
206    /// Reduces a value t modulo N using the Montgomery reduction algorithm.
207    /// This converts a value from the range [0, N*R) to [0, N) by computing (t * R^(-1)) mod N.
208    ///
209    /// # Arguments
210    /// * `t` - The value to reduce (typically a product in the range [0, N*R))
211    /// * `modulus` - The field modulus N
212    /// * `r` - The Montgomery radix R (typically a power of 2)
213    /// * `n_prime` - The Montgomery inverse of N modulo R
214    ///
215    /// # Returns
216    /// The reduced value (t * R^(-1)) mod N
217    fn montgomery_reduce_static(
218        t: &BigInt,
219        modulus: &BigInt,
220        r: &BigInt,
221        n_prime: &BigInt,
222    ) -> BigInt {
223        let m = t.mul(n_prime).div_rem(r).1;
224        let u = t.add(&m.mul(modulus)).div_rem(r).1;
225
226        if u.ct_cmp(modulus) != core::cmp::Ordering::Less {
227            u.sub(modulus)
228        } else {
229            u
230        }
231    }
232}
233
234/// Generic field arithmetic operations.
235///
236/// This trait defines the core arithmetic operations that can be performed
237/// on field elements in a finite field. All operations are performed modulo
238/// the field's prime modulus, ensuring results remain within the field.
239pub trait GenericFieldOps<P: FieldParameters> {
240    /// Add two field elements.
241    ///
242    /// Computes (self + rhs) mod modulus. The result is always a valid
243    /// field element in the range [0, modulus).
244    fn add(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P>;
245
246    /// Subtract two field elements.
247    ///
248    /// Computes (self - rhs) mod modulus. If the result would be negative,
249    /// the modulus is added to ensure the result is in [0, modulus).
250    fn sub(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P>;
251
252    /// Multiply two field elements.
253    ///
254    /// Computes (self * rhs) mod modulus. The result is always a valid
255    /// field element in the range [0, modulus).
256    fn mul(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P>;
257
258    /// Compute the multiplicative inverse.
259    ///
260    /// Finds the element x such that (self * x) ≡ 1 mod modulus.
261    /// Returns an error if the element is zero (which has no inverse)
262    /// or if the extended Euclidean algorithm fails.
263    fn inv(&self) -> Result<GenericFieldElement<P>, MathError>;
264
265    /// Compute the square of this field element.
266    ///
267    /// Computes (self * self) mod modulus. This is often more efficient
268    /// than general multiplication and is commonly used in exponentiation algorithms.
269    fn square(&self) -> GenericFieldElement<P>;
270
271    /// Check equality in constant time.
272    ///
273    /// Performs a constant-time comparison to prevent timing attacks.
274    /// Returns true if the two elements represent the same field value.
275    fn ct_eq(&self, rhs: &GenericFieldElement<P>) -> bool;
276
277    /// Check if this element is the additive identity (zero).
278    ///
279    /// Returns true if this element represents 0 in the field.
280    fn is_zero(&self) -> bool;
281}
282
283impl<P: FieldParameters> GenericFieldOps<P> for GenericFieldElement<P> {
284    /// Add two field elements.
285    ///
286    /// Performs modular addition: (self + rhs) mod modulus.
287    /// If the sum exceeds the modulus, it wraps around by subtracting the modulus once.
288    fn add(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P> {
289        let sum = self.value.add(&rhs.value);
290        let reduced = if sum.ct_cmp(&P::modulus()) != core::cmp::Ordering::Less {
291            sum.sub(&P::modulus())
292        } else {
293            sum
294        };
295
296        // The result is reduced modulo the modulus, so it's valid
297        Self::from_montgomery_checked(reduced)
298            .expect("Montgomery reduction should produce valid field element")
299    }
300
301    /// Subtract two field elements.
302    ///
303    /// Performs modular subtraction: (self - rhs) mod modulus.
304    /// If self < rhs, adds the modulus to the difference to ensure a positive result.
305    fn sub(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P> {
306        let diff = if self.value.ct_cmp(&rhs.value) != core::cmp::Ordering::Less {
307            self.value.sub(&rhs.value)
308        } else {
309            // Add modulus to handle underflow
310            let temp = self.value.add(&P::modulus());
311            temp.sub(&rhs.value)
312        };
313
314        // The result is in [0, modulus), so it's valid
315        Self::from_montgomery_checked(diff).unwrap()
316    }
317
318    fn mul(&self, rhs: &GenericFieldElement<P>) -> GenericFieldElement<P> {
319        let product = self.value.mul(&rhs.value);
320        let reduced = product.div_rem(&P::modulus()).1;
321
322        // The result is reduced modulo the modulus, so it's valid
323        Self::from_montgomery_checked(reduced)
324            .expect("Montgomery reduction should produce valid field element")
325    }
326
327    /// Compute the multiplicative inverse using the extended Euclidean algorithm.
328    ///
329    /// Finds x such that (self * x) ≡ 1 mod modulus.
330    /// Uses the extended Euclidean algorithm to compute the modular inverse.
331    /// Returns DivisionByZero error if the element is zero or if no inverse exists.
332    fn inv(&self) -> Result<GenericFieldElement<P>, MathError> {
333        if self.is_zero() {
334            return Err(MathError::DivisionByZero);
335        }
336
337        // For the extensible implementation, compute inverse using extended Euclidean algorithm
338        // This is simpler and works for any modulus
339        let modulus = P::modulus();
340        let mut t = BigInt::from_u64(0);
341        let mut new_t = BigInt::from_u64(1);
342        let mut r = modulus.clone();
343        let mut new_r = self.value.clone();
344
345        while new_r.ct_cmp(&BigInt::from_u64(0)) != core::cmp::Ordering::Equal {
346            let quotient = r.div_rem(&new_r).0;
347            let temp_t = t.clone();
348            t = new_t.clone();
349            new_t = temp_t.sub(&quotient.mul(&new_t));
350
351            let temp_r = r.clone();
352            r = new_r.clone();
353            new_r = temp_r.sub(&quotient.mul(&new_r));
354        }
355
356        if r.ct_cmp(&BigInt::from_u64(1)) != core::cmp::Ordering::Equal {
357            return Err(MathError::DivisionByZero); // No inverse exists
358        }
359
360        // Make result positive
361        if t.ct_cmp(&BigInt::from_u64(0)) == core::cmp::Ordering::Less {
362            t = t.add(&modulus);
363        }
364
365        // The result is a valid field element in [0, modulus)
366        Self::from_montgomery_checked(t)
367    }
368
369    /// Compute the square of this field element.
370    ///
371    /// Performs modular squaring: (self * self) mod modulus.
372    /// More efficient than general multiplication for exponentiation algorithms.
373    fn square(&self) -> GenericFieldElement<P> {
374        let squared = self.value.mul(&self.value);
375        let reduced = squared.div_rem(&P::modulus()).1;
376
377        // The result is reduced modulo the modulus, so it's valid
378        Self::from_montgomery_checked(reduced)
379            .expect("Montgomery reduction should produce valid field element")
380    }
381
382    /// Check equality in constant time.
383    ///
384    /// Performs a constant-time comparison of the underlying BigInt values
385    /// to prevent timing-based side-channel attacks.
386    fn ct_eq(&self, rhs: &GenericFieldElement<P>) -> bool {
387        // For BigInt comparison, we need to convert to bytes or use the cmp method
388        // This is a simplified version for now
389        self.value.ct_cmp(&rhs.value) == core::cmp::Ordering::Equal
390    }
391
392    /// Check if this element is the additive identity (zero).
393    ///
394    /// Returns true if this field element represents 0 in the finite field.
395    /// Converts to regular representation and compares with zero.
396    fn is_zero(&self) -> bool {
397        // Check if the regular representation is zero
398        self.to_regular().ct_cmp(&BigInt::from_u64(0)) == core::cmp::Ordering::Equal
399    }
400}