1#![allow(unused_assignments)]
4
5use alloc::{
6 collections::BTreeMap,
7 fmt::{self, Debug},
8 string::ToString,
9 vec::Vec,
10};
11
12use derive_getters::Getters;
13#[cfg(any(test, feature = "test-impl"))]
14use hex::FromHex;
15
16use rand_core::{CryptoRng, RngCore};
17use zeroize::{Zeroize, ZeroizeOnDrop};
18
19use crate::{
20 serialization::{SerializableElement, SerializableScalar},
21 Ciphersuite, Element, Error, Field, Group, Header,
22};
23
24#[cfg(feature = "serialization")]
25use crate::serialization::{Deserialize, Serialize};
26
27use super::{keys::SigningShare, Identifier};
28
29#[derive(Clone, Copy, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
33#[cfg_attr(feature = "serde", serde(transparent))]
34pub struct Nonce<C: Ciphersuite>(pub(super) SerializableScalar<C>);
35
36impl<C> Nonce<C>
37where
38 C: Ciphersuite,
39{
40 pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
50 where
51 R: CryptoRng + RngCore,
52 {
53 let mut random_bytes = [0; 32];
54 rng.fill_bytes(&mut random_bytes[..]);
55
56 Self::nonce_generate_from_random_bytes(secret, random_bytes)
57 }
58
59 #[cfg_attr(feature = "internals", visibility::make(pub))]
61 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
62 fn from_scalar(scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar) -> Self {
63 Self(SerializableScalar(scalar))
64 }
65
66 #[cfg_attr(feature = "internals", visibility::make(pub))]
68 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
69 pub(crate) fn to_scalar(
70 self,
71 ) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
72 self.0 .0
73 }
74
75 pub(crate) fn nonce_generate_from_random_bytes(
78 secret: &SigningShare<C>,
79 random_bytes: [u8; 32],
80 ) -> Self {
81 let secret_enc = secret.0.serialize();
82
83 let input: Vec<u8> = random_bytes
84 .iter()
85 .chain(secret_enc.iter())
86 .cloned()
87 .collect();
88
89 Self::from_scalar(C::H3(input.as_slice()))
90 }
91
92 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
94 Ok(Self(SerializableScalar::deserialize(bytes)?))
95 }
96
97 pub fn serialize(&self) -> Vec<u8> {
99 self.0.serialize()
100 }
101}
102
103impl<C> Zeroize for Nonce<C>
104where
105 C: Ciphersuite,
106{
107 fn zeroize(&mut self) {
108 *self = Nonce::from_scalar(<<C::Group as Group>::Field>::zero());
109 }
110}
111
112#[cfg(any(test, feature = "test-impl"))]
113impl<C> FromHex for Nonce<C>
114where
115 C: Ciphersuite,
116{
117 type Error = &'static str;
118
119 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
120 let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
121 Self::deserialize(&v).map_err(|_| "malformed nonce encoding")
122 }
123}
124
125#[derive(Clone, Copy, PartialEq, Eq)]
127#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
128#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
129pub struct NonceCommitment<C: Ciphersuite>(pub(super) SerializableElement<C>);
130
131impl<C> NonceCommitment<C>
132where
133 C: Ciphersuite,
134{
135 #[cfg_attr(feature = "internals", visibility::make(pub))]
137 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
138 pub(crate) fn new(value: Element<C>) -> Self {
139 Self(SerializableElement(value))
140 }
141
142 #[cfg_attr(feature = "internals", visibility::make(pub))]
144 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
145 pub(crate) fn value(&self) -> Element<C> {
146 self.0 .0
147 }
148
149 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
151 Ok(Self(SerializableElement::deserialize(bytes)?))
152 }
153
154 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
156 self.0.serialize()
157 }
158}
159
160impl<C> Debug for NonceCommitment<C>
161where
162 C: Ciphersuite,
163{
164 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165 f.debug_tuple("NonceCommitment")
166 .field(
167 &self
168 .serialize()
169 .map(hex::encode)
170 .unwrap_or("<invalid>".to_string()),
171 )
172 .finish()
173 }
174}
175
176impl<C> From<Nonce<C>> for NonceCommitment<C>
177where
178 C: Ciphersuite,
179{
180 fn from(nonce: Nonce<C>) -> Self {
181 From::from(&nonce)
182 }
183}
184
185impl<C> From<&Nonce<C>> for NonceCommitment<C>
186where
187 C: Ciphersuite,
188{
189 fn from(nonce: &Nonce<C>) -> Self {
190 Self::new(<C::Group>::generator() * nonce.to_scalar())
191 }
192}
193
194#[cfg(any(test, feature = "test-impl"))]
195impl<C> FromHex for NonceCommitment<C>
196where
197 C: Ciphersuite,
198{
199 type Error = &'static str;
200
201 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
202 let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
203 Self::deserialize(&v).map_err(|_| "malformed nonce commitment encoding")
204 }
205}
206
207#[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq, Getters)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
214#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
215#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
216pub struct SigningNonces<C: Ciphersuite> {
217 #[getter(skip)]
219 pub(crate) header: Header<C>,
220 pub(crate) hiding: Nonce<C>,
222 pub(crate) binding: Nonce<C>,
224 #[zeroize(skip)]
229 pub(crate) commitments: SigningCommitments<C>,
230}
231
232impl<C> SigningNonces<C>
233where
234 C: Ciphersuite,
235{
236 pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
241 where
242 R: CryptoRng + RngCore,
243 {
244 let hiding = Nonce::<C>::new(secret, rng);
245 let binding = Nonce::<C>::new(secret, rng);
246
247 Self::from_nonces(hiding, binding)
248 }
249
250 pub fn from_nonces(hiding: Nonce<C>, binding: Nonce<C>) -> Self {
258 let hiding_commitment = (&hiding).into();
259 let binding_commitment = (&binding).into();
260 let commitments = SigningCommitments::new(hiding_commitment, binding_commitment);
261
262 Self {
263 header: Header::default(),
264 hiding,
265 binding,
266 commitments,
267 }
268 }
269}
270
271impl<C> Debug for SigningNonces<C>
272where
273 C: Ciphersuite,
274{
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 f.debug_struct("SigningNonces")
277 .field("hiding", &"<redacted>")
278 .field("binding", &"<redacted>")
279 .finish()
280 }
281}
282
283#[cfg(feature = "serialization")]
284impl<C> SigningNonces<C>
285where
286 C: Ciphersuite,
287{
288 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
290 Serialize::serialize(&self)
291 }
292
293 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
295 Deserialize::deserialize(bytes)
296 }
297}
298
299#[derive(Copy, Clone, Debug, Eq, PartialEq, Getters)]
304#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
305#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
306#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
307pub struct SigningCommitments<C: Ciphersuite> {
308 #[getter(skip)]
310 pub(crate) header: Header<C>,
311 pub(crate) hiding: NonceCommitment<C>,
313 pub(crate) binding: NonceCommitment<C>,
315}
316
317impl<C> SigningCommitments<C>
318where
319 C: Ciphersuite,
320{
321 pub fn new(hiding: NonceCommitment<C>, binding: NonceCommitment<C>) -> Self {
323 Self {
324 header: Header::default(),
325 hiding,
326 binding,
327 }
328 }
329
330 #[cfg_attr(feature = "internals", visibility::make(pub))]
334 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
335 pub(super) fn to_group_commitment_share(
336 self,
337 binding_factor: &crate::BindingFactor<C>,
338 ) -> GroupCommitmentShare<C> {
339 GroupCommitmentShare::<C>(self.hiding.value() + (self.binding.value() * binding_factor.0))
340 }
341}
342
343#[cfg(feature = "serialization")]
344impl<C> SigningCommitments<C>
345where
346 C: Ciphersuite,
347{
348 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
350 Serialize::serialize(&self)
351 }
352
353 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
355 Deserialize::deserialize(bytes)
356 }
357}
358
359impl<C> From<&SigningNonces<C>> for SigningCommitments<C>
360where
361 C: Ciphersuite,
362{
363 fn from(nonces: &SigningNonces<C>) -> Self {
364 nonces.commitments
365 }
366}
367
368#[derive(Clone, Copy, PartialEq)]
371pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
372
373impl<C: Ciphersuite> GroupCommitmentShare<C> {
374 #[cfg_attr(feature = "internals", visibility::make(pub))]
376 #[allow(unused)]
377 pub(crate) fn from_element(element: Element<C>) -> Self {
378 Self(element)
379 }
380
381 #[cfg_attr(feature = "internals", visibility::make(pub))]
383 pub(crate) fn to_element(self) -> Element<C> {
384 self.0
385 }
386}
387
388#[cfg_attr(feature = "internals", visibility::make(pub))]
400#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
401pub(super) fn encode_group_commitments<C: Ciphersuite>(
402 signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
403) -> Result<Vec<u8>, Error<C>> {
404 let mut bytes = vec![];
405
406 for (item_identifier, item) in signing_commitments {
407 bytes.extend_from_slice(item_identifier.serialize().as_ref());
408 bytes.extend_from_slice(<C::Group>::serialize(&item.hiding.value())?.as_ref());
409 bytes.extend_from_slice(<C::Group>::serialize(&item.binding.value())?.as_ref());
410 }
411
412 Ok(bytes)
413}
414
415pub fn preprocess<C, R>(
426 num_nonces: u8,
427 secret: &SigningShare<C>,
428 rng: &mut R,
429) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
430where
431 C: Ciphersuite,
432 R: CryptoRng + RngCore,
433{
434 let mut signing_nonces: Vec<SigningNonces<C>> = Vec::with_capacity(num_nonces as usize);
435 let mut signing_commitments: Vec<SigningCommitments<C>> =
436 Vec::with_capacity(num_nonces as usize);
437
438 for _ in 0..num_nonces {
439 let nonces = SigningNonces::new(secret, rng);
440 signing_commitments.push(SigningCommitments::from(&nonces));
441 signing_nonces.push(nonces);
442 }
443
444 (signing_nonces, signing_commitments)
445}
446
447pub fn commit<C, R>(
456 secret: &SigningShare<C>,
457 rng: &mut R,
458) -> (SigningNonces<C>, SigningCommitments<C>)
459where
460 C: Ciphersuite,
461 R: CryptoRng + RngCore,
462{
463 let (mut vec_signing_nonces, mut vec_signing_commitments) = preprocess(1, secret, rng);
464 (
465 vec_signing_nonces.pop().expect("must have 1 element"),
466 vec_signing_commitments.pop().expect("must have 1 element"),
467 )
468}