1use bytes::{Buf, BufMut};
4use commonware_codec::{
5 EncodeSize, FixedSize as _, RangeCfg, Read, ReadExt as _, Write, varint::UInt,
6};
7use commonware_consensus::types::Epoch;
8use commonware_cryptography::{
9 Signer as _, Verifier as _,
10 bls12381::primitives::{group, poly::Public, variant::MinSig},
11 ed25519::{PrivateKey, PublicKey, Signature},
12};
13use commonware_utils::{quorum, set::Ordered};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Ack {
22 player: PublicKey,
24 signature: Signature,
27}
28
29impl Ack {
30 pub fn new(
32 namespace: &[u8],
33 signer: PrivateKey,
34 player: PublicKey,
35 epoch: Epoch,
36 dealer: &PublicKey,
37 commitment: &Public<MinSig>,
38 ) -> Self {
39 let payload = Self::construct_signature_payload(epoch, dealer, commitment);
40 let signature = signer.sign(Some(namespace), &payload);
41 Self { player, signature }
42 }
43
44 fn construct_signature_payload(
45 epoch: Epoch,
46 dealer: &PublicKey,
47 commitment: &Public<MinSig>,
48 ) -> Vec<u8> {
49 let mut payload =
50 Vec::with_capacity(Epoch::SIZE + PublicKey::SIZE + commitment.encode_size());
51 epoch.write(&mut payload);
52 dealer.write(&mut payload);
53 commitment.write(&mut payload);
54 payload
55 }
56
57 pub fn verify(
58 &self,
59 namespace: &[u8],
60 public_key: &PublicKey,
61 epoch: Epoch,
62 dealer: &PublicKey,
63 commitment: &Public<MinSig>,
64 ) -> bool {
65 let payload = Self::construct_signature_payload(epoch, dealer, commitment);
66 public_key.verify(Some(namespace), &payload, &self.signature)
67 }
68
69 pub fn player(&self) -> &PublicKey {
70 &self.player
71 }
72}
73
74impl Write for Ack {
75 fn write(&self, buf: &mut impl BufMut) {
76 self.player.write(buf);
77 self.signature.write(buf);
78 }
79}
80
81impl EncodeSize for Ack {
82 fn encode_size(&self) -> usize {
83 self.player.encode_size() + self.signature.encode_size()
84 }
85}
86
87impl Read for Ack {
88 type Cfg = ();
89
90 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
91 Ok(Self {
92 player: PublicKey::read(buf)?,
93 signature: Signature::read(buf)?,
94 })
95 }
96}
97
98#[derive(Clone, Debug, PartialEq, Eq)]
102pub struct PublicOutcome {
103 pub epoch: Epoch,
104 pub participants: Ordered<PublicKey>,
105 pub public: Public<MinSig>,
106}
107
108impl Write for PublicOutcome {
109 fn write(&self, buf: &mut impl BufMut) {
110 UInt(self.epoch).write(buf);
111 self.participants.write(buf);
112 self.public.write(buf);
113 }
114}
115
116impl Read for PublicOutcome {
117 type Cfg = ();
118
119 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
120 let epoch = UInt::read(buf)?.into();
121 let max_participants: usize = u16::MAX.into();
122 let participants = Ordered::read_cfg(buf, &(RangeCfg::from(1..=max_participants), ()))?;
123 let public =
124 Public::<MinSig>::read_cfg(buf, &(quorum(participants.len() as u32) as usize))?;
125 Ok(Self {
126 epoch,
127 participants,
128 public,
129 })
130 }
131}
132
133impl EncodeSize for PublicOutcome {
134 fn encode_size(&self) -> usize {
135 UInt(self.epoch).encode_size() + self.participants.encode_size() + self.public.encode_size()
136 }
137}
138
139#[derive(Clone, Debug, PartialEq, Eq)]
148pub struct IntermediateOutcome {
149 n_players: u16,
151
152 dealer: PublicKey,
154
155 dealer_signature: Signature,
157
158 epoch: Epoch,
160
161 commitment: Public<MinSig>,
163
164 acks: Vec<Ack>,
166
167 reveals: Vec<group::Share>,
169}
170
171impl IntermediateOutcome {
172 pub fn new(
181 n_players: u16,
182 dealer_signer: &PrivateKey,
183 namespace: &[u8],
184 epoch: Epoch,
185 commitment: Public<MinSig>,
186 acks: Vec<Ack>,
187 reveals: Vec<group::Share>,
188 ) -> Self {
189 let payload =
191 Self::signature_payload_from_parts(n_players, epoch, &commitment, &acks, &reveals);
192 let dealer_signature = dealer_signer.sign(Some(namespace), payload.as_ref());
193
194 Self {
195 n_players,
196 dealer: dealer_signer.public_key(),
197 dealer_signature,
198 epoch,
199 commitment,
200 acks,
201 reveals,
202 }
203 }
204
205 pub fn new_pre_allegretto(
219 n_players: u16,
220 dealer_signer: &PrivateKey,
221 namespace: &[u8],
222 epoch: Epoch,
223 commitment: Public<MinSig>,
224 acks: Vec<Ack>,
225 reveals: Vec<group::Share>,
226 ) -> Self {
227 let payload =
229 Self::signature_payload_from_parts_pre_allegretto(epoch, &commitment, &acks, &reveals);
230 let dealer_signature = dealer_signer.sign(Some(namespace), payload.as_ref());
231
232 Self {
233 n_players,
234 dealer: dealer_signer.public_key(),
235 dealer_signature,
236 epoch,
237 commitment,
238 acks,
239 reveals,
240 }
241 }
242
243 pub fn verify(&self, namespace: &[u8]) -> bool {
245 let payload = Self::signature_payload_from_parts(
246 self.n_players,
247 self.epoch,
248 &self.commitment,
249 &self.acks,
250 &self.reveals,
251 );
252 self.dealer
253 .verify(Some(namespace), &payload, &self.dealer_signature)
254 }
255
256 pub fn verify_pre_allegretto(&self, namespace: &[u8]) -> bool {
263 let payload = Self::signature_payload_from_parts_pre_allegretto(
264 self.epoch,
265 &self.commitment,
266 &self.acks,
267 &self.reveals,
268 );
269 self.dealer
270 .verify(Some(namespace), &payload, &self.dealer_signature)
271 }
272
273 fn signature_payload_from_parts(
275 n_players: u16,
276 epoch: Epoch,
277 commitment: &Public<MinSig>,
278 acks: &Vec<Ack>,
279 reveals: &Vec<group::Share>,
280 ) -> Vec<u8> {
281 let mut buf = Vec::with_capacity(
282 UInt(n_players).encode_size()
283 + UInt(epoch).encode_size()
284 + commitment.encode_size()
285 + acks.encode_size()
286 + reveals.encode_size(),
287 );
288 UInt(n_players).write(&mut buf);
289 UInt(epoch).write(&mut buf);
290 commitment.write(&mut buf);
291 acks.write(&mut buf);
292 reveals.write(&mut buf);
293 buf
294 }
295
296 fn signature_payload_from_parts_pre_allegretto(
303 epoch: Epoch,
304 commitment: &Public<MinSig>,
305 acks: &Vec<Ack>,
306 reveals: &Vec<group::Share>,
307 ) -> Vec<u8> {
308 let mut buf = Vec::with_capacity(
309 UInt(epoch).encode_size()
310 + commitment.encode_size()
311 + acks.encode_size()
312 + reveals.encode_size(),
313 );
314 UInt(epoch).write(&mut buf);
315 commitment.write(&mut buf);
316 acks.write(&mut buf);
317 reveals.write(&mut buf);
318 buf
319 }
320
321 pub fn acks(&self) -> &[Ack] {
322 &self.acks
323 }
324
325 pub fn dealer(&self) -> &PublicKey {
326 &self.dealer
327 }
328
329 pub fn signature(&self) -> &Signature {
330 &self.dealer_signature
331 }
332
333 pub fn epoch(&self) -> Epoch {
334 self.epoch
335 }
336
337 pub fn commitment(&self) -> &Public<MinSig> {
338 &self.commitment
339 }
340
341 pub fn reveals(&self) -> &[group::Share] {
342 &self.reveals
343 }
344}
345
346impl Write for IntermediateOutcome {
347 fn write(&self, buf: &mut impl bytes::BufMut) {
348 UInt(self.n_players).write(buf);
349 self.dealer.write(buf);
350 self.dealer_signature.write(buf);
351 UInt(self.epoch).write(buf);
352 self.commitment.write(buf);
353 self.acks.write(buf);
354 self.reveals.write(buf);
355 }
356}
357
358impl EncodeSize for IntermediateOutcome {
359 fn encode_size(&self) -> usize {
360 UInt(self.n_players).encode_size()
361 + self.dealer.encode_size()
362 + self.dealer_signature.encode_size()
363 + UInt(self.epoch).encode_size()
364 + self.commitment.encode_size()
365 + self.acks.encode_size()
366 + self.reveals.encode_size()
367 }
368}
369
370impl Read for IntermediateOutcome {
371 type Cfg = ();
372
373 fn read_cfg(
374 buf: &mut impl bytes::Buf,
375 _cfg: &Self::Cfg,
376 ) -> Result<Self, commonware_codec::Error> {
377 let n_players: u16 = UInt::read(buf)?.into();
378
379 if n_players == 0 {
381 return Err(commonware_codec::Error::Invalid(
382 "n_players",
383 "cannot be zero",
384 ));
385 }
386
387 let dealer = PublicKey::read(buf)?;
388 let dealer_signature = Signature::read(buf)?;
389 let epoch = UInt::read(buf)?.into();
390 let commitment = Public::<MinSig>::read_cfg(buf, &(quorum(n_players as u32) as usize))?;
391
392 let acks = Vec::read_cfg(buf, &(RangeCfg::from(0..=n_players as usize), ()))?;
393 let reveals =
394 Vec::<group::Share>::read_cfg(buf, &(RangeCfg::from(0..=n_players as usize), ()))?;
395
396 Ok(Self {
397 n_players,
398 dealer,
399 dealer_signature,
400 epoch,
401 commitment,
402 acks,
403 reveals,
404 })
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use commonware_codec::{DecodeExt as _, Encode as _};
411 use commonware_cryptography::{
412 PrivateKeyExt as _, Signer as _,
413 bls12381::{dkg, primitives::variant::MinSig},
414 ed25519::{PrivateKey, PublicKey},
415 };
416 use commonware_utils::{set::Ordered, union};
417 use rand::{SeedableRng as _, rngs::StdRng};
418
419 const ACK_NAMESPACE: &[u8] = b"_DKG_ACK";
420 const OUTCOME_NAMESPACE: &[u8] = b"_DKG_OUTCOME";
421
422 use crate::{Ack, PublicOutcome};
423
424 use super::IntermediateOutcome;
425
426 fn four_private_keys() -> Ordered<PrivateKey> {
427 vec![
428 PrivateKey::from_seed(0),
429 PrivateKey::from_seed(1),
430 PrivateKey::from_seed(2),
431 PrivateKey::from_seed(3),
432 ]
433 .into()
434 }
435
436 fn four_public_keys() -> Ordered<PublicKey> {
437 vec![
438 PrivateKey::from_seed(0).public_key(),
439 PrivateKey::from_seed(1).public_key(),
440 PrivateKey::from_seed(2).public_key(),
441 PrivateKey::from_seed(3).public_key(),
442 ]
443 .into()
444 }
445
446 #[test]
447 fn dealing_outcome_roundtrip() {
448 let (_, commitment, shares) = dkg::Dealer::<_, MinSig>::new(
449 &mut StdRng::from_seed([0; 32]),
450 None,
451 four_public_keys(),
452 );
453
454 let acks = vec![
455 Ack::new(
456 &union(b"test", ACK_NAMESPACE),
457 four_private_keys()[0].clone(),
458 four_public_keys()[0].clone(),
459 42,
460 &four_public_keys()[0],
461 &commitment,
462 ),
463 Ack::new(
464 &union(b"test", ACK_NAMESPACE),
465 four_private_keys()[1].clone(),
466 four_public_keys()[1].clone(),
467 42,
468 &four_public_keys()[0],
469 &commitment,
470 ),
471 Ack::new(
472 &union(b"test", ACK_NAMESPACE),
473 four_private_keys()[2].clone(),
474 four_public_keys()[2].clone(),
475 42,
476 &four_public_keys()[0],
477 &commitment,
478 ),
479 ];
480 let reveals = vec![shares[3].clone()];
481 let dealing_outcome = IntermediateOutcome::new(
482 4,
483 &four_private_keys()[0],
484 &union(b"test", OUTCOME_NAMESPACE),
485 42,
486 commitment,
487 acks,
488 reveals,
489 );
490
491 let bytes = dealing_outcome.encode();
492 assert_eq!(
493 IntermediateOutcome::decode(&mut bytes.as_ref()).unwrap(),
494 dealing_outcome,
495 );
496 }
497
498 #[test]
499 fn dealing_outcome_roundtrip_without_reveals() {
500 let (_, commitment, _) = dkg::Dealer::<_, MinSig>::new(
501 &mut StdRng::from_seed([0; 32]),
502 None,
503 four_public_keys(),
504 );
505
506 let acks = vec![
507 Ack::new(
508 &union(b"test", ACK_NAMESPACE),
509 four_private_keys()[0].clone(),
510 four_public_keys()[0].clone(),
511 42,
512 &four_public_keys()[0],
513 &commitment,
514 ),
515 Ack::new(
516 &union(b"test", ACK_NAMESPACE),
517 four_private_keys()[1].clone(),
518 four_public_keys()[1].clone(),
519 42,
520 &four_public_keys()[0],
521 &commitment,
522 ),
523 Ack::new(
524 &union(b"test", ACK_NAMESPACE),
525 four_private_keys()[2].clone(),
526 four_public_keys()[2].clone(),
527 42,
528 &four_public_keys()[0],
529 &commitment,
530 ),
531 Ack::new(
532 &union(b"test", ACK_NAMESPACE),
533 four_private_keys()[3].clone(),
534 four_public_keys()[3].clone(),
535 42,
536 &four_public_keys()[0],
537 &commitment,
538 ),
539 ];
540 let reveals = vec![];
541 let dealing_outcome = IntermediateOutcome::new(
542 4,
543 &four_private_keys()[0],
544 &union(b"test", OUTCOME_NAMESPACE),
545 42,
546 commitment,
547 acks,
548 reveals,
549 );
550
551 let bytes = dealing_outcome.encode();
552 assert_eq!(
553 IntermediateOutcome::decode(&mut bytes.as_ref()).unwrap(),
554 dealing_outcome,
555 );
556 }
557
558 #[test]
559 fn public_outcome_roundtrip() {
560 let (_, commitment, _) = dkg::Dealer::<_, MinSig>::new(
561 &mut StdRng::from_seed([0; 32]),
562 None,
563 four_public_keys(),
564 );
565 let public_outcome = PublicOutcome {
566 epoch: 42,
567 participants: four_public_keys(),
568 public: commitment,
569 };
570 let bytes = public_outcome.encode();
571 assert_eq!(
572 PublicOutcome::decode(&mut bytes.as_ref()).unwrap(),
573 public_outcome,
574 );
575 }
576}