commonware_cryptography/bls12381/dkg/
ops.rs1use crate::bls12381::{
4 dkg::Error,
5 primitives::{group::Share, poly},
6};
7use rand::RngCore;
8use rayon::{prelude::*, ThreadPoolBuilder};
9use std::collections::BTreeMap;
10
11pub fn generate_shares<R: RngCore>(
13 rng: &mut R,
14 share: Option<Share>,
15 n: u32,
16 t: u32,
17) -> (poly::Public, Vec<Share>) {
18 let mut secret = poly::new_from(t - 1, rng);
20 if let Some(share) = share {
21 secret.set(0, share.private);
24 }
25
26 let commitment = poly::Public::commit(secret.clone());
28 let shares = (0..n)
29 .map(|i| {
30 let eval = secret.evaluate(i);
31 Share {
32 index: eval.index,
33 private: eval.value,
34 }
35 })
36 .collect::<Vec<_>>();
37 (commitment, shares)
38}
39
40pub fn verify_commitment(
43 previous: Option<&poly::Public>,
44 dealer: u32,
45 commitment: &poly::Public,
46 t: u32,
47) -> Result<(), Error> {
48 if let Some(previous) = previous {
49 let expected = previous.evaluate(dealer).value;
50 if expected != *commitment.constant() {
51 return Err(Error::UnexpectedPolynomial);
52 }
53 }
54 if commitment.degree() != t - 1 {
55 return Err(Error::CommitmentWrongDegree);
56 }
57 Ok(())
58}
59
60pub fn verify_share(
62 previous: Option<&poly::Public>,
63 dealer: u32,
64 commitment: &poly::Public,
65 t: u32,
66 recipient: u32,
67 share: &Share,
68) -> Result<(), Error> {
69 verify_commitment(previous, dealer, commitment, t)?;
71
72 if share.index != recipient {
74 return Err(Error::MisdirectedShare);
75 }
76 let expected = share.public();
77 let given = commitment.evaluate(share.index);
78 if given.value != expected {
79 return Err(Error::ShareWrongCommitment);
80 }
81 Ok(())
82}
83
84pub fn construct_public(
86 commitments: Vec<poly::Public>,
87 required: u32,
88) -> Result<poly::Public, Error> {
89 if commitments.len() < required as usize {
90 return Err(Error::InsufficientDealings);
91 }
92 let mut public = poly::Public::zero();
93 for commitment in commitments {
94 public.add(&commitment);
95 }
96 Ok(public)
97}
98
99pub fn recover_public(
104 previous: &poly::Public,
105 commitments: BTreeMap<u32, poly::Public>,
106 threshold: u32,
107 concurrency: usize,
108) -> Result<poly::Public, Error> {
109 let required = previous.required();
111 if commitments.len() < required as usize {
112 return Err(Error::InsufficientDealings);
113 }
114
115 let pool = ThreadPoolBuilder::new()
117 .num_threads(concurrency)
118 .build()
119 .expect("unable to build thread pool");
120
121 let new = match pool.install(|| {
123 (0..threshold)
124 .into_par_iter()
125 .map(|coeff| {
126 let evals: Vec<_> = commitments
127 .iter()
128 .map(|(dealer, commitment)| poly::Eval {
129 index: *dealer,
130 value: commitment.get(coeff),
131 })
132 .collect();
133 match poly::Public::recover(required, evals) {
134 Ok(point) => Ok(point),
135 Err(_) => Err(Error::PublicKeyInterpolationFailed),
136 }
137 })
138 .collect::<Result<Vec<_>, _>>()
139 }) {
140 Ok(points) => poly::Public::from(points),
141 Err(e) => return Err(e),
142 };
143
144 if previous.constant() != new.constant() {
146 return Err(Error::ReshareMismatch);
147 }
148 Ok(new)
149}