yip_ca/threshold/
refresh.rs1use std::collections::BTreeMap;
2
3use frost::keys::{KeyPackage, PublicKeyPackage};
4use frost::Identifier;
5use frost_ed25519 as frost;
6
7use crate::threshold::ThresholdError;
8
9pub fn proactive_refresh(
15 current_key_packages: &BTreeMap<Identifier, KeyPackage>,
16 requested_threshold: u16,
17) -> Result<BTreeMap<Identifier, KeyPackage>, ThresholdError> {
18 if current_key_packages.is_empty() {
19 return Err(ThresholdError::InvalidParams("empty key package set"));
20 }
21
22 let first_kp = current_key_packages.values().next().unwrap();
23 if requested_threshold != *first_kp.min_signers() {
24 return Err(ThresholdError::InvalidParams(
25 "requested threshold does not match active key package threshold (CVE-2025-58359 guard)",
26 ));
27 }
28
29 let identifiers: Vec<Identifier> = current_key_packages.keys().copied().collect();
30 let mut verifying_shares = BTreeMap::new();
31 for (id, kp) in current_key_packages {
32 verifying_shares.insert(*id, *kp.verifying_share());
33 }
34
35 let pub_key_package = PublicKeyPackage::new(
36 verifying_shares,
37 *first_kp.verifying_key(),
38 Some(requested_threshold),
39 );
40
41 let mut rng = rand::rngs::OsRng;
42 let (refreshing_shares, _) =
43 frost::keys::refresh::compute_refreshing_shares(pub_key_package, &identifiers, &mut rng)?;
44
45 let mut refreshed_key_packages = BTreeMap::new();
46 for (id, secret_share) in identifiers.into_iter().zip(refreshing_shares) {
47 let current_kp = ¤t_key_packages[&id];
48 let refreshed_kp = frost::keys::refresh::refresh_share(secret_share, current_kp)?;
49 refreshed_key_packages.insert(id, refreshed_kp);
50 }
51
52 Ok(refreshed_key_packages)
53}
54
55pub fn repair_lost_share(
58 lost_participant: Identifier,
59 helpers: &[(Identifier, KeyPackage)],
60 pubkey_package: &PublicKeyPackage,
61) -> Result<KeyPackage, ThresholdError> {
62 let helper_ids: Vec<Identifier> = helpers.iter().map(|(id, _)| *id).collect();
63 let mut rng = rand::rngs::OsRng;
64
65 let mut deltas_by_recipient: BTreeMap<Identifier, Vec<frost::keys::repairable::Delta>> =
67 BTreeMap::new();
68
69 for (_id, kp) in helpers {
70 let deltas = frost::keys::repairable::repair_share_part1::<frost_ed25519::Ed25519Sha512, _>(
71 &helper_ids,
72 kp,
73 &mut rng,
74 lost_participant,
75 )?;
76 for (recipient, delta) in deltas {
77 deltas_by_recipient
78 .entry(recipient)
79 .or_default()
80 .push(delta);
81 }
82 }
83
84 let mut sigmas = Vec::new();
86 for id in &helper_ids {
87 let deltas = deltas_by_recipient
88 .remove(id)
89 .ok_or(ThresholdError::InvalidParams("missing helper delta"))?;
90 let sigma = frost::keys::repairable::repair_share_part2(&deltas);
91 sigmas.push(sigma);
92 }
93
94 let repaired_kp =
96 frost::keys::repairable::repair_share_part3(&sigmas, lost_participant, pubkey_package)?;
97
98 Ok(repaired_kp)
99}