Skip to main content

aura_core/effects/
amp.rs

1//! AMP channel lifecycle effect traits (Layer 1 interface)
2//!
3//! This defines the interface for creating/closing AMP channels and sending
4//! messages. Implementations live in higher layers (protocol/runtime). This
5//! module must remain interface-only (no state or OS access).
6
7use crate::types::identifiers::{AuthorityId, ChannelId, ContextId};
8use crate::Hash32;
9use async_trait::async_trait;
10use serde::{Deserialize, Serialize};
11
12pub const MAX_AMP_CIPHERTEXT_BYTES: usize = 65_536;
13pub const MAX_AMP_PLAINTEXT_BYTES: usize = 65_536;
14
15/// AMP channel error
16#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone, PartialEq, Eq)]
17pub enum AmpChannelError {
18    #[error("channel not found")]
19    NotFound,
20    #[error("context not found")]
21    ContextNotFound,
22    #[error("invalid state: {0}")]
23    InvalidState(String),
24    #[error("authorization failed")]
25    Unauthorized,
26    #[error("storage error: {0}")]
27    Storage(String),
28    #[error("crypto error: {0}")]
29    Crypto(String),
30    #[error("internal error: {0}")]
31    Internal(String),
32}
33
34impl crate::ProtocolErrorCode for AmpChannelError {
35    fn code(&self) -> &'static str {
36        match self {
37            AmpChannelError::NotFound => "not_found",
38            AmpChannelError::ContextNotFound => "not_found",
39            AmpChannelError::InvalidState(_) => "invalid_state",
40            AmpChannelError::Unauthorized => "unauthorized",
41            AmpChannelError::Storage(_) => "storage",
42            AmpChannelError::Crypto(_) => "crypto",
43            AmpChannelError::Internal(_) => "internal",
44        }
45    }
46}
47
48/// AMP message header (additional authenticated data)
49#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
50pub struct AmpHeader {
51    pub context: ContextId,
52    pub channel: ChannelId,
53    pub chan_epoch: u64,
54    pub ratchet_gen: u64,
55}
56
57/// Result of a send operation (ciphertext + header)
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
59pub struct AmpCiphertext {
60    pub header: AmpHeader,
61    pub ciphertext: Vec<u8>,
62}
63
64/// Bootstrap package for provisional AMP channel encryption.
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
66pub struct ChannelBootstrapPackage {
67    pub bootstrap_id: Hash32,
68    pub key: Vec<u8>,
69}
70
71/// Optional parameters for channel creation
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
73pub struct ChannelCreateParams {
74    pub context: ContextId,
75    /// Supply a channel id or let the implementation generate one
76    pub channel: Option<ChannelId>,
77    /// Optional skip window override (default 1024 in AMP spec)
78    pub skip_window: Option<u32>,
79    /// Human-friendly topic/label (metadata only)
80    pub topic: Option<String>,
81}
82
83/// Channel close parameters
84#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
85pub struct ChannelCloseParams {
86    pub context: ContextId,
87    pub channel: ChannelId,
88}
89
90/// Channel join parameters
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92pub struct ChannelJoinParams {
93    pub context: ContextId,
94    pub channel: ChannelId,
95    /// The participant joining the channel
96    pub participant: AuthorityId,
97}
98
99/// Channel leave parameters
100#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
101pub struct ChannelLeaveParams {
102    pub context: ContextId,
103    pub channel: ChannelId,
104    /// The participant leaving the channel
105    pub participant: AuthorityId,
106}
107
108/// Send parameters (plaintext provided by caller)
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
110pub struct ChannelSendParams {
111    pub context: ContextId,
112    pub channel: ChannelId,
113    pub sender: AuthorityId,
114    /// UTF-8 or arbitrary bytes; implementation encrypts
115    pub plaintext: Vec<u8>,
116    pub reply_to: Option<Vec<u8>>, // message id if available
117}
118
119#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
120#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
121pub trait AmpChannelEffects: Send + Sync {
122    /// Create a channel within a relational context. Returns the ChannelId.
123    async fn create_channel(
124        &self,
125        params: ChannelCreateParams,
126    ) -> Result<ChannelId, AmpChannelError>;
127
128    /// Close/archive a channel.
129    async fn close_channel(&self, params: ChannelCloseParams) -> Result<(), AmpChannelError>;
130
131    /// Join an existing channel.
132    async fn join_channel(&self, params: ChannelJoinParams) -> Result<(), AmpChannelError>;
133
134    /// Leave a channel.
135    async fn leave_channel(&self, params: ChannelLeaveParams) -> Result<(), AmpChannelError>;
136
137    /// Send a message on a channel, returning ciphertext + AMP header.
138    async fn send_message(
139        &self,
140        params: ChannelSendParams,
141    ) -> Result<AmpCiphertext, AmpChannelError>;
142}
143
144// Blanket impl for Arc<T>
145#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
146#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
147impl<T: AmpChannelEffects + ?Sized> AmpChannelEffects for std::sync::Arc<T> {
148    async fn create_channel(
149        &self,
150        params: ChannelCreateParams,
151    ) -> Result<ChannelId, AmpChannelError> {
152        (**self).create_channel(params).await
153    }
154
155    async fn close_channel(&self, params: ChannelCloseParams) -> Result<(), AmpChannelError> {
156        (**self).close_channel(params).await
157    }
158
159    async fn join_channel(&self, params: ChannelJoinParams) -> Result<(), AmpChannelError> {
160        (**self).join_channel(params).await
161    }
162
163    async fn leave_channel(&self, params: ChannelLeaveParams) -> Result<(), AmpChannelError> {
164        (**self).leave_channel(params).await
165    }
166
167    async fn send_message(
168        &self,
169        params: ChannelSendParams,
170    ) -> Result<AmpCiphertext, AmpChannelError> {
171        (**self).send_message(params).await
172    }
173}