lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

wire.rs (100341B)


      1 use crate::error::RadrootsSimplexSmpProtoError;
      2 use crate::uri::RadrootsSimplexSmpQueueMode;
      3 use crate::version::{
      4     RADROOTS_SIMPLEX_SMP_BLOCKED_ENTITY_TRANSPORT_VERSION,
      5     RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION,
      6     RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION,
      7     RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION,
      8     RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION,
      9     RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION, RadrootsSimplexSmpVersionRange,
     10 };
     11 use alloc::boxed::Box;
     12 use alloc::string::{String, ToString};
     13 use alloc::vec::Vec;
     14 use core::net::Ipv6Addr;
     15 use core::str::FromStr;
     16 
     17 const TAG_NEW: &[u8] = b"NEW";
     18 const TAG_SUB: &[u8] = b"SUB";
     19 const TAG_SUBS: &[u8] = b"SUBS";
     20 const TAG_KEY: &[u8] = b"KEY";
     21 const TAG_RKEY: &[u8] = b"RKEY";
     22 const TAG_LSET: &[u8] = b"LSET";
     23 const TAG_LDEL: &[u8] = b"LDEL";
     24 const TAG_NKEY: &[u8] = b"NKEY";
     25 const TAG_NDEL: &[u8] = b"NDEL";
     26 const TAG_GET: &[u8] = b"GET";
     27 const TAG_ACK: &[u8] = b"ACK";
     28 const TAG_OFF: &[u8] = b"OFF";
     29 const TAG_DEL: &[u8] = b"DEL";
     30 const TAG_QUE: &[u8] = b"QUE";
     31 const TAG_SKEY: &[u8] = b"SKEY";
     32 const TAG_SEND: &[u8] = b"SEND";
     33 const TAG_PING: &[u8] = b"PING";
     34 const TAG_LKEY: &[u8] = b"LKEY";
     35 const TAG_LGET: &[u8] = b"LGET";
     36 const TAG_NSUB: &[u8] = b"NSUB";
     37 const TAG_NSUBS: &[u8] = b"NSUBS";
     38 const TAG_PRXY: &[u8] = b"PRXY";
     39 const TAG_PFWD: &[u8] = b"PFWD";
     40 const TAG_RFWD: &[u8] = b"RFWD";
     41 
     42 const TAG_IDS: &[u8] = b"IDS";
     43 const TAG_LNK: &[u8] = b"LNK";
     44 const TAG_SOK: &[u8] = b"SOK";
     45 const TAG_SOKS: &[u8] = b"SOKS";
     46 const TAG_NID: &[u8] = b"NID";
     47 const TAG_MSG: &[u8] = b"MSG";
     48 const TAG_NMSG: &[u8] = b"NMSG";
     49 const TAG_PKEY: &[u8] = b"PKEY";
     50 const TAG_RRES: &[u8] = b"RRES";
     51 const TAG_PRES: &[u8] = b"PRES";
     52 const TAG_END: &[u8] = b"END";
     53 const TAG_ENDS: &[u8] = b"ENDS";
     54 const TAG_DELD: &[u8] = b"DELD";
     55 const TAG_INFO: &[u8] = b"INFO";
     56 const TAG_OK: &[u8] = b"OK";
     57 const TAG_ERR: &[u8] = b"ERR";
     58 const TAG_PONG: &[u8] = b"PONG";
     59 
     60 const COMMAND_ERR_UNKNOWN: &[u8] = b"UNKNOWN";
     61 const COMMAND_ERR_SYNTAX: &[u8] = b"SYNTAX";
     62 const COMMAND_ERR_PROHIBITED: &[u8] = b"PROHIBITED";
     63 const COMMAND_ERR_NO_AUTH: &[u8] = b"NO_AUTH";
     64 const COMMAND_ERR_HAS_AUTH: &[u8] = b"HAS_AUTH";
     65 const COMMAND_ERR_NO_ENTITY: &[u8] = b"NO_ENTITY";
     66 const COMMAND_ERR_NO_QUEUE: &[u8] = b"NO_QUEUE";
     67 
     68 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     69 pub enum RadrootsSimplexSmpSubscriptionMode {
     70     Subscribe,
     71     OnlyCreate,
     72 }
     73 
     74 #[derive(Debug, Clone, PartialEq, Eq)]
     75 pub struct RadrootsSimplexSmpQueueLinkData {
     76     pub fixed_data: Vec<u8>,
     77     pub user_data: Vec<u8>,
     78 }
     79 
     80 #[derive(Debug, Clone, PartialEq, Eq)]
     81 pub struct RadrootsSimplexSmpMessagingQueueRequest {
     82     pub sender_id: Vec<u8>,
     83     pub link_data: RadrootsSimplexSmpQueueLinkData,
     84 }
     85 
     86 #[derive(Debug, Clone, PartialEq, Eq)]
     87 pub struct RadrootsSimplexSmpContactQueueRequest {
     88     pub link_id: Vec<u8>,
     89     pub sender_id: Vec<u8>,
     90     pub link_data: RadrootsSimplexSmpQueueLinkData,
     91 }
     92 
     93 #[derive(Debug, Clone, PartialEq, Eq)]
     94 pub struct RadrootsSimplexSmpKeyList {
     95     pub first: Vec<u8>,
     96     pub rest: Vec<Vec<u8>>,
     97 }
     98 
     99 #[derive(Debug, Clone, PartialEq, Eq)]
    100 pub struct RadrootsSimplexSmpProtocolServer {
    101     pub hosts: Vec<String>,
    102     pub port: String,
    103     pub key_hash: Vec<u8>,
    104 }
    105 
    106 #[derive(Debug, Clone, PartialEq, Eq)]
    107 pub struct RadrootsSimplexSmpCertChainPublicKey {
    108     pub certificate_chain: Vec<Vec<u8>>,
    109     pub signed_public_key: Vec<u8>,
    110 }
    111 
    112 #[derive(Debug, Clone, PartialEq, Eq)]
    113 pub enum RadrootsSimplexSmpBlockingReason {
    114     Spam,
    115     Content,
    116     Other(String),
    117 }
    118 
    119 #[derive(Debug, Clone, PartialEq, Eq)]
    120 pub struct RadrootsSimplexSmpBlockingInfo {
    121     pub reason: RadrootsSimplexSmpBlockingReason,
    122 }
    123 
    124 #[derive(Debug, Clone, PartialEq, Eq)]
    125 pub enum RadrootsSimplexSmpHandshakeError {
    126     Parse,
    127     Identity,
    128     BadAuth,
    129     BadService,
    130     Other(String),
    131 }
    132 
    133 #[derive(Debug, Clone, PartialEq, Eq)]
    134 pub enum RadrootsSimplexSmpTransportError {
    135     Block,
    136     Version,
    137     LargeMsg,
    138     Session,
    139     NoAuth,
    140     Handshake(RadrootsSimplexSmpHandshakeError),
    141 }
    142 
    143 #[derive(Debug, Clone, PartialEq, Eq)]
    144 pub enum RadrootsSimplexSmpNetworkError {
    145     Connect(String),
    146     Tls(String),
    147     UnknownCa,
    148     Failed,
    149     Timeout,
    150     Subscribe(String),
    151 }
    152 
    153 #[derive(Debug, Clone, PartialEq, Eq)]
    154 pub enum RadrootsSimplexSmpBrokerError {
    155     Response(String),
    156     Unexpected(String),
    157     Network(RadrootsSimplexSmpNetworkError),
    158     Host,
    159     NoService,
    160     Transport(RadrootsSimplexSmpTransportError),
    161     Timeout,
    162 }
    163 
    164 #[derive(Debug, Clone, PartialEq, Eq)]
    165 pub enum RadrootsSimplexSmpProxyError {
    166     Protocol(Box<RadrootsSimplexSmpError>),
    167     Broker(RadrootsSimplexSmpBrokerError),
    168     BasicAuth,
    169     NoSession,
    170 }
    171 
    172 #[derive(Debug, Clone, PartialEq, Eq)]
    173 pub enum RadrootsSimplexSmpQueueRequestData {
    174     Messaging(Option<RadrootsSimplexSmpMessagingQueueRequest>),
    175     Contact(Option<RadrootsSimplexSmpContactQueueRequest>),
    176 }
    177 
    178 impl RadrootsSimplexSmpQueueRequestData {
    179     pub const fn queue_mode(&self) -> RadrootsSimplexSmpQueueMode {
    180         match self {
    181             Self::Messaging(_) => RadrootsSimplexSmpQueueMode::Messaging,
    182             Self::Contact(_) => RadrootsSimplexSmpQueueMode::Contact,
    183         }
    184     }
    185 }
    186 
    187 #[derive(Debug, Clone, PartialEq, Eq)]
    188 pub struct RadrootsSimplexSmpNewNotifierCredentials {
    189     pub notifier_auth_public_key: Vec<u8>,
    190     pub recipient_notification_dh_public_key: Vec<u8>,
    191 }
    192 
    193 #[derive(Debug, Clone, PartialEq, Eq)]
    194 pub struct RadrootsSimplexSmpServerNotifierCredentials {
    195     pub notifier_id: Vec<u8>,
    196     pub server_notification_dh_public_key: Vec<u8>,
    197 }
    198 
    199 #[derive(Debug, Clone, PartialEq, Eq)]
    200 pub struct RadrootsSimplexSmpNewQueueRequest {
    201     pub recipient_auth_public_key: Vec<u8>,
    202     pub recipient_dh_public_key: Vec<u8>,
    203     pub basic_auth: Option<String>,
    204     pub subscription_mode: RadrootsSimplexSmpSubscriptionMode,
    205     pub queue_request_data: Option<RadrootsSimplexSmpQueueRequestData>,
    206     pub notifier_credentials: Option<RadrootsSimplexSmpNewNotifierCredentials>,
    207 }
    208 
    209 impl RadrootsSimplexSmpNewQueueRequest {
    210     pub const fn sender_can_secure(&self) -> bool {
    211         matches!(
    212             self.queue_request_data,
    213             Some(RadrootsSimplexSmpQueueRequestData::Messaging(_))
    214         )
    215     }
    216 }
    217 
    218 #[derive(Debug, Clone, PartialEq, Eq)]
    219 pub struct RadrootsSimplexSmpMessageFlags {
    220     pub notification: bool,
    221     pub reserved: Vec<u8>,
    222 }
    223 
    224 impl RadrootsSimplexSmpMessageFlags {
    225     pub const fn notifications_enabled() -> Self {
    226         Self {
    227             notification: true,
    228             reserved: Vec::new(),
    229         }
    230     }
    231 
    232     pub const fn notifications_disabled() -> Self {
    233         Self {
    234             notification: false,
    235             reserved: Vec::new(),
    236         }
    237     }
    238 }
    239 
    240 impl Default for RadrootsSimplexSmpMessageFlags {
    241     fn default() -> Self {
    242         Self::notifications_disabled()
    243     }
    244 }
    245 
    246 #[derive(Debug, Clone, PartialEq, Eq)]
    247 pub struct RadrootsSimplexSmpSendCommand {
    248     pub flags: RadrootsSimplexSmpMessageFlags,
    249     pub message_body: Vec<u8>,
    250 }
    251 
    252 #[derive(Debug, Clone, PartialEq, Eq)]
    253 pub enum RadrootsSimplexSmpCommand {
    254     New(RadrootsSimplexSmpNewQueueRequest),
    255     Sub,
    256     Subs,
    257     Key(Vec<u8>),
    258     RKey(RadrootsSimplexSmpKeyList),
    259     LSet {
    260         link_id: Vec<u8>,
    261         link_data: RadrootsSimplexSmpQueueLinkData,
    262     },
    263     LDel,
    264     NKey {
    265         notifier_auth_public_key: Vec<u8>,
    266         recipient_notification_dh_public_key: Vec<u8>,
    267     },
    268     NDel,
    269     Get,
    270     Ack(Vec<u8>),
    271     Off,
    272     Del,
    273     Que,
    274     SKey(Vec<u8>),
    275     Send(RadrootsSimplexSmpSendCommand),
    276     Ping,
    277     LKey(Vec<u8>),
    278     LGet,
    279     NSub,
    280     NSubs,
    281     Prxy {
    282         server: RadrootsSimplexSmpProtocolServer,
    283         basic_auth: Option<String>,
    284     },
    285     PFwd {
    286         relay_version: u16,
    287         public_key: Vec<u8>,
    288         encrypted_transmission: Vec<u8>,
    289     },
    290     RFwd(Vec<u8>),
    291 }
    292 
    293 #[derive(Debug, Clone, PartialEq, Eq)]
    294 pub struct RadrootsSimplexSmpQueueIdsResponse {
    295     pub recipient_id: Vec<u8>,
    296     pub sender_id: Vec<u8>,
    297     pub server_dh_public_key: Vec<u8>,
    298     pub queue_mode: Option<RadrootsSimplexSmpQueueMode>,
    299     pub link_id: Option<Vec<u8>>,
    300     pub service_id: Option<Vec<u8>>,
    301     pub server_notification_credentials: Option<RadrootsSimplexSmpServerNotifierCredentials>,
    302 }
    303 
    304 impl RadrootsSimplexSmpQueueIdsResponse {
    305     pub const fn sender_can_secure(&self) -> bool {
    306         matches!(
    307             self.queue_mode,
    308             Some(RadrootsSimplexSmpQueueMode::Messaging)
    309         )
    310     }
    311 }
    312 
    313 #[derive(Debug, Clone, PartialEq, Eq)]
    314 pub struct RadrootsSimplexSmpNotifierIdsResponse {
    315     pub notifier_id: Vec<u8>,
    316     pub server_notification_dh_public_key: Vec<u8>,
    317 }
    318 
    319 #[derive(Debug, Clone, PartialEq, Eq)]
    320 pub struct RadrootsSimplexSmpReceivedMessage {
    321     pub message_id: Vec<u8>,
    322     pub encrypted_body: Vec<u8>,
    323 }
    324 
    325 #[derive(Debug, Clone, PartialEq, Eq)]
    326 pub enum RadrootsSimplexSmpCommandError {
    327     Unknown,
    328     Syntax,
    329     Prohibited,
    330     NoAuth,
    331     HasAuth,
    332     NoEntity,
    333     Other(Vec<u8>),
    334 }
    335 
    336 #[derive(Debug, Clone, PartialEq, Eq)]
    337 pub enum RadrootsSimplexSmpError {
    338     Block,
    339     Session,
    340     Command(RadrootsSimplexSmpCommandError),
    341     Proxy(RadrootsSimplexSmpProxyError),
    342     Auth,
    343     Blocked(RadrootsSimplexSmpBlockingInfo),
    344     Service,
    345     Crypto,
    346     Quota,
    347     Store(String),
    348     NoMsg,
    349     LargeMsg,
    350     Expired,
    351     Internal,
    352     Duplicate,
    353     Other(Vec<u8>),
    354 }
    355 
    356 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    357 pub struct RadrootsSimplexSmpCorrelationId([u8; 24]);
    358 
    359 impl RadrootsSimplexSmpCorrelationId {
    360     pub const LENGTH: usize = 24;
    361 
    362     pub const fn new(bytes: [u8; 24]) -> Self {
    363         Self(bytes)
    364     }
    365 
    366     pub fn from_slice(value: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> {
    367         if value.len() != Self::LENGTH {
    368             return Err(RadrootsSimplexSmpProtoError::InvalidCorrelationIdLength(
    369                 value.len(),
    370             ));
    371         }
    372         let mut bytes = [0_u8; Self::LENGTH];
    373         bytes.copy_from_slice(value);
    374         Ok(Self(bytes))
    375     }
    376 
    377     pub const fn as_bytes(&self) -> &[u8; 24] {
    378         &self.0
    379     }
    380 }
    381 
    382 #[derive(Debug, Clone, PartialEq, Eq)]
    383 pub enum RadrootsSimplexSmpBrokerMessage {
    384     Ids(RadrootsSimplexSmpQueueIdsResponse),
    385     Lnk {
    386         sender_id: Vec<u8>,
    387         link_data: RadrootsSimplexSmpQueueLinkData,
    388     },
    389     Sok(Option<Vec<u8>>),
    390     Soks(i64),
    391     Nid(RadrootsSimplexSmpNotifierIdsResponse),
    392     Msg(RadrootsSimplexSmpReceivedMessage),
    393     NMsg {
    394         nonce: [u8; 24],
    395         encrypted_metadata: Vec<u8>,
    396     },
    397     PKey {
    398         session_id: Vec<u8>,
    399         version_range: RadrootsSimplexSmpVersionRange,
    400         cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey,
    401     },
    402     RRes(Vec<u8>),
    403     PRes(Vec<u8>),
    404     End,
    405     Ends(i64),
    406     Deld,
    407     Info(Vec<u8>),
    408     Ok,
    409     Err(RadrootsSimplexSmpError),
    410     Pong,
    411 }
    412 
    413 #[derive(Debug, Clone, PartialEq, Eq)]
    414 pub struct RadrootsSimplexSmpCommandTransmission {
    415     pub authorization: Vec<u8>,
    416     pub correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
    417     pub entity_id: Vec<u8>,
    418     pub command: RadrootsSimplexSmpCommand,
    419 }
    420 
    421 #[derive(Debug, Clone, PartialEq, Eq)]
    422 pub struct RadrootsSimplexSmpBrokerTransmission {
    423     pub authorization: Vec<u8>,
    424     pub correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
    425     pub entity_id: Vec<u8>,
    426     pub message: RadrootsSimplexSmpBrokerMessage,
    427 }
    428 
    429 type RadrootsSimplexSmpDecodedTransmission<'a> = (
    430     Vec<u8>,
    431     Option<RadrootsSimplexSmpCorrelationId>,
    432     Vec<u8>,
    433     &'a [u8],
    434 );
    435 
    436 impl RadrootsSimplexSmpCommand {
    437     pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    438         self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
    439     }
    440 
    441     pub fn encode_for_version(
    442         &self,
    443         transport_version: u16,
    444     ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    445         let mut buffer = Vec::new();
    446         match self {
    447             Self::New(request) => encode_new_request(&mut buffer, request, transport_version)?,
    448             Self::Sub => buffer.extend_from_slice(TAG_SUB),
    449             Self::Subs => buffer.extend_from_slice(TAG_SUBS),
    450             Self::Key(sender_auth_public_key) => {
    451                 buffer.extend_from_slice(TAG_KEY);
    452                 buffer.push(b' ');
    453                 push_short_bytes(&mut buffer, sender_auth_public_key)?;
    454             }
    455             Self::RKey(recipient_auth_public_keys) => {
    456                 buffer.extend_from_slice(TAG_RKEY);
    457                 buffer.push(b' ');
    458                 push_short_key_list(&mut buffer, recipient_auth_public_keys)?;
    459             }
    460             Self::LSet { link_id, link_data } => {
    461                 buffer.extend_from_slice(TAG_LSET);
    462                 buffer.push(b' ');
    463                 push_short_bytes(&mut buffer, link_id)?;
    464                 encode_queue_link_data(&mut buffer, link_data)?;
    465             }
    466             Self::LDel => buffer.extend_from_slice(TAG_LDEL),
    467             Self::NKey {
    468                 notifier_auth_public_key,
    469                 recipient_notification_dh_public_key,
    470             } => {
    471                 buffer.extend_from_slice(TAG_NKEY);
    472                 buffer.push(b' ');
    473                 push_short_bytes(&mut buffer, notifier_auth_public_key)?;
    474                 push_short_bytes(&mut buffer, recipient_notification_dh_public_key)?;
    475             }
    476             Self::NDel => buffer.extend_from_slice(TAG_NDEL),
    477             Self::Get => buffer.extend_from_slice(TAG_GET),
    478             Self::Ack(message_id) => {
    479                 buffer.extend_from_slice(TAG_ACK);
    480                 buffer.push(b' ');
    481                 push_short_bytes(&mut buffer, message_id)?;
    482             }
    483             Self::Off => buffer.extend_from_slice(TAG_OFF),
    484             Self::Del => buffer.extend_from_slice(TAG_DEL),
    485             Self::Que => buffer.extend_from_slice(TAG_QUE),
    486             Self::SKey(sender_auth_public_key) => {
    487                 buffer.extend_from_slice(TAG_SKEY);
    488                 buffer.push(b' ');
    489                 push_short_bytes(&mut buffer, sender_auth_public_key)?;
    490             }
    491             Self::Send(send) => {
    492                 buffer.extend_from_slice(TAG_SEND);
    493                 buffer.push(b' ');
    494                 buffer.push(encode_bool(send.flags.notification));
    495                 buffer.extend_from_slice(&send.flags.reserved);
    496                 buffer.push(b' ');
    497                 buffer.extend_from_slice(&send.message_body);
    498             }
    499             Self::Ping => buffer.extend_from_slice(TAG_PING),
    500             Self::LKey(sender_auth_public_key) => {
    501                 buffer.extend_from_slice(TAG_LKEY);
    502                 buffer.push(b' ');
    503                 push_short_bytes(&mut buffer, sender_auth_public_key)?;
    504             }
    505             Self::LGet => buffer.extend_from_slice(TAG_LGET),
    506             Self::NSub => buffer.extend_from_slice(TAG_NSUB),
    507             Self::NSubs => buffer.extend_from_slice(TAG_NSUBS),
    508             Self::Prxy { server, basic_auth } => {
    509                 buffer.extend_from_slice(TAG_PRXY);
    510                 buffer.push(b' ');
    511                 encode_protocol_server(&mut buffer, server)?;
    512                 push_maybe_string(&mut buffer, basic_auth.as_deref())?;
    513             }
    514             Self::PFwd {
    515                 relay_version,
    516                 public_key,
    517                 encrypted_transmission,
    518             } => {
    519                 buffer.extend_from_slice(TAG_PFWD);
    520                 buffer.push(b' ');
    521                 buffer.extend_from_slice(&relay_version.to_be_bytes());
    522                 push_short_bytes(&mut buffer, public_key)?;
    523                 buffer.extend_from_slice(encrypted_transmission);
    524             }
    525             Self::RFwd(encrypted_forward_transmission) => {
    526                 buffer.extend_from_slice(TAG_RFWD);
    527                 buffer.push(b' ');
    528                 buffer.extend_from_slice(encrypted_forward_transmission);
    529             }
    530         }
    531         Ok(buffer)
    532     }
    533 
    534     pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> {
    535         Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes)
    536     }
    537 
    538     pub fn decode_for_version(
    539         transport_version: u16,
    540         bytes: &[u8],
    541     ) -> Result<Self, RadrootsSimplexSmpProtoError> {
    542         let (tag, rest) = parse_tag(bytes)?;
    543         let mut cursor = Cursor::new(rest);
    544         let command = match tag.as_slice() {
    545             TAG_NEW => Self::New(decode_new_request(&mut cursor, transport_version)?),
    546             TAG_SUB => Self::Sub,
    547             TAG_SUBS => Self::Subs,
    548             TAG_KEY => Self::Key(cursor.read_short_bytes()?),
    549             TAG_RKEY => Self::RKey(cursor.read_short_key_list()?),
    550             TAG_LSET => Self::LSet {
    551                 link_id: cursor.read_short_bytes()?,
    552                 link_data: decode_queue_link_data(&mut cursor)?,
    553             },
    554             TAG_LDEL => Self::LDel,
    555             TAG_NKEY => Self::NKey {
    556                 notifier_auth_public_key: cursor.read_short_bytes()?,
    557                 recipient_notification_dh_public_key: cursor.read_short_bytes()?,
    558             },
    559             TAG_NDEL => Self::NDel,
    560             TAG_GET => Self::Get,
    561             TAG_ACK => Self::Ack(cursor.read_short_bytes()?),
    562             TAG_OFF => Self::Off,
    563             TAG_DEL => Self::Del,
    564             TAG_QUE => Self::Que,
    565             TAG_SKEY => Self::SKey(cursor.read_short_bytes()?),
    566             TAG_SEND => Self::Send(decode_send_payload(rest)?),
    567             TAG_PING => Self::Ping,
    568             TAG_LKEY => Self::LKey(cursor.read_short_bytes()?),
    569             TAG_LGET => Self::LGet,
    570             TAG_NSUB => Self::NSub,
    571             TAG_NSUBS => Self::NSubs,
    572             TAG_PRXY => Self::Prxy {
    573                 server: decode_protocol_server(&mut cursor)?,
    574                 basic_auth: cursor.read_maybe_string()?,
    575             },
    576             TAG_PFWD => Self::PFwd {
    577                 relay_version: u16::from_be_bytes(cursor.read_array::<2>()?),
    578                 public_key: cursor.read_short_bytes()?,
    579                 encrypted_transmission: cursor.read_remaining().to_vec(),
    580             },
    581             TAG_RFWD => Self::RFwd(cursor.read_remaining().to_vec()),
    582             _ => {
    583                 return Err(RadrootsSimplexSmpProtoError::UnsupportedTag(
    584                     String::from_utf8_lossy(&tag).into_owned(),
    585                 ));
    586             }
    587         };
    588         if !matches!(command, Self::Send(_)) && !cursor.is_empty() {
    589             return Err(RadrootsSimplexSmpProtoError::TrailingBytes);
    590         }
    591         Ok(command)
    592     }
    593 }
    594 
    595 impl RadrootsSimplexSmpBrokerMessage {
    596     pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    597         self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
    598     }
    599 
    600     pub fn encode_for_version(
    601         &self,
    602         transport_version: u16,
    603     ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    604         let mut buffer = Vec::new();
    605         match self {
    606             Self::Ids(response) => encode_ids_response(&mut buffer, response, transport_version)?,
    607             Self::Lnk {
    608                 sender_id,
    609                 link_data,
    610             } => {
    611                 buffer.extend_from_slice(TAG_LNK);
    612                 buffer.push(b' ');
    613                 push_short_bytes(&mut buffer, sender_id)?;
    614                 encode_queue_link_data(&mut buffer, link_data)?;
    615             }
    616             Self::Sok(service_id) => {
    617                 if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION {
    618                     buffer.extend_from_slice(TAG_SOK);
    619                     buffer.push(b' ');
    620                     push_maybe_short_bytes(&mut buffer, service_id.as_deref())?;
    621                 } else {
    622                     buffer.extend_from_slice(TAG_OK);
    623                 }
    624             }
    625             Self::Soks(queue_count) => {
    626                 buffer.extend_from_slice(TAG_SOKS);
    627                 buffer.push(b' ');
    628                 push_i64(&mut buffer, *queue_count);
    629             }
    630             Self::Nid(response) => {
    631                 buffer.extend_from_slice(TAG_NID);
    632                 buffer.push(b' ');
    633                 push_short_bytes(&mut buffer, &response.notifier_id)?;
    634                 push_short_bytes(&mut buffer, &response.server_notification_dh_public_key)?;
    635             }
    636             Self::Msg(message) => {
    637                 buffer.extend_from_slice(TAG_MSG);
    638                 buffer.push(b' ');
    639                 push_short_bytes(&mut buffer, &message.message_id)?;
    640                 buffer.extend_from_slice(&message.encrypted_body);
    641             }
    642             Self::NMsg {
    643                 nonce,
    644                 encrypted_metadata,
    645             } => {
    646                 buffer.extend_from_slice(TAG_NMSG);
    647                 buffer.push(b' ');
    648                 buffer.extend_from_slice(nonce);
    649                 buffer.extend_from_slice(encrypted_metadata);
    650             }
    651             Self::PKey {
    652                 session_id,
    653                 version_range,
    654                 cert_chain_public_key,
    655             } => {
    656                 buffer.extend_from_slice(TAG_PKEY);
    657                 buffer.push(b' ');
    658                 push_short_bytes(&mut buffer, session_id)?;
    659                 buffer.extend_from_slice(&version_range.min.to_be_bytes());
    660                 buffer.extend_from_slice(&version_range.max.to_be_bytes());
    661                 encode_cert_chain_public_key(&mut buffer, cert_chain_public_key)?;
    662             }
    663             Self::RRes(encrypted_forward_response) => {
    664                 buffer.extend_from_slice(TAG_RRES);
    665                 buffer.push(b' ');
    666                 buffer.extend_from_slice(encrypted_forward_response);
    667             }
    668             Self::PRes(encrypted_response) => {
    669                 buffer.extend_from_slice(TAG_PRES);
    670                 buffer.push(b' ');
    671                 buffer.extend_from_slice(encrypted_response);
    672             }
    673             Self::End => buffer.extend_from_slice(TAG_END),
    674             Self::Ends(queue_count) => {
    675                 buffer.extend_from_slice(TAG_ENDS);
    676                 buffer.push(b' ');
    677                 push_i64(&mut buffer, *queue_count);
    678             }
    679             Self::Deld => buffer.extend_from_slice(TAG_DELD),
    680             Self::Info(info) => {
    681                 buffer.extend_from_slice(TAG_INFO);
    682                 buffer.push(b' ');
    683                 buffer.extend_from_slice(info);
    684             }
    685             Self::Ok => buffer.extend_from_slice(TAG_OK),
    686             Self::Err(error) => {
    687                 buffer.extend_from_slice(TAG_ERR);
    688                 buffer.push(b' ');
    689                 if transport_version < RADROOTS_SIMPLEX_SMP_BLOCKED_ENTITY_TRANSPORT_VERSION
    690                     && matches!(error, RadrootsSimplexSmpError::Blocked(_))
    691                 {
    692                     buffer.extend_from_slice(b"AUTH");
    693                 } else {
    694                     buffer.extend_from_slice(&encode_error(error));
    695                 }
    696             }
    697             Self::Pong => buffer.extend_from_slice(TAG_PONG),
    698         }
    699         Ok(buffer)
    700     }
    701 
    702     pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> {
    703         Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes)
    704     }
    705 
    706     pub fn decode_for_version(
    707         transport_version: u16,
    708         bytes: &[u8],
    709     ) -> Result<Self, RadrootsSimplexSmpProtoError> {
    710         let (tag, rest) = parse_tag(bytes)?;
    711         let mut cursor = Cursor::new(rest);
    712         let message = match tag.as_slice() {
    713             TAG_IDS => Self::Ids(decode_ids_response(&mut cursor, transport_version)?),
    714             TAG_LNK => Self::Lnk {
    715                 sender_id: cursor.read_short_bytes()?,
    716                 link_data: decode_queue_link_data(&mut cursor)?,
    717             },
    718             TAG_SOK => Self::Sok(cursor.read_maybe(Cursor::read_short_bytes)?),
    719             TAG_SOKS => Self::Soks(cursor.read_i64()?),
    720             TAG_NID => Self::Nid(RadrootsSimplexSmpNotifierIdsResponse {
    721                 notifier_id: cursor.read_short_bytes()?,
    722                 server_notification_dh_public_key: cursor.read_short_bytes()?,
    723             }),
    724             TAG_MSG => Self::Msg(RadrootsSimplexSmpReceivedMessage {
    725                 message_id: cursor.read_short_bytes()?,
    726                 encrypted_body: cursor.read_remaining().to_vec(),
    727             }),
    728             TAG_NMSG => {
    729                 let nonce = cursor.read_array::<24>().map_err(|error| match error {
    730                     RadrootsSimplexSmpProtoError::UnexpectedEof => {
    731                         RadrootsSimplexSmpProtoError::InvalidNonceLength(cursor.remaining_len())
    732                     }
    733                     other => other,
    734                 })?;
    735                 Self::NMsg {
    736                     nonce,
    737                     encrypted_metadata: cursor.read_remaining().to_vec(),
    738                 }
    739             }
    740             TAG_PKEY => {
    741                 let session_id = cursor.read_short_bytes()?;
    742                 let min = u16::from_be_bytes(cursor.read_array::<2>()?);
    743                 let max = u16::from_be_bytes(cursor.read_array::<2>()?);
    744                 Self::PKey {
    745                     session_id,
    746                     version_range: RadrootsSimplexSmpVersionRange::new(min, max)?,
    747                     cert_chain_public_key: decode_cert_chain_public_key(&mut cursor)?,
    748                 }
    749             }
    750             TAG_RRES => Self::RRes(cursor.read_remaining().to_vec()),
    751             TAG_PRES => Self::PRes(cursor.read_remaining().to_vec()),
    752             TAG_END => Self::End,
    753             TAG_ENDS => Self::Ends(cursor.read_i64()?),
    754             TAG_DELD => Self::Deld,
    755             TAG_INFO => Self::Info(cursor.read_remaining().to_vec()),
    756             TAG_OK => Self::Ok,
    757             TAG_ERR => Self::Err(decode_error(rest)?),
    758             TAG_PONG => Self::Pong,
    759             _ => {
    760                 return Err(RadrootsSimplexSmpProtoError::UnsupportedTag(
    761                     String::from_utf8_lossy(&tag).into_owned(),
    762                 ));
    763             }
    764         };
    765         if !matches!(
    766             message,
    767             Self::Msg(_)
    768                 | Self::NMsg { .. }
    769                 | Self::RRes(_)
    770                 | Self::PRes(_)
    771                 | Self::Info(_)
    772                 | Self::Err(_)
    773         ) && !cursor.is_empty()
    774         {
    775             return Err(RadrootsSimplexSmpProtoError::TrailingBytes);
    776         }
    777         Ok(message)
    778     }
    779 }
    780 
    781 impl RadrootsSimplexSmpCommandTransmission {
    782     pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    783         self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
    784     }
    785 
    786     pub fn encode_for_version(
    787         &self,
    788         transport_version: u16,
    789     ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    790         encode_transmission(
    791             transport_version,
    792             &self.authorization,
    793             self.correlation_id,
    794             &self.entity_id,
    795             &self.command.encode_for_version(transport_version)?,
    796         )
    797     }
    798 
    799     pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> {
    800         Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes)
    801     }
    802 
    803     pub fn decode_for_version(
    804         transport_version: u16,
    805         bytes: &[u8],
    806     ) -> Result<Self, RadrootsSimplexSmpProtoError> {
    807         let (authorization, correlation_id, entity_id, frame) =
    808             decode_transmission(transport_version, bytes)?;
    809         Ok(Self {
    810             authorization,
    811             correlation_id,
    812             entity_id,
    813             command: RadrootsSimplexSmpCommand::decode_for_version(transport_version, frame)?,
    814         })
    815     }
    816 }
    817 
    818 impl RadrootsSimplexSmpBrokerTransmission {
    819     pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    820         self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
    821     }
    822 
    823     pub fn encode_for_version(
    824         &self,
    825         transport_version: u16,
    826     ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
    827         encode_transmission(
    828             transport_version,
    829             &self.authorization,
    830             self.correlation_id,
    831             &self.entity_id,
    832             &self.message.encode_for_version(transport_version)?,
    833         )
    834     }
    835 
    836     pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> {
    837         Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes)
    838     }
    839 
    840     pub fn decode_for_version(
    841         transport_version: u16,
    842         bytes: &[u8],
    843     ) -> Result<Self, RadrootsSimplexSmpProtoError> {
    844         let (authorization, correlation_id, entity_id, frame) =
    845             decode_transmission(transport_version, bytes)?;
    846         Ok(Self {
    847             authorization,
    848             correlation_id,
    849             entity_id,
    850             message: RadrootsSimplexSmpBrokerMessage::decode_for_version(transport_version, frame)?,
    851         })
    852     }
    853 }
    854 
    855 fn encode_new_request(
    856     buffer: &mut Vec<u8>,
    857     request: &RadrootsSimplexSmpNewQueueRequest,
    858     transport_version: u16,
    859 ) -> Result<(), RadrootsSimplexSmpProtoError> {
    860     if transport_version < RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION {
    861         return Err(RadrootsSimplexSmpProtoError::UnsupportedTransportVersion(
    862             transport_version,
    863         ));
    864     }
    865 
    866     buffer.extend_from_slice(TAG_NEW);
    867     buffer.push(b' ');
    868     push_short_bytes(buffer, &request.recipient_auth_public_key)?;
    869     push_short_bytes(buffer, &request.recipient_dh_public_key)?;
    870     if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION {
    871         push_maybe_string(buffer, request.basic_auth.as_deref())?;
    872         buffer.push(encode_subscription_mode(request.subscription_mode));
    873         push_maybe(
    874             buffer,
    875             request.queue_request_data.as_ref(),
    876             encode_queue_request_data,
    877         )?;
    878         push_maybe(
    879             buffer,
    880             request.notifier_credentials.as_ref(),
    881             encode_new_notifier_credentials,
    882         )?;
    883     } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION {
    884         push_maybe_string(buffer, request.basic_auth.as_deref())?;
    885         buffer.push(encode_subscription_mode(request.subscription_mode));
    886         push_maybe(
    887             buffer,
    888             request.queue_request_data.as_ref(),
    889             encode_queue_request_data,
    890         )?;
    891     } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION {
    892         push_maybe_string(buffer, request.basic_auth.as_deref())?;
    893         buffer.push(encode_subscription_mode(request.subscription_mode));
    894         buffer.push(encode_bool(request.sender_can_secure()));
    895     } else {
    896         push_legacy_basic_auth(buffer, request.basic_auth.as_deref())?;
    897         buffer.push(encode_subscription_mode(request.subscription_mode));
    898     }
    899 
    900     Ok(())
    901 }
    902 
    903 fn decode_new_request(
    904     cursor: &mut Cursor<'_>,
    905     transport_version: u16,
    906 ) -> Result<RadrootsSimplexSmpNewQueueRequest, RadrootsSimplexSmpProtoError> {
    907     if transport_version < RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION {
    908         return Err(RadrootsSimplexSmpProtoError::UnsupportedTransportVersion(
    909             transport_version,
    910         ));
    911     }
    912 
    913     let recipient_auth_public_key = cursor.read_short_bytes()?;
    914     let recipient_dh_public_key = cursor.read_short_bytes()?;
    915     let (basic_auth, subscription_mode, queue_request_data, notifier_credentials) =
    916         if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION {
    917             (
    918                 cursor.read_maybe_string()?,
    919                 decode_subscription_mode(cursor.read_byte()?)?,
    920                 cursor.read_maybe(decode_queue_request_data)?,
    921                 cursor.read_maybe(decode_new_notifier_credentials)?,
    922             )
    923         } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION {
    924             (
    925                 cursor.read_maybe_string()?,
    926                 decode_subscription_mode(cursor.read_byte()?)?,
    927                 cursor.read_maybe(decode_queue_request_data)?,
    928                 None,
    929             )
    930         } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION {
    931             let basic_auth = cursor.read_maybe_string()?;
    932             let subscription_mode = decode_subscription_mode(cursor.read_byte()?)?;
    933             let sender_can_secure = decode_bool(cursor.read_byte()?)?;
    934             let queue_request_data = Some(if sender_can_secure {
    935                 RadrootsSimplexSmpQueueRequestData::Messaging(None)
    936             } else {
    937                 RadrootsSimplexSmpQueueRequestData::Contact(None)
    938             });
    939             (basic_auth, subscription_mode, queue_request_data, None)
    940         } else {
    941             (
    942                 cursor.read_legacy_basic_auth()?,
    943                 decode_subscription_mode(cursor.read_byte()?)?,
    944                 None,
    945                 None,
    946             )
    947         };
    948 
    949     Ok(RadrootsSimplexSmpNewQueueRequest {
    950         recipient_auth_public_key,
    951         recipient_dh_public_key,
    952         basic_auth,
    953         subscription_mode,
    954         queue_request_data,
    955         notifier_credentials,
    956     })
    957 }
    958 
    959 fn encode_ids_response(
    960     buffer: &mut Vec<u8>,
    961     response: &RadrootsSimplexSmpQueueIdsResponse,
    962     transport_version: u16,
    963 ) -> Result<(), RadrootsSimplexSmpProtoError> {
    964     buffer.extend_from_slice(TAG_IDS);
    965     buffer.push(b' ');
    966     push_short_bytes(buffer, &response.recipient_id)?;
    967     push_short_bytes(buffer, &response.sender_id)?;
    968     push_short_bytes(buffer, &response.server_dh_public_key)?;
    969 
    970     if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION {
    971         push_maybe(buffer, response.queue_mode, encode_queue_mode)?;
    972         push_maybe_short_bytes(buffer, response.link_id.as_deref())?;
    973         push_maybe_short_bytes(buffer, response.service_id.as_deref())?;
    974         push_maybe(
    975             buffer,
    976             response.server_notification_credentials.as_ref(),
    977             encode_server_notifier_credentials,
    978         )?;
    979     } else if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION {
    980         push_maybe(buffer, response.queue_mode, encode_queue_mode)?;
    981         push_maybe_short_bytes(buffer, response.link_id.as_deref())?;
    982         push_maybe_short_bytes(buffer, response.service_id.as_deref())?;
    983     } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION {
    984         push_maybe(buffer, response.queue_mode, encode_queue_mode)?;
    985         push_maybe_short_bytes(buffer, response.link_id.as_deref())?;
    986     } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION {
    987         buffer.push(encode_bool(response.sender_can_secure()));
    988     }
    989 
    990     Ok(())
    991 }
    992 
    993 fn decode_ids_response(
    994     cursor: &mut Cursor<'_>,
    995     transport_version: u16,
    996 ) -> Result<RadrootsSimplexSmpQueueIdsResponse, RadrootsSimplexSmpProtoError> {
    997     let recipient_id = cursor.read_short_bytes()?;
    998     let sender_id = cursor.read_short_bytes()?;
    999     let server_dh_public_key = cursor.read_short_bytes()?;
   1000 
   1001     let (queue_mode, link_id, service_id, server_notification_credentials) =
   1002         if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION {
   1003             (
   1004                 cursor.read_maybe(decode_queue_mode)?,
   1005                 cursor.read_maybe(Cursor::read_short_bytes)?,
   1006                 cursor.read_maybe(Cursor::read_short_bytes)?,
   1007                 cursor.read_maybe(decode_server_notifier_credentials)?,
   1008             )
   1009         } else if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION {
   1010             (
   1011                 cursor.read_maybe(decode_queue_mode)?,
   1012                 cursor.read_maybe(Cursor::read_short_bytes)?,
   1013                 cursor.read_maybe(Cursor::read_short_bytes)?,
   1014                 None,
   1015             )
   1016         } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION {
   1017             (
   1018                 cursor.read_maybe(decode_queue_mode)?,
   1019                 cursor.read_maybe(Cursor::read_short_bytes)?,
   1020                 None,
   1021                 None,
   1022             )
   1023         } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION {
   1024             let sender_can_secure = decode_bool(cursor.read_byte()?)?;
   1025             (
   1026                 Some(if sender_can_secure {
   1027                     RadrootsSimplexSmpQueueMode::Messaging
   1028                 } else {
   1029                     RadrootsSimplexSmpQueueMode::Contact
   1030                 }),
   1031                 None,
   1032                 None,
   1033                 None,
   1034             )
   1035         } else {
   1036             (None, None, None, None)
   1037         };
   1038 
   1039     Ok(RadrootsSimplexSmpQueueIdsResponse {
   1040         recipient_id,
   1041         sender_id,
   1042         server_dh_public_key,
   1043         queue_mode,
   1044         link_id,
   1045         service_id,
   1046         server_notification_credentials,
   1047     })
   1048 }
   1049 
   1050 fn encode_queue_request_data(
   1051     buffer: &mut Vec<u8>,
   1052     queue_request_data: &RadrootsSimplexSmpQueueRequestData,
   1053 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1054     match queue_request_data {
   1055         RadrootsSimplexSmpQueueRequestData::Messaging(data) => {
   1056             buffer.push(b'M');
   1057             push_maybe(buffer, data.as_ref(), encode_messaging_queue_request)
   1058         }
   1059         RadrootsSimplexSmpQueueRequestData::Contact(data) => {
   1060             buffer.push(b'C');
   1061             push_maybe(buffer, data.as_ref(), encode_contact_queue_request)
   1062         }
   1063     }
   1064 }
   1065 
   1066 fn decode_queue_request_data(
   1067     cursor: &mut Cursor<'_>,
   1068 ) -> Result<RadrootsSimplexSmpQueueRequestData, RadrootsSimplexSmpProtoError> {
   1069     match cursor.read_byte()? {
   1070         b'M' => Ok(RadrootsSimplexSmpQueueRequestData::Messaging(
   1071             cursor.read_maybe(decode_messaging_queue_request)?,
   1072         )),
   1073         b'C' => Ok(RadrootsSimplexSmpQueueRequestData::Contact(
   1074             cursor.read_maybe(decode_contact_queue_request)?,
   1075         )),
   1076         value => Err(RadrootsSimplexSmpProtoError::InvalidTag(
   1077             String::from_utf8_lossy(&[value]).into_owned(),
   1078         )),
   1079     }
   1080 }
   1081 
   1082 fn encode_messaging_queue_request(
   1083     buffer: &mut Vec<u8>,
   1084     request: &RadrootsSimplexSmpMessagingQueueRequest,
   1085 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1086     push_short_bytes(buffer, &request.sender_id)?;
   1087     encode_queue_link_data(buffer, &request.link_data)
   1088 }
   1089 
   1090 fn decode_messaging_queue_request(
   1091     cursor: &mut Cursor<'_>,
   1092 ) -> Result<RadrootsSimplexSmpMessagingQueueRequest, RadrootsSimplexSmpProtoError> {
   1093     Ok(RadrootsSimplexSmpMessagingQueueRequest {
   1094         sender_id: cursor.read_short_bytes()?,
   1095         link_data: decode_queue_link_data(cursor)?,
   1096     })
   1097 }
   1098 
   1099 fn encode_contact_queue_request(
   1100     buffer: &mut Vec<u8>,
   1101     request: &RadrootsSimplexSmpContactQueueRequest,
   1102 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1103     push_short_bytes(buffer, &request.link_id)?;
   1104     push_short_bytes(buffer, &request.sender_id)?;
   1105     encode_queue_link_data(buffer, &request.link_data)
   1106 }
   1107 
   1108 fn decode_contact_queue_request(
   1109     cursor: &mut Cursor<'_>,
   1110 ) -> Result<RadrootsSimplexSmpContactQueueRequest, RadrootsSimplexSmpProtoError> {
   1111     Ok(RadrootsSimplexSmpContactQueueRequest {
   1112         link_id: cursor.read_short_bytes()?,
   1113         sender_id: cursor.read_short_bytes()?,
   1114         link_data: decode_queue_link_data(cursor)?,
   1115     })
   1116 }
   1117 
   1118 fn encode_protocol_server(
   1119     buffer: &mut Vec<u8>,
   1120     server: &RadrootsSimplexSmpProtocolServer,
   1121 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1122     validate_transport_hosts(&server.hosts)?;
   1123     push_short_string_list(buffer, &server.hosts)?;
   1124     push_short_string(buffer, &server.port)?;
   1125     push_short_bytes(buffer, &server.key_hash)
   1126 }
   1127 
   1128 fn decode_protocol_server(
   1129     cursor: &mut Cursor<'_>,
   1130 ) -> Result<RadrootsSimplexSmpProtocolServer, RadrootsSimplexSmpProtoError> {
   1131     let hosts = cursor.read_short_string_list()?;
   1132     validate_transport_hosts(&hosts)?;
   1133     Ok(RadrootsSimplexSmpProtocolServer {
   1134         hosts,
   1135         port: cursor.read_short_string_lossy()?,
   1136         key_hash: cursor.read_short_bytes()?,
   1137     })
   1138 }
   1139 
   1140 fn encode_cert_chain_public_key(
   1141     buffer: &mut Vec<u8>,
   1142     cert_chain_public_key: &RadrootsSimplexSmpCertChainPublicKey,
   1143 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1144     push_large_bytes_list(buffer, &cert_chain_public_key.certificate_chain)?;
   1145     push_large_bytes(buffer, &cert_chain_public_key.signed_public_key)
   1146 }
   1147 
   1148 fn decode_cert_chain_public_key(
   1149     cursor: &mut Cursor<'_>,
   1150 ) -> Result<RadrootsSimplexSmpCertChainPublicKey, RadrootsSimplexSmpProtoError> {
   1151     Ok(RadrootsSimplexSmpCertChainPublicKey {
   1152         certificate_chain: cursor.read_large_bytes_list()?,
   1153         signed_public_key: cursor.read_large_bytes()?,
   1154     })
   1155 }
   1156 
   1157 fn encode_queue_link_data(
   1158     buffer: &mut Vec<u8>,
   1159     link_data: &RadrootsSimplexSmpQueueLinkData,
   1160 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1161     push_large_bytes(buffer, &link_data.fixed_data)?;
   1162     push_large_bytes(buffer, &link_data.user_data)
   1163 }
   1164 
   1165 fn decode_queue_link_data(
   1166     cursor: &mut Cursor<'_>,
   1167 ) -> Result<RadrootsSimplexSmpQueueLinkData, RadrootsSimplexSmpProtoError> {
   1168     Ok(RadrootsSimplexSmpQueueLinkData {
   1169         fixed_data: cursor.read_large_bytes()?,
   1170         user_data: cursor.read_large_bytes()?,
   1171     })
   1172 }
   1173 
   1174 fn encode_new_notifier_credentials(
   1175     buffer: &mut Vec<u8>,
   1176     credentials: &RadrootsSimplexSmpNewNotifierCredentials,
   1177 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1178     push_short_bytes(buffer, &credentials.notifier_auth_public_key)?;
   1179     push_short_bytes(buffer, &credentials.recipient_notification_dh_public_key)
   1180 }
   1181 
   1182 fn decode_new_notifier_credentials(
   1183     cursor: &mut Cursor<'_>,
   1184 ) -> Result<RadrootsSimplexSmpNewNotifierCredentials, RadrootsSimplexSmpProtoError> {
   1185     Ok(RadrootsSimplexSmpNewNotifierCredentials {
   1186         notifier_auth_public_key: cursor.read_short_bytes()?,
   1187         recipient_notification_dh_public_key: cursor.read_short_bytes()?,
   1188     })
   1189 }
   1190 
   1191 fn encode_server_notifier_credentials(
   1192     buffer: &mut Vec<u8>,
   1193     credentials: &RadrootsSimplexSmpServerNotifierCredentials,
   1194 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1195     push_short_bytes(buffer, &credentials.notifier_id)?;
   1196     push_short_bytes(buffer, &credentials.server_notification_dh_public_key)
   1197 }
   1198 
   1199 fn decode_server_notifier_credentials(
   1200     cursor: &mut Cursor<'_>,
   1201 ) -> Result<RadrootsSimplexSmpServerNotifierCredentials, RadrootsSimplexSmpProtoError> {
   1202     Ok(RadrootsSimplexSmpServerNotifierCredentials {
   1203         notifier_id: cursor.read_short_bytes()?,
   1204         server_notification_dh_public_key: cursor.read_short_bytes()?,
   1205     })
   1206 }
   1207 
   1208 fn encode_queue_mode(
   1209     buffer: &mut Vec<u8>,
   1210     queue_mode: RadrootsSimplexSmpQueueMode,
   1211 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1212     buffer.push(match queue_mode {
   1213         RadrootsSimplexSmpQueueMode::Messaging => b'M',
   1214         RadrootsSimplexSmpQueueMode::Contact => b'C',
   1215     });
   1216     Ok(())
   1217 }
   1218 
   1219 fn decode_queue_mode(
   1220     cursor: &mut Cursor<'_>,
   1221 ) -> Result<RadrootsSimplexSmpQueueMode, RadrootsSimplexSmpProtoError> {
   1222     match cursor.read_byte()? {
   1223         b'M' => Ok(RadrootsSimplexSmpQueueMode::Messaging),
   1224         b'C' => Ok(RadrootsSimplexSmpQueueMode::Contact),
   1225         value => Err(RadrootsSimplexSmpProtoError::InvalidTag(
   1226             String::from_utf8_lossy(&[value]).into_owned(),
   1227         )),
   1228     }
   1229 }
   1230 
   1231 fn validate_transport_hosts(hosts: &[String]) -> Result<(), RadrootsSimplexSmpProtoError> {
   1232     for host in hosts {
   1233         validate_transport_host(host)?;
   1234     }
   1235     Ok(())
   1236 }
   1237 
   1238 fn validate_transport_host(host: &str) -> Result<(), RadrootsSimplexSmpProtoError> {
   1239     if is_valid_ipv4_transport_host(host)
   1240         || is_valid_ipv6_transport_host(host)
   1241         || is_valid_onion_transport_host(host)
   1242         || is_valid_domain_transport_host(host)
   1243     {
   1244         return Ok(());
   1245     }
   1246     Err(RadrootsSimplexSmpProtoError::InvalidHostList(
   1247         host.to_string(),
   1248     ))
   1249 }
   1250 
   1251 fn is_valid_ipv4_transport_host(host: &str) -> bool {
   1252     let mut segments = 0_usize;
   1253     for segment in host.split('.') {
   1254         if segment.is_empty() || !segment.bytes().all(|byte| byte.is_ascii_digit()) {
   1255             return false;
   1256         }
   1257         if segment.parse::<u16>().map_or(true, |value| value > 255) {
   1258             return false;
   1259         }
   1260         segments += 1;
   1261     }
   1262     segments == 4
   1263 }
   1264 
   1265 fn is_valid_ipv6_transport_host(host: &str) -> bool {
   1266     let candidate = if let Some(stripped) = host.strip_prefix('[') {
   1267         let Some(inner) = stripped.strip_suffix(']') else {
   1268             return false;
   1269         };
   1270         inner
   1271     } else {
   1272         if host.ends_with(']') {
   1273             return false;
   1274         }
   1275         host
   1276     };
   1277     if candidate.is_empty()
   1278         || !candidate
   1279             .bytes()
   1280             .all(|byte| byte.is_ascii_hexdigit() || byte == b':')
   1281     {
   1282         return false;
   1283     }
   1284     Ipv6Addr::from_str(candidate).is_ok()
   1285 }
   1286 
   1287 fn is_valid_onion_transport_host(host: &str) -> bool {
   1288     let Some(prefix) = host.strip_suffix(".onion") else {
   1289         return false;
   1290     };
   1291     !prefix.is_empty()
   1292         && prefix
   1293             .bytes()
   1294             .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit())
   1295 }
   1296 
   1297 fn is_valid_domain_transport_host(host: &str) -> bool {
   1298     !host.is_empty()
   1299         && !host.ends_with(".onion")
   1300         && !host.starts_with('[')
   1301         && !host.ends_with(']')
   1302         && !host.contains(':')
   1303         && host
   1304             .chars()
   1305             .all(|character| !matches!(character, '#' | ',' | ';' | '/' | ' ' | '\n' | '\r' | '\t'))
   1306 }
   1307 
   1308 fn encode_transmission(
   1309     transport_version: u16,
   1310     authorization: &[u8],
   1311     correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
   1312     entity_id: &[u8],
   1313     frame: &[u8],
   1314 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
   1315     let mut buffer = Vec::new();
   1316     push_short_bytes(&mut buffer, authorization)?;
   1317     if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION
   1318         && !authorization.is_empty()
   1319     {
   1320         push_maybe_short_bytes(&mut buffer, None)?;
   1321     }
   1322     push_short_bytes(
   1323         &mut buffer,
   1324         correlation_id
   1325             .map(|id| id.0.to_vec())
   1326             .as_deref()
   1327             .unwrap_or_default(),
   1328     )?;
   1329     push_short_bytes(&mut buffer, entity_id)?;
   1330     buffer.extend_from_slice(frame);
   1331     Ok(buffer)
   1332 }
   1333 
   1334 fn decode_transmission(
   1335     transport_version: u16,
   1336     bytes: &[u8],
   1337 ) -> Result<RadrootsSimplexSmpDecodedTransmission<'_>, RadrootsSimplexSmpProtoError> {
   1338     let mut cursor = Cursor::new(bytes);
   1339     let authorization = cursor.read_short_bytes()?;
   1340     if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION
   1341         && !authorization.is_empty()
   1342     {
   1343         let _ = cursor.read_maybe(Cursor::read_short_bytes)?;
   1344     }
   1345     let correlation_id = match cursor.read_short_bytes()?.as_slice() {
   1346         [] => None,
   1347         value => Some(RadrootsSimplexSmpCorrelationId::from_slice(value)?),
   1348     };
   1349     let entity_id = cursor.read_short_bytes()?;
   1350     let frame = cursor.read_remaining();
   1351     if frame.is_empty() {
   1352         return Err(RadrootsSimplexSmpProtoError::UnexpectedEof);
   1353     }
   1354     Ok((authorization, correlation_id, entity_id, frame))
   1355 }
   1356 
   1357 fn decode_send_payload(
   1358     payload: &[u8],
   1359 ) -> Result<RadrootsSimplexSmpSendCommand, RadrootsSimplexSmpProtoError> {
   1360     let Some(space_index) = payload.iter().position(|byte| *byte == b' ') else {
   1361         return Err(RadrootsSimplexSmpProtoError::UnexpectedEof);
   1362     };
   1363     let flags_bytes = &payload[..space_index];
   1364     if flags_bytes.is_empty() {
   1365         return Err(RadrootsSimplexSmpProtoError::MissingField("msg_flags"));
   1366     }
   1367     let flags = RadrootsSimplexSmpMessageFlags {
   1368         notification: decode_bool(flags_bytes[0])?,
   1369         reserved: flags_bytes[1..].to_vec(),
   1370     };
   1371     Ok(RadrootsSimplexSmpSendCommand {
   1372         flags,
   1373         message_body: payload[space_index + 1..].to_vec(),
   1374     })
   1375 }
   1376 
   1377 fn encode_error(error: &RadrootsSimplexSmpError) -> Vec<u8> {
   1378     match error {
   1379         RadrootsSimplexSmpError::Block => b"BLOCK".to_vec(),
   1380         RadrootsSimplexSmpError::Session => b"SESSION".to_vec(),
   1381         RadrootsSimplexSmpError::Command(command_error) => {
   1382             let mut bytes = b"CMD ".to_vec();
   1383             bytes.extend_from_slice(match command_error {
   1384                 RadrootsSimplexSmpCommandError::Unknown => COMMAND_ERR_UNKNOWN,
   1385                 RadrootsSimplexSmpCommandError::Syntax => COMMAND_ERR_SYNTAX,
   1386                 RadrootsSimplexSmpCommandError::Prohibited => COMMAND_ERR_PROHIBITED,
   1387                 RadrootsSimplexSmpCommandError::NoAuth => COMMAND_ERR_NO_AUTH,
   1388                 RadrootsSimplexSmpCommandError::HasAuth => COMMAND_ERR_HAS_AUTH,
   1389                 RadrootsSimplexSmpCommandError::NoEntity => COMMAND_ERR_NO_ENTITY,
   1390                 RadrootsSimplexSmpCommandError::Other(raw) => raw,
   1391             });
   1392             bytes
   1393         }
   1394         RadrootsSimplexSmpError::Proxy(proxy_error) => {
   1395             let mut bytes = b"PROXY ".to_vec();
   1396             bytes.extend_from_slice(&encode_proxy_error(proxy_error));
   1397             bytes
   1398         }
   1399         RadrootsSimplexSmpError::Auth => b"AUTH".to_vec(),
   1400         RadrootsSimplexSmpError::Blocked(blocking_info) => {
   1401             let mut bytes = b"BLOCKED ".to_vec();
   1402             bytes.extend_from_slice(&encode_blocking_info(blocking_info));
   1403             bytes
   1404         }
   1405         RadrootsSimplexSmpError::Service => b"SERVICE".to_vec(),
   1406         RadrootsSimplexSmpError::Crypto => b"CRYPTO".to_vec(),
   1407         RadrootsSimplexSmpError::Quota => b"QUOTA".to_vec(),
   1408         RadrootsSimplexSmpError::Store(store_error) => {
   1409             let mut bytes = b"STORE ".to_vec();
   1410             bytes.extend_from_slice(store_error.as_bytes());
   1411             bytes
   1412         }
   1413         RadrootsSimplexSmpError::NoMsg => b"NO_MSG".to_vec(),
   1414         RadrootsSimplexSmpError::LargeMsg => b"LARGE_MSG".to_vec(),
   1415         RadrootsSimplexSmpError::Expired => b"EXPIRED".to_vec(),
   1416         RadrootsSimplexSmpError::Internal => b"INTERNAL".to_vec(),
   1417         RadrootsSimplexSmpError::Duplicate => b"DUPLICATE_".to_vec(),
   1418         RadrootsSimplexSmpError::Other(raw) => raw.clone(),
   1419     }
   1420 }
   1421 
   1422 fn decode_error(bytes: &[u8]) -> Result<RadrootsSimplexSmpError, RadrootsSimplexSmpProtoError> {
   1423     if bytes == b"BLOCK" {
   1424         return Ok(RadrootsSimplexSmpError::Block);
   1425     }
   1426     if bytes == b"SESSION" {
   1427         return Ok(RadrootsSimplexSmpError::Session);
   1428     }
   1429     if bytes == b"AUTH" {
   1430         return Ok(RadrootsSimplexSmpError::Auth);
   1431     }
   1432     if bytes == b"SERVICE" {
   1433         return Ok(RadrootsSimplexSmpError::Service);
   1434     }
   1435     if bytes == b"CRYPTO" {
   1436         return Ok(RadrootsSimplexSmpError::Crypto);
   1437     }
   1438     if bytes == b"QUOTA" {
   1439         return Ok(RadrootsSimplexSmpError::Quota);
   1440     }
   1441     if let Some(store_error) = bytes.strip_prefix(b"STORE ") {
   1442         return Ok(RadrootsSimplexSmpError::Store(
   1443             String::from_utf8_lossy(store_error).into_owned(),
   1444         ));
   1445     }
   1446     if bytes == b"NO_MSG" {
   1447         return Ok(RadrootsSimplexSmpError::NoMsg);
   1448     }
   1449     if bytes == b"LARGE_MSG" {
   1450         return Ok(RadrootsSimplexSmpError::LargeMsg);
   1451     }
   1452     if bytes == b"EXPIRED" {
   1453         return Ok(RadrootsSimplexSmpError::Expired);
   1454     }
   1455     if bytes == b"INTERNAL" {
   1456         return Ok(RadrootsSimplexSmpError::Internal);
   1457     }
   1458     if bytes == b"DUPLICATE_" {
   1459         return Ok(RadrootsSimplexSmpError::Duplicate);
   1460     }
   1461     if let Some(command) = bytes.strip_prefix(b"CMD ") {
   1462         let command_error = match command {
   1463             COMMAND_ERR_UNKNOWN => RadrootsSimplexSmpCommandError::Unknown,
   1464             COMMAND_ERR_SYNTAX => RadrootsSimplexSmpCommandError::Syntax,
   1465             COMMAND_ERR_PROHIBITED => RadrootsSimplexSmpCommandError::Prohibited,
   1466             COMMAND_ERR_NO_AUTH => RadrootsSimplexSmpCommandError::NoAuth,
   1467             COMMAND_ERR_HAS_AUTH => RadrootsSimplexSmpCommandError::HasAuth,
   1468             COMMAND_ERR_NO_ENTITY | COMMAND_ERR_NO_QUEUE => {
   1469                 RadrootsSimplexSmpCommandError::NoEntity
   1470             }
   1471             raw => RadrootsSimplexSmpCommandError::Other(raw.to_vec()),
   1472         };
   1473         return Ok(RadrootsSimplexSmpError::Command(command_error));
   1474     }
   1475     if let Some(proxy_error) = bytes.strip_prefix(b"PROXY ") {
   1476         return Ok(RadrootsSimplexSmpError::Proxy(decode_proxy_error(
   1477             proxy_error,
   1478         )?));
   1479     }
   1480     if let Some(blocking_info) = bytes.strip_prefix(b"BLOCKED ") {
   1481         return Ok(RadrootsSimplexSmpError::Blocked(decode_blocking_info(
   1482             blocking_info,
   1483         )?));
   1484     }
   1485     Ok(RadrootsSimplexSmpError::Other(bytes.to_vec()))
   1486 }
   1487 
   1488 fn encode_proxy_error(error: &RadrootsSimplexSmpProxyError) -> Vec<u8> {
   1489     match error {
   1490         RadrootsSimplexSmpProxyError::Protocol(error) => {
   1491             let mut bytes = b"PROTOCOL ".to_vec();
   1492             bytes.extend_from_slice(&encode_error(error));
   1493             bytes
   1494         }
   1495         RadrootsSimplexSmpProxyError::Broker(error) => {
   1496             let mut bytes = b"BROKER ".to_vec();
   1497             bytes.extend_from_slice(&encode_broker_error(error));
   1498             bytes
   1499         }
   1500         RadrootsSimplexSmpProxyError::BasicAuth => b"BASIC_AUTH".to_vec(),
   1501         RadrootsSimplexSmpProxyError::NoSession => b"NO_SESSION".to_vec(),
   1502     }
   1503 }
   1504 
   1505 fn decode_proxy_error(
   1506     bytes: &[u8],
   1507 ) -> Result<RadrootsSimplexSmpProxyError, RadrootsSimplexSmpProtoError> {
   1508     let (tag, rest) = parse_tag(bytes)?;
   1509     match tag.as_slice() {
   1510         b"PROTOCOL" => Ok(RadrootsSimplexSmpProxyError::Protocol(Box::new(
   1511             decode_error(rest)?,
   1512         ))),
   1513         b"BROKER" => Ok(RadrootsSimplexSmpProxyError::Broker(decode_broker_error(
   1514             rest,
   1515         )?)),
   1516         b"BASIC_AUTH" if rest.is_empty() => Ok(RadrootsSimplexSmpProxyError::BasicAuth),
   1517         b"NO_SESSION" if rest.is_empty() => Ok(RadrootsSimplexSmpProxyError::NoSession),
   1518         _ => Err(invalid_ascii_tag(&tag)),
   1519     }
   1520 }
   1521 
   1522 fn encode_broker_error(error: &RadrootsSimplexSmpBrokerError) -> Vec<u8> {
   1523     match error {
   1524         RadrootsSimplexSmpBrokerError::Response(response_error) => {
   1525             let mut bytes = b"RESPONSE ".to_vec();
   1526             push_short_string(&mut bytes, response_error)
   1527                 .expect("response_error length is bounded by SMP short-string encoding");
   1528             bytes
   1529         }
   1530         RadrootsSimplexSmpBrokerError::Unexpected(response_error) => {
   1531             let mut bytes = b"UNEXPECTED ".to_vec();
   1532             push_short_string(&mut bytes, response_error)
   1533                 .expect("response_error length is bounded by SMP short-string encoding");
   1534             bytes
   1535         }
   1536         RadrootsSimplexSmpBrokerError::Network(_) => b"NETWORK".to_vec(),
   1537         RadrootsSimplexSmpBrokerError::Host => b"HOST".to_vec(),
   1538         RadrootsSimplexSmpBrokerError::NoService => b"NO_SERVICE".to_vec(),
   1539         RadrootsSimplexSmpBrokerError::Transport(error) => {
   1540             let mut bytes = b"TRANSPORT ".to_vec();
   1541             bytes.extend_from_slice(&encode_transport_error(error));
   1542             bytes
   1543         }
   1544         RadrootsSimplexSmpBrokerError::Timeout => b"TIMEOUT".to_vec(),
   1545     }
   1546 }
   1547 
   1548 fn decode_broker_error(
   1549     bytes: &[u8],
   1550 ) -> Result<RadrootsSimplexSmpBrokerError, RadrootsSimplexSmpProtoError> {
   1551     let (tag, rest) = parse_tag(bytes)?;
   1552     match tag.as_slice() {
   1553         b"RESPONSE" => Ok(RadrootsSimplexSmpBrokerError::Response(
   1554             decode_short_string_lossy(rest)?,
   1555         )),
   1556         b"UNEXPECTED" => Ok(RadrootsSimplexSmpBrokerError::Unexpected(
   1557             decode_short_string_lossy(rest)?,
   1558         )),
   1559         b"TRANSPORT" => Ok(RadrootsSimplexSmpBrokerError::Transport(
   1560             decode_transport_error(rest)?,
   1561         )),
   1562         b"NETWORK" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Network(
   1563             RadrootsSimplexSmpNetworkError::Failed,
   1564         )),
   1565         b"NETWORK" => Ok(RadrootsSimplexSmpBrokerError::Network(
   1566             decode_network_error(rest)?,
   1567         )),
   1568         b"TIMEOUT" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Timeout),
   1569         b"HOST" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Host),
   1570         b"NO_SERVICE" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::NoService),
   1571         _ => Err(invalid_ascii_tag(&tag)),
   1572     }
   1573 }
   1574 
   1575 fn encode_transport_error(error: &RadrootsSimplexSmpTransportError) -> Vec<u8> {
   1576     match error {
   1577         RadrootsSimplexSmpTransportError::Block => b"BLOCK".to_vec(),
   1578         RadrootsSimplexSmpTransportError::Version => b"VERSION".to_vec(),
   1579         RadrootsSimplexSmpTransportError::LargeMsg => b"LARGE_MSG".to_vec(),
   1580         RadrootsSimplexSmpTransportError::Session => b"SESSION".to_vec(),
   1581         RadrootsSimplexSmpTransportError::NoAuth => b"NO_AUTH".to_vec(),
   1582         RadrootsSimplexSmpTransportError::Handshake(error) => {
   1583             let mut bytes = b"HANDSHAKE ".to_vec();
   1584             bytes.extend_from_slice(&encode_handshake_error(error));
   1585             bytes
   1586         }
   1587     }
   1588 }
   1589 
   1590 fn decode_transport_error(
   1591     bytes: &[u8],
   1592 ) -> Result<RadrootsSimplexSmpTransportError, RadrootsSimplexSmpProtoError> {
   1593     let (tag, rest) = parse_tag(bytes)?;
   1594     match tag.as_slice() {
   1595         b"BLOCK" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Block),
   1596         b"VERSION" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Version),
   1597         b"LARGE_MSG" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::LargeMsg),
   1598         b"SESSION" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Session),
   1599         b"NO_AUTH" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::NoAuth),
   1600         b"HANDSHAKE" => Ok(RadrootsSimplexSmpTransportError::Handshake(
   1601             decode_handshake_error(rest)?,
   1602         )),
   1603         _ => Err(invalid_ascii_tag(&tag)),
   1604     }
   1605 }
   1606 
   1607 #[cfg(test)]
   1608 fn encode_network_error(error: &RadrootsSimplexSmpNetworkError) -> Vec<u8> {
   1609     match error {
   1610         RadrootsSimplexSmpNetworkError::Connect(connect_error) => {
   1611             let mut bytes = b"CONNECT ".to_vec();
   1612             push_short_string(&mut bytes, connect_error)
   1613                 .expect("connect_error length is bounded by SMP short-string encoding");
   1614             bytes
   1615         }
   1616         RadrootsSimplexSmpNetworkError::Tls(tls_error) => {
   1617             let mut bytes = b"TLS ".to_vec();
   1618             push_short_string(&mut bytes, tls_error)
   1619                 .expect("tls_error length is bounded by SMP short-string encoding");
   1620             bytes
   1621         }
   1622         RadrootsSimplexSmpNetworkError::UnknownCa => b"UNKNOWNCA".to_vec(),
   1623         RadrootsSimplexSmpNetworkError::Failed => b"FAILED".to_vec(),
   1624         RadrootsSimplexSmpNetworkError::Timeout => b"TIMEOUT".to_vec(),
   1625         RadrootsSimplexSmpNetworkError::Subscribe(subscribe_error) => {
   1626             let mut bytes = b"SUBSCRIBE ".to_vec();
   1627             push_short_string(&mut bytes, subscribe_error)
   1628                 .expect("subscribe_error length is bounded by SMP short-string encoding");
   1629             bytes
   1630         }
   1631     }
   1632 }
   1633 
   1634 fn decode_network_error(
   1635     bytes: &[u8],
   1636 ) -> Result<RadrootsSimplexSmpNetworkError, RadrootsSimplexSmpProtoError> {
   1637     let (tag, rest) = parse_tag(bytes)?;
   1638     match tag.as_slice() {
   1639         b"CONNECT" => Ok(RadrootsSimplexSmpNetworkError::Connect(
   1640             decode_short_string_lossy(rest)?,
   1641         )),
   1642         b"TLS" => Ok(RadrootsSimplexSmpNetworkError::Tls(
   1643             decode_short_string_lossy(rest)?,
   1644         )),
   1645         b"UNKNOWNCA" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::UnknownCa),
   1646         b"FAILED" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::Failed),
   1647         b"TIMEOUT" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::Timeout),
   1648         b"SUBSCRIBE" => Ok(RadrootsSimplexSmpNetworkError::Subscribe(
   1649             decode_short_string_lossy(rest)?,
   1650         )),
   1651         _ => Err(invalid_ascii_tag(&tag)),
   1652     }
   1653 }
   1654 
   1655 fn encode_handshake_error(error: &RadrootsSimplexSmpHandshakeError) -> Vec<u8> {
   1656     match error {
   1657         RadrootsSimplexSmpHandshakeError::Parse => b"PARSE".to_vec(),
   1658         RadrootsSimplexSmpHandshakeError::Identity => b"IDENTITY".to_vec(),
   1659         RadrootsSimplexSmpHandshakeError::BadAuth => b"BAD_AUTH".to_vec(),
   1660         RadrootsSimplexSmpHandshakeError::BadService => b"BAD_SERVICE".to_vec(),
   1661         RadrootsSimplexSmpHandshakeError::Other(raw) => raw.as_bytes().to_vec(),
   1662     }
   1663 }
   1664 
   1665 fn decode_handshake_error(
   1666     bytes: &[u8],
   1667 ) -> Result<RadrootsSimplexSmpHandshakeError, RadrootsSimplexSmpProtoError> {
   1668     match bytes {
   1669         b"PARSE" => Ok(RadrootsSimplexSmpHandshakeError::Parse),
   1670         b"IDENTITY" => Ok(RadrootsSimplexSmpHandshakeError::Identity),
   1671         b"BAD_AUTH" => Ok(RadrootsSimplexSmpHandshakeError::BadAuth),
   1672         b"BAD_SERVICE" => Ok(RadrootsSimplexSmpHandshakeError::BadService),
   1673         raw => Err(invalid_ascii_tag(raw)),
   1674     }
   1675 }
   1676 
   1677 fn encode_blocking_info(info: &RadrootsSimplexSmpBlockingInfo) -> Vec<u8> {
   1678     let mut bytes = b"reason=".to_vec();
   1679     bytes.extend_from_slice(match &info.reason {
   1680         RadrootsSimplexSmpBlockingReason::Spam => b"spam",
   1681         RadrootsSimplexSmpBlockingReason::Content => b"content",
   1682         RadrootsSimplexSmpBlockingReason::Other(reason) => reason.as_bytes(),
   1683     });
   1684     bytes
   1685 }
   1686 
   1687 fn decode_blocking_info(
   1688     bytes: &[u8],
   1689 ) -> Result<RadrootsSimplexSmpBlockingInfo, RadrootsSimplexSmpProtoError> {
   1690     let Some(reason) = bytes.strip_prefix(b"reason=") else {
   1691         return Err(invalid_ascii_tag(bytes));
   1692     };
   1693     let reason = match reason {
   1694         b"spam" => RadrootsSimplexSmpBlockingReason::Spam,
   1695         b"content" => RadrootsSimplexSmpBlockingReason::Content,
   1696         raw => return Err(invalid_ascii_tag(raw)),
   1697     };
   1698     Ok(RadrootsSimplexSmpBlockingInfo { reason })
   1699 }
   1700 
   1701 fn decode_short_string_lossy(bytes: &[u8]) -> Result<String, RadrootsSimplexSmpProtoError> {
   1702     let mut cursor = Cursor::new(bytes);
   1703     let value = cursor.read_short_string_lossy()?;
   1704     if !cursor.is_empty() {
   1705         return Err(RadrootsSimplexSmpProtoError::TrailingBytes);
   1706     }
   1707     Ok(value)
   1708 }
   1709 
   1710 fn invalid_ascii_tag(bytes: &[u8]) -> RadrootsSimplexSmpProtoError {
   1711     RadrootsSimplexSmpProtoError::InvalidTag(String::from_utf8_lossy(bytes).into_owned())
   1712 }
   1713 
   1714 fn parse_tag(bytes: &[u8]) -> Result<(Vec<u8>, &[u8]), RadrootsSimplexSmpProtoError> {
   1715     if bytes.is_empty() {
   1716         return Err(RadrootsSimplexSmpProtoError::UnexpectedEof);
   1717     }
   1718     if let Some(space_index) = bytes.iter().position(|byte| *byte == b' ') {
   1719         Ok((bytes[..space_index].to_vec(), &bytes[space_index + 1..]))
   1720     } else {
   1721         Ok((bytes.to_vec(), &[]))
   1722     }
   1723 }
   1724 
   1725 fn encode_subscription_mode(mode: RadrootsSimplexSmpSubscriptionMode) -> u8 {
   1726     match mode {
   1727         RadrootsSimplexSmpSubscriptionMode::Subscribe => b'S',
   1728         RadrootsSimplexSmpSubscriptionMode::OnlyCreate => b'C',
   1729     }
   1730 }
   1731 
   1732 fn decode_subscription_mode(
   1733     value: u8,
   1734 ) -> Result<RadrootsSimplexSmpSubscriptionMode, RadrootsSimplexSmpProtoError> {
   1735     match value {
   1736         b'S' => Ok(RadrootsSimplexSmpSubscriptionMode::Subscribe),
   1737         b'C' => Ok(RadrootsSimplexSmpSubscriptionMode::OnlyCreate),
   1738         _ => Err(RadrootsSimplexSmpProtoError::InvalidTag(
   1739             String::from_utf8_lossy(&[value]).into_owned(),
   1740         )),
   1741     }
   1742 }
   1743 
   1744 fn encode_bool(value: bool) -> u8 {
   1745     if value { b'T' } else { b'F' }
   1746 }
   1747 
   1748 fn decode_bool(value: u8) -> Result<bool, RadrootsSimplexSmpProtoError> {
   1749     match value {
   1750         b'T' => Ok(true),
   1751         b'F' => Ok(false),
   1752         other => Err(RadrootsSimplexSmpProtoError::InvalidBoolEncoding(other)),
   1753     }
   1754 }
   1755 
   1756 fn push_i64(buffer: &mut Vec<u8>, value: i64) {
   1757     buffer.extend_from_slice(&value.to_be_bytes());
   1758 }
   1759 
   1760 fn push_short_bytes(
   1761     buffer: &mut Vec<u8>,
   1762     bytes: &[u8],
   1763 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1764     let len = u8::try_from(bytes.len())
   1765         .map_err(|_| RadrootsSimplexSmpProtoError::InvalidShortFieldLength(bytes.len()))?;
   1766     buffer.push(len);
   1767     buffer.extend_from_slice(bytes);
   1768     Ok(())
   1769 }
   1770 
   1771 fn push_short_string(
   1772     buffer: &mut Vec<u8>,
   1773     value: &str,
   1774 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1775     push_short_bytes(buffer, value.as_bytes())
   1776 }
   1777 
   1778 fn push_large_bytes(
   1779     buffer: &mut Vec<u8>,
   1780     bytes: &[u8],
   1781 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1782     let len = u16::try_from(bytes.len())
   1783         .map_err(|_| RadrootsSimplexSmpProtoError::InvalidLargeFieldLength(bytes.len()))?;
   1784     buffer.extend_from_slice(&len.to_be_bytes());
   1785     buffer.extend_from_slice(bytes);
   1786     Ok(())
   1787 }
   1788 
   1789 fn push_short_key_list(
   1790     buffer: &mut Vec<u8>,
   1791     keys: &RadrootsSimplexSmpKeyList,
   1792 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1793     let len = 1 + keys.rest.len();
   1794     let len =
   1795         u8::try_from(len).map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(len))?;
   1796     buffer.push(len);
   1797     push_short_bytes(buffer, &keys.first)?;
   1798     for key in &keys.rest {
   1799         push_short_bytes(buffer, key)?;
   1800     }
   1801     Ok(())
   1802 }
   1803 
   1804 fn push_short_string_list(
   1805     buffer: &mut Vec<u8>,
   1806     values: &[String],
   1807 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1808     if values.is_empty() {
   1809         return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0));
   1810     }
   1811     let len = u8::try_from(values.len())
   1812         .map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(values.len()))?;
   1813     buffer.push(len);
   1814     for value in values {
   1815         push_short_string(buffer, value)?;
   1816     }
   1817     Ok(())
   1818 }
   1819 
   1820 fn push_large_bytes_list(
   1821     buffer: &mut Vec<u8>,
   1822     values: &[Vec<u8>],
   1823 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1824     if values.is_empty() {
   1825         return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0));
   1826     }
   1827     let len = u8::try_from(values.len())
   1828         .map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(values.len()))?;
   1829     buffer.push(len);
   1830     for value in values {
   1831         push_large_bytes(buffer, value)?;
   1832     }
   1833     Ok(())
   1834 }
   1835 
   1836 fn push_maybe<T, F>(
   1837     buffer: &mut Vec<u8>,
   1838     value: Option<T>,
   1839     mut encode: F,
   1840 ) -> Result<(), RadrootsSimplexSmpProtoError>
   1841 where
   1842     T: Copy,
   1843     F: FnMut(&mut Vec<u8>, T) -> Result<(), RadrootsSimplexSmpProtoError>,
   1844 {
   1845     match value {
   1846         None => {
   1847             buffer.push(b'0');
   1848             Ok(())
   1849         }
   1850         Some(value) => {
   1851             buffer.push(b'1');
   1852             encode(buffer, value)
   1853         }
   1854     }
   1855 }
   1856 
   1857 fn push_maybe_short_bytes(
   1858     buffer: &mut Vec<u8>,
   1859     value: Option<&[u8]>,
   1860 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1861     push_maybe(buffer, value, push_short_bytes)
   1862 }
   1863 
   1864 fn push_maybe_string(
   1865     buffer: &mut Vec<u8>,
   1866     value: Option<&str>,
   1867 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1868     match value {
   1869         None => {
   1870             buffer.push(b'0');
   1871             Ok(())
   1872         }
   1873         Some(value) => {
   1874             validate_basic_auth(value)?;
   1875             buffer.push(b'1');
   1876             push_short_bytes(buffer, value.as_bytes())
   1877         }
   1878     }
   1879 }
   1880 
   1881 fn push_legacy_basic_auth(
   1882     buffer: &mut Vec<u8>,
   1883     value: Option<&str>,
   1884 ) -> Result<(), RadrootsSimplexSmpProtoError> {
   1885     match value {
   1886         None => Ok(()),
   1887         Some(value) => {
   1888             validate_basic_auth(value)?;
   1889             buffer.push(b'A');
   1890             push_short_bytes(buffer, value.as_bytes())
   1891         }
   1892     }
   1893 }
   1894 
   1895 fn validate_basic_auth(value: &str) -> Result<(), RadrootsSimplexSmpProtoError> {
   1896     if value
   1897         .bytes()
   1898         .all(|byte| byte.is_ascii_graphic() && byte != b'@' && byte != b':' && byte != b'/')
   1899     {
   1900         Ok(())
   1901     } else {
   1902         Err(RadrootsSimplexSmpProtoError::InvalidUri(value.to_string()))
   1903     }
   1904 }
   1905 
   1906 struct Cursor<'a> {
   1907     bytes: &'a [u8],
   1908     offset: usize,
   1909 }
   1910 
   1911 impl<'a> Cursor<'a> {
   1912     const fn new(bytes: &'a [u8]) -> Self {
   1913         Self { bytes, offset: 0 }
   1914     }
   1915 
   1916     fn is_empty(&self) -> bool {
   1917         self.offset >= self.bytes.len()
   1918     }
   1919 
   1920     fn remaining_len(&self) -> usize {
   1921         self.bytes.len().saturating_sub(self.offset)
   1922     }
   1923 
   1924     fn read_byte(&mut self) -> Result<u8, RadrootsSimplexSmpProtoError> {
   1925         let byte = *self
   1926             .bytes
   1927             .get(self.offset)
   1928             .ok_or(RadrootsSimplexSmpProtoError::UnexpectedEof)?;
   1929         self.offset += 1;
   1930         Ok(byte)
   1931     }
   1932 
   1933     fn read_exact(&mut self, len: usize) -> Result<&'a [u8], RadrootsSimplexSmpProtoError> {
   1934         let end = self.offset + len;
   1935         let value = self
   1936             .bytes
   1937             .get(self.offset..end)
   1938             .ok_or(RadrootsSimplexSmpProtoError::UnexpectedEof)?;
   1939         self.offset = end;
   1940         Ok(value)
   1941     }
   1942 
   1943     fn read_array<const N: usize>(&mut self) -> Result<[u8; N], RadrootsSimplexSmpProtoError> {
   1944         let mut array = [0_u8; N];
   1945         array.copy_from_slice(self.read_exact(N)?);
   1946         Ok(array)
   1947     }
   1948 
   1949     fn read_short_bytes(&mut self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
   1950         let len = usize::from(self.read_byte()?);
   1951         Ok(self.read_exact(len)?.to_vec())
   1952     }
   1953 
   1954     fn read_short_string(&mut self) -> Result<String, RadrootsSimplexSmpProtoError> {
   1955         String::from_utf8(self.read_short_bytes()?)
   1956             .map_err(|error| RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string()))
   1957     }
   1958 
   1959     fn read_short_string_lossy(&mut self) -> Result<String, RadrootsSimplexSmpProtoError> {
   1960         Ok(String::from_utf8_lossy(&self.read_short_bytes()?).into_owned())
   1961     }
   1962 
   1963     fn read_short_key_list(
   1964         &mut self,
   1965     ) -> Result<RadrootsSimplexSmpKeyList, RadrootsSimplexSmpProtoError> {
   1966         let len = usize::from(self.read_byte()?);
   1967         if len == 0 {
   1968             return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0));
   1969         }
   1970         let first = self.read_short_bytes()?;
   1971         let mut rest = Vec::with_capacity(len.saturating_sub(1));
   1972         for _ in 1..len {
   1973             rest.push(self.read_short_bytes()?);
   1974         }
   1975         Ok(RadrootsSimplexSmpKeyList { first, rest })
   1976     }
   1977 
   1978     fn read_short_string_list(&mut self) -> Result<Vec<String>, RadrootsSimplexSmpProtoError> {
   1979         let len = usize::from(self.read_byte()?);
   1980         if len == 0 {
   1981             return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0));
   1982         }
   1983         let mut values = Vec::with_capacity(len);
   1984         for _ in 0..len {
   1985             values.push(self.read_short_string()?);
   1986         }
   1987         Ok(values)
   1988     }
   1989 
   1990     fn read_large_bytes(&mut self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> {
   1991         let len = usize::from(u16::from_be_bytes(self.read_array::<2>()?));
   1992         Ok(self.read_exact(len)?.to_vec())
   1993     }
   1994 
   1995     fn read_large_bytes_list(&mut self) -> Result<Vec<Vec<u8>>, RadrootsSimplexSmpProtoError> {
   1996         let len = usize::from(self.read_byte()?);
   1997         if len == 0 {
   1998             return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0));
   1999         }
   2000         let mut values = Vec::with_capacity(len);
   2001         for _ in 0..len {
   2002             values.push(self.read_large_bytes()?);
   2003         }
   2004         Ok(values)
   2005     }
   2006 
   2007     fn read_i64(&mut self) -> Result<i64, RadrootsSimplexSmpProtoError> {
   2008         Ok(i64::from_be_bytes(self.read_array::<8>()?))
   2009     }
   2010 
   2011     fn read_maybe_string(&mut self) -> Result<Option<String>, RadrootsSimplexSmpProtoError> {
   2012         self.read_maybe(|cursor| {
   2013             let value = cursor.read_short_bytes()?;
   2014             let string = String::from_utf8(value)
   2015                 .map_err(|error| RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string()))?;
   2016             validate_basic_auth(&string)?;
   2017             Ok(string)
   2018         })
   2019     }
   2020 
   2021     fn read_legacy_basic_auth(&mut self) -> Result<Option<String>, RadrootsSimplexSmpProtoError> {
   2022         match self.bytes.get(self.offset).copied() {
   2023             Some(b'A') => {
   2024                 self.offset += 1;
   2025                 let value = self.read_short_bytes()?;
   2026                 let string = String::from_utf8(value).map_err(|error| {
   2027                     RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string())
   2028                 })?;
   2029                 validate_basic_auth(&string)?;
   2030                 Ok(Some(string))
   2031             }
   2032             Some(_) => Ok(None),
   2033             None => Err(RadrootsSimplexSmpProtoError::UnexpectedEof),
   2034         }
   2035     }
   2036 
   2037     fn read_maybe<T, F>(&mut self, decode: F) -> Result<Option<T>, RadrootsSimplexSmpProtoError>
   2038     where
   2039         F: FnOnce(&mut Self) -> Result<T, RadrootsSimplexSmpProtoError>,
   2040     {
   2041         match self.read_byte()? {
   2042             b'0' => Ok(None),
   2043             b'1' => Ok(Some(decode(self)?)),
   2044             other => Err(RadrootsSimplexSmpProtoError::InvalidMaybeTag(other)),
   2045         }
   2046     }
   2047 
   2048     fn read_remaining(&mut self) -> &'a [u8] {
   2049         let remaining = &self.bytes[self.offset..];
   2050         self.offset = self.bytes.len();
   2051         remaining
   2052     }
   2053 }
   2054 
   2055 #[cfg(test)]
   2056 mod tests {
   2057     use super::*;
   2058 
   2059     fn correlation_id(byte: u8) -> RadrootsSimplexSmpCorrelationId {
   2060         RadrootsSimplexSmpCorrelationId::new([byte; 24])
   2061     }
   2062 
   2063     #[test]
   2064     fn round_trips_current_new_command_transmission() {
   2065         let transmission = RadrootsSimplexSmpCommandTransmission {
   2066             authorization: vec![1, 2, 3],
   2067             correlation_id: Some(correlation_id(7)),
   2068             entity_id: Vec::new(),
   2069             command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2070                 recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2071                 recipient_dh_public_key: vec![0x04, 0x05],
   2072                 basic_auth: Some("server-pass".to_string()),
   2073                 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2074                 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some(
   2075                     RadrootsSimplexSmpMessagingQueueRequest {
   2076                         sender_id: vec![0x10, 0x11],
   2077                         link_data: RadrootsSimplexSmpQueueLinkData {
   2078                             fixed_data: vec![0xaa, 0xbb],
   2079                             user_data: vec![0xcc, 0xdd, 0xee],
   2080                         },
   2081                     },
   2082                 ))),
   2083                 notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials {
   2084                     notifier_auth_public_key: vec![0x21, 0x22],
   2085                     recipient_notification_dh_public_key: vec![0x23, 0x24],
   2086                 }),
   2087             }),
   2088         };
   2089 
   2090         let encoded = transmission.encode().unwrap();
   2091         let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap();
   2092         assert_eq!(decoded, transmission);
   2093     }
   2094 
   2095     #[test]
   2096     fn round_trips_v9_new_command_transmission() {
   2097         let transmission = RadrootsSimplexSmpCommandTransmission {
   2098             authorization: vec![1, 2, 3],
   2099             correlation_id: Some(correlation_id(7)),
   2100             entity_id: Vec::new(),
   2101             command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2102                 recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2103                 recipient_dh_public_key: vec![0x04, 0x05],
   2104                 basic_auth: Some("server-pass".to_string()),
   2105                 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2106                 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)),
   2107                 notifier_credentials: None,
   2108             }),
   2109         };
   2110 
   2111         let encoded = transmission
   2112             .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION)
   2113             .unwrap();
   2114         let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version(
   2115             RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION,
   2116             &encoded,
   2117         )
   2118         .unwrap();
   2119         assert_eq!(decoded, transmission);
   2120     }
   2121 
   2122     #[test]
   2123     fn round_trips_v6_new_command_transmission() {
   2124         let transmission = RadrootsSimplexSmpCommandTransmission {
   2125             authorization: vec![1, 2, 3],
   2126             correlation_id: Some(correlation_id(7)),
   2127             entity_id: Vec::new(),
   2128             command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2129                 recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2130                 recipient_dh_public_key: vec![0x04, 0x05],
   2131                 basic_auth: Some("server-pass".to_string()),
   2132                 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2133                 queue_request_data: None,
   2134                 notifier_credentials: None,
   2135             }),
   2136         };
   2137 
   2138         let encoded = transmission
   2139             .encode_for_version(RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION)
   2140             .unwrap();
   2141         let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version(
   2142             RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION,
   2143             &encoded,
   2144         )
   2145         .unwrap();
   2146         assert_eq!(decoded, transmission);
   2147     }
   2148 
   2149     #[test]
   2150     fn round_trips_send_command_transmission() {
   2151         let transmission = RadrootsSimplexSmpCommandTransmission {
   2152             authorization: Vec::new(),
   2153             correlation_id: Some(correlation_id(9)),
   2154             entity_id: vec![0xaa, 0xbb],
   2155             command: RadrootsSimplexSmpCommand::Send(RadrootsSimplexSmpSendCommand {
   2156                 flags: RadrootsSimplexSmpMessageFlags {
   2157                     notification: true,
   2158                     reserved: b"0".to_vec(),
   2159                 },
   2160                 message_body: vec![0xde, 0xad, 0xbe, 0xef],
   2161             }),
   2162         };
   2163 
   2164         let encoded = transmission.encode().unwrap();
   2165         let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap();
   2166         assert_eq!(decoded, transmission);
   2167     }
   2168 
   2169     #[test]
   2170     fn round_trips_v15_new_command_transmission() {
   2171         let transmission = RadrootsSimplexSmpCommandTransmission {
   2172             authorization: vec![1, 2, 3],
   2173             correlation_id: Some(correlation_id(7)),
   2174             entity_id: Vec::new(),
   2175             command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2176                 recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2177                 recipient_dh_public_key: vec![0x04, 0x05],
   2178                 basic_auth: Some("server-pass".to_string()),
   2179                 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2180                 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some(
   2181                     RadrootsSimplexSmpMessagingQueueRequest {
   2182                         sender_id: vec![0x10, 0x11],
   2183                         link_data: RadrootsSimplexSmpQueueLinkData {
   2184                             fixed_data: vec![0xaa, 0xbb],
   2185                             user_data: vec![0xcc, 0xdd, 0xee],
   2186                         },
   2187                     },
   2188                 ))),
   2189                 notifier_credentials: None,
   2190             }),
   2191         };
   2192 
   2193         let encoded = transmission
   2194             .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION)
   2195             .unwrap();
   2196         let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version(
   2197             RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION,
   2198             &encoded,
   2199         )
   2200         .unwrap();
   2201         assert_eq!(decoded, transmission);
   2202     }
   2203 
   2204     #[test]
   2205     fn current_authenticated_transmission_encodes_absent_service_signature_as_maybe_none() {
   2206         let transmission = RadrootsSimplexSmpCommandTransmission {
   2207             authorization: vec![1, 2, 3],
   2208             correlation_id: Some(correlation_id(7)),
   2209             entity_id: Vec::new(),
   2210             command: RadrootsSimplexSmpCommand::Ping,
   2211         };
   2212 
   2213         let encoded = transmission.encode().unwrap();
   2214         assert_eq!(encoded[0], 3);
   2215         assert_eq!(&encoded[1..4], &[1, 2, 3]);
   2216         assert_eq!(encoded[4], b'0');
   2217 
   2218         let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap();
   2219         assert_eq!(decoded, transmission);
   2220     }
   2221 
   2222     #[test]
   2223     fn round_trips_current_ids_broker_transmission() {
   2224         let transmission = RadrootsSimplexSmpBrokerTransmission {
   2225             authorization: Vec::new(),
   2226             correlation_id: Some(correlation_id(3)),
   2227             entity_id: Vec::new(),
   2228             message: RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse {
   2229                 recipient_id: vec![0x10],
   2230                 sender_id: vec![0x11],
   2231                 server_dh_public_key: vec![0x12, 0x13],
   2232                 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging),
   2233                 link_id: Some(vec![0x14, 0x15]),
   2234                 service_id: Some(vec![0x16, 0x17]),
   2235                 server_notification_credentials: Some(
   2236                     RadrootsSimplexSmpServerNotifierCredentials {
   2237                         notifier_id: vec![0x18, 0x19],
   2238                         server_notification_dh_public_key: vec![0x1a, 0x1b],
   2239                     },
   2240                 ),
   2241             }),
   2242         };
   2243 
   2244         let encoded = transmission.encode().unwrap();
   2245         let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap();
   2246         assert_eq!(decoded, transmission);
   2247     }
   2248 
   2249     #[test]
   2250     fn round_trips_v9_ids_broker_transmission() {
   2251         let transmission = RadrootsSimplexSmpBrokerTransmission {
   2252             authorization: Vec::new(),
   2253             correlation_id: Some(correlation_id(3)),
   2254             entity_id: Vec::new(),
   2255             message: RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse {
   2256                 recipient_id: vec![0x10],
   2257                 sender_id: vec![0x11],
   2258                 server_dh_public_key: vec![0x12, 0x13],
   2259                 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging),
   2260                 link_id: None,
   2261                 service_id: None,
   2262                 server_notification_credentials: None,
   2263             }),
   2264         };
   2265 
   2266         let encoded = transmission
   2267             .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION)
   2268             .unwrap();
   2269         let decoded = RadrootsSimplexSmpBrokerTransmission::decode_for_version(
   2270             RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION,
   2271             &encoded,
   2272         )
   2273         .unwrap();
   2274         assert_eq!(decoded, transmission);
   2275     }
   2276 
   2277     #[test]
   2278     fn round_trips_error_broker_transmission() {
   2279         let transmission = RadrootsSimplexSmpBrokerTransmission {
   2280             authorization: Vec::new(),
   2281             correlation_id: Some(correlation_id(5)),
   2282             entity_id: vec![0x01],
   2283             message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Command(
   2284                 RadrootsSimplexSmpCommandError::Prohibited,
   2285             )),
   2286         };
   2287 
   2288         let encoded = transmission.encode().unwrap();
   2289         let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap();
   2290         assert_eq!(decoded, transmission);
   2291     }
   2292 
   2293     #[test]
   2294     fn round_trips_message_notification() {
   2295         let transmission = RadrootsSimplexSmpBrokerTransmission {
   2296             authorization: Vec::new(),
   2297             correlation_id: None,
   2298             entity_id: vec![0x99],
   2299             message: RadrootsSimplexSmpBrokerMessage::NMsg {
   2300                 nonce: [0x22; 24],
   2301                 encrypted_metadata: vec![0x33, 0x44, 0x55],
   2302             },
   2303         };
   2304 
   2305         let encoded = transmission.encode().unwrap();
   2306         let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap();
   2307         assert_eq!(decoded, transmission);
   2308     }
   2309 
   2310     #[test]
   2311     fn v6_new_command_uses_legacy_basic_auth_layout() {
   2312         let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2313             recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2314             recipient_dh_public_key: vec![0x04, 0x05],
   2315             basic_auth: Some("server-pass".to_string()),
   2316             subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2317             queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)),
   2318             notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials {
   2319                 notifier_auth_public_key: vec![0x21, 0x22],
   2320                 recipient_notification_dh_public_key: vec![0x23, 0x24],
   2321             }),
   2322         });
   2323 
   2324         let encoded = command
   2325             .encode_for_version(RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION)
   2326             .unwrap();
   2327 
   2328         assert_eq!(
   2329             encoded,
   2330             b"NEW \x03\x01\x02\x03\x02\x04\x05A\x0bserver-passS".to_vec()
   2331         );
   2332     }
   2333 
   2334     #[test]
   2335     fn v9_new_matches_official_sender_secure_layout() {
   2336         let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2337             recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2338             recipient_dh_public_key: vec![0x04, 0x05],
   2339             basic_auth: Some("server-pass".to_string()),
   2340             subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2341             queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)),
   2342             notifier_credentials: None,
   2343         });
   2344 
   2345         let encoded = command
   2346             .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION)
   2347             .unwrap();
   2348 
   2349         assert_eq!(
   2350             encoded,
   2351             b"NEW \x03\x01\x02\x03\x02\x04\x051\x0bserver-passST".to_vec()
   2352         );
   2353     }
   2354 
   2355     #[test]
   2356     fn v15_new_matches_official_short_link_layout() {
   2357         let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest {
   2358             recipient_auth_public_key: vec![0x01, 0x02, 0x03],
   2359             recipient_dh_public_key: vec![0x04, 0x05],
   2360             basic_auth: Some("server-pass".to_string()),
   2361             subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe,
   2362             queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some(
   2363                 RadrootsSimplexSmpMessagingQueueRequest {
   2364                     sender_id: vec![0x10, 0x11],
   2365                     link_data: RadrootsSimplexSmpQueueLinkData {
   2366                         fixed_data: vec![0xaa, 0xbb],
   2367                         user_data: vec![0xcc, 0xdd, 0xee],
   2368                     },
   2369                 },
   2370             ))),
   2371             notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials {
   2372                 notifier_auth_public_key: vec![0x21, 0x22],
   2373                 recipient_notification_dh_public_key: vec![0x23, 0x24],
   2374             }),
   2375         });
   2376 
   2377         let encoded = command
   2378             .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION)
   2379             .unwrap();
   2380 
   2381         assert_eq!(
   2382             encoded,
   2383             b"NEW \x03\x01\x02\x03\x02\x04\x051\x0bserver-passS1M1\x02\x10\x11\x00\x02\xaa\xbb\x00\x03\xcc\xdd\xee"
   2384                 .to_vec()
   2385         );
   2386     }
   2387 
   2388     #[test]
   2389     fn v17_ids_matches_official_notifier_layout() {
   2390         let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse {
   2391             recipient_id: vec![0x10],
   2392             sender_id: vec![0x11],
   2393             server_dh_public_key: vec![0x12, 0x13],
   2394             queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging),
   2395             link_id: Some(vec![0x14, 0x15]),
   2396             service_id: Some(vec![0x16, 0x17]),
   2397             server_notification_credentials: Some(RadrootsSimplexSmpServerNotifierCredentials {
   2398                 notifier_id: vec![0x18, 0x19],
   2399                 server_notification_dh_public_key: vec![0x1a, 0x1b],
   2400             }),
   2401         });
   2402 
   2403         let encoded = response.encode().unwrap();
   2404 
   2405         assert_eq!(
   2406             encoded,
   2407             b"IDS \x01\x10\x01\x11\x02\x12\x131M1\x02\x14\x151\x02\x16\x171\x02\x18\x19\x02\x1a\x1b"
   2408                 .to_vec()
   2409         );
   2410     }
   2411 
   2412     #[test]
   2413     fn v15_ids_matches_official_short_link_layout() {
   2414         let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse {
   2415             recipient_id: vec![0x10],
   2416             sender_id: vec![0x11],
   2417             server_dh_public_key: vec![0x12, 0x13],
   2418             queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging),
   2419             link_id: Some(vec![0x14, 0x15]),
   2420             service_id: Some(vec![0x16, 0x17]),
   2421             server_notification_credentials: None,
   2422         });
   2423 
   2424         let encoded = response
   2425             .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION)
   2426             .unwrap();
   2427 
   2428         assert_eq!(
   2429             encoded,
   2430             b"IDS \x01\x10\x01\x11\x02\x12\x131M1\x02\x14\x15".to_vec()
   2431         );
   2432     }
   2433 
   2434     #[test]
   2435     fn v9_ids_matches_official_sender_secure_layout() {
   2436         let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse {
   2437             recipient_id: vec![0x10],
   2438             sender_id: vec![0x11],
   2439             server_dh_public_key: vec![0x12, 0x13],
   2440             queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging),
   2441             link_id: Some(vec![0x14, 0x15]),
   2442             service_id: Some(vec![0x16, 0x17]),
   2443             server_notification_credentials: None,
   2444         });
   2445 
   2446         let encoded = response
   2447             .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION)
   2448             .unwrap();
   2449 
   2450         assert_eq!(encoded, b"IDS \x01\x10\x01\x11\x02\x12\x13T".to_vec());
   2451     }
   2452 
   2453     #[test]
   2454     fn prxy_matches_official_proxy_session_layout() {
   2455         let command = RadrootsSimplexSmpCommand::Prxy {
   2456             server: RadrootsSimplexSmpProtocolServer {
   2457                 hosts: vec![
   2458                     "smp4.simplex.im".to_string(),
   2459                     "simplexabc.onion".to_string(),
   2460                 ],
   2461                 port: "5223".to_string(),
   2462                 key_hash: vec![0xaa, 0xbb, 0xcc],
   2463             },
   2464             basic_auth: Some("relay-pass".to_string()),
   2465         };
   2466 
   2467         let encoded = command.encode().unwrap();
   2468 
   2469         assert_eq!(
   2470             encoded,
   2471             b"PRXY \x02\x0fsmp4.simplex.im\x10simplexabc.onion\x045223\x03\xaa\xbb\xcc1\x0arelay-pass"
   2472                 .to_vec()
   2473         );
   2474     }
   2475 
   2476     #[test]
   2477     fn pkey_matches_official_proxy_session_key_layout() {
   2478         let message = RadrootsSimplexSmpBrokerMessage::PKey {
   2479             session_id: vec![0x31, 0x32],
   2480             version_range: RadrootsSimplexSmpVersionRange::new(8, 16).unwrap(),
   2481             cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey {
   2482                 certificate_chain: vec![vec![0x41, 0x42], vec![0x43, 0x44, 0x45]],
   2483                 signed_public_key: vec![0x51, 0x52, 0x53],
   2484             },
   2485         };
   2486 
   2487         let encoded = message.encode().unwrap();
   2488 
   2489         assert_eq!(
   2490             encoded,
   2491             b"PKEY \x0212\x00\x08\x00\x10\x02\x00\x02AB\x00\x03CDE\x00\x03QRS".to_vec()
   2492         );
   2493     }
   2494 
   2495     #[test]
   2496     fn proxy_transport_error_matches_official_nested_error_layout() {
   2497         let encoded = RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Proxy(
   2498             RadrootsSimplexSmpProxyError::Broker(RadrootsSimplexSmpBrokerError::Transport(
   2499                 RadrootsSimplexSmpTransportError::Handshake(
   2500                     RadrootsSimplexSmpHandshakeError::Identity,
   2501                 ),
   2502             )),
   2503         ))
   2504         .encode()
   2505         .unwrap();
   2506 
   2507         assert_eq!(
   2508             encoded,
   2509             b"ERR PROXY BROKER TRANSPORT HANDSHAKE IDENTITY".to_vec()
   2510         );
   2511     }
   2512 
   2513     #[test]
   2514     fn round_trips_proxy_and_short_link_commands() {
   2515         let prxy = RadrootsSimplexSmpCommandTransmission {
   2516             authorization: Vec::new(),
   2517             correlation_id: Some(correlation_id(1)),
   2518             entity_id: Vec::new(),
   2519             command: RadrootsSimplexSmpCommand::Prxy {
   2520                 server: RadrootsSimplexSmpProtocolServer {
   2521                     hosts: vec![
   2522                         "smp4.simplex.im".to_string(),
   2523                         "simplexabc.onion".to_string(),
   2524                     ],
   2525                     port: "5223".to_string(),
   2526                     key_hash: vec![0xaa, 0xbb, 0xcc],
   2527                 },
   2528                 basic_auth: Some("relay-pass".to_string()),
   2529             },
   2530         };
   2531 
   2532         let rkey = RadrootsSimplexSmpCommandTransmission {
   2533             authorization: vec![0x42],
   2534             correlation_id: Some(correlation_id(2)),
   2535             entity_id: vec![0x11],
   2536             command: RadrootsSimplexSmpCommand::RKey(RadrootsSimplexSmpKeyList {
   2537                 first: vec![0x01, 0x02],
   2538                 rest: vec![vec![0x03, 0x04], vec![0x05, 0x06]],
   2539             }),
   2540         };
   2541 
   2542         let pkey_encoded = prxy.encode().unwrap();
   2543         let pkey_decoded = RadrootsSimplexSmpCommandTransmission::decode(&pkey_encoded).unwrap();
   2544         assert_eq!(pkey_decoded, prxy);
   2545 
   2546         let rkey_encoded = rkey.encode().unwrap();
   2547         let rkey_decoded = RadrootsSimplexSmpCommandTransmission::decode(&rkey_encoded).unwrap();
   2548         assert_eq!(rkey_decoded, rkey);
   2549     }
   2550 
   2551     #[test]
   2552     fn protocol_server_accepts_official_transport_host_forms() {
   2553         let server = RadrootsSimplexSmpProtocolServer {
   2554             hosts: vec![
   2555                 "smp4.simplex.im".to_string(),
   2556                 "192.0.2.24".to_string(),
   2557                 "2001:db8::24".to_string(),
   2558                 "[2001:db8::42]".to_string(),
   2559                 "simplexabc.onion".to_string(),
   2560             ],
   2561             port: "5223".to_string(),
   2562             key_hash: vec![0xaa, 0xbb, 0xcc],
   2563         };
   2564 
   2565         let mut encoded = Vec::new();
   2566         encode_protocol_server(&mut encoded, &server).unwrap();
   2567         let decoded = decode_protocol_server(&mut Cursor::new(&encoded)).unwrap();
   2568 
   2569         assert_eq!(decoded, server);
   2570     }
   2571 
   2572     #[test]
   2573     fn protocol_server_rejects_invalid_transport_host_forms() {
   2574         let invalid_server = RadrootsSimplexSmpProtocolServer {
   2575             hosts: vec!["bad host".to_string()],
   2576             port: "5223".to_string(),
   2577             key_hash: vec![0xaa, 0xbb, 0xcc],
   2578         };
   2579 
   2580         let mut encoded = Vec::new();
   2581         assert_eq!(
   2582             encode_protocol_server(&mut encoded, &invalid_server),
   2583             Err(RadrootsSimplexSmpProtoError::InvalidHostList(
   2584                 "bad host".to_string(),
   2585             ))
   2586         );
   2587 
   2588         let mut invalid_bytes = Vec::new();
   2589         push_short_string_list(&mut invalid_bytes, &["[invalid]".to_string()]).unwrap();
   2590         push_short_string(&mut invalid_bytes, "5223").unwrap();
   2591         push_short_bytes(&mut invalid_bytes, &[0xaa, 0xbb, 0xcc]).unwrap();
   2592 
   2593         assert_eq!(
   2594             decode_protocol_server(&mut Cursor::new(&invalid_bytes)),
   2595             Err(RadrootsSimplexSmpProtoError::InvalidHostList(
   2596                 "[invalid]".to_string(),
   2597             ))
   2598         );
   2599     }
   2600 
   2601     #[test]
   2602     fn top_level_unknown_error_tags_stay_opaque() {
   2603         assert_eq!(
   2604             decode_error(b"FUTURE"),
   2605             Ok(RadrootsSimplexSmpError::Other(b"FUTURE".to_vec()))
   2606         );
   2607     }
   2608 
   2609     #[test]
   2610     fn malformed_nested_proxy_error_fails_decode() {
   2611         assert_eq!(
   2612             decode_error(b"PROXY BROKER TRANSPORT HANDSHAKE UNKNOWN"),
   2613             Err(RadrootsSimplexSmpProtoError::InvalidTag(
   2614                 "UNKNOWN".to_string(),
   2615             ))
   2616         );
   2617     }
   2618 
   2619     #[test]
   2620     fn malformed_blocked_reason_fails_decode() {
   2621         assert_eq!(
   2622             decode_error(b"BLOCKED reason=custom"),
   2623             Err(RadrootsSimplexSmpProtoError::InvalidTag(
   2624                 "custom".to_string(),
   2625             ))
   2626         );
   2627     }
   2628 
   2629     #[test]
   2630     fn malformed_network_detail_fails_decode() {
   2631         assert_eq!(
   2632             decode_broker_error(b"NETWORK CONNECT"),
   2633             Err(RadrootsSimplexSmpProtoError::UnexpectedEof)
   2634         );
   2635     }
   2636 
   2637     #[test]
   2638     fn round_trips_proxy_forward_commands() {
   2639         let pfwd = RadrootsSimplexSmpCommandTransmission {
   2640             authorization: Vec::new(),
   2641             correlation_id: Some(correlation_id(3)),
   2642             entity_id: vec![0x90, 0x91],
   2643             command: RadrootsSimplexSmpCommand::PFwd {
   2644                 relay_version: 16,
   2645                 public_key: vec![0x10, 0x11, 0x12],
   2646                 encrypted_transmission: vec![0xde, 0xad, 0xbe, 0xef],
   2647             },
   2648         };
   2649         let rfwd = RadrootsSimplexSmpCommandTransmission {
   2650             authorization: Vec::new(),
   2651             correlation_id: Some(correlation_id(4)),
   2652             entity_id: Vec::new(),
   2653             command: RadrootsSimplexSmpCommand::RFwd(vec![0xca, 0xfe, 0xba, 0xbe]),
   2654         };
   2655 
   2656         let pfwd_encoded = pfwd.encode().unwrap();
   2657         let pfwd_decoded = RadrootsSimplexSmpCommandTransmission::decode(&pfwd_encoded).unwrap();
   2658         assert_eq!(pfwd_decoded, pfwd);
   2659 
   2660         let rfwd_encoded = rfwd.encode().unwrap();
   2661         let rfwd_decoded = RadrootsSimplexSmpCommandTransmission::decode(&rfwd_encoded).unwrap();
   2662         assert_eq!(rfwd_decoded, rfwd);
   2663     }
   2664 
   2665     #[test]
   2666     fn round_trips_service_and_proxy_broker_messages() {
   2667         let service = RadrootsSimplexSmpBrokerTransmission {
   2668             authorization: Vec::new(),
   2669             correlation_id: Some(correlation_id(5)),
   2670             entity_id: vec![0x44],
   2671             message: RadrootsSimplexSmpBrokerMessage::Sok(Some(vec![0x20, 0x21])),
   2672         };
   2673         let proxy = RadrootsSimplexSmpBrokerTransmission {
   2674             authorization: Vec::new(),
   2675             correlation_id: None,
   2676             entity_id: Vec::new(),
   2677             message: RadrootsSimplexSmpBrokerMessage::PKey {
   2678                 session_id: vec![0x31, 0x32],
   2679                 version_range: RadrootsSimplexSmpVersionRange::new(8, 16).unwrap(),
   2680                 cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey {
   2681                     certificate_chain: vec![vec![0x41, 0x42], vec![0x43, 0x44, 0x45]],
   2682                     signed_public_key: vec![0x51, 0x52, 0x53],
   2683                 },
   2684             },
   2685         };
   2686 
   2687         let service_encoded = service.encode().unwrap();
   2688         let service_decoded =
   2689             RadrootsSimplexSmpBrokerTransmission::decode(&service_encoded).unwrap();
   2690         assert_eq!(service_decoded, service);
   2691 
   2692         let proxy_encoded = proxy.encode().unwrap();
   2693         let proxy_decoded = RadrootsSimplexSmpBrokerTransmission::decode(&proxy_encoded).unwrap();
   2694         assert_eq!(proxy_decoded, proxy);
   2695     }
   2696 
   2697     #[test]
   2698     fn round_trips_proxy_and_blocked_errors() {
   2699         let proxy_error = RadrootsSimplexSmpBrokerTransmission {
   2700             authorization: Vec::new(),
   2701             correlation_id: Some(correlation_id(6)),
   2702             entity_id: vec![0x77],
   2703             message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Proxy(
   2704                 RadrootsSimplexSmpProxyError::Broker(RadrootsSimplexSmpBrokerError::Transport(
   2705                     RadrootsSimplexSmpTransportError::Handshake(
   2706                         RadrootsSimplexSmpHandshakeError::Identity,
   2707                     ),
   2708                 )),
   2709             )),
   2710         };
   2711         let blocked_error = RadrootsSimplexSmpBrokerTransmission {
   2712             authorization: Vec::new(),
   2713             correlation_id: Some(correlation_id(7)),
   2714             entity_id: vec![0x88],
   2715             message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Blocked(
   2716                 RadrootsSimplexSmpBlockingInfo {
   2717                     reason: RadrootsSimplexSmpBlockingReason::Spam,
   2718                 },
   2719             )),
   2720         };
   2721 
   2722         let proxy_encoded = proxy_error.encode().unwrap();
   2723         let proxy_decoded = RadrootsSimplexSmpBrokerTransmission::decode(&proxy_encoded).unwrap();
   2724         assert_eq!(proxy_decoded, proxy_error);
   2725 
   2726         let blocked_encoded = blocked_error.encode().unwrap();
   2727         let blocked_decoded =
   2728             RadrootsSimplexSmpBrokerTransmission::decode(&blocked_encoded).unwrap();
   2729         assert_eq!(blocked_decoded, blocked_error);
   2730     }
   2731 
   2732     #[test]
   2733     fn service_ok_downgrades_to_ok_before_service_certs() {
   2734         let encoded = RadrootsSimplexSmpBrokerMessage::Sok(Some(vec![0x10]))
   2735             .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION)
   2736             .unwrap();
   2737 
   2738         assert_eq!(encoded, b"OK".to_vec());
   2739     }
   2740 
   2741     #[test]
   2742     fn blocked_error_downgrades_to_auth_before_blocked_entity_version() {
   2743         let encoded = RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Blocked(
   2744             RadrootsSimplexSmpBlockingInfo {
   2745                 reason: RadrootsSimplexSmpBlockingReason::Content,
   2746             },
   2747         ))
   2748         .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION)
   2749         .unwrap();
   2750 
   2751         assert_eq!(encoded, b"ERR AUTH".to_vec());
   2752     }
   2753 
   2754     #[test]
   2755     fn decodes_optional_network_detail_and_preserves_encode_behavior() {
   2756         let detailed = decode_broker_error(b"NETWORK CONNECT \x03dns").unwrap();
   2757         assert_eq!(
   2758             detailed,
   2759             RadrootsSimplexSmpBrokerError::Network(RadrootsSimplexSmpNetworkError::Connect(
   2760                 "dns".to_string(),
   2761             ))
   2762         );
   2763 
   2764         let encoded =
   2765             encode_network_error(&RadrootsSimplexSmpNetworkError::Connect("dns".to_string()));
   2766         assert_eq!(encoded, b"CONNECT \x03dns".to_vec());
   2767         assert_eq!(
   2768             encode_broker_error(&RadrootsSimplexSmpBrokerError::Network(
   2769                 RadrootsSimplexSmpNetworkError::Connect("dns".to_string()),
   2770             )),
   2771             b"NETWORK".to_vec()
   2772         );
   2773     }
   2774 }