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