clock_curve_math/bigint/
arithmetic.rs

1//! BigInt arithmetic operations trait for multi-precision integer mathematics.
2//!
3//! This module defines the core arithmetic operations for big integers (multi-precision
4//! integers) used throughout the cryptographic library. BigInt operations are fundamental
5//! to all cryptographic computations, providing the mathematical foundation for modular
6//! arithmetic, elliptic curve operations, and cryptographic protocols.
7//!
8//! # Multi-Precision Arithmetic
9//!
10//! BigInt represents integers that exceed the range of standard machine word sizes
11//! (typically 64 bits). Operations are implemented using:
12//!
13//! - **Limb-based representation**: Numbers stored as arrays of 64-bit limbs
14//! - **Little-endian ordering**: Least significant limb at index 0
15//! - **Fixed precision**: Operations assume consistent limb counts
16//! - **Constant-time execution**: All operations execute in time independent of values
17//!
18//! # Security Critical Operations
19//!
20//! All BigInt operations are designed with cryptographic security in mind:
21//!
22//! - **Constant-time execution**: Prevents timing-based side-channel attacks
23//! - **No data-dependent branches**: Eliminates cache timing vulnerabilities
24//! - **Predictable memory access**: Prevents cache-based information leakage
25//! - **Secure comparisons**: Constant-time equality and ordering checks
26//!
27//! # Performance Characteristics
28//!
29//! BigInt operations have different computational complexities:
30//!
31//! - **Addition/Subtraction**: O(n) where n is limb count
32//! - **Multiplication**: O(n²) for standard multiplication
33//! - **Wide multiplication**: O(n²) producing double-width results
34//! - **Shifts**: O(n) with bit-wise operations
35//! - **Comparisons**: O(n) with constant-time properties
36//!
37//! # Usage in Cryptographic Contexts
38//!
39//! BigInt arithmetic serves as the foundation for higher-level cryptographic operations:
40//!
41//! ```ignore
42//! use clock_curve_math::bigint::{BigInt, BigIntOps};
43//!
44//! // Modular arithmetic for Diffie-Hellman
45//! let base = BigInt::from_hex("2");
46//! let exponent = BigInt::from_hex("123456789ABCDEF");
47//! let modulus = BigInt::from_hex("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD...");
48//!
49//! // Compute base^exponent mod modulus (constant-time)
50//! let result = mod_pow(&base, &exponent, &modulus);
51//!
52//! // Elliptic curve point operations
53//! let x1 = BigInt::from_hex("123...");
54//! let y1 = BigInt::from_hex("456...");
55//! let x2 = BigInt::from_hex("789...");
56//! let y2 = BigInt::from_hex("ABC...");
57//!
58//! // Point addition uses BigInt arithmetic extensively
59//! let (x3, y3) = point_add(&x1, &y1, &x2, &y2, &curve_modulus);
60//! ```
61//!
62//! # Implementation Considerations
63//!
64//! ## Constant-Time Requirements
65//!
66//! Cryptographic operations require constant-time execution to prevent:
67//!
68//! - **Timing attacks**: Measuring execution time to infer secret keys
69//! - **Cache attacks**: Observing which memory locations are accessed
70//! - **Branch prediction attacks**: Analyzing control flow patterns
71//!
72//! ## Error Handling
73//!
74//! BigInt operations generally don't fail, but some considerations:
75//!
76//! - **Overflow**: Wide operations return double-width results to prevent overflow
77//! - **Invalid inputs**: Functions assume valid BigInt instances
78//! - **Memory safety**: All operations are memory-safe with bounds checking
79//!
80//! ## Optimization Opportunities
81//!
82//! The implementation provides optimization hooks:
83//!
84//! - **SIMD acceleration**: Potential for vectorized limb operations
85//! - **Hardware acceleration**: Integration with CPU carry chains
86//! - **Montgomery arithmetic**: Optimized modular operations
87//! - **Algorithm selection**: Different multiplication algorithms based on size
88
89use core::cmp::Ordering;
90
91use super::BigInt;
92
93/// Core trait for big integer arithmetic operations with cryptographic security guarantees.
94///
95/// This trait defines the essential arithmetic operations for multi-precision integers
96/// used in cryptographic computations. All operations are required to execute in
97/// constant time to prevent timing-based side-channel attacks that could compromise
98/// cryptographic security.
99///
100/// # Security Requirements
101///
102/// All implementing types must ensure:
103/// - **Constant-time execution**: Operation time independent of input values
104/// - **No data-dependent branches**: Control flow doesn't depend on secret data
105/// - **Predictable memory access**: Memory access patterns are consistent
106/// - **Secure comparisons**: Comparison operations don't leak timing information
107///
108/// # Implementation Contract
109///
110/// Implementations must:
111/// - Handle all edge cases (zero, maximum values, overflow conditions)
112/// - Maintain constant-time properties across all input ranges
113/// - Provide correct mathematical results for all operations
114/// - Document any performance characteristics or limitations
115///
116/// # Usage in Cryptographic Libraries
117///
118/// ```ignore
119/// use clock_curve_math::bigint::{BigInt, BigIntOps};
120///
121/// fn secure_modular_multiplication(a: &BigInt, b: &BigInt, modulus: &BigInt) -> BigInt {
122///     // Use wide multiplication to prevent overflow
123///     let (low, high) = a.mul_wide(b);
124///
125///     // Perform modular reduction (simplified example)
126///     let mut result = low;
127///     while result.ct_cmp(modulus) != core::cmp::Ordering::Less {
128///         result = result.sub(modulus);
129///     }
130///
131///     result
132/// }
133///
134/// fn constant_time_conditional_swap(a: &mut BigInt, b: &mut BigInt, condition: u64) {
135///     // Secure conditional swap without branching
136///     let temp = a.clone();
137///     *a = BigInt::ct_select(a, b, condition);
138///     *b = BigInt::ct_select(b, &temp, condition);
139/// }
140/// ```
141///
142/// # Performance Expectations
143///
144/// Implementations should optimize for cryptographic use cases:
145/// - Fast constant-time operations
146/// - Efficient limb-based arithmetic
147/// - Minimal memory allocations
148/// - Good cache locality
149pub trait BigIntOps {
150    /// Performs constant-time addition of two big integers.
151    ///
152    /// Computes `self + rhs` with full carry propagation. The operation
153    /// executes in constant time regardless of input values or carry patterns,
154    /// preventing timing attacks that could leak information about the operands.
155    ///
156    /// # Mathematical Properties
157    /// - **Commutative**: `a + b = b + a`
158    /// - **Associative**: `(a + b) + c = a + (b + c)`
159    /// - **Identity**: `a + 0 = a`
160    /// - **Overflow**: No overflow occurs (arbitrary precision)
161    ///
162    /// # Security Considerations
163    /// - Constant-time execution prevents carry-based timing attacks
164    /// - No information leaks through execution time variations
165    /// - Safe for cryptographic use with secret operands
166    ///
167    /// # Performance
168    /// O(n) time complexity where n is the number of limbs.
169    fn add(&self, rhs: &Self) -> Self;
170
171    /// Performs constant-time subtraction of two big integers.
172    ///
173    /// Computes `self - rhs` with borrow propagation. The operation maintains
174    /// constant-time execution even when borrowing occurs, preventing timing
175    /// attacks that could reveal information about relative magnitudes.
176    ///
177    /// # Mathematical Properties
178    /// - **Anti-commutative**: `a - b = -(b - a)`
179    /// - **Non-associative**: Subtraction is not associative
180    /// - **Identity**: `a - 0 = a`
181    /// - **Inverse**: `a - a = 0`
182    ///
183    /// # Security Considerations
184    /// - Constant-time execution prevents borrow-based timing attacks
185    /// - No timing leaks when `rhs > self` (produces negative result)
186    /// - Safe for cryptographic comparisons and reductions
187    ///
188    /// # Performance
189    /// O(n) time complexity where n is the number of limbs.
190    fn sub(&self, rhs: &Self) -> Self;
191
192    /// Performs constant-time multiplication of two big integers.
193    ///
194    /// Computes `self * rhs` using efficient multi-precision multiplication.
195    /// The result may require modular reduction for cryptographic applications.
196    ///
197    /// # Implementation Notes
198    /// This method may produce a result that overflows the standard BigInt
199    /// representation. For cryptographic modular arithmetic, consider using
200    /// `mul_wide()` followed by modular reduction to handle overflow correctly.
201    ///
202    /// # Mathematical Properties
203    /// - **Commutative**: `a * b = b * a`
204    /// - **Associative**: `(a * b) * c = a * (b * c)`
205    /// - **Distributive**: `a * (b + c) = a*b + a*c`
206    /// - **Identity**: `a * 1 = a`
207    /// - **Zero**: `a * 0 = 0`
208    ///
209    /// # Security Considerations
210    /// - Constant-time execution prevents timing attacks on multiplication
211    /// - No leaks through partial product computation timing
212    /// - Safe for cryptographic use with secret multiplicands
213    ///
214    /// # Performance
215    /// O(n²) time complexity for standard multiplication where n is limb count.
216    /// Consider using specialized algorithms for large operands.
217    ///
218    /// # Warning
219    /// The result may be double-width. Use `mul_wide()` for guaranteed
220    /// overflow handling in cryptographic applications.
221    fn mul(&self, rhs: &Self) -> Self;
222
223    /// Performs wide multiplication returning the full double-width result.
224    ///
225    /// Computes `self * rhs` and returns the result as two BigInts representing
226    /// the low and high parts of the full product. This prevents overflow and
227    /// enables correct modular reduction for cryptographic applications.
228    ///
229    /// # Return Value
230    /// Returns a tuple `(low, high)` where:
231    /// - `low`: Lower 256 bits (or equivalent) of the product
232    /// - `high`: Upper 256 bits (or equivalent) of the product
233    /// - The full product is `high * 2^(limb_count * 64) + low`
234    ///
235    /// # Use Cases
236    /// - **Montgomery reduction**: Requires full product before modular reduction
237    /// - **Barrett reduction**: Needs high bits for approximation
238    /// - **Modular exponentiation**: Prevents intermediate overflow
239    /// - **Large integer arithmetic**: Exact computation without precision loss
240    ///
241    /// # Security Considerations
242    /// - Constant-time execution for both operands
243    /// - No timing leaks during carry propagation
244    /// - Safe for cryptographic modular arithmetic
245    ///
246    /// # Performance
247    /// O(n²) time complexity where n is the number of limbs.
248    /// More expensive than regular multiplication but prevents overflow issues.
249    fn mul_wide(&self, rhs: &Self) -> (Self, Self)
250    where
251        Self: Sized;
252
253    /// Performs wide squaring returning the full double-width result.
254    ///
255    /// Computes `self * self` (squaring) and returns the result as two BigInts
256    /// representing the low and high parts. This is optimized compared to
257    /// `mul_wide(self, self)` by exploiting the symmetry of squaring.
258    ///
259    /// # Optimization Details
260    /// Squaring benefits from symmetry: each pair `(a[i], a[j])` where `i ≠ j`
261    /// contributes `2 * a[i] * a[j]` to the product, which can be computed more
262    /// efficiently than general multiplication. Diagonal terms `a[i] * a[i]`
263    /// are computed normally.
264    ///
265    /// # Return Value
266    /// Returns a tuple `(low, high)` where:
267    /// - `low`: Lower bits of the squared result
268    /// - `high`: Upper bits of the squared result
269    /// - The full square is `high * 2^(limb_count * 64) + low`
270    ///
271    /// # Use Cases
272    /// - **Montgomery squaring**: Optimized modular squaring in ECC
273    /// - **Exponentiation**: Squaring step in exponentiation algorithms
274    /// - **Field arithmetic**: Squaring in finite field operations
275    /// - **Performance-critical code**: Faster than general multiplication
276    ///
277    /// # Security Considerations
278    /// - Constant-time execution maintains security properties
279    /// - No optimization leaks timing information about the operand
280    /// - Safe for cryptographic use with secret values
281    ///
282    /// # Performance
283    /// Typically 25-50% faster than `mul_wide(self, self)` due to symmetry optimization.
284    /// O(n²) time complexity but with lower constant factors for squaring.
285    fn square_wide(&self) -> (Self, Self)
286    where
287        Self: Sized;
288
289    /// Performs constant-time left shift (multiplication by power of 2).
290    ///
291    /// Shifts the BigInt left by the specified number of bits, effectively
292    /// multiplying by `2^bits`. The operation maintains constant-time execution
293    /// regardless of the shift amount or the bit pattern of the operand.
294    ///
295    /// # Parameters
296    /// * `bits` - Number of bits to shift left (0 ≤ bits ≤ maximum bit length)
297    ///
298    /// # Mathematical Properties
299    /// - **Identity**: `x << 0 = x`
300    /// - **Additive**: `(x << a) << b = x << (a + b)`
301    /// - **Multiplicative**: `x << n = x * 2^n`
302    /// - **Associative**: `(x + y) << n = (x << n) + (y << n)`
303    ///
304    /// # Security Considerations
305    /// - Constant-time execution prevents shift-based timing attacks
306    /// - No leaks through shift amount processing
307    /// - Safe for cryptographic bit manipulation with secret shift amounts
308    ///
309    /// # Performance
310    /// O(n) time complexity where n is the number of limbs affected by the shift.
311    fn shl(&self, bits: u32) -> Self;
312
313    /// Performs constant-time right shift (division by power of 2).
314    ///
315    /// Shifts the BigInt right by the specified number of bits, effectively
316    /// performing floor division by `2^bits`. The operation executes in
317    /// constant time regardless of shift amount or operand values.
318    ///
319    /// # Parameters
320    /// * `bits` - Number of bits to shift right (0 ≤ bits ≤ maximum bit length)
321    ///
322    /// # Mathematical Properties
323    /// - **Identity**: `x >> 0 = x`
324    /// - **Additive**: `(x >> a) >> b = x >> (a + b)`
325    /// - **Divisive**: `x >> n = floor(x / 2^n)`
326    /// - **Rounding**: Always rounds toward zero (floor division)
327    ///
328    /// # Security Considerations
329    /// - Constant-time execution prevents shift-based timing attacks
330    /// - No information leaks through shift processing
331    /// - Safe for cryptographic bit extraction with secret shift amounts
332    ///
333    /// # Performance
334    /// O(n) time complexity where n is the number of limbs affected by the shift.
335    fn shr(&self, bits: u32) -> Self;
336
337    /// Performs standard comparison with potential timing side-channels.
338    ///
339    /// Compares two BigInts and returns their ordering relationship.
340    /// **Warning**: This comparison may leak timing information and should
341    /// not be used with secret values in cryptographic contexts.
342    ///
343    /// # Return Value
344    /// - `Ordering::Less` if `self < rhs`
345    /// - `Ordering::Equal` if `self == rhs`
346    /// - `Ordering::Greater` if `self > rhs`
347    ///
348    /// # Security Warning
349    /// This method may execute in variable time depending on the input values,
350    /// potentially leaking information about the operands through timing
351    /// side-channels. Use `ct_cmp()` for cryptographic applications.
352    ///
353    /// # Performance
354    /// May short-circuit on first difference, leading to variable execution time.
355    fn cmp(&self, rhs: &Self) -> Ordering;
356
357    /// Performs constant-time comparison that prevents timing side-channels.
358    ///
359    /// Compares two BigInts and returns their ordering relationship while
360    /// executing in constant time regardless of the input values. This prevents
361    /// timing-based attacks that could recover information about secret operands.
362    ///
363    /// # Security Properties
364    /// - **Constant-time execution**: Time independent of operand values
365    /// - **No data-dependent branches**: Control flow doesn't depend on secrets
366    /// - **Leak-resistant**: Prevents timing attacks on comparisons
367    /// - **Cryptographically secure**: Safe for use with secret values
368    ///
369    /// # Return Value
370    /// - `Ordering::Less` if `self < rhs`
371    /// - `Ordering::Equal` if `self == rhs`
372    /// - `Ordering::Greater` if `self > rhs`
373    ///
374    /// # Performance
375    /// O(n) time complexity where n is the number of limbs, with no short-circuiting.
376    /// Slightly slower than `cmp()` but cryptographically secure.
377    ///
378    /// # Use Cases
379    /// - Comparing cryptographic keys or intermediate values
380    /// - Sorting operations on secret data
381    /// - Conditional logic based on secret comparisons
382    /// - Any comparison involving cryptographic secrets
383    fn ct_cmp(&self, rhs: &Self) -> Ordering;
384
385    /// Performs constant-time conditional selection between two BigInts.
386    ///
387    /// Returns `a` if `flag == 0`, `b` if `flag == 1`. This operation is
388    /// fundamental for implementing constant-time conditional logic without
389    /// branching, which is essential for preventing timing side-channels.
390    ///
391    /// # Algorithm
392    /// Uses bitwise masking to select values without conditional execution:
393    /// ```text
394    /// result[i] = (a[i] & ~mask) | (b[i] & mask)
395    /// where mask = 0xFFFF_FFFF_FFFF_FFFF if flag == 1, else 0
396    /// ```
397    ///
398    /// # Security Properties
399    /// - **Constant-time**: Execution time independent of flag value or operands
400    /// - **Branch-free**: No conditional jumps that could create timing variations
401    /// - **Leak-proof**: No information leaks through selection process
402    /// - **Data-independent**: Memory access patterns are consistent
403    ///
404    /// # Parameters
405    /// * `a` - Value selected when `flag == 0`
406    /// * `b` - Value selected when `flag == 1`
407    /// * `flag` - Selection flag (must be 0 or 1)
408    ///
409    /// # Safety
410    /// `flag` must be either `0` or `1`. Other values may leak timing information
411    /// through the underlying mask generation. Always ensure flag is properly
412    /// sanitized before use.
413    ///
414    /// # Performance
415    /// O(n) time complexity where n is the number of limbs.
416    /// More expensive than simple assignment but cryptographically secure.
417    ///
418    /// # Examples
419    /// ```ignore
420    /// use clock_curve_math::bigint::{BigInt, BigIntOps};
421    ///
422    /// let secret_a = BigInt::from_u64(42);
423    /// let secret_b = BigInt::from_u64(123);
424    /// let condition = 1u64; // Some boolean condition (0 or 1)
425    ///
426    /// // Secure conditional assignment
427    /// let result = BigInt::ct_select(&secret_a, &secret_b, condition);
428    /// ```
429    fn ct_select(a: &Self, b: &Self, flag: u64) -> Self
430    where
431        Self: Sized;
432
433    /// Checks whether the BigInt represents zero in constant time.
434    ///
435    /// Returns `true` if all bits are zero, `false` otherwise. The operation
436    /// executes in constant time regardless of the value, preventing timing
437    /// attacks that could leak information about whether a secret value is zero.
438    ///
439    /// # Security Considerations
440    /// - Constant-time execution prevents zero-testing attacks
441    /// - No leaks through early exit or short-circuiting
442    /// - Safe for cryptographic use with secret values
443    ///
444    /// # Performance
445    /// O(n) time complexity where n is the number of limbs.
446    /// Checks all limbs even if an early zero is found.
447    fn is_zero(&self) -> bool;
448
449    /// Extracts a specific bit from the BigInt in constant time.
450    ///
451    /// Returns 1 if the bit at the specified position is set, 0 otherwise.
452    /// Bit positions start from 0 (least significant bit). The operation
453    /// executes in constant time regardless of the bit position or value.
454    ///
455    /// # Parameters
456    /// * `bit_position` - The bit position to extract (0 = LSB)
457    ///
458    /// # Return Value
459    /// - `1` if the bit is set
460    /// - `0` if the bit is clear
461    ///
462    /// # Security Considerations
463    /// - Constant-time execution prevents bit extraction timing attacks
464    /// - No leaks through array indexing or limb access patterns
465    /// - Safe for cryptographic bit manipulation with secret positions
466    ///
467    /// # Performance
468    /// O(1) time complexity - direct limb and bit access.
469    ///
470    /// # Examples
471    /// ```ignore
472    /// use clock_curve_math::bigint::{BigInt, BigIntOps};
473    ///
474    /// let value = BigInt::from_u64(0b1010); // Binary: 1010
475    /// assert_eq!(value.get_bit(0), 0); // LSB is 0
476    /// assert_eq!(value.get_bit(1), 1); // Bit 1 is set
477    /// assert_eq!(value.get_bit(2), 0); // Bit 2 is clear
478    /// assert_eq!(value.get_bit(3), 1); // Bit 3 is set
479    /// ```
480    fn get_bit(&self, bit_position: u32) -> u64;
481
482    /// Computes the minimum number of bits needed to represent the BigInt.
483    ///
484    /// Returns the position of the highest set bit plus one. Returns 0 for zero.
485    /// This is equivalent to `floor(log2(value)) + 1` for non-zero values.
486    ///
487    /// # Return Value
488    /// - `0` if the BigInt is zero
489    /// - `floor(log2(abs(value))) + 1` otherwise
490    ///
491    /// # Mathematical Properties
492    /// - **Zero case**: `bit_length(0) = 0`
493    /// - **Power of 2**: `bit_length(2^k) = k + 1`
494    /// - **Range**: For value v, `2^(length-1) ≤ v < 2^length`
495    ///
496    /// # Performance
497    /// O(n) time complexity where n is the number of limbs.
498    /// May short-circuit when the highest limb is found.
499    ///
500    /// # Examples
501    /// ```ignore
502    /// use clock_curve_math::bigint::{BigInt, BigIntOps};
503    ///
504    /// assert_eq!(BigInt::from_u64(0).bit_length(), 0);
505    /// assert_eq!(BigInt::from_u64(1).bit_length(), 1);     // 2^0
506    /// assert_eq!(BigInt::from_u64(2).bit_length(), 2);     // 2^1
507    /// assert_eq!(BigInt::from_u64(3).bit_length(), 2);     // Between 2^1 and 2^2
508    /// assert_eq!(BigInt::from_u64(4).bit_length(), 3);     // 2^2
509    /// ```
510    fn bit_length(&self) -> u32;
511}
512
513/// Implementation of BigIntOps for the BigInt type.
514///
515/// This implementation provides constant-time multi-precision arithmetic
516/// operations for cryptographic applications. All operations delegate to
517/// the underlying BigInt implementation while ensuring constant-time properties.
518///
519/// # Security Guarantees
520/// All operations maintain constant-time execution characteristics,
521/// making them safe for use with cryptographic secrets and private keys.
522///
523/// # Performance Characteristics
524/// Operations are optimized for the specific limb size and architecture,
525/// providing efficient multi-precision arithmetic for cryptographic workloads.
526impl BigIntOps for BigInt {
527    /// Delegates to BigInt::add for constant-time addition.
528    fn add(&self, rhs: &Self) -> Self {
529        self.add(rhs)
530    }
531
532    /// Delegates to BigInt::sub for constant-time subtraction.
533    fn sub(&self, rhs: &Self) -> Self {
534        self.sub(rhs)
535    }
536
537    /// Delegates to BigInt::mul for constant-time multiplication.
538    fn mul(&self, rhs: &Self) -> Self {
539        self.mul(rhs)
540    }
541
542    /// Delegates to BigInt::mul_wide for wide multiplication.
543    fn mul_wide(&self, rhs: &Self) -> (Self, Self) {
544        self.mul_wide(rhs)
545    }
546
547    /// Delegates to BigInt::square_wide for optimized wide squaring.
548    fn square_wide(&self) -> (Self, Self) {
549        self.square_wide()
550    }
551
552    /// Delegates to BigInt::shl for constant-time left shift.
553    fn shl(&self, bits: u32) -> Self {
554        self.shl(bits)
555    }
556
557    /// Delegates to BigInt::shr for constant-time right shift.
558    fn shr(&self, bits: u32) -> Self {
559        self.shr(bits)
560    }
561
562    /// Delegates to BigInt::cmp for standard comparison.
563    /// Warning: This may leak timing information - use ct_cmp for crypto.
564    fn cmp(&self, rhs: &Self) -> Ordering {
565        self.cmp(rhs)
566    }
567
568    /// Delegates to BigInt::ct_cmp for constant-time comparison.
569    fn ct_cmp(&self, rhs: &Self) -> Ordering {
570        self.ct_cmp(rhs)
571    }
572
573    /// Delegates to BigInt::ct_select for constant-time conditional selection.
574    fn ct_select(a: &Self, b: &Self, flag: u64) -> Self {
575        Self::ct_select(a, b, flag)
576    }
577
578    /// Delegates to BigInt::is_zero for constant-time zero check.
579    fn is_zero(&self) -> bool {
580        self.is_zero()
581    }
582
583    /// Delegates to BigInt::get_bit for constant-time bit extraction.
584    fn get_bit(&self, bit_position: u32) -> u64 {
585        self.get_bit(bit_position)
586    }
587
588    /// Delegates to BigInt::bit_length for bit length calculation.
589    fn bit_length(&self) -> u32 {
590        self.bit_length()
591    }
592}