1use core::{ops::Deref, fmt::Debug};
2use std::{
3 io::{self, Read, Write},
4 collections::HashMap,
5};
6
7use rand_core::{RngCore, CryptoRng, SeedableRng};
8use rand_chacha::ChaCha20Rng;
9
10use zeroize::{Zeroize, Zeroizing};
11
12use transcript::Transcript;
13
14use ciphersuite::group::{
15 ff::{Field, PrimeField},
16 GroupEncoding,
17};
18use multiexp::BatchVerifier;
19
20use crate::{
21 curve::Curve,
22 Participant, FrostError, ThresholdParams, ThresholdKeys, ThresholdView,
23 algorithm::{WriteAddendum, Addendum, Algorithm},
24 validate_map,
25};
26
27pub(crate) use crate::nonce::*;
28
29pub trait Writable {
31 fn write<W: Write>(&self, writer: &mut W) -> io::Result<()>;
32
33 fn serialize(&self) -> Vec<u8> {
34 let mut buf = vec![];
35 self.write(&mut buf).unwrap();
36 buf
37 }
38}
39
40impl<T: Writable> Writable for Vec<T> {
41 fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
42 for w in self {
43 w.write(writer)?;
44 }
45 Ok(())
46 }
47}
48
49#[derive(Clone, Zeroize)]
51struct Params<C: Curve, A: Algorithm<C>> {
52 #[zeroize(skip)]
54 algorithm: A,
55 keys: ThresholdKeys<C>,
56}
57
58impl<C: Curve, A: Algorithm<C>> Params<C, A> {
59 fn new(algorithm: A, keys: ThresholdKeys<C>) -> Params<C, A> {
60 Params { algorithm, keys }
61 }
62
63 fn multisig_params(&self) -> ThresholdParams {
64 self.keys.params()
65 }
66}
67
68#[derive(Clone, PartialEq, Eq)]
70pub struct Preprocess<C: Curve, A: Addendum> {
71 pub(crate) commitments: Commitments<C>,
72 pub addendum: A,
74}
75
76impl<C: Curve, A: Addendum> Writable for Preprocess<C, A> {
77 fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
78 self.commitments.write(writer)?;
79 self.addendum.write(writer)
80 }
81}
82
83#[derive(Zeroize)]
92pub struct CachedPreprocess(pub Zeroizing<[u8; 32]>);
93
94pub trait PreprocessMachine: Send {
96 type Preprocess: Clone + PartialEq + Writable;
98 type Signature: Clone + PartialEq + Debug;
100 type SignMachine: SignMachine<Self::Signature, Preprocess = Self::Preprocess>;
102
103 fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R)
107 -> (Self::SignMachine, Self::Preprocess);
108}
109
110pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
112 params: Params<C, A>,
113}
114
115impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> {
116 pub fn new(algorithm: A, keys: ThresholdKeys<C>) -> AlgorithmMachine<C, A> {
118 AlgorithmMachine { params: Params::new(algorithm, keys) }
119 }
120
121 fn seeded_preprocess(
122 self,
123 seed: CachedPreprocess,
124 ) -> (AlgorithmSignMachine<C, A>, Preprocess<C, A::Addendum>) {
125 let mut params = self.params;
126
127 let mut rng = ChaCha20Rng::from_seed(*seed.0);
128 let (nonces, commitments) =
129 Commitments::new::<_>(&mut rng, params.keys.secret_share(), ¶ms.algorithm.nonces());
130 let addendum = params.algorithm.preprocess_addendum(&mut rng, ¶ms.keys);
131
132 let preprocess = Preprocess { commitments, addendum };
133
134 let mut blame_entropy = [0; 32];
136 rng.fill_bytes(&mut blame_entropy);
137 (
138 AlgorithmSignMachine { params, seed, nonces, preprocess: preprocess.clone(), blame_entropy },
139 preprocess,
140 )
141 }
142
143 #[cfg(any(test, feature = "tests"))]
144 pub(crate) fn unsafe_override_preprocess(
145 self,
146 nonces: Vec<Nonce<C>>,
147 preprocess: Preprocess<C, A::Addendum>,
148 ) -> AlgorithmSignMachine<C, A> {
149 AlgorithmSignMachine {
150 params: self.params,
151 seed: CachedPreprocess(Zeroizing::new([0; 32])),
152
153 nonces,
154 preprocess,
155 blame_entropy: [0; 32],
159 }
160 }
161}
162
163impl<C: Curve, A: Algorithm<C>> PreprocessMachine for AlgorithmMachine<C, A> {
164 type Preprocess = Preprocess<C, A::Addendum>;
165 type Signature = A::Signature;
166 type SignMachine = AlgorithmSignMachine<C, A>;
167
168 fn preprocess<R: RngCore + CryptoRng>(
169 self,
170 rng: &mut R,
171 ) -> (Self::SignMachine, Preprocess<C, A::Addendum>) {
172 let mut seed = CachedPreprocess(Zeroizing::new([0; 32]));
173 rng.fill_bytes(seed.0.as_mut());
174 self.seeded_preprocess(seed)
175 }
176}
177
178#[derive(Clone, PartialEq, Eq)]
180pub struct SignatureShare<C: Curve>(C::F);
181impl<C: Curve> Writable for SignatureShare<C> {
182 fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
183 writer.write_all(self.0.to_repr().as_ref())
184 }
185}
186#[cfg(any(test, feature = "tests"))]
187impl<C: Curve> SignatureShare<C> {
188 pub(crate) fn invalidate(&mut self) {
189 self.0 += C::F::ONE;
190 }
191}
192
193pub trait SignMachine<S>: Send + Sync + Sized {
195 type Params: Clone;
197 type Keys;
199 type Preprocess: Clone + PartialEq + Writable;
201 type SignatureShare: Clone + PartialEq + Writable;
203 type SignatureMachine: SignatureMachine<S, SignatureShare = Self::SignatureShare>;
205
206 fn cache(self) -> CachedPreprocess;
211
212 fn from_cache(
217 params: Self::Params,
218 keys: Self::Keys,
219 cache: CachedPreprocess,
220 ) -> (Self, Self::Preprocess);
221
222 fn read_preprocess<R: Read>(&self, reader: &mut R) -> io::Result<Self::Preprocess>;
225
226 fn sign(
231 self,
232 commitments: HashMap<Participant, Self::Preprocess>,
233 msg: &[u8],
234 ) -> Result<(Self::SignatureMachine, Self::SignatureShare), FrostError>;
235}
236
237#[derive(Zeroize)]
239pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
240 params: Params<C, A>,
241 seed: CachedPreprocess,
242
243 pub(crate) nonces: Vec<Nonce<C>>,
244 #[zeroize(skip)]
246 pub(crate) preprocess: Preprocess<C, A::Addendum>,
247 pub(crate) blame_entropy: [u8; 32],
248}
249
250impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachine<C, A> {
251 type Params = A;
252 type Keys = ThresholdKeys<C>;
253 type Preprocess = Preprocess<C, A::Addendum>;
254 type SignatureShare = SignatureShare<C>;
255 type SignatureMachine = AlgorithmSignatureMachine<C, A>;
256
257 fn cache(self) -> CachedPreprocess {
258 self.seed
259 }
260
261 fn from_cache(
262 algorithm: A,
263 keys: ThresholdKeys<C>,
264 cache: CachedPreprocess,
265 ) -> (Self, Self::Preprocess) {
266 AlgorithmMachine::new(algorithm, keys).seeded_preprocess(cache)
267 }
268
269 fn read_preprocess<R: Read>(&self, reader: &mut R) -> io::Result<Self::Preprocess> {
270 Ok(Preprocess {
271 commitments: Commitments::read::<_>(reader, &self.params.algorithm.nonces())?,
272 addendum: self.params.algorithm.read_addendum(reader)?,
273 })
274 }
275
276 fn sign(
277 mut self,
278 mut preprocesses: HashMap<Participant, Preprocess<C, A::Addendum>>,
279 msg: &[u8],
280 ) -> Result<(Self::SignatureMachine, SignatureShare<C>), FrostError> {
281 let multisig_params = self.params.multisig_params();
282
283 let mut included = Vec::with_capacity(preprocesses.len() + 1);
284 included.push(multisig_params.i());
285 for l in preprocesses.keys() {
286 included.push(*l);
287 }
288 included.sort_unstable();
289
290 if included.len() < usize::from(multisig_params.t()) {
292 Err(FrostError::InvalidSigningSet("not enough signers"))?;
293 }
294 if u16::from(included[included.len() - 1]) > multisig_params.n() {
296 Err(FrostError::InvalidParticipant(multisig_params.n(), included[included.len() - 1]))?;
297 }
298 for i in 0 .. (included.len() - 1) {
300 if included[i] == included[i + 1] {
301 Err(FrostError::DuplicatedParticipant(included[i]))?;
302 }
303 }
304
305 let view = self.params.keys.view(included.clone()).unwrap();
306 validate_map(&preprocesses, &included, multisig_params.i())?;
307
308 {
309 self.params.algorithm.transcript().domain_separate(b"FROST");
311 }
312
313 let nonces = self.params.algorithm.nonces();
314 #[allow(non_snake_case)]
315 let mut B = BindingFactor(HashMap::<Participant, _>::with_capacity(included.len()));
316 {
317 for l in &included {
319 {
320 self
321 .params
322 .algorithm
323 .transcript()
324 .append_message(b"participant", C::F::from(u64::from(u16::from(*l))).to_repr());
325 }
326
327 if *l == self.params.keys.params().i() {
328 let commitments = self.preprocess.commitments.clone();
329 commitments.transcript(self.params.algorithm.transcript());
330
331 let addendum = self.preprocess.addendum.clone();
332 {
333 let mut buf = vec![];
334 addendum.write(&mut buf).unwrap();
335 self.params.algorithm.transcript().append_message(b"addendum", buf);
336 }
337
338 B.insert(*l, commitments);
339 self.params.algorithm.process_addendum(&view, *l, addendum)?;
340 } else {
341 let preprocess = preprocesses.remove(l).unwrap();
342 preprocess.commitments.transcript(self.params.algorithm.transcript());
343 {
344 let mut buf = vec![];
345 preprocess.addendum.write(&mut buf).unwrap();
346 self.params.algorithm.transcript().append_message(b"addendum", buf);
347 }
348
349 B.insert(*l, preprocess.commitments);
350 self.params.algorithm.process_addendum(&view, *l, preprocess.addendum)?;
351 }
352 }
353
354 let mut rho_transcript = A::Transcript::new(b"FROST_rho");
356 rho_transcript.append_message(
357 b"group_key",
358 (self.params.keys.group_key() +
359 (C::generator() * self.params.keys.current_offset().unwrap_or(C::F::ZERO)))
360 .to_bytes(),
361 );
362 rho_transcript.append_message(b"message", C::hash_msg(msg));
363 rho_transcript.append_message(
364 b"preprocesses",
365 C::hash_commitments(self.params.algorithm.transcript().challenge(b"preprocesses").as_ref()),
366 );
367
368 B.calculate_binding_factors(&rho_transcript);
370
371 self
374 .params
375 .algorithm
376 .transcript()
377 .append_message(b"rho_transcript", rho_transcript.challenge(b"merge"));
378 }
379
380 #[allow(non_snake_case)]
381 let Rs = B.nonces(&nonces);
382
383 let our_binding_factors = B.binding_factors(multisig_params.i());
384 let nonces = self
385 .nonces
386 .drain(..)
387 .enumerate()
388 .map(|(n, nonces)| {
389 let [base, mut actual] = nonces.0;
390 *actual *= our_binding_factors[n];
391 *actual += base.deref();
392 actual
393 })
394 .collect::<Vec<_>>();
395
396 let share = self.params.algorithm.sign_share(&view, &Rs, nonces, msg);
397
398 Ok((
399 AlgorithmSignatureMachine {
400 params: self.params.clone(),
401 view,
402 B,
403 Rs,
404 share,
405 blame_entropy: self.blame_entropy,
406 },
407 SignatureShare(share),
408 ))
409 }
410}
411
412pub trait SignatureMachine<S>: Send + Sync {
414 type SignatureShare: Clone + PartialEq + Writable;
416
417 fn read_share<R: Read>(&self, reader: &mut R) -> io::Result<Self::SignatureShare>;
419
420 fn complete(self, shares: HashMap<Participant, Self::SignatureShare>) -> Result<S, FrostError>;
423}
424
425#[allow(non_snake_case)]
429pub struct AlgorithmSignatureMachine<C: Curve, A: Algorithm<C>> {
430 params: Params<C, A>,
431 view: ThresholdView<C>,
432 B: BindingFactor<C>,
433 Rs: Vec<Vec<C::G>>,
434 share: C::F,
435 blame_entropy: [u8; 32],
436}
437
438impl<C: Curve, A: Algorithm<C>> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
439 type SignatureShare = SignatureShare<C>;
440
441 fn read_share<R: Read>(&self, reader: &mut R) -> io::Result<SignatureShare<C>> {
442 Ok(SignatureShare(C::read_F(reader)?))
443 }
444
445 fn complete(
446 self,
447 mut shares: HashMap<Participant, SignatureShare<C>>,
448 ) -> Result<A::Signature, FrostError> {
449 let params = self.params.multisig_params();
450 validate_map(&shares, self.view.included(), params.i())?;
451
452 let mut responses = HashMap::new();
453 responses.insert(params.i(), self.share);
454 let mut sum = self.share;
455 for (l, share) in shares.drain() {
456 responses.insert(l, share.0);
457 sum += share.0;
458 }
459
460 if let Some(sig) = self.params.algorithm.verify(self.view.group_key(), &self.Rs, sum) {
464 return Ok(sig);
465 }
466
467 let mut rng = ChaCha20Rng::from_seed(self.blame_entropy);
472 let mut batch = BatchVerifier::new(self.view.included().len());
473 for l in self.view.included() {
474 if let Ok(statements) = self.params.algorithm.verify_share(
475 self.view.verification_share(*l),
476 &self.B.bound(*l),
477 responses[l],
478 ) {
479 batch.queue(&mut rng, *l, statements);
480 } else {
481 Err(FrostError::InvalidShare(*l))?;
482 }
483 }
484
485 if let Err(l) = batch.verify_vartime_with_vartime_blame() {
486 Err(FrostError::InvalidShare(l))?;
487 }
488
489 Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid"))
493 }
494}