1use crypto_bigint::Encoding;
2
3use crypto_bigint::U128;
4
5#[cfg(feature = "zeroize")]
6use zeroize::{Zeroize, ZeroizeOnDrop};
7
8#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))]
10pub struct Nonce12 {
11 iv: U128,
12 seq_id: u64,
13}
14
15impl Nonce12 {
16 #[inline]
18 pub fn from_ks_iv(i: &[u8; 12]) -> Self {
19 let iv = U128::from_be_bytes([
20 0, 0, 0, 0, i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7], i[8], i[9], i[10], i[11],
21 ]);
22 let seq_id = 0u64;
23
24 Self { iv, seq_id }
25 }
26 #[inline]
28 pub fn use_and_incr(&mut self) -> Option<[u8; 12]> {
29 let seq_id = U128::from_u64(self.seq_id);
30 let nonce_u128 = self.iv.wrapping_xor(&seq_id);
31 let b: [u8; 16] = nonce_u128.to_be_bytes();
32
33 if self.seq_id == u64::MAX {
34 return None;
35 }
36
37 self.seq_id += 1;
38
39 Some([
40 b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15],
41 ])
42 }
43 #[inline]
45 #[cfg(test)]
46 pub fn hazmat_fast_forward_with_incr(&mut self, fast_forward: u64) -> Option<[u8; 12]> {
47 self.seq_id = fast_forward;
48 self.use_and_incr()
49 }
50}
51
52#[cfg(test)]
53mod test {
54
55 use super::*;
56 use hex_literal::hex;
57
58 #[test]
59 fn cur() {
60 let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
61 let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
62 let cur = running_nonce.use_and_incr();
63
64 assert_eq!(cur, Some(iv_bytes));
65 }
66
67 #[test]
68 fn packet_seq_1() {
69 let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
70 let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
71 let _cur = running_nonce.use_and_incr();
72 let seq_1 = running_nonce.use_and_incr();
73
74 assert_eq!(seq_1, Some(hex!("6fac81d4f2c3bebe02b8b374")));
75 }
76
77 #[test]
79 fn packet_seq_max() {
80 let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
81 let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
82 let cur = running_nonce.hazmat_fast_forward_with_incr(u64::MAX);
83
84 assert_eq!(cur, None);
85 }
86}