Skip to main content

hotmint_crypto/
signer.rs

1use ed25519_dalek::Verifier as DalekVerifier;
2use ed25519_dalek::{Signer as DalekSigner, SigningKey, VerifyingKey};
3use hotmint_types::crypto::{PublicKey, Signature};
4use hotmint_types::validator::{ValidatorId, ValidatorSet};
5use hotmint_types::{AggregateSignature, Signer, Verifier};
6
7/// Ed25519 signer implementation
8pub struct Ed25519Signer {
9    signing_key: SigningKey,
10    validator_id: ValidatorId,
11}
12
13impl Ed25519Signer {
14    pub fn new(signing_key: SigningKey, validator_id: ValidatorId) -> Self {
15        Self {
16            signing_key,
17            validator_id,
18        }
19    }
20
21    pub fn generate(validator_id: ValidatorId) -> Self {
22        let mut rng = rand::thread_rng();
23        let signing_key = SigningKey::generate(&mut rng);
24        Self::new(signing_key, validator_id)
25    }
26
27    pub fn verifying_key(&self) -> VerifyingKey {
28        self.signing_key.verifying_key()
29    }
30}
31
32impl Signer for Ed25519Signer {
33    fn sign(&self, message: &[u8]) -> Signature {
34        let sig = self.signing_key.sign(message);
35        Signature(sig.to_bytes().to_vec())
36    }
37
38    fn public_key(&self) -> PublicKey {
39        PublicKey(self.signing_key.verifying_key().to_bytes().to_vec())
40    }
41
42    fn validator_id(&self) -> ValidatorId {
43        self.validator_id
44    }
45}
46
47/// Ed25519 verifier implementation
48pub struct Ed25519Verifier;
49
50impl Verifier for Ed25519Verifier {
51    fn verify(&self, pk: &PublicKey, msg: &[u8], sig: &Signature) -> bool {
52        let vk_bytes: [u8; 32] = match pk.0.as_slice().try_into() {
53            Ok(b) => b,
54            Err(_) => return false,
55        };
56        let vk = match VerifyingKey::from_bytes(&vk_bytes) {
57            Ok(v) => v,
58            Err(_) => return false,
59        };
60        let sig_bytes: [u8; 64] = match sig.0.as_slice().try_into() {
61            Ok(b) => b,
62            Err(_) => return false,
63        };
64        let signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
65        vk.verify(msg, &signature).is_ok()
66    }
67
68    fn verify_aggregate(&self, vs: &ValidatorSet, msg: &[u8], agg: &AggregateSignature) -> bool {
69        // Collect all (public_key, signature) pairs for batch verification.
70        // ed25519_dalek::verify_batch is significantly faster than N individual
71        // verifications because it uses a random linear combination trick
72        // (Bos-Coster method) that amortises the expensive Ed25519 group ops.
73        let mut pks = Vec::new();
74        let mut sigs = Vec::new();
75        let mut sig_idx = 0;
76
77        for (i, signed) in agg.signers.iter().enumerate() {
78            if !signed {
79                continue;
80            }
81            if sig_idx >= agg.signatures.len() {
82                return false;
83            }
84            let Some(vi) = vs.validators().get(i) else {
85                return false;
86            };
87            let pk_bytes: [u8; 32] = match vi.public_key.0.as_slice().try_into() {
88                Ok(b) => b,
89                Err(_) => return false,
90            };
91            let Ok(vk) = ed25519_dalek::VerifyingKey::from_bytes(&pk_bytes) else {
92                return false;
93            };
94            let sig_bytes: [u8; 64] = match agg.signatures[sig_idx].0.as_slice().try_into() {
95                Ok(b) => b,
96                Err(_) => return false,
97            };
98            let sig = ed25519_dalek::Signature::from_bytes(&sig_bytes);
99            pks.push(vk);
100            sigs.push(sig);
101            sig_idx += 1;
102        }
103
104        if sig_idx != agg.signatures.len() {
105            return false;
106        }
107
108        // All signatures verify the same message, so expand it for each entry.
109        let messages: Vec<&[u8]> = vec![msg; sigs.len()];
110        ed25519_dalek::verify_batch(&messages, &sigs, &pks).is_ok()
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_sign_verify() {
120        let signer = Ed25519Signer::generate(ValidatorId(0));
121        let msg = b"test message";
122        let sig = signer.sign(msg);
123        let pk = signer.public_key();
124
125        let verifier = Ed25519Verifier;
126        assert!(verifier.verify(&pk, msg, &sig));
127        assert!(!verifier.verify(&pk, b"wrong message", &sig));
128    }
129}