#![allow(non_snake_case)]
use num_traits::identities::One;
use sha2::{Digest, Sha256};
use std::sync::Arc;
use crate::dleq::DLEQ;
use crate::group::Group;
use crate::sharebox::DistributionSharesBox;
#[derive(Debug, Clone)]
pub struct PVSS<G: Group> {
group: Arc<G>,
}
impl<G: Group> PVSS<G> {
pub fn new(group: Arc<G>) -> Self {
PVSS { group }
}
pub fn group(&self) -> &G {
&self.group
}
pub fn group_arc(&self) -> Arc<G> {
self.group.clone()
}
}
impl<G: Group> PVSS<G>
where
G::Scalar: Clone + One + From<i64>,
G::Element: Clone + Eq + Ord,
{
pub fn verify_distribution_shares(
&self,
distribute_sharesbox: &DistributionSharesBox<G>,
) -> bool {
let subgroup_gen = self.group.subgroup_generator();
let mut challenge_hasher = Sha256::new();
for publickey in &distribute_sharesbox.publickeys {
let pubkey_bytes = self.group.element_to_bytes(publickey);
let position = distribute_sharesbox.positions.get(&pubkey_bytes);
let response = distribute_sharesbox.responses.get(&pubkey_bytes);
let encrypted_share =
distribute_sharesbox.shares.get(&pubkey_bytes);
if position.is_none()
|| response.is_none()
|| encrypted_share.is_none()
{
return false;
}
let mut x_val = self.group.identity();
let mut exponent = G::Scalar::one();
for j in 0..distribute_sharesbox.commitments.len() {
let c_j_pow = self
.group
.exp(&distribute_sharesbox.commitments[j], &exponent);
x_val = self.group.mul(&x_val, &c_j_pow);
let pos_scalar = G::Scalar::from(*position.unwrap());
exponent = self.group.scalar_mul(&exponent, &pos_scalar);
}
let _ = DLEQ::<G>::verifier_update_hash(
self.group.as_ref(),
&subgroup_gen,
&x_val,
publickey,
encrypted_share.unwrap(),
response.unwrap(),
&distribute_sharesbox.challenge,
&mut challenge_hasher,
);
}
let challenge_hash = challenge_hasher.finalize();
let computed_challenge = self.group.hash_to_scalar(&challenge_hash);
computed_challenge == distribute_sharesbox.challenge
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::groups::ModpGroup;
use crate::participant::Participant;
use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
#[test]
fn test_generic_mpvss_new() {
let group = ModpGroup::new();
let pvss = PVSS::new(group);
let modulus = pvss.group().modulus();
let expected = modulus - BigInt::one();
assert_eq!(pvss.group().order(), &expected);
}
#[test]
fn test_generic_mpvss_verify_distribution_shares() {
let group = ModpGroup::new();
let pvss = PVSS::new(group.clone());
let mut dealer = Participant::with_arc(group.clone());
let secret = BigUint::from(123456u32);
let mut p1 = Participant::with_arc(group.clone());
let mut p2 = Participant::with_arc(group.clone());
let mut p3 = Participant::with_arc(group.clone());
p1.initialize();
p2.initialize();
p3.initialize();
let publickeys = vec![
p1.publickey.clone(),
p2.publickey.clone(),
p3.publickey.clone(),
];
let dist_box = dealer.distribute_secret(
&secret.to_bigint().unwrap(),
&publickeys,
3,
);
assert!(pvss.verify_distribution_shares(&dist_box));
}
#[test]
fn test_generic_mpvss_verify_share() {
let group = ModpGroup::new();
let mut rng = rand::thread_rng();
let mut dealer = Participant::with_arc(group.clone());
dealer.initialize();
let mut p1 = Participant::with_arc(group.clone());
let mut p2 = Participant::with_arc(group.clone());
let mut p3 = Participant::with_arc(group.clone());
p1.initialize();
p2.initialize();
p3.initialize();
let secret = BigUint::from(123456u32);
let publickeys = vec![
p1.publickey.clone(),
p2.publickey.clone(),
p3.publickey.clone(),
];
let dist_box = dealer.distribute_secret(
&secret.to_bigint().unwrap(),
&publickeys,
3,
);
let w: BigInt = rng
.gen_biguint_below(&group.modulus().to_biguint().unwrap())
.to_bigint()
.unwrap();
let s1 = p1
.extract_secret_share(&dist_box, &p1.privatekey, &w)
.unwrap();
assert!(dealer.verify_share(&s1, &dist_box, &p1.publickey));
}
#[test]
fn test_generic_mpvss_reconstruct() {
let group = ModpGroup::new();
let mut rng = rand::thread_rng();
let mut dealer = Participant::with_arc(group.clone());
dealer.initialize();
let mut p1 = Participant::with_arc(group.clone());
let mut p2 = Participant::with_arc(group.clone());
let mut p3 = Participant::with_arc(group.clone());
p1.initialize();
p2.initialize();
p3.initialize();
let secret = BigUint::from(123456u32);
let publickeys = vec![
p1.publickey.clone(),
p2.publickey.clone(),
p3.publickey.clone(),
];
let dist_box = dealer.distribute_secret(
&secret.to_bigint().unwrap(),
&publickeys,
3,
);
let w: BigInt = rng
.gen_biguint_below(&group.modulus().to_biguint().unwrap())
.to_bigint()
.unwrap();
let s1 = p1
.extract_secret_share(&dist_box, &p1.privatekey, &w)
.unwrap();
let s2 = p2
.extract_secret_share(&dist_box, &p2.privatekey, &w)
.unwrap();
let s3 = p3
.extract_secret_share(&dist_box, &p3.privatekey, &w)
.unwrap();
let reconstructed =
dealer.reconstruct(&[s1, s2, s3], &dist_box).unwrap();
assert_eq!(reconstructed.to_biguint().unwrap(), secret);
}
}