use amcl_wrapper::group_elem::GroupElement;
use amcl_wrapper::group_elem_g1::G1;
use amcl_wrapper::field_elem::{FieldElement, FieldElementVector};
use std::collections::HashMap;
use crate::pedersen_vss::PedersenVSS;
pub struct PedersenDVSSParticipant {
pub id: usize,
pub secret: FieldElement,
pub comm_coeffs: HashMap<usize, G1>,
pub s_shares: HashMap<usize, FieldElement>,
pub t_shares: HashMap<usize, FieldElement>,
all_comm_coeffs: HashMap<usize, HashMap<usize, G1>>,
all_shares: HashMap<usize, (FieldElement, FieldElement)>,
pub final_comm_coeffs: HashMap<usize, G1>,
pub secret_share: FieldElement,
}
impl PedersenDVSSParticipant {
pub fn new(id: usize, threshold: usize, total: usize, g: &G1, h: &G1) -> Self {
let (secret, _, comm_coeffs, s_shares, t_shares) =
PedersenVSS::deal(threshold, total, &g, &h);
Self {
id,
secret,
comm_coeffs,
s_shares,
t_shares,
all_comm_coeffs: HashMap::new(),
all_shares: HashMap::new(),
final_comm_coeffs: HashMap::new(),
secret_share: FieldElement::new(),
}
}
pub fn received_share(
&mut self,
sender_id: usize,
comm_coeffs: HashMap<usize, G1>,
share: (FieldElement, FieldElement),
threshold: usize,
total: usize,
g: &G1,
h: &G1,
) {
assert!(sender_id <= total);
assert!(!self.all_comm_coeffs.contains_key(&sender_id));
assert!(!self.all_shares.contains_key(&sender_id));
assert!(PedersenVSS::verify_share(
threshold,
self.id,
(&share.0, &share.1),
&comm_coeffs,
&g,
&h
));
self.all_comm_coeffs.insert(sender_id, comm_coeffs);
self.all_shares.insert(sender_id, share);
}
pub fn compute_final_comm_coeffs_and_shares(
&mut self,
threshold: usize,
total: usize,
g: &G1,
h: &G1,
) {
assert_eq!(self.all_comm_coeffs.len(), total - 1);
assert_eq!(self.all_shares.len(), total - 1);
for i in 0..threshold {
let mut cm = G1::identity();
for j in 1..=total {
if j != self.id {
cm += self.all_comm_coeffs[&j].get(&i).unwrap();
} else {
cm += self.comm_coeffs.get(&i).unwrap();
}
}
self.final_comm_coeffs.insert(i, cm);
}
let mut final_s_share = FieldElement::zero();
let mut final_t_share = FieldElement::zero();
for i in 1..=total {
let (s, t) = if i != self.id {
let tpl = &self.all_shares[&i];
(&tpl.0, &tpl.1)
} else {
(&self.s_shares[&i], &self.t_shares[&i])
};
final_s_share += s;
final_t_share += t;
}
assert!(PedersenVSS::verify_share(
threshold,
self.id,
(&final_s_share, &final_t_share),
&self.final_comm_coeffs,
&g,
&h
));
self.secret_share = final_s_share;
}
}
#[cfg(test)]
pub fn share_secret_for_testing(
threshold: usize,
total: usize,
g: &G1,
h: &G1,
) -> Vec<PedersenDVSSParticipant> {
let mut participants = vec![];
for i in 1..=total {
let p = PedersenDVSSParticipant::new(i, threshold, total, g, h);
participants.push(p);
}
for i in 0..total {
for j in 0..total {
if i == j {
continue;
}
let (id, comm_coeffs, (s, t)) = (
participants[j].id.clone(),
participants[j].comm_coeffs.clone(),
(
participants[j].s_shares[&(i + 1)].clone(),
participants[j].t_shares[&(i + 1)].clone(),
),
);
let recv_p = &mut participants[i];
recv_p.received_share(id, comm_coeffs, (s, t), threshold, total, g, h);
}
}
for i in 0..total {
participants[i].compute_final_comm_coeffs_and_shares(threshold, total, g, h);
}
participants
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shamir_secret_sharing::reconstruct_secret;
#[test]
fn test_Pedersen_DVSS() {
let threshold = 5;
let total = 10;
let (g, h) = PedersenVSS::gens("test".as_bytes());
let participants = share_secret_for_testing(threshold, total, &g, &h);
let mut expected_shared_secret = FieldElement::zero();
for p in &participants {
expected_shared_secret += &p.secret;
}
let mut shares = HashMap::new();
for i in 0..threshold {
shares.insert(participants[i].id, participants[i].secret_share.clone());
}
let recon_secret = reconstruct_secret(threshold, shares);
assert_eq!(expected_shared_secret, recon_secret);
}
}