Skip to main content

rings_core/message/protocols/
verify.rs

1#![warn(missing_docs)]
2
3//! Implementation of Message Verification.
4
5use serde::Deserialize;
6use serde::Serialize;
7
8use crate::consts::DEFAULT_TTL_MS;
9use crate::consts::MAX_TTL_MS;
10use crate::consts::TS_OFFSET_TOLERANCE_MS;
11use crate::dht::Did;
12use crate::error::Result;
13use crate::session::Session;
14use crate::session::SessionSk;
15use crate::utils::get_epoch_ms;
16
17/// Message Verification is based on session, and sig.
18/// it also included ttl time and created ts.
19#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
20pub struct MessageVerification {
21    /// The [Session] of the [SessionSk]. Used to identify a sender and verify the signature.
22    pub session: Session,
23    /// The time to live of the message in milliseconds.
24    pub ttl_ms: u64,
25    /// The timestamp of the message in milliseconds.
26    pub ts_ms: u128,
27    /// The signature of the message. Signed by [SessionSk]. Can be verified by [Session].
28    pub sig: Vec<u8>,
29}
30
31fn pack_msg(data: &[u8], ts_ms: u128, ttl_ms: u64) -> Vec<u8> {
32    let mut msg = vec![];
33
34    msg.extend_from_slice(&ts_ms.to_be_bytes());
35    msg.extend_from_slice(&ttl_ms.to_be_bytes());
36    msg.extend_from_slice(data);
37
38    msg
39}
40
41impl MessageVerification {
42    /// Create a new MessageVerification. Should provide the data and the [SessionSk].
43    pub fn new(data: &[u8], session_sk: &SessionSk) -> Result<Self> {
44        let ts_ms = get_epoch_ms();
45        let ttl_ms = DEFAULT_TTL_MS;
46        let msg = pack_msg(data, ts_ms, ttl_ms);
47        let verification = MessageVerification {
48            session: session_sk.session(),
49            sig: session_sk.sign(&msg)?,
50            ttl_ms,
51            ts_ms,
52        };
53        Ok(verification)
54    }
55
56    /// Verify a MessageVerification
57    pub fn verify(&self, data: &[u8]) -> bool {
58        let msg = pack_msg(data, self.ts_ms, self.ttl_ms);
59
60        self.session
61            .verify(&msg, &self.sig)
62            .map_err(|e| {
63                tracing::warn!("MessageVerification verify failed: {:?}", e);
64            })
65            .is_ok()
66    }
67}
68
69/// This trait helps a struct with `MessageVerification` field to `verify` itself.
70/// It also provides a `signer` method to let receiver know who sent the message.
71pub trait MessageVerificationExt {
72    /// Give the data to be verified.
73    fn verification_data(&self) -> Result<Vec<u8>>;
74
75    /// Give the verification field for verifying.
76    fn verification(&self) -> &MessageVerification;
77
78    /// Checks whether the message is expired.
79    fn is_expired(&self) -> bool {
80        if self.verification().ttl_ms > MAX_TTL_MS {
81            return false;
82        }
83
84        let now = get_epoch_ms();
85
86        if self.verification().ts_ms - TS_OFFSET_TOLERANCE_MS > now {
87            return false;
88        }
89
90        now > self.verification().ts_ms + self.verification().ttl_ms as u128
91    }
92
93    /// Verifies that the message is not expired and that the signature is valid.
94    fn verify(&self) -> bool {
95        if self.is_expired() {
96            tracing::warn!("message expired");
97            return false;
98        }
99
100        let Ok(data) = self.verification_data() else {
101            tracing::warn!("MessageVerificationExt verify get verification_data failed");
102            return false;
103        };
104
105        self.verification().verify(&data)
106    }
107
108    /// Get signer did from verification.
109    fn signer(&self) -> Did {
110        self.verification().session.account_did()
111    }
112}