dkg_recovery/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3#![no_std]
4
5use core::ops::{Deref, DerefMut};
6extern crate alloc;
7use alloc::vec::Vec;
8
9use zeroize::Zeroizing;
10
11use ciphersuite::Ciphersuite;
12
13pub use dkg::*;
14
15/// Errors encountered when recovering a secret-shared key from a collection of
16/// `dkg::ThresholdKeys`.
17#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
18pub enum RecoveryError {
19  /// No keys were provided.
20  #[error("no keys provided")]
21  NoKeysProvided,
22  /// Not enough keys were provided.
23  #[error("not enough keys provided (threshold required {required}, provided {provided})")]
24  NotEnoughKeysProvided { required: u16, provided: usize },
25  /// The keys had inconsistent parameters.
26  #[error("keys had inconsistent parameters")]
27  InconsistentParameters,
28  /// The keys are from distinct secret-sharing sessions or otherwise corrupt.
29  #[error("recovery failed")]
30  Failure,
31  /// An error propagated from the underlying `dkg` crate.
32  #[error("error from dkg ({0})")]
33  DkgError(DkgError),
34}
35
36/// Recover a shared secret from a collection of `dkg::ThresholdKeys`.
37pub fn recover_key<C: Ciphersuite>(
38  keys: &[ThresholdKeys<C>],
39) -> Result<Zeroizing<C::F>, RecoveryError> {
40  let included = keys.iter().map(|keys| keys.params().i()).collect::<Vec<_>>();
41
42  let keys_len = keys.len();
43  let mut keys = keys.iter();
44  let first_keys = keys.next().ok_or(RecoveryError::NoKeysProvided)?;
45  {
46    let t = first_keys.params().t();
47    if keys_len < usize::from(t) {
48      Err(RecoveryError::NotEnoughKeysProvided { required: t, provided: keys_len })?;
49    }
50  }
51  {
52    let first_params = (
53      first_keys.params().t(),
54      first_keys.params().n(),
55      first_keys.group_key(),
56      first_keys.current_scalar(),
57      first_keys.current_offset(),
58    );
59    for keys in keys.clone() {
60      let params = (
61        keys.params().t(),
62        keys.params().n(),
63        keys.group_key(),
64        keys.current_scalar(),
65        keys.current_offset(),
66      );
67      if params != first_params {
68        Err(RecoveryError::InconsistentParameters)?;
69      }
70    }
71  }
72
73  let mut res: Zeroizing<_> =
74    first_keys.view(included.clone()).map_err(RecoveryError::DkgError)?.secret_share().clone();
75  for keys in keys {
76    *res.deref_mut() +=
77      keys.view(included.clone()).map_err(RecoveryError::DkgError)?.secret_share().deref();
78  }
79
80  if (C::generator() * res.deref()) != first_keys.group_key() {
81    Err(RecoveryError::Failure)?;
82  }
83
84  Ok(res)
85}