commonware_cryptography/bls12381/dkg/
ops.rs1use crate::bls12381::{
4 dkg::Error,
5 primitives::{
6 group::Share,
7 ops::msm_interpolate,
8 poly::{self, compute_weights},
9 variant::Variant,
10 },
11};
12use rand::RngCore;
13use rayon::{prelude::*, ThreadPoolBuilder};
14use std::collections::BTreeMap;
15
16pub fn generate_shares<R: RngCore, V: Variant>(
18 rng: &mut R,
19 share: Option<Share>,
20 n: u32,
21 t: u32,
22) -> (poly::Public<V>, Vec<Share>) {
23 let mut secret = poly::new_from(t - 1, rng);
25 if let Some(share) = share {
26 secret.set(0, share.private);
29 }
30
31 let commitment = poly::Public::<V>::commit(secret.clone());
33 let shares = (0..n)
34 .map(|i| {
35 let eval = secret.evaluate(i);
36 Share {
37 index: eval.index,
38 private: eval.value,
39 }
40 })
41 .collect::<Vec<_>>();
42 (commitment, shares)
43}
44
45pub fn evaluate_all<V: Variant>(polynomial: &poly::Public<V>, n: u32) -> Vec<V::Public> {
47 let mut evals = Vec::with_capacity(n as usize);
48 for index in 0..n {
49 evals.push(polynomial.evaluate(index).value);
50 }
51 evals
52}
53
54pub fn verify_commitment<V: Variant>(
57 previous: Option<&poly::Public<V>>,
58 dealer: u32,
59 commitment: &poly::Public<V>,
60 t: u32,
61) -> Result<(), Error> {
62 if let Some(previous) = previous {
63 let expected = previous.evaluate(dealer).value;
64 if expected != *commitment.constant() {
65 return Err(Error::UnexpectedPolynomial);
66 }
67 }
68 if commitment.degree() != t - 1 {
69 return Err(Error::CommitmentWrongDegree);
70 }
71 Ok(())
72}
73
74pub fn verify_share<V: Variant>(
76 previous: Option<&poly::Public<V>>,
77 dealer: u32,
78 commitment: &poly::Public<V>,
79 t: u32,
80 recipient: u32,
81 share: &Share,
82) -> Result<(), Error> {
83 verify_commitment::<V>(previous, dealer, commitment, t)?;
85
86 if share.index != recipient {
88 return Err(Error::MisdirectedShare);
89 }
90 let expected = share.public::<V>();
91 let given = commitment.evaluate(share.index);
92 if given.value != expected {
93 return Err(Error::ShareWrongCommitment);
94 }
95 Ok(())
96}
97
98pub fn construct_public<V: Variant>(
100 commitments: Vec<poly::Public<V>>,
101 required: u32,
102) -> Result<poly::Public<V>, Error> {
103 if commitments.len() < required as usize {
104 return Err(Error::InsufficientDealings);
105 }
106 let mut public = poly::Public::<V>::zero();
107 for commitment in commitments {
108 public.add(&commitment);
109 }
110 Ok(public)
111}
112
113pub fn recover_public_with_weights<V: Variant>(
118 previous: &poly::Public<V>,
119 commitments: BTreeMap<u32, poly::Public<V>>,
120 weights: &BTreeMap<u32, poly::Weight>,
121 threshold: u32,
122 concurrency: usize,
123) -> Result<poly::Public<V>, Error> {
124 let required = previous.required();
126 if commitments.len() < required as usize {
127 return Err(Error::InsufficientDealings);
128 }
129
130 let pool = ThreadPoolBuilder::new()
132 .num_threads(concurrency)
133 .build()
134 .expect("unable to build thread pool");
135
136 let new = match pool.install(|| {
138 (0..threshold)
139 .into_par_iter()
140 .map(|coeff| {
141 let evals = commitments
143 .iter()
144 .map(|(dealer, commitment)| poly::Eval {
145 index: *dealer,
146 value: commitment.get(coeff),
147 })
148 .collect::<Vec<_>>();
149
150 msm_interpolate(weights, &evals).map_err(|_| Error::PublicKeyInterpolationFailed)
152 })
153 .collect::<Result<Vec<_>, _>>()
154 }) {
155 Ok(points) => poly::Public::<V>::from(points),
156 Err(e) => return Err(e),
157 };
158
159 if previous.constant() != new.constant() {
161 return Err(Error::ReshareMismatch);
162 }
163 Ok(new)
164}
165
166pub fn recover_public<V: Variant>(
171 previous: &poly::Public<V>,
172 commitments: BTreeMap<u32, poly::Public<V>>,
173 threshold: u32,
174 concurrency: usize,
175) -> Result<poly::Public<V>, Error> {
176 let required = previous.required();
178 if commitments.len() < required as usize {
179 return Err(Error::InsufficientDealings);
180 }
181
182 let indices: Vec<u32> = commitments.keys().cloned().collect();
184 let weights = compute_weights(indices).map_err(|_| Error::PublicKeyInterpolationFailed)?;
185
186 recover_public_with_weights::<V>(previous, commitments, &weights, threshold, concurrency)
188}