Skip to main content

elara_diffusion/
authority.rs

1//! Authority Model - Who can mutate what state
2//!
3//! In ELARA, authority determines who can change specific state atoms.
4//! This is cryptographically enforced, not just policy.
5
6use elara_core::NodeId;
7use std::collections::HashSet;
8
9/// Authority level for a state atom
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum AuthorityLevel {
12    /// Only one node can mutate (e.g., broadcaster's visual state)
13    Exclusive,
14    /// Multiple nodes can mutate with coordination (e.g., shared whiteboard)
15    Shared,
16    /// Any interested node can mutate (e.g., chat messages)
17    Open,
18    /// No one can mutate (read-only, historical)
19    Frozen,
20}
21
22/// Authority proof - cryptographic evidence of mutation rights
23#[derive(Debug, Clone)]
24pub struct AuthorityProof {
25    /// The node claiming authority
26    pub claimer: NodeId,
27    /// The state being claimed
28    pub state_id: u64,
29    /// Signature over (claimer, state_id, timestamp)
30    pub signature: Vec<u8>,
31    /// Timestamp of the claim
32    pub timestamp: i64,
33}
34
35impl AuthorityProof {
36    /// Create a new authority proof (signature would be computed externally)
37    pub fn new(claimer: NodeId, state_id: u64, timestamp: i64) -> Self {
38        Self {
39            claimer,
40            state_id,
41            signature: Vec::new(), // Would be filled by crypto layer
42            timestamp,
43        }
44    }
45
46    /// Check if this proof is for a specific state
47    pub fn is_for_state(&self, state_id: u64) -> bool {
48        self.state_id == state_id
49    }
50}
51
52/// Authority set - who has authority over a state
53#[derive(Debug, Clone)]
54pub struct AuthoritySet {
55    /// The state this authority set governs
56    pub state_id: u64,
57
58    /// Authority level
59    pub level: AuthorityLevel,
60
61    /// Nodes with authority (empty for Open level)
62    pub authorities: HashSet<NodeId>,
63
64    /// Delegation chain (who granted authority to whom)
65    pub delegations: Vec<(NodeId, NodeId)>,
66}
67
68impl AuthoritySet {
69    /// Create an exclusive authority set (single owner)
70    pub fn exclusive(state_id: u64, owner: NodeId) -> Self {
71        let mut authorities = HashSet::new();
72        authorities.insert(owner);
73
74        Self {
75            state_id,
76            level: AuthorityLevel::Exclusive,
77            authorities,
78            delegations: Vec::new(),
79        }
80    }
81
82    /// Create a shared authority set
83    pub fn shared(state_id: u64, owners: Vec<NodeId>) -> Self {
84        Self {
85            state_id,
86            level: AuthorityLevel::Shared,
87            authorities: owners.into_iter().collect(),
88            delegations: Vec::new(),
89        }
90    }
91
92    /// Create an open authority set (anyone can mutate)
93    pub fn open(state_id: u64) -> Self {
94        Self {
95            state_id,
96            level: AuthorityLevel::Open,
97            authorities: HashSet::new(),
98            delegations: Vec::new(),
99        }
100    }
101
102    /// Create a frozen authority set (no mutations)
103    pub fn frozen(state_id: u64) -> Self {
104        Self {
105            state_id,
106            level: AuthorityLevel::Frozen,
107            authorities: HashSet::new(),
108            delegations: Vec::new(),
109        }
110    }
111
112    /// Check if a node has authority
113    pub fn has_authority(&self, node: NodeId) -> bool {
114        match self.level {
115            AuthorityLevel::Exclusive | AuthorityLevel::Shared => self.authorities.contains(&node),
116            AuthorityLevel::Open => true,
117            AuthorityLevel::Frozen => false,
118        }
119    }
120
121    /// Add authority for a node (for shared level)
122    pub fn grant(&mut self, granter: NodeId, grantee: NodeId) -> bool {
123        if self.level != AuthorityLevel::Shared {
124            return false;
125        }
126
127        if !self.authorities.contains(&granter) {
128            return false;
129        }
130
131        self.authorities.insert(grantee);
132        self.delegations.push((granter, grantee));
133        true
134    }
135
136    /// Remove authority from a node
137    pub fn revoke(&mut self, revoker: NodeId, revokee: NodeId) -> bool {
138        if self.level != AuthorityLevel::Shared {
139            return false;
140        }
141
142        if !self.authorities.contains(&revoker) {
143            return false;
144        }
145
146        // Can't revoke from yourself if you're the last one
147        if self.authorities.len() == 1 && self.authorities.contains(&revokee) {
148            return false;
149        }
150
151        self.authorities.remove(&revokee);
152        true
153    }
154}
155
156/// Livestream authority model
157#[derive(Debug, Clone)]
158pub struct LivestreamAuthority {
159    /// The broadcaster (exclusive authority over visual/audio)
160    pub broadcaster: NodeId,
161
162    /// Visual state authority
163    pub visual_authority: AuthoritySet,
164
165    /// Audio state authority
166    pub audio_authority: AuthoritySet,
167
168    /// Chat state authority (open to all viewers)
169    pub chat_authority: AuthoritySet,
170
171    /// Moderators (can mute viewers in chat)
172    pub moderators: HashSet<NodeId>,
173}
174
175impl LivestreamAuthority {
176    /// Create a new livestream authority model
177    pub fn new(broadcaster: NodeId, stream_id: u64) -> Self {
178        Self {
179            broadcaster,
180            visual_authority: AuthoritySet::exclusive(stream_id, broadcaster),
181            audio_authority: AuthoritySet::exclusive(stream_id + 1, broadcaster),
182            chat_authority: AuthoritySet::open(stream_id + 2),
183            moderators: HashSet::new(),
184        }
185    }
186
187    /// Add a moderator
188    pub fn add_moderator(&mut self, moderator: NodeId) {
189        self.moderators.insert(moderator);
190    }
191
192    /// Check if a node can mutate visual state
193    pub fn can_mutate_visual(&self, node: NodeId) -> bool {
194        self.visual_authority.has_authority(node)
195    }
196
197    /// Check if a node can mutate audio state
198    pub fn can_mutate_audio(&self, node: NodeId) -> bool {
199        self.audio_authority.has_authority(node)
200    }
201
202    /// Check if a node can send chat
203    pub fn can_chat(&self, node: NodeId) -> bool {
204        self.chat_authority.has_authority(node)
205    }
206
207    /// Check if a node is a moderator
208    pub fn is_moderator(&self, node: NodeId) -> bool {
209        self.moderators.contains(&node) || node == self.broadcaster
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    #[test]
218    fn test_exclusive_authority() {
219        let owner = NodeId::new(1);
220        let other = NodeId::new(2);
221        let auth = AuthoritySet::exclusive(100, owner);
222
223        assert!(auth.has_authority(owner));
224        assert!(!auth.has_authority(other));
225    }
226
227    #[test]
228    fn test_shared_authority() {
229        let node1 = NodeId::new(1);
230        let node2 = NodeId::new(2);
231        let node3 = NodeId::new(3);
232
233        let mut auth = AuthoritySet::shared(100, vec![node1, node2]);
234
235        assert!(auth.has_authority(node1));
236        assert!(auth.has_authority(node2));
237        assert!(!auth.has_authority(node3));
238
239        // Grant authority to node3
240        assert!(auth.grant(node1, node3));
241        assert!(auth.has_authority(node3));
242    }
243
244    #[test]
245    fn test_open_authority() {
246        let auth = AuthoritySet::open(100);
247
248        assert!(auth.has_authority(NodeId::new(1)));
249        assert!(auth.has_authority(NodeId::new(999)));
250    }
251
252    #[test]
253    fn test_frozen_authority() {
254        let auth = AuthoritySet::frozen(100);
255
256        assert!(!auth.has_authority(NodeId::new(1)));
257        assert!(!auth.has_authority(NodeId::new(999)));
258    }
259
260    #[test]
261    fn test_livestream_authority() {
262        let broadcaster = NodeId::new(1);
263        let viewer = NodeId::new(2);
264
265        let auth = LivestreamAuthority::new(broadcaster, 1000);
266
267        assert!(auth.can_mutate_visual(broadcaster));
268        assert!(!auth.can_mutate_visual(viewer));
269
270        assert!(auth.can_mutate_audio(broadcaster));
271        assert!(!auth.can_mutate_audio(viewer));
272
273        // Both can chat
274        assert!(auth.can_chat(broadcaster));
275        assert!(auth.can_chat(viewer));
276    }
277}