nomad_protocol/crypto/
nonce.rs1use crate::core::{AEAD_NONCE_SIZE, NONCE_DIR_INITIATOR, NONCE_DIR_RESPONDER};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum Direction {
14 InitiatorToResponder,
16 ResponderToInitiator,
18}
19
20impl Direction {
21 pub fn as_byte(self) -> u8 {
23 match self {
24 Direction::InitiatorToResponder => NONCE_DIR_INITIATOR,
25 Direction::ResponderToInitiator => NONCE_DIR_RESPONDER,
26 }
27 }
28
29 pub fn opposite(self) -> Self {
31 match self {
32 Direction::InitiatorToResponder => Direction::ResponderToInitiator,
33 Direction::ResponderToInitiator => Direction::InitiatorToResponder,
34 }
35 }
36}
37
38pub fn construct_nonce(epoch: u32, direction: Direction, counter: u64) -> [u8; AEAD_NONCE_SIZE] {
50 let mut nonce = [0u8; AEAD_NONCE_SIZE];
51
52 nonce[0..4].copy_from_slice(&epoch.to_le_bytes());
54
55 nonce[4] = direction.as_byte();
57
58 nonce[16..24].copy_from_slice(&counter.to_le_bytes());
62
63 nonce
64}
65
66pub fn parse_nonce(nonce: &[u8; AEAD_NONCE_SIZE]) -> (u32, Direction, u64) {
70 let epoch = u32::from_le_bytes([nonce[0], nonce[1], nonce[2], nonce[3]]);
71
72 let direction = if nonce[4] == NONCE_DIR_INITIATOR {
73 Direction::InitiatorToResponder
74 } else {
75 Direction::ResponderToInitiator
76 };
77
78 let counter = u64::from_le_bytes([
79 nonce[16], nonce[17], nonce[18], nonce[19], nonce[20], nonce[21], nonce[22], nonce[23],
80 ]);
81
82 (epoch, direction, counter)
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_nonce_construction() {
91 let nonce = construct_nonce(1, Direction::InitiatorToResponder, 42);
92
93 assert_eq!(nonce.len(), AEAD_NONCE_SIZE);
94
95 assert_eq!(&nonce[0..4], &1u32.to_le_bytes());
97
98 assert_eq!(nonce[4], 0x00);
100
101 assert_eq!(&nonce[5..16], &[0u8; 11]);
103
104 assert_eq!(&nonce[16..24], &42u64.to_le_bytes());
106 }
107
108 #[test]
109 fn test_nonce_roundtrip() {
110 let epoch = 0x12345678;
111 let direction = Direction::ResponderToInitiator;
112 let counter = 0xDEADBEEFCAFEBABE;
113
114 let nonce = construct_nonce(epoch, direction, counter);
115 let (parsed_epoch, parsed_dir, parsed_counter) = parse_nonce(&nonce);
116
117 assert_eq!(parsed_epoch, epoch);
118 assert_eq!(parsed_dir, direction);
119 assert_eq!(parsed_counter, counter);
120 }
121
122 #[test]
123 fn test_direction_opposite() {
124 assert_eq!(
125 Direction::InitiatorToResponder.opposite(),
126 Direction::ResponderToInitiator
127 );
128 assert_eq!(
129 Direction::ResponderToInitiator.opposite(),
130 Direction::InitiatorToResponder
131 );
132 }
133
134 #[test]
135 fn test_direction_bytes() {
136 assert_eq!(Direction::InitiatorToResponder.as_byte(), 0x00);
137 assert_eq!(Direction::ResponderToInitiator.as_byte(), 0x01);
138 }
139}