Skip to main content

hotmint_types/
crypto.rs

1use ruc::*;
2use serde::{Deserialize, Serialize};
3
4use crate::validator::{ValidatorId, ValidatorSet};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct Signature(pub Vec<u8>);
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct PublicKey(pub Vec<u8>);
11
12/// Simple aggregate signature: bitfield indicating which validators signed + individual signatures
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct AggregateSignature {
15    pub signers: Vec<bool>,
16    pub signatures: Vec<Signature>,
17}
18
19impl AggregateSignature {
20    pub fn new(validator_count: usize) -> Self {
21        Self {
22            signers: vec![false; validator_count],
23            signatures: Vec::new(),
24        }
25    }
26
27    pub fn add(&mut self, index: usize, sig: Signature) -> Result<()> {
28        if index >= self.signers.len() {
29            return Err(eg!("signer index out of bounds"));
30        }
31        if self.signers[index] {
32            return Err(eg!("duplicate signature from validator {}", index));
33        }
34        self.signers[index] = true;
35        // Insert in sorted position so signatures stay in index order
36        // (required by verify_aggregate which walks signers left-to-right).
37        let pos = self.signers[..index].iter().filter(|&&s| s).count();
38        self.signatures.insert(pos, sig);
39        Ok(())
40    }
41
42    pub fn count(&self) -> usize {
43        self.signers.iter().filter(|&&s| s).count()
44    }
45}
46
47pub trait Signer: Send + Sync {
48    fn sign(&self, message: &[u8]) -> Signature;
49    fn public_key(&self) -> PublicKey;
50    fn validator_id(&self) -> ValidatorId;
51}
52
53pub trait Verifier: Send + Sync {
54    fn verify(&self, pk: &PublicKey, msg: &[u8], sig: &Signature) -> bool;
55    fn verify_aggregate(&self, vs: &ValidatorSet, msg: &[u8], agg: &AggregateSignature) -> bool;
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_aggregate_signature_add() {
64        let mut agg = AggregateSignature::new(4);
65        assert_eq!(agg.count(), 0);
66        agg.add(0, Signature(vec![1])).unwrap();
67        assert_eq!(agg.count(), 1);
68        agg.add(2, Signature(vec![2])).unwrap();
69        assert_eq!(agg.count(), 2);
70    }
71
72    #[test]
73    fn test_aggregate_signature_duplicate_rejected() {
74        let mut agg = AggregateSignature::new(4);
75        agg.add(1, Signature(vec![1])).unwrap();
76        assert!(agg.add(1, Signature(vec![2])).is_err());
77    }
78
79    #[test]
80    fn test_aggregate_signature_out_of_bounds() {
81        let mut agg = AggregateSignature::new(3);
82        assert!(agg.add(3, Signature(vec![1])).is_err());
83        assert!(agg.add(100, Signature(vec![1])).is_err());
84    }
85
86    #[test]
87    fn test_aggregate_signature_zero_size() {
88        let agg = AggregateSignature::new(0);
89        assert_eq!(agg.count(), 0);
90    }
91}