1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Our take on the WIP *[ChillDKG: Distributed Key Generation for FROST][ChillDKG]* spec
//!
//! ChillDKG is a modular distributed key generation protocol. At the end all the intended parties
//! have a valid `t-of-n` [Shamir secret sharing] of a secret key without requiring a trusted party
//! or even an honest majority.
//!
//! The [WIP spec][ChillDKG] defines two roles:
//!
//! - *Coordinator*: A central party who relays and aggregates messages between the other parties.
//! - *Participants*: The parties who provide secret input and receive secret shares as output from the protocol.
//!
//! In this implementation we split "participants" into two further roles:
//!
//! - *Contributors*: parties that provide secret input into the key generation
//! - *Receivers*: parties that receive a secret share from the protocol.
//!
//! We see a benefit to having parties that provide secret input but do not receive secret output —
//! we call these *aux contributors* (and the parties that do both *receiver-contributors*; every
//! receiver is also a contributor by protocol invariant). The main example of an aux contributor
//! is the coordinator itself. In the context of a Bitcoin hardware wallet, the coordinator is
//! usually the only party with access to the internet therefore, if the coordinator contributes
//! input honestly, even if all the non-internet connected devices are malicious the *remote*
//! adversary (who set the code of the malicious device) will not know the secret key. In fact,
//! the adversary would have to recover `t` devices and extract their internal state to
//! reconstruct the key. This is nice, because *in theory* and in this limited sense it gives the
//! attacker no advantage from controlling the code of the signing devices (anyone who wants to
//! reconstruct the key already needs `t` shares).
//!
//! ## Variants
//!
//! The spec comes in three variants. Most applications want [`certpedpop`].
//!
//! - [`simplepedpop`]: bare-bones FROST key generation. The application is responsible
//! for transporting per-receiver secret shares out-of-band and for confirming all parties
//! agree on the result.
//! - [`encpedpop`]: adds share encryption so the coordinator can aggregate encrypted shares
//! into a single message. The application still has to confirm agreement.
//! - [`certpedpop`]: adds certification, so once the protocol completes every party holds a
//! cryptographic proof that everyone else certified the same result.
//!
//! ## Lifecycle
//!
//! Each layer follows the same pipeline:
//!
//! 1. Each contributor calls `Contributor::gen_keygen_input` and sends the resulting
//! `KeygenInput` to the coordinator.
//! 2. The coordinator collects inputs via `Coordinator::add_input`/`finish` and broadcasts
//! the resulting `AggKeygenInput` back.
//! 3. Each contributor calls `verify_agg_input` to obtain a `VerifiedAggKeygenInput`.
//! Receivers also extract their secret share at this step. In `certpedpop`, a
//! certificate from every party must be collected before the share is released.
//!
//! ## Roles
//!
//! Use [`ShareReceiver`] (a contributor that also receives a share) or [`AuxContributor`]
//! (a contributor-only party, e.g. an internet-connected coordinator) as the type
//! parameter `R` on the layered `Contributor<R>` types. Pick the role with turbofish at
//! the call site, e.g.
//! `Contributor::<ShareReceiver>::gen_keygen_input(...)`.
//!
//! [ChillDKG]: https://github.com/BlockstreamResearch/bip-frost-dkg
// Re-export CertificationScheme trait from certpedpop
pub use CertificationScheme;
/// The role a contributor plays in the protocol. Implemented by
/// [`ShareReceiver`] and [`AuxContributor`]; sealed so no other types can.
///
/// Picked via turbofish on `Contributor<R>::gen_keygen_input` at every layer.
/// A contributor that also receives a secret share. The main case: a participant
/// (e.g. a hardware wallet) that contributes entropy and gets a share back.
;
/// A contributor that does not receive a share. The main case: an
/// internet-connected coordinator that contributes entropy so a remote attacker
/// who controls every receiver still cannot reconstruct the key without
/// physical access to `t` devices.
;
/// Identifies a contributor by role-relative index. Use this anywhere the API
/// asks for a party — the absolute slot translation is the protocol's job.
///
/// `Receiver(i)` is the receiver at slot `i` (`i < n_receivers`).
/// `AuxContributor(i)` is the aux at offset `i` (`i < n_aux_contributors`).
/// Ordering matches absolute slot order: every `Receiver` precedes every
/// `AuxContributor`, and within each variant the inner index orders.