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}