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