Skip to main content

hap_ble/
broadcast_state.rs

1//! Persistable HAP-BLE broadcast material: the broadcast key + last-seen GSN.
2//! Returned from pairing and accepted back on reconnect so a caller can resume
3//! encrypted-broadcast decryption across process restarts (see the controller).
4
5use hap_crypto::BroadcastKey;
6
7/// Broadcast-notification material for one accessory, persistable by the caller.
8/// Holds a secret ([`BroadcastKey`] is zeroized on drop).
9#[derive(Clone)]
10pub struct BleBroadcastState {
11    /// The broadcast decryption key.
12    pub key: BroadcastKey,
13    /// The last Global State Number observed/decrypted (0 when freshly minted).
14    pub gsn: u16,
15}
16
17#[cfg(test)]
18#[allow(clippy::unwrap_used)]
19mod tests {
20    use super::*;
21
22    #[test]
23    fn new_state_has_zero_gsn_and_key_roundtrips() {
24        let raw = [0x42u8; 32];
25        let state = BleBroadcastState {
26            key: BroadcastKey::from_bytes(raw),
27            gsn: 0,
28        };
29        assert_eq!(state.gsn, 0);
30        assert_eq!(state.key.as_bytes(), &raw);
31    }
32
33    #[test]
34    fn gsn_can_be_updated() {
35        let state = BleBroadcastState {
36            key: BroadcastKey::from_bytes([0u8; 32]),
37            gsn: 7,
38        };
39        assert_eq!(state.gsn, 7);
40    }
41
42    #[test]
43    fn clone_preserves_key_and_gsn() {
44        let raw = [0x11u8; 32];
45        let state = BleBroadcastState {
46            key: BroadcastKey::from_bytes(raw),
47            gsn: 99,
48        };
49        let cloned = state.clone();
50        assert_eq!(cloned.gsn, 99);
51        assert_eq!(cloned.key.as_bytes(), &raw);
52    }
53}