umsh_node/
channel.rs

1use alloc::string::String;
2
3use umsh_core::{ChannelId, ChannelKey};
4use umsh_crypto::{
5    ChannelNameError, CryptoEngine,
6    software::{SoftwareAes, SoftwareSha256},
7};
8
9/// A channel descriptor — holds the key, derived ID, and display name.
10///
11/// Not bound to any node. Create via [`Channel::named`] (key derived from name)
12/// or [`Channel::private`] (key independent of name).
13#[derive(Clone)]
14pub struct Channel {
15    key: ChannelKey,
16    channel_id: ChannelId,
17    name: String,
18}
19
20impl core::fmt::Debug for Channel {
21    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22        f.debug_struct("Channel")
23            .field("channel_id", &self.channel_id)
24            .field("name", &self.name)
25            .finish()
26    }
27}
28
29impl Channel {
30    /// Create a named channel whose key is derived from the name.
31    ///
32    /// Uses the same derivation as the MAC layer's `add_named_channel`: the
33    /// name is canonicalized (ASCII lowercase fold) before derivation, so
34    /// `Public` and `public` are the same channel. The display name keeps the
35    /// caller's original casing. Fails if the name is non-ASCII or too long.
36    pub fn named(name: &str) -> Result<Self, ChannelNameError> {
37        let crypto = CryptoEngine::new(SoftwareAes, SoftwareSha256);
38        let key = crypto.derive_named_channel_key(name)?;
39        let channel_id = crypto.derive_channel_id(&key);
40
41        Ok(Self {
42            key,
43            channel_id,
44            name: String::from(name),
45        })
46    }
47
48    /// Create a private channel with an explicit key.
49    ///
50    /// The name is for display only — it does not affect the key.
51    pub fn private(key: ChannelKey, name: &str) -> Self {
52        let crypto = CryptoEngine::new(SoftwareAes, SoftwareSha256);
53        let channel_id = crypto.derive_channel_id(&key);
54
55        Self {
56            key,
57            channel_id,
58            name: String::from(name),
59        }
60    }
61
62    /// The channel's display name.
63    pub fn name(&self) -> &str {
64        &self.name
65    }
66
67    /// The derived 2-byte channel ID (used for routing/filtering).
68    pub fn channel_id(&self) -> &ChannelId {
69        &self.channel_id
70    }
71
72    /// The full symmetric channel key.
73    pub fn key(&self) -> &ChannelKey {
74        &self.key
75    }
76}
77
78impl PartialEq for Channel {
79    fn eq(&self, other: &Self) -> bool {
80        self.key.0 == other.key.0
81    }
82}
83
84impl Eq for Channel {}