vsss_rust/utils/
mod.rs

1//! The module for cryptographic operations, including polynomial generation, evaluation,
2//! prime number generation, hashing, modular arithmetic, and Lagrange interpolation.
3extern crate num_bigint;
4extern crate num_traits;
5extern crate rand;
6
7use num_bigint::{BigUint, BigInt, RandBigInt, ToBigInt};
8use num_traits::{One,Zero};
9use rand::thread_rng;
10use num_prime::RandPrime;
11use num_prime::PrimalityTestConfig;
12use sha2::{Sha256, Digest};
13
14
15/// Represents a polynomial with coefficients in `BigUint`.
16/// This struct is used for operations such as Shamir's Secret Sharing.
17pub struct Polynomial {
18    /// The coefficients of the polynomial.
19    pub coefficients: Vec<BigUint>,
20}
21
22impl Polynomial {
23    /// Creates a new polynomial with random coefficients.
24    /// 
25    /// # Arguments
26    ///
27    /// * `degree` - The degree of the polynomial.
28    /// * `max_bit_size` - The maximum bit size for the random coefficients.
29    ///
30    /// # Returns
31    ///
32    /// A `Polynomial` instance with randomly generated coefficients.
33
34    pub fn new(degree: usize, max_bit_size: usize) -> Self {
35        let mut rng = thread_rng();
36        let mut coefficients = Vec::with_capacity(degree + 1);
37
38        let n = BigUint::one() << max_bit_size;
39
40        for _ in 0..=degree {
41            let coef = rng.gen_biguint_range(&BigUint::one(), &n);
42            coefficients.push(coef);
43        }
44
45        Polynomial { coefficients }
46    }
47    /// Creates a new polynomial specifically designed for Shamir's Secret Sharing (SSS).
48    /// In SSS, the secret is embedded as the constant term (the 0th coefficient) of the polynomial,
49    /// and the remaining coefficients are generated randomly. This method ensures that the polynomial
50    /// is initialized accordingly, with the provided secret as the constant term and random coefficients
51    /// for the other terms, up to the specified threshold.
52    ///
53    /// # Arguments
54    ///
55    /// * `threshold`: The threshold number of shares needed to reconstruct the secret. This also
56    /// determines the degree of the polynomial, which will be `threshold - 1`.
57    /// * `secret_bits`: The number of bits of the secret. This is used to determine the range of
58    /// random coefficients generated for the polynomial's terms, ensuring they are of a similar
59    /// magnitude to the secret.
60    /// * `secret`: A reference to the `BigUint` representing the secret to be shared. This value
61    /// will be used as the constant term of the polynomial.
62    ///
63    /// # Returns
64    ///
65    /// A `Polynomial` instance with the specified secret embedded as the constant term, and random
66    /// coefficients for the other terms, making it suitable for use in Shamir's Secret Sharing.
67    ///
68    pub fn new_for_shamir(threshold: usize, secret_bits: usize, secret: &BigUint) -> Self {
69        let mut rng = thread_rng();
70        let mut coefficients = vec![secret.clone()];
71
72        for _ in 1..threshold {
73            let coef = rng.gen_biguint_range(&BigUint::one(), &(BigUint::one() << secret_bits));
74            coefficients.push(coef);
75        }
76
77        Polynomial { coefficients }
78    }
79    /// Evaluates the polynomial at a given point `x`.
80    ///
81    /// # Arguments
82    ///
83    /// * `x` - The point at which to evaluate the polynomial.
84    ///
85    /// # Returns
86    ///
87    /// The value of the polynomial at point `x`.
88    pub fn evaluate(&self, x: &BigUint) -> BigUint {
89        let mut result = BigUint::zero();
90        let mut x_pow = BigUint::one();
91
92        for coef in &self.coefficients {
93            result += coef * &x_pow;
94            x_pow *= x;
95        }
96
97        result
98    }
99
100    /// Returns a string representation of the polynomial.
101    pub fn to_string(&self) -> String {
102        self.coefficients.iter().enumerate().map(|(index, coef)| {
103            match index {
104                0 => format!("{}", coef),
105                1 => format!("{}x", coef),
106                _ => format!("{}x^{}", coef, index),
107            }
108        }).collect::<Vec<String>>().join(" + ")
109    }
110}
111
112/// Generates a random `BigUint` number within the range `[1, modulus)`.
113///
114/// This function creates a random number that is greater than or equal to `1` and less than
115/// the specified `modulus`. It uses the thread-local random number generator to ensure unpredictability
116/// and suitability for cryptographic applications where secure random number generation is crucial.
117///
118/// # Parameters
119///
120/// * `modulus`: A reference to a `BigUint` that specifies the upper bound of the random number generation.
121///   The generated number will be in the range `[1, modulus)`, meaning it includes `1` but excludes `modulus`.
122///
123/// # Returns
124///
125/// Returns a `BigUint` representing the randomly generated number within the specified range.
126///
127
128pub fn gen_rand(modulus: &BigUint) -> BigUint{
129    let mut rng = thread_rng();
130    rng.gen_biguint_range(&BigUint::one(), modulus)
131}
132
133
134/// Generates a prime number of a specified bit size.
135///
136/// # Arguments
137///
138/// * `bit_size` - The bit size of the prime number to generate.
139///
140/// # Returns
141///
142/// A `BigUint` representing the generated prime number.
143pub fn generate_prime(bit_size: usize) -> BigUint {
144    let mut rng = thread_rng();
145    let config = PrimalityTestConfig::default();
146    rng.gen_prime(bit_size, Some(config))
147}
148/// Hashes input data using SHA-256.
149///
150/// # Arguments
151///
152/// * `data` - The data to hash.
153///
154/// # Returns
155///
156/// A vector of bytes representing the SHA-256 hash of the input data.
157pub fn hash_data(data: &[u8]) -> Vec<u8> {
158    let mut hasher = Sha256::new();
159    hasher.update(data);
160    hasher.finalize().to_vec()
161}
162
163/// Calculates the modular exponentiation of a base raised to an exponent modulo a modulus.
164///
165/// # Arguments
166///
167/// * `base` - The base of the exponentiation.
168/// * `exponent` - The exponent.
169/// * `modulus` - The modulus.
170///
171/// # Returns
172///
173/// The result of the modular exponentiation as a `BigUint`.
174pub fn mod_exp(base: &BigUint, exponent: &BigUint, modulus: &BigUint) -> BigUint {
175    base.modpow(exponent, modulus)
176}
177
178/// Extended Euclidean algorithm for computing the greatest common divisor (gcd) and Bezout coefficients.
179/// 
180/// # Arguments
181/// 
182/// * `a` - The first integer.
183/// * `b` - The second integer.
184/// 
185/// # Returns
186/// 
187/// A tuple `(g, x, y)` representing the gcd of `a` and `b` (`g`), and the Bezout coefficients `x` and `y`.
188pub fn egcd(a: BigInt, b: BigInt) -> (BigInt, BigInt, BigInt) {
189    if a.is_zero() {
190        (b, Zero::zero(), One::one())
191    } else {
192        let (g, x, y) = egcd(b.clone() % a.clone(), a.clone());
193        (g, y - (b / a.clone()) * x.clone(), x)
194    }
195}
196
197/// Computes the modular multiplicative inverse of `a` modulo `m`.
198/// 
199/// # Arguments
200/// 
201/// * `a` - The number to find the inverse for, as a `BigUint`.
202/// * `m` - The modulus, as a `BigUint`.
203/// 
204/// # Returns
205/// 
206/// An `Option<BigUint>` representing the modular multiplicative inverse of `a` modulo `m` if it exists.
207pub fn mod_inv(a: &BigUint, m: &BigUint) -> Option<BigUint> {
208    let (g, x, _) = egcd(a.to_bigint().unwrap(), m.to_bigint().unwrap());
209    if g == One::one() {
210        let x_mod_m = ((x % m.to_bigint().unwrap()) + m.to_bigint().unwrap()) % m.to_bigint().unwrap();
211        
212        Some(x_mod_m.to_biguint().unwrap())
213    } else {
214        None
215    }
216}
217
218/// Performs Lagrange interpolation at zero for a given set of points modulo a given modulus.
219///
220/// This function calculates the Lagrange polynomial that passes through a given set of points
221/// and evaluates it at zero. This is particularly useful in secret sharing schemes,
222/// such as Shamir's Secret Sharing, where the secret is reconstructed from shares without revealing
223/// the shares themselves.
224///
225/// # Parameters
226///
227/// * `points`: A slice of tuples where each tuple contains two `BigUint` values. The first element of each tuple
228/// represents the x-coordinate, and the second element represents the y-coordinate of a point on the polynomial.
229/// * `modulus`: A reference to a `BigUint` value representing the modulus for the finite field operations.
230///
231/// # Returns
232///
233/// Returns `Some(BigUint)` representing the secret (the polynomial evaluated at zero) if the inverse of the
234/// denominator exists for all terms in the interpolation formula. Otherwise, returns `None`.
235///
236
237pub fn lagrange_interpolation_zero(points: &[(BigUint, BigUint)], modulus: &BigUint) -> Option<BigUint> {
238    let mut secret = BigUint::zero();
239
240    for (i, (x_i, y_i)) in points.iter().enumerate() {
241        let mut numerator = BigUint::one();
242        let mut denominator = BigUint::one();
243
244        for (j, (x_j, _)) in points.iter().enumerate() {
245            if i != j {
246                let x_diff = (modulus - x_j) % modulus;
247                numerator = (numerator * x_diff) % modulus;
248                denominator = (denominator * (x_i + modulus - x_j) % modulus) % modulus;
249            }
250        }
251        let inv_denominator = mod_inv(&denominator, modulus)?;
252        let term = (y_i * &numerator * inv_denominator) % modulus;        
253        secret = (secret + term) % modulus;
254    }
255    Some(secret)
256}
257
258
259#[cfg(test)]
260mod tests {
261    use super::*;
262    use num_bigint::ToBigUint;
263
264    // Test for converting polynomial to string representation
265    #[test]
266    fn test_polynomial_to_string() {
267        let poly = Polynomial {
268            coefficients: vec![1.to_biguint().unwrap(), 2.to_biguint().unwrap(), 3.to_biguint().unwrap()],
269        };
270
271        let expected = "1 + 2x + 3x^2".to_string();
272        assert_eq!(poly.to_string(), expected);
273    }
274    #[test]
275    fn test_evaluation(){
276        let poly = Polynomial {
277            coefficients: vec![90782.to_biguint().unwrap(), 222234.to_biguint().unwrap(), 123343.to_biguint().unwrap()],
278        };   
279        let x=poly.evaluate(&(1.to_biguint().unwrap()));   
280        let y = poly.coefficients.iter().fold(BigUint::zero(), |acc, coeff| acc + coeff); 
281        assert_eq!(y,x); 
282    }
283
284    // Test for prime generation
285    #[test]
286    fn test_prime_generation() {
287        let prime = generate_prime(128);
288        println!("Prime:{}", prime);
289    }
290
291    // Test for hashing data
292    #[test]
293    fn test_hash_data() {
294        let data = b"hello, world";
295        let hash = hash_data(data);
296        assert_eq!(hash.len(), 32); // SHA-256 produces a 32-byte (256-bit) hash
297    }
298
299    // Test for modular exponentiation
300    #[test]
301    fn test_mod_exp() {
302        let base = 2.to_biguint().unwrap();
303        let exponent = 10.to_biguint().unwrap();
304        let modulus = 1000.to_biguint().unwrap();
305        let result = mod_exp(&base, &exponent, &modulus);
306        assert_eq!(result, 24.to_biguint().unwrap());
307    }
308
309    // Test for modular inverse
310    #[test]
311    fn test_mod_inv() {
312        let a = 3.to_biguint().unwrap();
313        let m = 11.to_biguint().unwrap();
314        let inv = mod_inv(&a, &m).unwrap();
315        assert_eq!(inv, 4.to_biguint().unwrap());
316    }
317
318    // Test for Lagrange interpolation at zero
319    #[test]
320    fn test_lagrange_interpolation_zero() {
321        let points = vec![
322            (1.to_biguint().unwrap(), 90.to_biguint().unwrap()),
323            (2.to_biguint().unwrap(), 87.to_biguint().unwrap()),
324            (3.to_biguint().unwrap(), 678.to_biguint().unwrap())
325        ];
326        let modulus = 1009.to_biguint().unwrap();
327        let secret = lagrange_interpolation_zero(&points, &modulus).unwrap();
328        assert_eq!(secret, 687.to_biguint().unwrap());
329    }
330}