alto_types/
lib.rs

1//! Common types used throughout `alto`.
2
3mod block;
4pub use block::{Block, Finalized, Notarized};
5mod consensus;
6use commonware_utils::hex;
7pub use consensus::{
8    Activity, Evaluation, Finalization, Identity, Notarization, PublicKey, Scheme, Seed, Seedable,
9    Signature,
10};
11pub mod wasm;
12
13/// The unique namespace prefix used in all signing operations to prevent signature replay attacks.
14pub const NAMESPACE: &[u8] = b"_ALTO";
15
16/// The epoch number used in [commonware_consensus::simplex].
17///
18/// Because alto does not implement reconfiguration (validator set changes and resharing), we hardcode the epoch to 0.
19///
20/// For an example of how to implement reconfiguration and resharing, see [commonware-reshare](https://github.com/commonwarexyz/monorepo/tree/main/examples/reshare).
21pub const EPOCH: u64 = 0;
22/// The epoch length used in [commonware_consensus::simplex].
23///
24/// Because alto does not implement reconfiguration (validator set changes and resharing), we hardcode the epoch length to u64::MAX (to
25/// stay in the first epoch forever).
26///
27/// For an example of how to implement reconfiguration and resharing, see [commonware-reshare](https://github.com/commonwarexyz/monorepo/tree/main/examples/reshare).
28pub const EPOCH_LENGTH: u64 = u64::MAX;
29
30#[repr(u8)]
31pub enum Kind {
32    Seed = 0,
33    Notarization = 1,
34    Finalization = 2,
35}
36
37impl Kind {
38    pub fn from_u8(value: u8) -> Option<Self> {
39        match value {
40            0 => Some(Self::Seed),
41            1 => Some(Self::Notarization),
42            2 => Some(Self::Finalization),
43            _ => None,
44        }
45    }
46
47    pub fn to_hex(&self) -> String {
48        match self {
49            Self::Seed => hex(&[0]),
50            Self::Notarization => hex(&[1]),
51            Self::Finalization => hex(&[2]),
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use commonware_codec::{DecodeExt, Encode};
60    use commonware_consensus::{
61        simplex::types::{Finalization, Finalize, Notarization, Notarize, Proposal},
62        types::Round,
63    };
64    use commonware_cryptography::{
65        bls12381::{dkg::ops, primitives::variant::MinSig},
66        ed25519, Digestible, Hasher, PrivateKeyExt, Sha256, Signer,
67    };
68    use commonware_utils::set::Ordered;
69    use rand::{rngs::StdRng, SeedableRng};
70
71    #[test]
72    fn test_notarized() {
73        // Create network key
74        let mut rng = StdRng::seed_from_u64(0);
75        let n = 4;
76        let participants = (0..n)
77            .map(|_| ed25519::PrivateKey::from_rng(&mut rng).public_key())
78            .collect::<Ordered<_>>();
79        let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, 3);
80        let schemes: Vec<_> = shares
81            .into_iter()
82            .map(|share| Scheme::new(participants.clone(), &polynomial, share))
83            .collect();
84
85        // Create a block
86        let digest = Sha256::hash(b"hello world");
87        let block = Block::new(digest, 10, 100);
88        let proposal = Proposal::new(Round::new(EPOCH, 11), 8, block.digest());
89
90        // Create a notarization
91        let notarizes: Vec<_> = schemes
92            .iter()
93            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
94            .collect();
95        let notarization = Notarization::from_notarizes(&schemes[0], &notarizes).unwrap();
96        let notarized = Notarized::new(notarization, block.clone());
97
98        // Serialize and deserialize
99        let encoded = notarized.encode();
100        let decoded = Notarized::decode(encoded).expect("failed to decode notarized");
101        assert_eq!(notarized, decoded);
102
103        // Verify notarized
104        assert!(notarized.verify(&schemes[0], NAMESPACE));
105    }
106
107    #[test]
108    fn test_finalized() {
109        // Create network key
110        let mut rng = StdRng::seed_from_u64(0);
111        let n = 4;
112        let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, 3);
113        let participants = (0..n)
114            .map(|_| ed25519::PrivateKey::from_rng(&mut rng).public_key())
115            .collect::<Ordered<_>>();
116        let schemes: Vec<_> = shares
117            .into_iter()
118            .map(|share| Scheme::new(participants.clone(), &polynomial, share))
119            .collect();
120
121        // Create a block
122        let digest = Sha256::hash(b"hello world");
123        let block = Block::new(digest, 10, 100);
124        let proposal = Proposal::new(Round::new(EPOCH, 11), 8, block.digest());
125
126        // Create a finalization
127        let finalizes: Vec<_> = schemes
128            .iter()
129            .map(|scheme| Finalize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
130            .collect();
131        let finalization = Finalization::from_finalizes(&schemes[0], &finalizes).unwrap();
132        let finalized = Finalized::new(finalization, block.clone());
133
134        // Serialize and deserialize
135        let encoded = finalized.encode();
136        let decoded = Finalized::decode(encoded).expect("failed to decode finalized");
137        assert_eq!(finalized, decoded);
138
139        // Verify finalized
140        assert!(finalized.verify(&schemes[0], NAMESPACE));
141    }
142}