clock_curve_math/
validation.rs

1//! Input validation utilities for clock-curve-math.
2//!
3//! This module provides comprehensive validation functions for all public APIs
4//! to ensure inputs are within valid ranges and prevent invalid operations.
5//!
6//! ## Validation Functions
7//!
8//! The validation functions check that inputs conform to the mathematical
9//! constraints of the cryptographic primitives:
10//!
11//! - **Field elements** must be in the range [0, p) where p = 2^255 - 19
12//! - **Scalars** must be in the range [0, l) where l = 2^252 + 27742317777372353535851937790883648493
13//! - **Exponents** must be non-negative (though BigInt always represents non-negative values)
14//! - **Moduli** must be positive and non-zero
15//! - **Buffers** must have the correct size for the operation
16//!
17//! ## Error Conditions
18//!
19//! All validation functions return [`MathError`] variants that precisely
20//! describe the validation failure:
21//!
22//! - [`MathError::InvalidFieldElement`]: Value not in [0, p)
23//! - [`MathError::InvalidScalar`]: Value not in [0, l)
24//! - [`MathError::InvalidExponent`]: Negative exponent provided
25//! - [`MathError::InvalidModulus`]: Zero or negative modulus
26//! - [`MathError::BufferTooSmall`]: Input buffer smaller than required
27//! - [`MathError::BufferTooLarge`]: Input buffer larger than required
28//!
29//! ## Usage
30//!
31//! ```rust
32//! use clock_curve_math::validation::*;
33//!
34//! // Validate a field element byte representation
35//! let bytes = [42u8; 32];
36//! assert!(validate_field_bytes(&bytes).is_ok());
37//!
38//! // Validate a scalar BigInt value
39//! let scalar_value = clock_curve_math::BigInt::from_u64(12345);
40//! assert!(validate_scalar_bigint(&scalar_value).is_ok());
41//! ```
42
43use crate::bigint::BigInt;
44use crate::constants::{L_LIMBS, P_LIMBS};
45use crate::error::MathError;
46
47/// Validate that a byte array represents a valid field element (in [0, p)).
48///
49/// # Arguments
50///
51/// * `bytes` - The byte array to validate (must be 32 bytes)
52///
53/// # Returns
54///
55/// Returns `Ok(())` if the bytes represent a valid field element, or an error otherwise.
56///
57/// # Errors
58///
59/// Returns [`MathError::InvalidFieldElement`] if the value is not in [0, p).
60/// Returns [`MathError::BufferTooSmall`] or [`MathError::BufferTooLarge`] if the buffer size is incorrect.
61pub fn validate_field_bytes(bytes: &[u8]) -> Result<(), MathError> {
62    if bytes.len() != 32 {
63        return if bytes.len() < 32 {
64            Err(MathError::BufferTooSmall)
65        } else {
66            Err(MathError::BufferTooLarge)
67        };
68    }
69
70    // SAFETY: We just checked that bytes.len() == 32
71    let bytes_array: &[u8; 32] = bytes.try_into().unwrap();
72    let value = BigInt::from_bytes(bytes_array);
73    let p = BigInt::from_limbs(&P_LIMBS);
74
75    if value.cmp(&p) != core::cmp::Ordering::Less {
76        return Err(MathError::InvalidFieldElement);
77    }
78
79    Ok(())
80}
81
82/// Validate that a byte array represents a valid scalar (in [0, l)).
83///
84/// # Arguments
85///
86/// * `bytes` - The byte array to validate (must be 32 bytes)
87///
88/// # Returns
89///
90/// Returns `Ok(())` if the bytes represent a valid scalar, or an error otherwise.
91///
92/// # Errors
93///
94/// Returns [`MathError::InvalidScalar`] if the value is not in [0, l).
95/// Returns [`MathError::BufferTooSmall`] or [`MathError::BufferTooLarge`] if the buffer size is incorrect.
96pub fn validate_scalar_bytes(bytes: &[u8]) -> Result<(), MathError> {
97    if bytes.len() != 32 {
98        return if bytes.len() < 32 {
99            Err(MathError::BufferTooSmall)
100        } else {
101            Err(MathError::BufferTooLarge)
102        };
103    }
104
105    // SAFETY: We just checked that bytes.len() == 32
106    let bytes_array: &[u8; 32] = bytes.try_into().unwrap();
107    let value = BigInt::from_bytes(bytes_array);
108    let l = BigInt::from_limbs(&L_LIMBS);
109
110    if value.cmp(&l) != core::cmp::Ordering::Less {
111        return Err(MathError::InvalidScalar);
112    }
113
114    Ok(())
115}
116
117/// Validate that a BigInt represents a valid field element (in [0, p)).
118///
119/// # Arguments
120///
121/// * `value` - The BigInt value to validate
122///
123/// # Returns
124///
125/// Returns `Ok(())` if the value is a valid field element, or an error otherwise.
126///
127/// # Errors
128///
129/// Returns [`MathError::InvalidFieldElement`] if the value is not in [0, p).
130pub fn validate_field_bigint(value: &BigInt) -> Result<(), MathError> {
131    let p = BigInt::from_limbs(&P_LIMBS);
132
133    // Check value < p (BigInt values are always >= 0)
134    if value.cmp(&p) != core::cmp::Ordering::Less {
135        return Err(MathError::InvalidFieldElement);
136    }
137
138    Ok(())
139}
140
141/// Validate that a BigInt represents a valid scalar (in [0, l)).
142///
143/// # Arguments
144///
145/// * `value` - The BigInt value to validate
146///
147/// # Returns
148///
149/// Returns `Ok(())` if the value is a valid scalar, or an error otherwise.
150///
151/// # Errors
152///
153/// Returns [`MathError::InvalidScalar`] if the value is not in [0, l).
154pub fn validate_scalar_bigint(value: &BigInt) -> Result<(), MathError> {
155    let l = BigInt::from_limbs(&L_LIMBS);
156
157    // Check value < l (BigInt values are always >= 0)
158    if value.cmp(&l) != core::cmp::Ordering::Less {
159        return Err(MathError::InvalidScalar);
160    }
161
162    Ok(())
163}
164
165/// Validate that a BigInt is a valid exponent for modular exponentiation.
166///
167/// # Arguments
168///
169/// * `exponent` - The exponent to validate
170///
171/// # Returns
172///
173/// Returns `Ok(())` if the exponent is valid, or an error otherwise.
174///
175/// # Errors
176///
177/// Returns [`MathError::InvalidExponent`] if the exponent is negative.
178pub fn validate_exponent(exponent: &BigInt) -> Result<(), MathError> {
179    if exponent.cmp(&crate::ZERO()) == core::cmp::Ordering::Less {
180        return Err(MathError::InvalidExponent);
181    }
182
183    Ok(())
184}
185
186/// Validate that a BigInt is a valid modulus for modular operations.
187///
188/// # Arguments
189///
190/// * `modulus` - The modulus to validate
191///
192/// # Returns
193///
194/// Returns `Ok(())` if the modulus is valid, or an error otherwise.
195///
196/// # Errors
197///
198/// Returns [`MathError::InvalidModulus`] if the modulus is zero or negative.
199pub fn validate_modulus(modulus: &BigInt) -> Result<(), MathError> {
200    if modulus.cmp(&crate::ZERO()) != core::cmp::Ordering::Greater {
201        return Err(MathError::InvalidModulus);
202    }
203
204    Ok(())
205}
206
207/// Validate that a value is not zero (for operations that require non-zero inputs).
208///
209/// # Arguments
210///
211/// * `value` - The value to check
212/// * `_operation` - Description of the operation requiring non-zero input (currently unused)
213///
214/// # Returns
215///
216/// Returns `Ok(())` if the value is non-zero, or an error otherwise.
217///
218/// # Errors
219///
220/// Returns [`MathError::DivisionByZero`] if the value is zero.
221pub fn validate_non_zero(value: &BigInt, _operation: &str) -> Result<(), MathError> {
222    if value.is_zero() {
223        // Note: DivisionByZero is used here even for operations other than division
224        // that require non-zero inputs (like modular inverse)
225        return Err(MathError::DivisionByZero);
226    }
227
228    Ok(())
229}
230
231/// Validate buffer size for byte array operations.
232///
233/// # Arguments
234///
235/// * `buffer` - The buffer to validate
236/// * `expected_size` - The expected buffer size
237///
238/// # Returns
239///
240/// Returns `Ok(())` if the buffer size is correct, or an error otherwise.
241///
242/// # Errors
243///
244/// Returns [`MathError::BufferTooSmall`] or [`MathError::BufferTooLarge`] if the buffer size is incorrect.
245pub fn validate_buffer_size(buffer: &[u8], expected_size: usize) -> Result<(), MathError> {
246    if buffer.len() != expected_size {
247        return if buffer.len() < expected_size {
248            Err(MathError::BufferTooSmall)
249        } else {
250            Err(MathError::BufferTooLarge)
251        };
252    }
253
254    Ok(())
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260    use crate::bigint::BigInt;
261
262    #[test]
263    fn test_validate_field_bytes_valid() {
264        let bytes = [42u8; 32];
265        assert!(validate_field_bytes(&bytes).is_ok());
266    }
267
268    #[test]
269    fn test_validate_field_bytes_invalid_too_large() {
270        // p = 2^255 - 19, so any value >= p should be invalid
271        let p_bytes = [
272            0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
273            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F
274        ];
275        assert!(matches!(validate_field_bytes(&p_bytes), Err(MathError::InvalidFieldElement)));
276    }
277
278    #[test]
279    fn test_validate_field_bytes_wrong_size() {
280        let small_buffer = [42u8; 16];
281        assert!(matches!(validate_field_bytes(&small_buffer), Err(MathError::BufferTooSmall)));
282
283        let large_buffer = [42u8; 64];
284        assert!(matches!(validate_field_bytes(&large_buffer), Err(MathError::BufferTooLarge)));
285    }
286
287    #[test]
288    fn test_validate_scalar_bytes_valid() {
289        // Use a small value that is definitely < l
290        let mut bytes = [0u8; 32];
291        bytes[0] = 42; // Only the least significant byte is non-zero
292        assert!(validate_scalar_bytes(&bytes).is_ok());
293    }
294
295    #[test]
296    fn test_validate_scalar_bytes_invalid_too_large() {
297        // Create bytes that represent a value >= l
298        let large_bytes = [0xFF; 32];
299        // This will likely be >= l, but let's test it
300        let result = validate_scalar_bytes(&large_bytes);
301        // It might be valid or invalid depending on the exact value, but shouldn't panic
302        assert!(result.is_ok() || matches!(result, Err(MathError::InvalidScalar)));
303    }
304
305    #[test]
306    fn test_validate_field_bigint_valid() {
307        let value = BigInt::from_u64(42);
308        assert!(validate_field_bigint(&value).is_ok());
309    }
310
311    #[test]
312    fn test_validate_field_bigint_too_large() {
313        let p = BigInt::from_limbs(&P_LIMBS);
314        let too_large = p.add(&BigInt::from_u64(1));
315        assert!(matches!(validate_field_bigint(&too_large), Err(MathError::InvalidFieldElement)));
316    }
317
318    #[test]
319    fn test_validate_exponent_negative() {
320        // BigInt doesn't support negative numbers, so we test with a large positive number
321        // that would underflow if it were negative
322        let large_value = BigInt::from_limbs(&[u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
323        // This should pass since BigInt treats all values as positive
324        assert!(validate_exponent(&large_value).is_ok());
325    }
326
327    #[test]
328    fn test_validate_exponent_zero() {
329        let zero = BigInt::from_u64(0);
330        assert!(validate_exponent(&zero).is_ok());
331    }
332
333    #[test]
334    fn test_validate_modulus_zero() {
335        let zero = BigInt::from_u64(0);
336        assert!(matches!(validate_modulus(&zero), Err(MathError::InvalidModulus)));
337    }
338
339    #[test]
340    fn test_validate_modulus_large_positive() {
341        // Test with a modulus that's actually valid (non-zero)
342        let valid_modulus = BigInt::from_u64(17);
343        assert!(validate_modulus(&valid_modulus).is_ok());
344    }
345
346    #[test]
347    fn test_validate_non_zero() {
348        let zero = BigInt::from_u64(0);
349        assert!(matches!(validate_non_zero(&zero, "test"), Err(MathError::DivisionByZero)));
350
351        let non_zero = BigInt::from_u64(42);
352        assert!(validate_non_zero(&non_zero, "test").is_ok());
353    }
354}