oasis_core_runtime/common/crypto/mrae/
nonce.rs

1//! Nonce utility used to ensure nonces are safely incremented.
2use std::ops::Deref;
3
4use anyhow::{anyhow, Result};
5use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
6use rand::{rngs::OsRng, Rng};
7
8/// Size of the nonce in bytes.
9pub use super::deoxysii::NONCE_SIZE;
10/// Size of tag portion of the nonce in bytes. These bytes will never update.
11pub const TAG_SIZE: usize = 11;
12
13/// 120 bit nonce with a 88 bit tag and 32 bit counter. If the counter exceeds
14/// 32 bits, then the nonce is no longer valid and must be refreshed with a new
15/// random nonce. It is expected that all 128 bits are given randomly. However,
16/// the last 32 counting bits may wrap around to ensure 2^32 counts may be used
17/// per nonce.
18#[derive(Debug, Clone)]
19pub struct Nonce {
20    /// The current value of the nonce, from which we may increment.
21    current_value: [u8; NONCE_SIZE],
22    /// The initial value of the nonce, used to ensure we never allow the nonce
23    /// to be the same again (after incrementing 2^32 times).
24    start_value: [u8; NONCE_SIZE],
25}
26
27impl Nonce {
28    /// Create a new nonce.
29    pub fn new(start_value: [u8; NONCE_SIZE]) -> Self {
30        Nonce {
31            current_value: start_value,
32            start_value,
33        }
34    }
35
36    /// Generate a random nonce.
37    pub fn generate() -> Self {
38        let mut rng = OsRng {};
39        let mut start_value = [0u8; NONCE_SIZE];
40        rng.fill(&mut start_value);
41
42        Self::new(start_value)
43    }
44
45    /// Adds one to the nonce, affecting only the last 32 counting bits.
46    /// Returns an error iff we've exceeded our nonce's counter capacity, i.e.,
47    /// we've incremented 2^32 times. In this case, the Nonce remains unchanged,
48    /// and all subsequent calls to this method will return an Error.
49    pub fn increment(&mut self) -> Result<()> {
50        // Extract the current counter out of the nonce.
51        let mut counter_array = &self.current_value[TAG_SIZE..];
52        // Increment the count and wrap to 0 if necessary.
53        let new_counter: u32 = {
54            let mut counter = counter_array.read_u32::<BigEndian>().unwrap();
55            // If about to overflow wrap around to 0.
56            #[allow(clippy::nonminimal_bool)]
57            if counter == !0u32 {
58                counter = 0;
59            } else {
60                counter += 1;
61            }
62            counter
63        };
64        // Merge this new counter back into the nonce.
65        let new_value: [u8; NONCE_SIZE] = {
66            let mut new_value_vec = self.current_value[..TAG_SIZE].to_vec();
67            new_value_vec.write_u32::<BigEndian>(new_counter).unwrap();
68
69            assert!(new_value_vec.len() == NONCE_SIZE);
70
71            let mut new_value = [0; NONCE_SIZE];
72            new_value.copy_from_slice(&new_value_vec);
73            new_value
74        };
75        // If we've exhausted all 2^32 counters, then error.
76        if new_value == self.start_value {
77            return Err(anyhow!(
78                "This nonce has been exhausted, and a new one must be created",
79            ));
80        }
81        // Update is valid, so mutate.
82        self.current_value = new_value;
83        // Success.
84        Ok(())
85    }
86}
87
88impl Deref for Nonce {
89    type Target = [u8; NONCE_SIZE];
90
91    fn deref(&self) -> &Self::Target {
92        &self.current_value
93    }
94}
95
96#[cfg(test)]
97mod tests {
98
99    use super::*;
100
101    #[test]
102    fn test_increment_zero() {
103        let inner = [0; 15];
104        let mut nonce = Nonce::new(inner);
105        nonce.increment().unwrap();
106        let mut expected = [0; 15];
107        expected[14] = 1;
108        assert_eq!(nonce.to_vec(), expected.to_vec());
109    }
110
111    #[test]
112    fn test_increment_one() {
113        let mut start_value = [0; 15];
114        start_value[14] = 1;
115        let mut nonce = Nonce::new(start_value);
116        nonce.increment().unwrap();
117        let mut expected = [0; 15];
118        expected[14] = 2;
119
120        assert_eq!(nonce.to_vec(), expected.to_vec());
121    }
122
123    #[test]
124    fn test_increment_carry() {
125        let start_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255];
126        let mut nonce = Nonce::new(start_value);
127        nonce.increment().unwrap();
128        let expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0];
129        assert_eq!(nonce.to_vec(), expected.to_vec());
130    }
131
132    #[test]
133    fn test_increment_overflow() {
134        let start_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255];
135        let mut nonce = Nonce::new(start_value);
136        nonce.increment().unwrap();
137        let expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
138        assert_eq!(nonce.to_vec(), expected.to_vec());
139    }
140
141    #[test]
142    fn test_increment_exhaustion() {
143        let start_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255];
144        let current_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 254];
145        let mut nonce = Nonce {
146            start_value,
147            current_value,
148        };
149        assert_eq!(nonce.increment().is_err(), true);
150        // Try again.
151        assert_eq!(nonce.increment().is_err(), true);
152    }
153
154    #[test]
155    fn test_double_increment_exhaustion() {
156        let start_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255];
157        let current_value = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 253];
158        let mut nonce = Nonce {
159            start_value,
160            current_value,
161        };
162        let first_expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 254];
163        nonce.increment().unwrap();
164        assert_eq!(nonce.to_vec(), first_expected.to_vec());
165        assert_eq!(nonce.increment().is_err(), true);
166    }
167}