mls_rs/tree_kem/
lifetime.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5use crate::{client::MlsError, time::MlsTime};
6use core::time::Duration;
7use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
8
9#[derive(Clone, Debug, PartialEq, Eq, MlsSize, MlsEncode, MlsDecode, Default)]
10#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[non_exhaustive]
13pub struct Lifetime {
14    pub not_before: MlsTime,
15    pub not_after: MlsTime,
16}
17
18impl Lifetime {
19    pub fn new(not_before: MlsTime, not_after: MlsTime) -> Lifetime {
20        Lifetime {
21            not_before,
22            not_after,
23        }
24    }
25
26    pub fn seconds(s: u64, maybe_not_before: Option<MlsTime>) -> Result<Self, MlsError> {
27        #[cfg(feature = "std")]
28        let not_before = MlsTime::now();
29        #[cfg(not(feature = "std"))]
30        // There is no clock on no_std, this is here just so that we can run tests.
31        let not_before = MlsTime::from(3600u64);
32
33        let not_before = if let Some(not_before_time) = maybe_not_before {
34            not_before_time
35        } else {
36            not_before
37        };
38
39        let not_after = MlsTime::from(
40            not_before
41                .seconds_since_epoch()
42                .checked_add(s)
43                .ok_or(MlsError::TimeOverflow)?,
44        );
45
46        Ok(Lifetime {
47            // Subtract 1 hour to address time difference between machines
48            not_before: not_before - Duration::from_secs(3600),
49            not_after,
50        })
51    }
52
53    pub fn days(d: u32, maybe_not_before: Option<MlsTime>) -> Result<Self, MlsError> {
54        Self::seconds((d * 86400) as u64, maybe_not_before)
55    }
56
57    pub fn years(y: u8, maybe_not_before: Option<MlsTime>) -> Result<Self, MlsError> {
58        Self::days(365 * y as u32, maybe_not_before)
59    }
60
61    pub(crate) fn within_lifetime(&self, time: MlsTime) -> bool {
62        self.not_before <= time && time <= self.not_after
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use core::time::Duration;
69
70    use super::*;
71    use assert_matches::assert_matches;
72
73    const HOUR: Duration = Duration::from_secs(3600);
74    const DAY: Duration = Duration::from_secs(24 * 3600);
75
76    #[test]
77    fn test_lifetime_overflow() {
78        let res = Lifetime::seconds(u64::MAX, None);
79        assert_matches!(res, Err(MlsError::TimeOverflow))
80    }
81
82    #[test]
83    fn test_seconds() {
84        let seconds = 10;
85        let lifetime = Lifetime::seconds(seconds, None).unwrap();
86        assert_eq!(
87            lifetime.not_after - lifetime.not_before,
88            Duration::from_secs(3610)
89        );
90    }
91
92    #[test]
93    fn test_days() {
94        let days = 2;
95        let lifetime = Lifetime::days(days, None).unwrap();
96
97        assert_eq!(
98            lifetime.not_after - lifetime.not_before,
99            days * DAY + 1 * HOUR
100        );
101    }
102
103    #[test]
104    fn test_years() {
105        let years = 2;
106        let lifetime = Lifetime::years(years, None).unwrap();
107
108        assert_eq!(
109            lifetime.not_after - lifetime.not_before,
110            365 * DAY * (years as u32) + 1 * HOUR
111        );
112    }
113
114    #[test]
115    fn test_bounds() {
116        let test_lifetime = Lifetime {
117            not_before: MlsTime::from(5),
118            not_after: MlsTime::from(10),
119        };
120
121        assert!(!test_lifetime
122            .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(4))));
123
124        assert!(!test_lifetime
125            .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(11))));
126
127        assert!(test_lifetime
128            .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(5))));
129
130        assert!(test_lifetime
131            .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(10))));
132
133        assert!(test_lifetime
134            .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(6))));
135    }
136}