primitives/signing/
mod.rs

1pub use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
2use ed25519_dalek::{Signer as DalekSigner, Verifier as DalekVerifier};
3use itertools::chain;
4
5use crate::{
6    errors::{PrimitiveError, VerificationError},
7    types::SessionId,
8};
9
10/// Message identifier type: (SessionId, round, protocol tag)
11pub type MessageId = (SessionId, u8, &'static [u8]);
12
13// ------------------------------ Defaults ---------------------------------- //
14// Set Ed25519 as the default signing scheme
15pub trait Signer: UCSigner<Signature> {}
16impl<SR: UCSigner<Signature>> Signer for SR {}
17
18pub trait Verifier: UCVerifier<Signature> + Sync + Send {}
19impl<VR: UCVerifier<Signature>> Verifier for VR {}
20
21// -------------------------------- Traits ---------------------------------- //
22/// Signer that signs messages alongside metadata (round, protocol tag and session ID)
23/// to avoid replay attacks in UC protocols.
24pub trait UCSigner<S>: DalekSigner<S> + Sync + Send {
25    /// Signs a message for a protocol, uniquely identified by the triple (round, protocol tag,
26    /// session ID) to avoid replay attacks.
27    fn sign_with(&self, message: &[u8], id: &MessageId) -> Result<S, PrimitiveError> {
28        let round = id.1.to_le_bytes();
29        let message_with_id: Vec<u8> = chain!(message, &id.0, &round, id.2).copied().collect();
30        let signature = self
31            .try_sign(&message_with_id)
32            .map_err(|e| VerificationError::InvalidSignature(e.to_string()))?;
33        Ok(signature)
34    }
35}
36
37/// Verifier that verifies message signatures with metadata (round, protocol tag and session ID)
38/// to avoid replay attacks in UC protocols.
39pub trait UCVerifier<S>: DalekVerifier<S> + Sync + Send {
40    /// Verifies a signature for a protocol, uniquely identified by the triple (round, protocol tag,
41    /// session ID) to avoid replay attacks.
42    fn verify_with(
43        &self,
44        message: &[u8],
45        signature: &S,
46        &id: &MessageId,
47    ) -> Result<(), PrimitiveError> {
48        let round = id.1.to_le_bytes();
49        let message_with_id: Vec<u8> = chain!(message, &id.0, &round, id.2).copied().collect();
50        self.verify(&message_with_id, signature)
51            .map_err(|e| VerificationError::InvalidSignature(e.to_string()))?;
52        Ok(())
53    }
54}
55
56impl<S, T: DalekSigner<S> + Sync + Send> UCSigner<S> for T {}
57impl<S, T: DalekVerifier<S> + Sync + Send> UCVerifier<S> for T {}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::{
63        random::{self, Random},
64        types::SessionId,
65    };
66
67    #[test]
68    fn test_sign_protocol_message() {
69        let mut rng = random::test_rng();
70        let signing_key = SigningKey::generate(&mut rng);
71        let message = b"Hello, protocol!";
72        let protocol_id: &'static [u8] = &[2, 1];
73        let message_id = (SessionId::random(&mut rng), 1, protocol_id);
74
75        let signature = signing_key.sign_with(message, &message_id).unwrap();
76        assert!(signing_key
77            .verify_with(message, &signature, &message_id)
78            .is_ok());
79    }
80}