vsss_rust/feldman_verifiability/
mod.rs

1//! # Feldman's Verifiable Secret Sharing (VSS) Module
2//!
3//! This module implements Feldman's Verifiable Secret Sharing scheme, an extension
4//! of Shamir's Secret Sharing (SSS) that adds a layer of verifiability to the shared
5//! secrets. In Feldman's VSS, commitments to the coefficients of the polynomial used
6//! in Shamir's scheme are publicly shared. These commitments enable any party to verify
7//! their shares without revealing the secret or the coefficients of the polynomial.
8//!
9//! The key functionalities include:
10//! - Generation of shares based on a secret.
11//! - Creation of public commitments to the polynomial's coefficients.
12//! - Verification of shares against the public commitments.
13//! - Reconstruction of the secret from a subset of shares using Lagrange interpolation.
14//!
15//! This module requires `Polynomial`, `mod_exp`, `lagrange_interpolation_zero` and potentially other utility functions
16//! from the `utils` module for its operations.
17
18
19use crate::utils::{Polynomial, mod_exp,lagrange_interpolation_zero};
20use num_bigint::{BigUint, ToBigUint};
21use num_traits::One;
22
23/// Represents the public parameters for the Feldman VSS scheme.
24pub struct FeldmanVSSParams {
25    pub g: BigUint, // Generator of the group G
26    pub q: BigUint, // Prime order of the group G
27}
28
29impl FeldmanVSSParams {
30
31    /// Initializes Feldman VSS parameters with a generator and prime order.
32    pub fn new(g: BigUint, q: BigUint) -> Self {
33        FeldmanVSSParams { g, q }
34    }
35
36
37    /// Generates shares for Shamir's Secret Sharing (SSS) scheme and creates commitments for 
38    /// Feldman's Verifiable Secret Sharing (VSS) based on a provided secret, a threshold, 
39    /// and the total number of shares. It combines the secret sharing mechanism with a 
40    /// verifiable component by publishing commitments to the coefficients of the polynomial
41    /// used to generate the shares.
42    ///
43    /// # Arguments
44    ///
45    /// * `secret` - A `BigUint` representing the secret to be shared.
46    /// * `threshold` - The minimum number of shares required to reconstruct the secret.
47    /// * `num_shares` - The total number of shares to be generated.
48    ///
49    /// # Returns
50    ///
51    /// A tuple containing two vectors:
52    /// - The first vector contains tuples of `BigUint`, each representing a share with an
53    ///   index (x-value) and the corresponding share value (y-value).
54    /// - The second vector contains `BigUint` commitments to the coefficients of the polynomial,
55    ///   enabling the verification of shares without revealing the coefficients themselves.
56
57    pub fn generate_shares(&self, secret: &BigUint, threshold: usize, num_shares: usize) -> (Vec<(BigUint, BigUint)>, Vec<BigUint>) {
58        let poly = Polynomial::new_for_shamir(threshold - 1, secret.bits() as usize, secret);
59        let mut shares = Vec::with_capacity(num_shares);
60
61        // Generate shares using the polynomial, similar to Shamir's scheme
62        for i in 1..=num_shares {
63            let x = i.to_biguint().unwrap();
64            let y = poly.evaluate(&x) % &self.q; // Ensure the evaluation is done modulo q
65            shares.push((x, y));
66        }
67
68        // Generate commitments for the polynomial's coefficients for verifiability
69        let commitments = self.generate_commitments(&poly);
70
71        (shares, commitments)
72    }
73    
74    /// Generates verifiable commitments to the coefficients of the polynomial used in the secret sharing.
75    ///
76    /// In Feldman's Verifiable Secret Sharing scheme, these commitments are made public and allow any party
77    /// to verify their shares without compromising the security of the secret or needing access to the polynomial's
78    /// coefficients directly. Each commitment is calculated using the group's generator `g` raised to the power
79    /// of the coefficient, all operations performed modulo `q`, the prime order of the group.
80    ///
81    /// # Arguments
82    ///
83    /// * `polynomial` - A reference to the `Polynomial` instance that represents the polynomial used
84    ///   to generate shares in the secret sharing scheme. The polynomial's coefficients are used to
85    ///   create the commitments.
86    ///
87    /// # Returns
88    ///
89    /// A vector of `BigUint` representing the commitments to each coefficient of the polynomial.
90    /// These commitments can be publicly shared to enable verification of shares by participants
91    /// without revealing the polynomial's coefficients or the shared secret itself.
92    ///
93    /// Each commitment is of the form `g^coef mod q`, where `g` is the generator of the group,
94    /// `coef` is a coefficient of the polynomial, and `q` is the prime order of the group.
95    fn generate_commitments(&self, polynomial: &Polynomial) -> Vec<BigUint> {
96        polynomial.coefficients.iter().map(|coef| {
97            mod_exp(&self.g, coef, &self.q) // Compute g^coef mod q for each coefficient
98        }).collect()
99    }
100
101}
102
103
104/// Verifies a share against the public commitments using the Feldman Verifiable Secret Sharing scheme.
105/// This function checks if a share is valid by verifying that g^share equals the product of the commitments
106/// raised to the power of their respective indices, all operations performed modulo q.
107///
108/// # Arguments
109///
110/// * `i` - A `BigUint` representing the index of the share being verified.
111/// * `share` - A `BigUint` representing the share value associated with the index `i`.
112/// * `commitments` - A slice of `BigUint` representing the public commitments to the polynomial coefficients.
113/// * `params` - A reference to the `FeldmanVSSParams` containing the public parameters (g and q) of the scheme.
114///
115/// # Returns
116///
117/// `true` if the share is valid according to the verification equation, otherwise `false`.
118
119pub fn verify_share(
120    i: &BigUint, // Share index
121    share: &BigUint, // Share value
122    commitments: &[BigUint], // Public commitments
123    params: &FeldmanVSSParams, // VSS parameters
124) -> bool {
125    // Calculate the left-hand side (LHS) as g^share mod q
126    let lhs = mod_exp(&params.g, share, &params.q);
127
128    // Calculate the right-hand side (RHS) as the product of commitments raised to the power of the share index
129    let rhs = commitments.iter().enumerate().fold(BigUint::one(), |acc, (j, commitment)| {
130        let exponent = i.modpow(&BigUint::from(j), &params.q);
131        (acc * mod_exp(commitment, &exponent, &params.q)) % &params.q
132    });
133
134    lhs == rhs
135}
136
137/// Reconstructs the secret from a set of shares using Lagrange interpolation at zero.
138/// This function is a critical part of Shamir's Secret Sharing, enabling the recovery
139/// of the secret from a minimum number of shares without revealing the shares themselves.
140///
141/// # Arguments
142///
143/// * `shares` - A slice of tuples containing shares, where each tuple consists of an
144///   index (x-value) and the corresponding share value (y-value).
145/// * `modulus` - A `BigUint` representing the modulus used for the finite field operations,
146///   which should be the same as used in share generation.
147///
148/// # Returns
149///
150/// An `Option<BigUint>` containing the reconstructed secret if successful, otherwise `None`.
151
152pub fn reconstruct_secret(shares: &[(BigUint, BigUint)], modulus: &BigUint) -> Option<BigUint> {
153    lagrange_interpolation_zero(shares, modulus)
154}
155
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160    use num_bigint::ToBigUint;
161    use crate::utils::generate_prime;
162
163    #[test]
164    fn test_share_generation_and_verification() {
165        let secret = 1234.to_biguint().unwrap();
166        let threshold = 3;
167        let num_shares = 5;
168
169        let g = 2.to_biguint().unwrap();
170        let q = generate_prime(256);
171
172        let params = FeldmanVSSParams::new(g, q);
173
174        let (shares, commitments) = params.generate_shares(&secret, threshold, num_shares);
175
176        for (i, &(ref x, ref y)) in shares.iter().enumerate() {
177            assert!(verify_share(x, y, &commitments, &params), "Share {} failed verification", i + 1);
178        }
179
180        let reconstructed_secret = reconstruct_secret(&shares[..threshold], &params.q).unwrap();
181        assert_eq!(secret, reconstructed_secret, "Reconstructed secret does not match the original secret.");
182    }
183}