1use crate::{
4 simplex::scheme,
5 types::{Epoch, Round, View},
6 Epochable, Viewable,
7};
8use bytes::{Buf, BufMut};
9use commonware_codec::{varint::UInt, EncodeSize, Error, Read, ReadExt, ReadRangeExt, Write};
10use commonware_cryptography::{
11 certificate::{Attestation, Scheme},
12 Digest, PublicKey,
13};
14use rand::{CryptoRng, Rng};
15use std::{collections::HashSet, fmt::Debug, hash::Hash};
16
17#[derive(Clone, Debug)]
20pub struct Context<D: Digest, P: PublicKey> {
21 pub round: Round,
23 pub leader: P,
25 pub parent: (View, D),
32}
33
34impl<D: Digest, P: PublicKey> Epochable for Context<D, P> {
35 fn epoch(&self) -> Epoch {
36 self.round.epoch()
37 }
38}
39
40impl<D: Digest, P: PublicKey> Viewable for Context<D, P> {
41 fn view(&self) -> View {
42 self.round.view()
43 }
44}
45
46pub trait Attributable {
49 fn signer(&self) -> u32;
51}
52
53pub struct AttributableMap<T: Attributable> {
58 data: Vec<Option<T>>,
59 added: usize,
60}
61
62impl<T: Attributable> AttributableMap<T> {
63 pub fn new(participants: usize) -> Self {
65 let mut data = Vec::with_capacity(participants);
67 data.resize_with(participants, || None);
68
69 Self { data, added: 0 }
70 }
71
72 pub fn clear(&mut self) {
74 self.data.fill_with(|| None);
75 self.added = 0;
76 }
77
78 pub fn insert(&mut self, item: T) -> bool {
84 let index = item.signer() as usize;
85 if index >= self.data.len() {
86 return false;
87 }
88 if self.data[index].is_some() {
89 return false;
90 }
91 self.data[index] = Some(item);
92 self.added += 1;
93 true
94 }
95
96 pub const fn len(&self) -> usize {
98 self.added
99 }
100
101 pub const fn is_empty(&self) -> bool {
103 self.added == 0
104 }
105
106 pub fn get(&self, signer: u32) -> Option<&T> {
108 self.data.get(signer as usize)?.as_ref()
109 }
110
111 pub fn iter(&self) -> impl Iterator<Item = &T> {
114 self.data.iter().filter_map(|o| o.as_ref())
115 }
116}
117
118pub struct VoteTracker<S: Scheme, D: Digest> {
124 notarizes: AttributableMap<Notarize<S, D>>,
126 nullifies: AttributableMap<Nullify<S>>,
128 finalizes: AttributableMap<Finalize<S, D>>,
133}
134
135impl<S: Scheme, D: Digest> VoteTracker<S, D> {
136 pub fn new(participants: usize) -> Self {
138 Self {
139 notarizes: AttributableMap::new(participants),
140 nullifies: AttributableMap::new(participants),
141 finalizes: AttributableMap::new(participants),
142 }
143 }
144
145 pub fn insert_notarize(&mut self, vote: Notarize<S, D>) -> bool {
147 self.notarizes.insert(vote)
148 }
149
150 pub fn insert_nullify(&mut self, vote: Nullify<S>) -> bool {
152 self.nullifies.insert(vote)
153 }
154
155 pub fn insert_finalize(&mut self, vote: Finalize<S, D>) -> bool {
157 self.finalizes.insert(vote)
158 }
159
160 pub fn notarize(&self, signer: u32) -> Option<&Notarize<S, D>> {
162 self.notarizes.get(signer)
163 }
164
165 pub fn nullify(&self, signer: u32) -> Option<&Nullify<S>> {
167 self.nullifies.get(signer)
168 }
169
170 pub fn finalize(&self, signer: u32) -> Option<&Finalize<S, D>> {
172 self.finalizes.get(signer)
173 }
174
175 pub fn iter_notarizes(&self) -> impl Iterator<Item = &Notarize<S, D>> {
177 self.notarizes.iter()
178 }
179
180 pub fn iter_nullifies(&self) -> impl Iterator<Item = &Nullify<S>> {
182 self.nullifies.iter()
183 }
184
185 pub fn iter_finalizes(&self) -> impl Iterator<Item = &Finalize<S, D>> {
187 self.finalizes.iter()
188 }
189
190 pub fn len_notarizes(&self) -> u32 {
192 u32::try_from(self.notarizes.len()).expect("too many notarize votes")
193 }
194
195 pub fn len_nullifies(&self) -> u32 {
197 u32::try_from(self.nullifies.len()).expect("too many nullify votes")
198 }
199
200 pub fn len_finalizes(&self) -> u32 {
202 u32::try_from(self.finalizes.len()).expect("too many finalize votes")
203 }
204
205 pub fn has_notarize(&self, signer: u32) -> bool {
207 self.notarize(signer).is_some()
208 }
209
210 pub fn has_nullify(&self, signer: u32) -> bool {
212 self.nullify(signer).is_some()
213 }
214
215 pub fn has_finalize(&self, signer: u32) -> bool {
217 self.finalize(signer).is_some()
218 }
219
220 pub fn clear_notarizes(&mut self) {
222 self.notarizes.clear();
223 }
224
225 pub fn clear_finalizes(&mut self) {
227 self.finalizes.clear();
228 }
229}
230
231#[derive(Copy, Clone, Debug)]
236pub enum Subject<'a, D: Digest> {
237 Notarize { proposal: &'a Proposal<D> },
239 Nullify { round: Round },
241 Finalize { proposal: &'a Proposal<D> },
243}
244
245impl<D: Digest> Viewable for Subject<'_, D> {
246 fn view(&self) -> View {
247 match self {
248 Subject::Notarize { proposal } => proposal.view(),
249 Subject::Nullify { round } => round.view(),
250 Subject::Finalize { proposal } => proposal.view(),
251 }
252 }
253}
254
255#[derive(Clone, Debug, PartialEq)]
257pub enum Vote<S: Scheme, D: Digest> {
258 Notarize(Notarize<S, D>),
260 Nullify(Nullify<S>),
262 Finalize(Finalize<S, D>),
264}
265
266impl<S: Scheme, D: Digest> Write for Vote<S, D> {
267 fn write(&self, writer: &mut impl BufMut) {
268 match self {
269 Self::Notarize(v) => {
270 0u8.write(writer);
271 v.write(writer);
272 }
273 Self::Nullify(v) => {
274 1u8.write(writer);
275 v.write(writer);
276 }
277 Self::Finalize(v) => {
278 2u8.write(writer);
279 v.write(writer);
280 }
281 }
282 }
283}
284
285impl<S: Scheme, D: Digest> EncodeSize for Vote<S, D> {
286 fn encode_size(&self) -> usize {
287 1 + match self {
288 Self::Notarize(v) => v.encode_size(),
289 Self::Nullify(v) => v.encode_size(),
290 Self::Finalize(v) => v.encode_size(),
291 }
292 }
293}
294
295impl<S: Scheme, D: Digest> Read for Vote<S, D> {
296 type Cfg = ();
297
298 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
299 let tag = <u8>::read(reader)?;
300 match tag {
301 0 => {
302 let v = Notarize::read(reader)?;
303 Ok(Self::Notarize(v))
304 }
305 1 => {
306 let v = Nullify::read(reader)?;
307 Ok(Self::Nullify(v))
308 }
309 2 => {
310 let v = Finalize::read(reader)?;
311 Ok(Self::Finalize(v))
312 }
313 _ => Err(Error::Invalid("consensus::simplex::Vote", "Invalid type")),
314 }
315 }
316}
317
318impl<S: Scheme, D: Digest> Epochable for Vote<S, D> {
319 fn epoch(&self) -> Epoch {
320 match self {
321 Self::Notarize(v) => v.epoch(),
322 Self::Nullify(v) => v.epoch(),
323 Self::Finalize(v) => v.epoch(),
324 }
325 }
326}
327
328impl<S: Scheme, D: Digest> Viewable for Vote<S, D> {
329 fn view(&self) -> View {
330 match self {
331 Self::Notarize(v) => v.view(),
332 Self::Nullify(v) => v.view(),
333 Self::Finalize(v) => v.view(),
334 }
335 }
336}
337
338#[cfg(feature = "arbitrary")]
339impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Vote<S, D>
340where
341 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
342 D: for<'a> arbitrary::Arbitrary<'a>,
343{
344 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
345 let tag = u.int_in_range(0..=2)?;
346 match tag {
347 0 => {
348 let v = Notarize::arbitrary(u)?;
349 Ok(Self::Notarize(v))
350 }
351 1 => {
352 let v = Nullify::arbitrary(u)?;
353 Ok(Self::Nullify(v))
354 }
355 2 => {
356 let v = Finalize::arbitrary(u)?;
357 Ok(Self::Finalize(v))
358 }
359 _ => unreachable!(),
360 }
361 }
362}
363
364#[derive(Clone, Debug, PartialEq)]
366pub enum Certificate<S: Scheme, D: Digest> {
367 Notarization(Notarization<S, D>),
369 Nullification(Nullification<S>),
371 Finalization(Finalization<S, D>),
373}
374
375impl<S: Scheme, D: Digest> Write for Certificate<S, D> {
376 fn write(&self, writer: &mut impl BufMut) {
377 match self {
378 Self::Notarization(v) => {
379 0u8.write(writer);
380 v.write(writer);
381 }
382 Self::Nullification(v) => {
383 1u8.write(writer);
384 v.write(writer);
385 }
386 Self::Finalization(v) => {
387 2u8.write(writer);
388 v.write(writer);
389 }
390 }
391 }
392}
393
394impl<S: Scheme, D: Digest> EncodeSize for Certificate<S, D> {
395 fn encode_size(&self) -> usize {
396 1 + match self {
397 Self::Notarization(v) => v.encode_size(),
398 Self::Nullification(v) => v.encode_size(),
399 Self::Finalization(v) => v.encode_size(),
400 }
401 }
402}
403
404impl<S: Scheme, D: Digest> Read for Certificate<S, D> {
405 type Cfg = <S::Certificate as Read>::Cfg;
406
407 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
408 let tag = <u8>::read(reader)?;
409 match tag {
410 0 => {
411 let v = Notarization::read_cfg(reader, cfg)?;
412 Ok(Self::Notarization(v))
413 }
414 1 => {
415 let v = Nullification::read_cfg(reader, cfg)?;
416 Ok(Self::Nullification(v))
417 }
418 2 => {
419 let v = Finalization::read_cfg(reader, cfg)?;
420 Ok(Self::Finalization(v))
421 }
422 _ => Err(Error::Invalid(
423 "consensus::simplex::Certificate",
424 "Invalid type",
425 )),
426 }
427 }
428}
429
430impl<S: Scheme, D: Digest> Epochable for Certificate<S, D> {
431 fn epoch(&self) -> Epoch {
432 match self {
433 Self::Notarization(v) => v.epoch(),
434 Self::Nullification(v) => v.epoch(),
435 Self::Finalization(v) => v.epoch(),
436 }
437 }
438}
439
440impl<S: Scheme, D: Digest> Viewable for Certificate<S, D> {
441 fn view(&self) -> View {
442 match self {
443 Self::Notarization(v) => v.view(),
444 Self::Nullification(v) => v.view(),
445 Self::Finalization(v) => v.view(),
446 }
447 }
448}
449
450#[cfg(feature = "arbitrary")]
451impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Certificate<S, D>
452where
453 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
454 D: for<'a> arbitrary::Arbitrary<'a>,
455{
456 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
457 let tag = u.int_in_range(0..=2)?;
458 match tag {
459 0 => {
460 let v = Notarization::arbitrary(u)?;
461 Ok(Self::Notarization(v))
462 }
463 1 => {
464 let v = Nullification::arbitrary(u)?;
465 Ok(Self::Nullification(v))
466 }
467 2 => {
468 let v = Finalization::arbitrary(u)?;
469 Ok(Self::Finalization(v))
470 }
471 _ => unreachable!(),
472 }
473 }
474}
475
476#[derive(Clone, Debug, PartialEq)]
478pub enum Artifact<S: Scheme, D: Digest> {
479 Notarize(Notarize<S, D>),
481 Notarization(Notarization<S, D>),
483 Certification(Round, bool),
485 Nullify(Nullify<S>),
487 Nullification(Nullification<S>),
489 Finalize(Finalize<S, D>),
491 Finalization(Finalization<S, D>),
493}
494
495impl<S: Scheme, D: Digest> Write for Artifact<S, D> {
496 fn write(&self, writer: &mut impl BufMut) {
497 match self {
498 Self::Notarize(v) => {
499 0u8.write(writer);
500 v.write(writer);
501 }
502 Self::Notarization(v) => {
503 1u8.write(writer);
504 v.write(writer);
505 }
506 Self::Certification(r, b) => {
507 2u8.write(writer);
508 r.write(writer);
509 b.write(writer);
510 }
511 Self::Nullify(v) => {
512 3u8.write(writer);
513 v.write(writer);
514 }
515 Self::Nullification(v) => {
516 4u8.write(writer);
517 v.write(writer);
518 }
519 Self::Finalize(v) => {
520 5u8.write(writer);
521 v.write(writer);
522 }
523 Self::Finalization(v) => {
524 6u8.write(writer);
525 v.write(writer);
526 }
527 }
528 }
529}
530
531impl<S: Scheme, D: Digest> EncodeSize for Artifact<S, D> {
532 fn encode_size(&self) -> usize {
533 1 + match self {
534 Self::Notarize(v) => v.encode_size(),
535 Self::Notarization(v) => v.encode_size(),
536 Self::Certification(r, b) => r.encode_size() + b.encode_size(),
537 Self::Nullify(v) => v.encode_size(),
538 Self::Nullification(v) => v.encode_size(),
539 Self::Finalize(v) => v.encode_size(),
540 Self::Finalization(v) => v.encode_size(),
541 }
542 }
543}
544
545impl<S: Scheme, D: Digest> Read for Artifact<S, D> {
546 type Cfg = <S::Certificate as Read>::Cfg;
547
548 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
549 let tag = <u8>::read(reader)?;
550 match tag {
551 0 => {
552 let v = Notarize::read(reader)?;
553 Ok(Self::Notarize(v))
554 }
555 1 => {
556 let v = Notarization::read_cfg(reader, cfg)?;
557 Ok(Self::Notarization(v))
558 }
559 2 => {
560 let r = Round::read(reader)?;
561 let b = bool::read(reader)?;
562 Ok(Self::Certification(r, b))
563 }
564 3 => {
565 let v = Nullify::read(reader)?;
566 Ok(Self::Nullify(v))
567 }
568 4 => {
569 let v = Nullification::read_cfg(reader, cfg)?;
570 Ok(Self::Nullification(v))
571 }
572 5 => {
573 let v = Finalize::read(reader)?;
574 Ok(Self::Finalize(v))
575 }
576 6 => {
577 let v = Finalization::read_cfg(reader, cfg)?;
578 Ok(Self::Finalization(v))
579 }
580 _ => Err(Error::Invalid(
581 "consensus::simplex::Artifact",
582 "Invalid type",
583 )),
584 }
585 }
586}
587
588impl<S: Scheme, D: Digest> Epochable for Artifact<S, D> {
589 fn epoch(&self) -> Epoch {
590 match self {
591 Self::Notarize(v) => v.epoch(),
592 Self::Notarization(v) => v.epoch(),
593 Self::Certification(r, _) => r.epoch(),
594 Self::Nullify(v) => v.epoch(),
595 Self::Nullification(v) => v.epoch(),
596 Self::Finalize(v) => v.epoch(),
597 Self::Finalization(v) => v.epoch(),
598 }
599 }
600}
601
602impl<S: Scheme, D: Digest> Viewable for Artifact<S, D> {
603 fn view(&self) -> View {
604 match self {
605 Self::Notarize(v) => v.view(),
606 Self::Notarization(v) => v.view(),
607 Self::Certification(r, _) => r.view(),
608 Self::Nullify(v) => v.view(),
609 Self::Nullification(v) => v.view(),
610 Self::Finalize(v) => v.view(),
611 Self::Finalization(v) => v.view(),
612 }
613 }
614}
615
616impl<S: Scheme, D: Digest> From<Vote<S, D>> for Artifact<S, D> {
617 fn from(vote: Vote<S, D>) -> Self {
618 match vote {
619 Vote::Notarize(v) => Self::Notarize(v),
620 Vote::Nullify(v) => Self::Nullify(v),
621 Vote::Finalize(v) => Self::Finalize(v),
622 }
623 }
624}
625
626impl<S: Scheme, D: Digest> From<Certificate<S, D>> for Artifact<S, D> {
627 fn from(cert: Certificate<S, D>) -> Self {
628 match cert {
629 Certificate::Notarization(v) => Self::Notarization(v),
630 Certificate::Nullification(v) => Self::Nullification(v),
631 Certificate::Finalization(v) => Self::Finalization(v),
632 }
633 }
634}
635
636#[cfg(feature = "arbitrary")]
637impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Artifact<S, D>
638where
639 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
640 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
641 D: for<'a> arbitrary::Arbitrary<'a>,
642{
643 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
644 let tag = u.int_in_range(0..=6)?;
645 match tag {
646 0 => {
647 let v = Notarize::arbitrary(u)?;
648 Ok(Self::Notarize(v))
649 }
650 1 => {
651 let v = Notarization::arbitrary(u)?;
652 Ok(Self::Notarization(v))
653 }
654 2 => {
655 let r = Round::arbitrary(u)?;
656 let b = bool::arbitrary(u)?;
657 Ok(Self::Certification(r, b))
658 }
659 3 => {
660 let v = Nullify::arbitrary(u)?;
661 Ok(Self::Nullify(v))
662 }
663 4 => {
664 let v = Nullification::arbitrary(u)?;
665 Ok(Self::Nullification(v))
666 }
667 5 => {
668 let v = Finalize::arbitrary(u)?;
669 Ok(Self::Finalize(v))
670 }
671 6 => {
672 let v = Finalization::arbitrary(u)?;
673 Ok(Self::Finalization(v))
674 }
675 _ => unreachable!(),
676 }
677 }
678}
679
680#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
683pub struct Proposal<D: Digest> {
684 pub round: Round,
686 pub parent: View,
688 pub payload: D,
690}
691
692impl<D: Digest> Proposal<D> {
693 pub const fn new(round: Round, parent: View, payload: D) -> Self {
695 Self {
696 round,
697 parent,
698 payload,
699 }
700 }
701}
702
703impl<D: Digest> Write for Proposal<D> {
704 fn write(&self, writer: &mut impl BufMut) {
705 self.round.write(writer);
706 self.parent.write(writer);
707 self.payload.write(writer)
708 }
709}
710
711impl<D: Digest> Read for Proposal<D> {
712 type Cfg = ();
713
714 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
715 let round = Round::read(reader)?;
716 let parent = View::read(reader)?;
717 let payload = D::read(reader)?;
718 Ok(Self {
719 round,
720 parent,
721 payload,
722 })
723 }
724}
725
726impl<D: Digest> EncodeSize for Proposal<D> {
727 fn encode_size(&self) -> usize {
728 self.round.encode_size() + self.parent.encode_size() + self.payload.encode_size()
729 }
730}
731
732impl<D: Digest> Epochable for Proposal<D> {
733 fn epoch(&self) -> Epoch {
734 self.round.epoch()
735 }
736}
737
738impl<D: Digest> Viewable for Proposal<D> {
739 fn view(&self) -> View {
740 self.round.view()
741 }
742}
743
744#[cfg(feature = "arbitrary")]
745impl<D: Digest> arbitrary::Arbitrary<'_> for Proposal<D>
746where
747 D: for<'a> arbitrary::Arbitrary<'a>,
748{
749 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
750 let round = Round::arbitrary(u)?;
751 let parent = View::arbitrary(u)?;
752 let payload = D::arbitrary(u)?;
753 Ok(Self {
754 round,
755 parent,
756 payload,
757 })
758 }
759}
760
761#[derive(Clone, Debug)]
763pub struct Notarize<S: Scheme, D: Digest> {
764 pub proposal: Proposal<D>,
766 pub attestation: Attestation<S>,
768}
769
770impl<S: Scheme, D: Digest> Notarize<S, D> {
771 pub fn sign(scheme: &S, namespace: &[u8], proposal: Proposal<D>) -> Option<Self>
773 where
774 S: scheme::Scheme<D>,
775 {
776 let attestation = scheme.sign::<D>(
777 namespace,
778 Subject::Notarize {
779 proposal: &proposal,
780 },
781 )?;
782
783 Some(Self {
784 proposal,
785 attestation,
786 })
787 }
788
789 pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool
793 where
794 S: scheme::Scheme<D>,
795 {
796 scheme.verify_attestation::<D>(
797 namespace,
798 Subject::Notarize {
799 proposal: &self.proposal,
800 },
801 &self.attestation,
802 )
803 }
804
805 pub const fn round(&self) -> Round {
807 self.proposal.round
808 }
809}
810
811impl<S: Scheme, D: Digest> PartialEq for Notarize<S, D> {
812 fn eq(&self, other: &Self) -> bool {
813 self.proposal == other.proposal && self.attestation == other.attestation
814 }
815}
816
817impl<S: Scheme, D: Digest> Eq for Notarize<S, D> {}
818
819impl<S: Scheme, D: Digest> Hash for Notarize<S, D> {
820 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
821 self.proposal.hash(state);
822 self.attestation.hash(state);
823 }
824}
825
826impl<S: Scheme, D: Digest> Write for Notarize<S, D> {
827 fn write(&self, writer: &mut impl BufMut) {
828 self.proposal.write(writer);
829 self.attestation.write(writer);
830 }
831}
832
833impl<S: Scheme, D: Digest> EncodeSize for Notarize<S, D> {
834 fn encode_size(&self) -> usize {
835 self.proposal.encode_size() + self.attestation.encode_size()
836 }
837}
838
839impl<S: Scheme, D: Digest> Read for Notarize<S, D> {
840 type Cfg = ();
841
842 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
843 let proposal = Proposal::read(reader)?;
844 let attestation = Attestation::read(reader)?;
845
846 Ok(Self {
847 proposal,
848 attestation,
849 })
850 }
851}
852
853impl<S: Scheme, D: Digest> Attributable for Notarize<S, D> {
854 fn signer(&self) -> u32 {
855 self.attestation.signer
856 }
857}
858
859impl<S: Scheme, D: Digest> Epochable for Notarize<S, D> {
860 fn epoch(&self) -> Epoch {
861 self.proposal.epoch()
862 }
863}
864
865impl<S: Scheme, D: Digest> Viewable for Notarize<S, D> {
866 fn view(&self) -> View {
867 self.proposal.view()
868 }
869}
870
871#[cfg(feature = "arbitrary")]
872impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Notarize<S, D>
873where
874 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
875 D: for<'a> arbitrary::Arbitrary<'a>,
876{
877 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
878 let proposal = Proposal::arbitrary(u)?;
879 let attestation = Attestation::arbitrary(u)?;
880 Ok(Self {
881 proposal,
882 attestation,
883 })
884 }
885}
886
887#[derive(Clone, Debug)]
894pub struct Notarization<S: Scheme, D: Digest> {
895 pub proposal: Proposal<D>,
897 pub certificate: S::Certificate,
899}
900
901impl<S: Scheme, D: Digest> Notarization<S, D> {
902 pub fn from_notarizes<'a>(
904 scheme: &S,
905 notarizes: impl IntoIterator<Item = &'a Notarize<S, D>>,
906 ) -> Option<Self> {
907 let mut iter = notarizes.into_iter().peekable();
908 let proposal = iter.peek()?.proposal.clone();
909 let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()))?;
910
911 Some(Self {
912 proposal,
913 certificate,
914 })
915 }
916
917 pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool
921 where
922 S: scheme::Scheme<D>,
923 {
924 scheme.verify_certificate::<_, D>(
925 rng,
926 namespace,
927 Subject::Notarize {
928 proposal: &self.proposal,
929 },
930 &self.certificate,
931 )
932 }
933
934 pub const fn round(&self) -> Round {
936 self.proposal.round
937 }
938}
939
940impl<S: Scheme, D: Digest> PartialEq for Notarization<S, D> {
941 fn eq(&self, other: &Self) -> bool {
942 self.proposal == other.proposal && self.certificate == other.certificate
943 }
944}
945
946impl<S: Scheme, D: Digest> Eq for Notarization<S, D> {}
947
948impl<S: Scheme, D: Digest> Hash for Notarization<S, D> {
949 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
950 self.proposal.hash(state);
951 self.certificate.hash(state);
952 }
953}
954
955impl<S: Scheme, D: Digest> Write for Notarization<S, D> {
956 fn write(&self, writer: &mut impl BufMut) {
957 self.proposal.write(writer);
958 self.certificate.write(writer);
959 }
960}
961
962impl<S: Scheme, D: Digest> EncodeSize for Notarization<S, D> {
963 fn encode_size(&self) -> usize {
964 self.proposal.encode_size() + self.certificate.encode_size()
965 }
966}
967
968impl<S: Scheme, D: Digest> Read for Notarization<S, D> {
969 type Cfg = <S::Certificate as Read>::Cfg;
970
971 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
972 let proposal = Proposal::read(reader)?;
973 let certificate = S::Certificate::read_cfg(reader, cfg)?;
974
975 Ok(Self {
976 proposal,
977 certificate,
978 })
979 }
980}
981
982impl<S: Scheme, D: Digest> Epochable for Notarization<S, D> {
983 fn epoch(&self) -> Epoch {
984 self.proposal.epoch()
985 }
986}
987
988impl<S: Scheme, D: Digest> Viewable for Notarization<S, D> {
989 fn view(&self) -> View {
990 self.proposal.view()
991 }
992}
993
994#[cfg(feature = "arbitrary")]
995impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Notarization<S, D>
996where
997 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
998 D: for<'a> arbitrary::Arbitrary<'a>,
999{
1000 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1001 let proposal = Proposal::arbitrary(u)?;
1002 let certificate = S::Certificate::arbitrary(u)?;
1003 Ok(Self {
1004 proposal,
1005 certificate,
1006 })
1007 }
1008}
1009
1010#[derive(Clone, Debug)]
1013pub struct Nullify<S: Scheme> {
1014 pub round: Round,
1016 pub attestation: Attestation<S>,
1018}
1019
1020impl<S: Scheme> PartialEq for Nullify<S> {
1021 fn eq(&self, other: &Self) -> bool {
1022 self.round == other.round && self.attestation == other.attestation
1023 }
1024}
1025
1026impl<S: Scheme> Eq for Nullify<S> {}
1027
1028impl<S: Scheme> Hash for Nullify<S> {
1029 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1030 self.round.hash(state);
1031 self.attestation.hash(state);
1032 }
1033}
1034
1035impl<S: Scheme> Nullify<S> {
1036 pub fn sign<D: Digest>(scheme: &S, namespace: &[u8], round: Round) -> Option<Self>
1038 where
1039 S: scheme::Scheme<D>,
1040 {
1041 let attestation = scheme.sign::<D>(namespace, Subject::Nullify { round })?;
1042
1043 Some(Self { round, attestation })
1044 }
1045
1046 pub fn verify<D: Digest>(&self, scheme: &S, namespace: &[u8]) -> bool
1050 where
1051 S: scheme::Scheme<D>,
1052 {
1053 scheme.verify_attestation::<D>(
1054 namespace,
1055 Subject::Nullify { round: self.round },
1056 &self.attestation,
1057 )
1058 }
1059
1060 pub const fn round(&self) -> Round {
1062 self.round
1063 }
1064}
1065
1066impl<S: Scheme> Write for Nullify<S> {
1067 fn write(&self, writer: &mut impl BufMut) {
1068 self.round.write(writer);
1069 self.attestation.write(writer);
1070 }
1071}
1072
1073impl<S: Scheme> EncodeSize for Nullify<S> {
1074 fn encode_size(&self) -> usize {
1075 self.round.encode_size() + self.attestation.encode_size()
1076 }
1077}
1078
1079impl<S: Scheme> Read for Nullify<S> {
1080 type Cfg = ();
1081
1082 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1083 let round = Round::read(reader)?;
1084 let attestation = Attestation::read(reader)?;
1085
1086 Ok(Self { round, attestation })
1087 }
1088}
1089
1090impl<S: Scheme> Attributable for Nullify<S> {
1091 fn signer(&self) -> u32 {
1092 self.attestation.signer
1093 }
1094}
1095
1096impl<S: Scheme> Epochable for Nullify<S> {
1097 fn epoch(&self) -> Epoch {
1098 self.round.epoch()
1099 }
1100}
1101
1102impl<S: Scheme> Viewable for Nullify<S> {
1103 fn view(&self) -> View {
1104 self.round.view()
1105 }
1106}
1107
1108#[cfg(feature = "arbitrary")]
1109impl<S: Scheme> arbitrary::Arbitrary<'_> for Nullify<S>
1110where
1111 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1112{
1113 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1114 let round = Round::arbitrary(u)?;
1115 let attestation = Attestation::arbitrary(u)?;
1116 Ok(Self { round, attestation })
1117 }
1118}
1119
1120#[derive(Clone, Debug)]
1123pub struct Nullification<S: Scheme> {
1124 pub round: Round,
1126 pub certificate: S::Certificate,
1128}
1129
1130impl<S: Scheme> Nullification<S> {
1131 pub fn from_nullifies<'a>(
1133 scheme: &S,
1134 nullifies: impl IntoIterator<Item = &'a Nullify<S>>,
1135 ) -> Option<Self> {
1136 let mut iter = nullifies.into_iter().peekable();
1137 let round = iter.peek()?.round;
1138 let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()))?;
1139
1140 Some(Self { round, certificate })
1141 }
1142
1143 pub fn verify<R: Rng + CryptoRng, D: Digest>(
1147 &self,
1148 rng: &mut R,
1149 scheme: &S,
1150 namespace: &[u8],
1151 ) -> bool
1152 where
1153 S: scheme::Scheme<D>,
1154 {
1155 scheme.verify_certificate::<_, D>(
1156 rng,
1157 namespace,
1158 Subject::Nullify { round: self.round },
1159 &self.certificate,
1160 )
1161 }
1162
1163 pub const fn round(&self) -> Round {
1165 self.round
1166 }
1167}
1168
1169impl<S: Scheme> PartialEq for Nullification<S> {
1170 fn eq(&self, other: &Self) -> bool {
1171 self.round == other.round && self.certificate == other.certificate
1172 }
1173}
1174
1175impl<S: Scheme> Eq for Nullification<S> {}
1176
1177impl<S: Scheme> Hash for Nullification<S> {
1178 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1179 self.round.hash(state);
1180 self.certificate.hash(state);
1181 }
1182}
1183
1184impl<S: Scheme> Write for Nullification<S> {
1185 fn write(&self, writer: &mut impl BufMut) {
1186 self.round.write(writer);
1187 self.certificate.write(writer);
1188 }
1189}
1190
1191impl<S: Scheme> EncodeSize for Nullification<S> {
1192 fn encode_size(&self) -> usize {
1193 self.round.encode_size() + self.certificate.encode_size()
1194 }
1195}
1196
1197impl<S: Scheme> Read for Nullification<S> {
1198 type Cfg = <S::Certificate as Read>::Cfg;
1199
1200 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1201 let round = Round::read(reader)?;
1202 let certificate = S::Certificate::read_cfg(reader, cfg)?;
1203
1204 Ok(Self { round, certificate })
1205 }
1206}
1207
1208impl<S: Scheme> Epochable for Nullification<S> {
1209 fn epoch(&self) -> Epoch {
1210 self.round.epoch()
1211 }
1212}
1213
1214impl<S: Scheme> Viewable for Nullification<S> {
1215 fn view(&self) -> View {
1216 self.round.view()
1217 }
1218}
1219
1220#[cfg(feature = "arbitrary")]
1221impl<S: Scheme> arbitrary::Arbitrary<'_> for Nullification<S>
1222where
1223 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1224{
1225 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1226 let round = Round::arbitrary(u)?;
1227 let certificate = S::Certificate::arbitrary(u)?;
1228 Ok(Self { round, certificate })
1229 }
1230}
1231
1232#[derive(Clone, Debug)]
1236pub struct Finalize<S: Scheme, D: Digest> {
1237 pub proposal: Proposal<D>,
1239 pub attestation: Attestation<S>,
1241}
1242
1243impl<S: Scheme, D: Digest> Finalize<S, D> {
1244 pub fn sign(scheme: &S, namespace: &[u8], proposal: Proposal<D>) -> Option<Self>
1246 where
1247 S: scheme::Scheme<D>,
1248 {
1249 let attestation = scheme.sign::<D>(
1250 namespace,
1251 Subject::Finalize {
1252 proposal: &proposal,
1253 },
1254 )?;
1255
1256 Some(Self {
1257 proposal,
1258 attestation,
1259 })
1260 }
1261
1262 pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool
1266 where
1267 S: scheme::Scheme<D>,
1268 {
1269 scheme.verify_attestation::<D>(
1270 namespace,
1271 Subject::Finalize {
1272 proposal: &self.proposal,
1273 },
1274 &self.attestation,
1275 )
1276 }
1277
1278 pub const fn round(&self) -> Round {
1280 self.proposal.round
1281 }
1282}
1283
1284impl<S: Scheme, D: Digest> PartialEq for Finalize<S, D> {
1285 fn eq(&self, other: &Self) -> bool {
1286 self.proposal == other.proposal && self.attestation == other.attestation
1287 }
1288}
1289
1290impl<S: Scheme, D: Digest> Eq for Finalize<S, D> {}
1291
1292impl<S: Scheme, D: Digest> Hash for Finalize<S, D> {
1293 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1294 self.proposal.hash(state);
1295 self.attestation.hash(state);
1296 }
1297}
1298
1299impl<S: Scheme, D: Digest> Write for Finalize<S, D> {
1300 fn write(&self, writer: &mut impl BufMut) {
1301 self.proposal.write(writer);
1302 self.attestation.write(writer);
1303 }
1304}
1305
1306impl<S: Scheme, D: Digest> EncodeSize for Finalize<S, D> {
1307 fn encode_size(&self) -> usize {
1308 self.proposal.encode_size() + self.attestation.encode_size()
1309 }
1310}
1311
1312impl<S: Scheme, D: Digest> Read for Finalize<S, D> {
1313 type Cfg = ();
1314
1315 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1316 let proposal = Proposal::read(reader)?;
1317 let attestation = Attestation::read(reader)?;
1318
1319 Ok(Self {
1320 proposal,
1321 attestation,
1322 })
1323 }
1324}
1325
1326impl<S: Scheme, D: Digest> Attributable for Finalize<S, D> {
1327 fn signer(&self) -> u32 {
1328 self.attestation.signer
1329 }
1330}
1331
1332impl<S: Scheme, D: Digest> Epochable for Finalize<S, D> {
1333 fn epoch(&self) -> Epoch {
1334 self.proposal.epoch()
1335 }
1336}
1337
1338impl<S: Scheme, D: Digest> Viewable for Finalize<S, D> {
1339 fn view(&self) -> View {
1340 self.proposal.view()
1341 }
1342}
1343
1344#[cfg(feature = "arbitrary")]
1345impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Finalize<S, D>
1346where
1347 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1348 D: for<'a> arbitrary::Arbitrary<'a>,
1349{
1350 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1351 let proposal = Proposal::arbitrary(u)?;
1352 let attestation = Attestation::arbitrary(u)?;
1353 Ok(Self {
1354 proposal,
1355 attestation,
1356 })
1357 }
1358}
1359
1360#[derive(Clone, Debug)]
1367pub struct Finalization<S: Scheme, D: Digest> {
1368 pub proposal: Proposal<D>,
1370 pub certificate: S::Certificate,
1372}
1373
1374impl<S: Scheme, D: Digest> Finalization<S, D> {
1375 pub fn from_finalizes<'a>(
1377 scheme: &S,
1378 finalizes: impl IntoIterator<Item = &'a Finalize<S, D>>,
1379 ) -> Option<Self> {
1380 let mut iter = finalizes.into_iter().peekable();
1381 let proposal = iter.peek()?.proposal.clone();
1382 let certificate = scheme.assemble(iter.map(|f| f.attestation.clone()))?;
1383
1384 Some(Self {
1385 proposal,
1386 certificate,
1387 })
1388 }
1389
1390 pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool
1394 where
1395 S: scheme::Scheme<D>,
1396 {
1397 scheme.verify_certificate::<_, D>(
1398 rng,
1399 namespace,
1400 Subject::Finalize {
1401 proposal: &self.proposal,
1402 },
1403 &self.certificate,
1404 )
1405 }
1406
1407 pub const fn round(&self) -> Round {
1409 self.proposal.round
1410 }
1411}
1412
1413impl<S: Scheme, D: Digest> PartialEq for Finalization<S, D> {
1414 fn eq(&self, other: &Self) -> bool {
1415 self.proposal == other.proposal && self.certificate == other.certificate
1416 }
1417}
1418
1419impl<S: Scheme, D: Digest> Eq for Finalization<S, D> {}
1420
1421impl<S: Scheme, D: Digest> Hash for Finalization<S, D> {
1422 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1423 self.proposal.hash(state);
1424 self.certificate.hash(state);
1425 }
1426}
1427
1428impl<S: Scheme, D: Digest> Write for Finalization<S, D> {
1429 fn write(&self, writer: &mut impl BufMut) {
1430 self.proposal.write(writer);
1431 self.certificate.write(writer);
1432 }
1433}
1434
1435impl<S: Scheme, D: Digest> EncodeSize for Finalization<S, D> {
1436 fn encode_size(&self) -> usize {
1437 self.proposal.encode_size() + self.certificate.encode_size()
1438 }
1439}
1440
1441impl<S: Scheme, D: Digest> Read for Finalization<S, D> {
1442 type Cfg = <S::Certificate as Read>::Cfg;
1443
1444 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1445 let proposal = Proposal::read(reader)?;
1446 let certificate = S::Certificate::read_cfg(reader, cfg)?;
1447
1448 Ok(Self {
1449 proposal,
1450 certificate,
1451 })
1452 }
1453}
1454
1455impl<S: Scheme, D: Digest> Epochable for Finalization<S, D> {
1456 fn epoch(&self) -> Epoch {
1457 self.proposal.epoch()
1458 }
1459}
1460
1461impl<S: Scheme, D: Digest> Viewable for Finalization<S, D> {
1462 fn view(&self) -> View {
1463 self.proposal.view()
1464 }
1465}
1466
1467#[cfg(feature = "arbitrary")]
1468impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Finalization<S, D>
1469where
1470 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1471 D: for<'a> arbitrary::Arbitrary<'a>,
1472{
1473 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1474 let proposal = Proposal::arbitrary(u)?;
1475 let certificate = S::Certificate::arbitrary(u)?;
1476 Ok(Self {
1477 proposal,
1478 certificate,
1479 })
1480 }
1481}
1482
1483#[derive(Clone, Debug, PartialEq)]
1486pub enum Backfiller<S: Scheme, D: Digest> {
1487 Request(Request),
1489 Response(Response<S, D>),
1491}
1492
1493impl<S: Scheme, D: Digest> Write for Backfiller<S, D> {
1494 fn write(&self, writer: &mut impl BufMut) {
1495 match self {
1496 Self::Request(request) => {
1497 0u8.write(writer);
1498 request.write(writer);
1499 }
1500 Self::Response(response) => {
1501 1u8.write(writer);
1502 response.write(writer);
1503 }
1504 }
1505 }
1506}
1507
1508impl<S: Scheme, D: Digest> EncodeSize for Backfiller<S, D> {
1509 fn encode_size(&self) -> usize {
1510 1 + match self {
1511 Self::Request(v) => v.encode_size(),
1512 Self::Response(v) => v.encode_size(),
1513 }
1514 }
1515}
1516
1517impl<S: Scheme, D: Digest> Read for Backfiller<S, D> {
1518 type Cfg = (usize, <S::Certificate as Read>::Cfg);
1519
1520 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1521 let tag = <u8>::read(reader)?;
1522 match tag {
1523 0 => {
1524 let (max_len, _) = cfg;
1525 let v = Request::read_cfg(reader, max_len)?;
1526 Ok(Self::Request(v))
1527 }
1528 1 => {
1529 let v = Response::<S, D>::read_cfg(reader, cfg)?;
1530 Ok(Self::Response(v))
1531 }
1532 _ => Err(Error::Invalid(
1533 "consensus::simplex::Backfiller",
1534 "Invalid type",
1535 )),
1536 }
1537 }
1538}
1539
1540#[cfg(feature = "arbitrary")]
1541impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Backfiller<S, D>
1542where
1543 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1544 D: for<'a> arbitrary::Arbitrary<'a>,
1545{
1546 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1547 let tag = u.int_in_range(0..=1)?;
1548 match tag {
1549 0 => {
1550 let v = Request::arbitrary(u)?;
1551 Ok(Self::Request(v))
1552 }
1553 1 => {
1554 let v = Response::<S, D>::arbitrary(u)?;
1555 Ok(Self::Response(v))
1556 }
1557 _ => unreachable!(),
1558 }
1559 }
1560}
1561
1562#[derive(Clone, Debug, PartialEq)]
1565#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1566pub struct Request {
1567 pub id: u64,
1569 pub notarizations: Vec<View>,
1571 pub nullifications: Vec<View>,
1573}
1574
1575impl Request {
1576 pub const fn new(id: u64, notarizations: Vec<View>, nullifications: Vec<View>) -> Self {
1578 Self {
1579 id,
1580 notarizations,
1581 nullifications,
1582 }
1583 }
1584}
1585
1586impl Write for Request {
1587 fn write(&self, writer: &mut impl BufMut) {
1588 UInt(self.id).write(writer);
1589 self.notarizations.write(writer);
1590 self.nullifications.write(writer);
1591 }
1592}
1593
1594impl EncodeSize for Request {
1595 fn encode_size(&self) -> usize {
1596 UInt(self.id).encode_size()
1597 + self.notarizations.encode_size()
1598 + self.nullifications.encode_size()
1599 }
1600}
1601
1602impl Read for Request {
1603 type Cfg = usize;
1604
1605 fn read_cfg(reader: &mut impl Buf, max_len: &usize) -> Result<Self, Error> {
1606 let id = UInt::read(reader)?.into();
1607 let mut views = HashSet::new();
1608 let notarizations = Vec::<View>::read_range(reader, ..=*max_len)?;
1609 for view in notarizations.iter() {
1610 if !views.insert(view) {
1611 return Err(Error::Invalid(
1612 "consensus::simplex::Request",
1613 "Duplicate notarization",
1614 ));
1615 }
1616 }
1617 let remaining = max_len - notarizations.len();
1618 views.clear();
1619 let nullifications = Vec::<View>::read_range(reader, ..=remaining)?;
1620 for view in nullifications.iter() {
1621 if !views.insert(view) {
1622 return Err(Error::Invalid(
1623 "consensus::simplex::Request",
1624 "Duplicate nullification",
1625 ));
1626 }
1627 }
1628 Ok(Self {
1629 id,
1630 notarizations,
1631 nullifications,
1632 })
1633 }
1634}
1635
1636#[derive(Clone, Debug, PartialEq)]
1639pub struct Response<S: Scheme, D: Digest> {
1640 pub id: u64,
1642 pub notarizations: Vec<Notarization<S, D>>,
1644 pub nullifications: Vec<Nullification<S>>,
1646}
1647
1648impl<S: Scheme, D: Digest> Response<S, D> {
1649 pub const fn new(
1651 id: u64,
1652 notarizations: Vec<Notarization<S, D>>,
1653 nullifications: Vec<Nullification<S>>,
1654 ) -> Self {
1655 Self {
1656 id,
1657 notarizations,
1658 nullifications,
1659 }
1660 }
1661
1662 pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool
1664 where
1665 S: scheme::Scheme<D>,
1666 {
1667 if self.notarizations.is_empty() && self.nullifications.is_empty() {
1669 return true;
1670 }
1671
1672 let notarizations = self.notarizations.iter().map(|notarization| {
1673 let context = Subject::Notarize {
1674 proposal: ¬arization.proposal,
1675 };
1676
1677 (context, ¬arization.certificate)
1678 });
1679
1680 let nullifications = self.nullifications.iter().map(|nullification| {
1681 let context = Subject::Nullify {
1682 round: nullification.round,
1683 };
1684
1685 (context, &nullification.certificate)
1686 });
1687
1688 scheme.verify_certificates::<_, D, _>(rng, namespace, notarizations.chain(nullifications))
1689 }
1690}
1691
1692impl<S: Scheme, D: Digest> Write for Response<S, D> {
1693 fn write(&self, writer: &mut impl BufMut) {
1694 UInt(self.id).write(writer);
1695 self.notarizations.write(writer);
1696 self.nullifications.write(writer);
1697 }
1698}
1699
1700impl<S: Scheme, D: Digest> EncodeSize for Response<S, D> {
1701 fn encode_size(&self) -> usize {
1702 UInt(self.id).encode_size()
1703 + self.notarizations.encode_size()
1704 + self.nullifications.encode_size()
1705 }
1706}
1707
1708impl<S: Scheme, D: Digest> Read for Response<S, D> {
1709 type Cfg = (usize, <S::Certificate as Read>::Cfg);
1710
1711 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1712 let (max_len, certificate_cfg) = cfg;
1713 let id = UInt::read(reader)?.into();
1714 let mut views = HashSet::new();
1715 let notarizations = Vec::<Notarization<S, D>>::read_cfg(
1716 reader,
1717 &((..=*max_len).into(), certificate_cfg.clone()),
1718 )?;
1719 for notarization in notarizations.iter() {
1720 if !views.insert(notarization.view()) {
1721 return Err(Error::Invalid(
1722 "consensus::simplex::Response",
1723 "Duplicate notarization",
1724 ));
1725 }
1726 }
1727 let remaining = max_len - notarizations.len();
1728 views.clear();
1729 let nullifications = Vec::<Nullification<S>>::read_cfg(
1730 reader,
1731 &((..=remaining).into(), certificate_cfg.clone()),
1732 )?;
1733 for nullification in nullifications.iter() {
1734 if !views.insert(nullification.view()) {
1735 return Err(Error::Invalid(
1736 "consensus::simplex::Response",
1737 "Duplicate nullification",
1738 ));
1739 }
1740 }
1741 Ok(Self {
1742 id,
1743 notarizations,
1744 nullifications,
1745 })
1746 }
1747}
1748
1749#[cfg(feature = "arbitrary")]
1750impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Response<S, D>
1751where
1752 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1753 D: for<'a> arbitrary::Arbitrary<'a>,
1754{
1755 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1756 let id = u.arbitrary()?;
1757 let notarizations = u.arbitrary()?;
1758 let nullifications = u.arbitrary()?;
1759 Ok(Self {
1760 id,
1761 notarizations,
1762 nullifications,
1763 })
1764 }
1765}
1766
1767#[derive(Clone, Debug)]
1785pub enum Activity<S: Scheme, D: Digest> {
1786 Notarize(Notarize<S, D>),
1788 Notarization(Notarization<S, D>),
1790 Certification(Notarization<S, D>),
1792 Nullify(Nullify<S>),
1794 Nullification(Nullification<S>),
1796 Finalize(Finalize<S, D>),
1798 Finalization(Finalization<S, D>),
1800 ConflictingNotarize(ConflictingNotarize<S, D>),
1802 ConflictingFinalize(ConflictingFinalize<S, D>),
1804 NullifyFinalize(NullifyFinalize<S, D>),
1806}
1807
1808impl<S: Scheme, D: Digest> PartialEq for Activity<S, D> {
1809 fn eq(&self, other: &Self) -> bool {
1810 match (self, other) {
1811 (Self::Notarize(a), Self::Notarize(b)) => a == b,
1812 (Self::Notarization(a), Self::Notarization(b)) => a == b,
1813 (Self::Certification(a), Self::Certification(b)) => a == b,
1814 (Self::Nullify(a), Self::Nullify(b)) => a == b,
1815 (Self::Nullification(a), Self::Nullification(b)) => a == b,
1816 (Self::Finalize(a), Self::Finalize(b)) => a == b,
1817 (Self::Finalization(a), Self::Finalization(b)) => a == b,
1818 (Self::ConflictingNotarize(a), Self::ConflictingNotarize(b)) => a == b,
1819 (Self::ConflictingFinalize(a), Self::ConflictingFinalize(b)) => a == b,
1820 (Self::NullifyFinalize(a), Self::NullifyFinalize(b)) => a == b,
1821 _ => false,
1822 }
1823 }
1824}
1825
1826impl<S: Scheme, D: Digest> Eq for Activity<S, D> {}
1827
1828impl<S: Scheme, D: Digest> Hash for Activity<S, D> {
1829 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1830 match self {
1831 Self::Notarize(v) => {
1832 0u8.hash(state);
1833 v.hash(state);
1834 }
1835 Self::Notarization(v) => {
1836 1u8.hash(state);
1837 v.hash(state);
1838 }
1839 Self::Certification(v) => {
1840 2u8.hash(state);
1841 v.hash(state);
1842 }
1843 Self::Nullify(v) => {
1844 3u8.hash(state);
1845 v.hash(state);
1846 }
1847 Self::Nullification(v) => {
1848 4u8.hash(state);
1849 v.hash(state);
1850 }
1851 Self::Finalize(v) => {
1852 5u8.hash(state);
1853 v.hash(state);
1854 }
1855 Self::Finalization(v) => {
1856 6u8.hash(state);
1857 v.hash(state);
1858 }
1859 Self::ConflictingNotarize(v) => {
1860 7u8.hash(state);
1861 v.hash(state);
1862 }
1863 Self::ConflictingFinalize(v) => {
1864 8u8.hash(state);
1865 v.hash(state);
1866 }
1867 Self::NullifyFinalize(v) => {
1868 9u8.hash(state);
1869 v.hash(state);
1870 }
1871 }
1872 }
1873}
1874
1875impl<S: Scheme, D: Digest> Activity<S, D> {
1876 pub const fn verified(&self) -> bool {
1878 match self {
1879 Self::Notarize(_) => false,
1880 Self::Notarization(_) => true,
1881 Self::Certification(_) => false,
1882 Self::Nullify(_) => false,
1883 Self::Nullification(_) => true,
1884 Self::Finalize(_) => false,
1885 Self::Finalization(_) => true,
1886 Self::ConflictingNotarize(_) => false,
1887 Self::ConflictingFinalize(_) => false,
1888 Self::NullifyFinalize(_) => false,
1889 }
1890 }
1891
1892 pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool
1898 where
1899 S: scheme::Scheme<D>,
1900 {
1901 match self {
1902 Self::Notarize(n) => n.verify(scheme, namespace),
1903 Self::Notarization(n) => n.verify(rng, scheme, namespace),
1904 Self::Certification(n) => n.verify(rng, scheme, namespace),
1905 Self::Nullify(n) => n.verify(scheme, namespace),
1906 Self::Nullification(n) => n.verify(rng, scheme, namespace),
1907 Self::Finalize(f) => f.verify(scheme, namespace),
1908 Self::Finalization(f) => f.verify(rng, scheme, namespace),
1909 Self::ConflictingNotarize(c) => c.verify(scheme, namespace),
1910 Self::ConflictingFinalize(c) => c.verify(scheme, namespace),
1911 Self::NullifyFinalize(c) => c.verify(scheme, namespace),
1912 }
1913 }
1914}
1915
1916impl<S: Scheme, D: Digest> Write for Activity<S, D> {
1917 fn write(&self, writer: &mut impl BufMut) {
1918 match self {
1919 Self::Notarize(v) => {
1920 0u8.write(writer);
1921 v.write(writer);
1922 }
1923 Self::Notarization(v) => {
1924 1u8.write(writer);
1925 v.write(writer);
1926 }
1927 Self::Certification(v) => {
1928 2u8.write(writer);
1929 v.write(writer);
1930 }
1931 Self::Nullify(v) => {
1932 3u8.write(writer);
1933 v.write(writer);
1934 }
1935 Self::Nullification(v) => {
1936 4u8.write(writer);
1937 v.write(writer);
1938 }
1939 Self::Finalize(v) => {
1940 5u8.write(writer);
1941 v.write(writer);
1942 }
1943 Self::Finalization(v) => {
1944 6u8.write(writer);
1945 v.write(writer);
1946 }
1947 Self::ConflictingNotarize(v) => {
1948 7u8.write(writer);
1949 v.write(writer);
1950 }
1951 Self::ConflictingFinalize(v) => {
1952 8u8.write(writer);
1953 v.write(writer);
1954 }
1955 Self::NullifyFinalize(v) => {
1956 9u8.write(writer);
1957 v.write(writer);
1958 }
1959 }
1960 }
1961}
1962
1963impl<S: Scheme, D: Digest> EncodeSize for Activity<S, D> {
1964 fn encode_size(&self) -> usize {
1965 1 + match self {
1966 Self::Notarize(v) => v.encode_size(),
1967 Self::Notarization(v) => v.encode_size(),
1968 Self::Certification(v) => v.encode_size(),
1969 Self::Nullify(v) => v.encode_size(),
1970 Self::Nullification(v) => v.encode_size(),
1971 Self::Finalize(v) => v.encode_size(),
1972 Self::Finalization(v) => v.encode_size(),
1973 Self::ConflictingNotarize(v) => v.encode_size(),
1974 Self::ConflictingFinalize(v) => v.encode_size(),
1975 Self::NullifyFinalize(v) => v.encode_size(),
1976 }
1977 }
1978}
1979
1980impl<S: Scheme, D: Digest> Read for Activity<S, D> {
1981 type Cfg = <S::Certificate as Read>::Cfg;
1982
1983 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1984 let tag = <u8>::read(reader)?;
1985 match tag {
1986 0 => {
1987 let v = Notarize::<S, D>::read(reader)?;
1988 Ok(Self::Notarize(v))
1989 }
1990 1 => {
1991 let v = Notarization::<S, D>::read_cfg(reader, cfg)?;
1992 Ok(Self::Notarization(v))
1993 }
1994 2 => {
1995 let v = Notarization::<S, D>::read_cfg(reader, cfg)?;
1996 Ok(Self::Certification(v))
1997 }
1998 3 => {
1999 let v = Nullify::<S>::read(reader)?;
2000 Ok(Self::Nullify(v))
2001 }
2002 4 => {
2003 let v = Nullification::<S>::read_cfg(reader, cfg)?;
2004 Ok(Self::Nullification(v))
2005 }
2006 5 => {
2007 let v = Finalize::<S, D>::read(reader)?;
2008 Ok(Self::Finalize(v))
2009 }
2010 6 => {
2011 let v = Finalization::<S, D>::read_cfg(reader, cfg)?;
2012 Ok(Self::Finalization(v))
2013 }
2014 7 => {
2015 let v = ConflictingNotarize::<S, D>::read(reader)?;
2016 Ok(Self::ConflictingNotarize(v))
2017 }
2018 8 => {
2019 let v = ConflictingFinalize::<S, D>::read(reader)?;
2020 Ok(Self::ConflictingFinalize(v))
2021 }
2022 9 => {
2023 let v = NullifyFinalize::<S, D>::read(reader)?;
2024 Ok(Self::NullifyFinalize(v))
2025 }
2026 _ => Err(Error::Invalid(
2027 "consensus::simplex::Activity",
2028 "Invalid type",
2029 )),
2030 }
2031 }
2032}
2033
2034impl<S: Scheme, D: Digest> Epochable for Activity<S, D> {
2035 fn epoch(&self) -> Epoch {
2036 match self {
2037 Self::Notarize(v) => v.epoch(),
2038 Self::Notarization(v) => v.epoch(),
2039 Self::Certification(v) => v.epoch(),
2040 Self::Nullify(v) => v.epoch(),
2041 Self::Nullification(v) => v.epoch(),
2042 Self::Finalize(v) => v.epoch(),
2043 Self::Finalization(v) => v.epoch(),
2044 Self::ConflictingNotarize(v) => v.epoch(),
2045 Self::ConflictingFinalize(v) => v.epoch(),
2046 Self::NullifyFinalize(v) => v.epoch(),
2047 }
2048 }
2049}
2050
2051impl<S: Scheme, D: Digest> Viewable for Activity<S, D> {
2052 fn view(&self) -> View {
2053 match self {
2054 Self::Notarize(v) => v.view(),
2055 Self::Notarization(v) => v.view(),
2056 Self::Certification(v) => v.view(),
2057 Self::Nullify(v) => v.view(),
2058 Self::Nullification(v) => v.view(),
2059 Self::Finalize(v) => v.view(),
2060 Self::Finalization(v) => v.view(),
2061 Self::ConflictingNotarize(v) => v.view(),
2062 Self::ConflictingFinalize(v) => v.view(),
2063 Self::NullifyFinalize(v) => v.view(),
2064 }
2065 }
2066}
2067
2068#[cfg(feature = "arbitrary")]
2069impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Activity<S, D>
2070where
2071 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2072 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
2073 D: for<'a> arbitrary::Arbitrary<'a>,
2074{
2075 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2076 let tag = u.int_in_range(0..=9)?;
2077 match tag {
2078 0 => {
2079 let v = Notarize::<S, D>::arbitrary(u)?;
2080 Ok(Self::Notarize(v))
2081 }
2082 1 => {
2083 let v = Notarization::<S, D>::arbitrary(u)?;
2084 Ok(Self::Notarization(v))
2085 }
2086 2 => {
2087 let v = Notarization::<S, D>::arbitrary(u)?;
2088 Ok(Self::Certification(v))
2089 }
2090 3 => {
2091 let v = Nullify::<S>::arbitrary(u)?;
2092 Ok(Self::Nullify(v))
2093 }
2094 4 => {
2095 let v = Nullification::<S>::arbitrary(u)?;
2096 Ok(Self::Nullification(v))
2097 }
2098 5 => {
2099 let v = Finalize::<S, D>::arbitrary(u)?;
2100 Ok(Self::Finalize(v))
2101 }
2102 6 => {
2103 let v = Finalization::<S, D>::arbitrary(u)?;
2104 Ok(Self::Finalization(v))
2105 }
2106 7 => {
2107 let v = ConflictingNotarize::<S, D>::arbitrary(u)?;
2108 Ok(Self::ConflictingNotarize(v))
2109 }
2110 8 => {
2111 let v = ConflictingFinalize::<S, D>::arbitrary(u)?;
2112 Ok(Self::ConflictingFinalize(v))
2113 }
2114 9 => {
2115 let v = NullifyFinalize::<S, D>::arbitrary(u)?;
2116 Ok(Self::NullifyFinalize(v))
2117 }
2118 _ => unreachable!(),
2119 }
2120 }
2121}
2122
2123#[derive(Clone, Debug)]
2126pub struct ConflictingNotarize<S: Scheme, D: Digest> {
2127 notarize_1: Notarize<S, D>,
2129 notarize_2: Notarize<S, D>,
2131}
2132
2133impl<S: Scheme, D: Digest> PartialEq for ConflictingNotarize<S, D> {
2134 fn eq(&self, other: &Self) -> bool {
2135 self.notarize_1 == other.notarize_1 && self.notarize_2 == other.notarize_2
2136 }
2137}
2138
2139impl<S: Scheme, D: Digest> Eq for ConflictingNotarize<S, D> {}
2140
2141impl<S: Scheme, D: Digest> Hash for ConflictingNotarize<S, D> {
2142 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2143 self.notarize_1.hash(state);
2144 self.notarize_2.hash(state);
2145 }
2146}
2147
2148impl<S: Scheme, D: Digest> ConflictingNotarize<S, D> {
2149 pub fn new(notarize_1: Notarize<S, D>, notarize_2: Notarize<S, D>) -> Self {
2151 assert_eq!(notarize_1.round(), notarize_2.round());
2152 assert_eq!(notarize_1.signer(), notarize_2.signer());
2153
2154 Self {
2155 notarize_1,
2156 notarize_2,
2157 }
2158 }
2159
2160 pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool
2162 where
2163 S: scheme::Scheme<D>,
2164 {
2165 self.notarize_1.verify(scheme, namespace) && self.notarize_2.verify(scheme, namespace)
2166 }
2167}
2168
2169impl<S: Scheme, D: Digest> Attributable for ConflictingNotarize<S, D> {
2170 fn signer(&self) -> u32 {
2171 self.notarize_1.signer()
2172 }
2173}
2174
2175impl<S: Scheme, D: Digest> Epochable for ConflictingNotarize<S, D> {
2176 fn epoch(&self) -> Epoch {
2177 self.notarize_1.epoch()
2178 }
2179}
2180
2181impl<S: Scheme, D: Digest> Viewable for ConflictingNotarize<S, D> {
2182 fn view(&self) -> View {
2183 self.notarize_1.view()
2184 }
2185}
2186
2187impl<S: Scheme, D: Digest> Write for ConflictingNotarize<S, D> {
2188 fn write(&self, writer: &mut impl BufMut) {
2189 self.notarize_1.write(writer);
2190 self.notarize_2.write(writer);
2191 }
2192}
2193
2194impl<S: Scheme, D: Digest> Read for ConflictingNotarize<S, D> {
2195 type Cfg = ();
2196
2197 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2198 let notarize_1 = Notarize::read(reader)?;
2199 let notarize_2 = Notarize::read(reader)?;
2200
2201 if notarize_1.signer() != notarize_2.signer() || notarize_1.round() != notarize_2.round() {
2202 return Err(Error::Invalid(
2203 "consensus::simplex::ConflictingNotarize",
2204 "invalid conflicting notarize",
2205 ));
2206 }
2207
2208 Ok(Self {
2209 notarize_1,
2210 notarize_2,
2211 })
2212 }
2213}
2214
2215impl<S: Scheme, D: Digest> EncodeSize for ConflictingNotarize<S, D> {
2216 fn encode_size(&self) -> usize {
2217 self.notarize_1.encode_size() + self.notarize_2.encode_size()
2218 }
2219}
2220
2221#[cfg(feature = "arbitrary")]
2222impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for ConflictingNotarize<S, D>
2223where
2224 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2225 D: for<'a> arbitrary::Arbitrary<'a>,
2226{
2227 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2228 let notarize_1 = Notarize::arbitrary(u)?;
2229 let notarize_2 = Notarize::arbitrary(u)?;
2230 Ok(Self {
2231 notarize_1,
2232 notarize_2,
2233 })
2234 }
2235}
2236
2237#[derive(Clone, Debug)]
2240pub struct ConflictingFinalize<S: Scheme, D: Digest> {
2241 finalize_1: Finalize<S, D>,
2243 finalize_2: Finalize<S, D>,
2245}
2246
2247impl<S: Scheme, D: Digest> PartialEq for ConflictingFinalize<S, D> {
2248 fn eq(&self, other: &Self) -> bool {
2249 self.finalize_1 == other.finalize_1 && self.finalize_2 == other.finalize_2
2250 }
2251}
2252
2253impl<S: Scheme, D: Digest> Eq for ConflictingFinalize<S, D> {}
2254
2255impl<S: Scheme, D: Digest> Hash for ConflictingFinalize<S, D> {
2256 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2257 self.finalize_1.hash(state);
2258 self.finalize_2.hash(state);
2259 }
2260}
2261
2262impl<S: Scheme, D: Digest> ConflictingFinalize<S, D> {
2263 pub fn new(finalize_1: Finalize<S, D>, finalize_2: Finalize<S, D>) -> Self {
2265 assert_eq!(finalize_1.round(), finalize_2.round());
2266 assert_eq!(finalize_1.signer(), finalize_2.signer());
2267
2268 Self {
2269 finalize_1,
2270 finalize_2,
2271 }
2272 }
2273
2274 pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool
2276 where
2277 S: scheme::Scheme<D>,
2278 {
2279 self.finalize_1.verify(scheme, namespace) && self.finalize_2.verify(scheme, namespace)
2280 }
2281}
2282
2283impl<S: Scheme, D: Digest> Attributable for ConflictingFinalize<S, D> {
2284 fn signer(&self) -> u32 {
2285 self.finalize_1.signer()
2286 }
2287}
2288
2289impl<S: Scheme, D: Digest> Epochable for ConflictingFinalize<S, D> {
2290 fn epoch(&self) -> Epoch {
2291 self.finalize_1.epoch()
2292 }
2293}
2294
2295impl<S: Scheme, D: Digest> Viewable for ConflictingFinalize<S, D> {
2296 fn view(&self) -> View {
2297 self.finalize_1.view()
2298 }
2299}
2300
2301impl<S: Scheme, D: Digest> Write for ConflictingFinalize<S, D> {
2302 fn write(&self, writer: &mut impl BufMut) {
2303 self.finalize_1.write(writer);
2304 self.finalize_2.write(writer);
2305 }
2306}
2307
2308impl<S: Scheme, D: Digest> Read for ConflictingFinalize<S, D> {
2309 type Cfg = ();
2310
2311 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2312 let finalize_1 = Finalize::read(reader)?;
2313 let finalize_2 = Finalize::read(reader)?;
2314
2315 if finalize_1.signer() != finalize_2.signer() || finalize_1.round() != finalize_2.round() {
2316 return Err(Error::Invalid(
2317 "consensus::simplex::ConflictingFinalize",
2318 "invalid conflicting finalize",
2319 ));
2320 }
2321
2322 Ok(Self {
2323 finalize_1,
2324 finalize_2,
2325 })
2326 }
2327}
2328
2329impl<S: Scheme, D: Digest> EncodeSize for ConflictingFinalize<S, D> {
2330 fn encode_size(&self) -> usize {
2331 self.finalize_1.encode_size() + self.finalize_2.encode_size()
2332 }
2333}
2334
2335#[cfg(feature = "arbitrary")]
2336impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for ConflictingFinalize<S, D>
2337where
2338 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2339 D: for<'a> arbitrary::Arbitrary<'a>,
2340{
2341 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2342 let finalize_1 = Finalize::arbitrary(u)?;
2343 let finalize_2 = Finalize::arbitrary(u)?;
2344 Ok(Self {
2345 finalize_1,
2346 finalize_2,
2347 })
2348 }
2349}
2350
2351#[derive(Clone, Debug)]
2355pub struct NullifyFinalize<S: Scheme, D: Digest> {
2356 nullify: Nullify<S>,
2358 finalize: Finalize<S, D>,
2360}
2361
2362impl<S: Scheme, D: Digest> PartialEq for NullifyFinalize<S, D> {
2363 fn eq(&self, other: &Self) -> bool {
2364 self.nullify == other.nullify && self.finalize == other.finalize
2365 }
2366}
2367
2368impl<S: Scheme, D: Digest> Eq for NullifyFinalize<S, D> {}
2369
2370impl<S: Scheme, D: Digest> Hash for NullifyFinalize<S, D> {
2371 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2372 self.nullify.hash(state);
2373 self.finalize.hash(state);
2374 }
2375}
2376
2377impl<S: Scheme, D: Digest> NullifyFinalize<S, D> {
2378 pub fn new(nullify: Nullify<S>, finalize: Finalize<S, D>) -> Self {
2380 assert_eq!(nullify.round, finalize.round());
2381 assert_eq!(nullify.signer(), finalize.signer());
2382
2383 Self { nullify, finalize }
2384 }
2385
2386 pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool
2388 where
2389 S: scheme::Scheme<D>,
2390 {
2391 self.nullify.verify(scheme, namespace) && self.finalize.verify(scheme, namespace)
2392 }
2393}
2394
2395impl<S: Scheme, D: Digest> Attributable for NullifyFinalize<S, D> {
2396 fn signer(&self) -> u32 {
2397 self.nullify.signer()
2398 }
2399}
2400
2401impl<S: Scheme, D: Digest> Epochable for NullifyFinalize<S, D> {
2402 fn epoch(&self) -> Epoch {
2403 self.nullify.epoch()
2404 }
2405}
2406
2407impl<S: Scheme, D: Digest> Viewable for NullifyFinalize<S, D> {
2408 fn view(&self) -> View {
2409 self.nullify.view()
2410 }
2411}
2412
2413impl<S: Scheme, D: Digest> Write for NullifyFinalize<S, D> {
2414 fn write(&self, writer: &mut impl BufMut) {
2415 self.nullify.write(writer);
2416 self.finalize.write(writer);
2417 }
2418}
2419
2420impl<S: Scheme, D: Digest> Read for NullifyFinalize<S, D> {
2421 type Cfg = ();
2422
2423 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2424 let nullify = Nullify::read(reader)?;
2425 let finalize = Finalize::read(reader)?;
2426
2427 if nullify.signer() != finalize.signer() || nullify.round != finalize.round() {
2428 return Err(Error::Invalid(
2429 "consensus::simplex::NullifyFinalize",
2430 "mismatched signatures",
2431 ));
2432 }
2433
2434 Ok(Self { nullify, finalize })
2435 }
2436}
2437
2438impl<S: Scheme, D: Digest> EncodeSize for NullifyFinalize<S, D> {
2439 fn encode_size(&self) -> usize {
2440 self.nullify.encode_size() + self.finalize.encode_size()
2441 }
2442}
2443
2444#[cfg(feature = "arbitrary")]
2445impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for NullifyFinalize<S, D>
2446where
2447 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2448 D: for<'a> arbitrary::Arbitrary<'a>,
2449{
2450 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2451 let nullify = Nullify::arbitrary(u)?;
2452 let finalize = Finalize::arbitrary(u)?;
2453 Ok(Self { nullify, finalize })
2454 }
2455}
2456
2457#[cfg(test)]
2458mod tests {
2459 use super::*;
2460 use crate::simplex::scheme::{bls12381_multisig, bls12381_threshold, ed25519, Scheme};
2461 use commonware_codec::{Decode, DecodeExt, Encode};
2462 use commonware_cryptography::{
2463 bls12381::primitives::variant::{MinPk, MinSig},
2464 certificate::mocks::Fixture,
2465 sha256::Digest as Sha256,
2466 };
2467 use commonware_utils::{quorum, quorum_from_slice};
2468 use rand::{
2469 rngs::{OsRng, StdRng},
2470 SeedableRng,
2471 };
2472
2473 const NAMESPACE: &[u8] = b"test";
2474
2475 fn sample_digest(v: u8) -> Sha256 {
2477 Sha256::from([v; 32]) }
2479
2480 fn setup<S, F>(n: u32, fixture: F) -> Fixture<S>
2482 where
2483 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2484 {
2485 let mut rng = StdRng::seed_from_u64(0);
2486 fixture(&mut rng, n)
2487 }
2488
2489 fn setup_seeded<S, F>(n: u32, seed: u64, fixture: F) -> Fixture<S>
2491 where
2492 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2493 {
2494 let mut rng = StdRng::seed_from_u64(seed);
2495 fixture(&mut rng, n)
2496 }
2497
2498 #[test]
2499 fn test_proposal_encode_decode() {
2500 let proposal = Proposal::new(
2501 Round::new(Epoch::new(0), View::new(10)),
2502 View::new(5),
2503 sample_digest(1),
2504 );
2505 let encoded = proposal.encode();
2506 let decoded = Proposal::<Sha256>::decode(encoded).unwrap();
2507 assert_eq!(proposal, decoded);
2508 }
2509
2510 fn notarize_encode_decode<S, F>(fixture: F)
2511 where
2512 S: Scheme<Sha256>,
2513 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2514 {
2515 let fixture = setup(5, fixture);
2516 let round = Round::new(Epoch::new(0), View::new(10));
2517 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2518 let notarize = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
2519
2520 let encoded = notarize.encode();
2521 let decoded = Notarize::decode(encoded).unwrap();
2522
2523 assert_eq!(notarize, decoded);
2524 assert!(decoded.verify(&fixture.schemes[0], NAMESPACE));
2525 }
2526
2527 #[test]
2528 fn test_notarize_encode_decode() {
2529 notarize_encode_decode(ed25519::fixture);
2530 notarize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2531 notarize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2532 notarize_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2533 notarize_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2534 }
2535
2536 fn notarization_encode_decode<S, F>(fixture: F)
2537 where
2538 S: Scheme<Sha256>,
2539 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2540 {
2541 let fixture = setup(5, fixture);
2542 let proposal = Proposal::new(
2543 Round::new(Epoch::new(0), View::new(10)),
2544 View::new(5),
2545 sample_digest(1),
2546 );
2547 let notarizes: Vec<_> = fixture
2548 .schemes
2549 .iter()
2550 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2551 .collect();
2552 let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap();
2553 let encoded = notarization.encode();
2554 let cfg = fixture.schemes[0].certificate_codec_config();
2555 let decoded = Notarization::decode_cfg(encoded, &cfg).unwrap();
2556 assert_eq!(notarization, decoded);
2557 assert!(decoded.verify(&mut OsRng, &fixture.schemes[0], NAMESPACE));
2558 }
2559
2560 #[test]
2561 fn test_notarization_encode_decode() {
2562 notarization_encode_decode(ed25519::fixture);
2563 notarization_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2564 notarization_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2565 notarization_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2566 notarization_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2567 }
2568
2569 fn nullify_encode_decode<S, F>(fixture: F)
2570 where
2571 S: Scheme<Sha256>,
2572 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2573 {
2574 let fixture = setup(5, fixture);
2575 let round = Round::new(Epoch::new(0), View::new(10));
2576 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], NAMESPACE, round).unwrap();
2577 let encoded = nullify.encode();
2578 let decoded = Nullify::decode(encoded).unwrap();
2579 assert_eq!(nullify, decoded);
2580 assert!(decoded.verify::<Sha256>(&fixture.schemes[0], NAMESPACE));
2581 }
2582
2583 #[test]
2584 fn test_nullify_encode_decode() {
2585 nullify_encode_decode(ed25519::fixture);
2586 nullify_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2587 nullify_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2588 nullify_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2589 nullify_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2590 }
2591
2592 fn nullification_encode_decode<S, F>(fixture: F)
2593 where
2594 S: Scheme<Sha256>,
2595 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2596 {
2597 let fixture = setup(5, fixture);
2598 let round = Round::new(Epoch::new(333), View::new(10));
2599 let nullifies: Vec<_> = fixture
2600 .schemes
2601 .iter()
2602 .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2603 .collect();
2604 let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap();
2605 let encoded = nullification.encode();
2606 let cfg = fixture.schemes[0].certificate_codec_config();
2607 let decoded = Nullification::decode_cfg(encoded, &cfg).unwrap();
2608 assert_eq!(nullification, decoded);
2609 assert!(decoded.verify::<_, Sha256>(&mut OsRng, &fixture.schemes[0], NAMESPACE));
2610 }
2611
2612 #[test]
2613 fn test_nullification_encode_decode() {
2614 nullification_encode_decode(ed25519::fixture);
2615 nullification_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2616 nullification_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2617 nullification_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2618 nullification_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2619 }
2620
2621 fn finalize_encode_decode<S, F>(fixture: F)
2622 where
2623 S: Scheme<Sha256>,
2624 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2625 {
2626 let fixture = setup(5, fixture);
2627 let round = Round::new(Epoch::new(0), View::new(10));
2628 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2629 let finalize = Finalize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
2630 let encoded = finalize.encode();
2631 let decoded = Finalize::decode(encoded).unwrap();
2632 assert_eq!(finalize, decoded);
2633 assert!(decoded.verify(&fixture.schemes[0], NAMESPACE));
2634 }
2635
2636 #[test]
2637 fn test_finalize_encode_decode() {
2638 finalize_encode_decode(ed25519::fixture);
2639 finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2640 finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2641 finalize_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2642 finalize_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2643 }
2644
2645 fn finalization_encode_decode<S, F>(fixture: F)
2646 where
2647 S: Scheme<Sha256>,
2648 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2649 {
2650 let fixture = setup(5, fixture);
2651 let round = Round::new(Epoch::new(0), View::new(10));
2652 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2653 let finalizes: Vec<_> = fixture
2654 .schemes
2655 .iter()
2656 .map(|scheme| Finalize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2657 .collect();
2658 let finalization = Finalization::from_finalizes(&fixture.schemes[0], &finalizes).unwrap();
2659 let encoded = finalization.encode();
2660 let cfg = fixture.schemes[0].certificate_codec_config();
2661 let decoded = Finalization::decode_cfg(encoded, &cfg).unwrap();
2662 assert_eq!(finalization, decoded);
2663 assert!(decoded.verify(&mut OsRng, &fixture.schemes[0], NAMESPACE));
2664 }
2665
2666 #[test]
2667 fn test_finalization_encode_decode() {
2668 finalization_encode_decode(ed25519::fixture);
2669 finalization_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2670 finalization_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2671 finalization_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2672 finalization_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2673 }
2674
2675 fn backfiller_encode_decode<S, F>(fixture: F)
2676 where
2677 S: Scheme<Sha256>,
2678 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2679 {
2680 let fixture = setup(5, fixture);
2681 let cfg = fixture.schemes[0].certificate_codec_config();
2682 let request = Request::new(
2683 1,
2684 vec![View::new(10), View::new(11)],
2685 vec![View::new(12), View::new(13)],
2686 );
2687 let encoded_request = Backfiller::<S, Sha256>::Request(request.clone()).encode();
2688 let decoded_request =
2689 Backfiller::<S, Sha256>::decode_cfg(encoded_request, &(usize::MAX, cfg.clone()))
2690 .unwrap();
2691 assert!(matches!(decoded_request, Backfiller::Request(r) if r == request));
2692
2693 let round = Round::new(Epoch::new(0), View::new(10));
2694 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2695 let notarizes: Vec<_> = fixture
2696 .schemes
2697 .iter()
2698 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2699 .collect();
2700 let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap();
2701
2702 let nullifies: Vec<_> = fixture
2703 .schemes
2704 .iter()
2705 .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2706 .collect();
2707 let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap();
2708
2709 let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
2710 let encoded_response = Backfiller::<S, Sha256>::Response(response.clone()).encode();
2711 let decoded_response =
2712 Backfiller::<S, Sha256>::decode_cfg(encoded_response, &(usize::MAX, cfg)).unwrap();
2713 assert!(matches!(decoded_response, Backfiller::Response(r) if r.id == response.id));
2714 }
2715
2716 #[test]
2717 fn test_backfiller_encode_decode() {
2718 backfiller_encode_decode(ed25519::fixture);
2719 backfiller_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2720 backfiller_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2721 backfiller_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2722 backfiller_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2723 }
2724
2725 #[test]
2726 fn test_request_encode_decode() {
2727 let request = Request::new(
2728 1,
2729 vec![View::new(10), View::new(11)],
2730 vec![View::new(12), View::new(13)],
2731 );
2732 let encoded = request.encode();
2733 let decoded = Request::decode_cfg(encoded, &usize::MAX).unwrap();
2734 assert_eq!(request, decoded);
2735 }
2736
2737 fn response_encode_decode<S, F>(fixture: F)
2738 where
2739 S: Scheme<Sha256>,
2740 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2741 {
2742 let fixture = setup(5, fixture);
2743 let round = Round::new(Epoch::new(0), View::new(10));
2744 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2745
2746 let notarizes: Vec<_> = fixture
2747 .schemes
2748 .iter()
2749 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2750 .collect();
2751 let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap();
2752
2753 let nullifies: Vec<_> = fixture
2754 .schemes
2755 .iter()
2756 .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2757 .collect();
2758 let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap();
2759
2760 let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
2761 let cfg = fixture.schemes[0].certificate_codec_config();
2762 let mut decoded =
2763 Response::<S, Sha256>::decode_cfg(response.encode(), &(usize::MAX, cfg)).unwrap();
2764 assert_eq!(response.id, decoded.id);
2765 assert_eq!(response.notarizations.len(), decoded.notarizations.len());
2766 assert_eq!(response.nullifications.len(), decoded.nullifications.len());
2767
2768 let mut rng = OsRng;
2769 assert!(decoded.verify(&mut rng, &fixture.schemes[0], NAMESPACE));
2770
2771 decoded.nullifications[0].round = Round::new(
2772 decoded.nullifications[0].round.epoch(),
2773 decoded.nullifications[0].round.view().next(),
2774 );
2775 assert!(!decoded.verify(&mut rng, &fixture.schemes[0], NAMESPACE));
2776 }
2777
2778 #[test]
2779 fn test_response_encode_decode() {
2780 response_encode_decode(ed25519::fixture);
2781 response_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2782 response_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2783 response_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2784 response_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2785 }
2786
2787 fn conflicting_notarize_encode_decode<S, F>(fixture: F)
2788 where
2789 S: Scheme<Sha256>,
2790 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2791 {
2792 let fixture = setup(5, fixture);
2793 let proposal1 = Proposal::new(
2794 Round::new(Epoch::new(0), View::new(10)),
2795 View::new(5),
2796 sample_digest(1),
2797 );
2798 let proposal2 = Proposal::new(
2799 Round::new(Epoch::new(0), View::new(10)),
2800 View::new(5),
2801 sample_digest(2),
2802 );
2803 let notarize1 = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal1).unwrap();
2804 let notarize2 = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal2).unwrap();
2805 let conflicting = ConflictingNotarize::new(notarize1, notarize2);
2806
2807 let encoded = conflicting.encode();
2808 let decoded = ConflictingNotarize::<S, Sha256>::decode(encoded).unwrap();
2809
2810 assert_eq!(conflicting, decoded);
2811 assert!(decoded.verify(&fixture.schemes[0], NAMESPACE));
2812 }
2813
2814 #[test]
2815 fn test_conflicting_notarize_encode_decode() {
2816 conflicting_notarize_encode_decode(ed25519::fixture);
2817 conflicting_notarize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2818 conflicting_notarize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2819 conflicting_notarize_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2820 conflicting_notarize_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2821 }
2822
2823 fn conflicting_finalize_encode_decode<S, F>(fixture: F)
2824 where
2825 S: Scheme<Sha256>,
2826 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2827 {
2828 let fixture = setup(5, fixture);
2829 let proposal1 = Proposal::new(
2830 Round::new(Epoch::new(0), View::new(10)),
2831 View::new(5),
2832 sample_digest(1),
2833 );
2834 let proposal2 = Proposal::new(
2835 Round::new(Epoch::new(0), View::new(10)),
2836 View::new(5),
2837 sample_digest(2),
2838 );
2839 let finalize1 = Finalize::sign(&fixture.schemes[0], NAMESPACE, proposal1).unwrap();
2840 let finalize2 = Finalize::sign(&fixture.schemes[0], NAMESPACE, proposal2).unwrap();
2841 let conflicting = ConflictingFinalize::new(finalize1, finalize2);
2842
2843 let encoded = conflicting.encode();
2844 let decoded = ConflictingFinalize::<S, Sha256>::decode(encoded).unwrap();
2845
2846 assert_eq!(conflicting, decoded);
2847 assert!(decoded.verify(&fixture.schemes[0], NAMESPACE));
2848 }
2849
2850 #[test]
2851 fn test_conflicting_finalize_encode_decode() {
2852 conflicting_finalize_encode_decode(ed25519::fixture);
2853 conflicting_finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2854 conflicting_finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2855 conflicting_finalize_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2856 conflicting_finalize_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2857 }
2858
2859 fn nullify_finalize_encode_decode<S, F>(fixture: F)
2860 where
2861 S: Scheme<Sha256>,
2862 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2863 {
2864 let fixture = setup(5, fixture);
2865 let round = Round::new(Epoch::new(0), View::new(10));
2866 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2867 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], NAMESPACE, round).unwrap();
2868 let finalize = Finalize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
2869 let conflict = NullifyFinalize::new(nullify, finalize);
2870
2871 let encoded = conflict.encode();
2872 let decoded = NullifyFinalize::<S, Sha256>::decode(encoded).unwrap();
2873
2874 assert_eq!(conflict, decoded);
2875 assert!(decoded.verify(&fixture.schemes[0], NAMESPACE));
2876 }
2877
2878 #[test]
2879 fn test_nullify_finalize_encode_decode() {
2880 nullify_finalize_encode_decode(ed25519::fixture);
2881 nullify_finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
2882 nullify_finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
2883 nullify_finalize_encode_decode(bls12381_threshold::fixture::<MinPk, _>);
2884 nullify_finalize_encode_decode(bls12381_threshold::fixture::<MinSig, _>);
2885 }
2886
2887 fn notarize_verify_wrong_namespace<S, F>(fixture: F)
2888 where
2889 S: Scheme<Sha256>,
2890 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2891 {
2892 let fixture = setup(5, fixture);
2893 let round = Round::new(Epoch::new(0), View::new(10));
2894 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
2895 let notarize = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
2896
2897 assert!(notarize.verify(&fixture.schemes[0], NAMESPACE));
2898 assert!(!notarize.verify(&fixture.schemes[0], b"wrong_namespace"));
2899 }
2900
2901 #[test]
2902 fn test_notarize_verify_wrong_namespace() {
2903 notarize_verify_wrong_namespace(ed25519::fixture);
2904 notarize_verify_wrong_namespace(bls12381_multisig::fixture::<MinPk, _>);
2905 notarize_verify_wrong_namespace(bls12381_multisig::fixture::<MinSig, _>);
2906 notarize_verify_wrong_namespace(bls12381_threshold::fixture::<MinPk, _>);
2907 notarize_verify_wrong_namespace(bls12381_threshold::fixture::<MinSig, _>);
2908 }
2909
2910 fn notarize_verify_wrong_scheme<S, F>(f: F)
2911 where
2912 S: Scheme<Sha256>,
2913 F: Fn(&mut StdRng, u32) -> Fixture<S>,
2914 {
2915 let fixture = setup_seeded(5, 0, &f);
2916 let wrong_fixture = setup_seeded(5, 1, &f);
2917 let round = Round::new(Epoch::new(0), View::new(10));
2918 let proposal = Proposal::new(round, View::new(5), sample_digest(2));
2919 let notarize = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
2920
2921 assert!(notarize.verify(&fixture.schemes[0], NAMESPACE));
2922 assert!(!notarize.verify(&wrong_fixture.verifier, NAMESPACE));
2923 }
2924
2925 #[test]
2926 fn test_notarize_verify_wrong_scheme() {
2927 notarize_verify_wrong_scheme(ed25519::fixture);
2928 notarize_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
2929 notarize_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
2930 notarize_verify_wrong_scheme(bls12381_threshold::fixture::<MinPk, _>);
2931 notarize_verify_wrong_scheme(bls12381_threshold::fixture::<MinSig, _>);
2932 }
2933
2934 fn notarization_verify_wrong_scheme<S, F>(f: F)
2935 where
2936 S: Scheme<Sha256>,
2937 F: Fn(&mut StdRng, u32) -> Fixture<S>,
2938 {
2939 let fixture = setup_seeded(5, 0, &f);
2940 let wrong_fixture = setup_seeded(5, 1, &f);
2941 let round = Round::new(Epoch::new(0), View::new(10));
2942 let proposal = Proposal::new(round, View::new(5), sample_digest(3));
2943 let quorum = quorum_from_slice(&fixture.schemes) as usize;
2944 let notarizes: Vec<_> = fixture
2945 .schemes
2946 .iter()
2947 .take(quorum)
2948 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2949 .collect();
2950
2951 let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes)
2952 .expect("quorum notarization");
2953 let mut rng = OsRng;
2954 assert!(notarization.verify(&mut rng, &fixture.schemes[0], NAMESPACE));
2955
2956 let mut rng = OsRng;
2957 assert!(!notarization.verify(&mut rng, &wrong_fixture.verifier, NAMESPACE));
2958 }
2959
2960 #[test]
2961 fn test_notarization_verify_wrong_scheme() {
2962 notarization_verify_wrong_scheme(ed25519::fixture);
2963 notarization_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
2964 notarization_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
2965 notarization_verify_wrong_scheme(bls12381_threshold::fixture::<MinPk, _>);
2966 notarization_verify_wrong_scheme(bls12381_threshold::fixture::<MinSig, _>);
2967 }
2968
2969 fn notarization_verify_wrong_namespace<S, F>(fixture: F)
2970 where
2971 S: Scheme<Sha256>,
2972 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
2973 {
2974 let fixture = setup(5, fixture);
2975 let round = Round::new(Epoch::new(0), View::new(10));
2976 let proposal = Proposal::new(round, View::new(5), sample_digest(4));
2977 let quorum = quorum_from_slice(&fixture.schemes) as usize;
2978 let notarizes: Vec<_> = fixture
2979 .schemes
2980 .iter()
2981 .take(quorum)
2982 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2983 .collect();
2984
2985 let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes)
2986 .expect("quorum notarization");
2987 let mut rng = OsRng;
2988 assert!(notarization.verify(&mut rng, &fixture.schemes[0], NAMESPACE));
2989
2990 let mut rng = OsRng;
2991 assert!(!notarization.verify(&mut rng, &fixture.schemes[0], b"wrong_namespace"));
2992 }
2993
2994 #[test]
2995 fn test_notarization_verify_wrong_namespace() {
2996 notarization_verify_wrong_namespace(ed25519::fixture);
2997 notarization_verify_wrong_namespace(bls12381_multisig::fixture::<MinPk, _>);
2998 notarization_verify_wrong_namespace(bls12381_multisig::fixture::<MinSig, _>);
2999 notarization_verify_wrong_namespace(bls12381_threshold::fixture::<MinPk, _>);
3000 notarization_verify_wrong_namespace(bls12381_threshold::fixture::<MinSig, _>);
3001 }
3002
3003 fn notarization_recover_insufficient_signatures<S, F>(fixture: F)
3004 where
3005 S: Scheme<Sha256>,
3006 F: FnOnce(&mut StdRng, u32) -> Fixture<S>,
3007 {
3008 let fixture = setup(5, fixture);
3009 let quorum_size = quorum(fixture.schemes.len() as u32) as usize;
3010 assert!(quorum_size > 1, "test requires quorum larger than one");
3011 let round = Round::new(Epoch::new(0), View::new(10));
3012 let proposal = Proposal::new(round, View::new(5), sample_digest(5));
3013 let notarizes: Vec<_> = fixture
3014 .schemes
3015 .iter()
3016 .take(quorum_size - 1)
3017 .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
3018 .collect();
3019
3020 assert!(
3021 Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).is_none(),
3022 "insufficient votes should not form a notarization"
3023 );
3024 }
3025
3026 #[test]
3027 fn test_notarization_recover_insufficient_signatures() {
3028 notarization_recover_insufficient_signatures(ed25519::fixture);
3029 notarization_recover_insufficient_signatures(bls12381_multisig::fixture::<MinPk, _>);
3030 notarization_recover_insufficient_signatures(bls12381_multisig::fixture::<MinSig, _>);
3031 notarization_recover_insufficient_signatures(bls12381_threshold::fixture::<MinPk, _>);
3032 notarization_recover_insufficient_signatures(bls12381_threshold::fixture::<MinSig, _>);
3033 }
3034
3035 fn conflicting_notarize_detection<S, F>(f: F)
3036 where
3037 S: Scheme<Sha256>,
3038 F: Fn(&mut StdRng, u32) -> Fixture<S>,
3039 {
3040 let fixture = setup_seeded(5, 0, &f);
3041 let wrong_fixture = setup_seeded(5, 1, &f);
3042 let round = Round::new(Epoch::new(0), View::new(10));
3043 let proposal1 = Proposal::new(round, View::new(5), sample_digest(6));
3044 let proposal2 = Proposal::new(round, View::new(5), sample_digest(7));
3045
3046 let notarize1 = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal1).unwrap();
3047 let notarize2 = Notarize::sign(&fixture.schemes[0], NAMESPACE, proposal2).unwrap();
3048 let conflict = ConflictingNotarize::new(notarize1, notarize2);
3049
3050 assert!(conflict.verify(&fixture.schemes[0], NAMESPACE));
3051 assert!(!conflict.verify(&fixture.schemes[0], b"wrong_namespace"));
3052 assert!(!conflict.verify(&wrong_fixture.verifier, NAMESPACE));
3053 }
3054
3055 #[test]
3056 fn test_conflicting_notarize_detection() {
3057 conflicting_notarize_detection(ed25519::fixture);
3058 conflicting_notarize_detection(bls12381_multisig::fixture::<MinPk, _>);
3059 conflicting_notarize_detection(bls12381_multisig::fixture::<MinSig, _>);
3060 conflicting_notarize_detection(bls12381_threshold::fixture::<MinPk, _>);
3061 conflicting_notarize_detection(bls12381_threshold::fixture::<MinSig, _>);
3062 }
3063
3064 fn nullify_finalize_detection<S, F>(f: F)
3065 where
3066 S: Scheme<Sha256>,
3067 F: Fn(&mut StdRng, u32) -> Fixture<S>,
3068 {
3069 let fixture = setup_seeded(5, 0, &f);
3070 let wrong_fixture = setup_seeded(5, 1, &f);
3071 let round = Round::new(Epoch::new(0), View::new(10));
3072 let proposal = Proposal::new(round, View::new(5), sample_digest(8));
3073
3074 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], NAMESPACE, round).unwrap();
3075 let finalize = Finalize::sign(&fixture.schemes[0], NAMESPACE, proposal).unwrap();
3076 let conflict = NullifyFinalize::new(nullify, finalize);
3077
3078 assert!(conflict.verify(&fixture.schemes[0], NAMESPACE));
3079 assert!(!conflict.verify(&fixture.schemes[0], b"wrong_namespace"));
3080 assert!(!conflict.verify(&wrong_fixture.verifier, NAMESPACE));
3081 }
3082
3083 #[test]
3084 fn test_nullify_finalize_detection() {
3085 nullify_finalize_detection(ed25519::fixture);
3086 nullify_finalize_detection(bls12381_multisig::fixture::<MinPk, _>);
3087 nullify_finalize_detection(bls12381_multisig::fixture::<MinSig, _>);
3088 nullify_finalize_detection(bls12381_threshold::fixture::<MinPk, _>);
3089 nullify_finalize_detection(bls12381_threshold::fixture::<MinSig, _>);
3090 }
3091
3092 fn finalization_verify_wrong_scheme<S, F>(f: F)
3093 where
3094 S: Scheme<Sha256>,
3095 F: Fn(&mut StdRng, u32) -> Fixture<S>,
3096 {
3097 let fixture = setup_seeded(5, 0, &f);
3098 let wrong_fixture = setup_seeded(5, 1, &f);
3099 let round = Round::new(Epoch::new(0), View::new(10));
3100 let proposal = Proposal::new(round, View::new(5), sample_digest(9));
3101 let quorum = quorum_from_slice(&fixture.schemes) as usize;
3102 let finalizes: Vec<_> = fixture
3103 .schemes
3104 .iter()
3105 .take(quorum)
3106 .map(|scheme| Finalize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
3107 .collect();
3108
3109 let finalization = Finalization::from_finalizes(&fixture.schemes[0], &finalizes)
3110 .expect("quorum finalization");
3111 let mut rng = OsRng;
3112 assert!(finalization.verify(&mut rng, &fixture.schemes[0], NAMESPACE));
3113
3114 let mut rng = OsRng;
3115 assert!(!finalization.verify(&mut rng, &wrong_fixture.verifier, NAMESPACE));
3116 }
3117
3118 #[test]
3119 fn test_finalization_wrong_scheme() {
3120 finalization_verify_wrong_scheme(ed25519::fixture);
3121 finalization_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
3122 finalization_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
3123 finalization_verify_wrong_scheme(bls12381_threshold::fixture::<MinPk, _>);
3124 finalization_verify_wrong_scheme(bls12381_threshold::fixture::<MinSig, _>);
3125 }
3126
3127 struct MockAttributable(u32);
3128
3129 impl Attributable for MockAttributable {
3130 fn signer(&self) -> u32 {
3131 self.0
3132 }
3133 }
3134
3135 #[test]
3136 fn test_attributable_map() {
3137 let mut map = AttributableMap::new(5);
3138 assert_eq!(map.len(), 0);
3139 assert!(map.is_empty());
3140
3141 for i in 0..5 {
3143 assert!(map.get(i).is_none());
3144 }
3145
3146 assert!(map.insert(MockAttributable(3)));
3147 assert_eq!(map.len(), 1);
3148 assert!(!map.is_empty());
3149 let mut iter = map.iter();
3150 assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3151 assert!(iter.next().is_none());
3152 drop(iter);
3153
3154 assert!(matches!(map.get(3), Some(a) if a.signer() == 3));
3156
3157 assert!(map.insert(MockAttributable(1)));
3158 assert_eq!(map.len(), 2);
3159 assert!(!map.is_empty());
3160 let mut iter = map.iter();
3161 assert!(matches!(iter.next(), Some(a) if a.signer() == 1));
3162 assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3163 assert!(iter.next().is_none());
3164 drop(iter);
3165
3166 assert!(matches!(map.get(1), Some(a) if a.signer() == 1));
3168 assert!(matches!(map.get(3), Some(a) if a.signer() == 3));
3169
3170 assert!(map.get(0).is_none());
3172 assert!(map.get(2).is_none());
3173 assert!(map.get(4).is_none());
3174
3175 assert!(!map.insert(MockAttributable(3)));
3176 assert_eq!(map.len(), 2);
3177 assert!(!map.is_empty());
3178 let mut iter = map.iter();
3179 assert!(matches!(iter.next(), Some(a) if a.signer() == 1));
3180 assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3181 assert!(iter.next().is_none());
3182 drop(iter);
3183
3184 assert!(!map.insert(MockAttributable(5)));
3186 assert!(!map.insert(MockAttributable(100)));
3187 assert_eq!(map.len(), 2);
3188
3189 map.clear();
3191 assert_eq!(map.len(), 0);
3192 assert!(map.is_empty());
3193 assert!(map.iter().next().is_none());
3194
3195 assert!(map.insert(MockAttributable(2)));
3197 assert_eq!(map.len(), 1);
3198 let mut iter = map.iter();
3199 assert!(matches!(iter.next(), Some(a) if a.signer() == 2));
3200 assert!(iter.next().is_none());
3201 }
3202
3203 #[cfg(feature = "arbitrary")]
3204 mod conformance {
3205 use super::*;
3206 use crate::simplex::scheme::bls12381_threshold;
3207 use commonware_codec::conformance::CodecConformance;
3208 use commonware_cryptography::{ed25519::PublicKey, sha256::Digest as Sha256Digest};
3209
3210 type Scheme = bls12381_threshold::Scheme<PublicKey, MinSig>;
3211
3212 commonware_conformance::conformance_tests! {
3213 CodecConformance<Vote<Scheme, Sha256Digest>>,
3214 CodecConformance<Certificate<Scheme, Sha256Digest>>,
3215 CodecConformance<Artifact<Scheme, Sha256Digest>>,
3216 CodecConformance<Proposal<Sha256Digest>>,
3217 CodecConformance<Notarize<Scheme, Sha256Digest>>,
3218 CodecConformance<Notarization<Scheme, Sha256Digest>>,
3219 CodecConformance<Nullify<Scheme>>,
3220 CodecConformance<Nullification<Scheme>>,
3221 CodecConformance<Finalize<Scheme, Sha256Digest>>,
3222 CodecConformance<Finalization<Scheme, Sha256Digest>>,
3223 CodecConformance<Backfiller<Scheme, Sha256Digest>>,
3224 CodecConformance<Request>,
3225 CodecConformance<Response<Scheme, Sha256Digest>>,
3226 CodecConformance<Activity<Scheme, Sha256Digest>>,
3227 CodecConformance<ConflictingNotarize<Scheme, Sha256Digest>>,
3228 CodecConformance<ConflictingFinalize<Scheme, Sha256Digest>>,
3229 CodecConformance<NullifyFinalize<Scheme, Sha256Digest>>,
3230 }
3231 }
3232}