commonware_consensus/threshold_simplex/
types.rs

1//! Types used in [crate::threshold_simplex].
2
3use crate::Viewable;
4use bytes::{Buf, BufMut};
5use commonware_codec::{
6    varint::UInt, Encode, EncodeSize, Error, Read, ReadExt, ReadRangeExt, Write,
7};
8use commonware_cryptography::{
9    bls12381::primitives::{
10        group::Share,
11        ops::{
12            aggregate_signatures, aggregate_verify_multiple_messages, partial_sign_message,
13            partial_verify_multiple_public_keys_precomputed, verify_message,
14        },
15        poly::PartialSignature,
16        variant::Variant,
17    },
18    Digest,
19};
20use commonware_utils::union;
21use std::{
22    collections::{BTreeSet, HashMap, HashSet},
23    hash::Hash,
24};
25
26/// View is a monotonically increasing counter that represents the current focus of consensus.
27/// Each View corresponds to a round in the consensus protocol where validators attempt to agree
28/// on a block to commit.
29pub type View = u64;
30
31/// Context is a collection of metadata from consensus about a given payload.
32/// It provides information about the current view and the parent payload that new proposals are built on.
33#[derive(Clone)]
34pub struct Context<D: Digest> {
35    /// Current view (round) of consensus.
36    pub view: View,
37
38    /// Parent the payload is built on.
39    ///
40    /// If there is a gap between the current view and the parent view, the participant
41    /// must possess a nullification for each discarded view to safely vote on the proposed
42    /// payload (any view without a nullification may eventually be finalized and skipping
43    /// it would result in a fork).
44    pub parent: (View, D),
45}
46
47/// Attributable is a trait that provides access to the signer index.
48/// This is used to identify which participant signed a given message.
49pub trait Attributable {
50    /// Returns the index of the signer (validator) who produced this message.
51    fn signer(&self) -> u32;
52}
53
54/// Seedable is a trait that provides access to the seed associated with a message.
55pub trait Seedable<V: Variant> {
56    /// Returns the seed associated with this object.
57    fn seed(&self) -> Seed<V>;
58}
59
60// Constants for domain separation in signature verification
61// These are used to prevent cross-protocol attacks and message-type confusion
62pub const SEED_SUFFIX: &[u8] = b"_SEED";
63pub const NOTARIZE_SUFFIX: &[u8] = b"_NOTARIZE";
64pub const NULLIFY_SUFFIX: &[u8] = b"_NULLIFY";
65pub const FINALIZE_SUFFIX: &[u8] = b"_FINALIZE";
66
67/// Creates a message to be signed containing just the view number
68#[inline]
69pub fn view_message(view: View) -> Vec<u8> {
70    View::encode(&view).into()
71}
72
73/// Creates a namespace for seed messages by appending the SEED_SUFFIX
74/// The seed is used for leader election and randomness generation
75#[inline]
76pub fn seed_namespace(namespace: &[u8]) -> Vec<u8> {
77    union(namespace, SEED_SUFFIX)
78}
79
80/// Creates a namespace for notarize messages by appending the NOTARIZE_SUFFIX
81/// Domain separation prevents cross-protocol attacks
82#[inline]
83pub fn notarize_namespace(namespace: &[u8]) -> Vec<u8> {
84    union(namespace, NOTARIZE_SUFFIX)
85}
86
87/// Creates a namespace for nullify messages by appending the NULLIFY_SUFFIX
88/// Domain separation prevents cross-protocol attacks
89#[inline]
90pub fn nullify_namespace(namespace: &[u8]) -> Vec<u8> {
91    union(namespace, NULLIFY_SUFFIX)
92}
93
94/// Creates a namespace for finalize messages by appending the FINALIZE_SUFFIX
95/// Domain separation prevents cross-protocol attacks
96#[inline]
97pub fn finalize_namespace(namespace: &[u8]) -> Vec<u8> {
98    union(namespace, FINALIZE_SUFFIX)
99}
100
101/// `BatchVerifier` is a utility for tracking and batch verifying consensus messages.
102///
103/// In consensus, verifying multiple signatures at the same time can be much more efficient
104/// than verifying them one by one. This struct collects messages from participants in consensus
105/// and signals they are ready to be verified when certain conditions are met (e.g., enough messages
106/// to potentially reach a quorum, or when a leader's message is received).
107///
108/// To avoid unnecessary verification, it also tracks the number of already verified messages (ensuring
109/// we no longer attempt to verify messages after a quorum of valid messages have already been verified).
110pub struct BatchVerifier<V: Variant, D: Digest> {
111    quorum: Option<usize>,
112
113    leader: Option<u32>,
114    leader_proposal: Option<Proposal<D>>,
115
116    notarizes: Vec<Notarize<V, D>>,
117    notarizes_force: bool,
118    notarizes_verified: usize,
119
120    nullifies: Vec<Nullify<V>>,
121    nullifies_verified: usize,
122
123    finalizes: Vec<Finalize<V, D>>,
124    finalizes_verified: usize,
125}
126
127impl<V: Variant, D: Digest> BatchVerifier<V, D> {
128    /// Creates a new `BatchVerifier`.
129    ///
130    /// # Arguments
131    ///
132    /// * `quorum` - An optional `u32` specifying the number of votes (2f+1)
133    ///   required to reach a quorum. If `None`, batch verification readiness
134    ///   checks based on quorum size are skipped.
135    pub fn new(quorum: Option<u32>) -> Self {
136        Self {
137            quorum: quorum.map(|q| q as usize),
138
139            leader: None,
140            leader_proposal: None,
141
142            notarizes: Vec::new(),
143            notarizes_force: false,
144            notarizes_verified: 0,
145
146            nullifies: Vec::new(),
147            nullifies_verified: 0,
148
149            finalizes: Vec::new(),
150            finalizes_verified: 0,
151        }
152    }
153
154    /// Clears any pending messages that are not for the leader's proposal and forces
155    /// the notarizes to be verified.
156    ///
157    /// We force verification because we need to know the leader's proposal
158    /// to begin verifying it.
159    fn set_leader_proposal(&mut self, proposal: Proposal<D>) {
160        // Drop all notarizes/finalizes that aren't for the leader proposal
161        self.notarizes.retain(|n| n.proposal == proposal);
162        self.finalizes.retain(|f| f.proposal == proposal);
163
164        // Set the leader proposal
165        self.leader_proposal = Some(proposal);
166
167        // Force the notarizes to be verified
168        self.notarizes_force = true;
169    }
170
171    /// Adds a [Voter] message to the batch for later verification.
172    ///
173    /// If the message has already been verified (e.g., we built it), it increments
174    /// the count of verified messages directly. Otherwise, it adds the message to
175    /// the appropriate pending queue.
176    ///
177    /// If a leader is known and the message is a [Voter::Notarize] from that leader,
178    /// this method may trigger `set_leader_proposal`.
179    ///
180    /// Recovered messages (e.g., [Voter::Notarization], [Voter::Nullification], [Voter::Finalization])
181    /// are not expected here and will cause a panic.
182    ///
183    /// # Arguments
184    ///
185    /// * `msg` - The [Voter] message to add.
186    /// * `verified` - A boolean indicating if the message has already been verified.
187    pub fn add(&mut self, msg: Voter<V, D>, verified: bool) {
188        match msg {
189            Voter::Notarize(notarize) => {
190                if let Some(ref leader_proposal) = self.leader_proposal {
191                    // If leader proposal is set and the message is not for it, drop it
192                    if leader_proposal != &notarize.proposal {
193                        return;
194                    }
195                } else if let Some(leader) = self.leader {
196                    // If leader is set but leader proposal is not, set it
197                    if leader == notarize.signer() {
198                        // Set the leader proposal
199                        self.set_leader_proposal(notarize.proposal.clone());
200                    }
201                }
202
203                // If we've made it this far, add the notarize
204                if verified {
205                    self.notarizes_verified += 1;
206                } else {
207                    self.notarizes.push(notarize);
208                }
209            }
210            Voter::Nullify(nullify) => {
211                if verified {
212                    self.nullifies_verified += 1;
213                } else {
214                    self.nullifies.push(nullify);
215                }
216            }
217            Voter::Finalize(finalize) => {
218                // If leader proposal is set and the message is not for it, drop it
219                if let Some(ref leader_proposal) = self.leader_proposal {
220                    if leader_proposal != &finalize.proposal {
221                        return;
222                    }
223                }
224
225                // If we've made it this far, add the finalize
226                if verified {
227                    self.finalizes_verified += 1;
228                } else {
229                    self.finalizes.push(finalize);
230                }
231            }
232            Voter::Notarization(_) | Voter::Nullification(_) | Voter::Finalization(_) => {
233                unreachable!("should not be adding recovered messages to partial verifier");
234            }
235        }
236    }
237
238    /// Sets the leader for the current consensus view.
239    ///
240    /// If the leader is found, we may call `set_leader_proposal` to clear any pending
241    /// messages that are not for the leader's proposal and to force verification of said
242    /// proposal.
243    ///
244    /// # Arguments
245    ///
246    /// * `leader` - The `u32` identifier of the leader.
247    pub fn set_leader(&mut self, leader: u32) {
248        // Set the leader
249        assert!(self.leader.is_none());
250        self.leader = Some(leader);
251
252        // Look for a notarize from the leader
253        let Some(notarize) = self.notarizes.iter().find(|n| n.signer() == leader) else {
254            return;
255        };
256
257        // Set the leader proposal
258        self.set_leader_proposal(notarize.proposal.clone());
259    }
260
261    /// Verifies a batch of pending [Voter::Notarize] messages.
262    ///
263    /// It uses `Notarize::verify_multiple` for efficient batch verification against
264    /// the provided `polynomial`.
265    ///
266    /// # Arguments
267    ///
268    /// * `namespace` - The namespace for signature domain separation.
269    /// * `polynomial` - The public polynomial (`Poly<V::Public>`) of the DKG.
270    ///
271    /// # Returns
272    ///
273    /// A tuple containing:
274    /// * A `Vec<Voter<V, D>>` of successfully verified [Voter::Notarize] messages (wrapped as [Voter]).
275    /// * A `Vec<u32>` of signer indices for whom verification failed.
276    pub fn verify_notarizes(
277        &mut self,
278        namespace: &[u8],
279        polynomial: &[V::Public],
280    ) -> (Vec<Voter<V, D>>, Vec<u32>) {
281        self.notarizes_force = false;
282        let (notarizes, failed) =
283            Notarize::verify_multiple(namespace, polynomial, std::mem::take(&mut self.notarizes));
284        self.notarizes_verified += notarizes.len();
285        (notarizes.into_iter().map(Voter::Notarize).collect(), failed)
286    }
287
288    /// Checks if there are [Voter::Notarize] messages ready for batch verification.
289    ///
290    /// Verification is considered "ready" if:
291    /// 1. `notarizes_force` is true (e.g., after a leader's proposal is set).
292    /// 2. A leader and their proposal are known, and:
293    ///    a. The quorum (if set) has not yet been met by verified messages.
294    ///    b. The sum of verified and pending messages is enough to potentially reach the quorum.
295    /// 3. There are pending [Voter::Notarize] messages to verify.
296    ///
297    /// # Returns
298    ///
299    /// `true` if [Voter::Notarize] messages should be verified, `false` otherwise.
300    pub fn ready_notarizes(&self) -> bool {
301        // If there are no pending notarizes, there is nothing to do.
302        if self.notarizes.is_empty() {
303            return false;
304        }
305
306        // If we have the leader's notarize, we should verify immediately to start
307        // block verification.
308        if self.notarizes_force {
309            return true;
310        }
311
312        // If we don't yet know the leader, notarizes may contain messages for
313        // a number of different proposals.
314        if self.leader.is_none() || self.leader_proposal.is_none() {
315            return false;
316        }
317
318        // If we have a quorum, we need to check if we have enough verified and pending
319        if let Some(quorum) = self.quorum {
320            // If we have already performed sufficient verifications, there is nothing more
321            // to do.
322            if self.notarizes_verified >= quorum {
323                return false;
324            }
325
326            // If we don't have enough to reach the quorum, there is nothing to do yet.
327            if self.notarizes_verified + self.notarizes.len() < quorum {
328                return false;
329            }
330        }
331
332        // If there is no required quorum and we have pending notarizes, we should verify.
333        true
334    }
335
336    /// Verifies a batch of pending [Voter::Nullify] messages.
337    ///
338    /// It uses `Nullify::verify_multiple` for efficient batch verification against
339    /// the provided `polynomial`.
340    ///
341    /// # Arguments
342    ///
343    /// * `namespace` - The namespace for signature domain separation.
344    /// * `polynomial` - The public polynomial (`Poly<V::Public>`) of the DKG.
345    ///
346    /// # Returns
347    ///
348    /// A tuple containing:
349    /// * A `Vec<Voter<V, D>>` of successfully verified [Voter::Nullify] messages (wrapped as [Voter]).
350    /// * A `Vec<u32>` of signer indices for whom verification failed.
351    pub fn verify_nullifies(
352        &mut self,
353        namespace: &[u8],
354        polynomial: &[V::Public],
355    ) -> (Vec<Voter<V, D>>, Vec<u32>) {
356        let (nullifies, failed) =
357            Nullify::verify_multiple(namespace, polynomial, std::mem::take(&mut self.nullifies));
358        self.nullifies_verified += nullifies.len();
359        (nullifies.into_iter().map(Voter::Nullify).collect(), failed)
360    }
361
362    /// Checks if there are [Voter::Nullify] messages ready for batch verification.
363    ///
364    /// Verification is considered "ready" if:
365    /// 1. The quorum (if set) has not yet been met by verified messages.
366    /// 2. The sum of verified and pending messages is enough to potentially reach the quorum.
367    /// 3. There are pending [Voter::Nullify] messages to verify.
368    ///
369    /// # Returns
370    ///
371    /// `true` if [Voter::Nullify] messages should be verified, `false` otherwise.
372    pub fn ready_nullifies(&self) -> bool {
373        // If there are no pending nullifies, there is nothing to do.
374        if self.nullifies.is_empty() {
375            return false;
376        }
377
378        if let Some(quorum) = self.quorum {
379            // If we have already performed sufficient verifications, there is nothing more
380            // to do.
381            if self.nullifies_verified >= quorum {
382                return false;
383            }
384
385            // If we don't have enough to reach the quorum, there is nothing to do yet.
386            if self.nullifies_verified + self.nullifies.len() < quorum {
387                return false;
388            }
389        }
390
391        // If there is no required quorum and we have pending nullifies, we should verify.
392        true
393    }
394
395    /// Verifies a batch of pending [Voter::Finalize] messages.
396    ///
397    /// It uses `Finalize::verify_multiple` for efficient batch verification against
398    /// the provided `polynomial`.
399    ///
400    /// # Arguments
401    ///
402    /// * `namespace` - The namespace for signature domain separation.
403    /// * `polynomial` - The public polynomial (`Poly<V::Public>`) of the DKG.
404    ///
405    /// # Returns
406    ///
407    /// A tuple containing:
408    /// * A `Vec<Voter<V, D>>` of successfully verified [Voter::Finalize] messages (wrapped as [Voter]).
409    /// * A `Vec<u32>` of signer indices for whom verification failed.
410    pub fn verify_finalizes(
411        &mut self,
412        namespace: &[u8],
413        polynomial: &[V::Public],
414    ) -> (Vec<Voter<V, D>>, Vec<u32>) {
415        let (finalizes, failed) =
416            Finalize::verify_multiple(namespace, polynomial, std::mem::take(&mut self.finalizes));
417        self.finalizes_verified += finalizes.len();
418        (finalizes.into_iter().map(Voter::Finalize).collect(), failed)
419    }
420
421    /// Checks if there are [Voter::Finalize] messages ready for batch verification.
422    ///
423    /// Verification is considered "ready" if:
424    /// 1. A leader and their proposal are known (finalizes are proposal-specific).
425    /// 2. The quorum (if set) has not yet been met by verified messages.
426    /// 3. The sum of verified and pending messages is enough to potentially reach the quorum.
427    /// 4. There are pending [Voter::Finalize] messages to verify.
428    ///
429    /// # Returns
430    ///
431    /// `true` if [Voter::Finalize] messages should be verified, `false` otherwise.
432    pub fn ready_finalizes(&self) -> bool {
433        // If there are no pending finalizes, there is nothing to do.
434        if self.finalizes.is_empty() {
435            return false;
436        }
437
438        // If we don't yet know the leader, finalizers may contain messages for
439        // a number of different proposals.
440        if self.leader.is_none() || self.leader_proposal.is_none() {
441            return false;
442        }
443        if let Some(quorum) = self.quorum {
444            // If we have already performed sufficient verifications, there is nothing more
445            // to do.
446            if self.finalizes_verified >= quorum {
447                return false;
448            }
449
450            // If we don't have enough to reach the quorum, there is nothing to do yet.
451            if self.finalizes_verified + self.finalizes.len() < quorum {
452                return false;
453            }
454        }
455
456        // If there is no required quorum and we have pending finalizes, we should verify.
457        true
458    }
459}
460
461/// Voter represents all possible message types that can be sent by validators
462/// in the consensus protocol.
463#[derive(Clone, Debug, PartialEq)]
464pub enum Voter<V: Variant, D: Digest> {
465    /// A single validator notarize over a proposal
466    Notarize(Notarize<V, D>),
467    /// A recovered threshold signature for a notarization
468    Notarization(Notarization<V, D>),
469    /// A single validator nullify to skip the current view (usually when leader is unresponsive)
470    Nullify(Nullify<V>),
471    /// A recovered threshold signature for a nullification
472    Nullification(Nullification<V>),
473    /// A single validator finalize over a proposal
474    Finalize(Finalize<V, D>),
475    /// A recovered threshold signature for a finalization
476    Finalization(Finalization<V, D>),
477}
478
479impl<V: Variant, D: Digest> Write for Voter<V, D> {
480    fn write(&self, writer: &mut impl BufMut) {
481        match self {
482            Voter::Notarize(v) => {
483                0u8.write(writer);
484                v.write(writer);
485            }
486            Voter::Notarization(v) => {
487                1u8.write(writer);
488                v.write(writer);
489            }
490            Voter::Nullify(v) => {
491                2u8.write(writer);
492                v.write(writer);
493            }
494            Voter::Nullification(v) => {
495                3u8.write(writer);
496                v.write(writer);
497            }
498            Voter::Finalize(v) => {
499                4u8.write(writer);
500                v.write(writer);
501            }
502            Voter::Finalization(v) => {
503                5u8.write(writer);
504                v.write(writer);
505            }
506        }
507    }
508}
509
510impl<V: Variant, D: Digest> EncodeSize for Voter<V, D> {
511    fn encode_size(&self) -> usize {
512        1 + match self {
513            Voter::Notarize(v) => v.encode_size(),
514            Voter::Notarization(v) => v.encode_size(),
515            Voter::Nullify(v) => v.encode_size(),
516            Voter::Nullification(v) => v.encode_size(),
517            Voter::Finalize(v) => v.encode_size(),
518            Voter::Finalization(v) => v.encode_size(),
519        }
520    }
521}
522
523impl<V: Variant, D: Digest> Read for Voter<V, D> {
524    type Cfg = ();
525
526    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
527        let tag = <u8>::read(reader)?;
528        match tag {
529            0 => {
530                let v = Notarize::read(reader)?;
531                Ok(Voter::Notarize(v))
532            }
533            1 => {
534                let v = Notarization::read(reader)?;
535                Ok(Voter::Notarization(v))
536            }
537            2 => {
538                let v = Nullify::read(reader)?;
539                Ok(Voter::Nullify(v))
540            }
541            3 => {
542                let v = Nullification::read(reader)?;
543                Ok(Voter::Nullification(v))
544            }
545            4 => {
546                let v = Finalize::read(reader)?;
547                Ok(Voter::Finalize(v))
548            }
549            5 => {
550                let v = Finalization::read(reader)?;
551                Ok(Voter::Finalization(v))
552            }
553            _ => Err(Error::Invalid(
554                "consensus::threshold_simplex::Voter",
555                "Invalid type",
556            )),
557        }
558    }
559}
560
561impl<V: Variant, D: Digest> Viewable for Voter<V, D> {
562    type View = View;
563
564    fn view(&self) -> View {
565        match self {
566            Voter::Notarize(v) => v.view(),
567            Voter::Notarization(v) => v.view(),
568            Voter::Nullify(v) => v.view(),
569            Voter::Nullification(v) => v.view(),
570            Voter::Finalize(v) => v.view(),
571            Voter::Finalization(v) => v.view(),
572        }
573    }
574}
575
576/// Proposal represents a proposed block in the protocol.
577/// It includes the view number, the parent view, and the actual payload (typically a digest of block data).
578#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
579pub struct Proposal<D: Digest> {
580    /// The view (round) in which this proposal is made
581    pub view: View,
582    /// The view of the parent proposal that this one builds upon
583    pub parent: View,
584    /// The actual payload/content of the proposal (typically a digest of the block data)
585    pub payload: D,
586}
587
588impl<D: Digest> Proposal<D> {
589    /// Creates a new proposal with the specified view, parent view, and payload.
590    pub fn new(view: View, parent: View, payload: D) -> Self {
591        Proposal {
592            view,
593            parent,
594            payload,
595        }
596    }
597}
598
599impl<D: Digest> Write for Proposal<D> {
600    fn write(&self, writer: &mut impl BufMut) {
601        UInt(self.view).write(writer);
602        UInt(self.parent).write(writer);
603        self.payload.write(writer)
604    }
605}
606
607impl<D: Digest> Read for Proposal<D> {
608    type Cfg = ();
609
610    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
611        let view = UInt::read(reader)?.into();
612        let parent = UInt::read(reader)?.into();
613        let payload = D::read(reader)?;
614        Ok(Self {
615            view,
616            parent,
617            payload,
618        })
619    }
620}
621
622impl<D: Digest> EncodeSize for Proposal<D> {
623    fn encode_size(&self) -> usize {
624        UInt(self.view).encode_size() + UInt(self.parent).encode_size() + self.payload.encode_size()
625    }
626}
627
628impl<D: Digest> Viewable for Proposal<D> {
629    type View = View;
630
631    fn view(&self) -> View {
632        self.view
633    }
634}
635
636/// Notarize represents a validator's vote to notarize a proposal.
637/// In threshold_simplex, it contains a partial signature on the proposal and a partial signature for the seed.
638/// The seed is used for leader election and as a source of randomness.
639#[derive(Clone, Debug, PartialEq, Hash, Eq)]
640pub struct Notarize<V: Variant, D: Digest> {
641    /// The proposal that is being notarized
642    pub proposal: Proposal<D>,
643    /// The validator's partial signature on the proposal
644    pub proposal_signature: PartialSignature<V>,
645    /// The validator's partial signature on the seed (for leader election/randomness)
646    pub seed_signature: PartialSignature<V>,
647}
648
649impl<V: Variant, D: Digest> Notarize<V, D> {
650    /// Creates a new notarize with the given proposal and signatures.
651    pub fn new(
652        proposal: Proposal<D>,
653        proposal_signature: PartialSignature<V>,
654        seed_signature: PartialSignature<V>,
655    ) -> Self {
656        Notarize {
657            proposal,
658            proposal_signature,
659            seed_signature,
660        }
661    }
662
663    /// Verifies the [PartialSignature]s on this [Notarize].
664    ///
665    /// This ensures that:
666    /// 1. The notarize signature is valid for the claimed proposal
667    /// 2. The seed signature is valid for the view
668    /// 3. Both signatures are from the same signer
669    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
670        let notarize_namespace = notarize_namespace(namespace);
671        let notarize_message = self.proposal.encode();
672        let notarize_message = (Some(notarize_namespace.as_ref()), notarize_message.as_ref());
673        let seed_namespace = seed_namespace(namespace);
674        let seed_message = view_message(self.proposal.view);
675        let seed_message = (Some(seed_namespace.as_ref()), seed_message.as_ref());
676        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
677            return false;
678        };
679        let signature = aggregate_signatures::<V, _>(&[
680            self.proposal_signature.value,
681            self.seed_signature.value,
682        ]);
683        aggregate_verify_multiple_messages::<V, _>(
684            evaluated,
685            &[notarize_message, seed_message],
686            &signature,
687            1,
688        )
689        .is_ok()
690    }
691
692    /// Verifies a batch of [Notarize] messages using BLS aggregate verification.
693    ///
694    /// This function verifies a batch of [Notarize] messages using BLS aggregate verification.
695    /// It returns a tuple containing:
696    /// * A vector of successfully verified [Notarize] messages.
697    /// * A vector of signer indices for whom verification failed.
698    pub fn verify_multiple(
699        namespace: &[u8],
700        polynomial: &[V::Public],
701        notarizes: Vec<Notarize<V, D>>,
702    ) -> (Vec<Notarize<V, D>>, Vec<u32>) {
703        // Prepare to verify
704        if notarizes.is_empty() {
705            return (notarizes, vec![]);
706        } else if notarizes.len() == 1 {
707            // If there is only one notarize, verify it directly (will perform
708            // inner aggregation)
709            let valid = notarizes[0].verify(namespace, polynomial);
710            if valid {
711                return (notarizes, vec![]);
712            } else {
713                return (vec![], vec![notarizes[0].signer()]);
714            }
715        }
716        let proposal = &notarizes[0].proposal;
717        let mut invalid = BTreeSet::new();
718
719        // Verify proposal signatures
720        let notarize_namespace = notarize_namespace(namespace);
721        let notarize_message = proposal.encode();
722        let notarize_signatures = notarizes.iter().map(|n| &n.proposal_signature);
723        if let Err(err) = partial_verify_multiple_public_keys_precomputed::<V, _>(
724            polynomial,
725            Some(&notarize_namespace),
726            &notarize_message,
727            notarize_signatures,
728        ) {
729            for signature in err.iter() {
730                invalid.insert(signature.index);
731            }
732        }
733
734        // Verify seed signatures
735        let seed_namespace = seed_namespace(namespace);
736        let seed_message = view_message(proposal.view);
737        let seed_signatures = notarizes
738            .iter()
739            .filter(|n| !invalid.contains(&n.seed_signature.index))
740            .map(|n| &n.seed_signature);
741        if let Err(err) = partial_verify_multiple_public_keys_precomputed::<V, _>(
742            polynomial,
743            Some(&seed_namespace),
744            &seed_message,
745            seed_signatures,
746        ) {
747            for signature in err.iter() {
748                invalid.insert(signature.index);
749            }
750        }
751
752        // Remove invalid notarizes
753        (
754            notarizes
755                .into_iter()
756                .filter(|n| !invalid.contains(&n.signer()))
757                .collect(),
758            invalid.into_iter().collect(),
759        )
760    }
761
762    /// Creates a [PartialSignature] over this [Notarize].
763    pub fn sign(namespace: &[u8], share: &Share, proposal: Proposal<D>) -> Self {
764        let notarize_namespace = notarize_namespace(namespace);
765        let proposal_message = proposal.encode();
766        let proposal_signature =
767            partial_sign_message::<V>(share, Some(notarize_namespace.as_ref()), &proposal_message);
768        let seed_namespace = seed_namespace(namespace);
769        let seed_message = view_message(proposal.view);
770        let seed_signature =
771            partial_sign_message::<V>(share, Some(seed_namespace.as_ref()), &seed_message);
772        Notarize::new(proposal, proposal_signature, seed_signature)
773    }
774}
775
776impl<V: Variant, D: Digest> Attributable for Notarize<V, D> {
777    fn signer(&self) -> u32 {
778        self.proposal_signature.index
779    }
780}
781
782impl<V: Variant, D: Digest> Viewable for Notarize<V, D> {
783    type View = View;
784
785    fn view(&self) -> View {
786        self.proposal.view()
787    }
788}
789
790impl<V: Variant, D: Digest> Write for Notarize<V, D> {
791    fn write(&self, writer: &mut impl BufMut) {
792        self.proposal.write(writer);
793        self.proposal_signature.write(writer);
794        self.seed_signature.write(writer);
795    }
796}
797
798impl<V: Variant, D: Digest> Read for Notarize<V, D> {
799    type Cfg = ();
800
801    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
802        let proposal = Proposal::read(reader)?;
803        let proposal_signature = PartialSignature::<V>::read(reader)?;
804        let seed_signature = PartialSignature::<V>::read(reader)?;
805        if proposal_signature.index != seed_signature.index {
806            return Err(Error::Invalid(
807                "consensus::threshold_simplex::Notarize",
808                "mismatched signatures",
809            ));
810        }
811        Ok(Notarize {
812            proposal,
813            proposal_signature,
814            seed_signature,
815        })
816    }
817}
818
819impl<V: Variant, D: Digest> EncodeSize for Notarize<V, D> {
820    fn encode_size(&self) -> usize {
821        self.proposal.encode_size()
822            + self.proposal_signature.encode_size()
823            + self.seed_signature.encode_size()
824    }
825}
826
827/// Notarization represents a recovered threshold signature certifying a proposal.
828/// When a proposal is notarized, it means at least 2f+1 validators have voted for it.
829/// The threshold signatures provide compact verification compared to collecting individual signatures.
830#[derive(Clone, Debug, PartialEq, Hash, Eq)]
831pub struct Notarization<V: Variant, D: Digest> {
832    /// The proposal that has been notarized
833    pub proposal: Proposal<D>,
834    /// The recovered threshold signature on the proposal
835    pub proposal_signature: V::Signature,
836    /// The recovered threshold signature on the seed (for leader election/randomness)
837    pub seed_signature: V::Signature,
838}
839
840impl<V: Variant, D: Digest> Notarization<V, D> {
841    /// Creates a new notarization with the given proposal and aggregated signatures.
842    pub fn new(
843        proposal: Proposal<D>,
844        proposal_signature: V::Signature,
845        seed_signature: V::Signature,
846    ) -> Self {
847        Notarization {
848            proposal,
849            proposal_signature,
850            seed_signature,
851        }
852    }
853
854    /// Verifies the threshold signatures on this [Notarization].
855    ///
856    /// This ensures that:
857    /// 1. The notarization signature is a valid threshold signature for the proposal
858    /// 2. The seed signature is a valid threshold signature for the view
859    pub fn verify(&self, namespace: &[u8], identity: &V::Public) -> bool {
860        let notarize_namespace = notarize_namespace(namespace);
861        let notarize_message = self.proposal.encode();
862        let notarize_message = (Some(notarize_namespace.as_ref()), notarize_message.as_ref());
863        let seed_namespace = seed_namespace(namespace);
864        let seed_message = view_message(self.proposal.view);
865        let seed_message = (Some(seed_namespace.as_ref()), seed_message.as_ref());
866        let signature =
867            aggregate_signatures::<V, _>(&[self.proposal_signature, self.seed_signature]);
868        aggregate_verify_multiple_messages::<V, _>(
869            identity,
870            &[notarize_message, seed_message],
871            &signature,
872            1,
873        )
874        .is_ok()
875    }
876}
877
878impl<V: Variant, D: Digest> Viewable for Notarization<V, D> {
879    type View = View;
880
881    fn view(&self) -> View {
882        self.proposal.view()
883    }
884}
885
886impl<V: Variant, D: Digest> Write for Notarization<V, D> {
887    fn write(&self, writer: &mut impl BufMut) {
888        self.proposal.write(writer);
889        self.proposal_signature.write(writer);
890        self.seed_signature.write(writer)
891    }
892}
893
894impl<V: Variant, D: Digest> Read for Notarization<V, D> {
895    type Cfg = ();
896
897    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
898        let proposal = Proposal::read(reader)?;
899        let proposal_signature = V::Signature::read(reader)?;
900        let seed_signature = V::Signature::read(reader)?;
901        Ok(Notarization {
902            proposal,
903            proposal_signature,
904            seed_signature,
905        })
906    }
907}
908
909impl<V: Variant, D: Digest> EncodeSize for Notarization<V, D> {
910    fn encode_size(&self) -> usize {
911        self.proposal.encode_size()
912            + self.proposal_signature.encode_size()
913            + self.seed_signature.encode_size()
914    }
915}
916
917impl<V: Variant, D: Digest> Seedable<V> for Notarization<V, D> {
918    fn seed(&self) -> Seed<V> {
919        Seed::new(self.view(), self.seed_signature)
920    }
921}
922
923/// Nullify represents a validator's vote to skip the current view.
924/// This is typically used when the leader is unresponsive or fails to propose a valid block.
925/// It contains partial signatures for the view and seed.
926#[derive(Clone, Debug, PartialEq, Hash, Eq)]
927pub struct Nullify<V: Variant> {
928    /// The view to be nullified (skipped)
929    pub view: View,
930    /// The validator's partial signature on the view
931    pub view_signature: PartialSignature<V>,
932    /// The validator's partial signature on the seed (for leader election/randomness)
933    pub seed_signature: PartialSignature<V>,
934}
935
936impl<V: Variant> Nullify<V> {
937    /// Creates a new nullify with the given view and signatures.
938    pub fn new(
939        view: View,
940        view_signature: PartialSignature<V>,
941        seed_signature: PartialSignature<V>,
942    ) -> Self {
943        Nullify {
944            view,
945            view_signature,
946            seed_signature,
947        }
948    }
949
950    /// Verifies the [PartialSignature]s on this [Nullify].
951    ///
952    /// This ensures that:
953    /// 1. The view signature is valid for the given view
954    /// 2. The seed signature is valid for the view
955    /// 3. Both signatures are from the same signer
956    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
957        let nullify_namespace = nullify_namespace(namespace);
958        let view_message = view_message(self.view);
959        let nullify_message = (Some(nullify_namespace.as_ref()), view_message.as_ref());
960        let seed_namespace = seed_namespace(namespace);
961        let seed_message = (Some(seed_namespace.as_ref()), view_message.as_ref());
962        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
963            return false;
964        };
965        let signature =
966            aggregate_signatures::<V, _>(&[self.view_signature.value, self.seed_signature.value]);
967        aggregate_verify_multiple_messages::<V, _>(
968            evaluated,
969            &[nullify_message, seed_message],
970            &signature,
971            1,
972        )
973        .is_ok()
974    }
975
976    /// Verifies a batch of [Nullify] messages using BLS aggregate verification.
977    ///
978    /// This function verifies a batch of [Nullify] messages using BLS aggregate verification.
979    /// It returns a tuple containing:
980    /// * A vector of successfully verified [Nullify] messages.
981    /// * A vector of signer indices for whom verification failed.
982    pub fn verify_multiple(
983        namespace: &[u8],
984        polynomial: &[V::Public],
985        nullifies: Vec<Nullify<V>>,
986    ) -> (Vec<Nullify<V>>, Vec<u32>) {
987        // Prepare to verify
988        if nullifies.is_empty() {
989            return (nullifies, vec![]);
990        } else if nullifies.len() == 1 {
991            let valid = nullifies[0].verify(namespace, polynomial);
992            if valid {
993                return (nullifies, vec![]);
994            } else {
995                return (vec![], vec![nullifies[0].signer()]);
996            }
997        }
998        let selected = &nullifies[0];
999        let mut invalid = BTreeSet::new();
1000
1001        // Verify view signature
1002        let nullify_namespace = nullify_namespace(namespace);
1003        let view_message = view_message(selected.view);
1004        let view_signatures = nullifies.iter().map(|n| &n.view_signature);
1005        if let Err(err) = partial_verify_multiple_public_keys_precomputed::<V, _>(
1006            polynomial,
1007            Some(&nullify_namespace),
1008            &view_message,
1009            view_signatures,
1010        ) {
1011            for signature in err.iter() {
1012                invalid.insert(signature.index);
1013            }
1014        }
1015
1016        // Verify seed signature
1017        let seed_namespace = seed_namespace(namespace);
1018        let seed_signatures = nullifies
1019            .iter()
1020            .filter(|n| !invalid.contains(&n.seed_signature.index))
1021            .map(|n| &n.seed_signature);
1022        if let Err(err) = partial_verify_multiple_public_keys_precomputed::<V, _>(
1023            polynomial,
1024            Some(&seed_namespace),
1025            &view_message,
1026            seed_signatures,
1027        ) {
1028            for signature in err.iter() {
1029                invalid.insert(signature.index);
1030            }
1031        }
1032
1033        // Return valid nullifies and invalid signers
1034        (
1035            nullifies
1036                .into_iter()
1037                .filter(|n| !invalid.contains(&n.signer()))
1038                .collect(),
1039            invalid.into_iter().collect(),
1040        )
1041    }
1042
1043    /// Creates a [PartialSignature] over this [Nullify].
1044    pub fn sign(namespace: &[u8], share: &Share, view: View) -> Self {
1045        let nullify_namespace = nullify_namespace(namespace);
1046        let view_message = view_message(view);
1047        let view_signature =
1048            partial_sign_message::<V>(share, Some(nullify_namespace.as_ref()), &view_message);
1049        let seed_namespace = seed_namespace(namespace);
1050        let seed_signature =
1051            partial_sign_message::<V>(share, Some(seed_namespace.as_ref()), &view_message);
1052        Nullify::new(view, view_signature, seed_signature)
1053    }
1054}
1055
1056impl<V: Variant> Attributable for Nullify<V> {
1057    fn signer(&self) -> u32 {
1058        self.view_signature.index
1059    }
1060}
1061
1062impl<V: Variant> Viewable for Nullify<V> {
1063    type View = View;
1064
1065    fn view(&self) -> View {
1066        self.view
1067    }
1068}
1069
1070impl<V: Variant> Write for Nullify<V> {
1071    fn write(&self, writer: &mut impl BufMut) {
1072        UInt(self.view).write(writer);
1073        self.view_signature.write(writer);
1074        self.seed_signature.write(writer);
1075    }
1076}
1077
1078impl<V: Variant> Read for Nullify<V> {
1079    type Cfg = ();
1080
1081    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1082        let view = UInt::read(reader)?.into();
1083        let view_signature = PartialSignature::<V>::read(reader)?;
1084        let seed_signature = PartialSignature::<V>::read(reader)?;
1085        if view_signature.index != seed_signature.index {
1086            return Err(Error::Invalid(
1087                "consensus::threshold_simplex::Nullify",
1088                "mismatched signatures",
1089            ));
1090        }
1091        Ok(Nullify {
1092            view,
1093            view_signature,
1094            seed_signature,
1095        })
1096    }
1097}
1098
1099impl<V: Variant> EncodeSize for Nullify<V> {
1100    fn encode_size(&self) -> usize {
1101        UInt(self.view).encode_size()
1102            + self.view_signature.encode_size()
1103            + self.seed_signature.encode_size()
1104    }
1105}
1106
1107/// Nullification represents a recovered threshold signature to skip a view.
1108/// When a view is nullified, the consensus moves to the next view without finalizing a block.
1109/// The threshold signatures provide compact verification compared to collecting individual signatures.
1110#[derive(Clone, Debug, PartialEq, Hash, Eq)]
1111pub struct Nullification<V: Variant> {
1112    /// The view that has been nullified
1113    pub view: View,
1114    /// The recovered threshold signature on the view
1115    pub view_signature: V::Signature,
1116    /// The recovered threshold signature on the seed (for leader election/randomness)
1117    pub seed_signature: V::Signature,
1118}
1119
1120impl<V: Variant> Nullification<V> {
1121    /// Creates a new nullification with the given view and aggregated signatures.
1122    pub fn new(view: View, view_signature: V::Signature, seed_signature: V::Signature) -> Self {
1123        Nullification {
1124            view,
1125            view_signature,
1126            seed_signature,
1127        }
1128    }
1129
1130    /// Verifies the threshold signatures on this [Nullification].
1131    ///
1132    /// This ensures that:
1133    /// 1. The view signature is a valid threshold signature for the view
1134    /// 2. The seed signature is a valid threshold signature for the view
1135    pub fn verify(&self, namespace: &[u8], identity: &V::Public) -> bool {
1136        let nullify_namespace = nullify_namespace(namespace);
1137        let view_message = view_message(self.view);
1138        let nullify_message = (Some(nullify_namespace.as_ref()), view_message.as_ref());
1139        let seed_namespace = seed_namespace(namespace);
1140        let seed_message = (Some(seed_namespace.as_ref()), view_message.as_ref());
1141        let signature = aggregate_signatures::<V, _>(&[self.view_signature, self.seed_signature]);
1142        aggregate_verify_multiple_messages::<V, _>(
1143            identity,
1144            &[nullify_message, seed_message],
1145            &signature,
1146            1,
1147        )
1148        .is_ok()
1149    }
1150}
1151
1152impl<V: Variant> Viewable for Nullification<V> {
1153    type View = View;
1154
1155    fn view(&self) -> View {
1156        self.view
1157    }
1158}
1159
1160impl<V: Variant> Write for Nullification<V> {
1161    fn write(&self, writer: &mut impl BufMut) {
1162        UInt(self.view).write(writer);
1163        self.view_signature.write(writer);
1164        self.seed_signature.write(writer);
1165    }
1166}
1167
1168impl<V: Variant> Read for Nullification<V> {
1169    type Cfg = ();
1170
1171    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1172        let view = UInt::read(reader)?.into();
1173        let view_signature = V::Signature::read(reader)?;
1174        let seed_signature = V::Signature::read(reader)?;
1175        Ok(Nullification {
1176            view,
1177            view_signature,
1178            seed_signature,
1179        })
1180    }
1181}
1182
1183impl<V: Variant> EncodeSize for Nullification<V> {
1184    fn encode_size(&self) -> usize {
1185        UInt(self.view).encode_size()
1186            + self.view_signature.encode_size()
1187            + self.seed_signature.encode_size()
1188    }
1189}
1190
1191impl<V: Variant> Seedable<V> for Nullification<V> {
1192    fn seed(&self) -> Seed<V> {
1193        Seed::new(self.view(), self.seed_signature)
1194    }
1195}
1196
1197/// Finalize represents a validator's vote to finalize a proposal.
1198/// This happens after a proposal has been notarized, confirming it as the canonical block for this view.
1199/// It contains a partial signature on the proposal.
1200#[derive(Clone, Debug, PartialEq, Hash, Eq)]
1201pub struct Finalize<V: Variant, D: Digest> {
1202    /// The proposal to be finalized
1203    pub proposal: Proposal<D>,
1204    /// The validator's partial signature on the proposal
1205    pub proposal_signature: PartialSignature<V>,
1206}
1207
1208impl<V: Variant, D: Digest> Finalize<V, D> {
1209    /// Creates a new finalize with the given proposal and signature.
1210    pub fn new(proposal: Proposal<D>, proposal_signature: PartialSignature<V>) -> Self {
1211        Finalize {
1212            proposal,
1213            proposal_signature,
1214        }
1215    }
1216
1217    /// Verifies the [PartialSignature] on this [Finalize].
1218    ///
1219    /// This ensures that the signature is valid for the given proposal.
1220    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
1221        let finalize_namespace = finalize_namespace(namespace);
1222        let message = self.proposal.encode();
1223        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
1224            return false;
1225        };
1226        verify_message::<V>(
1227            evaluated,
1228            Some(finalize_namespace.as_ref()),
1229            &message,
1230            &self.proposal_signature.value,
1231        )
1232        .is_ok()
1233    }
1234
1235    /// Verifies a batch of [Finalize] messages using BLS aggregate verification.
1236    ///
1237    /// This function verifies a batch of [Finalize] messages using BLS aggregate verification.
1238    /// It returns a tuple containing:
1239    /// * A vector of successfully verified [Finalize] messages.
1240    /// * A vector of signer indices for whom verification failed.
1241    pub fn verify_multiple(
1242        namespace: &[u8],
1243        polynomial: &[V::Public],
1244        finalizes: Vec<Finalize<V, D>>,
1245    ) -> (Vec<Finalize<V, D>>, Vec<u32>) {
1246        // Prepare to verify
1247        if finalizes.is_empty() {
1248            return (finalizes, vec![]);
1249        } else if finalizes.len() == 1 {
1250            let valid = finalizes[0].verify(namespace, polynomial);
1251            if valid {
1252                return (finalizes, vec![]);
1253            } else {
1254                return (vec![], vec![finalizes[0].signer()]);
1255            }
1256        }
1257        let proposal = &finalizes[0].proposal;
1258        let mut invalid = BTreeSet::new();
1259
1260        // Verify proposal signature
1261        let finalize_namespace = finalize_namespace(namespace);
1262        let finalize_message = proposal.encode();
1263        let finalize_signatures = finalizes.iter().map(|f| &f.proposal_signature);
1264        if let Err(err) = partial_verify_multiple_public_keys_precomputed::<V, _>(
1265            polynomial,
1266            Some(&finalize_namespace),
1267            &finalize_message,
1268            finalize_signatures,
1269        ) {
1270            for signature in err.iter() {
1271                invalid.insert(signature.index);
1272            }
1273        }
1274
1275        // Return valid finalizes and invalid signers
1276        (
1277            finalizes
1278                .into_iter()
1279                .filter(|f| !invalid.contains(&f.signer()))
1280                .collect(),
1281            invalid.into_iter().collect(),
1282        )
1283    }
1284
1285    /// Creates a [PartialSignature] over this [Finalize].
1286    pub fn sign(namespace: &[u8], share: &Share, proposal: Proposal<D>) -> Self {
1287        let finalize_namespace = finalize_namespace(namespace);
1288        let message = proposal.encode();
1289        let proposal_signature =
1290            partial_sign_message::<V>(share, Some(finalize_namespace.as_ref()), &message);
1291        Finalize::new(proposal, proposal_signature)
1292    }
1293}
1294
1295impl<V: Variant, D: Digest> Attributable for Finalize<V, D> {
1296    fn signer(&self) -> u32 {
1297        self.proposal_signature.index
1298    }
1299}
1300
1301impl<V: Variant, D: Digest> Viewable for Finalize<V, D> {
1302    type View = View;
1303
1304    fn view(&self) -> View {
1305        self.proposal.view()
1306    }
1307}
1308
1309impl<V: Variant, D: Digest> Write for Finalize<V, D> {
1310    fn write(&self, writer: &mut impl BufMut) {
1311        self.proposal.write(writer);
1312        self.proposal_signature.write(writer);
1313    }
1314}
1315
1316impl<V: Variant, D: Digest> Read for Finalize<V, D> {
1317    type Cfg = ();
1318
1319    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1320        let proposal = Proposal::read(reader)?;
1321        let proposal_signature = PartialSignature::<V>::read(reader)?;
1322        Ok(Finalize {
1323            proposal,
1324            proposal_signature,
1325        })
1326    }
1327}
1328
1329impl<V: Variant, D: Digest> EncodeSize for Finalize<V, D> {
1330    fn encode_size(&self) -> usize {
1331        self.proposal.encode_size() + self.proposal_signature.encode_size()
1332    }
1333}
1334
1335/// Finalization represents a recovered threshold signature to finalize a proposal.
1336/// When a proposal is finalized, it becomes the canonical block for its view.
1337/// The threshold signatures provide compact verification compared to collecting individual signatures.
1338#[derive(Clone, Debug, PartialEq, Hash, Eq)]
1339pub struct Finalization<V: Variant, D: Digest> {
1340    /// The proposal that has been finalized
1341    pub proposal: Proposal<D>,
1342    /// The recovered threshold signature on the proposal
1343    pub proposal_signature: V::Signature,
1344    /// The recovered threshold signature on the seed (for leader election/randomness)
1345    pub seed_signature: V::Signature,
1346}
1347
1348impl<V: Variant, D: Digest> Finalization<V, D> {
1349    /// Creates a new finalization with the given proposal and aggregated signatures.
1350    pub fn new(
1351        proposal: Proposal<D>,
1352        proposal_signature: V::Signature,
1353        seed_signature: V::Signature,
1354    ) -> Self {
1355        Finalization {
1356            proposal,
1357            proposal_signature,
1358            seed_signature,
1359        }
1360    }
1361
1362    /// Verifies the threshold signatures on this [Finalization].
1363    ///
1364    /// This ensures that:
1365    /// 1. The proposal signature is a valid threshold signature for the proposal
1366    /// 2. The seed signature is a valid threshold signature for the view
1367    pub fn verify(&self, namespace: &[u8], identity: &V::Public) -> bool {
1368        let finalize_namespace = finalize_namespace(namespace);
1369        let finalize_message = self.proposal.encode();
1370        let finalize_message = (Some(finalize_namespace.as_ref()), finalize_message.as_ref());
1371        let seed_namespace = seed_namespace(namespace);
1372        let seed_message = view_message(self.proposal.view);
1373        let seed_message = (Some(seed_namespace.as_ref()), seed_message.as_ref());
1374        let signature =
1375            aggregate_signatures::<V, _>(&[self.proposal_signature, self.seed_signature]);
1376        aggregate_verify_multiple_messages::<V, _>(
1377            identity,
1378            &[finalize_message, seed_message],
1379            &signature,
1380            1,
1381        )
1382        .is_ok()
1383    }
1384}
1385
1386impl<V: Variant, D: Digest> Viewable for Finalization<V, D> {
1387    type View = View;
1388
1389    fn view(&self) -> View {
1390        self.proposal.view()
1391    }
1392}
1393
1394impl<V: Variant, D: Digest> Write for Finalization<V, D> {
1395    fn write(&self, writer: &mut impl BufMut) {
1396        self.proposal.write(writer);
1397        self.proposal_signature.write(writer);
1398        self.seed_signature.write(writer);
1399    }
1400}
1401
1402impl<V: Variant, D: Digest> Read for Finalization<V, D> {
1403    type Cfg = ();
1404
1405    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1406        let proposal = Proposal::read(reader)?;
1407        let proposal_signature = V::Signature::read(reader)?;
1408        let seed_signature = V::Signature::read(reader)?;
1409        Ok(Finalization {
1410            proposal,
1411            proposal_signature,
1412            seed_signature,
1413        })
1414    }
1415}
1416
1417impl<V: Variant, D: Digest> EncodeSize for Finalization<V, D> {
1418    fn encode_size(&self) -> usize {
1419        self.proposal.encode_size()
1420            + self.proposal_signature.encode_size()
1421            + self.seed_signature.encode_size()
1422    }
1423}
1424
1425impl<V: Variant, D: Digest> Seedable<V> for Finalization<V, D> {
1426    fn seed(&self) -> Seed<V> {
1427        Seed::new(self.view(), self.seed_signature)
1428    }
1429}
1430
1431/// Backfiller is a message type for requesting and receiving missing consensus artifacts.
1432/// This is used to synchronize validators that have fallen behind or just joined the network.
1433#[derive(Clone, Debug, PartialEq)]
1434pub enum Backfiller<V: Variant, D: Digest> {
1435    /// Request for missing notarizations and nullifications
1436    Request(Request),
1437    /// Response containing requested notarizations and nullifications
1438    Response(Response<V, D>),
1439}
1440
1441impl<V: Variant, D: Digest> Write for Backfiller<V, D> {
1442    fn write(&self, writer: &mut impl BufMut) {
1443        match self {
1444            Backfiller::Request(v) => {
1445                0u8.write(writer);
1446                v.write(writer);
1447            }
1448            Backfiller::Response(v) => {
1449                1u8.write(writer);
1450                v.write(writer);
1451            }
1452        }
1453    }
1454}
1455
1456impl<V: Variant, D: Digest> EncodeSize for Backfiller<V, D> {
1457    fn encode_size(&self) -> usize {
1458        1 + match self {
1459            Backfiller::Request(v) => v.encode_size(),
1460            Backfiller::Response(v) => v.encode_size(),
1461        }
1462    }
1463}
1464
1465impl<V: Variant, D: Digest> Read for Backfiller<V, D> {
1466    type Cfg = usize;
1467
1468    fn read_cfg(reader: &mut impl Buf, cfg: &usize) -> Result<Self, Error> {
1469        let tag = <u8>::read(reader)?;
1470        match tag {
1471            0 => {
1472                let v = Request::read_cfg(reader, cfg)?;
1473                Ok(Backfiller::Request(v))
1474            }
1475            1 => {
1476                let v = Response::<V, D>::read_cfg(reader, cfg)?;
1477                Ok(Backfiller::Response(v))
1478            }
1479            _ => Err(Error::Invalid(
1480                "consensus::threshold_simplex::Backfiller",
1481                "Invalid type",
1482            )),
1483        }
1484    }
1485}
1486
1487/// Request is a message to request missing notarizations and nullifications.
1488/// This is used by validators who need to catch up with the consensus state.
1489#[derive(Clone, Debug, PartialEq)]
1490pub struct Request {
1491    /// Unique identifier for this request (used to match responses)
1492    pub id: u64,
1493    /// Views for which notarizations are requested
1494    pub notarizations: Vec<View>,
1495    /// Views for which nullifications are requested
1496    pub nullifications: Vec<View>,
1497}
1498
1499impl Request {
1500    /// Creates a new request for missing notarizations and nullifications.
1501    pub fn new(id: u64, notarizations: Vec<View>, nullifications: Vec<View>) -> Self {
1502        Request {
1503            id,
1504            notarizations,
1505            nullifications,
1506        }
1507    }
1508}
1509
1510impl Write for Request {
1511    fn write(&self, writer: &mut impl BufMut) {
1512        UInt(self.id).write(writer);
1513        self.notarizations.write(writer);
1514        self.nullifications.write(writer);
1515    }
1516}
1517
1518impl EncodeSize for Request {
1519    fn encode_size(&self) -> usize {
1520        UInt(self.id).encode_size()
1521            + self.notarizations.encode_size()
1522            + self.nullifications.encode_size()
1523    }
1524}
1525
1526impl Read for Request {
1527    type Cfg = usize;
1528
1529    fn read_cfg(reader: &mut impl Buf, max_len: &usize) -> Result<Self, Error> {
1530        let id = UInt::read(reader)?.into();
1531        let mut views = HashSet::new();
1532        let notarizations = Vec::<View>::read_range(reader, ..=*max_len)?;
1533        for view in notarizations.iter() {
1534            if !views.insert(view) {
1535                return Err(Error::Invalid(
1536                    "consensus::threshold_simplex::Request",
1537                    "Duplicate notarization",
1538                ));
1539            }
1540        }
1541        let remaining = max_len - notarizations.len();
1542        views.clear();
1543        let nullifications = Vec::<View>::read_range(reader, ..=remaining)?;
1544        for view in nullifications.iter() {
1545            if !views.insert(view) {
1546                return Err(Error::Invalid(
1547                    "consensus::threshold_simplex::Request",
1548                    "Duplicate nullification",
1549                ));
1550            }
1551        }
1552        Ok(Request {
1553            id,
1554            notarizations,
1555            nullifications,
1556        })
1557    }
1558}
1559
1560/// Response is a message containing the requested notarizations and nullifications.
1561/// This is sent in response to a Request message.
1562#[derive(Clone, Debug, PartialEq)]
1563pub struct Response<V: Variant, D: Digest> {
1564    /// Identifier matching the original request
1565    pub id: u64,
1566    /// Notarizations for the requested views
1567    pub notarizations: Vec<Notarization<V, D>>,
1568    /// Nullifications for the requested views
1569    pub nullifications: Vec<Nullification<V>>,
1570}
1571
1572impl<V: Variant, D: Digest> Response<V, D> {
1573    /// Creates a new response with the given id, notarizations, and nullifications.
1574    pub fn new(
1575        id: u64,
1576        notarizations: Vec<Notarization<V, D>>,
1577        nullifications: Vec<Nullification<V>>,
1578    ) -> Self {
1579        Response {
1580            id,
1581            notarizations,
1582            nullifications,
1583        }
1584    }
1585
1586    /// Verifies the signatures on this response using BLS aggregate verification.
1587    pub fn verify(&self, namespace: &[u8], identity: &V::Public) -> bool {
1588        // Prepare to verify
1589        if self.notarizations.is_empty() && self.nullifications.is_empty() {
1590            return true;
1591        }
1592        let mut seeds = HashMap::new();
1593        let mut messages = Vec::new();
1594        let mut signatures = Vec::new();
1595
1596        // Parse all notarizations
1597        let notarize_namespace = notarize_namespace(namespace);
1598        let seed_namespace = seed_namespace(namespace);
1599        for notarization in self.notarizations.iter() {
1600            // Prepare notarize message
1601            let notarize_message = notarization.proposal.encode().to_vec();
1602            let notarize_message = (Some(notarize_namespace.as_slice()), notarize_message);
1603            messages.push(notarize_message);
1604            signatures.push(&notarization.proposal_signature);
1605
1606            // Add seed message (if not already present)
1607            if let Some(previous) = seeds.get(&notarization.proposal.view) {
1608                if *previous != &notarization.seed_signature {
1609                    return false;
1610                }
1611            } else {
1612                let seed_message = view_message(notarization.proposal.view);
1613                let seed_message = (Some(seed_namespace.as_slice()), seed_message);
1614                messages.push(seed_message);
1615                signatures.push(&notarization.seed_signature);
1616                seeds.insert(notarization.proposal.view, &notarization.seed_signature);
1617            }
1618        }
1619
1620        // Parse all nullifications
1621        let nullify_namespace = nullify_namespace(namespace);
1622        for nullification in self.nullifications.iter() {
1623            // Prepare nullify message
1624            let nullify_message = view_message(nullification.view);
1625            let nullify_message = (Some(nullify_namespace.as_slice()), nullify_message);
1626            messages.push(nullify_message);
1627            signatures.push(&nullification.view_signature);
1628
1629            // Add seed message (if not already present)
1630            if let Some(previous) = seeds.get(&nullification.view) {
1631                if *previous != &nullification.seed_signature {
1632                    return false;
1633                }
1634            } else {
1635                let seed_message = view_message(nullification.view);
1636                let seed_message = (Some(seed_namespace.as_slice()), seed_message);
1637                messages.push(seed_message);
1638                signatures.push(&nullification.seed_signature);
1639                seeds.insert(nullification.view, &nullification.seed_signature);
1640            }
1641        }
1642
1643        // Aggregate signatures
1644        let signature = aggregate_signatures::<V, _>(signatures);
1645        aggregate_verify_multiple_messages::<V, _>(
1646            identity,
1647            &messages
1648                .iter()
1649                .map(|(namespace, message)| (namespace.as_deref(), message.as_ref()))
1650                .collect::<Vec<_>>(),
1651            &signature,
1652            1,
1653        )
1654        .is_ok()
1655    }
1656}
1657
1658impl<V: Variant, D: Digest> Write for Response<V, D> {
1659    fn write(&self, writer: &mut impl BufMut) {
1660        UInt(self.id).write(writer);
1661        self.notarizations.write(writer);
1662        self.nullifications.write(writer);
1663    }
1664}
1665
1666impl<V: Variant, D: Digest> EncodeSize for Response<V, D> {
1667    fn encode_size(&self) -> usize {
1668        UInt(self.id).encode_size()
1669            + self.notarizations.encode_size()
1670            + self.nullifications.encode_size()
1671    }
1672}
1673
1674impl<V: Variant, D: Digest> Read for Response<V, D> {
1675    type Cfg = usize;
1676
1677    fn read_cfg(reader: &mut impl Buf, max_len: &usize) -> Result<Self, Error> {
1678        let id = UInt::read(reader)?.into();
1679        let mut views = HashSet::new();
1680        let notarizations = Vec::<Notarization<V, D>>::read_range(reader, ..=*max_len)?;
1681        for notarization in notarizations.iter() {
1682            if !views.insert(notarization.proposal.view) {
1683                return Err(Error::Invalid(
1684                    "consensus::threshold_simplex::Response",
1685                    "Duplicate notarization",
1686                ));
1687            }
1688        }
1689        let remaining = max_len - notarizations.len();
1690        views.clear();
1691        let nullifications = Vec::<Nullification<V>>::read_range(reader, ..=remaining)?;
1692        for nullification in nullifications.iter() {
1693            if !views.insert(nullification.view) {
1694                return Err(Error::Invalid(
1695                    "consensus::threshold_simplex::Response",
1696                    "Duplicate nullification",
1697                ));
1698            }
1699        }
1700        Ok(Response {
1701            id,
1702            notarizations,
1703            nullifications,
1704        })
1705    }
1706}
1707
1708/// Activity represents all possible activities that can occur in the consensus protocol.
1709/// This includes both regular consensus messages and fault evidence.
1710///
1711/// Some activities issued by consensus are not verified. To determine if an activity has been verified,
1712/// use the `verified` method.
1713///
1714/// # Warning
1715///
1716/// After collecting `t` [PartialSignature]s for the same [Activity], an attacker can derive
1717/// the [PartialSignature] for the `n-t` remaining participants.
1718///
1719/// For this reason, it is not sound to use [PartialSignature]-backed [Activity] to reward participants
1720/// for their contributions (as an attacker, for example, could forge contributions from offline participants).
1721#[derive(Clone, Debug, PartialEq, Hash, Eq)]
1722pub enum Activity<V: Variant, D: Digest> {
1723    /// A single validator notarize over a proposal
1724    Notarize(Notarize<V, D>),
1725    /// A threshold signature for a notarization
1726    Notarization(Notarization<V, D>),
1727    /// A single validator nullify to skip the current view
1728    Nullify(Nullify<V>),
1729    /// A threshold signature for a nullification
1730    Nullification(Nullification<V>),
1731    /// A single validator finalize over a proposal
1732    Finalize(Finalize<V, D>),
1733    /// A threshold signature for a finalization
1734    Finalization(Finalization<V, D>),
1735    /// Evidence of a validator sending conflicting notarizes (Byzantine behavior)
1736    ConflictingNotarize(ConflictingNotarize<V, D>),
1737    /// Evidence of a validator sending conflicting finalizes (Byzantine behavior)
1738    ConflictingFinalize(ConflictingFinalize<V, D>),
1739    /// Evidence of a validator sending both nullify and finalize for the same view (Byzantine behavior)
1740    NullifyFinalize(NullifyFinalize<V, D>),
1741}
1742
1743impl<V: Variant, D: Digest> Activity<V, D> {
1744    /// Indicates whether the activity has been verified by consensus.
1745    pub fn verified(&self) -> bool {
1746        match self {
1747            Activity::Notarize(_) => false,
1748            Activity::Notarization(_) => true,
1749            Activity::Nullify(_) => false,
1750            Activity::Nullification(_) => true,
1751            Activity::Finalize(_) => false,
1752            Activity::Finalization(_) => true,
1753            Activity::ConflictingNotarize(_) => false,
1754            Activity::ConflictingFinalize(_) => false,
1755            Activity::NullifyFinalize(_) => false,
1756        }
1757    }
1758}
1759
1760impl<V: Variant, D: Digest> Write for Activity<V, D> {
1761    fn write(&self, writer: &mut impl BufMut) {
1762        match self {
1763            Activity::Notarize(v) => {
1764                0u8.write(writer);
1765                v.write(writer);
1766            }
1767            Activity::Notarization(v) => {
1768                1u8.write(writer);
1769                v.write(writer);
1770            }
1771            Activity::Nullify(v) => {
1772                2u8.write(writer);
1773                v.write(writer);
1774            }
1775            Activity::Nullification(v) => {
1776                3u8.write(writer);
1777                v.write(writer);
1778            }
1779            Activity::Finalize(v) => {
1780                4u8.write(writer);
1781                v.write(writer);
1782            }
1783            Activity::Finalization(v) => {
1784                5u8.write(writer);
1785                v.write(writer);
1786            }
1787            Activity::ConflictingNotarize(v) => {
1788                6u8.write(writer);
1789                v.write(writer);
1790            }
1791            Activity::ConflictingFinalize(v) => {
1792                7u8.write(writer);
1793                v.write(writer);
1794            }
1795            Activity::NullifyFinalize(v) => {
1796                8u8.write(writer);
1797                v.write(writer);
1798            }
1799        }
1800    }
1801}
1802
1803impl<V: Variant, D: Digest> EncodeSize for Activity<V, D> {
1804    fn encode_size(&self) -> usize {
1805        1 + match self {
1806            Activity::Notarize(v) => v.encode_size(),
1807            Activity::Notarization(v) => v.encode_size(),
1808            Activity::Nullify(v) => v.encode_size(),
1809            Activity::Nullification(v) => v.encode_size(),
1810            Activity::Finalize(v) => v.encode_size(),
1811            Activity::Finalization(v) => v.encode_size(),
1812            Activity::ConflictingNotarize(v) => v.encode_size(),
1813            Activity::ConflictingFinalize(v) => v.encode_size(),
1814            Activity::NullifyFinalize(v) => v.encode_size(),
1815        }
1816    }
1817}
1818
1819impl<V: Variant, D: Digest> Read for Activity<V, D> {
1820    type Cfg = ();
1821
1822    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1823        let tag = <u8>::read(reader)?;
1824        match tag {
1825            0 => {
1826                let v = Notarize::<V, D>::read(reader)?;
1827                Ok(Activity::Notarize(v))
1828            }
1829            1 => {
1830                let v = Notarization::<V, D>::read(reader)?;
1831                Ok(Activity::Notarization(v))
1832            }
1833            2 => {
1834                let v = Nullify::<V>::read(reader)?;
1835                Ok(Activity::Nullify(v))
1836            }
1837            3 => {
1838                let v = Nullification::<V>::read(reader)?;
1839                Ok(Activity::Nullification(v))
1840            }
1841            4 => {
1842                let v = Finalize::<V, D>::read(reader)?;
1843                Ok(Activity::Finalize(v))
1844            }
1845            5 => {
1846                let v = Finalization::<V, D>::read(reader)?;
1847                Ok(Activity::Finalization(v))
1848            }
1849            6 => {
1850                let v = ConflictingNotarize::<V, D>::read(reader)?;
1851                Ok(Activity::ConflictingNotarize(v))
1852            }
1853            7 => {
1854                let v = ConflictingFinalize::<V, D>::read(reader)?;
1855                Ok(Activity::ConflictingFinalize(v))
1856            }
1857            8 => {
1858                let v = NullifyFinalize::<V, D>::read(reader)?;
1859                Ok(Activity::NullifyFinalize(v))
1860            }
1861            _ => Err(Error::Invalid(
1862                "consensus::threshold_simplex::Activity",
1863                "Invalid type",
1864            )),
1865        }
1866    }
1867}
1868
1869impl<V: Variant, D: Digest> Viewable for Activity<V, D> {
1870    type View = View;
1871
1872    fn view(&self) -> View {
1873        match self {
1874            Activity::Notarize(v) => v.view(),
1875            Activity::Notarization(v) => v.view(),
1876            Activity::Nullify(v) => v.view(),
1877            Activity::Nullification(v) => v.view(),
1878            Activity::Finalize(v) => v.view(),
1879            Activity::Finalization(v) => v.view(),
1880            Activity::ConflictingNotarize(v) => v.view(),
1881            Activity::ConflictingFinalize(v) => v.view(),
1882            Activity::NullifyFinalize(v) => v.view(),
1883        }
1884    }
1885}
1886
1887/// Seed represents a threshold signature over the current view.
1888#[derive(Clone, Debug, PartialEq, Hash, Eq)]
1889pub struct Seed<V: Variant> {
1890    /// The view for which this seed is generated
1891    pub view: View,
1892    /// The partial signature on the seed
1893    pub signature: V::Signature,
1894}
1895
1896impl<V: Variant> Seed<V> {
1897    /// Creates a new seed with the given view and signature.
1898    pub fn new(view: View, signature: V::Signature) -> Self {
1899        Seed { view, signature }
1900    }
1901
1902    /// Verifies the threshold signature on this [Seed].
1903    pub fn verify(&self, namespace: &[u8], identity: &V::Public) -> bool {
1904        let seed_namespace = seed_namespace(namespace);
1905        let message = view_message(self.view);
1906        verify_message::<V>(identity, Some(&seed_namespace), &message, &self.signature).is_ok()
1907    }
1908}
1909
1910impl<V: Variant> Viewable for Seed<V> {
1911    type View = View;
1912
1913    fn view(&self) -> View {
1914        self.view
1915    }
1916}
1917
1918impl<V: Variant> Write for Seed<V> {
1919    fn write(&self, writer: &mut impl BufMut) {
1920        UInt(self.view).write(writer);
1921        self.signature.write(writer);
1922    }
1923}
1924
1925impl<V: Variant> Read for Seed<V> {
1926    type Cfg = ();
1927
1928    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1929        let view = UInt::read(reader)?.into();
1930        let signature = V::Signature::read(reader)?;
1931        Ok(Seed { view, signature })
1932    }
1933}
1934
1935impl<V: Variant> EncodeSize for Seed<V> {
1936    fn encode_size(&self) -> usize {
1937        UInt(self.view).encode_size() + self.signature.encode_size()
1938    }
1939}
1940
1941/// ConflictingNotarize represents evidence of a Byzantine validator sending conflicting notarizes.
1942/// This is used to prove that a validator has equivocated (voted for different proposals in the same view).
1943#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1944pub struct ConflictingNotarize<V: Variant, D: Digest> {
1945    /// The view in which the conflict occurred
1946    pub view: View,
1947    /// The parent view of the first conflicting proposal
1948    pub parent_1: View,
1949    /// The payload of the first conflicting proposal
1950    pub payload_1: D,
1951    /// The signature on the first conflicting proposal
1952    pub signature_1: PartialSignature<V>,
1953    /// The parent view of the second conflicting proposal
1954    pub parent_2: View,
1955    /// The payload of the second conflicting proposal
1956    pub payload_2: D,
1957    /// The signature on the second conflicting proposal
1958    pub signature_2: PartialSignature<V>,
1959}
1960
1961impl<V: Variant, D: Digest> ConflictingNotarize<V, D> {
1962    /// Creates a new conflicting notarize evidence from two conflicting notarizes.
1963    pub fn new(notarize_1: Notarize<V, D>, notarize_2: Notarize<V, D>) -> Self {
1964        assert_eq!(notarize_1.view(), notarize_2.view());
1965        assert_eq!(notarize_1.signer(), notarize_2.signer());
1966        ConflictingNotarize {
1967            view: notarize_1.view(),
1968            parent_1: notarize_1.proposal.parent,
1969            payload_1: notarize_1.proposal.payload,
1970            signature_1: notarize_1.proposal_signature,
1971            parent_2: notarize_2.proposal.parent,
1972            payload_2: notarize_2.proposal.payload,
1973            signature_2: notarize_2.proposal_signature,
1974        }
1975    }
1976
1977    /// Reconstructs the original proposals from this evidence.
1978    pub fn proposals(&self) -> (Proposal<D>, Proposal<D>) {
1979        (
1980            Proposal::new(self.view, self.parent_1, self.payload_1),
1981            Proposal::new(self.view, self.parent_2, self.payload_2),
1982        )
1983    }
1984
1985    /// Verifies that both conflicting signatures are valid, proving Byzantine behavior.
1986    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
1987        let (proposal_1, proposal_2) = self.proposals();
1988        let notarize_namespace = notarize_namespace(namespace);
1989        let notarize_message_1 = proposal_1.encode();
1990        let notarize_message_1 = (
1991            Some(notarize_namespace.as_ref()),
1992            notarize_message_1.as_ref(),
1993        );
1994        let notarize_message_2 = proposal_2.encode();
1995        let notarize_message_2 = (
1996            Some(notarize_namespace.as_ref()),
1997            notarize_message_2.as_ref(),
1998        );
1999        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
2000            return false;
2001        };
2002        let signature =
2003            aggregate_signatures::<V, _>(&[self.signature_1.value, self.signature_2.value]);
2004        aggregate_verify_multiple_messages::<V, _>(
2005            evaluated,
2006            &[notarize_message_1, notarize_message_2],
2007            &signature,
2008            1,
2009        )
2010        .is_ok()
2011    }
2012}
2013
2014impl<V: Variant, D: Digest> Attributable for ConflictingNotarize<V, D> {
2015    fn signer(&self) -> u32 {
2016        self.signature_1.index
2017    }
2018}
2019
2020impl<V: Variant, D: Digest> Viewable for ConflictingNotarize<V, D> {
2021    type View = View;
2022
2023    fn view(&self) -> View {
2024        self.view
2025    }
2026}
2027
2028impl<V: Variant, D: Digest> Write for ConflictingNotarize<V, D> {
2029    fn write(&self, writer: &mut impl BufMut) {
2030        UInt(self.view).write(writer);
2031        UInt(self.parent_1).write(writer);
2032        self.payload_1.write(writer);
2033        self.signature_1.write(writer);
2034        UInt(self.parent_2).write(writer);
2035        self.payload_2.write(writer);
2036        self.signature_2.write(writer);
2037    }
2038}
2039
2040impl<V: Variant, D: Digest> Read for ConflictingNotarize<V, D> {
2041    type Cfg = ();
2042
2043    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2044        let view = UInt::read(reader)?.into();
2045        let parent_1 = UInt::read(reader)?.into();
2046        let payload_1 = D::read(reader)?;
2047        let signature_1 = PartialSignature::<V>::read(reader)?;
2048        let parent_2 = UInt::read(reader)?.into();
2049        let payload_2 = D::read(reader)?;
2050        let signature_2 = PartialSignature::<V>::read(reader)?;
2051        if signature_1.index != signature_2.index {
2052            return Err(Error::Invalid(
2053                "consensus::threshold_simplex::ConflictingNotarize",
2054                "mismatched signatures",
2055            ));
2056        }
2057        Ok(ConflictingNotarize {
2058            view,
2059            parent_1,
2060            payload_1,
2061            signature_1,
2062            parent_2,
2063            payload_2,
2064            signature_2,
2065        })
2066    }
2067}
2068
2069impl<V: Variant, D: Digest> EncodeSize for ConflictingNotarize<V, D> {
2070    fn encode_size(&self) -> usize {
2071        UInt(self.view).encode_size()
2072            + UInt(self.parent_1).encode_size()
2073            + self.payload_1.encode_size()
2074            + self.signature_1.encode_size()
2075            + UInt(self.parent_2).encode_size()
2076            + self.payload_2.encode_size()
2077            + self.signature_2.encode_size()
2078    }
2079}
2080
2081/// ConflictingFinalize represents evidence of a Byzantine validator sending conflicting finalizes.
2082/// Similar to ConflictingNotarize, but for finalizes.
2083#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2084pub struct ConflictingFinalize<V: Variant, D: Digest> {
2085    /// The view in which the conflict occurred
2086    pub view: View,
2087    /// The parent view of the first conflicting proposal
2088    pub parent_1: View,
2089    /// The payload of the first conflicting proposal
2090    pub payload_1: D,
2091    /// The signature on the first conflicting proposal
2092    pub signature_1: PartialSignature<V>,
2093    /// The parent view of the second conflicting proposal
2094    pub parent_2: View,
2095    /// The payload of the second conflicting proposal
2096    pub payload_2: D,
2097    /// The signature on the second conflicting proposal
2098    pub signature_2: PartialSignature<V>,
2099}
2100
2101impl<V: Variant, D: Digest> ConflictingFinalize<V, D> {
2102    /// Creates a new conflicting finalize evidence from two conflicting finalizes.
2103    pub fn new(finalize_1: Finalize<V, D>, finalize_2: Finalize<V, D>) -> Self {
2104        assert_eq!(finalize_1.view(), finalize_2.view());
2105        assert_eq!(finalize_1.signer(), finalize_2.signer());
2106        ConflictingFinalize {
2107            view: finalize_1.view(),
2108            parent_1: finalize_1.proposal.parent,
2109            payload_1: finalize_1.proposal.payload,
2110            signature_1: finalize_1.proposal_signature,
2111            parent_2: finalize_2.proposal.parent,
2112            payload_2: finalize_2.proposal.payload,
2113            signature_2: finalize_2.proposal_signature,
2114        }
2115    }
2116
2117    /// Reconstructs the original proposals from this evidence.
2118    pub fn proposals(&self) -> (Proposal<D>, Proposal<D>) {
2119        (
2120            Proposal::new(self.view, self.parent_1, self.payload_1),
2121            Proposal::new(self.view, self.parent_2, self.payload_2),
2122        )
2123    }
2124
2125    /// Verifies that both conflicting signatures are valid, proving Byzantine behavior.
2126    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
2127        let (proposal_1, proposal_2) = self.proposals();
2128        let finalize_namespace = finalize_namespace(namespace);
2129        let finalize_message_1 = proposal_1.encode();
2130        let finalize_message_1 = (
2131            Some(finalize_namespace.as_ref()),
2132            finalize_message_1.as_ref(),
2133        );
2134        let finalize_message_2 = proposal_2.encode();
2135        let finalize_message_2 = (
2136            Some(finalize_namespace.as_ref()),
2137            finalize_message_2.as_ref(),
2138        );
2139        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
2140            return false;
2141        };
2142        let signature =
2143            aggregate_signatures::<V, _>(&[self.signature_1.value, self.signature_2.value]);
2144        aggregate_verify_multiple_messages::<V, _>(
2145            evaluated,
2146            &[finalize_message_1, finalize_message_2],
2147            &signature,
2148            1,
2149        )
2150        .is_ok()
2151    }
2152}
2153
2154impl<V: Variant, D: Digest> Attributable for ConflictingFinalize<V, D> {
2155    fn signer(&self) -> u32 {
2156        self.signature_1.index
2157    }
2158}
2159
2160impl<V: Variant, D: Digest> Viewable for ConflictingFinalize<V, D> {
2161    type View = View;
2162
2163    fn view(&self) -> View {
2164        self.view
2165    }
2166}
2167
2168impl<V: Variant, D: Digest> Write for ConflictingFinalize<V, D> {
2169    fn write(&self, writer: &mut impl BufMut) {
2170        UInt(self.view).write(writer);
2171        UInt(self.parent_1).write(writer);
2172        self.payload_1.write(writer);
2173        self.signature_1.write(writer);
2174        UInt(self.parent_2).write(writer);
2175        self.payload_2.write(writer);
2176        self.signature_2.write(writer);
2177    }
2178}
2179
2180impl<V: Variant, D: Digest> Read for ConflictingFinalize<V, D> {
2181    type Cfg = ();
2182
2183    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2184        let view = UInt::read(reader)?.into();
2185        let parent_1 = UInt::read(reader)?.into();
2186        let payload_1 = D::read(reader)?;
2187        let signature_1 = PartialSignature::<V>::read(reader)?;
2188        let parent_2 = UInt::read(reader)?.into();
2189        let payload_2 = D::read(reader)?;
2190        let signature_2 = PartialSignature::<V>::read(reader)?;
2191        if signature_1.index != signature_2.index {
2192            return Err(Error::Invalid(
2193                "consensus::threshold_simplex::ConflictingFinalize",
2194                "mismatched signatures",
2195            ));
2196        }
2197        Ok(ConflictingFinalize {
2198            view,
2199            parent_1,
2200            payload_1,
2201            signature_1,
2202            parent_2,
2203            payload_2,
2204            signature_2,
2205        })
2206    }
2207}
2208
2209impl<V: Variant, D: Digest> EncodeSize for ConflictingFinalize<V, D> {
2210    fn encode_size(&self) -> usize {
2211        UInt(self.view).encode_size()
2212            + UInt(self.parent_1).encode_size()
2213            + self.payload_1.encode_size()
2214            + self.signature_1.encode_size()
2215            + UInt(self.parent_2).encode_size()
2216            + self.payload_2.encode_size()
2217            + self.signature_2.encode_size()
2218    }
2219}
2220
2221/// NullifyFinalize represents evidence of a Byzantine validator sending both a nullify and finalize
2222/// for the same view, which is contradictory behavior (a validator should either try to skip a view OR
2223/// finalize a proposal, not both).
2224#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2225pub struct NullifyFinalize<V: Variant, D: Digest> {
2226    /// The proposal that the validator tried to finalize
2227    pub proposal: Proposal<D>,
2228    /// The signature on the nullify
2229    pub view_signature: PartialSignature<V>,
2230    /// The signature on the finalize
2231    pub finalize_signature: PartialSignature<V>,
2232}
2233
2234impl<V: Variant, D: Digest> NullifyFinalize<V, D> {
2235    /// Creates a new nullify-finalize evidence from a nullify and a finalize.
2236    pub fn new(nullify: Nullify<V>, finalize: Finalize<V, D>) -> Self {
2237        assert_eq!(nullify.view(), finalize.view());
2238        assert_eq!(nullify.signer(), finalize.signer());
2239        NullifyFinalize {
2240            proposal: finalize.proposal,
2241            view_signature: nullify.view_signature,
2242            finalize_signature: finalize.proposal_signature,
2243        }
2244    }
2245
2246    /// Verifies that both the nullify and finalize signatures are valid, proving Byzantine behavior.
2247    pub fn verify(&self, namespace: &[u8], polynomial: &[V::Public]) -> bool {
2248        let nullify_namespace = nullify_namespace(namespace);
2249        let nullify_message = view_message(self.proposal.view);
2250        let nullify_message = (Some(nullify_namespace.as_ref()), nullify_message.as_ref());
2251        let finalize_namespace = finalize_namespace(namespace);
2252        let finalize_message = self.proposal.encode();
2253        let finalize_message = (Some(finalize_namespace.as_ref()), finalize_message.as_ref());
2254        let Some(evaluated) = polynomial.get(self.signer() as usize) else {
2255            return false;
2256        };
2257        let signature = aggregate_signatures::<V, _>(&[
2258            self.view_signature.value,
2259            self.finalize_signature.value,
2260        ]);
2261        aggregate_verify_multiple_messages::<V, _>(
2262            evaluated,
2263            &[nullify_message, finalize_message],
2264            &signature,
2265            1,
2266        )
2267        .is_ok()
2268    }
2269}
2270
2271impl<V: Variant, D: Digest> Attributable for NullifyFinalize<V, D> {
2272    fn signer(&self) -> u32 {
2273        self.view_signature.index
2274    }
2275}
2276
2277impl<V: Variant, D: Digest> Viewable for NullifyFinalize<V, D> {
2278    type View = View;
2279
2280    fn view(&self) -> View {
2281        self.proposal.view()
2282    }
2283}
2284
2285impl<V: Variant, D: Digest> Write for NullifyFinalize<V, D> {
2286    fn write(&self, writer: &mut impl BufMut) {
2287        self.proposal.write(writer);
2288        self.view_signature.write(writer);
2289        self.finalize_signature.write(writer);
2290    }
2291}
2292
2293impl<V: Variant, D: Digest> Read for NullifyFinalize<V, D> {
2294    type Cfg = ();
2295
2296    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2297        let proposal = Proposal::read(reader)?;
2298        let view_signature = PartialSignature::<V>::read(reader)?;
2299        let finalize_signature = PartialSignature::<V>::read(reader)?;
2300        if view_signature.index != finalize_signature.index {
2301            return Err(Error::Invalid(
2302                "consensus::threshold_simplex::NullifyFinalize",
2303                "mismatched signatures",
2304            ));
2305        }
2306        Ok(NullifyFinalize {
2307            proposal,
2308            view_signature,
2309            finalize_signature,
2310        })
2311    }
2312}
2313
2314impl<V: Variant, D: Digest> EncodeSize for NullifyFinalize<V, D> {
2315    fn encode_size(&self) -> usize {
2316        self.proposal.encode_size()
2317            + self.view_signature.encode_size()
2318            + self.finalize_signature.encode_size()
2319    }
2320}
2321
2322#[cfg(test)]
2323mod tests {
2324    use super::*;
2325    use commonware_codec::{Decode, DecodeExt, Encode};
2326    use commonware_cryptography::{
2327        bls12381::{
2328            dkg::ops::{self, evaluate_all},
2329            primitives::{
2330                group::{Element, Share},
2331                ops::threshold_signature_recover,
2332                poly,
2333                variant::MinSig,
2334            },
2335        },
2336        sha256::Digest as Sha256,
2337    };
2338    use commonware_utils::quorum;
2339    use rand::{rngs::StdRng, SeedableRng};
2340
2341    const NAMESPACE: &[u8] = b"test";
2342
2343    // Helper function to create a sample digest
2344    fn sample_digest(v: u8) -> Sha256 {
2345        Sha256::from([v; 32]) // Simple fixed digest for testing
2346    }
2347
2348    // Helper function to generate BLS shares and polynomial
2349    fn generate_test_data(
2350        n: u32,
2351        t: u32,
2352        seed: u64,
2353    ) -> (
2354        <MinSig as Variant>::Public,
2355        Vec<<MinSig as Variant>::Public>,
2356        Vec<Share>,
2357    ) {
2358        let mut rng = StdRng::seed_from_u64(seed);
2359        let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
2360        let identity = poly::public::<MinSig>(&polynomial);
2361        let polynomial = evaluate_all::<MinSig>(&polynomial, n);
2362        (*identity, polynomial, shares)
2363    }
2364
2365    #[test]
2366    fn test_proposal_encode_decode() {
2367        let proposal = Proposal::new(10, 5, sample_digest(1));
2368        let encoded = proposal.encode();
2369        let decoded = Proposal::<Sha256>::decode(encoded).unwrap();
2370        assert_eq!(proposal, decoded);
2371    }
2372
2373    #[test]
2374    fn test_notarize_encode_decode() {
2375        let n = 5;
2376        let t = quorum(n);
2377        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2378
2379        let proposal = Proposal::new(10, 5, sample_digest(1));
2380        let notarize = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal);
2381
2382        let encoded = notarize.encode();
2383        let decoded = Notarize::<MinSig, Sha256>::decode(encoded).unwrap();
2384
2385        assert_eq!(notarize, decoded);
2386        assert!(decoded.verify(NAMESPACE, &polynomial));
2387    }
2388
2389    #[test]
2390    fn test_notarization_encode_decode() {
2391        let n = 5;
2392        let t = quorum(n);
2393        let (identity, _, shares) = generate_test_data(n, t, 0);
2394
2395        let proposal = Proposal::new(10, 5, sample_digest(1));
2396
2397        // Create notarizes
2398        let notarizes: Vec<_> = shares
2399            .iter()
2400            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2401            .collect();
2402
2403        // Recover threshold signature
2404        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2405        let proposal_signature =
2406            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2407        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2408        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2409
2410        // Create notarization
2411        let notarization = Notarization::new(proposal, proposal_signature, seed_signature);
2412        let encoded = notarization.encode();
2413        let decoded = Notarization::<MinSig, Sha256>::decode(encoded).unwrap();
2414        assert_eq!(notarization, decoded);
2415
2416        // Verify the notarization
2417        assert!(decoded.verify(NAMESPACE, &identity));
2418
2419        // Create seed
2420        let seed = notarization.seed();
2421        let encoded = seed.encode();
2422        let decoded = Seed::<MinSig>::decode(encoded).unwrap();
2423        assert_eq!(seed, decoded);
2424
2425        // Verify the seed
2426        assert!(decoded.verify(NAMESPACE, &identity));
2427    }
2428
2429    #[test]
2430    fn test_nullify_encode_decode() {
2431        let n = 5;
2432        let t = quorum(n);
2433        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2434
2435        let nullify = Nullify::<MinSig>::sign(NAMESPACE, &shares[0], 10);
2436
2437        let encoded = nullify.encode();
2438        let decoded = Nullify::<MinSig>::decode(encoded).unwrap();
2439
2440        assert_eq!(nullify, decoded);
2441        assert!(decoded.verify(NAMESPACE, &polynomial));
2442    }
2443
2444    #[test]
2445    fn test_nullification_encode_decode() {
2446        let n = 5;
2447        let t = quorum(n);
2448        let (identity, _, shares) = generate_test_data(n, t, 0);
2449
2450        // Create nullifies
2451        let nullifies: Vec<_> = shares
2452            .iter()
2453            .map(|s| Nullify::<MinSig>::sign(NAMESPACE, s, 10))
2454            .collect();
2455
2456        // Recover threshold signature
2457        let view_partials = nullifies.iter().map(|n| &n.view_signature);
2458        let view_signature = threshold_signature_recover::<MinSig, _>(t, view_partials).unwrap();
2459        let seed_partials = nullifies.iter().map(|n| &n.seed_signature);
2460        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2461
2462        // Create nullification
2463        let nullification = Nullification::new(10, view_signature, seed_signature);
2464        let encoded = nullification.encode();
2465        let decoded = Nullification::<MinSig>::decode(encoded).unwrap();
2466        assert_eq!(nullification, decoded);
2467
2468        // Verify the nullification
2469        assert!(decoded.verify(NAMESPACE, &identity));
2470
2471        // Create seed
2472        let seed = nullification.seed();
2473        let encoded = seed.encode();
2474        let decoded = Seed::<MinSig>::decode(encoded).unwrap();
2475        assert_eq!(seed, decoded);
2476
2477        // Verify the seed
2478        assert!(decoded.verify(NAMESPACE, &identity));
2479    }
2480
2481    #[test]
2482    fn test_finalize_encode_decode() {
2483        let n = 5;
2484        let t = quorum(n);
2485        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2486
2487        let proposal = Proposal::new(10, 5, sample_digest(1));
2488        let finalize = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal);
2489
2490        let encoded = finalize.encode();
2491        let decoded = Finalize::<MinSig, Sha256>::decode(encoded).unwrap();
2492
2493        assert_eq!(finalize, decoded);
2494        assert!(decoded.verify(NAMESPACE, &polynomial));
2495    }
2496
2497    #[test]
2498    fn test_finalization_encode_decode() {
2499        let n = 5;
2500        let t = quorum(n);
2501        let (identity, _, shares) = generate_test_data(n, t, 0);
2502
2503        let proposal = Proposal::new(10, 5, sample_digest(1));
2504
2505        // Create finalizes
2506        let notarizes: Vec<_> = shares
2507            .iter()
2508            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2509            .collect();
2510        let finalizes: Vec<_> = shares
2511            .iter()
2512            .map(|s| Finalize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2513            .collect();
2514
2515        // Recover threshold signatures
2516        let proposal_partials = finalizes.iter().map(|f| &f.proposal_signature);
2517        let proposal_signature =
2518            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2519        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2520        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2521
2522        // Create finalization
2523        let finalization = Finalization::new(proposal, proposal_signature, seed_signature);
2524        let encoded = finalization.encode();
2525        let decoded = Finalization::<MinSig, Sha256>::decode(encoded).unwrap();
2526        assert_eq!(finalization, decoded);
2527
2528        // Verify the finalization
2529        assert!(decoded.verify(NAMESPACE, &identity));
2530
2531        // Create seed
2532        let seed = finalization.seed();
2533        let encoded = seed.encode();
2534        let decoded = Seed::<MinSig>::decode(encoded).unwrap();
2535        assert_eq!(seed, decoded);
2536
2537        // Verify the seed
2538        assert!(decoded.verify(NAMESPACE, &identity));
2539    }
2540
2541    #[test]
2542    fn test_backfiller_encode_decode() {
2543        // Test Request
2544        let request = Request::new(1, vec![10, 11], vec![12, 13]);
2545        let backfiller = Backfiller::<MinSig, Sha256>::Request(request.clone());
2546        let encoded = backfiller.encode();
2547        let decoded = Backfiller::<MinSig, Sha256>::decode_cfg(encoded, &usize::MAX).unwrap();
2548        assert!(matches!(decoded, Backfiller::Request(r) if r == request));
2549
2550        // Test Response
2551        let n = 5;
2552        let t = quorum(n);
2553        let (_, _, shares) = generate_test_data(n, t, 0);
2554
2555        // Create a notarization
2556        let proposal = Proposal::new(10, 5, sample_digest(1));
2557        let notarizes: Vec<_> = shares
2558            .iter()
2559            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2560            .collect();
2561
2562        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2563        let proposal_signature =
2564            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2565        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2566        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2567
2568        let notarization = Notarization::new(proposal, proposal_signature, seed_signature);
2569
2570        // Create a nullification
2571        let nullifies: Vec<_> = shares
2572            .iter()
2573            .map(|s| Nullify::<MinSig>::sign(NAMESPACE, s, 11))
2574            .collect();
2575
2576        let view_partials = nullifies.iter().map(|n| &n.view_signature);
2577        let view_signature = threshold_signature_recover::<MinSig, _>(t, view_partials).unwrap();
2578        let seed_partials = nullifies.iter().map(|n| &n.seed_signature);
2579        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2580
2581        let nullification = Nullification::new(11, view_signature, seed_signature);
2582
2583        // Create a response
2584        let response = Response::new(1, vec![notarization], vec![nullification]);
2585        let backfiller = Backfiller::<MinSig, Sha256>::Response(response.clone());
2586        let encoded = backfiller.encode();
2587        let decoded = Backfiller::<MinSig, Sha256>::decode_cfg(encoded, &usize::MAX).unwrap();
2588        assert!(matches!(decoded, Backfiller::Response(r) if r.id == response.id));
2589    }
2590
2591    #[test]
2592    fn test_request_encode_decode() {
2593        let request = Request::new(1, vec![10, 11], vec![12, 13]);
2594        let encoded = request.encode();
2595        let decoded = Request::decode_cfg(encoded, &usize::MAX).unwrap();
2596        assert_eq!(request, decoded);
2597    }
2598
2599    #[test]
2600    fn test_response_encode_decode() {
2601        let n = 5;
2602        let t = quorum(n);
2603        let (identity, _, shares) = generate_test_data(n, t, 0);
2604
2605        // Create a notarization
2606        let proposal = Proposal::new(10, 5, sample_digest(1));
2607        let notarizes: Vec<_> = shares
2608            .iter()
2609            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2610            .collect();
2611
2612        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2613        let proposal_signature =
2614            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2615        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2616        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2617
2618        let notarization = Notarization::new(proposal, proposal_signature, seed_signature);
2619
2620        // Create a nullification
2621        let nullifies: Vec<_> = shares
2622            .iter()
2623            .map(|s| Nullify::<MinSig>::sign(NAMESPACE, s, 11))
2624            .collect();
2625
2626        let view_partials = nullifies.iter().map(|n| &n.view_signature);
2627        let view_signature = threshold_signature_recover::<MinSig, _>(t, view_partials).unwrap();
2628        let seed_partials = nullifies.iter().map(|n| &n.seed_signature);
2629        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2630
2631        let nullification = Nullification::new(11, view_signature, seed_signature);
2632
2633        // Create a response
2634        let response = Response::<MinSig, Sha256>::new(1, vec![notarization], vec![nullification]);
2635        let encoded = response.encode();
2636        let mut decoded = Response::<MinSig, Sha256>::decode_cfg(encoded, &usize::MAX).unwrap();
2637        assert_eq!(response.id, decoded.id);
2638        assert_eq!(response.notarizations.len(), decoded.notarizations.len());
2639        assert_eq!(response.nullifications.len(), decoded.nullifications.len());
2640
2641        // Verify the response
2642        assert!(decoded.verify(NAMESPACE, &identity));
2643
2644        // Modify the response
2645        decoded.nullifications[0]
2646            .view_signature
2647            .add(&<MinSig as Variant>::Signature::one());
2648
2649        // Verify the modified response
2650        assert!(!decoded.verify(NAMESPACE, &identity));
2651    }
2652
2653    #[test]
2654    fn test_conflicting_notarize_encode_decode() {
2655        let n = 5;
2656        let t = quorum(n);
2657        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2658
2659        let proposal1 = Proposal::new(10, 5, sample_digest(1));
2660        let proposal2 = Proposal::new(10, 5, sample_digest(2));
2661        let notarize1 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal1);
2662        let notarize2 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal2);
2663        let conflicting_notarize = ConflictingNotarize::new(notarize1, notarize2);
2664
2665        let encoded = conflicting_notarize.encode();
2666        let decoded = ConflictingNotarize::<MinSig, Sha256>::decode(encoded).unwrap();
2667
2668        assert_eq!(conflicting_notarize, decoded);
2669        assert!(decoded.verify(NAMESPACE, &polynomial));
2670    }
2671
2672    #[test]
2673    fn test_conflicting_finalize_encode_decode() {
2674        let n = 5;
2675        let t = quorum(n);
2676        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2677
2678        let proposal1 = Proposal::new(10, 5, sample_digest(1));
2679        let proposal2 = Proposal::new(10, 5, sample_digest(2));
2680        let finalize1 = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal1);
2681        let finalize2 = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal2);
2682        let conflicting_finalize = ConflictingFinalize::new(finalize1, finalize2);
2683
2684        let encoded = conflicting_finalize.encode();
2685        let decoded = ConflictingFinalize::<MinSig, Sha256>::decode(encoded).unwrap();
2686
2687        assert_eq!(conflicting_finalize, decoded);
2688        assert!(decoded.verify(NAMESPACE, &polynomial));
2689    }
2690
2691    #[test]
2692    fn test_nullify_finalize_encode_decode() {
2693        let n = 5;
2694        let t = quorum(n);
2695        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2696
2697        let proposal = Proposal::new(10, 5, sample_digest(1));
2698        let nullify = Nullify::<MinSig>::sign(NAMESPACE, &shares[0], 10);
2699        let finalize = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal);
2700        let nullify_finalize = NullifyFinalize::new(nullify, finalize);
2701
2702        let encoded = nullify_finalize.encode();
2703        let decoded = NullifyFinalize::<MinSig, Sha256>::decode(encoded).unwrap();
2704
2705        assert_eq!(nullify_finalize, decoded);
2706        assert!(decoded.verify(NAMESPACE, &polynomial));
2707    }
2708
2709    #[test]
2710    fn test_notarize_verify_wrong_namespace() {
2711        let n = 5;
2712        let t = quorum(n);
2713        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2714
2715        let proposal = Proposal::new(10, 5, sample_digest(1));
2716        let notarize = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal);
2717
2718        // Verify with correct namespace and polynomial - should pass
2719        assert!(notarize.verify(NAMESPACE, &polynomial));
2720
2721        // Verify with wrong namespace - should fail
2722        assert!(!notarize.verify(b"wrong_namespace", &polynomial));
2723    }
2724
2725    #[test]
2726    fn test_notarize_verify_wrong_polynomial() {
2727        let n = 5;
2728        let t = quorum(n);
2729        let (_, polynomial1, shares1) = generate_test_data(n, t, 0);
2730
2731        // Generate a different set of BLS keys/shares
2732        let (_, polynomial2, _) = generate_test_data(n, t, 1);
2733
2734        let proposal = Proposal::new(10, 5, sample_digest(1));
2735        let notarize = Notarize::<MinSig, _>::sign(NAMESPACE, &shares1[0], proposal);
2736
2737        // Verify with correct polynomial - should pass
2738        assert!(notarize.verify(NAMESPACE, &polynomial1));
2739
2740        // Verify with wrong polynomial - should fail
2741        assert!(!notarize.verify(NAMESPACE, &polynomial2));
2742    }
2743
2744    #[test]
2745    fn test_notarization_verify_wrong_keys() {
2746        let n = 5;
2747        let t = quorum(n);
2748        let (identity, _, shares) = generate_test_data(n, t, 0);
2749
2750        let proposal = Proposal::new(10, 5, sample_digest(1));
2751
2752        // Create notarizes
2753        let notarizes: Vec<_> = shares
2754            .iter()
2755            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2756            .collect();
2757
2758        // Recover threshold signature
2759        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2760        let proposal_signature =
2761            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2762        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2763        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2764
2765        // Create notarization
2766        let notarization =
2767            Notarization::<MinSig, _>::new(proposal, proposal_signature, seed_signature);
2768
2769        // Verify with correct public key - should pass
2770        assert!(notarization.verify(NAMESPACE, &identity));
2771
2772        // Generate a different set of BLS keys/shares
2773        let (wrong_identity, _, _) = generate_test_data(n, t, 1);
2774
2775        // Verify with wrong public key - should fail
2776        assert!(!notarization.verify(NAMESPACE, &wrong_identity));
2777    }
2778
2779    #[test]
2780    fn test_notarization_verify_wrong_namespace() {
2781        let n = 5;
2782        let t = quorum(n);
2783        let (identity, _, shares) = generate_test_data(n, t, 0);
2784
2785        let proposal = Proposal::new(10, 5, sample_digest(1));
2786
2787        // Create notarizes
2788        let notarizes: Vec<_> = shares
2789            .iter()
2790            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2791            .collect();
2792
2793        // Recover threshold signature
2794        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2795        let proposal_signature =
2796            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2797        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2798        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2799
2800        // Create notarization
2801        let notarization =
2802            Notarization::<MinSig, _>::new(proposal, proposal_signature, seed_signature);
2803
2804        // Verify with correct namespace - should pass
2805        assert!(notarization.verify(NAMESPACE, &identity));
2806
2807        // Verify with wrong namespace - should fail
2808        assert!(!notarization.verify(b"wrong_namespace", &identity));
2809    }
2810
2811    #[test]
2812    fn test_threshold_recover_insufficient_signatures() {
2813        let n = 5;
2814        let t = quorum(n); // For n=5, t should be 4 (2f+1 where f=1)
2815        let (_, _, shares) = generate_test_data(n, t, 0);
2816
2817        let proposal = Proposal::new(10, 5, sample_digest(1));
2818
2819        // Create notarizes, but only collect t-1 of them
2820        let notarizes: Vec<_> = shares
2821            .iter()
2822            .take((t as usize) - 1) // One less than the threshold
2823            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2824            .collect();
2825
2826        // Try to recover threshold signature with insufficient partials - should fail
2827        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2828        let result = threshold_signature_recover::<MinSig, _>(t, proposal_partials);
2829
2830        // Should not be able to recover the threshold signature
2831        assert!(result.is_err());
2832    }
2833
2834    #[test]
2835    fn test_conflicting_notarize_detection() {
2836        let n = 5;
2837        let t = quorum(n);
2838        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2839
2840        // Create two different proposals for the same view
2841        let proposal1 = Proposal::new(10, 5, sample_digest(1));
2842        let proposal2 = Proposal::new(10, 5, sample_digest(2)); // Same view, different payload
2843
2844        // Create notarizes for both proposals from the same validator
2845        let notarize1 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal1.clone());
2846        let notarize2 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal2);
2847
2848        // Create conflict evidence
2849        let conflict = ConflictingNotarize::new(notarize1, notarize2.clone());
2850
2851        // Verify the evidence is valid
2852        assert!(conflict.verify(NAMESPACE, &polynomial));
2853
2854        // Now create invalid evidence using different validator keys
2855        let notarize3 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[1], proposal1.clone());
2856
2857        // This should compile but verification should fail because the signatures
2858        // are from different validators
2859        let invalid_conflict: ConflictingNotarize<MinSig, Sha256> = ConflictingNotarize {
2860            view: conflict.view,
2861            parent_1: conflict.parent_1,
2862            payload_1: conflict.payload_1,
2863            signature_1: conflict.signature_1.clone(),
2864            parent_2: notarize3.proposal.parent,
2865            payload_2: notarize3.proposal.payload,
2866            signature_2: notarize3.proposal_signature,
2867        };
2868
2869        // Verification should still fail even with correct polynomial
2870        assert!(!invalid_conflict.verify(NAMESPACE, &polynomial));
2871    }
2872
2873    #[test]
2874    fn test_nullify_finalize_detection() {
2875        let n = 5;
2876        let t = quorum(n);
2877        let (_, polynomial, shares) = generate_test_data(n, t, 0);
2878
2879        let view = 10;
2880
2881        // Create a nullify for view 10
2882        let nullify = Nullify::<MinSig>::sign(NAMESPACE, &shares[0], view);
2883
2884        // Create a finalize for the same view
2885        let proposal = Proposal::new(view, 5, sample_digest(1));
2886        let finalize = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal);
2887
2888        // Create nullify+finalize evidence
2889        let conflict = NullifyFinalize::new(nullify, finalize.clone());
2890
2891        // Verify the evidence is valid
2892        assert!(conflict.verify(NAMESPACE, &polynomial));
2893
2894        // Now try with wrong namespace
2895        assert!(!conflict.verify(b"wrong_namespace", &polynomial));
2896
2897        // Now create invalid evidence with different validators
2898        let nullify2 = Nullify::<MinSig>::sign(NAMESPACE, &shares[1], view);
2899
2900        // Compile but verification should fail because signatures are from different validators
2901        let invalid_conflict: NullifyFinalize<MinSig, Sha256> = NullifyFinalize {
2902            proposal: finalize.proposal.clone(),
2903            view_signature: conflict.view_signature.clone(),
2904            finalize_signature: nullify2.view_signature,
2905        };
2906
2907        // Verification should fail
2908        assert!(!invalid_conflict.verify(NAMESPACE, &polynomial));
2909    }
2910
2911    #[test]
2912    fn test_finalization_wrong_signature() {
2913        let n = 5;
2914        let t = quorum(n);
2915        let (identity, _, shares) = generate_test_data(n, t, 0);
2916
2917        // Create a completely different key set
2918        let (wrong_identity, _, _) = generate_test_data(n, t, 1);
2919
2920        let proposal = Proposal::new(10, 5, sample_digest(1));
2921
2922        // Create finalizes and notarizes for threshold signatures
2923        let finalizes: Vec<_> = shares
2924            .iter()
2925            .map(|s| Finalize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2926            .collect();
2927        let notarizes: Vec<_> = shares
2928            .iter()
2929            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2930            .collect();
2931
2932        // Recover threshold signatures
2933        let proposal_partials = finalizes.iter().map(|f| &f.proposal_signature);
2934        let proposal_signature =
2935            threshold_signature_recover::<MinSig, _>(t, proposal_partials).unwrap();
2936        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2937        let seed_signature = threshold_signature_recover::<MinSig, _>(t, seed_partials).unwrap();
2938
2939        // Create finalization
2940        let finalization =
2941            Finalization::<MinSig, _>::new(proposal, proposal_signature, seed_signature);
2942
2943        // Verify with correct public key - should pass
2944        assert!(finalization.verify(NAMESPACE, &identity));
2945
2946        // Verify with wrong public key - should fail
2947        assert!(!finalization.verify(NAMESPACE, &wrong_identity));
2948    }
2949
2950    // Helper to create a Notarize message
2951    fn create_notarize(
2952        share: &Share,
2953        view: View,
2954        parent_view: View,
2955        payload_val: u8,
2956    ) -> Notarize<MinSig, Sha256> {
2957        let proposal = Proposal::new(view, parent_view, sample_digest(payload_val));
2958        Notarize::<MinSig, _>::sign(NAMESPACE, share, proposal)
2959    }
2960
2961    // Helper to create a Nullify message
2962    fn create_nullify(share: &Share, view: View) -> Nullify<MinSig> {
2963        Nullify::<MinSig>::sign(NAMESPACE, share, view)
2964    }
2965
2966    // Helper to create a Finalize message
2967    fn create_finalize(
2968        share: &Share,
2969        view: View,
2970        parent_view: View,
2971        payload_val: u8,
2972    ) -> Finalize<MinSig, Sha256> {
2973        let proposal = Proposal::new(view, parent_view, sample_digest(payload_val));
2974        Finalize::<MinSig, _>::sign(NAMESPACE, share, proposal)
2975    }
2976
2977    // Helper to create a Notarization (for panic test)
2978    fn create_notarization(
2979        proposal_view: View,
2980        parent_view: View,
2981        payload_val: u8,
2982        shares: &[Share],
2983        threshold: u32,
2984    ) -> Notarization<MinSig, Sha256> {
2985        let proposal = Proposal::new(proposal_view, parent_view, sample_digest(payload_val));
2986        let notarizes: Vec<_> = shares
2987            .iter()
2988            .take(threshold as usize)
2989            .map(|s| Notarize::<MinSig, _>::sign(NAMESPACE, s, proposal.clone()))
2990            .collect();
2991        let proposal_partials = notarizes.iter().map(|n| &n.proposal_signature);
2992        let proposal_signature =
2993            threshold_signature_recover::<MinSig, _>(threshold, proposal_partials).unwrap();
2994        let seed_partials = notarizes.iter().map(|n| &n.seed_signature);
2995        let seed_signature =
2996            threshold_signature_recover::<MinSig, _>(threshold, seed_partials).unwrap();
2997        Notarization::new(proposal, proposal_signature, seed_signature)
2998    }
2999
3000    #[test]
3001    fn test_batch_verifier_add_notarize() {
3002        let n_validators = 5;
3003        let threshold = quorum(n_validators);
3004        let (_, _, shares) = generate_test_data(n_validators, threshold, 123);
3005
3006        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3007
3008        let notarize1_s0 = create_notarize(&shares[0], 1, 0, 1); // validator 0
3009        let notarize2_s1 = create_notarize(&shares[1], 1, 0, 1); // validator 1 (same proposal)
3010        let notarize_diff_prop_s2 = create_notarize(&shares[2], 1, 0, 2); // validator 2 (different proposal)
3011
3012        // Add notarize1 (unverified)
3013        verifier.add(Voter::Notarize(notarize1_s0.clone()), false);
3014        assert_eq!(verifier.notarizes.len(), 1);
3015        assert_eq!(verifier.notarizes_verified, 0);
3016
3017        // Add notarize1 again (verified)
3018        verifier.add(Voter::Notarize(notarize1_s0.clone()), true);
3019        assert_eq!(verifier.notarizes.len(), 1); // Still 1 pending
3020        assert_eq!(verifier.notarizes_verified, 1); // Verified count increases
3021
3022        // Set leader to validator 0 (signer of notarize1)
3023        // This should trigger set_leader_proposal with notarize1's proposal
3024        verifier.set_leader(shares[0].index);
3025        assert!(verifier.leader_proposal.is_some());
3026        assert_eq!(
3027            verifier.leader_proposal.as_ref().unwrap(),
3028            &notarize1_s0.proposal
3029        );
3030        assert!(verifier.notarizes_force); // Force verification
3031        assert_eq!(verifier.notarizes.len(), 1); // notarize1 still there
3032
3033        // Add notarize2 (matches leader proposal)
3034        verifier.add(Voter::Notarize(notarize2_s1.clone()), false);
3035        assert_eq!(verifier.notarizes.len(), 2);
3036
3037        // Add notarize_diff_prop (does not match leader proposal, should be dropped)
3038        verifier.add(Voter::Notarize(notarize_diff_prop_s2.clone()), false);
3039        assert_eq!(verifier.notarizes.len(), 2); // Should not have been added
3040
3041        // Test adding when leader is set, but proposal comes from non-leader first
3042        let mut verifier2 = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3043        let notarize_s1_v2 = create_notarize(&shares[1], 2, 1, 3); // from validator 1
3044        let notarize_s0_v2_leader = create_notarize(&shares[0], 2, 1, 3); // from validator 0 (leader)
3045
3046        verifier2.set_leader(shares[0].index); // Leader is 0
3047        verifier2.add(Voter::Notarize(notarize_s1_v2.clone()), false); // Add non-leader's msg
3048        assert!(verifier2.leader_proposal.is_none()); // Leader proposal not set yet
3049        assert_eq!(verifier2.notarizes.len(), 1);
3050
3051        verifier2.add(Voter::Notarize(notarize_s0_v2_leader.clone()), false); // Add leader's msg
3052        assert!(verifier2.leader_proposal.is_some()); // Now set
3053        assert_eq!(
3054            verifier2.leader_proposal.as_ref().unwrap(),
3055            &notarize_s0_v2_leader.proposal
3056        );
3057        assert_eq!(verifier2.notarizes.len(), 2); // Both should be there
3058    }
3059
3060    #[test]
3061    fn test_batch_verifier_set_leader() {
3062        let n_validators = 5;
3063        let threshold = quorum(n_validators);
3064        let (_, _, shares) = generate_test_data(n_validators, threshold, 124);
3065        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3066
3067        let notarize_s0 = create_notarize(&shares[0], 1, 0, 1);
3068        let notarize_s1 = create_notarize(&shares[1], 1, 0, 1);
3069
3070        // Add notarize from non-leader first
3071        verifier.add(Voter::Notarize(notarize_s1.clone()), false);
3072        assert_eq!(verifier.notarizes.len(), 1);
3073
3074        // Set leader to s0 (no notarize from s0 yet)
3075        verifier.set_leader(shares[0].index);
3076        assert_eq!(verifier.leader, Some(shares[0].index));
3077        assert!(verifier.leader_proposal.is_none()); // No proposal from leader yet
3078        assert!(!verifier.notarizes_force);
3079        assert_eq!(verifier.notarizes.len(), 1); // notarize_s1 still there
3080
3081        // Add notarize from leader (s0)
3082        verifier.add(Voter::Notarize(notarize_s0.clone()), false);
3083        assert!(verifier.leader_proposal.is_some()); // Leader proposal now set
3084        assert_eq!(
3085            verifier.leader_proposal.as_ref().unwrap(),
3086            &notarize_s0.proposal
3087        );
3088        assert!(verifier.notarizes_force); // Force verification
3089        assert_eq!(verifier.notarizes.len(), 2); // Both notarizes present (assuming same proposal)
3090    }
3091
3092    #[test]
3093    fn test_batch_verifier_ready_and_verify_notarizes() {
3094        let n_validators = 5;
3095        let threshold = quorum(n_validators); // threshold = 4
3096        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 125);
3097
3098        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3099        let proposal = Proposal::new(1, 0, sample_digest(1));
3100
3101        let notarize_s0 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal.clone());
3102        let notarize_s1 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[1], proposal.clone());
3103        let notarize_s2 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[2], proposal.clone());
3104        let notarize_s3 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[3], proposal.clone()); // Enough for quorum
3105
3106        // Not ready - no leader/proposal (This specific check is now in test_ready_notarizes_without_leader_or_proposal)
3107        assert!(!verifier.ready_notarizes());
3108
3109        // Set leader and add leader's notarize
3110        verifier.set_leader(shares[0].index);
3111        verifier.add(Voter::Notarize(notarize_s0.clone()), false);
3112        assert!(verifier.ready_notarizes()); // notarizes_force is true (Covered by test_ready_notarizes_behavior_with_force_flag)
3113        assert_eq!(verifier.notarizes.len(), 1);
3114
3115        let (verified_n, failed_n) = verifier.verify_notarizes(NAMESPACE, &polynomial);
3116        assert_eq!(verified_n.len(), 1);
3117        assert!(failed_n.is_empty());
3118        assert_eq!(verifier.notarizes_verified, 1);
3119        assert!(verifier.notarizes.is_empty());
3120        assert!(!verifier.notarizes_force); // Reset after verify (Covered by test_ready_notarizes_behavior_with_force_flag)
3121
3122        // Not ready - not enough
3123        verifier.add(Voter::Notarize(notarize_s1.clone()), false); // Verified: 1, Pending: 1. Total: 2 < 4
3124        assert!(!verifier.ready_notarizes());
3125        verifier.add(Voter::Notarize(notarize_s2.clone()), false); // Verified: 1, Pending: 2. Total: 3 < 4
3126        assert!(!verifier.ready_notarizes());
3127        verifier.add(Voter::Notarize(notarize_s3.clone()), false); // Verified: 1, Pending: 3. Total: 4 == 4
3128        assert!(verifier.ready_notarizes()); // (Covered by test_ready_notarizes_exact_quorum)
3129        assert_eq!(verifier.notarizes.len(), 3);
3130
3131        let (verified_n, failed_n) = verifier.verify_notarizes(NAMESPACE, &polynomial);
3132        assert_eq!(verified_n.len(), 3);
3133        assert!(failed_n.is_empty());
3134        assert_eq!(verifier.notarizes_verified, 1 + 3); // 1 previous + 3 new
3135        assert!(verifier.notarizes.is_empty());
3136
3137        // Not ready - quorum met by verified (Covered by test_ready_notarizes_quorum_already_met_by_verified)
3138        assert!(!verifier.ready_notarizes());
3139
3140        // Scenario: Verification with a faulty signature
3141        let mut verifier2 = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3142        verifier2.set_leader(shares[0].index); // Set leader
3143        let leader_notarize = create_notarize(&shares[0], 2, 1, 10);
3144        verifier2.add(Voter::Notarize(leader_notarize.clone()), false); // Add leader's notarize
3145
3146        let mut faulty_notarize = create_notarize(&shares[1], 2, 1, 10); // Same proposal as leader
3147                                                                         // Corrupt a signature
3148        let (_, _, other_shares) = generate_test_data(n_validators, threshold, 126);
3149        faulty_notarize.proposal_signature = Notarize::<MinSig, _>::sign(
3150            NAMESPACE,
3151            &other_shares[1],
3152            faulty_notarize.proposal.clone(),
3153        ) // Sign with a "wrong" share for that index
3154        .proposal_signature;
3155
3156        verifier2.add(Voter::Notarize(faulty_notarize.clone()), false); // Add invalid notarize
3157        assert!(verifier2.ready_notarizes()); // Force is true
3158
3159        let (verified_n, failed_n) = verifier2.verify_notarizes(NAMESPACE, &polynomial);
3160        assert_eq!(verified_n.len(), 1); // Only leader's should verify
3161        assert!(verified_n.contains(&Voter::Notarize(leader_notarize)));
3162        assert_eq!(failed_n.len(), 1);
3163        assert_eq!(failed_n[0], shares[1].index); // s1's should fail
3164    }
3165
3166    #[test]
3167    fn test_batch_verifier_add_nullify() {
3168        let n_validators = 5;
3169        let threshold = quorum(n_validators);
3170        let (_, _, shares) = generate_test_data(n_validators, threshold, 127);
3171        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3172
3173        let nullify1_s0 = create_nullify(&shares[0], 1);
3174
3175        // Add unverified
3176        verifier.add(Voter::Nullify(nullify1_s0.clone()), false);
3177        assert_eq!(verifier.nullifies.len(), 1);
3178        assert_eq!(verifier.nullifies_verified, 0);
3179
3180        // Add verified
3181        verifier.add(Voter::Nullify(nullify1_s0.clone()), true);
3182        assert_eq!(verifier.nullifies.len(), 1);
3183        assert_eq!(verifier.nullifies_verified, 1);
3184    }
3185
3186    #[test]
3187    fn test_batch_verifier_ready_and_verify_nullifies() {
3188        let n_validators = 5;
3189        let threshold = quorum(n_validators); // threshold = 4
3190        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 128);
3191        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3192
3193        let nullify_s0 = create_nullify(&shares[0], 1);
3194        let nullify_s1 = create_nullify(&shares[1], 1);
3195        let nullify_s2 = create_nullify(&shares[2], 1);
3196        let nullify_s3 = create_nullify(&shares[3], 1); // Enough for quorum
3197
3198        // Not ready, not enough
3199        verifier.add(Voter::Nullify(nullify_s0.clone()), true); // Verified: 1
3200        assert_eq!(verifier.nullifies_verified, 1);
3201        verifier.add(Voter::Nullify(nullify_s1.clone()), false); // Verified: 1, Pending: 1. Total: 2 < 4
3202        assert!(!verifier.ready_nullifies());
3203        verifier.add(Voter::Nullify(nullify_s2.clone()), false); // Verified: 1, Pending: 2. Total: 3 < 4
3204        assert!(!verifier.ready_nullifies());
3205
3206        // Ready, enough for quorum
3207        verifier.add(Voter::Nullify(nullify_s3.clone()), false); // Verified: 1, Pending: 3. Total: 4 == 4
3208        assert!(verifier.ready_nullifies());
3209        assert_eq!(verifier.nullifies.len(), 3);
3210
3211        let (verified_null, failed_null) = verifier.verify_nullifies(NAMESPACE, &polynomial);
3212        assert_eq!(verified_null.len(), 3);
3213        assert!(failed_null.is_empty());
3214        assert_eq!(verifier.nullifies_verified, 1 + 3);
3215
3216        // Nothing to do after verify
3217        assert!(verifier.nullifies.is_empty());
3218        assert!(!verifier.ready_nullifies());
3219    }
3220
3221    #[test]
3222    fn test_batch_verifier_add_finalize() {
3223        let n_validators = 5;
3224        let threshold = quorum(n_validators);
3225        let (_, _, shares) = generate_test_data(n_validators, threshold, 129);
3226        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3227
3228        let finalize_s0_prop_a = create_finalize(&shares[0], 1, 0, 1); // Proposal A
3229        let finalize_s1_prop_b = create_finalize(&shares[1], 1, 0, 2); // Proposal B
3230
3231        // Add finalize_s1_propB (unverified) - No leader proposal yet, so it's added
3232        verifier.add(Voter::Finalize(finalize_s1_prop_b.clone()), false);
3233        assert_eq!(verifier.finalizes.len(), 1);
3234        assert_eq!(verifier.finalizes_verified, 0);
3235
3236        // Add finalize_s0_prop_a (unverified)
3237        verifier.add(Voter::Finalize(finalize_s0_prop_a.clone()), false);
3238        assert_eq!(verifier.finalizes.len(), 2); // Both are present
3239
3240        // Set leader and leader proposal to Proposal A
3241        // This specific call to set_leader won't set leader_proposal because no notarize from leader exists.
3242        verifier.set_leader(shares[0].index);
3243        assert!(verifier.leader_proposal.is_none());
3244        // Manually set leader_proposal for finalize_s0_propA
3245        verifier.set_leader_proposal(finalize_s0_prop_a.proposal.clone());
3246        // Now, finalize_s1_propB should have been removed.
3247        assert_eq!(verifier.finalizes.len(), 1);
3248        assert_eq!(verifier.finalizes[0], finalize_s0_prop_a);
3249        assert_eq!(verifier.finalizes_verified, 0);
3250
3251        // Add finalize_s0_propA (verified)
3252        verifier.add(Voter::Finalize(finalize_s0_prop_a.clone()), true);
3253        assert_eq!(verifier.finalizes.len(), 1); // Still finalize_s0_propA
3254        assert_eq!(verifier.finalizes_verified, 1); // Verified count increased
3255
3256        // Add finalize_s1_propB (unverified) - should be dropped as it doesn't match leader proposal
3257        verifier.add(Voter::Finalize(finalize_s1_prop_b.clone()), false);
3258        assert_eq!(verifier.finalizes.len(), 1); // Should still be 1 (finalize_s0_propA)
3259        assert_eq!(verifier.finalizes_verified, 1);
3260    }
3261
3262    #[test]
3263    fn test_batch_verifier_ready_and_verify_finalizes() {
3264        let n_validators = 5;
3265        let threshold = quorum(n_validators); // threshold = 4
3266        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 130);
3267        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3268        let leader_proposal = Proposal::new(1, 0, sample_digest(1));
3269
3270        let finalize_s0 =
3271            Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], leader_proposal.clone());
3272        let finalize_s1 =
3273            Finalize::<MinSig, _>::sign(NAMESPACE, &shares[1], leader_proposal.clone());
3274        let finalize_s2 =
3275            Finalize::<MinSig, _>::sign(NAMESPACE, &shares[2], leader_proposal.clone());
3276        let finalize_s3 =
3277            Finalize::<MinSig, _>::sign(NAMESPACE, &shares[3], leader_proposal.clone());
3278
3279        // Not ready - no leader/proposal set (Covered by test_ready_finalizes_without_leader_or_proposal)
3280        assert!(!verifier.ready_finalizes());
3281
3282        // Set leader and leader proposal
3283        verifier.set_leader(shares[0].index); // Leader is s0
3284                                              // Manually set leader proposal, as set_leader won't do it without a notarize from leader.
3285        verifier.set_leader_proposal(leader_proposal.clone());
3286
3287        // Add some (verified and unverified)
3288        verifier.add(Voter::Finalize(finalize_s0.clone()), true); // Verified: 1
3289        assert_eq!(verifier.finalizes_verified, 1);
3290        assert_eq!(verifier.finalizes.len(), 0);
3291
3292        verifier.add(Voter::Finalize(finalize_s1.clone()), false); // Verified: 1, Pending: 1. Total: 2 < 4
3293        assert!(!verifier.ready_finalizes());
3294        verifier.add(Voter::Finalize(finalize_s2.clone()), false); // Verified: 1, Pending: 2. Total: 3 < 4
3295        assert!(!verifier.ready_finalizes());
3296
3297        // Ready for finalizes
3298        verifier.add(Voter::Finalize(finalize_s3.clone()), false); // Verified: 1, Pending: 3. Total: 4 == 4
3299        assert!(verifier.ready_finalizes()); // (Covered by test_ready_finalizes_exact_quorum)
3300
3301        let (verified_fin, failed_fin) = verifier.verify_finalizes(NAMESPACE, &polynomial);
3302        assert_eq!(verified_fin.len(), 3);
3303        assert!(failed_fin.is_empty());
3304        assert_eq!(verifier.finalizes_verified, 1 + 3);
3305        assert!(verifier.finalizes.is_empty());
3306
3307        // Not ready, quorum met (Covered by test_ready_finalizes_quorum_already_met_by_verified)
3308        assert!(!verifier.ready_finalizes());
3309    }
3310
3311    #[test]
3312    fn test_batch_verifier_quorum_none() {
3313        let n_validators = 3;
3314        let threshold = quorum(n_validators); // Not strictly used by BatchVerifier logic when quorum is None
3315        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 200);
3316
3317        // Test with Notarizes
3318        let mut verifier_n = BatchVerifier::<MinSig, Sha256>::new(None);
3319        let prop1 = Proposal::new(1, 0, sample_digest(1));
3320        let notarize1 = create_notarize(&shares[0], 1, 0, 1);
3321
3322        assert!(!verifier_n.ready_notarizes()); // No leader/proposal
3323        verifier_n.set_leader(shares[0].index);
3324        verifier_n.add(Voter::Notarize(notarize1.clone()), false); // Sets leader proposal and notarizes_force
3325        assert!(verifier_n.ready_notarizes()); // notarizes_force is true, and notarizes is not empty
3326
3327        let (verified, failed) = verifier_n.verify_notarizes(NAMESPACE, &polynomial);
3328        assert_eq!(verified.len(), 1);
3329        assert!(failed.is_empty());
3330        assert_eq!(verifier_n.notarizes_verified, 1);
3331        assert!(!verifier_n.ready_notarizes()); // notarizes_force is false, list is empty
3332
3333        // Test with Nullifies
3334        let mut verifier_null = BatchVerifier::<MinSig, Sha256>::new(None);
3335        let nullify1 = create_nullify(&shares[0], 1);
3336        assert!(!verifier_null.ready_nullifies()); // List is empty
3337        verifier_null.add(Voter::Nullify(nullify1.clone()), false);
3338        assert!(verifier_null.ready_nullifies()); // List is not empty
3339        let (verified, failed) = verifier_null.verify_nullifies(NAMESPACE, &polynomial);
3340        assert_eq!(verified.len(), 1);
3341        assert!(failed.is_empty());
3342        assert_eq!(verifier_null.nullifies_verified, 1);
3343        assert!(!verifier_null.ready_nullifies()); // List is empty
3344
3345        // Test with Finalizes
3346        let mut verifier_f = BatchVerifier::<MinSig, Sha256>::new(None);
3347        let finalize1 = create_finalize(&shares[0], 1, 0, 1);
3348        assert!(!verifier_f.ready_finalizes()); // No leader/proposal
3349        verifier_f.set_leader(shares[0].index);
3350        verifier_f.set_leader_proposal(prop1.clone()); // Assume prop1 is the leader's proposal
3351        verifier_f.add(Voter::Finalize(finalize1.clone()), false);
3352        assert!(verifier_f.ready_finalizes()); // Leader/proposal set, list not empty
3353        let (verified, failed) = verifier_f.verify_finalizes(NAMESPACE, &polynomial);
3354        assert_eq!(verified.len(), 1);
3355        assert!(failed.is_empty());
3356        assert_eq!(verifier_f.finalizes_verified, 1);
3357        assert!(!verifier_f.ready_finalizes()); // List is empty
3358    }
3359
3360    #[test]
3361    fn test_batch_verifier_leader_proposal_filters_messages() {
3362        let n_validators = 3;
3363        let threshold = quorum(n_validators);
3364        let (_, _, shares) = generate_test_data(n_validators, threshold, 201);
3365        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3366
3367        let proposal_a = Proposal::new(1, 0, sample_digest(10));
3368        let proposal_b = Proposal::new(1, 0, sample_digest(20));
3369
3370        let notarize_a_s0 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal_a.clone());
3371        let notarize_b_s1 = Notarize::<MinSig, _>::sign(NAMESPACE, &shares[1], proposal_b.clone());
3372        let finalize_a_s0 = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[0], proposal_a.clone());
3373        let finalize_b_s1 = Finalize::<MinSig, _>::sign(NAMESPACE, &shares[1], proposal_b.clone());
3374
3375        verifier.add(Voter::Notarize(notarize_a_s0.clone()), false);
3376        verifier.add(Voter::Notarize(notarize_b_s1.clone()), false);
3377        verifier.add(Voter::Finalize(finalize_a_s0.clone()), false);
3378        verifier.add(Voter::Finalize(finalize_b_s1.clone()), false);
3379
3380        assert_eq!(verifier.notarizes.len(), 2);
3381        assert_eq!(verifier.finalizes.len(), 2);
3382
3383        // Set leader proposal to proposal_A
3384        // To make set_leader_proposal get called from set_leader, a notarize from the leader must exist.
3385        // Or, call it directly.
3386        verifier.set_leader(shares[0].index);
3387
3388        assert!(verifier.notarizes_force);
3389        assert_eq!(verifier.notarizes.len(), 1);
3390        assert_eq!(verifier.notarizes[0].proposal, proposal_a);
3391        assert_eq!(verifier.finalizes.len(), 1);
3392        assert_eq!(verifier.finalizes[0].proposal, proposal_a);
3393    }
3394
3395    #[test]
3396    #[should_panic(expected = "self.leader.is_none()")]
3397    fn test_batch_verifier_set_leader_twice_panics() {
3398        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(3));
3399        verifier.set_leader(0);
3400        verifier.set_leader(1); // This should panic
3401    }
3402
3403    #[test]
3404    #[should_panic(expected = "should not be adding recovered messages to partial verifier")]
3405    fn test_batch_verifier_add_recovered_message_panics() {
3406        let n_validators = 3;
3407        let threshold = quorum(n_validators);
3408        let (_, _, shares) = generate_test_data(n_validators, threshold, 202);
3409        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3410
3411        let notarization = create_notarization(1, 0, 1, &shares, threshold);
3412        verifier.add(Voter::Notarization(notarization), false); // This should panic
3413    }
3414
3415    #[test]
3416    fn test_ready_notarizes_behavior_with_force_flag() {
3417        let n_validators = 3;
3418        let threshold = quorum(n_validators);
3419        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 203);
3420        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3421
3422        let leader_notarize = create_notarize(&shares[0], 1, 0, 1);
3423
3424        // Set leader and add leader's notarize
3425        verifier.set_leader(shares[0].index);
3426        // Manually add leader's notarize for it to pick up leader_proposal
3427        verifier.add(Voter::Notarize(leader_notarize.clone()), false);
3428
3429        assert!(
3430            verifier.notarizes_force,
3431            "notarizes_force should be true after leader's proposal is set"
3432        );
3433        assert!(
3434            verifier.ready_notarizes(),
3435            "Ready should be true when notarizes_force is true"
3436        );
3437
3438        // Assume leader's own notarize is processed. Let's verify it.
3439        let (verified, _) = verifier.verify_notarizes(NAMESPACE, &polynomial);
3440        assert_eq!(verified.len(), 1);
3441
3442        assert!(
3443            !verifier.notarizes_force,
3444            "notarizes_force should be false after verification"
3445        );
3446        assert!(
3447            !verifier.ready_notarizes(),
3448            "Ready should be false now (no pending, quorum not met by verified alone)"
3449        );
3450    }
3451
3452    #[test]
3453    fn test_ready_notarizes_without_leader_or_proposal() {
3454        let n_validators = 3;
3455        let threshold = quorum(n_validators);
3456        let (_, _, shares) = generate_test_data(n_validators, threshold, 204);
3457        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3458
3459        // Collect sufficient number of unverified notarizes
3460        for i in 0..threshold {
3461            verifier.add(
3462                Voter::Notarize(create_notarize(&shares[i as usize], 1, 0, 1)),
3463                false,
3464            );
3465        }
3466        assert!(
3467            !verifier.ready_notarizes(),
3468            "Should not be ready without leader/proposal set"
3469        );
3470
3471        // Set leader
3472        verifier.set_leader(shares[0].index);
3473        assert!(
3474            verifier.ready_notarizes(),
3475            "Should be ready once leader is set"
3476        );
3477    }
3478
3479    #[test]
3480    fn test_ready_finalizes_without_leader_or_proposal() {
3481        let n_validators = 3;
3482        let threshold = quorum(n_validators);
3483        let (_, _, shares) = generate_test_data(n_validators, threshold, 205);
3484        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3485
3486        for i in 0..threshold {
3487            verifier.add(
3488                Voter::Finalize(create_finalize(&shares[i as usize], 1, 0, 1)),
3489                false,
3490            );
3491        }
3492        assert!(
3493            !verifier.ready_finalizes(),
3494            "Should not be ready without leader/proposal set"
3495        );
3496
3497        // Set leader, still not ready
3498        verifier.set_leader(shares[0].index);
3499        assert!(
3500            !verifier.ready_finalizes(),
3501            "Should not be ready without leader_proposal set"
3502        );
3503    }
3504
3505    #[test]
3506    fn test_verify_notarizes_empty_pending_when_forced() {
3507        let n_validators = 3;
3508        let threshold = quorum(n_validators);
3509        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3510
3511        let leader_proposal = Proposal::new(1, 0, sample_digest(1));
3512        verifier.set_leader_proposal(leader_proposal); // This sets notarizes_force = true
3513
3514        assert!(verifier.notarizes_force);
3515        assert!(verifier.notarizes.is_empty());
3516        assert!(!verifier.ready_notarizes());
3517    }
3518
3519    #[test]
3520    fn test_verify_nullifies_empty_pending() {
3521        let n_validators = 3;
3522        let threshold = quorum(n_validators);
3523        let (_, polynomial, _) = generate_test_data(n_validators, threshold, 207);
3524        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3525
3526        assert!(verifier.nullifies.is_empty());
3527        // ready_nullifies will be false if the list is empty and quorum is Some
3528        assert!(!verifier.ready_nullifies());
3529
3530        let (verified, failed) = verifier.verify_nullifies(NAMESPACE, &polynomial);
3531        assert!(verified.is_empty());
3532        assert!(failed.is_empty());
3533        assert_eq!(verifier.nullifies_verified, 0);
3534    }
3535
3536    #[test]
3537    fn test_verify_finalizes_empty_pending() {
3538        let n_validators = 3;
3539        let threshold = quorum(n_validators);
3540        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 208);
3541        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3542
3543        // ready_finalizes will be false if the list is empty and quorum is Some
3544        verifier.set_leader(shares[0].index);
3545        assert!(verifier.finalizes.is_empty());
3546        assert!(!verifier.ready_finalizes());
3547
3548        let (verified, failed) = verifier.verify_finalizes(NAMESPACE, &polynomial);
3549        assert!(verified.is_empty());
3550        assert!(failed.is_empty());
3551        assert_eq!(verifier.finalizes_verified, 0);
3552    }
3553
3554    #[test]
3555    fn test_ready_notarizes_exact_quorum() {
3556        let n_validators = 5;
3557        let threshold = quorum(n_validators); // threshold = 4
3558        let (_, polynomial, shares) = generate_test_data(n_validators, threshold, 209);
3559        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3560
3561        let leader_notarize = create_notarize(&shares[0], 1, 0, 1);
3562        verifier.set_leader(shares[0].index);
3563        verifier.add(Voter::Notarize(leader_notarize), true); // 1 verified
3564        assert_eq!(verifier.notarizes_verified, 1);
3565
3566        // Add next verified notarize
3567        verifier.add(Voter::Notarize(create_notarize(&shares[1], 1, 0, 1)), false);
3568
3569        // Perform forced verification
3570        assert!(verifier.ready_notarizes());
3571        let (verified, failed) = verifier.verify_notarizes(NAMESPACE, &polynomial);
3572        assert_eq!(verified.len(), 1);
3573        assert!(failed.is_empty());
3574        assert_eq!(verifier.notarizes_verified, 1 + 1);
3575
3576        // Add threshold - 1 pending notarizes
3577        for share in shares.iter().take(threshold as usize).skip(2) {
3578            assert!(!verifier.ready_notarizes());
3579            verifier.add(Voter::Notarize(create_notarize(share, 1, 0, 1)), false);
3580        }
3581
3582        // Now, notarizes_verified = 2, notarizes.len() = 2. Total = 4 == threshold
3583        assert!(verifier.ready_notarizes());
3584    }
3585
3586    #[test]
3587    fn test_ready_nullifies_exact_quorum() {
3588        let n_validators = 5;
3589        let threshold = quorum(n_validators); // threshold = 4
3590        let (_, _, shares) = generate_test_data(n_validators, threshold, 210);
3591        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3592
3593        verifier.add(Voter::Nullify(create_nullify(&shares[0], 1)), true); // 1 verified
3594        assert_eq!(verifier.nullifies_verified, 1);
3595
3596        for share in shares.iter().take(threshold as usize).skip(1) {
3597            assert!(!verifier.ready_nullifies());
3598            verifier.add(Voter::Nullify(create_nullify(share, 1)), false);
3599        }
3600        assert!(verifier.ready_nullifies());
3601    }
3602
3603    #[test]
3604    fn test_ready_finalizes_exact_quorum() {
3605        let n_validators = 5;
3606        let threshold = quorum(n_validators); // threshold = 4
3607        let (_, _, shares) = generate_test_data(n_validators, threshold, 211);
3608        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3609
3610        let leader_proposal = Proposal::new(1, 0, sample_digest(1));
3611        verifier.set_leader(shares[0].index);
3612        verifier.set_leader_proposal(leader_proposal.clone());
3613
3614        verifier.add(Voter::Finalize(create_finalize(&shares[0], 1, 0, 1)), true); // 1 verified
3615        assert_eq!(verifier.finalizes_verified, 1);
3616
3617        for share in shares.iter().take(threshold as usize).skip(1) {
3618            assert!(!verifier.ready_finalizes());
3619            verifier.add(Voter::Finalize(create_finalize(share, 1, 0, 1)), false);
3620        }
3621        assert!(verifier.ready_finalizes());
3622    }
3623
3624    #[test]
3625    fn test_ready_notarizes_quorum_already_met_by_verified() {
3626        let n_validators = 5;
3627        let threshold = quorum(n_validators); // threshold = 4
3628        let (_, _, shares) = generate_test_data(n_validators, threshold, 212);
3629        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3630
3631        let leader_notarize = create_notarize(&shares[0], 1, 0, 1);
3632        verifier.set_leader(shares[0].index);
3633        verifier.add(Voter::Notarize(leader_notarize), false); // This sets leader_proposal and notarizes_force
3634                                                               // Manually set notarizes_force to false as if verify_notarizes was called.
3635        verifier.notarizes_force = false;
3636
3637        for share in shares.iter().take(threshold as usize) {
3638            verifier.add(Voter::Notarize(create_notarize(share, 1, 0, 1)), true);
3639        }
3640        assert_eq!(verifier.notarizes_verified as u32, threshold);
3641        assert!(
3642            !verifier.ready_notarizes(),
3643            "Should not be ready if quorum already met by verified messages"
3644        );
3645
3646        // Add one more pending, still should not be ready
3647        verifier.add(
3648            Voter::Notarize(create_notarize(&shares[threshold as usize], 1, 0, 1)),
3649            false,
3650        );
3651        assert!(!verifier.ready_notarizes());
3652    }
3653
3654    #[test]
3655    fn test_ready_nullifies_quorum_already_met_by_verified() {
3656        let n_validators = 5;
3657        let threshold = quorum(n_validators); // threshold = 4
3658        let (_, _, shares) = generate_test_data(n_validators, threshold, 213);
3659        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3660
3661        for share in shares.iter().take(threshold as usize) {
3662            verifier.add(Voter::Nullify(create_nullify(share, 1)), true);
3663        }
3664        assert_eq!(verifier.nullifies_verified as u32, threshold);
3665        assert!(!verifier.ready_nullifies());
3666
3667        verifier.add(
3668            Voter::Nullify(create_nullify(&shares[threshold as usize], 1)),
3669            false,
3670        );
3671        assert!(!verifier.ready_nullifies());
3672    }
3673
3674    #[test]
3675    fn test_ready_finalizes_quorum_already_met_by_verified() {
3676        let n_validators = 5;
3677        let threshold = quorum(n_validators); // threshold = 4
3678        let (_, _, shares) = generate_test_data(n_validators, threshold, 214);
3679        let mut verifier = BatchVerifier::<MinSig, Sha256>::new(Some(threshold));
3680
3681        let leader_proposal = Proposal::new(1, 0, sample_digest(1));
3682        verifier.set_leader(shares[0].index);
3683        verifier.set_leader_proposal(leader_proposal.clone());
3684
3685        for share in shares.iter().take(threshold as usize) {
3686            verifier.add(Voter::Finalize(create_finalize(share, 1, 0, 1)), true);
3687        }
3688        assert_eq!(verifier.finalizes_verified as u32, threshold);
3689        assert!(!verifier.ready_finalizes());
3690
3691        verifier.add(
3692            Voter::Finalize(create_finalize(&shares[threshold as usize], 1, 0, 1)),
3693            false,
3694        );
3695        assert!(!verifier.ready_finalizes());
3696    }
3697}