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}