commonware_consensus/simplex/signing_scheme/
utils.rs1use bytes::{Buf, BufMut};
4use commonware_codec::{EncodeSize, Error, Read, Write};
5use commonware_utils::bitmap::BitMap;
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub struct Signers {
12 bitmap: BitMap<1>,
13}
14
15impl Signers {
16 pub fn from(participants: usize, signers: impl IntoIterator<Item = u32>) -> Self {
23 let mut bitmap = BitMap::zeroes(participants as u64);
24 for signer in signers.into_iter() {
25 assert!(
26 !bitmap.get(signer as u64),
27 "duplicate signer index: {signer}",
28 );
29 bitmap.set(signer as u64, true);
34 }
35
36 Self { bitmap }
37 }
38
39 #[allow(clippy::len_without_is_empty)]
41 pub fn len(&self) -> usize {
42 self.bitmap.len() as usize
43 }
44
45 pub fn count(&self) -> usize {
47 self.bitmap.count_ones() as usize
48 }
49
50 pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
52 self.bitmap
53 .iter()
54 .enumerate()
55 .filter_map(|(index, bit)| bit.then_some(index as u32))
56 }
57}
58
59impl Write for Signers {
60 fn write(&self, writer: &mut impl BufMut) {
61 self.bitmap.write(writer);
62 }
63}
64
65impl EncodeSize for Signers {
66 fn encode_size(&self) -> usize {
67 self.bitmap.encode_size()
68 }
69}
70
71impl Read for Signers {
72 type Cfg = usize;
73
74 fn read_cfg(reader: &mut impl Buf, max_participants: &usize) -> Result<Self, Error> {
75 let bitmap = BitMap::read_cfg(reader, &(*max_participants as u64))?;
76 Ok(Self { bitmap })
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use commonware_codec::{Decode, Encode};
90
91 #[test]
92 fn test_from_signers() {
93 let signers = Signers::from(6, [0, 3, 5]);
94 let collected: Vec<_> = signers.iter().collect();
95 assert_eq!(collected, vec![0, 3, 5]);
96 assert_eq!(signers.count(), 3);
97 }
98
99 #[test]
100 #[should_panic(expected = "bit 4 out of bounds (len: 4)")]
101 fn test_from_out_of_bounds() {
102 Signers::from(4, [0, 4]);
103 }
104
105 #[test]
106 #[should_panic(expected = "duplicate signer index: 0")]
107 fn test_from_duplicate() {
108 Signers::from(4, [0, 0, 1]);
109 }
110
111 #[test]
112 fn test_from_not_increasing() {
113 Signers::from(4, [2, 1]);
114 }
115
116 #[test]
117 fn test_codec_round_trip() {
118 let signers = Signers::from(9, [1, 6]);
119 let encoded = signers.encode();
120 let decoded = Signers::decode_cfg(encoded, &9).unwrap();
121 assert_eq!(decoded, signers);
122 }
123
124 #[test]
125 fn test_decode_respects_participant_limit() {
126 let signers = Signers::from(8, [0, 3, 7]);
127 let encoded = signers.encode();
128 assert!(Signers::decode_cfg(encoded.clone(), &2).is_err());
130 assert!(Signers::decode_cfg(encoded.clone(), &8).is_ok());
132 assert!(Signers::decode_cfg(encoded.clone(), &10).is_ok());
134 }
135}