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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! frostito — threshold Schnorr for custodial groups.
//!
//! Distributed key generation, FROST signing, nested FROST, and proactive
//! resharing, over ristretto255, Pallas, secp256k1 and decaf377.
//!
//! # What is here, and what is not
//!
//! The signing math is being rooted in ZF [`frost-core`], which implements
//! RFC 9591 and has been audited. What this crate adds is the part frost-core
//! deliberately leaves to the caller:
//!
//! - [`sealed`] — confidential, authenticated DKG round 2 over Noise_K.
//! `frost_core::keys::dkg::part2` requires the caller to supply that
//! channel and provides none.
//! - [`dkg`] — an echo round over the round-1 set, so an equivocating dealer
//! cannot hand two participants different commitments, plus signed,
//! ceremony-bound complaints and a quorum-gated tally.
//! - [`reshare`] — dealerless rotation to a *different* committee with a
//! *different* threshold, group key preserved. `frost_core::keys::refresh`
//! is trusted-dealer, cannot grow the set, and cannot change the threshold.
//! - [`nested`] — one outer FROST position held distributively by an inner
//! group, the outer share never materialized as a scalar.
//!
//! [`frost-core`]: https://github.com/ZcashFoundation/frost
//!
//! # Curve backends
//!
//! `ristretto255` (default), `pallas` (including the Orchard spend-auth
//! group), `secp256k1`, `decaf377`. ZF ships FROST ciphersuites for the first
//! three; [`zf`] supplies the fourth.
//!
//! # Caller obligations
//!
//! Three things this crate cannot do for you, each of which has been got
//! wrong in practice: reliable broadcast (the echo round compares digests, it
//! does not deliver them), agreement on complaints across nodes, and durable
//! spent-nonce state. See the module docs for each.
extern crate alloc;
pub
pub use ;
pub use ;
pub use Error;
pub use compute_lagrange_coefficients;
/// Sample a uniform scalar for any backend curve, from a `rand_core` 0.6 RNG.
///
/// Sugar over [`CurveScalar::random`] for callers that would otherwise
/// hand-roll nonce sampling. Reach for it when a backend's own `Field::random`
/// is out of reach: the pallas backend rides on `ff` 0.14 (Zakura Common 1.0),
/// which moved `Field::random` onto rand_core 0.10's `Rng` trait, so a
/// rand_core 0.6 `OsRng` cannot call it. This crate keeps its whole public API
/// on rand_core 0.6 and samples by wide reduction internally; external callers
/// should use this rather than re-deriving that bridge and risking a different
/// distribution.
///
/// ```ignore
/// use frostito::random_scalar;
/// use pasta_curves::pallas::Scalar;
///
/// let nonce: Scalar = random_scalar(&mut rand_core::OsRng);
/// ```
/// A secret share from DKG
///
/// # Security
///
/// This struct holds secret key material. It implements `ZeroizeOnDrop`
/// to ensure the scalar is zeroed when the share goes out of scope.