clock_curve_math/montgomery/
mod.rs

1//! Montgomery arithmetic for efficient modular operations.
2//!
3//! This module provides Montgomery reduction and multiplication algorithms
4//! optimized for the Curve25519 elliptic curve parameters. Montgomery arithmetic
5//! enables efficient modular multiplication by avoiding expensive division operations.
6//!
7//! ## Overview
8//!
9//! Montgomery arithmetic represents numbers in a transformed domain where
10//! modular multiplication can be performed using only multiplication, addition,
11//! and bit shifts. The key insight is that multiplication by R^(-1) (where R
12//! is a power of 2) can be computed efficiently.
13//!
14//! For Curve25519:
15//! - Field modulus: p = 2^255 - 19
16//! - Scalar modulus: l = 2^252 + 27_742_317_777_372_353_535_851_937_790_883_648_493
17//! - Montgomery radix: R = 2^256
18//!
19//! ## Usage
20//!
21//! For most use cases, use the high-level conversion functions:
22//!
23//! ```rust
24//! use clock_curve_math::{BigInt, montgomery::{to_montgomery_p, from_montgomery_p}};
25//!
26//! // Convert to Montgomery form
27//! let value = BigInt::from_u64(42);
28//! let mont_value = to_montgomery_p(&value);
29//!
30//! // Perform operations in Montgomery domain
31//! // ... arithmetic operations ...
32//!
33//! // Convert back to standard form
34//! let result = from_montgomery_p(&mont_value);
35//!
36//! // Verify roundtrip
37//! assert_eq!(result, value);
38//! ```
39//!
40//! For low-level operations, use the core functions directly:
41//!
42//! ```rust
43//! use clock_curve_math::{BigInt, constants::P_LIMBS, montgomery::{to_montgomery, R_SQUARED_MOD_P, N_PRIME_P}};
44//!
45//! // Manual conversion with explicit constants
46//! let r_squared = BigInt::from_limbs(&R_SQUARED_MOD_P);
47//! let modulus = BigInt::from_limbs(&P_LIMBS);
48//! let n_prime = BigInt::from_limbs(&N_PRIME_P);
49//! let value = BigInt::from_u64(42);
50//!
51//! let mont_value = to_montgomery(&value, &r_squared, &modulus, &n_prime);
52//! ```
53//!
54//! ## Security Notes
55//!
56//! - All operations execute in constant time to prevent timing attacks
57//! - Input validation ensures only supported Curve25519 moduli are used
58//! - Precomputed constants are validated during initialization
59//! - The implementation is hardened against side-channel attacks
60//!
61//! ## Performance Characteristics
62//!
63//! - Montgomery reduction: O(1) - fixed 256-bit operations
64//! - Montgomery multiplication: O(1) - efficient limb-based arithmetic
65//! - Conversion functions: O(1) - optimized for Curve25519 parameters
66
67mod precomputed;
68mod reduce;
69
70pub use precomputed::{
71    N_PRIME_L, N_PRIME_P, R_SQUARED_MOD_L, R_SQUARED_MOD_P, from_montgomery, to_montgomery,
72    validate_constants,
73};
74pub use reduce::{montgomery_mul, montgomery_reduce, montgomery_square};
75
76/// Initialize and validate the Montgomery arithmetic module.
77///
78/// This function should be called during application initialization to ensure
79/// that all precomputed constants are valid and the module is ready for use.
80/// It performs comprehensive validation of Montgomery parameters.
81///
82/// # Panics
83///
84/// Panics if any precomputed constants are invalid or inconsistent.
85pub fn init() {
86    validate_constants();
87}
88
89/// Convert a value to Montgomery form for the field modulus p.
90///
91/// The field modulus p = 2^255 - 19 is used for Curve25519 field elements.
92/// This function converts standard BigInt values to Montgomery representation
93/// for efficient modular arithmetic.
94///
95/// # Arguments
96///
97/// * `value` - The value to convert (must be reduced modulo p)
98///
99/// # Returns
100///
101/// The Montgomery representation of the input value.
102pub fn to_montgomery_p(value: &crate::bigint::BigInt) -> crate::bigint::BigInt {
103    let r_squared = crate::bigint::BigInt::from_limbs(&R_SQUARED_MOD_P);
104    let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
105    let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
106    to_montgomery(value, &r_squared, &n, &n_prime)
107}
108
109/// Convert a value from Montgomery form for the field modulus p.
110///
111/// This function converts Montgomery representation back to standard form.
112/// The result is guaranteed to be in [0, p).
113///
114/// # Arguments
115///
116/// * `value` - The Montgomery representation to convert
117///
118/// # Returns
119///
120/// The standard representation of the input value.
121pub fn from_montgomery_p(value: &crate::bigint::BigInt) -> crate::bigint::BigInt {
122    let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
123    let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
124    from_montgomery(value, &n, &n_prime)
125}
126
127/// Convert a value to Montgomery form for the scalar modulus l.
128///
129/// The scalar modulus l = 2^252 + 27_742_317_777_372_353_535_851_937_790_883_648_493
130/// is used for Curve25519 scalar values.
131///
132/// # Arguments
133///
134/// * `value` - The value to convert (must be reduced modulo l)
135///
136/// # Returns
137///
138/// The Montgomery representation of the input value.
139pub fn to_montgomery_l(value: &crate::bigint::BigInt) -> crate::bigint::BigInt {
140    let r_squared = crate::bigint::BigInt::from_limbs(&R_SQUARED_MOD_L);
141    let n = crate::bigint::BigInt::from_limbs(&crate::constants::L_LIMBS);
142    let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_L);
143    to_montgomery(value, &r_squared, &n, &n_prime)
144}
145
146/// Convert a value from Montgomery form for the scalar modulus l.
147///
148/// This function converts Montgomery representation back to standard form.
149/// The result is guaranteed to be in [0, l).
150///
151/// # Arguments
152///
153/// * `value` - The Montgomery representation to convert
154///
155/// # Returns
156///
157/// The standard representation of the input value.
158pub fn from_montgomery_l(value: &crate::bigint::BigInt) -> crate::bigint::BigInt {
159    let n = crate::bigint::BigInt::from_limbs(&crate::constants::L_LIMBS);
160    let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_L);
161    from_montgomery(value, &n, &n_prime)
162}
163
164/// Trait for Montgomery arithmetic operations.
165///
166/// This trait provides a common interface for types that support Montgomery
167/// arithmetic operations. Implementations are expected to provide constant-time
168/// operations for cryptographic security.
169///
170/// Note: This trait is implemented by BigInt for Curve25519 field operations.
171/// It provides Montgomery arithmetic for the prime modulus p = 2^255 - 19.
172pub trait MontgomeryOps {
173    /// Perform Montgomery reduction.
174    ///
175    /// Reduces a double-width product using Montgomery's REDC algorithm.
176    /// Uses the Curve25519 field modulus p = 2^255 - 19.
177    fn montgomery_reduce(t: &crate::bigint::BigInt) -> crate::bigint::BigInt;
178
179    /// Perform Montgomery multiplication.
180    ///
181    /// Computes (a * b) * R^(-1) mod p where p is the Curve25519 field modulus.
182    /// Both operands must be in Montgomery form.
183    fn montgomery_mul(
184        a: &crate::bigint::BigInt,
185        b: &crate::bigint::BigInt,
186    ) -> crate::bigint::BigInt;
187
188    /// Convert to Montgomery form.
189    ///
190    /// Transforms a standard integer into its Montgomery representation for modulus p.
191    fn to_montgomery(a: &crate::bigint::BigInt) -> crate::bigint::BigInt;
192
193    /// Convert from Montgomery form.
194    ///
195    /// Transforms a Montgomery representation back to standard form.
196    fn from_montgomery(a: &crate::bigint::BigInt) -> crate::bigint::BigInt;
197}
198
199impl MontgomeryOps for crate::bigint::BigInt {
200    fn montgomery_reduce(t: &crate::bigint::BigInt) -> crate::bigint::BigInt {
201        let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
202        let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
203        reduce::montgomery_reduce(t, &n, &n_prime)
204    }
205
206    fn montgomery_mul(
207        a: &crate::bigint::BigInt,
208        b: &crate::bigint::BigInt,
209    ) -> crate::bigint::BigInt {
210        let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
211        let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
212        reduce::montgomery_mul(a, b, &n, &n_prime)
213    }
214
215    fn to_montgomery(a: &crate::bigint::BigInt) -> crate::bigint::BigInt {
216        let r_squared = crate::bigint::BigInt::from_limbs(&R_SQUARED_MOD_P);
217        let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
218        let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
219        precomputed::to_montgomery(a, &r_squared, &n, &n_prime)
220    }
221
222    fn from_montgomery(a: &crate::bigint::BigInt) -> crate::bigint::BigInt {
223        let n = crate::bigint::BigInt::from_limbs(&crate::constants::P_LIMBS);
224        let n_prime = crate::bigint::BigInt::from_limbs(&N_PRIME_P);
225        precomputed::from_montgomery(a, &n, &n_prime)
226    }
227}
228
229#[cfg(test)]
230mod tests {
231    use super::*;
232    use crate::bigint::BigInt;
233    use core::cmp::Ordering;
234
235    #[test]
236    fn test_to_from_montgomery_p_roundtrip() {
237        // Test roundtrip conversion for field modulus
238        let test_values = [
239            BigInt::from_u64(0),
240            BigInt::from_u64(1),
241            BigInt::from_u64(42),
242            BigInt::from_u64(u64::MAX),
243        ];
244
245        for value in &test_values {
246            let mont = to_montgomery_p(value);
247            let recovered = from_montgomery_p(&mont);
248            assert_eq!(
249                *value, recovered,
250                "Montgomery roundtrip failed for {:?}",
251                value
252            );
253        }
254    }
255
256    #[test]
257    fn test_to_from_montgomery_l_roundtrip() {
258        // Test roundtrip conversion for scalar modulus
259        let test_values = [
260            BigInt::from_u64(0),
261            BigInt::from_u64(1),
262            BigInt::from_u64(42),
263            BigInt::from_u64(u64::MAX),
264        ];
265
266        for value in &test_values {
267            let mont = to_montgomery_l(value);
268            let recovered = from_montgomery_l(&mont);
269            assert_eq!(
270                *value, recovered,
271                "Montgomery roundtrip failed for {:?}",
272                value
273            );
274        }
275    }
276
277    #[test]
278    fn test_montgomery_p_identity() {
279        // Test that R * R^(-1) ≡ 1 mod p in Montgomery form
280        let r_mont = to_montgomery_p(&BigInt::from_u64(1));
281        let r_inv_mont = from_montgomery_p(&r_mont);
282        assert_eq!(r_inv_mont, BigInt::from_u64(1));
283    }
284
285    #[test]
286    fn test_montgomery_l_identity() {
287        // Test that R * R^(-1) ≡ 1 mod l in Montgomery form
288        let r_mont = to_montgomery_l(&BigInt::from_u64(1));
289        let r_inv_mont = from_montgomery_l(&r_mont);
290        assert_eq!(r_inv_mont, BigInt::from_u64(1));
291    }
292
293    #[test]
294    fn test_montgomery_p_constants() {
295        // Verify that the precomputed constants are consistent
296        let _p = BigInt::from_limbs(&crate::constants::P_LIMBS);
297        let _n_prime = BigInt::from_limbs(&N_PRIME_P);
298        let r_squared = BigInt::from_limbs(&R_SQUARED_MOD_P);
299
300        // R² mod p should equal the precomputed constant
301        // Since r = 2^256, we can't easily compute r² mod p directly
302        // Instead, we verify the constant is non-zero (basic sanity check)
303        assert!(!r_squared.is_zero());
304
305        // Test that N' is correct: N' = -N^(-1) mod R
306        // For our case, we trust the precomputed values are correct
307        // (they are verified in the precomputed module tests)
308        assert!(!N_PRIME_P.iter().all(|&x| x == 0)); // Should be non-zero
309    }
310
311    #[test]
312    fn test_montgomery_l_constants() {
313        // Verify that the precomputed constants are consistent
314        let l = BigInt::from_limbs(&crate::constants::L_LIMBS);
315
316        // Test that constants are non-zero and have expected properties
317        assert!(!N_PRIME_L.iter().all(|&x| x == 0)); // Should be non-zero
318        assert!(!R_SQUARED_MOD_L.iter().all(|&x| x == 0)); // Should be non-zero
319
320        // R² mod L should be less than L (basic Montgomery arithmetic property)
321        let r_squared = BigInt::from_limbs(&R_SQUARED_MOD_L);
322        assert!(r_squared.cmp(&l) == Ordering::Less);
323    }
324
325    #[test]
326    fn test_montgomery_conversion_properties() {
327        // Test mathematical properties of Montgomery conversion
328
329        // For any x, from_montgomery(to_montgomery(x)) ≡ x mod p
330        let x = BigInt::from_u64(12345);
331        let mont_x = to_montgomery_p(&x);
332        let recovered_x = from_montgomery_p(&mont_x);
333
334        // The result should be x mod p, but since x < p, it should be x
335        assert_eq!(recovered_x, x);
336
337        // Test field modulus with larger values too
338        for &test_val in &[1u64, 42u64, 100u64, 1000u64, 10000u64] {
339            let x_test = BigInt::from_u64(test_val);
340            let mont_x = to_montgomery_p(&x_test);
341            let recovered_x = from_montgomery_p(&mont_x);
342            assert_eq!(
343                recovered_x, x_test,
344                "Field modulus failed for value {}",
345                test_val
346            );
347        }
348
349        // Test with scalar modulus - now works for larger values
350        for &test_val in &[1u64, 42u64, 10000u64, 100000u64, 1000000u64] {
351            let x_test = BigInt::from_u64(test_val);
352            let mont_x_l = to_montgomery_l(&x_test);
353            let recovered_x_l = from_montgomery_l(&mont_x_l);
354            assert_eq!(
355                recovered_x_l, x_test,
356                "Scalar modulus failed for value {}",
357                test_val
358            );
359        }
360    }
361}