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