modular_frost/tests/
nonces.rs1use std::io::{self, Read};
2
3use zeroize::Zeroizing;
4
5use rand_core::{RngCore, CryptoRng, SeedableRng};
6use rand_chacha::ChaCha20Rng;
7
8use transcript::{Transcript, RecommendedTranscript};
9
10use ciphersuite::group::{ff::Field, Group, GroupEncoding};
11
12use crate::{
13 Curve, Participant, ThresholdView, ThresholdKeys, FrostError,
14 algorithm::Algorithm,
15 tests::{key_gen, algorithm_machines, sign},
16};
17
18#[derive(Clone)]
19struct MultiNonce<C: Curve> {
20 transcript: RecommendedTranscript,
21 nonces: Option<Vec<Vec<C::G>>>,
22}
23
24impl<C: Curve> MultiNonce<C> {
25 fn new() -> MultiNonce<C> {
26 MultiNonce {
27 transcript: RecommendedTranscript::new(b"FROST MultiNonce Algorithm Test"),
28 nonces: None,
29 }
30 }
31}
32
33fn nonces<C: Curve>() -> Vec<Vec<C::G>> {
34 vec![
35 vec![C::generator(), C::generator().double()],
36 vec![C::generator(), C::generator() * C::F::from(3), C::generator() * C::F::from(4)],
37 ]
38}
39
40fn verify_nonces<C: Curve>(nonces: &[Vec<C::G>]) {
41 assert_eq!(nonces.len(), 2);
42
43 assert_eq!(nonces[0].len(), 2);
49 assert_eq!(nonces[0][0].double(), nonces[0][1]);
50
51 assert_eq!(nonces[1].len(), 3);
52 assert_eq!(nonces[1][0] * C::F::from(3), nonces[1][1]);
53 assert_eq!(nonces[1][0] * C::F::from(4), nonces[1][2]);
54
55 assert!(nonces[0][0] != nonces[1][0]);
56}
57
58impl<C: Curve> Algorithm<C> for MultiNonce<C> {
59 type Transcript = RecommendedTranscript;
60 type Addendum = ();
61 type Signature = ();
62
63 fn transcript(&mut self) -> &mut Self::Transcript {
64 &mut self.transcript
65 }
66
67 fn nonces(&self) -> Vec<Vec<C::G>> {
68 nonces::<C>()
69 }
70
71 fn preprocess_addendum<R: RngCore + CryptoRng>(&mut self, _: &mut R, _: &ThresholdKeys<C>) {}
72
73 fn read_addendum<R: Read>(&self, _: &mut R) -> io::Result<Self::Addendum> {
74 Ok(())
75 }
76
77 fn process_addendum(
78 &mut self,
79 _: &ThresholdView<C>,
80 _: Participant,
81 (): (),
82 ) -> Result<(), FrostError> {
83 Ok(())
84 }
85
86 fn sign_share(
87 &mut self,
88 _: &ThresholdView<C>,
89 nonce_sums: &[Vec<C::G>],
90 nonces: Vec<Zeroizing<C::F>>,
91 _: &[u8],
92 ) -> C::F {
93 verify_nonces::<C>(nonce_sums);
95
96 assert_eq!(nonces.len(), 2);
98 assert!(nonces[0] != nonces[1]);
99
100 assert!(self.nonces.is_none());
102 self.nonces = Some(nonce_sums.to_vec());
103
104 let mut res = C::F::ZERO;
106
107 for nonce in nonce_sums {
111 self.transcript.domain_separate(b"nonce");
112 for commitment in nonce {
113 self.transcript.append_message(b"commitment", commitment.to_bytes());
114 }
115 }
116 let mut rng = ChaCha20Rng::from_seed(self.transcript.clone().rng_seed(b"weight"));
117
118 for nonce in nonces {
119 res += *nonce * C::F::random(&mut rng);
120 }
121 res
122 }
123
124 #[must_use]
125 fn verify(&self, _: C::G, nonces: &[Vec<C::G>], sum: C::F) -> Option<Self::Signature> {
126 verify_nonces::<C>(nonces);
127 assert_eq!(&self.nonces.clone().unwrap(), nonces);
128
129 let mut res = C::G::identity();
131 let mut rng = ChaCha20Rng::from_seed(self.transcript.clone().rng_seed(b"weight"));
132 for nonce in nonces {
133 res += nonce[0] * C::F::random(&mut rng);
134 }
135 assert_eq!(res, C::generator() * sum);
136
137 Some(())
138 }
139
140 fn verify_share(&self, _: C::G, _: &[Vec<C::G>], _: C::F) -> Result<Vec<(C::F, C::G)>, ()> {
141 panic!("share verification triggered");
142 }
143}
144
145pub fn test_multi_nonce<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
152 let keys = key_gen::<R, C>(&mut *rng);
153 let machines = algorithm_machines(&mut *rng, &MultiNonce::<C>::new(), &keys);
154 sign(&mut *rng, &MultiNonce::<C>::new(), keys.clone(), machines, &[]);
155}