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}