1use core::{marker::PhantomData, fmt::Debug};
2use std::io::{self, Read, Write};
3
4use zeroize::Zeroizing;
5use rand_core::{RngCore, CryptoRng};
6
7use transcript::Transcript;
8
9use crate::{Participant, ThresholdKeys, ThresholdView, Curve, FrostError};
10pub use schnorr::SchnorrSignature;
11
12pub trait WriteAddendum {
14 fn write<W: Write>(&self, writer: &mut W) -> io::Result<()>;
15}
16
17impl WriteAddendum for () {
18 fn write<W: Write>(&self, _: &mut W) -> io::Result<()> {
19 Ok(())
20 }
21}
22
23pub trait Addendum: Send + Sync + Clone + PartialEq + Debug + WriteAddendum {}
25impl<A: Send + Sync + Clone + PartialEq + Debug + WriteAddendum> Addendum for A {}
26
27pub trait Algorithm<C: Curve>: Send + Sync + Clone {
29 type Transcript: Sync + Clone + Debug + Transcript;
32 type Addendum: Addendum;
34 type Signature: Clone + PartialEq + Debug;
36
37 fn transcript(&mut self) -> &mut Self::Transcript;
39
40 fn nonces(&self) -> Vec<Vec<C::G>>;
43
44 fn preprocess_addendum<R: RngCore + CryptoRng>(
46 &mut self,
47 rng: &mut R,
48 keys: &ThresholdKeys<C>,
49 ) -> Self::Addendum;
50
51 fn read_addendum<R: Read>(&self, reader: &mut R) -> io::Result<Self::Addendum>;
53
54 fn process_addendum(
56 &mut self,
57 params: &ThresholdView<C>,
58 l: Participant,
59 reader: Self::Addendum,
60 ) -> Result<(), FrostError>;
61
62 fn sign_share(
67 &mut self,
68 params: &ThresholdView<C>,
69 nonce_sums: &[Vec<C::G>],
70 nonces: Vec<Zeroizing<C::F>>,
71 msg: &[u8],
72 ) -> C::F;
73
74 #[must_use]
76 fn verify(&self, group_key: C::G, nonces: &[Vec<C::G>], sum: C::F) -> Option<Self::Signature>;
77
78 #[allow(clippy::type_complexity, clippy::result_unit_err)]
82 fn verify_share(
83 &self,
84 verification_share: C::G,
85 nonces: &[Vec<C::G>],
86 share: C::F,
87 ) -> Result<Vec<(C::F, C::G)>, ()>;
88}
89
90mod sealed {
91 pub use super::*;
92
93 #[derive(Clone, Debug)]
96 pub struct IetfTranscript(pub(crate) Vec<u8>);
97 impl Transcript for IetfTranscript {
98 type Challenge = Vec<u8>;
99
100 fn new(_: &'static [u8]) -> IetfTranscript {
101 IetfTranscript(vec![])
102 }
103
104 fn domain_separate(&mut self, _: &[u8]) {}
105
106 fn append_message<M: AsRef<[u8]>>(&mut self, _: &'static [u8], message: M) {
107 self.0.extend(message.as_ref());
108 }
109
110 fn challenge(&mut self, _: &'static [u8]) -> Vec<u8> {
111 self.0.clone()
112 }
113
114 fn rng_seed(&mut self, _: &'static [u8]) -> [u8; 32] {
116 unimplemented!()
117 }
118 }
119}
120pub(crate) use sealed::IetfTranscript;
121
122pub trait Hram<C: Curve>: Send + Sync + Clone {
124 #[allow(non_snake_case)]
127 fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F;
128}
129
130#[derive(Clone)]
132pub struct Schnorr<C: Curve, T: Sync + Clone + Debug + Transcript, H: Hram<C>> {
133 transcript: T,
134 c: Option<C::F>,
135 _hram: PhantomData<H>,
136}
137
138pub type IetfSchnorr<C, H> = Schnorr<C, IetfTranscript, H>;
147
148impl<C: Curve, T: Sync + Clone + Debug + Transcript, H: Hram<C>> Schnorr<C, T, H> {
149 pub fn new(transcript: T) -> Schnorr<C, T, H> {
151 Schnorr { transcript, c: None, _hram: PhantomData }
152 }
153}
154
155impl<C: Curve, H: Hram<C>> IetfSchnorr<C, H> {
156 pub fn ietf() -> IetfSchnorr<C, H> {
160 Schnorr::new(IetfTranscript(vec![]))
161 }
162}
163
164impl<C: Curve, T: Sync + Clone + Debug + Transcript, H: Hram<C>> Algorithm<C> for Schnorr<C, T, H> {
165 type Transcript = T;
166 type Addendum = ();
167 type Signature = SchnorrSignature<C>;
168
169 fn transcript(&mut self) -> &mut Self::Transcript {
170 &mut self.transcript
171 }
172
173 fn nonces(&self) -> Vec<Vec<C::G>> {
174 vec![vec![C::generator()]]
175 }
176
177 fn preprocess_addendum<R: RngCore + CryptoRng>(&mut self, _: &mut R, _: &ThresholdKeys<C>) {}
178
179 fn read_addendum<R: Read>(&self, _: &mut R) -> io::Result<Self::Addendum> {
180 Ok(())
181 }
182
183 fn process_addendum(
184 &mut self,
185 _: &ThresholdView<C>,
186 _: Participant,
187 _: (),
188 ) -> Result<(), FrostError> {
189 Ok(())
190 }
191
192 fn sign_share(
193 &mut self,
194 params: &ThresholdView<C>,
195 nonce_sums: &[Vec<C::G>],
196 mut nonces: Vec<Zeroizing<C::F>>,
197 msg: &[u8],
198 ) -> C::F {
199 let c = H::hram(&nonce_sums[0][0], ¶ms.group_key(), msg);
200 self.c = Some(c);
201 SchnorrSignature::<C>::sign(params.secret_share(), nonces.swap_remove(0), c).s
202 }
203
204 #[must_use]
205 fn verify(&self, group_key: C::G, nonces: &[Vec<C::G>], sum: C::F) -> Option<Self::Signature> {
206 let sig = SchnorrSignature { R: nonces[0][0], s: sum };
207 Some(sig).filter(|sig| sig.verify(group_key, self.c.unwrap()))
208 }
209
210 fn verify_share(
211 &self,
212 verification_share: C::G,
213 nonces: &[Vec<C::G>],
214 share: C::F,
215 ) -> Result<Vec<(C::F, C::G)>, ()> {
216 Ok(
217 SchnorrSignature::<C> { R: nonces[0][0], s: share }
218 .batch_statements(verification_share, self.c.unwrap())
219 .to_vec(),
220 )
221 }
222}