1mod block;
4pub use block::{Block, Finalized, Notarized};
5mod consensus;
6use commonware_utils::hex;
7pub use consensus::{
8 leader_index, Activity, Evaluation, Finalization, Identity, Notarization, Seed, Signature,
9};
10pub mod wasm;
11
12pub const NAMESPACE: &[u8] = b"_ALTO";
13
14#[repr(u8)]
15pub enum Kind {
16 Seed = 0,
17 Notarization = 1,
18 Finalization = 2,
19}
20
21impl Kind {
22 pub fn from_u8(value: u8) -> Option<Self> {
23 match value {
24 0 => Some(Self::Seed),
25 1 => Some(Self::Notarization),
26 2 => Some(Self::Finalization),
27 _ => None,
28 }
29 }
30
31 pub fn to_hex(&self) -> String {
32 match self {
33 Self::Seed => hex(&[0]),
34 Self::Notarization => hex(&[1]),
35 Self::Finalization => hex(&[2]),
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use commonware_codec::{DecodeExt, Encode};
44 use commonware_consensus::threshold_simplex::types::{
45 Finalization, Finalize, Notarization, Notarize, Proposal,
46 };
47 use commonware_cryptography::{
48 bls12381::{
49 dkg::ops,
50 primitives::{ops::threshold_signature_recover, poly, variant::MinSig},
51 },
52 hash, Digestible,
53 };
54 use rand::{rngs::StdRng, SeedableRng};
55
56 #[test]
57 fn test_notarized() {
58 let mut rng = StdRng::seed_from_u64(0);
60 let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, 4, 3);
61
62 let digest = hash(b"hello world");
64 let block = Block::new(digest, 10, 100);
65 let proposal = Proposal::new(11, 8, block.digest());
66
67 let partials = shares
69 .iter()
70 .map(|share| Notarize::<MinSig, _>::sign(NAMESPACE, share, proposal.clone()))
71 .collect::<Vec<_>>();
72 let proposal_partials = partials
73 .iter()
74 .map(|partial| partial.proposal_signature.clone())
75 .collect::<Vec<_>>();
76 let proposal_recovered =
77 threshold_signature_recover::<MinSig, _>(3, &proposal_partials).unwrap();
78 let seed_partials = partials
79 .into_iter()
80 .map(|partial| partial.seed_signature)
81 .collect::<Vec<_>>();
82 let seed_recovered = threshold_signature_recover::<MinSig, _>(3, &seed_partials).unwrap();
83 let notarization = Notarization::new(proposal, proposal_recovered, seed_recovered);
84 let notarized = Notarized::new(notarization, block.clone());
85
86 let encoded = notarized.encode();
88 let decoded = Notarized::decode(encoded).expect("failed to decode notarized");
89 assert_eq!(notarized, decoded);
90
91 let public_key = poly::public::<MinSig>(&polynomial);
93 assert!(notarized.verify(NAMESPACE, public_key));
94 }
95
96 #[test]
97 fn test_finalized() {
98 let mut rng = StdRng::seed_from_u64(0);
100 let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, 4, 3);
101
102 let digest = hash(b"hello world");
104 let block = Block::new(digest, 10, 100);
105 let proposal = Proposal::new(11, 8, block.digest());
106
107 let partials = shares
109 .iter()
110 .map(|share| Notarize::<MinSig, _>::sign(NAMESPACE, share, proposal.clone()))
111 .collect::<Vec<_>>();
112 let seed_partials = partials
113 .into_iter()
114 .map(|partial| partial.seed_signature)
115 .collect::<Vec<_>>();
116 let seed_recovered = threshold_signature_recover::<MinSig, _>(3, &seed_partials).unwrap();
117 let finalize_partials = shares
118 .iter()
119 .map(|share| Finalize::<MinSig, _>::sign(NAMESPACE, share, proposal.clone()))
120 .collect::<Vec<_>>();
121 let finalize_partials = finalize_partials
122 .into_iter()
123 .map(|partial| partial.proposal_signature)
124 .collect::<Vec<_>>();
125 let finalize_recovered =
126 threshold_signature_recover::<MinSig, _>(3, &finalize_partials).unwrap();
127 let finalized = Finalization::new(proposal, finalize_recovered, seed_recovered);
128 let finalized = Finalized::new(finalized, block.clone());
129
130 let encoded = finalized.encode();
132 let decoded = Finalized::decode(encoded).expect("failed to decode finalized");
133 assert_eq!(finalized, decoded);
134
135 let public_key = poly::public::<MinSig>(&polynomial);
137 assert!(finalized.verify(NAMESPACE, public_key));
138 }
139}