1use serde::{Deserialize, Serialize};
8
9use super::ciphersuite::Ciphersuite;
10use super::transport::MultiDeviceTransport;
11use crate::error::NoiseProtocolError;
12use crate::symmetric_key::SymmetricKey;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct PersistentTransportState {
24 ciphersuite: Ciphersuite,
26 send_key: SymmetricKey,
28 recv_key: SymmetricKey,
30 send_rekey_counter: u64,
32 recv_rekey_counter: u64,
34 last_rekeyed_time: u64,
36 rekey_interval: u64,
38}
39
40impl From<&MultiDeviceTransport> for PersistentTransportState {
41 fn from(transport: &MultiDeviceTransport) -> Self {
42 let (send_key, recv_key) = transport.keys();
43
44 Self {
45 ciphersuite: transport.ciphersuite(),
46 send_key,
47 recv_key,
48 send_rekey_counter: transport.send_rekey_counter(),
49 recv_rekey_counter: transport.recv_rekey_counter(),
50 last_rekeyed_time: transport.last_rekeyed_time(),
51 rekey_interval: transport.rekey_interval(),
52 }
53 }
54}
55
56impl From<PersistentTransportState> for MultiDeviceTransport {
57 fn from(state: PersistentTransportState) -> Self {
58 MultiDeviceTransport::restore_from_state(
59 state.ciphersuite,
60 state.send_key,
61 state.recv_key,
62 state.send_rekey_counter,
63 state.recv_rekey_counter,
64 state.last_rekeyed_time,
65 state.rekey_interval,
66 )
67 }
68}
69
70impl PersistentTransportState {
71 pub fn to_bytes(&self) -> Result<Vec<u8>, NoiseProtocolError> {
73 let mut bytes = Vec::new();
74 ciborium::ser::into_writer(self, &mut bytes)
75 .map_err(|_| NoiseProtocolError::CborEncodeFailed)?;
76 Ok(bytes)
77 }
78
79 pub fn from_bytes(bytes: &[u8]) -> Result<Self, NoiseProtocolError> {
81 ciborium::de::from_reader(bytes).map_err(|_| NoiseProtocolError::CborDecodeFailed)
82 }
83}
84
85impl MultiDeviceTransport {
87 pub fn save_state(&self) -> Result<Vec<u8>, NoiseProtocolError> {
89 let persistent: PersistentTransportState = self.into();
90 persistent.to_bytes()
91 }
92
93 pub fn restore_state(bytes: &[u8]) -> Result<Self, NoiseProtocolError> {
95 let persistent = PersistentTransportState::from_bytes(bytes)?;
96 Ok(persistent.into())
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::symmetric_key::{SYMMETRIC_KEY_TEST_VECTOR_1, SYMMETRIC_KEY_TEST_VECTOR_2};
104
105 fn setup_sender_receiver() -> (MultiDeviceTransport, MultiDeviceTransport) {
106 let send_key = SYMMETRIC_KEY_TEST_VECTOR_1;
107 let recv_key = SYMMETRIC_KEY_TEST_VECTOR_2;
108
109 let sender_send_key = send_key.clone();
111 let sender_recv_key = recv_key.clone();
112 let receiver_send_key = recv_key.clone();
113 let receiver_recv_key = send_key.clone();
114
115 let sender = MultiDeviceTransport::new(
116 Ciphersuite::ClassicalNNpsk2_25519_XChaCha20Poly1035,
117 sender_send_key,
118 sender_recv_key,
119 );
120
121 let receiver = MultiDeviceTransport::new(
122 Ciphersuite::ClassicalNNpsk2_25519_XChaCha20Poly1035,
123 receiver_send_key,
124 receiver_recv_key,
125 );
126
127 (sender, receiver)
128 }
129
130 #[test]
131 fn test_persistent_state_roundtrip() {
132 let (mut sender, _) = setup_sender_receiver();
133 sender.set_send_rekey_counter(42);
134 sender.set_recv_rekey_counter(43);
135 sender.set_last_rekeyed_time(1000);
136
137 let persistent: PersistentTransportState = (&sender).into();
139 let restored: MultiDeviceTransport = persistent.into();
140
141 assert_eq!(
142 restored.ciphersuite(),
143 Ciphersuite::ClassicalNNpsk2_25519_XChaCha20Poly1035
144 );
145 assert_eq!(restored.send_rekey_counter(), 42);
146 assert_eq!(restored.recv_rekey_counter(), 43);
147 assert_eq!(restored.last_rekeyed_time(), 1000);
148
149 assert_eq!(sender.send_key(), restored.send_key());
150 assert_eq!(sender.recv_key(), restored.recv_key());
151 }
152}