use crate::utils::{Polynomial, mod_exp,lagrange_interpolation_zero};
use num_bigint::{BigUint, ToBigUint};
use num_traits::One;
pub struct FeldmanVSSParams {
pub g: BigUint, pub q: BigUint, }
impl FeldmanVSSParams {
pub fn new(g: BigUint, q: BigUint) -> Self {
FeldmanVSSParams { g, q }
}
pub fn generate_shares(&self, secret: &BigUint, threshold: usize, num_shares: usize) -> (Vec<(BigUint, BigUint)>, Vec<BigUint>) {
let poly = Polynomial::new_for_shamir(threshold - 1, secret.bits() as usize, secret);
let mut shares = Vec::with_capacity(num_shares);
for i in 1..=num_shares {
let x = i.to_biguint().unwrap();
let y = poly.evaluate(&x) % &self.q; shares.push((x, y));
}
let commitments = self.generate_commitments(&poly);
(shares, commitments)
}
fn generate_commitments(&self, polynomial: &Polynomial) -> Vec<BigUint> {
polynomial.coefficients.iter().map(|coef| {
mod_exp(&self.g, coef, &self.q) }).collect()
}
}
pub fn verify_share(
i: &BigUint, share: &BigUint, commitments: &[BigUint], params: &FeldmanVSSParams, ) -> bool {
let lhs = mod_exp(¶ms.g, share, ¶ms.q);
let rhs = commitments.iter().enumerate().fold(BigUint::one(), |acc, (j, commitment)| {
let exponent = i.modpow(&BigUint::from(j), ¶ms.q);
(acc * mod_exp(commitment, &exponent, ¶ms.q)) % ¶ms.q
});
lhs == rhs
}
pub fn reconstruct_secret(shares: &[(BigUint, BigUint)], modulus: &BigUint) -> Option<BigUint> {
lagrange_interpolation_zero(shares, modulus)
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::ToBigUint;
use crate::utils::generate_prime;
#[test]
fn test_share_generation_and_verification() {
let secret = 1234.to_biguint().unwrap();
let threshold = 3;
let num_shares = 5;
let g = 2.to_biguint().unwrap();
let q = generate_prime(256);
let params = FeldmanVSSParams::new(g, q);
let (shares, commitments) = params.generate_shares(&secret, threshold, num_shares);
for (i, &(ref x, ref y)) in shares.iter().enumerate() {
assert!(verify_share(x, y, &commitments, ¶ms), "Share {} failed verification", i + 1);
}
let reconstructed_secret = reconstruct_secret(&shares[..threshold], ¶ms.q).unwrap();
assert_eq!(secret, reconstructed_secret, "Reconstructed secret does not match the original secret.");
}
}