1use crate::{
4 Epochable, Viewable,
5 simplex::scheme::{self, CertificateVerifier},
6 types::{Epoch, Participant, Round, View},
7};
8use bytes::{Buf, BufMut};
9use commonware_codec::{EncodeSize, Error, Read, ReadExt, ReadRangeExt, Write, varint::UInt};
10use commonware_cryptography::{
11 Digest, PublicKey,
12 certificate::{AssemblyError, Attestation, Scheme},
13};
14use commonware_parallel::Strategy;
15use commonware_utils::{iter::NonEmpty, non_empty};
16use rand_core::CryptoRng;
17use std::{collections::HashSet, fmt::Debug, hash::Hash};
18
19#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct Context<D: Digest, P: PublicKey> {
23 pub round: Round,
25 pub leader: P,
27 pub parent: (View, D),
37}
38
39impl<D: Digest, P: PublicKey> Epochable for Context<D, P> {
40 fn epoch(&self) -> Epoch {
41 self.round.epoch()
42 }
43}
44
45impl<D: Digest, P: PublicKey> Viewable for Context<D, P> {
46 fn view(&self) -> View {
47 self.round.view()
48 }
49}
50
51impl<D: Digest, P: PublicKey> Write for Context<D, P> {
52 fn write(&self, buf: &mut impl BufMut) {
53 self.round.write(buf);
54 self.leader.write(buf);
55 self.parent.write(buf);
56 }
57}
58
59impl<D: Digest, P: PublicKey> EncodeSize for Context<D, P> {
60 fn encode_size(&self) -> usize {
61 self.round.encode_size() + self.leader.encode_size() + self.parent.encode_size()
62 }
63}
64
65impl<D: Digest, P: PublicKey> Read for Context<D, P> {
66 type Cfg = ();
67
68 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
69 let round = Round::read(reader)?;
70 let leader = P::read(reader)?;
71 let parent = <(View, D)>::read_cfg(reader, &((), ()))?;
72
73 Ok(Self {
74 round,
75 leader,
76 parent,
77 })
78 }
79}
80
81#[cfg(feature = "arbitrary")]
82impl<D: Digest, P: PublicKey> arbitrary::Arbitrary<'_> for Context<D, P>
83where
84 D: for<'a> arbitrary::Arbitrary<'a>,
85 P: for<'a> arbitrary::Arbitrary<'a>,
86{
87 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
88 Ok(Self {
89 round: Round::arbitrary(u)?,
90 leader: P::arbitrary(u)?,
91 parent: (View::arbitrary(u)?, D::arbitrary(u)?),
92 })
93 }
94}
95
96pub trait Attributable {
99 fn signer(&self) -> Participant;
101}
102
103pub struct AttributableMap<T: Attributable> {
108 participants: usize,
109 data: Vec<Option<T>>,
110 added: usize,
111}
112
113impl<T: Attributable> AttributableMap<T> {
114 pub const fn new(participants: usize) -> Self {
116 Self {
117 participants,
118 data: Vec::new(),
119 added: 0,
120 }
121 }
122
123 pub fn clear(&mut self) {
125 self.data = Vec::new();
126 self.added = 0;
127 }
128
129 pub fn insert(&mut self, item: T) -> bool {
135 let index: usize = item.signer().into();
136 if index >= self.participants {
137 return false;
138 }
139 if self.data.is_empty() {
140 self.data.reserve_exact(self.participants);
142 self.data.resize_with(self.participants, || None);
143 }
144 if self.data[index].is_some() {
145 return false;
146 }
147 self.data[index] = Some(item);
148 self.added += 1;
149 true
150 }
151
152 pub const fn len(&self) -> usize {
154 self.added
155 }
156
157 pub const fn is_empty(&self) -> bool {
159 self.added == 0
160 }
161
162 pub fn get(&self, signer: Participant) -> Option<&T> {
164 self.data.get(<usize>::from(signer))?.as_ref()
165 }
166
167 pub fn iter(&self) -> impl Iterator<Item = &T> {
170 self.data.iter().filter_map(|o| o.as_ref())
171 }
172}
173
174#[cfg(not(target_arch = "wasm32"))]
176enum Phase<T: Attributable> {
177 Full(AttributableMap<T>),
178 Compacted,
179}
180
181#[cfg(not(target_arch = "wasm32"))]
182impl<T: Attributable> Phase<T> {
183 const fn new(participants: usize) -> Self {
184 Self::Full(AttributableMap::new(participants))
185 }
186
187 fn insert(&mut self, vote: T) -> bool {
188 match self {
189 Self::Full(votes) => votes.insert(vote),
190 Self::Compacted => false,
191 }
192 }
193
194 fn get(&self, signer: Participant) -> Option<&T> {
195 match self {
196 Self::Full(votes) => votes.get(signer),
197 Self::Compacted => None,
198 }
199 }
200
201 fn iter(&self) -> impl Iterator<Item = &T> {
202 match self {
203 Self::Full(votes) => Some(votes),
204 Self::Compacted => None,
205 }
206 .into_iter()
207 .flat_map(AttributableMap::iter)
208 }
209
210 const fn len(&self) -> usize {
211 match self {
212 Self::Full(votes) => votes.len(),
213 Self::Compacted => 0,
214 }
215 }
216
217 fn compact(&mut self) -> Option<AttributableMap<T>> {
218 match std::mem::replace(self, Self::Compacted) {
219 Self::Full(votes) => Some(votes),
220 Self::Compacted => None,
221 }
222 }
223
224 fn reset(&mut self, participants: usize) {
225 *self = Self::new(participants);
226 }
227}
228
229#[cfg(not(target_arch = "wasm32"))]
236pub struct VoteTracker<S: Scheme, D: Digest> {
237 participants: usize,
238 retain_votes_after_certification: bool,
239 compacted: Vec<u8>,
243 notarizes: Phase<Notarize<S, D>>,
244 nullifies: Phase<Nullify<S>>,
245 finalizes: Phase<Finalize<S, D>>,
248}
249
250#[cfg(not(target_arch = "wasm32"))]
252pub(crate) enum Outcome {
253 Added { retained: bool },
255 Duplicate { retained: bool },
257 Conflicting,
259}
260
261#[cfg(not(target_arch = "wasm32"))]
263pub(crate) enum ObservedVote<'a, T> {
264 Retained(&'a T),
265 Compacted,
266}
267
268#[cfg(not(target_arch = "wasm32"))]
269impl<S: Scheme, D: Digest> VoteTracker<S, D> {
270 const NOTARIZE_SEEN: u8 = 1 << 0;
271 const NOTARIZE_HAS_PROPOSAL: u8 = 1 << 1;
272 const NULLIFY_SEEN: u8 = 1 << 2;
273 const FINALIZE_SEEN: u8 = 1 << 3;
274 const FINALIZE_HAS_PROPOSAL: u8 = 1 << 4;
275
276 pub const fn new(participants: usize, retain_votes_after_certification: bool) -> Self {
282 Self {
283 participants,
284 retain_votes_after_certification,
285 compacted: Vec::new(),
286 notarizes: Phase::new(participants),
287 nullifies: Phase::new(participants),
288 finalizes: Phase::new(participants),
289 }
290 }
291}
292
293#[cfg(not(target_arch = "wasm32"))]
294impl<S: Scheme, D: Digest> VoteTracker<S, D> {
295 fn remember(
300 participants: usize,
301 compacted: &mut Vec<u8>,
302 signer: Participant,
303 seen: u8,
304 proposal_relation: Option<(u8, bool)>,
305 ) -> Outcome {
306 let index = usize::from(signer);
307 if index >= participants {
308 return Outcome::Duplicate { retained: false };
309 }
310
311 if compacted.is_empty() {
313 compacted.resize(participants, 0);
314 }
315
316 let flags = &mut compacted[index];
317 let previously_seen = *flags & seen != 0;
318 let proposal_conflict = proposal_relation.is_some_and(|(has_proposal, matches)| {
319 previously_seen && (*flags & has_proposal != 0) != matches
320 });
321 *flags |= seen;
322 if let Some((has_proposal, true)) = proposal_relation {
323 *flags |= has_proposal;
324 }
325 if !previously_seen {
326 Outcome::Added { retained: false }
327 } else if proposal_conflict {
328 Outcome::Conflicting
329 } else {
330 Outcome::Duplicate { retained: false }
331 }
332 }
333
334 fn record_phase<T: Attributable + Clone>(
339 participants: usize,
340 compacted: &mut Vec<u8>,
341 phase: &mut Phase<T>,
342 vote: &T,
343 seen: u8,
344 proposal_relation: Option<(u8, bool)>,
345 ) -> Outcome {
346 match phase {
347 Phase::Full(votes) => {
348 if votes.insert(vote.clone()) {
349 Outcome::Added { retained: true }
350 } else {
351 Outcome::Duplicate { retained: true }
352 }
353 }
354 Phase::Compacted => Self::remember(
355 participants,
356 compacted,
357 vote.signer(),
358 seen,
359 proposal_relation,
360 ),
361 }
362 }
363
364 fn remembered(&self, signer: Participant, flag: u8) -> bool {
365 self.compacted
366 .get(usize::from(signer))
367 .is_some_and(|flags| flags & flag != 0)
368 }
369
370 pub(crate) fn record(&mut self, vote: &Vote<S, D>, proposal: Option<&Proposal<D>>) -> Outcome {
374 match vote {
375 Vote::Notarize(notarize) => Self::record_phase(
376 self.participants,
377 &mut self.compacted,
378 &mut self.notarizes,
379 notarize,
380 Self::NOTARIZE_SEEN,
381 proposal
382 .map(|proposal| (Self::NOTARIZE_HAS_PROPOSAL, proposal == ¬arize.proposal)),
383 ),
384 Vote::Nullify(nullify) => Self::record_phase(
385 self.participants,
386 &mut self.compacted,
387 &mut self.nullifies,
388 nullify,
389 Self::NULLIFY_SEEN,
390 None,
391 ),
392 Vote::Finalize(finalize) => Self::record_phase(
393 self.participants,
394 &mut self.compacted,
395 &mut self.finalizes,
396 finalize,
397 Self::FINALIZE_SEEN,
398 proposal
399 .map(|proposal| (Self::FINALIZE_HAS_PROPOSAL, proposal == &finalize.proposal)),
400 ),
401 }
402 }
403
404 fn release<T: Attributable>(
409 participants: usize,
410 compacted: &mut Vec<u8>,
411 phase: &mut Phase<T>,
412 seen: u8,
413 has_proposal: u8,
414 carries_proposal: impl Fn(&T) -> bool,
415 ) {
416 let Some(votes) = phase.compact() else {
417 return;
418 };
419
420 if !votes.is_empty() && compacted.is_empty() {
423 compacted.resize(participants, 0);
424 }
425
426 for vote in votes.iter() {
428 let flags = &mut compacted[usize::from(vote.signer())];
429 *flags |= seen;
430 if carries_proposal(vote) {
431 *flags |= has_proposal;
432 }
433 }
434 }
435
436 pub(crate) fn saw_nullify(&self, signer: Participant) -> Option<ObservedVote<'_, Nullify<S>>> {
438 self.nullify(signer)
439 .map(ObservedVote::Retained)
440 .or_else(|| {
441 self.remembered(signer, Self::NULLIFY_SEEN)
442 .then_some(ObservedVote::Compacted)
443 })
444 }
445
446 pub(crate) fn saw_finalize(
448 &self,
449 signer: Participant,
450 ) -> Option<ObservedVote<'_, Finalize<S, D>>> {
451 self.finalize(signer)
452 .map(ObservedVote::Retained)
453 .or_else(|| {
454 self.remembered(signer, Self::FINALIZE_SEEN)
455 .then_some(ObservedVote::Compacted)
456 })
457 }
458
459 pub(crate) fn has_notarize_for(&self, signer: Participant, proposal: &Proposal<D>) -> bool {
462 self.remembered(signer, Self::NOTARIZE_HAS_PROPOSAL)
463 || self
464 .notarize(signer)
465 .is_some_and(|vote| &vote.proposal == proposal)
466 }
467
468 pub(crate) fn has_finalize_for(&self, signer: Participant, proposal: &Proposal<D>) -> bool {
471 self.remembered(signer, Self::FINALIZE_HAS_PROPOSAL)
472 || self
473 .finalize(signer)
474 .is_some_and(|vote| &vote.proposal == proposal)
475 }
476
477 pub(crate) fn release_notarizes(&mut self, proposal: &Proposal<D>) {
479 if self.retain_votes_after_certification {
480 return;
481 }
482 Self::release(
483 self.participants,
484 &mut self.compacted,
485 &mut self.notarizes,
486 Self::NOTARIZE_SEEN,
487 Self::NOTARIZE_HAS_PROPOSAL,
488 |vote: &Notarize<S, D>| &vote.proposal == proposal,
489 );
490 }
491
492 pub(crate) fn release_nullifies(&mut self) {
494 if self.retain_votes_after_certification {
495 return;
496 }
497 Self::release(
498 self.participants,
499 &mut self.compacted,
500 &mut self.nullifies,
501 Self::NULLIFY_SEEN,
502 0,
503 |_| false,
504 );
505 }
506
507 pub(crate) fn release_finalizes(&mut self, proposal: &Proposal<D>) {
509 if self.retain_votes_after_certification {
510 return;
511 }
512 Self::release(
513 self.participants,
514 &mut self.compacted,
515 &mut self.finalizes,
516 Self::FINALIZE_SEEN,
517 Self::FINALIZE_HAS_PROPOSAL,
518 |vote: &Finalize<S, D>| &vote.proposal == proposal,
519 );
520 }
521}
522
523#[cfg(not(target_arch = "wasm32"))]
524impl<S: Scheme, D: Digest> VoteTracker<S, D> {
525 fn clear_compacted(&mut self, cleared: u8) {
526 for flags in &mut self.compacted {
527 *flags &= !cleared;
528 }
529 if self.compacted.iter().all(|&flags| flags == 0) {
530 self.compacted = Vec::new();
531 }
532 }
533
534 pub fn insert_notarize(&mut self, vote: Notarize<S, D>) -> bool {
536 self.notarizes.insert(vote)
537 }
538
539 pub fn insert_nullify(&mut self, vote: Nullify<S>) -> bool {
541 self.nullifies.insert(vote)
542 }
543
544 pub fn insert_finalize(&mut self, vote: Finalize<S, D>) -> bool {
546 self.finalizes.insert(vote)
547 }
548
549 pub fn notarize(&self, signer: Participant) -> Option<&Notarize<S, D>> {
551 self.notarizes.get(signer)
552 }
553
554 pub fn nullify(&self, signer: Participant) -> Option<&Nullify<S>> {
556 self.nullifies.get(signer)
557 }
558
559 pub fn finalize(&self, signer: Participant) -> Option<&Finalize<S, D>> {
561 self.finalizes.get(signer)
562 }
563
564 pub fn iter_notarizes(&self) -> impl Iterator<Item = &Notarize<S, D>> {
566 self.notarizes.iter()
567 }
568
569 pub fn iter_nullifies(&self) -> impl Iterator<Item = &Nullify<S>> {
571 self.nullifies.iter()
572 }
573
574 pub fn iter_finalizes(&self) -> impl Iterator<Item = &Finalize<S, D>> {
576 self.finalizes.iter()
577 }
578
579 pub fn len_notarizes(&self) -> u32 {
581 let len = self.notarizes.len();
582 u32::try_from(len).expect("too many notarize votes")
583 }
584
585 pub fn len_nullifies(&self) -> u32 {
587 let len = self.nullifies.len();
588 u32::try_from(len).expect("too many nullify votes")
589 }
590
591 pub fn len_finalizes(&self) -> u32 {
593 let len = self.finalizes.len();
594 u32::try_from(len).expect("too many finalize votes")
595 }
596
597 pub fn has_notarize(&self, signer: Participant) -> bool {
599 self.notarize(signer).is_some()
600 }
601
602 pub fn has_nullify(&self, signer: Participant) -> bool {
604 self.nullify(signer).is_some()
605 }
606
607 pub fn has_finalize(&self, signer: Participant) -> bool {
609 self.finalize(signer).is_some()
610 }
611
612 pub fn clear_notarizes(&mut self) {
614 self.notarizes.reset(self.participants);
615 self.clear_compacted(Self::NOTARIZE_SEEN | Self::NOTARIZE_HAS_PROPOSAL);
616 }
617
618 pub fn clear_finalizes(&mut self) {
620 self.finalizes.reset(self.participants);
621 self.clear_compacted(Self::FINALIZE_SEEN | Self::FINALIZE_HAS_PROPOSAL);
622 }
623}
624
625#[derive(Copy, Clone, Debug)]
630pub enum Subject<'a, D: Digest> {
631 Notarize { proposal: &'a Proposal<D> },
633 Nullify { round: Round },
635 Finalize { proposal: &'a Proposal<D> },
637}
638
639impl<D: Digest> Viewable for Subject<'_, D> {
640 fn view(&self) -> View {
641 match self {
642 Subject::Notarize { proposal } => proposal.view(),
643 Subject::Nullify { round } => round.view(),
644 Subject::Finalize { proposal } => proposal.view(),
645 }
646 }
647}
648
649#[derive(Clone, Debug, PartialEq)]
651pub enum Vote<S: Scheme, D: Digest> {
652 Notarize(Notarize<S, D>),
654 Nullify(Nullify<S>),
656 Finalize(Finalize<S, D>),
658}
659
660impl<S: Scheme, D: Digest> Write for Vote<S, D> {
661 fn write(&self, writer: &mut impl BufMut) {
662 match self {
663 Self::Notarize(v) => {
664 0u8.write(writer);
665 v.write(writer);
666 }
667 Self::Nullify(v) => {
668 1u8.write(writer);
669 v.write(writer);
670 }
671 Self::Finalize(v) => {
672 2u8.write(writer);
673 v.write(writer);
674 }
675 }
676 }
677}
678
679impl<S: Scheme, D: Digest> EncodeSize for Vote<S, D> {
680 fn encode_size(&self) -> usize {
681 1 + match self {
682 Self::Notarize(v) => v.encode_size(),
683 Self::Nullify(v) => v.encode_size(),
684 Self::Finalize(v) => v.encode_size(),
685 }
686 }
687}
688
689impl<S: Scheme, D: Digest> Read for Vote<S, D> {
690 type Cfg = ();
691
692 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
693 let tag = <u8>::read(reader)?;
694 match tag {
695 0 => {
696 let v = Notarize::read(reader)?;
697 Ok(Self::Notarize(v))
698 }
699 1 => {
700 let v = Nullify::read(reader)?;
701 Ok(Self::Nullify(v))
702 }
703 2 => {
704 let v = Finalize::read(reader)?;
705 Ok(Self::Finalize(v))
706 }
707 _ => Err(Error::Invalid("consensus::simplex::Vote", "Invalid type")),
708 }
709 }
710}
711
712impl<S: Scheme, D: Digest> Epochable for Vote<S, D> {
713 fn epoch(&self) -> Epoch {
714 match self {
715 Self::Notarize(v) => v.epoch(),
716 Self::Nullify(v) => v.epoch(),
717 Self::Finalize(v) => v.epoch(),
718 }
719 }
720}
721
722impl<S: Scheme, D: Digest> Viewable for Vote<S, D> {
723 fn view(&self) -> View {
724 match self {
725 Self::Notarize(v) => v.view(),
726 Self::Nullify(v) => v.view(),
727 Self::Finalize(v) => v.view(),
728 }
729 }
730}
731
732#[cfg(feature = "arbitrary")]
733impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Vote<S, D>
734where
735 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
736 D: for<'a> arbitrary::Arbitrary<'a>,
737{
738 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
739 let tag = u.int_in_range(0..=2)?;
740 match tag {
741 0 => {
742 let v = Notarize::arbitrary(u)?;
743 Ok(Self::Notarize(v))
744 }
745 1 => {
746 let v = Nullify::arbitrary(u)?;
747 Ok(Self::Nullify(v))
748 }
749 2 => {
750 let v = Finalize::arbitrary(u)?;
751 Ok(Self::Finalize(v))
752 }
753 _ => unreachable!(),
754 }
755 }
756}
757
758#[derive(Clone, Debug, PartialEq)]
760pub enum Certificate<S: Scheme, D: Digest> {
761 Notarization(Notarization<S, D>),
763 Nullification(Nullification<S>),
765 Finalization(Finalization<S, D>),
767}
768
769#[cfg(not(target_arch = "wasm32"))]
771#[derive(Clone, Copy, Debug, PartialEq, Eq)]
772pub(crate) enum Kind {
773 Notarization,
774 Nullification,
775 Finalization,
776}
777
778#[cfg(not(target_arch = "wasm32"))]
779impl std::fmt::Display for Kind {
780 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
782 f.write_str(match self {
783 Self::Notarization => "notarization",
784 Self::Nullification => "nullification",
785 Self::Finalization => "finalization",
786 })
787 }
788}
789
790#[cfg(not(target_arch = "wasm32"))]
791impl<S: Scheme, D: Digest> Certificate<S, D> {
792 pub(crate) const fn kind(&self) -> Kind {
794 match self {
795 Self::Notarization(_) => Kind::Notarization,
796 Self::Nullification(_) => Kind::Nullification,
797 Self::Finalization(_) => Kind::Finalization,
798 }
799 }
800}
801
802impl<S: Scheme, D: Digest> Write for Certificate<S, D> {
803 fn write(&self, writer: &mut impl BufMut) {
804 match self {
805 Self::Notarization(v) => {
806 0u8.write(writer);
807 v.write(writer);
808 }
809 Self::Nullification(v) => {
810 1u8.write(writer);
811 v.write(writer);
812 }
813 Self::Finalization(v) => {
814 2u8.write(writer);
815 v.write(writer);
816 }
817 }
818 }
819}
820
821impl<S: Scheme, D: Digest> EncodeSize for Certificate<S, D> {
822 fn encode_size(&self) -> usize {
823 1 + match self {
824 Self::Notarization(v) => v.encode_size(),
825 Self::Nullification(v) => v.encode_size(),
826 Self::Finalization(v) => v.encode_size(),
827 }
828 }
829}
830
831impl<S: Scheme, D: Digest> Read for Certificate<S, D> {
832 type Cfg = <S::Certificate as Read>::Cfg;
833
834 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
835 let tag = <u8>::read(reader)?;
836 match tag {
837 0 => {
838 let v = Notarization::read_cfg(reader, cfg)?;
839 Ok(Self::Notarization(v))
840 }
841 1 => {
842 let v = Nullification::read_cfg(reader, cfg)?;
843 Ok(Self::Nullification(v))
844 }
845 2 => {
846 let v = Finalization::read_cfg(reader, cfg)?;
847 Ok(Self::Finalization(v))
848 }
849 _ => Err(Error::Invalid(
850 "consensus::simplex::Certificate",
851 "Invalid type",
852 )),
853 }
854 }
855}
856
857impl<S: Scheme, D: Digest> Epochable for Certificate<S, D> {
858 fn epoch(&self) -> Epoch {
859 match self {
860 Self::Notarization(v) => v.epoch(),
861 Self::Nullification(v) => v.epoch(),
862 Self::Finalization(v) => v.epoch(),
863 }
864 }
865}
866
867impl<S: Scheme, D: Digest> Viewable for Certificate<S, D> {
868 fn view(&self) -> View {
869 match self {
870 Self::Notarization(v) => v.view(),
871 Self::Nullification(v) => v.view(),
872 Self::Finalization(v) => v.view(),
873 }
874 }
875}
876
877impl<S: Scheme, D: Digest> Certificate<S, D> {
878 pub fn verify<R: CryptoRng>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
880 where
881 S: scheme::Scheme<D>,
882 {
883 match self {
884 Self::Notarization(notarization) => notarization.verify(rng, scheme, strategy),
885 Self::Nullification(nullification) => {
886 nullification.verify::<_, D>(rng, scheme, strategy)
887 }
888 Self::Finalization(finalization) => finalization.verify(rng, scheme, strategy),
889 }
890 }
891}
892
893#[cfg(feature = "arbitrary")]
894impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Certificate<S, D>
895where
896 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
897 D: for<'a> arbitrary::Arbitrary<'a>,
898{
899 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
900 let tag = u.int_in_range(0..=2)?;
901 match tag {
902 0 => {
903 let v = Notarization::arbitrary(u)?;
904 Ok(Self::Notarization(v))
905 }
906 1 => {
907 let v = Nullification::arbitrary(u)?;
908 Ok(Self::Nullification(v))
909 }
910 2 => {
911 let v = Finalization::arbitrary(u)?;
912 Ok(Self::Finalization(v))
913 }
914 _ => unreachable!(),
915 }
916 }
917}
918
919#[derive(Clone, Debug, PartialEq)]
921pub enum Artifact<S: Scheme, D: Digest> {
922 Notarize(Notarize<S, D>),
924 Notarization(Notarization<S, D>),
926 Certification(Round, bool),
928 Nullify(Nullify<S>),
930 Nullification(Nullification<S>),
932 Finalize(Finalize<S, D>),
934 Finalization(Finalization<S, D>),
936}
937
938impl<S: Scheme, D: Digest> Write for Artifact<S, D> {
939 fn write(&self, writer: &mut impl BufMut) {
940 match self {
941 Self::Notarize(v) => {
942 0u8.write(writer);
943 v.write(writer);
944 }
945 Self::Notarization(v) => {
946 1u8.write(writer);
947 v.write(writer);
948 }
949 Self::Certification(r, b) => {
950 2u8.write(writer);
951 r.write(writer);
952 b.write(writer);
953 }
954 Self::Nullify(v) => {
955 3u8.write(writer);
956 v.write(writer);
957 }
958 Self::Nullification(v) => {
959 4u8.write(writer);
960 v.write(writer);
961 }
962 Self::Finalize(v) => {
963 5u8.write(writer);
964 v.write(writer);
965 }
966 Self::Finalization(v) => {
967 6u8.write(writer);
968 v.write(writer);
969 }
970 }
971 }
972}
973
974impl<S: Scheme, D: Digest> EncodeSize for Artifact<S, D> {
975 fn encode_size(&self) -> usize {
976 1 + match self {
977 Self::Notarize(v) => v.encode_size(),
978 Self::Notarization(v) => v.encode_size(),
979 Self::Certification(r, b) => r.encode_size() + b.encode_size(),
980 Self::Nullify(v) => v.encode_size(),
981 Self::Nullification(v) => v.encode_size(),
982 Self::Finalize(v) => v.encode_size(),
983 Self::Finalization(v) => v.encode_size(),
984 }
985 }
986}
987
988impl<S: Scheme, D: Digest> Read for Artifact<S, D> {
989 type Cfg = <S::Certificate as Read>::Cfg;
990
991 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
992 let tag = <u8>::read(reader)?;
993 match tag {
994 0 => {
995 let v = Notarize::read(reader)?;
996 Ok(Self::Notarize(v))
997 }
998 1 => {
999 let v = Notarization::read_cfg(reader, cfg)?;
1000 Ok(Self::Notarization(v))
1001 }
1002 2 => {
1003 let r = Round::read(reader)?;
1004 let b = bool::read(reader)?;
1005 Ok(Self::Certification(r, b))
1006 }
1007 3 => {
1008 let v = Nullify::read(reader)?;
1009 Ok(Self::Nullify(v))
1010 }
1011 4 => {
1012 let v = Nullification::read_cfg(reader, cfg)?;
1013 Ok(Self::Nullification(v))
1014 }
1015 5 => {
1016 let v = Finalize::read(reader)?;
1017 Ok(Self::Finalize(v))
1018 }
1019 6 => {
1020 let v = Finalization::read_cfg(reader, cfg)?;
1021 Ok(Self::Finalization(v))
1022 }
1023 _ => Err(Error::Invalid(
1024 "consensus::simplex::Artifact",
1025 "Invalid type",
1026 )),
1027 }
1028 }
1029}
1030
1031impl<S: Scheme, D: Digest> Epochable for Artifact<S, D> {
1032 fn epoch(&self) -> Epoch {
1033 match self {
1034 Self::Notarize(v) => v.epoch(),
1035 Self::Notarization(v) => v.epoch(),
1036 Self::Certification(r, _) => r.epoch(),
1037 Self::Nullify(v) => v.epoch(),
1038 Self::Nullification(v) => v.epoch(),
1039 Self::Finalize(v) => v.epoch(),
1040 Self::Finalization(v) => v.epoch(),
1041 }
1042 }
1043}
1044
1045impl<S: Scheme, D: Digest> Viewable for Artifact<S, D> {
1046 fn view(&self) -> View {
1047 match self {
1048 Self::Notarize(v) => v.view(),
1049 Self::Notarization(v) => v.view(),
1050 Self::Certification(r, _) => r.view(),
1051 Self::Nullify(v) => v.view(),
1052 Self::Nullification(v) => v.view(),
1053 Self::Finalize(v) => v.view(),
1054 Self::Finalization(v) => v.view(),
1055 }
1056 }
1057}
1058
1059impl<S: Scheme, D: Digest> From<Vote<S, D>> for Artifact<S, D> {
1060 fn from(vote: Vote<S, D>) -> Self {
1061 match vote {
1062 Vote::Notarize(v) => Self::Notarize(v),
1063 Vote::Nullify(v) => Self::Nullify(v),
1064 Vote::Finalize(v) => Self::Finalize(v),
1065 }
1066 }
1067}
1068
1069impl<S: Scheme, D: Digest> From<Certificate<S, D>> for Artifact<S, D> {
1070 fn from(cert: Certificate<S, D>) -> Self {
1071 match cert {
1072 Certificate::Notarization(v) => Self::Notarization(v),
1073 Certificate::Nullification(v) => Self::Nullification(v),
1074 Certificate::Finalization(v) => Self::Finalization(v),
1075 }
1076 }
1077}
1078
1079#[cfg(feature = "arbitrary")]
1080impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Artifact<S, D>
1081where
1082 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1083 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1084 D: for<'a> arbitrary::Arbitrary<'a>,
1085{
1086 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1087 let tag = u.int_in_range(0..=6)?;
1088 match tag {
1089 0 => {
1090 let v = Notarize::arbitrary(u)?;
1091 Ok(Self::Notarize(v))
1092 }
1093 1 => {
1094 let v = Notarization::arbitrary(u)?;
1095 Ok(Self::Notarization(v))
1096 }
1097 2 => {
1098 let r = Round::arbitrary(u)?;
1099 let b = bool::arbitrary(u)?;
1100 Ok(Self::Certification(r, b))
1101 }
1102 3 => {
1103 let v = Nullify::arbitrary(u)?;
1104 Ok(Self::Nullify(v))
1105 }
1106 4 => {
1107 let v = Nullification::arbitrary(u)?;
1108 Ok(Self::Nullification(v))
1109 }
1110 5 => {
1111 let v = Finalize::arbitrary(u)?;
1112 Ok(Self::Finalize(v))
1113 }
1114 6 => {
1115 let v = Finalization::arbitrary(u)?;
1116 Ok(Self::Finalization(v))
1117 }
1118 _ => unreachable!(),
1119 }
1120 }
1121}
1122
1123#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1126pub struct Proposal<D: Digest> {
1127 pub round: Round,
1129 pub parent: View,
1131 pub payload: D,
1133}
1134
1135impl<D: Digest> Proposal<D> {
1136 pub const fn new(round: Round, parent: View, payload: D) -> Self {
1138 Self {
1139 round,
1140 parent,
1141 payload,
1142 }
1143 }
1144}
1145
1146impl<D: Digest> Write for Proposal<D> {
1147 fn write(&self, writer: &mut impl BufMut) {
1148 self.round.write(writer);
1149 self.parent.write(writer);
1150 self.payload.write(writer)
1151 }
1152}
1153
1154impl<D: Digest> Read for Proposal<D> {
1155 type Cfg = ();
1156
1157 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1158 let round = Round::read(reader)?;
1159 let parent = View::read(reader)?;
1160 let payload = D::read(reader)?;
1161 Ok(Self {
1162 round,
1163 parent,
1164 payload,
1165 })
1166 }
1167}
1168
1169impl<D: Digest> EncodeSize for Proposal<D> {
1170 fn encode_size(&self) -> usize {
1171 self.round.encode_size() + self.parent.encode_size() + self.payload.encode_size()
1172 }
1173}
1174
1175impl<D: Digest> Epochable for Proposal<D> {
1176 fn epoch(&self) -> Epoch {
1177 self.round.epoch()
1178 }
1179}
1180
1181impl<D: Digest> Viewable for Proposal<D> {
1182 fn view(&self) -> View {
1183 self.round.view()
1184 }
1185}
1186
1187#[cfg(feature = "arbitrary")]
1188impl<D: Digest> arbitrary::Arbitrary<'_> for Proposal<D>
1189where
1190 D: for<'a> arbitrary::Arbitrary<'a>,
1191{
1192 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1193 let round = Round::arbitrary(u)?;
1194 let parent = View::arbitrary(u)?;
1195 let payload = D::arbitrary(u)?;
1196 Ok(Self {
1197 round,
1198 parent,
1199 payload,
1200 })
1201 }
1202}
1203
1204#[derive(Clone, Debug)]
1206pub struct Notarize<S: Scheme, D: Digest> {
1207 pub proposal: Proposal<D>,
1209 pub attestation: Attestation<S>,
1211}
1212
1213impl<S: Scheme, D: Digest> Notarize<S, D> {
1214 pub fn sign(scheme: &S, proposal: Proposal<D>) -> Option<Self>
1216 where
1217 S: scheme::Scheme<D>,
1218 {
1219 let attestation = scheme.sign::<D>(Subject::Notarize {
1220 proposal: &proposal,
1221 })?;
1222
1223 Some(Self {
1224 proposal,
1225 attestation,
1226 })
1227 }
1228
1229 pub fn verify<R>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
1233 where
1234 R: CryptoRng,
1235 S: scheme::Scheme<D>,
1236 {
1237 scheme.verify_attestation::<_, D>(
1238 rng,
1239 Subject::Notarize {
1240 proposal: &self.proposal,
1241 },
1242 &self.attestation,
1243 strategy,
1244 )
1245 }
1246
1247 pub const fn round(&self) -> Round {
1249 self.proposal.round
1250 }
1251}
1252
1253impl<S: Scheme, D: Digest> PartialEq for Notarize<S, D> {
1254 fn eq(&self, other: &Self) -> bool {
1255 self.proposal == other.proposal && self.attestation == other.attestation
1256 }
1257}
1258
1259impl<S: Scheme, D: Digest> Eq for Notarize<S, D> {}
1260
1261impl<S: Scheme, D: Digest> Hash for Notarize<S, D> {
1262 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1263 self.proposal.hash(state);
1264 self.attestation.hash(state);
1265 }
1266}
1267
1268impl<S: Scheme, D: Digest> Write for Notarize<S, D> {
1269 fn write(&self, writer: &mut impl BufMut) {
1270 self.proposal.write(writer);
1271 self.attestation.write(writer);
1272 }
1273}
1274
1275impl<S: Scheme, D: Digest> EncodeSize for Notarize<S, D> {
1276 fn encode_size(&self) -> usize {
1277 self.proposal.encode_size() + self.attestation.encode_size()
1278 }
1279}
1280
1281impl<S: Scheme, D: Digest> Read for Notarize<S, D> {
1282 type Cfg = ();
1283
1284 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1285 let proposal = Proposal::read(reader)?;
1286 let attestation = Attestation::read(reader)?;
1287
1288 Ok(Self {
1289 proposal,
1290 attestation,
1291 })
1292 }
1293}
1294
1295impl<S: Scheme, D: Digest> Attributable for Notarize<S, D> {
1296 fn signer(&self) -> Participant {
1297 self.attestation.signer
1298 }
1299}
1300
1301impl<S: Scheme, D: Digest> Epochable for Notarize<S, D> {
1302 fn epoch(&self) -> Epoch {
1303 self.proposal.epoch()
1304 }
1305}
1306
1307impl<S: Scheme, D: Digest> Viewable for Notarize<S, D> {
1308 fn view(&self) -> View {
1309 self.proposal.view()
1310 }
1311}
1312
1313#[cfg(feature = "arbitrary")]
1314impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Notarize<S, D>
1315where
1316 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1317 D: for<'a> arbitrary::Arbitrary<'a>,
1318{
1319 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1320 let proposal = Proposal::arbitrary(u)?;
1321 let attestation = Attestation::arbitrary(u)?;
1322 Ok(Self {
1323 proposal,
1324 attestation,
1325 })
1326 }
1327}
1328
1329pub fn verify_certificates<'a, R, S, D>(
1334 rng: &mut R,
1335 scheme: &S,
1336 certificates: &[(Subject<'a, D>, &'a S::Certificate)],
1337 strategy: &impl Strategy,
1338) -> Vec<bool>
1339where
1340 R: CryptoRng,
1341 S: CertificateVerifier<D>,
1342 D: Digest,
1343{
1344 scheme.verify_certificates_bisect::<_, D>(rng, certificates, strategy)
1345}
1346
1347#[derive(Clone, Debug)]
1354pub struct Notarization<S: Scheme, D: Digest> {
1355 pub proposal: Proposal<D>,
1357 pub certificate: S::Certificate,
1359}
1360
1361impl<S: Scheme, D: Digest> Notarization<S, D> {
1362 pub fn from_owned_notarizes<I>(
1365 scheme: &S,
1366 notarizes: NonEmpty<I>,
1367 strategy: &impl Strategy,
1368 ) -> Result<Self, AssemblyError>
1369 where
1370 I: Iterator<Item = Notarize<S, D>> + Send,
1371 {
1372 let (first, notarizes) = notarizes.into_parts();
1373 let Notarize {
1374 proposal,
1375 attestation,
1376 } = first;
1377 let attestations =
1378 NonEmpty::new(attestation, notarizes.map(|notarize| notarize.attestation));
1379 let certificate = scheme.assemble(attestations, strategy)?;
1380
1381 Ok(Self {
1382 proposal,
1383 certificate,
1384 })
1385 }
1386
1387 pub fn from_notarizes<'a, I>(
1389 scheme: &S,
1390 notarizes: NonEmpty<I>,
1391 strategy: &impl Strategy,
1392 ) -> Result<Self, AssemblyError>
1393 where
1394 I: Iterator<Item = &'a Notarize<S, D>> + Send,
1395 {
1396 Self::from_owned_notarizes(
1397 scheme,
1398 non_empty![@notarizes.into_iter().cloned()],
1399 strategy,
1400 )
1401 }
1402
1403 pub fn verify<R: CryptoRng>(
1407 &self,
1408 rng: &mut R,
1409 scheme: &impl CertificateVerifier<D, Certificate = S::Certificate>,
1410 strategy: &impl Strategy,
1411 ) -> bool {
1412 scheme.verify_certificate::<_, D>(
1413 rng,
1414 Subject::Notarize {
1415 proposal: &self.proposal,
1416 },
1417 &self.certificate,
1418 strategy,
1419 )
1420 }
1421
1422 pub const fn round(&self) -> Round {
1424 self.proposal.round
1425 }
1426}
1427
1428impl<S: Scheme, D: Digest> PartialEq for Notarization<S, D> {
1429 fn eq(&self, other: &Self) -> bool {
1430 self.proposal == other.proposal && self.certificate == other.certificate
1431 }
1432}
1433
1434impl<S: Scheme, D: Digest> Eq for Notarization<S, D> {}
1435
1436impl<S: Scheme, D: Digest> Hash for Notarization<S, D> {
1437 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1438 self.proposal.hash(state);
1439 self.certificate.hash(state);
1440 }
1441}
1442
1443impl<S: Scheme, D: Digest> Write for Notarization<S, D> {
1444 fn write(&self, writer: &mut impl BufMut) {
1445 self.proposal.write(writer);
1446 self.certificate.write(writer);
1447 }
1448}
1449
1450impl<S: Scheme, D: Digest> EncodeSize for Notarization<S, D> {
1451 fn encode_size(&self) -> usize {
1452 self.proposal.encode_size() + self.certificate.encode_size()
1453 }
1454}
1455
1456impl<S: Scheme, D: Digest> Read for Notarization<S, D> {
1457 type Cfg = <S::Certificate as Read>::Cfg;
1458
1459 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1460 let proposal = Proposal::read(reader)?;
1461 let certificate = S::Certificate::read_cfg(reader, cfg)?;
1462
1463 Ok(Self {
1464 proposal,
1465 certificate,
1466 })
1467 }
1468}
1469
1470impl<S: Scheme, D: Digest> Epochable for Notarization<S, D> {
1471 fn epoch(&self) -> Epoch {
1472 self.proposal.epoch()
1473 }
1474}
1475
1476impl<S: Scheme, D: Digest> Viewable for Notarization<S, D> {
1477 fn view(&self) -> View {
1478 self.proposal.view()
1479 }
1480}
1481
1482#[cfg(feature = "arbitrary")]
1483impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Notarization<S, D>
1484where
1485 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1486 D: for<'a> arbitrary::Arbitrary<'a>,
1487{
1488 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1489 let proposal = Proposal::arbitrary(u)?;
1490 let certificate = S::Certificate::arbitrary(u)?;
1491 Ok(Self {
1492 proposal,
1493 certificate,
1494 })
1495 }
1496}
1497
1498#[derive(Clone, Debug)]
1501pub struct Nullify<S: Scheme> {
1502 pub round: Round,
1504 pub attestation: Attestation<S>,
1506}
1507
1508impl<S: Scheme> PartialEq for Nullify<S> {
1509 fn eq(&self, other: &Self) -> bool {
1510 self.round == other.round && self.attestation == other.attestation
1511 }
1512}
1513
1514impl<S: Scheme> Eq for Nullify<S> {}
1515
1516impl<S: Scheme> Hash for Nullify<S> {
1517 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1518 self.round.hash(state);
1519 self.attestation.hash(state);
1520 }
1521}
1522
1523impl<S: Scheme> Nullify<S> {
1524 pub fn sign<D: Digest>(scheme: &S, round: Round) -> Option<Self>
1526 where
1527 S: scheme::Scheme<D>,
1528 {
1529 let attestation = scheme.sign::<D>(Subject::Nullify { round })?;
1530
1531 Some(Self { round, attestation })
1532 }
1533
1534 pub fn verify<R, D: Digest>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
1538 where
1539 R: CryptoRng,
1540 S: scheme::Scheme<D>,
1541 {
1542 scheme.verify_attestation::<_, D>(
1543 rng,
1544 Subject::Nullify { round: self.round },
1545 &self.attestation,
1546 strategy,
1547 )
1548 }
1549
1550 pub const fn round(&self) -> Round {
1552 self.round
1553 }
1554}
1555
1556impl<S: Scheme> Write for Nullify<S> {
1557 fn write(&self, writer: &mut impl BufMut) {
1558 self.round.write(writer);
1559 self.attestation.write(writer);
1560 }
1561}
1562
1563impl<S: Scheme> EncodeSize for Nullify<S> {
1564 fn encode_size(&self) -> usize {
1565 self.round.encode_size() + self.attestation.encode_size()
1566 }
1567}
1568
1569impl<S: Scheme> Read for Nullify<S> {
1570 type Cfg = ();
1571
1572 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1573 let round = Round::read(reader)?;
1574 let attestation = Attestation::read(reader)?;
1575
1576 Ok(Self { round, attestation })
1577 }
1578}
1579
1580impl<S: Scheme> Attributable for Nullify<S> {
1581 fn signer(&self) -> Participant {
1582 self.attestation.signer
1583 }
1584}
1585
1586impl<S: Scheme> Epochable for Nullify<S> {
1587 fn epoch(&self) -> Epoch {
1588 self.round.epoch()
1589 }
1590}
1591
1592impl<S: Scheme> Viewable for Nullify<S> {
1593 fn view(&self) -> View {
1594 self.round.view()
1595 }
1596}
1597
1598#[cfg(feature = "arbitrary")]
1599impl<S: Scheme> arbitrary::Arbitrary<'_> for Nullify<S>
1600where
1601 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1602{
1603 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1604 let round = Round::arbitrary(u)?;
1605 let attestation = Attestation::arbitrary(u)?;
1606 Ok(Self { round, attestation })
1607 }
1608}
1609
1610#[derive(Clone, Debug)]
1615pub struct Nullification<S: Scheme> {
1616 pub round: Round,
1618 pub certificate: S::Certificate,
1620}
1621
1622impl<S: Scheme> Nullification<S> {
1623 pub fn from_owned_nullifies<I>(
1626 scheme: &S,
1627 nullifies: NonEmpty<I>,
1628 strategy: &impl Strategy,
1629 ) -> Result<Self, AssemblyError>
1630 where
1631 I: Iterator<Item = Nullify<S>> + Send,
1632 {
1633 let (first, nullifies) = nullifies.into_parts();
1634 let round = first.round;
1635 let attestations = NonEmpty::new(
1636 first.attestation,
1637 nullifies.map(|nullify| nullify.attestation),
1638 );
1639 let certificate = scheme.assemble(attestations, strategy)?;
1640
1641 Ok(Self { round, certificate })
1642 }
1643
1644 pub fn from_nullifies<'a, I>(
1646 scheme: &S,
1647 nullifies: NonEmpty<I>,
1648 strategy: &impl Strategy,
1649 ) -> Result<Self, AssemblyError>
1650 where
1651 I: Iterator<Item = &'a Nullify<S>> + Send,
1652 {
1653 Self::from_owned_nullifies(
1654 scheme,
1655 non_empty![@nullifies.into_iter().cloned()],
1656 strategy,
1657 )
1658 }
1659
1660 pub fn verify<R: CryptoRng, D: Digest>(
1664 &self,
1665 rng: &mut R,
1666 scheme: &impl CertificateVerifier<D, Certificate = S::Certificate>,
1667 strategy: &impl Strategy,
1668 ) -> bool {
1669 scheme.verify_certificate::<_, D>(
1670 rng,
1671 Subject::Nullify { round: self.round },
1672 &self.certificate,
1673 strategy,
1674 )
1675 }
1676
1677 pub const fn round(&self) -> Round {
1679 self.round
1680 }
1681}
1682
1683impl<S: Scheme> PartialEq for Nullification<S> {
1684 fn eq(&self, other: &Self) -> bool {
1685 self.round == other.round && self.certificate == other.certificate
1686 }
1687}
1688
1689impl<S: Scheme> Eq for Nullification<S> {}
1690
1691impl<S: Scheme> Hash for Nullification<S> {
1692 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1693 self.round.hash(state);
1694 self.certificate.hash(state);
1695 }
1696}
1697
1698impl<S: Scheme> Write for Nullification<S> {
1699 fn write(&self, writer: &mut impl BufMut) {
1700 self.round.write(writer);
1701 self.certificate.write(writer);
1702 }
1703}
1704
1705impl<S: Scheme> EncodeSize for Nullification<S> {
1706 fn encode_size(&self) -> usize {
1707 self.round.encode_size() + self.certificate.encode_size()
1708 }
1709}
1710
1711impl<S: Scheme> Read for Nullification<S> {
1712 type Cfg = <S::Certificate as Read>::Cfg;
1713
1714 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1715 let round = Round::read(reader)?;
1716 let certificate = S::Certificate::read_cfg(reader, cfg)?;
1717
1718 Ok(Self { round, certificate })
1719 }
1720}
1721
1722impl<S: Scheme> Epochable for Nullification<S> {
1723 fn epoch(&self) -> Epoch {
1724 self.round.epoch()
1725 }
1726}
1727
1728impl<S: Scheme> Viewable for Nullification<S> {
1729 fn view(&self) -> View {
1730 self.round.view()
1731 }
1732}
1733
1734#[cfg(feature = "arbitrary")]
1735impl<S: Scheme> arbitrary::Arbitrary<'_> for Nullification<S>
1736where
1737 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
1738{
1739 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1740 let round = Round::arbitrary(u)?;
1741 let certificate = S::Certificate::arbitrary(u)?;
1742 Ok(Self { round, certificate })
1743 }
1744}
1745
1746#[derive(Clone, Debug)]
1750pub struct Finalize<S: Scheme, D: Digest> {
1751 pub proposal: Proposal<D>,
1753 pub attestation: Attestation<S>,
1755}
1756
1757impl<S: Scheme, D: Digest> Finalize<S, D> {
1758 pub fn sign(scheme: &S, proposal: Proposal<D>) -> Option<Self>
1760 where
1761 S: scheme::Scheme<D>,
1762 {
1763 let attestation = scheme.sign::<D>(Subject::Finalize {
1764 proposal: &proposal,
1765 })?;
1766
1767 Some(Self {
1768 proposal,
1769 attestation,
1770 })
1771 }
1772
1773 pub fn verify<R>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
1777 where
1778 R: CryptoRng,
1779 S: scheme::Scheme<D>,
1780 {
1781 scheme.verify_attestation::<_, D>(
1782 rng,
1783 Subject::Finalize {
1784 proposal: &self.proposal,
1785 },
1786 &self.attestation,
1787 strategy,
1788 )
1789 }
1790
1791 pub const fn round(&self) -> Round {
1793 self.proposal.round
1794 }
1795}
1796
1797impl<S: Scheme, D: Digest> PartialEq for Finalize<S, D> {
1798 fn eq(&self, other: &Self) -> bool {
1799 self.proposal == other.proposal && self.attestation == other.attestation
1800 }
1801}
1802
1803impl<S: Scheme, D: Digest> Eq for Finalize<S, D> {}
1804
1805impl<S: Scheme, D: Digest> Hash for Finalize<S, D> {
1806 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1807 self.proposal.hash(state);
1808 self.attestation.hash(state);
1809 }
1810}
1811
1812impl<S: Scheme, D: Digest> Write for Finalize<S, D> {
1813 fn write(&self, writer: &mut impl BufMut) {
1814 self.proposal.write(writer);
1815 self.attestation.write(writer);
1816 }
1817}
1818
1819impl<S: Scheme, D: Digest> EncodeSize for Finalize<S, D> {
1820 fn encode_size(&self) -> usize {
1821 self.proposal.encode_size() + self.attestation.encode_size()
1822 }
1823}
1824
1825impl<S: Scheme, D: Digest> Read for Finalize<S, D> {
1826 type Cfg = ();
1827
1828 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1829 let proposal = Proposal::read(reader)?;
1830 let attestation = Attestation::read(reader)?;
1831
1832 Ok(Self {
1833 proposal,
1834 attestation,
1835 })
1836 }
1837}
1838
1839impl<S: Scheme, D: Digest> Attributable for Finalize<S, D> {
1840 fn signer(&self) -> Participant {
1841 self.attestation.signer
1842 }
1843}
1844
1845impl<S: Scheme, D: Digest> Epochable for Finalize<S, D> {
1846 fn epoch(&self) -> Epoch {
1847 self.proposal.epoch()
1848 }
1849}
1850
1851impl<S: Scheme, D: Digest> Viewable for Finalize<S, D> {
1852 fn view(&self) -> View {
1853 self.proposal.view()
1854 }
1855}
1856
1857#[cfg(feature = "arbitrary")]
1858impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Finalize<S, D>
1859where
1860 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
1861 D: for<'a> arbitrary::Arbitrary<'a>,
1862{
1863 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1864 let proposal = Proposal::arbitrary(u)?;
1865 let attestation = Attestation::arbitrary(u)?;
1866 Ok(Self {
1867 proposal,
1868 attestation,
1869 })
1870 }
1871}
1872
1873#[derive(Clone, Debug)]
1880pub struct Finalization<S: Scheme, D: Digest> {
1881 pub proposal: Proposal<D>,
1883 pub certificate: S::Certificate,
1885}
1886
1887impl<S: Scheme, D: Digest> Finalization<S, D> {
1888 pub fn from_owned_finalizes<I>(
1891 scheme: &S,
1892 finalizes: NonEmpty<I>,
1893 strategy: &impl Strategy,
1894 ) -> Result<Self, AssemblyError>
1895 where
1896 I: Iterator<Item = Finalize<S, D>> + Send,
1897 {
1898 let (first, finalizes) = finalizes.into_parts();
1899 let Finalize {
1900 proposal,
1901 attestation,
1902 } = first;
1903 let attestations =
1904 NonEmpty::new(attestation, finalizes.map(|finalize| finalize.attestation));
1905 let certificate = scheme.assemble(attestations, strategy)?;
1906
1907 Ok(Self {
1908 proposal,
1909 certificate,
1910 })
1911 }
1912
1913 pub fn from_finalizes<'a, I>(
1915 scheme: &S,
1916 finalizes: NonEmpty<I>,
1917 strategy: &impl Strategy,
1918 ) -> Result<Self, AssemblyError>
1919 where
1920 I: Iterator<Item = &'a Finalize<S, D>> + Send,
1921 {
1922 Self::from_owned_finalizes(
1923 scheme,
1924 non_empty![@finalizes.into_iter().cloned()],
1925 strategy,
1926 )
1927 }
1928
1929 pub fn verify<R: CryptoRng>(
1933 &self,
1934 rng: &mut R,
1935 scheme: &impl CertificateVerifier<D, Certificate = S::Certificate>,
1936 strategy: &impl Strategy,
1937 ) -> bool {
1938 scheme.verify_certificate::<_, D>(
1939 rng,
1940 Subject::Finalize {
1941 proposal: &self.proposal,
1942 },
1943 &self.certificate,
1944 strategy,
1945 )
1946 }
1947
1948 pub const fn round(&self) -> Round {
1950 self.proposal.round
1951 }
1952}
1953
1954impl<S: Scheme, D: Digest> PartialEq for Finalization<S, D> {
1955 fn eq(&self, other: &Self) -> bool {
1956 self.proposal == other.proposal && self.certificate == other.certificate
1957 }
1958}
1959
1960impl<S: Scheme, D: Digest> Eq for Finalization<S, D> {}
1961
1962impl<S: Scheme, D: Digest> Hash for Finalization<S, D> {
1963 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1964 self.proposal.hash(state);
1965 self.certificate.hash(state);
1966 }
1967}
1968
1969impl<S: Scheme, D: Digest> Write for Finalization<S, D> {
1970 fn write(&self, writer: &mut impl BufMut) {
1971 self.proposal.write(writer);
1972 self.certificate.write(writer);
1973 }
1974}
1975
1976impl<S: Scheme, D: Digest> EncodeSize for Finalization<S, D> {
1977 fn encode_size(&self) -> usize {
1978 self.proposal.encode_size() + self.certificate.encode_size()
1979 }
1980}
1981
1982impl<S: Scheme, D: Digest> Read for Finalization<S, D> {
1983 type Cfg = <S::Certificate as Read>::Cfg;
1984
1985 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1986 let proposal = Proposal::read(reader)?;
1987 let certificate = S::Certificate::read_cfg(reader, cfg)?;
1988
1989 Ok(Self {
1990 proposal,
1991 certificate,
1992 })
1993 }
1994}
1995
1996impl<S: Scheme, D: Digest> Epochable for Finalization<S, D> {
1997 fn epoch(&self) -> Epoch {
1998 self.proposal.epoch()
1999 }
2000}
2001
2002impl<S: Scheme, D: Digest> Viewable for Finalization<S, D> {
2003 fn view(&self) -> View {
2004 self.proposal.view()
2005 }
2006}
2007
2008#[cfg(feature = "arbitrary")]
2009impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Finalization<S, D>
2010where
2011 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
2012 D: for<'a> arbitrary::Arbitrary<'a>,
2013{
2014 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2015 let proposal = Proposal::arbitrary(u)?;
2016 let certificate = S::Certificate::arbitrary(u)?;
2017 Ok(Self {
2018 proposal,
2019 certificate,
2020 })
2021 }
2022}
2023
2024#[derive(Clone, Debug, PartialEq)]
2027pub enum Backfiller<S: Scheme, D: Digest> {
2028 Request(Request),
2030 Response(Response<S, D>),
2032}
2033
2034impl<S: Scheme, D: Digest> Write for Backfiller<S, D> {
2035 fn write(&self, writer: &mut impl BufMut) {
2036 match self {
2037 Self::Request(request) => {
2038 0u8.write(writer);
2039 request.write(writer);
2040 }
2041 Self::Response(response) => {
2042 1u8.write(writer);
2043 response.write(writer);
2044 }
2045 }
2046 }
2047}
2048
2049impl<S: Scheme, D: Digest> EncodeSize for Backfiller<S, D> {
2050 fn encode_size(&self) -> usize {
2051 1 + match self {
2052 Self::Request(v) => v.encode_size(),
2053 Self::Response(v) => v.encode_size(),
2054 }
2055 }
2056}
2057
2058impl<S: Scheme, D: Digest> Read for Backfiller<S, D> {
2059 type Cfg = (usize, <S::Certificate as Read>::Cfg);
2060
2061 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
2062 let tag = <u8>::read(reader)?;
2063 match tag {
2064 0 => {
2065 let (max_len, _) = cfg;
2066 let v = Request::read_cfg(reader, max_len)?;
2067 Ok(Self::Request(v))
2068 }
2069 1 => {
2070 let v = Response::<S, D>::read_cfg(reader, cfg)?;
2071 Ok(Self::Response(v))
2072 }
2073 _ => Err(Error::Invalid(
2074 "consensus::simplex::Backfiller",
2075 "Invalid type",
2076 )),
2077 }
2078 }
2079}
2080
2081#[cfg(feature = "arbitrary")]
2082impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Backfiller<S, D>
2083where
2084 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
2085 D: for<'a> arbitrary::Arbitrary<'a>,
2086{
2087 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2088 let tag = u.int_in_range(0..=1)?;
2089 match tag {
2090 0 => {
2091 let v = Request::arbitrary(u)?;
2092 Ok(Self::Request(v))
2093 }
2094 1 => {
2095 let v = Response::<S, D>::arbitrary(u)?;
2096 Ok(Self::Response(v))
2097 }
2098 _ => unreachable!(),
2099 }
2100 }
2101}
2102
2103#[derive(Clone, Debug, PartialEq)]
2106#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2107pub struct Request {
2108 pub id: u64,
2110 pub notarizations: Vec<View>,
2112 pub nullifications: Vec<View>,
2114}
2115
2116impl Request {
2117 pub const fn new(id: u64, notarizations: Vec<View>, nullifications: Vec<View>) -> Self {
2119 Self {
2120 id,
2121 notarizations,
2122 nullifications,
2123 }
2124 }
2125}
2126
2127impl Write for Request {
2128 fn write(&self, writer: &mut impl BufMut) {
2129 UInt(self.id).write(writer);
2130 self.notarizations.write(writer);
2131 self.nullifications.write(writer);
2132 }
2133}
2134
2135impl EncodeSize for Request {
2136 fn encode_size(&self) -> usize {
2137 UInt(self.id).encode_size()
2138 + self.notarizations.encode_size()
2139 + self.nullifications.encode_size()
2140 }
2141}
2142
2143impl Read for Request {
2144 type Cfg = usize;
2145
2146 fn read_cfg(reader: &mut impl Buf, max_len: &usize) -> Result<Self, Error> {
2147 let id = UInt::read(reader)?.into();
2148 let mut views = HashSet::new();
2149 let notarizations = Vec::<View>::read_range(reader, ..=*max_len)?;
2150 for view in notarizations.iter() {
2151 if !views.insert(view) {
2152 return Err(Error::Invalid(
2153 "consensus::simplex::Request",
2154 "Duplicate notarization",
2155 ));
2156 }
2157 }
2158 let remaining = max_len - notarizations.len();
2159 views.clear();
2160 let nullifications = Vec::<View>::read_range(reader, ..=remaining)?;
2161 for view in nullifications.iter() {
2162 if !views.insert(view) {
2163 return Err(Error::Invalid(
2164 "consensus::simplex::Request",
2165 "Duplicate nullification",
2166 ));
2167 }
2168 }
2169 Ok(Self {
2170 id,
2171 notarizations,
2172 nullifications,
2173 })
2174 }
2175}
2176
2177#[derive(Clone, Debug, PartialEq)]
2180pub struct Response<S: Scheme, D: Digest> {
2181 pub id: u64,
2183 pub notarizations: Vec<Notarization<S, D>>,
2185 pub nullifications: Vec<Nullification<S>>,
2187}
2188
2189impl<S: Scheme, D: Digest> Response<S, D> {
2190 pub const fn new(
2192 id: u64,
2193 notarizations: Vec<Notarization<S, D>>,
2194 nullifications: Vec<Nullification<S>>,
2195 ) -> Self {
2196 Self {
2197 id,
2198 notarizations,
2199 nullifications,
2200 }
2201 }
2202
2203 pub fn verify<R: CryptoRng>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
2205 where
2206 S: scheme::Scheme<D>,
2207 {
2208 if self.notarizations.is_empty() && self.nullifications.is_empty() {
2211 return true;
2212 }
2213
2214 let notarizations = self.notarizations.iter().map(|notarization| {
2215 let context = Subject::Notarize {
2216 proposal: ¬arization.proposal,
2217 };
2218
2219 (context, ¬arization.certificate)
2220 });
2221
2222 let nullifications = self.nullifications.iter().map(|nullification| {
2223 let context = Subject::Nullify {
2224 round: nullification.round,
2225 };
2226
2227 (context, &nullification.certificate)
2228 });
2229
2230 let certificates = NonEmpty::try_new(notarizations.chain(nullifications))
2231 .expect("non-empty response must contain a certificate");
2232
2233 scheme.verify_certificates::<_, D, _>(rng, certificates, strategy)
2234 }
2235}
2236
2237impl<S: Scheme, D: Digest> Write for Response<S, D> {
2238 fn write(&self, writer: &mut impl BufMut) {
2239 UInt(self.id).write(writer);
2240 self.notarizations.write(writer);
2241 self.nullifications.write(writer);
2242 }
2243}
2244
2245impl<S: Scheme, D: Digest> EncodeSize for Response<S, D> {
2246 fn encode_size(&self) -> usize {
2247 UInt(self.id).encode_size()
2248 + self.notarizations.encode_size()
2249 + self.nullifications.encode_size()
2250 }
2251}
2252
2253impl<S: Scheme, D: Digest> Read for Response<S, D> {
2254 type Cfg = (usize, <S::Certificate as Read>::Cfg);
2255
2256 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
2257 let (max_len, certificate_cfg) = cfg;
2258 let id = UInt::read(reader)?.into();
2259 let mut views = HashSet::new();
2260 let notarizations = Vec::<Notarization<S, D>>::read_cfg(
2261 reader,
2262 &((..=*max_len).into(), certificate_cfg.clone()),
2263 )?;
2264 for notarization in notarizations.iter() {
2265 if !views.insert(notarization.view()) {
2266 return Err(Error::Invalid(
2267 "consensus::simplex::Response",
2268 "Duplicate notarization",
2269 ));
2270 }
2271 }
2272 let remaining = max_len - notarizations.len();
2273 views.clear();
2274 let nullifications = Vec::<Nullification<S>>::read_cfg(
2275 reader,
2276 &((..=remaining).into(), certificate_cfg.clone()),
2277 )?;
2278 for nullification in nullifications.iter() {
2279 if !views.insert(nullification.view()) {
2280 return Err(Error::Invalid(
2281 "consensus::simplex::Response",
2282 "Duplicate nullification",
2283 ));
2284 }
2285 }
2286 Ok(Self {
2287 id,
2288 notarizations,
2289 nullifications,
2290 })
2291 }
2292}
2293
2294#[cfg(feature = "arbitrary")]
2295impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Response<S, D>
2296where
2297 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
2298 D: for<'a> arbitrary::Arbitrary<'a>,
2299{
2300 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2301 let id = u.arbitrary()?;
2302 let notarizations = u.arbitrary()?;
2303 let nullifications = u.arbitrary()?;
2304 Ok(Self {
2305 id,
2306 notarizations,
2307 nullifications,
2308 })
2309 }
2310}
2311
2312#[derive(Clone, Debug)]
2330pub enum Activity<S: Scheme, D: Digest> {
2331 Notarize(Notarize<S, D>),
2333 Notarization(Notarization<S, D>),
2335 Certification(Notarization<S, D>),
2337 Nullify(Nullify<S>),
2339 Nullification(Nullification<S>),
2341 Finalize(Finalize<S, D>),
2343 Finalization(Finalization<S, D>),
2345 ConflictingNotarize(ConflictingNotarize<S, D>),
2347 ConflictingFinalize(ConflictingFinalize<S, D>),
2349 NullifyFinalize(NullifyFinalize<S, D>),
2351}
2352
2353impl<S: Scheme, D: Digest> PartialEq for Activity<S, D> {
2354 fn eq(&self, other: &Self) -> bool {
2355 match (self, other) {
2356 (Self::Notarize(a), Self::Notarize(b)) => a == b,
2357 (Self::Notarization(a), Self::Notarization(b)) => a == b,
2358 (Self::Certification(a), Self::Certification(b)) => a == b,
2359 (Self::Nullify(a), Self::Nullify(b)) => a == b,
2360 (Self::Nullification(a), Self::Nullification(b)) => a == b,
2361 (Self::Finalize(a), Self::Finalize(b)) => a == b,
2362 (Self::Finalization(a), Self::Finalization(b)) => a == b,
2363 (Self::ConflictingNotarize(a), Self::ConflictingNotarize(b)) => a == b,
2364 (Self::ConflictingFinalize(a), Self::ConflictingFinalize(b)) => a == b,
2365 (Self::NullifyFinalize(a), Self::NullifyFinalize(b)) => a == b,
2366 _ => false,
2367 }
2368 }
2369}
2370
2371impl<S: Scheme, D: Digest> Eq for Activity<S, D> {}
2372
2373impl<S: Scheme, D: Digest> Hash for Activity<S, D> {
2374 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2375 match self {
2376 Self::Notarize(v) => {
2377 0u8.hash(state);
2378 v.hash(state);
2379 }
2380 Self::Notarization(v) => {
2381 1u8.hash(state);
2382 v.hash(state);
2383 }
2384 Self::Certification(v) => {
2385 2u8.hash(state);
2386 v.hash(state);
2387 }
2388 Self::Nullify(v) => {
2389 3u8.hash(state);
2390 v.hash(state);
2391 }
2392 Self::Nullification(v) => {
2393 4u8.hash(state);
2394 v.hash(state);
2395 }
2396 Self::Finalize(v) => {
2397 5u8.hash(state);
2398 v.hash(state);
2399 }
2400 Self::Finalization(v) => {
2401 6u8.hash(state);
2402 v.hash(state);
2403 }
2404 Self::ConflictingNotarize(v) => {
2405 7u8.hash(state);
2406 v.hash(state);
2407 }
2408 Self::ConflictingFinalize(v) => {
2409 8u8.hash(state);
2410 v.hash(state);
2411 }
2412 Self::NullifyFinalize(v) => {
2413 9u8.hash(state);
2414 v.hash(state);
2415 }
2416 }
2417 }
2418}
2419
2420impl<S: Scheme, D: Digest> Activity<S, D> {
2421 pub const fn verified(&self) -> bool {
2423 match self {
2424 Self::Notarize(_) => false,
2425 Self::Notarization(_) => true,
2426 Self::Certification(_) => false,
2427 Self::Nullify(_) => false,
2428 Self::Nullification(_) => true,
2429 Self::Finalize(_) => false,
2430 Self::Finalization(_) => true,
2431 Self::ConflictingNotarize(_) => false,
2432 Self::ConflictingFinalize(_) => false,
2433 Self::NullifyFinalize(_) => false,
2434 }
2435 }
2436
2437 pub fn verify<R: CryptoRng>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
2443 where
2444 S: scheme::Scheme<D>,
2445 {
2446 match self {
2447 Self::Notarize(n) => n.verify(rng, scheme, strategy),
2448 Self::Notarization(n) => n.verify(rng, scheme, strategy),
2449 Self::Certification(n) => n.verify(rng, scheme, strategy),
2450 Self::Nullify(n) => n.verify(rng, scheme, strategy),
2451 Self::Nullification(n) => n.verify(rng, scheme, strategy),
2452 Self::Finalize(f) => f.verify(rng, scheme, strategy),
2453 Self::Finalization(f) => f.verify(rng, scheme, strategy),
2454 Self::ConflictingNotarize(c) => c.verify(rng, scheme, strategy),
2455 Self::ConflictingFinalize(c) => c.verify(rng, scheme, strategy),
2456 Self::NullifyFinalize(c) => c.verify(rng, scheme, strategy),
2457 }
2458 }
2459}
2460
2461impl<S: Scheme, D: Digest> Write for Activity<S, D> {
2462 fn write(&self, writer: &mut impl BufMut) {
2463 match self {
2464 Self::Notarize(v) => {
2465 0u8.write(writer);
2466 v.write(writer);
2467 }
2468 Self::Notarization(v) => {
2469 1u8.write(writer);
2470 v.write(writer);
2471 }
2472 Self::Certification(v) => {
2473 2u8.write(writer);
2474 v.write(writer);
2475 }
2476 Self::Nullify(v) => {
2477 3u8.write(writer);
2478 v.write(writer);
2479 }
2480 Self::Nullification(v) => {
2481 4u8.write(writer);
2482 v.write(writer);
2483 }
2484 Self::Finalize(v) => {
2485 5u8.write(writer);
2486 v.write(writer);
2487 }
2488 Self::Finalization(v) => {
2489 6u8.write(writer);
2490 v.write(writer);
2491 }
2492 Self::ConflictingNotarize(v) => {
2493 7u8.write(writer);
2494 v.write(writer);
2495 }
2496 Self::ConflictingFinalize(v) => {
2497 8u8.write(writer);
2498 v.write(writer);
2499 }
2500 Self::NullifyFinalize(v) => {
2501 9u8.write(writer);
2502 v.write(writer);
2503 }
2504 }
2505 }
2506}
2507
2508impl<S: Scheme, D: Digest> EncodeSize for Activity<S, D> {
2509 fn encode_size(&self) -> usize {
2510 1 + match self {
2511 Self::Notarize(v) => v.encode_size(),
2512 Self::Notarization(v) => v.encode_size(),
2513 Self::Certification(v) => v.encode_size(),
2514 Self::Nullify(v) => v.encode_size(),
2515 Self::Nullification(v) => v.encode_size(),
2516 Self::Finalize(v) => v.encode_size(),
2517 Self::Finalization(v) => v.encode_size(),
2518 Self::ConflictingNotarize(v) => v.encode_size(),
2519 Self::ConflictingFinalize(v) => v.encode_size(),
2520 Self::NullifyFinalize(v) => v.encode_size(),
2521 }
2522 }
2523}
2524
2525impl<S: Scheme, D: Digest> Read for Activity<S, D> {
2526 type Cfg = <S::Certificate as Read>::Cfg;
2527
2528 fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
2529 let tag = <u8>::read(reader)?;
2530 match tag {
2531 0 => {
2532 let v = Notarize::<S, D>::read(reader)?;
2533 Ok(Self::Notarize(v))
2534 }
2535 1 => {
2536 let v = Notarization::<S, D>::read_cfg(reader, cfg)?;
2537 Ok(Self::Notarization(v))
2538 }
2539 2 => {
2540 let v = Notarization::<S, D>::read_cfg(reader, cfg)?;
2541 Ok(Self::Certification(v))
2542 }
2543 3 => {
2544 let v = Nullify::<S>::read(reader)?;
2545 Ok(Self::Nullify(v))
2546 }
2547 4 => {
2548 let v = Nullification::<S>::read_cfg(reader, cfg)?;
2549 Ok(Self::Nullification(v))
2550 }
2551 5 => {
2552 let v = Finalize::<S, D>::read(reader)?;
2553 Ok(Self::Finalize(v))
2554 }
2555 6 => {
2556 let v = Finalization::<S, D>::read_cfg(reader, cfg)?;
2557 Ok(Self::Finalization(v))
2558 }
2559 7 => {
2560 let v = ConflictingNotarize::<S, D>::read(reader)?;
2561 Ok(Self::ConflictingNotarize(v))
2562 }
2563 8 => {
2564 let v = ConflictingFinalize::<S, D>::read(reader)?;
2565 Ok(Self::ConflictingFinalize(v))
2566 }
2567 9 => {
2568 let v = NullifyFinalize::<S, D>::read(reader)?;
2569 Ok(Self::NullifyFinalize(v))
2570 }
2571 _ => Err(Error::Invalid(
2572 "consensus::simplex::Activity",
2573 "Invalid type",
2574 )),
2575 }
2576 }
2577}
2578
2579impl<S: Scheme, D: Digest> Epochable for Activity<S, D> {
2580 fn epoch(&self) -> Epoch {
2581 match self {
2582 Self::Notarize(v) => v.epoch(),
2583 Self::Notarization(v) => v.epoch(),
2584 Self::Certification(v) => v.epoch(),
2585 Self::Nullify(v) => v.epoch(),
2586 Self::Nullification(v) => v.epoch(),
2587 Self::Finalize(v) => v.epoch(),
2588 Self::Finalization(v) => v.epoch(),
2589 Self::ConflictingNotarize(v) => v.epoch(),
2590 Self::ConflictingFinalize(v) => v.epoch(),
2591 Self::NullifyFinalize(v) => v.epoch(),
2592 }
2593 }
2594}
2595
2596impl<S: Scheme, D: Digest> Viewable for Activity<S, D> {
2597 fn view(&self) -> View {
2598 match self {
2599 Self::Notarize(v) => v.view(),
2600 Self::Notarization(v) => v.view(),
2601 Self::Certification(v) => v.view(),
2602 Self::Nullify(v) => v.view(),
2603 Self::Nullification(v) => v.view(),
2604 Self::Finalize(v) => v.view(),
2605 Self::Finalization(v) => v.view(),
2606 Self::ConflictingNotarize(v) => v.view(),
2607 Self::ConflictingFinalize(v) => v.view(),
2608 Self::NullifyFinalize(v) => v.view(),
2609 }
2610 }
2611}
2612
2613#[cfg(feature = "arbitrary")]
2614impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for Activity<S, D>
2615where
2616 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2617 S::Certificate: for<'a> arbitrary::Arbitrary<'a>,
2618 D: for<'a> arbitrary::Arbitrary<'a>,
2619{
2620 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2621 let tag = u.int_in_range(0..=9)?;
2622 match tag {
2623 0 => {
2624 let v = Notarize::<S, D>::arbitrary(u)?;
2625 Ok(Self::Notarize(v))
2626 }
2627 1 => {
2628 let v = Notarization::<S, D>::arbitrary(u)?;
2629 Ok(Self::Notarization(v))
2630 }
2631 2 => {
2632 let v = Notarization::<S, D>::arbitrary(u)?;
2633 Ok(Self::Certification(v))
2634 }
2635 3 => {
2636 let v = Nullify::<S>::arbitrary(u)?;
2637 Ok(Self::Nullify(v))
2638 }
2639 4 => {
2640 let v = Nullification::<S>::arbitrary(u)?;
2641 Ok(Self::Nullification(v))
2642 }
2643 5 => {
2644 let v = Finalize::<S, D>::arbitrary(u)?;
2645 Ok(Self::Finalize(v))
2646 }
2647 6 => {
2648 let v = Finalization::<S, D>::arbitrary(u)?;
2649 Ok(Self::Finalization(v))
2650 }
2651 7 => {
2652 let v = ConflictingNotarize::<S, D>::arbitrary(u)?;
2653 Ok(Self::ConflictingNotarize(v))
2654 }
2655 8 => {
2656 let v = ConflictingFinalize::<S, D>::arbitrary(u)?;
2657 Ok(Self::ConflictingFinalize(v))
2658 }
2659 9 => {
2660 let v = NullifyFinalize::<S, D>::arbitrary(u)?;
2661 Ok(Self::NullifyFinalize(v))
2662 }
2663 _ => unreachable!(),
2664 }
2665 }
2666}
2667
2668#[derive(Clone, Debug)]
2671pub struct ConflictingNotarize<S: Scheme, D: Digest> {
2672 notarize_1: Notarize<S, D>,
2674 notarize_2: Notarize<S, D>,
2676}
2677
2678impl<S: Scheme, D: Digest> PartialEq for ConflictingNotarize<S, D> {
2679 fn eq(&self, other: &Self) -> bool {
2680 self.notarize_1 == other.notarize_1 && self.notarize_2 == other.notarize_2
2681 }
2682}
2683
2684impl<S: Scheme, D: Digest> Eq for ConflictingNotarize<S, D> {}
2685
2686impl<S: Scheme, D: Digest> Hash for ConflictingNotarize<S, D> {
2687 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2688 self.notarize_1.hash(state);
2689 self.notarize_2.hash(state);
2690 }
2691}
2692
2693impl<S: Scheme, D: Digest> ConflictingNotarize<S, D> {
2694 pub fn new(notarize_1: Notarize<S, D>, notarize_2: Notarize<S, D>) -> Self {
2701 assert_eq!(notarize_1.round(), notarize_2.round());
2702 assert_eq!(notarize_1.signer(), notarize_2.signer());
2703 assert_ne!(
2704 notarize_1.proposal, notarize_2.proposal,
2705 "proposals must differ to constitute conflicting evidence"
2706 );
2707
2708 Self {
2709 notarize_1,
2710 notarize_2,
2711 }
2712 }
2713
2714 pub fn verify<R>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
2716 where
2717 R: CryptoRng,
2718 S: scheme::Scheme<D>,
2719 {
2720 self.notarize_1.verify(rng, scheme, strategy)
2721 && self.notarize_2.verify(rng, scheme, strategy)
2722 }
2723}
2724
2725impl<S: Scheme, D: Digest> Attributable for ConflictingNotarize<S, D> {
2726 fn signer(&self) -> Participant {
2727 self.notarize_1.signer()
2728 }
2729}
2730
2731impl<S: Scheme, D: Digest> Epochable for ConflictingNotarize<S, D> {
2732 fn epoch(&self) -> Epoch {
2733 self.notarize_1.epoch()
2734 }
2735}
2736
2737impl<S: Scheme, D: Digest> Viewable for ConflictingNotarize<S, D> {
2738 fn view(&self) -> View {
2739 self.notarize_1.view()
2740 }
2741}
2742
2743impl<S: Scheme, D: Digest> Write for ConflictingNotarize<S, D> {
2744 fn write(&self, writer: &mut impl BufMut) {
2745 self.notarize_1.write(writer);
2746 self.notarize_2.write(writer);
2747 }
2748}
2749
2750impl<S: Scheme, D: Digest> Read for ConflictingNotarize<S, D> {
2751 type Cfg = ();
2752
2753 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2754 let notarize_1 = Notarize::read(reader)?;
2755 let notarize_2 = Notarize::read(reader)?;
2756
2757 if notarize_1.signer() != notarize_2.signer()
2758 || notarize_1.round() != notarize_2.round()
2759 || notarize_1.proposal == notarize_2.proposal
2760 {
2761 return Err(Error::Invalid(
2762 "consensus::simplex::ConflictingNotarize",
2763 "invalid conflicting notarize",
2764 ));
2765 }
2766
2767 Ok(Self {
2768 notarize_1,
2769 notarize_2,
2770 })
2771 }
2772}
2773
2774impl<S: Scheme, D: Digest> EncodeSize for ConflictingNotarize<S, D> {
2775 fn encode_size(&self) -> usize {
2776 self.notarize_1.encode_size() + self.notarize_2.encode_size()
2777 }
2778}
2779
2780#[cfg(feature = "arbitrary")]
2781impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for ConflictingNotarize<S, D>
2782where
2783 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2784 D: for<'a> arbitrary::Arbitrary<'a>,
2785{
2786 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2787 let notarize_1 = Notarize::arbitrary(u)?;
2788 let notarize_2 = Notarize::arbitrary(u)?;
2789 Ok(Self {
2790 notarize_1,
2791 notarize_2,
2792 })
2793 }
2794}
2795
2796#[derive(Clone, Debug)]
2799pub struct ConflictingFinalize<S: Scheme, D: Digest> {
2800 finalize_1: Finalize<S, D>,
2802 finalize_2: Finalize<S, D>,
2804}
2805
2806impl<S: Scheme, D: Digest> PartialEq for ConflictingFinalize<S, D> {
2807 fn eq(&self, other: &Self) -> bool {
2808 self.finalize_1 == other.finalize_1 && self.finalize_2 == other.finalize_2
2809 }
2810}
2811
2812impl<S: Scheme, D: Digest> Eq for ConflictingFinalize<S, D> {}
2813
2814impl<S: Scheme, D: Digest> Hash for ConflictingFinalize<S, D> {
2815 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2816 self.finalize_1.hash(state);
2817 self.finalize_2.hash(state);
2818 }
2819}
2820
2821impl<S: Scheme, D: Digest> ConflictingFinalize<S, D> {
2822 pub fn new(finalize_1: Finalize<S, D>, finalize_2: Finalize<S, D>) -> Self {
2829 assert_eq!(finalize_1.round(), finalize_2.round());
2830 assert_eq!(finalize_1.signer(), finalize_2.signer());
2831 assert_ne!(
2832 finalize_1.proposal, finalize_2.proposal,
2833 "proposals must differ to constitute conflicting evidence"
2834 );
2835
2836 Self {
2837 finalize_1,
2838 finalize_2,
2839 }
2840 }
2841
2842 pub fn verify<R>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
2844 where
2845 R: CryptoRng,
2846 S: scheme::Scheme<D>,
2847 {
2848 self.finalize_1.verify(rng, scheme, strategy)
2849 && self.finalize_2.verify(rng, scheme, strategy)
2850 }
2851}
2852
2853impl<S: Scheme, D: Digest> Attributable for ConflictingFinalize<S, D> {
2854 fn signer(&self) -> Participant {
2855 self.finalize_1.signer()
2856 }
2857}
2858
2859impl<S: Scheme, D: Digest> Epochable for ConflictingFinalize<S, D> {
2860 fn epoch(&self) -> Epoch {
2861 self.finalize_1.epoch()
2862 }
2863}
2864
2865impl<S: Scheme, D: Digest> Viewable for ConflictingFinalize<S, D> {
2866 fn view(&self) -> View {
2867 self.finalize_1.view()
2868 }
2869}
2870
2871impl<S: Scheme, D: Digest> Write for ConflictingFinalize<S, D> {
2872 fn write(&self, writer: &mut impl BufMut) {
2873 self.finalize_1.write(writer);
2874 self.finalize_2.write(writer);
2875 }
2876}
2877
2878impl<S: Scheme, D: Digest> Read for ConflictingFinalize<S, D> {
2879 type Cfg = ();
2880
2881 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2882 let finalize_1 = Finalize::read(reader)?;
2883 let finalize_2 = Finalize::read(reader)?;
2884
2885 if finalize_1.signer() != finalize_2.signer()
2886 || finalize_1.round() != finalize_2.round()
2887 || finalize_1.proposal == finalize_2.proposal
2888 {
2889 return Err(Error::Invalid(
2890 "consensus::simplex::ConflictingFinalize",
2891 "invalid conflicting finalize",
2892 ));
2893 }
2894
2895 Ok(Self {
2896 finalize_1,
2897 finalize_2,
2898 })
2899 }
2900}
2901
2902impl<S: Scheme, D: Digest> EncodeSize for ConflictingFinalize<S, D> {
2903 fn encode_size(&self) -> usize {
2904 self.finalize_1.encode_size() + self.finalize_2.encode_size()
2905 }
2906}
2907
2908#[cfg(feature = "arbitrary")]
2909impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for ConflictingFinalize<S, D>
2910where
2911 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
2912 D: for<'a> arbitrary::Arbitrary<'a>,
2913{
2914 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
2915 let finalize_1 = Finalize::arbitrary(u)?;
2916 let finalize_2 = Finalize::arbitrary(u)?;
2917 Ok(Self {
2918 finalize_1,
2919 finalize_2,
2920 })
2921 }
2922}
2923
2924#[derive(Clone, Debug)]
2928pub struct NullifyFinalize<S: Scheme, D: Digest> {
2929 nullify: Nullify<S>,
2931 finalize: Finalize<S, D>,
2933}
2934
2935impl<S: Scheme, D: Digest> PartialEq for NullifyFinalize<S, D> {
2936 fn eq(&self, other: &Self) -> bool {
2937 self.nullify == other.nullify && self.finalize == other.finalize
2938 }
2939}
2940
2941impl<S: Scheme, D: Digest> Eq for NullifyFinalize<S, D> {}
2942
2943impl<S: Scheme, D: Digest> Hash for NullifyFinalize<S, D> {
2944 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2945 self.nullify.hash(state);
2946 self.finalize.hash(state);
2947 }
2948}
2949
2950impl<S: Scheme, D: Digest> NullifyFinalize<S, D> {
2951 pub fn new(nullify: Nullify<S>, finalize: Finalize<S, D>) -> Self {
2953 assert_eq!(nullify.round, finalize.round());
2954 assert_eq!(nullify.signer(), finalize.signer());
2955
2956 Self { nullify, finalize }
2957 }
2958
2959 pub fn verify<R>(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool
2961 where
2962 R: CryptoRng,
2963 S: scheme::Scheme<D>,
2964 {
2965 self.nullify.verify(rng, scheme, strategy) && self.finalize.verify(rng, scheme, strategy)
2966 }
2967}
2968
2969impl<S: Scheme, D: Digest> Attributable for NullifyFinalize<S, D> {
2970 fn signer(&self) -> Participant {
2971 self.nullify.signer()
2972 }
2973}
2974
2975impl<S: Scheme, D: Digest> Epochable for NullifyFinalize<S, D> {
2976 fn epoch(&self) -> Epoch {
2977 self.nullify.epoch()
2978 }
2979}
2980
2981impl<S: Scheme, D: Digest> Viewable for NullifyFinalize<S, D> {
2982 fn view(&self) -> View {
2983 self.nullify.view()
2984 }
2985}
2986
2987impl<S: Scheme, D: Digest> Write for NullifyFinalize<S, D> {
2988 fn write(&self, writer: &mut impl BufMut) {
2989 self.nullify.write(writer);
2990 self.finalize.write(writer);
2991 }
2992}
2993
2994impl<S: Scheme, D: Digest> Read for NullifyFinalize<S, D> {
2995 type Cfg = ();
2996
2997 fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2998 let nullify = Nullify::read(reader)?;
2999 let finalize = Finalize::read(reader)?;
3000
3001 if nullify.signer() != finalize.signer() || nullify.round != finalize.round() {
3002 return Err(Error::Invalid(
3003 "consensus::simplex::NullifyFinalize",
3004 "mismatched signatures",
3005 ));
3006 }
3007
3008 Ok(Self { nullify, finalize })
3009 }
3010}
3011
3012impl<S: Scheme, D: Digest> EncodeSize for NullifyFinalize<S, D> {
3013 fn encode_size(&self) -> usize {
3014 self.nullify.encode_size() + self.finalize.encode_size()
3015 }
3016}
3017
3018#[cfg(feature = "arbitrary")]
3019impl<S: Scheme, D: Digest> arbitrary::Arbitrary<'_> for NullifyFinalize<S, D>
3020where
3021 S::Signature: for<'a> arbitrary::Arbitrary<'a>,
3022 D: for<'a> arbitrary::Arbitrary<'a>,
3023{
3024 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
3025 let nullify = Nullify::arbitrary(u)?;
3026 let finalize = Finalize::arbitrary(u)?;
3027 Ok(Self { nullify, finalize })
3028 }
3029}
3030
3031#[cfg(test)]
3032mod tests {
3033 use super::*;
3034 use crate::simplex::{
3035 quorum,
3036 scheme::{
3037 Scheme, bls12381_multisig,
3038 bls12381_threshold::{
3039 standard as bls12381_threshold_std, vrf as bls12381_threshold_vrf,
3040 },
3041 ed25519, secp256r1,
3042 },
3043 };
3044 use bytes::Bytes;
3045 use commonware_codec::{Decode, DecodeExt, Encode};
3046 use commonware_cryptography::{
3047 bls12381::primitives::variant::{MinPk, MinSig},
3048 certificate::mocks::Fixture,
3049 sha256::Digest as Sha256,
3050 };
3051 use commonware_parallel::Sequential;
3052 use commonware_utils::{Faults, N3f1, TestRng, test_rng};
3053
3054 const NAMESPACE: &[u8] = b"test";
3055
3056 fn sample_digest(v: u8) -> Sha256 {
3058 Sha256::from([v; 32]) }
3060
3061 fn setup_seeded<S, F>(n: u32, seed: u64, fixture: F) -> Fixture<S>
3063 where
3064 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3065 {
3066 setup_seeded_ns(n, seed, NAMESPACE, fixture)
3067 }
3068
3069 fn setup_seeded_ns<S, F>(n: u32, seed: u64, namespace: &[u8], fixture: F) -> Fixture<S>
3071 where
3072 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3073 {
3074 let mut rng = TestRng::new(seed);
3075 fixture(&mut rng, namespace, n)
3076 }
3077
3078 #[test]
3079 fn test_proposal_encode_decode() {
3080 let proposal = Proposal::new(
3081 Round::new(Epoch::new(0), View::new(10)),
3082 View::new(5),
3083 sample_digest(1),
3084 );
3085 let encoded = proposal.encode();
3086 let decoded = Proposal::<Sha256>::decode(encoded).unwrap();
3087 assert_eq!(proposal, decoded);
3088 }
3089
3090 fn notarize_encode_decode<S, F>(fixture: F)
3091 where
3092 S: Scheme<Sha256>,
3093 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3094 {
3095 let mut rng = test_rng();
3096 let fixture = fixture(&mut rng, NAMESPACE, 5);
3097 let round = Round::new(Epoch::new(0), View::new(10));
3098 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3099 let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap();
3100
3101 let encoded = notarize.encode();
3102 let decoded = Notarize::decode(encoded).unwrap();
3103
3104 assert_eq!(notarize, decoded);
3105 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3106 }
3107
3108 #[test]
3109 fn test_notarize_encode_decode() {
3110 notarize_encode_decode(ed25519::fixture);
3111 notarize_encode_decode(secp256r1::fixture);
3112 notarize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3113 notarize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3114 notarize_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3115 notarize_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3116 notarize_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3117 notarize_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3118 }
3119
3120 fn notarization_encode_decode<S, F>(fixture: F)
3121 where
3122 S: Scheme<Sha256>,
3123 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3124 {
3125 let mut rng = test_rng();
3126 let fixture = fixture(&mut rng, NAMESPACE, 5);
3127 let proposal = Proposal::new(
3128 Round::new(Epoch::new(0), View::new(10)),
3129 View::new(5),
3130 sample_digest(1),
3131 );
3132 let notarizes: Vec<_> = fixture
3133 .schemes
3134 .iter()
3135 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3136 .collect();
3137 let notarization =
3138 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential)
3139 .expect("quorum notarization");
3140 let encoded = notarization.encode();
3141 let cfg = fixture.schemes[0].certificate_codec_config();
3142 let decoded = Notarization::decode_cfg(encoded, &cfg).unwrap();
3143 assert_eq!(notarization, decoded);
3144 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3145 }
3146
3147 #[test]
3148 fn test_notarization_encode_decode() {
3149 notarization_encode_decode(ed25519::fixture);
3150 notarization_encode_decode(secp256r1::fixture);
3151 notarization_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3152 notarization_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3153 notarization_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3154 notarization_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3155 notarization_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3156 notarization_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3157 }
3158
3159 fn nullify_encode_decode<S, F>(fixture: F)
3160 where
3161 S: Scheme<Sha256>,
3162 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3163 {
3164 let mut rng = test_rng();
3165 let fixture = fixture(&mut rng, NAMESPACE, 5);
3166 let round = Round::new(Epoch::new(0), View::new(10));
3167 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], round).unwrap();
3168 let encoded = nullify.encode();
3169 let decoded = Nullify::decode(encoded).unwrap();
3170 assert_eq!(nullify, decoded);
3171 assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0], &Sequential));
3172 }
3173
3174 #[test]
3175 fn test_nullify_encode_decode() {
3176 nullify_encode_decode(ed25519::fixture);
3177 nullify_encode_decode(secp256r1::fixture);
3178 nullify_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3179 nullify_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3180 nullify_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3181 nullify_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3182 nullify_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3183 nullify_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3184 }
3185
3186 fn nullification_encode_decode<S, F>(fixture: F)
3187 where
3188 S: Scheme<Sha256>,
3189 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3190 {
3191 let mut rng = test_rng();
3192 let fixture = fixture(&mut rng, NAMESPACE, 5);
3193 let round = Round::new(Epoch::new(333), View::new(10));
3194 let nullifies: Vec<_> = fixture
3195 .schemes
3196 .iter()
3197 .map(|scheme| Nullify::sign::<Sha256>(scheme, round).unwrap())
3198 .collect();
3199 let nullification = Nullification::from_nullifies(
3200 &fixture.schemes[0],
3201 non_empty![@&nullifies],
3202 &Sequential,
3203 )
3204 .unwrap();
3205 let encoded = nullification.encode();
3206 let cfg = fixture.schemes[0].certificate_codec_config();
3207 let decoded = Nullification::decode_cfg(encoded, &cfg).unwrap();
3208 assert_eq!(nullification, decoded);
3209 assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0], &Sequential));
3210 }
3211
3212 #[test]
3213 fn test_nullification_encode_decode() {
3214 nullification_encode_decode(ed25519::fixture);
3215 nullification_encode_decode(secp256r1::fixture);
3216 nullification_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3217 nullification_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3218 nullification_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3219 nullification_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3220 nullification_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3221 nullification_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3222 }
3223
3224 fn finalize_encode_decode<S, F>(fixture: F)
3225 where
3226 S: Scheme<Sha256>,
3227 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3228 {
3229 let mut rng = test_rng();
3230 let fixture = fixture(&mut rng, NAMESPACE, 5);
3231 let round = Round::new(Epoch::new(0), View::new(10));
3232 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3233 let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap();
3234 let encoded = finalize.encode();
3235 let decoded = Finalize::decode(encoded).unwrap();
3236 assert_eq!(finalize, decoded);
3237 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3238 }
3239
3240 #[test]
3241 fn test_finalize_encode_decode() {
3242 finalize_encode_decode(ed25519::fixture);
3243 finalize_encode_decode(secp256r1::fixture);
3244 finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3245 finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3246 finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3247 finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3248 finalize_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3249 finalize_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3250 }
3251
3252 fn finalization_encode_decode<S, F>(fixture: F)
3253 where
3254 S: Scheme<Sha256>,
3255 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3256 {
3257 let mut rng = test_rng();
3258 let fixture = fixture(&mut rng, NAMESPACE, 5);
3259 let round = Round::new(Epoch::new(0), View::new(10));
3260 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3261 let finalizes: Vec<_> = fixture
3262 .schemes
3263 .iter()
3264 .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap())
3265 .collect();
3266 let finalization =
3267 Finalization::from_finalizes(&fixture.schemes[0], non_empty![@&finalizes], &Sequential)
3268 .unwrap();
3269 let encoded = finalization.encode();
3270 let cfg = fixture.schemes[0].certificate_codec_config();
3271 let decoded = Finalization::decode_cfg(encoded, &cfg).unwrap();
3272 assert_eq!(finalization, decoded);
3273 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3274 }
3275
3276 #[test]
3277 fn test_finalization_encode_decode() {
3278 finalization_encode_decode(ed25519::fixture);
3279 finalization_encode_decode(secp256r1::fixture);
3280 finalization_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3281 finalization_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3282 finalization_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3283 finalization_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3284 finalization_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3285 finalization_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3286 }
3287
3288 fn backfiller_encode_decode<S, F>(fixture: F)
3289 where
3290 S: Scheme<Sha256>,
3291 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3292 {
3293 let mut rng = test_rng();
3294 let fixture = fixture(&mut rng, NAMESPACE, 5);
3295 let cfg = fixture.schemes[0].certificate_codec_config();
3296 let request = Request::new(
3297 1,
3298 vec![View::new(10), View::new(11)],
3299 vec![View::new(12), View::new(13)],
3300 );
3301 let encoded_request = Backfiller::<S, Sha256>::Request(request.clone()).encode();
3302 let decoded_request =
3303 Backfiller::<S, Sha256>::decode_cfg(encoded_request, &(usize::MAX, cfg.clone()))
3304 .unwrap();
3305 assert!(matches!(decoded_request, Backfiller::Request(r) if r == request));
3306
3307 let round = Round::new(Epoch::new(0), View::new(10));
3308 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3309 let notarizes: Vec<_> = fixture
3310 .schemes
3311 .iter()
3312 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3313 .collect();
3314 let notarization =
3315 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential)
3316 .expect("quorum notarization");
3317
3318 let nullifies: Vec<_> = fixture
3319 .schemes
3320 .iter()
3321 .map(|scheme| Nullify::sign::<Sha256>(scheme, round).unwrap())
3322 .collect();
3323 let nullification = Nullification::from_nullifies(
3324 &fixture.schemes[0],
3325 non_empty![@&nullifies],
3326 &Sequential,
3327 )
3328 .unwrap();
3329
3330 let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
3331 let encoded_response = Backfiller::<S, Sha256>::Response(response.clone()).encode();
3332 let decoded_response =
3333 Backfiller::<S, Sha256>::decode_cfg(encoded_response, &(usize::MAX, cfg)).unwrap();
3334 assert!(matches!(decoded_response, Backfiller::Response(r) if r.id == response.id));
3335 }
3336
3337 #[test]
3338 fn test_backfiller_encode_decode() {
3339 backfiller_encode_decode(ed25519::fixture);
3340 backfiller_encode_decode(secp256r1::fixture);
3341 backfiller_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3342 backfiller_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3343 backfiller_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3344 backfiller_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3345 backfiller_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3346 backfiller_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3347 }
3348
3349 #[test]
3350 fn test_request_encode_decode() {
3351 let request = Request::new(
3352 1,
3353 vec![View::new(10), View::new(11)],
3354 vec![View::new(12), View::new(13)],
3355 );
3356 let encoded = request.encode();
3357 let decoded = Request::decode_cfg(encoded, &usize::MAX).unwrap();
3358 assert_eq!(request, decoded);
3359 }
3360
3361 fn response_encode_decode<S, F>(fixture: F)
3362 where
3363 S: Scheme<Sha256>,
3364 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3365 {
3366 let mut rng = test_rng();
3367 let fixture = fixture(&mut rng, NAMESPACE, 5);
3368 let round = Round::new(Epoch::new(0), View::new(10));
3369 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3370
3371 let notarizes: Vec<_> = fixture
3372 .schemes
3373 .iter()
3374 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3375 .collect();
3376 let notarization =
3377 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential)
3378 .unwrap();
3379
3380 let nullifies: Vec<_> = fixture
3381 .schemes
3382 .iter()
3383 .map(|scheme| Nullify::sign::<Sha256>(scheme, round).unwrap())
3384 .collect();
3385 let nullification = Nullification::from_nullifies(
3386 &fixture.schemes[0],
3387 non_empty![@&nullifies],
3388 &Sequential,
3389 )
3390 .unwrap();
3391
3392 let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
3393 let cfg = fixture.schemes[0].certificate_codec_config();
3394 let mut decoded =
3395 Response::<S, Sha256>::decode_cfg(response.encode(), &(usize::MAX, cfg)).unwrap();
3396 assert_eq!(response.id, decoded.id);
3397 assert_eq!(response.notarizations.len(), decoded.notarizations.len());
3398 assert_eq!(response.nullifications.len(), decoded.nullifications.len());
3399
3400 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3401
3402 decoded.nullifications[0].round = Round::new(
3403 decoded.nullifications[0].round.epoch(),
3404 decoded.nullifications[0].round.view().next(),
3405 );
3406 assert!(!decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3407 }
3408
3409 #[test]
3410 fn test_response_encode_decode() {
3411 response_encode_decode(ed25519::fixture);
3412 response_encode_decode(secp256r1::fixture);
3413 response_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3414 response_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3415 response_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3416 response_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3417 response_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3418 response_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3419 }
3420
3421 #[test]
3422 fn empty_response_is_valid() {
3423 let mut rng = test_rng();
3424 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 5);
3425 let response = Response::<ed25519::Scheme, Sha256>::new(1, Vec::new(), Vec::new());
3426
3427 assert!(response.verify(&mut rng, &fixture.schemes[0], &Sequential));
3428 }
3429
3430 fn conflicting_notarize_encode_decode<S, F>(fixture: F)
3431 where
3432 S: Scheme<Sha256>,
3433 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3434 {
3435 let mut rng = test_rng();
3436 let fixture = fixture(&mut rng, NAMESPACE, 5);
3437 let proposal1 = Proposal::new(
3438 Round::new(Epoch::new(0), View::new(10)),
3439 View::new(5),
3440 sample_digest(1),
3441 );
3442 let proposal2 = Proposal::new(
3443 Round::new(Epoch::new(0), View::new(10)),
3444 View::new(5),
3445 sample_digest(2),
3446 );
3447 let notarize1 = Notarize::sign(&fixture.schemes[0], proposal1).unwrap();
3448 let notarize2 = Notarize::sign(&fixture.schemes[0], proposal2).unwrap();
3449 let conflicting = ConflictingNotarize::new(notarize1, notarize2);
3450
3451 let encoded = conflicting.encode();
3452 let decoded = ConflictingNotarize::<S, Sha256>::decode(encoded).unwrap();
3453
3454 assert_eq!(conflicting, decoded);
3455 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3456 }
3457
3458 #[test]
3459 fn test_conflicting_notarize_encode_decode() {
3460 conflicting_notarize_encode_decode(ed25519::fixture);
3461 conflicting_notarize_encode_decode(secp256r1::fixture);
3462 conflicting_notarize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3463 conflicting_notarize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3464 conflicting_notarize_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3465 conflicting_notarize_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3466 conflicting_notarize_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3467 conflicting_notarize_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3468 }
3469
3470 fn conflicting_finalize_encode_decode<S, F>(fixture: F)
3471 where
3472 S: Scheme<Sha256>,
3473 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3474 {
3475 let mut rng = test_rng();
3476 let fixture = fixture(&mut rng, NAMESPACE, 5);
3477 let proposal1 = Proposal::new(
3478 Round::new(Epoch::new(0), View::new(10)),
3479 View::new(5),
3480 sample_digest(1),
3481 );
3482 let proposal2 = Proposal::new(
3483 Round::new(Epoch::new(0), View::new(10)),
3484 View::new(5),
3485 sample_digest(2),
3486 );
3487 let finalize1 = Finalize::sign(&fixture.schemes[0], proposal1).unwrap();
3488 let finalize2 = Finalize::sign(&fixture.schemes[0], proposal2).unwrap();
3489 let conflicting = ConflictingFinalize::new(finalize1, finalize2);
3490
3491 let encoded = conflicting.encode();
3492 let decoded = ConflictingFinalize::<S, Sha256>::decode(encoded).unwrap();
3493
3494 assert_eq!(conflicting, decoded);
3495 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3496 }
3497
3498 #[test]
3499 fn test_conflicting_finalize_encode_decode() {
3500 conflicting_finalize_encode_decode(ed25519::fixture);
3501 conflicting_finalize_encode_decode(secp256r1::fixture);
3502 conflicting_finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3503 conflicting_finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3504 conflicting_finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3505 conflicting_finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3506 conflicting_finalize_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3507 conflicting_finalize_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3508 }
3509
3510 fn nullify_finalize_encode_decode<S, F>(fixture: F)
3511 where
3512 S: Scheme<Sha256>,
3513 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3514 {
3515 let mut rng = test_rng();
3516 let fixture = fixture(&mut rng, NAMESPACE, 5);
3517 let round = Round::new(Epoch::new(0), View::new(10));
3518 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3519 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], round).unwrap();
3520 let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap();
3521 let conflict = NullifyFinalize::new(nullify, finalize);
3522
3523 let encoded = conflict.encode();
3524 let decoded = NullifyFinalize::<S, Sha256>::decode(encoded).unwrap();
3525
3526 assert_eq!(conflict, decoded);
3527 assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential));
3528 }
3529
3530 #[test]
3531 fn test_nullify_finalize_encode_decode() {
3532 nullify_finalize_encode_decode(ed25519::fixture);
3533 nullify_finalize_encode_decode(secp256r1::fixture);
3534 nullify_finalize_encode_decode(bls12381_multisig::fixture::<MinPk, _>);
3535 nullify_finalize_encode_decode(bls12381_multisig::fixture::<MinSig, _>);
3536 nullify_finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinPk, _>);
3537 nullify_finalize_encode_decode(bls12381_threshold_vrf::fixture::<MinSig, _>);
3538 nullify_finalize_encode_decode(bls12381_threshold_std::fixture::<MinPk, _>);
3539 nullify_finalize_encode_decode(bls12381_threshold_std::fixture::<MinSig, _>);
3540 }
3541
3542 fn notarize_verify_wrong_namespace<S, F>(f: F)
3543 where
3544 S: Scheme<Sha256>,
3545 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3546 {
3547 let mut rng = test_rng();
3549 let fixture = setup_seeded_ns(5, 0, NAMESPACE, &f);
3550 let wrong_fixture = setup_seeded_ns(5, 0, b"wrong_namespace", &f);
3551 let round = Round::new(Epoch::new(0), View::new(10));
3552 let proposal = Proposal::new(round, View::new(5), sample_digest(1));
3553 let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap();
3554
3555 assert!(notarize.verify(&mut rng, &fixture.schemes[0], &Sequential));
3556 assert!(!notarize.verify(&mut rng, &wrong_fixture.schemes[0], &Sequential));
3557 }
3558
3559 #[test]
3560 fn test_notarize_verify_wrong_namespace() {
3561 notarize_verify_wrong_namespace(ed25519::fixture);
3562 notarize_verify_wrong_namespace(secp256r1::fixture);
3563 notarize_verify_wrong_namespace(bls12381_multisig::fixture::<MinPk, _>);
3564 notarize_verify_wrong_namespace(bls12381_multisig::fixture::<MinSig, _>);
3565 notarize_verify_wrong_namespace(bls12381_threshold_vrf::fixture::<MinPk, _>);
3566 notarize_verify_wrong_namespace(bls12381_threshold_vrf::fixture::<MinSig, _>);
3567 notarize_verify_wrong_namespace(bls12381_threshold_std::fixture::<MinPk, _>);
3568 notarize_verify_wrong_namespace(bls12381_threshold_std::fixture::<MinSig, _>);
3569 }
3570
3571 fn notarize_verify_wrong_scheme<S, F>(f: F)
3572 where
3573 S: Scheme<Sha256>,
3574 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3575 {
3576 let mut rng = test_rng();
3577 let fixture = setup_seeded(5, 0, &f);
3578 let wrong_fixture = setup_seeded(5, 1, &f);
3579 let round = Round::new(Epoch::new(0), View::new(10));
3580 let proposal = Proposal::new(round, View::new(5), sample_digest(2));
3581 let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap();
3582
3583 assert!(notarize.verify(&mut rng, &fixture.schemes[0], &Sequential));
3584 assert!(!notarize.verify(&mut rng, &wrong_fixture.verifier, &Sequential));
3585 }
3586
3587 #[test]
3588 fn test_notarize_verify_wrong_scheme() {
3589 notarize_verify_wrong_scheme(ed25519::fixture);
3590 notarize_verify_wrong_scheme(secp256r1::fixture);
3591 notarize_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
3592 notarize_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
3593 notarize_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinPk, _>);
3594 notarize_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinSig, _>);
3595 notarize_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinPk, _>);
3596 notarize_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinSig, _>);
3597 }
3598
3599 fn notarization_verify_wrong_scheme<S, F>(f: F)
3600 where
3601 S: Scheme<Sha256>,
3602 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3603 {
3604 let mut rng = test_rng();
3605 let fixture = setup_seeded(5, 0, &f);
3606 let wrong_fixture = setup_seeded(5, 1, &f);
3607 let round = Round::new(Epoch::new(0), View::new(10));
3608 let proposal = Proposal::new(round, View::new(5), sample_digest(3));
3609 let quorum = N3f1::quorum(fixture.schemes.len()) as usize;
3610 let notarizes: Vec<_> = fixture
3611 .schemes
3612 .iter()
3613 .take(quorum)
3614 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3615 .collect();
3616
3617 let notarization =
3618 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential)
3619 .unwrap();
3620 assert!(notarization.verify(&mut rng, &fixture.schemes[0], &Sequential));
3621 assert!(!notarization.verify(&mut rng, &wrong_fixture.verifier, &Sequential));
3622 }
3623
3624 #[test]
3625 fn test_notarization_verify_wrong_scheme() {
3626 notarization_verify_wrong_scheme(ed25519::fixture);
3627 notarization_verify_wrong_scheme(secp256r1::fixture);
3628 notarization_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
3629 notarization_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
3630 notarization_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinPk, _>);
3631 notarization_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinSig, _>);
3632 notarization_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinPk, _>);
3633 notarization_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinSig, _>);
3634 }
3635
3636 fn notarization_verify_wrong_namespace<S, F>(f: F)
3637 where
3638 S: Scheme<Sha256>,
3639 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3640 {
3641 let fixture = setup_seeded_ns(5, 0, NAMESPACE, &f);
3643 let wrong_fixture = setup_seeded_ns(5, 0, b"wrong_namespace", &f);
3644 let mut rng = test_rng();
3645 let round = Round::new(Epoch::new(0), View::new(10));
3646 let proposal = Proposal::new(round, View::new(5), sample_digest(4));
3647 let quorum = N3f1::quorum(fixture.schemes.len()) as usize;
3648 let notarizes: Vec<_> = fixture
3649 .schemes
3650 .iter()
3651 .take(quorum)
3652 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3653 .collect();
3654
3655 let notarization =
3656 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential)
3657 .unwrap();
3658 assert!(notarization.verify(&mut rng, &fixture.schemes[0], &Sequential));
3659
3660 assert!(!notarization.verify(&mut rng, &wrong_fixture.schemes[0], &Sequential));
3661 }
3662
3663 #[test]
3664 fn test_notarization_verify_wrong_namespace() {
3665 notarization_verify_wrong_namespace(ed25519::fixture);
3666 notarization_verify_wrong_namespace(secp256r1::fixture);
3667 notarization_verify_wrong_namespace(bls12381_multisig::fixture::<MinPk, _>);
3668 notarization_verify_wrong_namespace(bls12381_multisig::fixture::<MinSig, _>);
3669 notarization_verify_wrong_namespace(bls12381_threshold_vrf::fixture::<MinPk, _>);
3670 notarization_verify_wrong_namespace(bls12381_threshold_vrf::fixture::<MinSig, _>);
3671 notarization_verify_wrong_namespace(bls12381_threshold_std::fixture::<MinPk, _>);
3672 notarization_verify_wrong_namespace(bls12381_threshold_std::fixture::<MinSig, _>);
3673 }
3674
3675 fn notarization_recover_insufficient_signatures<S, F>(fixture: F)
3676 where
3677 S: Scheme<Sha256>,
3678 F: FnOnce(&mut TestRng, &[u8], u32) -> Fixture<S>,
3679 {
3680 let mut rng = test_rng();
3681 let fixture = fixture(&mut rng, NAMESPACE, 5);
3682 let participant_count =
3683 u32::try_from(fixture.schemes.len()).expect("participant count exceeds u32::MAX");
3684 let quorum_size = quorum(participant_count);
3685 let subquorum = usize::try_from(quorum_size - 1).expect("quorum exceeds usize::MAX");
3686 assert!(quorum_size > 1, "test requires quorum larger than one");
3687 let round = Round::new(Epoch::new(0), View::new(10));
3688 let proposal = Proposal::new(round, View::new(5), sample_digest(5));
3689 let notarizes: Vec<_> = fixture
3690 .schemes
3691 .iter()
3692 .take(subquorum)
3693 .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
3694 .collect();
3695
3696 assert_eq!(
3697 Notarization::from_notarizes(&fixture.schemes[0], non_empty![@¬arizes], &Sequential),
3698 Err(AssemblyError::InsufficientAttestations(
3699 quorum_size,
3700 quorum_size - 1
3701 )),
3702 "insufficient votes should not form a notarization"
3703 );
3704 }
3705
3706 #[test]
3707 fn test_notarization_recover_insufficient_signatures() {
3708 notarization_recover_insufficient_signatures(ed25519::fixture);
3709 notarization_recover_insufficient_signatures(secp256r1::fixture);
3710 notarization_recover_insufficient_signatures(bls12381_multisig::fixture::<MinPk, _>);
3711 notarization_recover_insufficient_signatures(bls12381_multisig::fixture::<MinSig, _>);
3712 notarization_recover_insufficient_signatures(bls12381_threshold_vrf::fixture::<MinPk, _>);
3713 notarization_recover_insufficient_signatures(bls12381_threshold_vrf::fixture::<MinSig, _>);
3714 notarization_recover_insufficient_signatures(bls12381_threshold_std::fixture::<MinPk, _>);
3715 notarization_recover_insufficient_signatures(bls12381_threshold_std::fixture::<MinSig, _>);
3716 }
3717
3718 fn conflicting_notarize_detection<S, F>(f: F)
3719 where
3720 S: Scheme<Sha256>,
3721 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3722 {
3723 let mut rng = test_rng();
3724 let fixture = setup_seeded(5, 0, &f);
3725 let wrong_ns_fixture = setup_seeded_ns(5, 0, b"wrong_namespace", &f);
3726 let wrong_scheme_fixture = setup_seeded(5, 1, &f);
3727
3728 let round = Round::new(Epoch::new(0), View::new(10));
3729 let proposal1 = Proposal::new(round, View::new(5), sample_digest(6));
3730 let proposal2 = Proposal::new(round, View::new(5), sample_digest(7));
3731
3732 let notarize1 = Notarize::sign(&fixture.schemes[0], proposal1).unwrap();
3733 let notarize2 = Notarize::sign(&fixture.schemes[0], proposal2).unwrap();
3734 let conflict = ConflictingNotarize::new(notarize1, notarize2);
3735
3736 assert!(conflict.verify(&mut rng, &fixture.schemes[0], &Sequential));
3737 assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0], &Sequential));
3738 assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier, &Sequential));
3739 }
3740
3741 #[test]
3742 fn test_conflicting_notarize_detection() {
3743 conflicting_notarize_detection(ed25519::fixture);
3744 conflicting_notarize_detection(secp256r1::fixture);
3745 conflicting_notarize_detection(bls12381_multisig::fixture::<MinPk, _>);
3746 conflicting_notarize_detection(bls12381_multisig::fixture::<MinSig, _>);
3747 conflicting_notarize_detection(bls12381_threshold_vrf::fixture::<MinPk, _>);
3748 conflicting_notarize_detection(bls12381_threshold_vrf::fixture::<MinSig, _>);
3749 conflicting_notarize_detection(bls12381_threshold_std::fixture::<MinPk, _>);
3750 conflicting_notarize_detection(bls12381_threshold_std::fixture::<MinSig, _>);
3751 }
3752
3753 fn nullify_finalize_detection<S, F>(f: F)
3754 where
3755 S: Scheme<Sha256>,
3756 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3757 {
3758 let mut rng = test_rng();
3759 let fixture = setup_seeded(5, 0, &f);
3760 let wrong_ns_fixture = setup_seeded_ns(5, 0, b"wrong_namespace", &f);
3761 let wrong_scheme_fixture = setup_seeded(5, 1, &f);
3762
3763 let round = Round::new(Epoch::new(0), View::new(10));
3764 let proposal = Proposal::new(round, View::new(5), sample_digest(8));
3765
3766 let nullify = Nullify::sign::<Sha256>(&fixture.schemes[0], round).unwrap();
3767 let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap();
3768 let conflict = NullifyFinalize::new(nullify, finalize);
3769
3770 assert!(conflict.verify(&mut rng, &fixture.schemes[0], &Sequential));
3771 assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0], &Sequential));
3772 assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier, &Sequential));
3773 }
3774
3775 #[test]
3776 fn test_nullify_finalize_detection() {
3777 nullify_finalize_detection(ed25519::fixture);
3778 nullify_finalize_detection(secp256r1::fixture);
3779 nullify_finalize_detection(bls12381_multisig::fixture::<MinPk, _>);
3780 nullify_finalize_detection(bls12381_multisig::fixture::<MinSig, _>);
3781 nullify_finalize_detection(bls12381_threshold_vrf::fixture::<MinPk, _>);
3782 nullify_finalize_detection(bls12381_threshold_vrf::fixture::<MinSig, _>);
3783 nullify_finalize_detection(bls12381_threshold_std::fixture::<MinPk, _>);
3784 nullify_finalize_detection(bls12381_threshold_std::fixture::<MinSig, _>);
3785 }
3786
3787 fn finalization_verify_wrong_scheme<S, F>(f: F)
3788 where
3789 S: Scheme<Sha256>,
3790 F: Fn(&mut TestRng, &[u8], u32) -> Fixture<S>,
3791 {
3792 let mut rng = test_rng();
3793 let fixture = setup_seeded(5, 0, &f);
3794 let wrong_fixture = setup_seeded(5, 1, &f);
3795 let round = Round::new(Epoch::new(0), View::new(10));
3796 let proposal = Proposal::new(round, View::new(5), sample_digest(9));
3797 let quorum = N3f1::quorum(fixture.schemes.len()) as usize;
3798 let finalizes: Vec<_> = fixture
3799 .schemes
3800 .iter()
3801 .take(quorum)
3802 .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap())
3803 .collect();
3804
3805 let finalization =
3806 Finalization::from_finalizes(&fixture.schemes[0], non_empty![@&finalizes], &Sequential)
3807 .expect("quorum finalization");
3808 assert!(finalization.verify(&mut rng, &fixture.schemes[0], &Sequential));
3809 assert!(!finalization.verify(&mut rng, &wrong_fixture.verifier, &Sequential));
3810 }
3811
3812 #[test]
3813 fn test_finalization_wrong_scheme() {
3814 finalization_verify_wrong_scheme(ed25519::fixture);
3815 finalization_verify_wrong_scheme(secp256r1::fixture);
3816 finalization_verify_wrong_scheme(bls12381_multisig::fixture::<MinPk, _>);
3817 finalization_verify_wrong_scheme(bls12381_multisig::fixture::<MinSig, _>);
3818 finalization_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinPk, _>);
3819 finalization_verify_wrong_scheme(bls12381_threshold_vrf::fixture::<MinSig, _>);
3820 finalization_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinPk, _>);
3821 finalization_verify_wrong_scheme(bls12381_threshold_std::fixture::<MinSig, _>);
3822 }
3823
3824 struct MockAttributable(Participant);
3825
3826 impl Attributable for MockAttributable {
3827 fn signer(&self) -> Participant {
3828 self.0
3829 }
3830 }
3831
3832 #[test]
3833 fn test_attributable_map() {
3834 let mut map = AttributableMap::new(5);
3835 assert_eq!(map.len(), 0);
3836 assert!(map.is_empty());
3837 assert_eq!(map.data.capacity(), 0, "empty maps should allocate lazily");
3838
3839 for i in 0..5 {
3841 assert!(map.get(Participant::new(i)).is_none());
3842 }
3843
3844 assert!(map.insert(MockAttributable(Participant::new(3))));
3845 assert!(map.data.capacity() >= 5);
3846 assert_eq!(map.len(), 1);
3847 assert!(!map.is_empty());
3848 let mut iter = map.iter();
3849 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(3)));
3850 assert!(iter.next().is_none());
3851 drop(iter);
3852
3853 assert!(
3855 matches!(map.get(Participant::new(3)), Some(a) if a.signer() == Participant::new(3))
3856 );
3857
3858 assert!(map.insert(MockAttributable(Participant::new(1))));
3859 assert_eq!(map.len(), 2);
3860 assert!(!map.is_empty());
3861 let mut iter = map.iter();
3862 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(1)));
3863 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(3)));
3864 assert!(iter.next().is_none());
3865 drop(iter);
3866
3867 assert!(
3869 matches!(map.get(Participant::new(1)), Some(a) if a.signer() == Participant::new(1))
3870 );
3871 assert!(
3872 matches!(map.get(Participant::new(3)), Some(a) if a.signer() == Participant::new(3))
3873 );
3874
3875 assert!(map.get(Participant::new(0)).is_none());
3877 assert!(map.get(Participant::new(2)).is_none());
3878 assert!(map.get(Participant::new(4)).is_none());
3879
3880 assert!(!map.insert(MockAttributable(Participant::new(3))));
3881 assert_eq!(map.len(), 2);
3882 assert!(!map.is_empty());
3883 let mut iter = map.iter();
3884 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(1)));
3885 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(3)));
3886 assert!(iter.next().is_none());
3887 drop(iter);
3888
3889 assert!(!map.insert(MockAttributable(Participant::new(5))));
3891 assert!(!map.insert(MockAttributable(Participant::new(100))));
3892 assert_eq!(map.len(), 2);
3893
3894 map.clear();
3896 assert_eq!(map.len(), 0);
3897 assert!(map.is_empty());
3898 assert!(map.iter().next().is_none());
3899 assert_eq!(map.data.capacity(), 0, "clear should release vote storage");
3900
3901 assert!(map.insert(MockAttributable(Participant::new(2))));
3903 assert_eq!(map.len(), 1);
3904 let mut iter = map.iter();
3905 assert!(matches!(iter.next(), Some(a) if a.signer() == Participant::new(2)));
3906 assert!(iter.next().is_none());
3907 }
3908
3909 #[test]
3910 fn test_vote_tracker_clears_compacted_state() {
3911 let mut rng = test_rng();
3912 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 2);
3913 let round = Round::new(Epoch::new(0), View::new(1));
3914 let mut tracker = VoteTracker::<ed25519::Scheme, Sha256>::new(2, false);
3915 let signer = Participant::new(1);
3916 let scheme = &fixture.schemes[usize::from(signer)];
3917 let proposal = Proposal::new(round, View::zero(), sample_digest(1));
3918 let notarize = Vote::Notarize(Notarize::sign(scheme, proposal.clone()).unwrap());
3919 let finalize = Vote::Finalize(Finalize::sign(scheme, proposal.clone()).unwrap());
3920
3921 tracker.release_notarizes(&proposal);
3922 tracker.release_finalizes(&proposal);
3923 assert!(matches!(
3924 tracker.record(¬arize, Some(&proposal)),
3925 Outcome::Added { retained: false }
3926 ));
3927 assert!(matches!(
3928 tracker.record(&finalize, Some(&proposal)),
3929 Outcome::Added { retained: false }
3930 ));
3931 assert!(tracker.has_notarize_for(signer, &proposal));
3932 assert!(tracker.has_finalize_for(signer, &proposal));
3933
3934 tracker.clear_notarizes();
3935 assert!(!tracker.has_notarize_for(signer, &proposal));
3936 assert!(matches!(
3937 tracker.record(¬arize, Some(&proposal)),
3938 Outcome::Added { retained: true }
3939 ));
3940
3941 tracker.clear_finalizes();
3942 assert!(!tracker.has_finalize_for(signer, &proposal));
3943 assert_eq!(tracker.compacted.capacity(), 0);
3944 assert!(matches!(
3945 tracker.record(&finalize, Some(&proposal)),
3946 Outcome::Added { retained: true }
3947 ));
3948 }
3949
3950 #[test]
3951 fn test_vote_tracker_insert_and_accessors() {
3952 let mut rng = test_rng();
3953 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 2);
3954 let round = Round::new(Epoch::new(0), View::new(1));
3955 let proposal = Proposal::new(round, View::zero(), sample_digest(1));
3956 let scheme = &fixture.schemes[0];
3957 let signer = Participant::new(0);
3958 let notarize = Notarize::sign(scheme, proposal.clone()).unwrap();
3959 let nullify = Nullify::sign::<Sha256>(scheme, round).unwrap();
3960 let finalize = Finalize::sign(scheme, proposal.clone()).unwrap();
3961 let mut tracker = VoteTracker::new(2, false);
3962
3963 assert!(tracker.insert_notarize(notarize.clone()));
3964 assert!(tracker.insert_nullify(nullify.clone()));
3965 assert!(tracker.insert_finalize(finalize.clone()));
3966 assert_eq!(tracker.len_notarizes(), 1);
3967 assert_eq!(tracker.len_nullifies(), 1);
3968 assert_eq!(tracker.len_finalizes(), 1);
3969 assert!(tracker.has_notarize(signer));
3970 assert!(tracker.has_nullify(signer));
3971 assert!(tracker.has_finalize(signer));
3972
3973 tracker.release_notarizes(&proposal);
3974 tracker.release_nullifies();
3975 tracker.release_finalizes(&proposal);
3976 assert_eq!(tracker.len_notarizes(), 0);
3977 assert_eq!(tracker.len_nullifies(), 0);
3978 assert_eq!(tracker.len_finalizes(), 0);
3979 assert!(!tracker.has_notarize(signer));
3980 assert!(!tracker.has_nullify(signer));
3981 assert!(!tracker.has_finalize(signer));
3982 assert!(tracker.iter_notarizes().next().is_none());
3983 assert!(tracker.iter_nullifies().next().is_none());
3984 assert!(tracker.iter_finalizes().next().is_none());
3985 assert!(!tracker.insert_notarize(notarize));
3986 assert!(!tracker.insert_nullify(nullify));
3987 assert!(!tracker.insert_finalize(finalize));
3988
3989 tracker.release_notarizes(&proposal);
3991 }
3992
3993 #[test]
3994 fn test_vote_tracker_retention_policy() {
3995 let mut rng = test_rng();
3996 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 2);
3997 let proposal = Proposal::new(
3998 Round::new(Epoch::new(0), View::new(1)),
3999 View::zero(),
4000 sample_digest(1),
4001 );
4002 let notarize = Notarize::sign(&fixture.schemes[0], proposal.clone()).unwrap();
4003 let signer = notarize.signer();
4004 let vote = Vote::Notarize(notarize);
4005
4006 let mut releasing = VoteTracker::new(2, false);
4007 assert!(matches!(
4008 releasing.record(&vote, Some(&proposal)),
4009 Outcome::Added { retained: true }
4010 ));
4011 let Phase::Full(votes) = &releasing.notarizes else {
4012 panic!("notarize phase compacted before certification");
4013 };
4014 assert!(votes.data.capacity() >= 2);
4015 releasing.release_notarizes(&proposal);
4016 assert!(matches!(&releasing.notarizes, Phase::Compacted));
4017 assert!(matches!(
4018 releasing.record(&vote, Some(&proposal)),
4019 Outcome::Duplicate { retained: false }
4020 ));
4021
4022 let mut certificate_first = VoteTracker::new(2, false);
4025 certificate_first.release_notarizes(&proposal);
4026 assert!(matches!(
4027 certificate_first.record(&vote, Some(&proposal)),
4028 Outcome::Added { retained: false }
4029 ));
4030 assert!(matches!(&certificate_first.notarizes, Phase::Compacted));
4031 assert!(matches!(
4032 certificate_first.record(&vote, Some(&proposal)),
4033 Outcome::Duplicate { retained: false }
4034 ));
4035
4036 let mut retaining = VoteTracker::new(2, true);
4037 assert!(matches!(
4038 retaining.record(&vote, Some(&proposal)),
4039 Outcome::Added { retained: true }
4040 ));
4041 let Phase::Full(votes) = &retaining.notarizes else {
4042 panic!("retained notarize phase compacted");
4043 };
4044 let retained_capacity = votes.data.capacity();
4045 retaining.release_notarizes(&proposal);
4046 let Phase::Full(votes) = &retaining.notarizes else {
4047 panic!("retained notarize phase compacted");
4048 };
4049 assert_eq!(votes.data.capacity(), retained_capacity);
4050 assert!(retaining.notarize(signer).is_some());
4051 }
4052
4053 #[test]
4054 #[should_panic(expected = "proposals must differ")]
4055 fn issue_2944_regression_conflicting_notarize_new() {
4056 let mut rng = test_rng();
4057 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 1);
4058 let proposal = Proposal::new(
4059 Round::new(Epoch::new(0), View::new(10)),
4060 View::new(5),
4061 sample_digest(1),
4062 );
4063 let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap();
4064 let _ = ConflictingNotarize::new(notarize.clone(), notarize);
4065 }
4066
4067 #[test]
4068 fn issue_2944_regression_conflicting_notarize_decode() {
4069 let mut rng = test_rng();
4070 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 1);
4071 let proposal = Proposal::new(
4072 Round::new(Epoch::new(0), View::new(10)),
4073 View::new(5),
4074 sample_digest(1),
4075 );
4076 let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap();
4077
4078 let mut buf = Vec::new();
4080 notarize.write(&mut buf);
4081 notarize.write(&mut buf);
4082
4083 let result = ConflictingNotarize::<ed25519::Scheme, Sha256>::decode(Bytes::from(buf));
4085 assert!(result.is_err());
4086 }
4087
4088 #[test]
4089 #[should_panic(expected = "proposals must differ")]
4090 fn issue_2944_regression_conflicting_finalize_new() {
4091 let mut rng = test_rng();
4092 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 1);
4093 let proposal = Proposal::new(
4094 Round::new(Epoch::new(0), View::new(10)),
4095 View::new(5),
4096 sample_digest(1),
4097 );
4098 let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap();
4099 let _ = ConflictingFinalize::new(finalize.clone(), finalize);
4100 }
4101
4102 #[test]
4103 fn issue_2944_regression_conflicting_finalize_decode() {
4104 let mut rng = test_rng();
4105 let fixture = ed25519::fixture(&mut rng, NAMESPACE, 1);
4106 let proposal = Proposal::new(
4107 Round::new(Epoch::new(0), View::new(10)),
4108 View::new(5),
4109 sample_digest(1),
4110 );
4111 let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap();
4112
4113 let mut buf = Vec::new();
4115 finalize.write(&mut buf);
4116 finalize.write(&mut buf);
4117
4118 let result = ConflictingFinalize::<ed25519::Scheme, Sha256>::decode(Bytes::from(buf));
4120 assert!(result.is_err());
4121 }
4122
4123 #[cfg(feature = "arbitrary")]
4124 mod conformance {
4125 use super::*;
4126 use crate::simplex::scheme::bls12381_threshold::vrf as bls12381_threshold_vrf;
4127 use commonware_codec::conformance::CodecConformance;
4128 use commonware_cryptography::{ed25519::PublicKey, sha256::Digest as Sha256Digest};
4129
4130 type Scheme = bls12381_threshold_vrf::Scheme<PublicKey, MinSig>;
4131
4132 commonware_conformance::conformance_tests! {
4133 CodecConformance<Vote<Scheme, Sha256Digest>>,
4134 CodecConformance<Certificate<Scheme, Sha256Digest>>,
4135 CodecConformance<Artifact<Scheme, Sha256Digest>>,
4136 CodecConformance<Proposal<Sha256Digest>>,
4137 CodecConformance<Notarize<Scheme, Sha256Digest>>,
4138 CodecConformance<Notarization<Scheme, Sha256Digest>>,
4139 CodecConformance<Nullify<Scheme>>,
4140 CodecConformance<Nullification<Scheme>>,
4141 CodecConformance<Finalize<Scheme, Sha256Digest>>,
4142 CodecConformance<Finalization<Scheme, Sha256Digest>>,
4143 CodecConformance<Backfiller<Scheme, Sha256Digest>>,
4144 CodecConformance<Request>,
4145 CodecConformance<Response<Scheme, Sha256Digest>>,
4146 CodecConformance<Activity<Scheme, Sha256Digest>>,
4147 CodecConformance<ConflictingNotarize<Scheme, Sha256Digest>>,
4148 CodecConformance<ConflictingFinalize<Scheme, Sha256Digest>>,
4149 CodecConformance<NullifyFinalize<Scheme, Sha256Digest>>,
4150 CodecConformance<Context<Sha256Digest, PublicKey>>
4151 }
4152 }
4153}