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