stem_rs/client/
datatype.rs

1//! Data types for the Tor relay protocol.
2//!
3//! This module provides low-level data types used in ORPort communication
4//! with Tor relays. These types handle the binary encoding and decoding
5//! of protocol messages as defined in the
6//! [Tor specification](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt).
7//!
8//! # Overview
9//!
10//! The module contains several categories of types:
11//!
12//! - **Size types**: [`Size`] for packing/unpacking integers of various widths
13//! - **Protocol versioning**: [`LinkProtocol`] for version-dependent constants
14//! - **Addressing**: [`Address`], [`AddrType`], and [`LinkSpecifier`] for relay addresses
15//! - **Certificates**: [`Certificate`] and [`CertType`] for relay certificates
16//! - **Commands**: [`RelayCommand`] and [`CloseReason`] for circuit operations
17//! - **Key derivation**: [`KDF`] for cryptographic key material
18//!
19//! # Conceptual Role
20//!
21//! These types form the foundation of the ORPort protocol implementation.
22//! They handle the serialization and deserialization of binary data according
23//! to Tor's wire format, which uses big-endian byte ordering throughout.
24//!
25//! Most users should interact with the higher-level [`Relay`](super::Relay)
26//! and [`RelayCircuit`](super::RelayCircuit) types rather than using these
27//! primitives directly.
28//!
29//! # Wire Format
30//!
31//! All multi-byte integers are encoded in network byte order (big-endian).
32//! Variable-length fields are typically prefixed with their length.
33//!
34//! # Example
35//!
36//! ```rust
37//! use stem_rs::client::datatype::{Size, Address, AddrType};
38//!
39//! // Pack and unpack integers
40//! let packed = Size::Short.pack(9001);
41//! assert_eq!(packed, vec![0x23, 0x29]);
42//!
43//! let unpacked = Size::Short.unpack(&packed).unwrap();
44//! assert_eq!(unpacked, 9001);
45//!
46//! // Parse an IPv4 address
47//! let addr = Address::new("127.0.0.1").unwrap();
48//! assert_eq!(addr.addr_type, AddrType::IPv4);
49//! ```
50//!
51//! # Security Considerations
52//!
53//! These types handle untrusted network data. All parsing functions validate
54//! input lengths and return errors for malformed data rather than panicking.
55//!
56//! # See Also
57//!
58//! - [`cell`](super::cell) - Cell types that use these data types for encoding
59//! - [`Relay`](super::Relay) - High-level relay connection interface
60//! - [`RelayCircuit`](super::RelayCircuit) - Circuit management using these primitives
61
62use crate::Error;
63use sha1::{Digest, Sha1};
64use std::fmt;
65use std::net::{Ipv4Addr, Ipv6Addr};
66
67/// Null byte constant used for padding in the Tor protocol.
68pub const ZERO: u8 = 0x00;
69
70/// Length of SHA-1 hash output in bytes (160 bits).
71///
72/// Used throughout the Tor protocol for identity fingerprints and
73/// key derivation functions.
74pub const HASH_LEN: usize = 20;
75
76/// Length of symmetric encryption keys in bytes (128 bits).
77///
78/// Used for AES-128-CTR encryption in relay cells.
79pub const KEY_LEN: usize = 16;
80
81/// Splits a byte slice at the given position, clamping to the slice length.
82///
83/// This is a helper function for parsing binary data that safely handles
84/// cases where the requested split position exceeds the slice length.
85///
86/// # Arguments
87///
88/// * `content` - The byte slice to split
89/// * `size` - The position at which to split (clamped to `content.len()`)
90///
91/// # Returns
92///
93/// A tuple of `(left, right)` where:
94/// - `left` contains bytes `[0..min(size, len))`
95/// - `right` contains the remaining bytes
96///
97/// # Example
98///
99/// ```rust
100/// use stem_rs::client::datatype::split;
101///
102/// let data = b"hello";
103/// let (left, right) = split(data, 2);
104/// assert_eq!(left, b"he");
105/// assert_eq!(right, b"llo");
106///
107/// // Size exceeds length - returns entire slice and empty remainder
108/// let (left, right) = split(data, 100);
109/// assert_eq!(left, b"hello");
110/// assert_eq!(right, b"");
111/// ```
112pub fn split(content: &[u8], size: usize) -> (&[u8], &[u8]) {
113    content.split_at(size.min(content.len()))
114}
115
116/// Integer size types for packing and unpacking binary data.
117///
118/// The Tor protocol uses fixed-width unsigned integers in network byte order
119/// (big-endian). This enum provides methods for encoding and decoding these
120/// integers according to the
121/// [struct pack format](https://docs.python.org/3/library/struct.html#format-characters).
122///
123/// # Variants
124///
125/// | Variant    | Size    | Range                    |
126/// |------------|---------|--------------------------|
127/// | `Char`     | 1 byte  | 0 to 255                 |
128/// | `Short`    | 2 bytes | 0 to 65,535              |
129/// | `Long`     | 4 bytes | 0 to 4,294,967,295       |
130/// | `LongLong` | 8 bytes | 0 to 18,446,744,073,709,551,615 |
131///
132/// # Example
133///
134/// ```rust
135/// use stem_rs::client::datatype::Size;
136///
137/// // Pack a 16-bit port number
138/// let port: u64 = 9001;
139/// let packed = Size::Short.pack(port);
140/// assert_eq!(packed, vec![0x23, 0x29]);
141///
142/// // Unpack it back
143/// let unpacked = Size::Short.unpack(&packed).unwrap();
144/// assert_eq!(unpacked, 9001);
145///
146/// // Pop from a larger buffer
147/// let buffer = vec![0x23, 0x29, 0xFF, 0xFF];
148/// let (value, remainder) = Size::Short.pop(&buffer).unwrap();
149/// assert_eq!(value, 9001);
150/// assert_eq!(remainder, &[0xFF, 0xFF]);
151/// ```
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153pub enum Size {
154    /// Unsigned 8-bit integer (1 byte).
155    Char,
156    /// Unsigned 16-bit integer (2 bytes, big-endian).
157    Short,
158    /// Unsigned 32-bit integer (4 bytes, big-endian).
159    Long,
160    /// Unsigned 64-bit integer (8 bytes, big-endian).
161    LongLong,
162}
163
164impl Size {
165    /// Returns the size in bytes for this integer type.
166    ///
167    /// # Example
168    ///
169    /// ```rust
170    /// use stem_rs::client::datatype::Size;
171    ///
172    /// assert_eq!(Size::Char.size(), 1);
173    /// assert_eq!(Size::Short.size(), 2);
174    /// assert_eq!(Size::Long.size(), 4);
175    /// assert_eq!(Size::LongLong.size(), 8);
176    /// ```
177    pub fn size(&self) -> usize {
178        match self {
179            Size::Char => 1,
180            Size::Short => 2,
181            Size::Long => 4,
182            Size::LongLong => 8,
183        }
184    }
185
186    /// Packs an integer value into big-endian bytes.
187    ///
188    /// # Arguments
189    ///
190    /// * `value` - The integer value to pack (truncated to fit the size)
191    ///
192    /// # Returns
193    ///
194    /// A `Vec<u8>` containing the packed bytes in network byte order.
195    ///
196    /// # Example
197    ///
198    /// ```rust
199    /// use stem_rs::client::datatype::Size;
200    ///
201    /// assert_eq!(Size::Char.pack(0x12), vec![0x12]);
202    /// assert_eq!(Size::Short.pack(0x1234), vec![0x12, 0x34]);
203    /// assert_eq!(Size::Long.pack(0x12345678), vec![0x12, 0x34, 0x56, 0x78]);
204    /// ```
205    pub fn pack(&self, value: u64) -> Vec<u8> {
206        match self {
207            Size::Char => vec![value as u8],
208            Size::Short => (value as u16).to_be_bytes().to_vec(),
209            Size::Long => (value as u32).to_be_bytes().to_vec(),
210            Size::LongLong => value.to_be_bytes().to_vec(),
211        }
212    }
213
214    /// Unpacks big-endian bytes into an integer value.
215    ///
216    /// # Arguments
217    ///
218    /// * `data` - The bytes to unpack (must be exactly `self.size()` bytes)
219    ///
220    /// # Errors
221    ///
222    /// Returns [`Error::Protocol`] if `data.len()` does not match `self.size()`.
223    ///
224    /// # Example
225    ///
226    /// ```rust
227    /// use stem_rs::client::datatype::Size;
228    ///
229    /// assert_eq!(Size::Char.unpack(&[0x12]).unwrap(), 0x12);
230    /// assert_eq!(Size::Short.unpack(&[0x12, 0x34]).unwrap(), 0x1234);
231    ///
232    /// // Wrong size returns an error
233    /// assert!(Size::Short.unpack(&[0x12]).is_err());
234    /// ```
235    pub fn unpack(&self, data: &[u8]) -> Result<u64, Error> {
236        if data.len() != self.size() {
237            return Err(Error::Protocol(format!(
238                "{:?} is the wrong size for a {:?} field",
239                data, self
240            )));
241        }
242        Ok(match self {
243            Size::Char => data[0] as u64,
244            Size::Short => u16::from_be_bytes([data[0], data[1]]) as u64,
245            Size::Long => u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as u64,
246            Size::LongLong => u64::from_be_bytes([
247                data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
248            ]),
249        })
250    }
251
252    /// Unpacks an integer from the start of a byte slice, returning the remainder.
253    ///
254    /// This is useful for parsing sequential fields from a binary buffer.
255    ///
256    /// # Arguments
257    ///
258    /// * `data` - The byte slice to read from (must have at least `self.size()` bytes)
259    ///
260    /// # Returns
261    ///
262    /// A tuple of `(value, remainder)` where:
263    /// - `value` is the unpacked integer
264    /// - `remainder` is the unconsumed portion of the input
265    ///
266    /// # Errors
267    ///
268    /// Returns [`Error::Protocol`] if `data.len()` is less than `self.size()`.
269    ///
270    /// # Example
271    ///
272    /// ```rust
273    /// use stem_rs::client::datatype::Size;
274    ///
275    /// let data = vec![0x00, 0x12, 0xFF, 0xFF];
276    /// let (value, rest) = Size::Short.pop(&data).unwrap();
277    /// assert_eq!(value, 18);
278    /// assert_eq!(rest, &[0xFF, 0xFF]);
279    /// ```
280    pub fn pop<'a>(&self, data: &'a [u8]) -> Result<(u64, &'a [u8]), Error> {
281        if data.len() < self.size() {
282            return Err(Error::Protocol(format!(
283                "{:?} is the wrong size for a {:?} field",
284                data, self
285            )));
286        }
287        let (to_unpack, remainder) = split(data, self.size());
288        Ok((self.unpack(to_unpack)?, remainder))
289    }
290}
291
292/// Link protocol version with version-dependent constants.
293///
294/// The Tor link protocol has evolved over time, with different versions
295/// using different field sizes and constants. This struct encapsulates
296/// the version-specific parameters needed for cell encoding and decoding.
297///
298/// # Version Differences
299///
300/// | Version | Circuit ID Size | First Circuit ID | Fixed Cell Length |
301/// |---------|-----------------|------------------|-------------------|
302/// | 1-3     | 2 bytes (Short) | 0x0001           | 512 bytes         |
303/// | 4+      | 4 bytes (Long)  | 0x80000000       | 514 bytes         |
304///
305/// The `first_circ_id` determines the starting point for client-initiated
306/// circuit identifiers. Clients use IDs with the high bit set (version 4+)
307/// or starting from 1 (version 1-3).
308///
309/// # Example
310///
311/// ```rust
312/// use stem_rs::client::datatype::{LinkProtocol, Size};
313///
314/// // Version 3 uses 2-byte circuit IDs
315/// let v3 = LinkProtocol::new(3);
316/// assert_eq!(v3.circ_id_size, Size::Short);
317/// assert_eq!(v3.first_circ_id, 0x01);
318///
319/// // Version 5 uses 4-byte circuit IDs
320/// let v5 = LinkProtocol::new(5);
321/// assert_eq!(v5.circ_id_size, Size::Long);
322/// assert_eq!(v5.first_circ_id, 0x80000000);
323/// ```
324///
325/// # Equality
326///
327/// `LinkProtocol` can be compared directly with `u32` version numbers:
328///
329/// ```rust
330/// use stem_rs::client::datatype::LinkProtocol;
331///
332/// let protocol = LinkProtocol::new(5);
333/// assert!(protocol == 5);
334/// assert!(protocol != 4);
335/// ```
336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
337pub struct LinkProtocol {
338    /// The link protocol version number.
339    pub version: u32,
340    /// Size of circuit identifier fields (2 or 4 bytes).
341    pub circ_id_size: Size,
342    /// Total length of fixed-size cells in bytes.
343    pub fixed_cell_length: usize,
344    /// First circuit ID to use when creating circuits.
345    ///
346    /// Clients pick circuit IDs from a range determined by the protocol version
347    /// to avoid collisions with relay-initiated circuits.
348    pub first_circ_id: u32,
349}
350
351impl LinkProtocol {
352    /// Creates a new `LinkProtocol` for the given version number.
353    ///
354    /// This automatically configures all version-dependent constants based
355    /// on the protocol specification.
356    ///
357    /// # Arguments
358    ///
359    /// * `version` - The link protocol version (typically 4 or 5 for modern Tor)
360    ///
361    /// # Example
362    ///
363    /// ```rust
364    /// use stem_rs::client::datatype::LinkProtocol;
365    ///
366    /// let protocol = LinkProtocol::new(5);
367    /// assert_eq!(protocol.version, 5);
368    /// assert_eq!(protocol.fixed_cell_length, 514);
369    /// ```
370    pub fn new(version: u32) -> Self {
371        let circ_id_size = if version > 3 { Size::Long } else { Size::Short };
372        let first_circ_id = if version > 3 { 0x80000000 } else { 0x01 };
373        let cell_header_size = circ_id_size.size() + 1;
374        let fixed_cell_length = cell_header_size + super::cell::FIXED_PAYLOAD_LEN;
375
376        LinkProtocol {
377            version,
378            circ_id_size,
379            fixed_cell_length,
380            first_circ_id,
381        }
382    }
383}
384
385impl From<u32> for LinkProtocol {
386    /// Creates a `LinkProtocol` from a version number.
387    fn from(version: u32) -> Self {
388        LinkProtocol::new(version)
389    }
390}
391
392impl PartialEq<u32> for LinkProtocol {
393    /// Compares the protocol version with a `u32`.
394    fn eq(&self, other: &u32) -> bool {
395        self.version == *other
396    }
397}
398
399/// Address type identifier for relay addresses.
400///
401/// Indicates the format of an address in the Tor protocol. This is used
402/// in NETINFO cells and other places where addresses are exchanged.
403///
404/// # Variants
405///
406/// | Variant          | Value | Description                              |
407/// |------------------|-------|------------------------------------------|
408/// | `Hostname`       | 0     | DNS hostname (not typically used)        |
409/// | `IPv4`           | 4     | IPv4 address (4 bytes)                   |
410/// | `IPv6`           | 6     | IPv6 address (16 bytes)                  |
411/// | `ErrorTransient` | 16    | Temporary error retrieving address       |
412/// | `ErrorPermanent` | 17    | Permanent error retrieving address       |
413/// | `Unknown`        | -     | Unrecognized address type                |
414///
415/// # Example
416///
417/// ```rust
418/// use stem_rs::client::datatype::AddrType;
419///
420/// let (addr_type, raw_value) = AddrType::get(4);
421/// assert_eq!(addr_type, AddrType::IPv4);
422/// assert_eq!(raw_value, 4);
423///
424/// // Unknown types preserve the raw value
425/// let (addr_type, raw_value) = AddrType::get(99);
426/// assert_eq!(addr_type, AddrType::Unknown);
427/// assert_eq!(raw_value, 99);
428/// ```
429#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
430pub enum AddrType {
431    /// DNS hostname.
432    Hostname = 0,
433    /// IPv4 address (4 bytes).
434    IPv4 = 4,
435    /// IPv6 address (16 bytes).
436    IPv6 = 6,
437    /// Temporary error retrieving the address.
438    ErrorTransient = 16,
439    /// Permanent error retrieving the address.
440    ErrorPermanent = 17,
441    /// Unrecognized address type.
442    Unknown,
443}
444
445impl AddrType {
446    /// Converts a raw byte value to an `AddrType` and its integer representation.
447    ///
448    /// # Arguments
449    ///
450    /// * `val` - The raw address type byte from the protocol
451    ///
452    /// # Returns
453    ///
454    /// A tuple of `(AddrType, u8)` where the second element is the original
455    /// byte value. This preserves unknown type values for round-tripping.
456    ///
457    /// # Example
458    ///
459    /// ```rust
460    /// use stem_rs::client::datatype::AddrType;
461    ///
462    /// assert_eq!(AddrType::get(4), (AddrType::IPv4, 4));
463    /// assert_eq!(AddrType::get(6), (AddrType::IPv6, 6));
464    /// assert_eq!(AddrType::get(99), (AddrType::Unknown, 99));
465    /// ```
466    pub fn get(val: u8) -> (AddrType, u8) {
467        match val {
468            0 => (AddrType::Hostname, 0),
469            4 => (AddrType::IPv4, 4),
470            6 => (AddrType::IPv6, 6),
471            16 => (AddrType::ErrorTransient, 16),
472            17 => (AddrType::ErrorPermanent, 17),
473            _ => (AddrType::Unknown, val),
474        }
475    }
476
477    /// Returns the integer value for this address type.
478    ///
479    /// Returns 255 for `Unknown` types (the original value is lost).
480    pub fn value(&self) -> u8 {
481        match self {
482            AddrType::Hostname => 0,
483            AddrType::IPv4 => 4,
484            AddrType::IPv6 => 6,
485            AddrType::ErrorTransient => 16,
486            AddrType::ErrorPermanent => 17,
487            AddrType::Unknown => 255,
488        }
489    }
490}
491
492/// A relay address with type information.
493///
494/// Represents an address in the Tor protocol, supporting IPv4, IPv6, and
495/// other address types. Addresses are encoded with a type byte, length byte,
496/// and variable-length value.
497///
498/// # Wire Format
499///
500/// ```text
501/// +----------+--------+------------------+
502/// | Type (1) | Len (1)| Value (Len bytes)|
503/// +----------+--------+------------------+
504/// ```
505///
506/// # Example
507///
508/// ```rust
509/// use stem_rs::client::datatype::{Address, AddrType};
510///
511/// // Create from string
512/// let addr = Address::new("127.0.0.1").unwrap();
513/// assert_eq!(addr.addr_type, AddrType::IPv4);
514/// assert_eq!(addr.value, Some("127.0.0.1".to_string()));
515///
516/// // Pack and unpack
517/// let packed = addr.pack();
518/// let unpacked = Address::unpack(&packed).unwrap();
519/// assert_eq!(addr, unpacked);
520/// ```
521///
522/// # IPv6 Handling
523///
524/// IPv6 addresses are normalized to their fully expanded form:
525///
526/// ```rust
527/// use stem_rs::client::datatype::Address;
528///
529/// let addr = Address::new("::1").unwrap();
530/// assert_eq!(addr.value, Some("0000:0000:0000:0000:0000:0000:0000:0001".to_string()));
531/// ```
532#[derive(Debug, Clone, PartialEq, Eq)]
533pub struct Address {
534    /// The type of this address.
535    pub addr_type: AddrType,
536    /// The raw type byte (preserved for unknown types).
537    pub type_int: u8,
538    /// The human-readable address string (if applicable).
539    ///
540    /// This is `None` for error types and unknown address types.
541    pub value: Option<String>,
542    /// The raw binary representation of the address.
543    pub value_bin: Vec<u8>,
544}
545
546impl Address {
547    /// Creates a new `Address` from an IP address string.
548    ///
549    /// Automatically detects whether the address is IPv4 or IPv6.
550    ///
551    /// # Arguments
552    ///
553    /// * `value` - An IPv4 or IPv6 address string
554    ///
555    /// # Errors
556    ///
557    /// Returns [`Error::Protocol`] if the string is not a valid IPv4 or IPv6 address.
558    ///
559    /// # Example
560    ///
561    /// ```rust
562    /// use stem_rs::client::datatype::{Address, AddrType};
563    ///
564    /// let ipv4 = Address::new("192.168.1.1").unwrap();
565    /// assert_eq!(ipv4.addr_type, AddrType::IPv4);
566    ///
567    /// let ipv6 = Address::new("2001:db8::1").unwrap();
568    /// assert_eq!(ipv6.addr_type, AddrType::IPv6);
569    ///
570    /// // Invalid addresses return an error
571    /// assert!(Address::new("not-an-address").is_err());
572    /// ```
573    pub fn new(value: &str) -> Result<Self, Error> {
574        if let Ok(ipv4) = value.parse::<Ipv4Addr>() {
575            return Ok(Address {
576                addr_type: AddrType::IPv4,
577                type_int: 4,
578                value: Some(value.to_string()),
579                value_bin: ipv4.octets().to_vec(),
580            });
581        }
582        if let Ok(ipv6) = value.parse::<Ipv6Addr>() {
583            let expanded = format!(
584                "{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}",
585                ipv6.segments()[0],
586                ipv6.segments()[1],
587                ipv6.segments()[2],
588                ipv6.segments()[3],
589                ipv6.segments()[4],
590                ipv6.segments()[5],
591                ipv6.segments()[6],
592                ipv6.segments()[7]
593            );
594            return Ok(Address {
595                addr_type: AddrType::IPv6,
596                type_int: 6,
597                value: Some(expanded),
598                value_bin: ipv6.octets().to_vec(),
599            });
600        }
601        Err(Error::Protocol(format!(
602            "'{}' isn't an IPv4 or IPv6 address",
603            value
604        )))
605    }
606
607    /// Creates an `Address` from raw bytes with a specified type.
608    ///
609    /// This is used when parsing addresses from the wire format where
610    /// the type is already known.
611    ///
612    /// # Arguments
613    ///
614    /// * `value` - The raw address bytes
615    /// * `addr_type` - The address type byte
616    ///
617    /// # Errors
618    ///
619    /// Returns [`Error::Protocol`] if:
620    /// - `addr_type` is 4 (IPv4) but `value` is not 4 bytes
621    /// - `addr_type` is 6 (IPv6) but `value` is not 16 bytes
622    ///
623    /// # Example
624    ///
625    /// ```rust
626    /// use stem_rs::client::datatype::{Address, AddrType};
627    ///
628    /// let addr = Address::with_type(&[127, 0, 0, 1], 4).unwrap();
629    /// assert_eq!(addr.value, Some("127.0.0.1".to_string()));
630    ///
631    /// // Unknown types are accepted
632    /// let unknown = Address::with_type(b"data", 99).unwrap();
633    /// assert_eq!(unknown.addr_type, AddrType::Unknown);
634    /// ```
635    pub fn with_type(value: &[u8], addr_type: u8) -> Result<Self, Error> {
636        let (atype, type_int) = AddrType::get(addr_type);
637        match atype {
638            AddrType::IPv4 => {
639                if value.len() != 4 {
640                    return Err(Error::Protocol(format!(
641                        "Packed IPv4 addresses should be four bytes, but was: {:?}",
642                        value
643                    )));
644                }
645                let addr_str = format!("{}.{}.{}.{}", value[0], value[1], value[2], value[3]);
646                Ok(Address {
647                    addr_type: atype,
648                    type_int,
649                    value: Some(addr_str),
650                    value_bin: value.to_vec(),
651                })
652            }
653            AddrType::IPv6 => {
654                if value.len() != 16 {
655                    return Err(Error::Protocol(format!(
656                        "Packed IPv6 addresses should be sixteen bytes, but was: {:?}",
657                        value
658                    )));
659                }
660                let addr_str = unpack_ipv6_address(value);
661                Ok(Address {
662                    addr_type: atype,
663                    type_int,
664                    value: Some(addr_str),
665                    value_bin: value.to_vec(),
666                })
667            }
668            _ => Ok(Address {
669                addr_type: atype,
670                type_int,
671                value: None,
672                value_bin: value.to_vec(),
673            }),
674        }
675    }
676
677    /// Packs the address into its wire format.
678    ///
679    /// # Returns
680    ///
681    /// A `Vec<u8>` containing: `[type, length, value...]`
682    ///
683    /// # Example
684    ///
685    /// ```rust
686    /// use stem_rs::client::datatype::Address;
687    ///
688    /// let addr = Address::new("127.0.0.1").unwrap();
689    /// let packed = addr.pack();
690    /// assert_eq!(packed, vec![0x04, 0x04, 127, 0, 0, 1]);
691    /// ```
692    pub fn pack(&self) -> Vec<u8> {
693        let mut cell = Vec::new();
694        cell.push(self.type_int);
695        cell.push(self.value_bin.len() as u8);
696        cell.extend_from_slice(&self.value_bin);
697        cell
698    }
699
700    /// Unpacks an address from its wire format.
701    ///
702    /// # Arguments
703    ///
704    /// * `data` - The packed address bytes (must be exactly the right size)
705    ///
706    /// # Errors
707    ///
708    /// Returns [`Error::Protocol`] if:
709    /// - The data is too short
710    /// - There are extra bytes after the address
711    /// - The address type/length combination is invalid
712    pub fn unpack(data: &[u8]) -> Result<Self, Error> {
713        let (addr, remainder) = Self::pop(data)?;
714        if !remainder.is_empty() {
715            return Err(Error::Protocol(format!(
716                "Address had {} extra bytes",
717                remainder.len()
718            )));
719        }
720        Ok(addr)
721    }
722
723    /// Unpacks an address from the start of a byte slice, returning the remainder.
724    ///
725    /// # Arguments
726    ///
727    /// * `content` - The byte slice to read from
728    ///
729    /// # Returns
730    ///
731    /// A tuple of `(Address, remainder)`.
732    ///
733    /// # Errors
734    ///
735    /// Returns [`Error::Protocol`] if the data is malformed.
736    pub fn pop(content: &[u8]) -> Result<(Self, &[u8]), Error> {
737        if content.len() < 2 {
738            return Err(Error::Protocol(
739                "Address requires at least 2 bytes".to_string(),
740            ));
741        }
742        let (addr_type, content) = (content[0], &content[1..]);
743        let (addr_length, content) = (content[0] as usize, &content[1..]);
744        if content.len() < addr_length {
745            return Err(Error::Protocol(format!(
746                "Address specified a payload of {} bytes, but only had {}",
747                addr_length,
748                content.len()
749            )));
750        }
751        let (addr_value, content) = split(content, addr_length);
752        Ok((Address::with_type(addr_value, addr_type)?, content))
753    }
754}
755
756/// Unpacks a 16-byte IPv6 address into its colon-separated hex string form.
757fn unpack_ipv6_address(value: &[u8]) -> String {
758    let segments: Vec<String> = (0..8)
759        .map(|i| {
760            let high = value[i * 2] as u16;
761            let low = value[i * 2 + 1] as u16;
762            format!("{:04x}", (high << 8) | low)
763        })
764        .collect();
765    segments.join(":")
766}
767
768/// Certificate type identifier.
769///
770/// Identifies the purpose of a certificate in the Tor protocol. Different
771/// certificate types are used for different authentication and signing purposes.
772///
773/// For more information, see:
774/// - [tor-spec.txt section 4.2](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt)
775/// - [cert-spec.txt section A.1](https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt)
776/// - [rend-spec-v3.txt appendix E](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt)
777///
778/// # Variants
779///
780/// | Variant              | Value | Description                                    |
781/// |----------------------|-------|------------------------------------------------|
782/// | `Link`               | 1     | Link key certificate (RSA1024 identity)        |
783/// | `Identity`           | 2     | RSA1024 identity certificate                   |
784/// | `Authenticate`       | 3     | RSA1024 AUTHENTICATE cell link certificate     |
785/// | `Ed25519Signing`     | 4     | Ed25519 signing key (signed with identity)     |
786/// | `LinkCert`           | 5     | TLS link cert (signed with Ed25519 signing)    |
787/// | `Ed25519Authenticate`| 6     | Ed25519 AUTHENTICATE cell key                  |
788/// | `Ed25519Identity`    | 7     | Ed25519 identity (signed with RSA identity)    |
789/// | `HsV3DescSigning`    | 8     | HS v3 short-term descriptor signing key        |
790/// | `HsV3IntroAuth`      | 9     | HS v3 introduction point authentication key    |
791/// | `NtorOnionKey`       | 10    | ntor onion key cross-certifying Ed25519        |
792/// | `HsV3NtorEnc`        | 11    | HS v3 ntor-extra encryption key                |
793/// | `Unknown`            | -     | Unrecognized certificate type                  |
794///
795/// # Example
796///
797/// ```rust
798/// use stem_rs::client::datatype::CertType;
799///
800/// let (cert_type, raw) = CertType::get(4);
801/// assert_eq!(cert_type, CertType::Ed25519Signing);
802/// assert_eq!(format!("{}", cert_type), "ED25519_SIGNING");
803/// ```
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
805pub enum CertType {
806    /// Link key certificate certified by RSA1024 identity.
807    Link = 1,
808    /// RSA1024 identity certificate.
809    Identity = 2,
810    /// RSA1024 AUTHENTICATE cell link certificate.
811    Authenticate = 3,
812    /// Ed25519 signing key, signed with identity key.
813    Ed25519Signing = 4,
814    /// TLS link certificate, signed with Ed25519 signing key.
815    LinkCert = 5,
816    /// Ed25519 AUTHENTICATE cell key, signed with Ed25519 signing key.
817    Ed25519Authenticate = 6,
818    /// Ed25519 identity, signed with RSA identity.
819    Ed25519Identity = 7,
820    /// Hidden service v3 short-term descriptor signing key.
821    HsV3DescSigning = 8,
822    /// Hidden service v3 introduction point authentication key.
823    HsV3IntroAuth = 9,
824    /// ntor onion key cross-certifying Ed25519 identity key.
825    NtorOnionKey = 10,
826    /// Hidden service v3 ntor-extra encryption key.
827    HsV3NtorEnc = 11,
828    /// Unrecognized certificate type.
829    Unknown,
830}
831
832impl CertType {
833    /// Converts a raw byte value to a `CertType` and its integer representation.
834    ///
835    /// # Arguments
836    ///
837    /// * `val` - The raw certificate type byte from the protocol
838    ///
839    /// # Returns
840    ///
841    /// A tuple of `(CertType, u8)` where the second element is the original
842    /// byte value. This preserves unknown type values for round-tripping.
843    pub fn get(val: u8) -> (CertType, u8) {
844        match val {
845            1 => (CertType::Link, 1),
846            2 => (CertType::Identity, 2),
847            3 => (CertType::Authenticate, 3),
848            4 => (CertType::Ed25519Signing, 4),
849            5 => (CertType::LinkCert, 5),
850            6 => (CertType::Ed25519Authenticate, 6),
851            7 => (CertType::Ed25519Identity, 7),
852            8 => (CertType::HsV3DescSigning, 8),
853            9 => (CertType::HsV3IntroAuth, 9),
854            10 => (CertType::NtorOnionKey, 10),
855            11 => (CertType::HsV3NtorEnc, 11),
856            _ => (CertType::Unknown, val),
857        }
858    }
859
860    /// Returns the integer value for this certificate type.
861    ///
862    /// Returns 255 for `Unknown` types.
863    pub fn value(&self) -> u8 {
864        match self {
865            CertType::Link => 1,
866            CertType::Identity => 2,
867            CertType::Authenticate => 3,
868            CertType::Ed25519Signing => 4,
869            CertType::LinkCert => 5,
870            CertType::Ed25519Authenticate => 6,
871            CertType::Ed25519Identity => 7,
872            CertType::HsV3DescSigning => 8,
873            CertType::HsV3IntroAuth => 9,
874            CertType::NtorOnionKey => 10,
875            CertType::HsV3NtorEnc => 11,
876            CertType::Unknown => 255,
877        }
878    }
879}
880
881impl fmt::Display for CertType {
882    /// Formats the certificate type as its canonical string name.
883    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
884        match self {
885            CertType::Link => write!(f, "LINK"),
886            CertType::Identity => write!(f, "IDENTITY"),
887            CertType::Authenticate => write!(f, "AUTHENTICATE"),
888            CertType::Ed25519Signing => write!(f, "ED25519_SIGNING"),
889            CertType::LinkCert => write!(f, "LINK_CERT"),
890            CertType::Ed25519Authenticate => write!(f, "ED25519_AUTHENTICATE"),
891            CertType::Ed25519Identity => write!(f, "ED25519_IDENTITY"),
892            CertType::HsV3DescSigning => write!(f, "HS_V3_DESC_SIGNING"),
893            CertType::HsV3IntroAuth => write!(f, "HS_V3_INTRO_AUTH"),
894            CertType::NtorOnionKey => write!(f, "NTOR_ONION_KEY"),
895            CertType::HsV3NtorEnc => write!(f, "HS_V3_NTOR_ENC"),
896            CertType::Unknown => write!(f, "UNKNOWN"),
897        }
898    }
899}
900
901/// A relay certificate as defined in tor-spec section 4.2.
902///
903/// Certificates are used in CERTS cells to authenticate relays during
904/// the link handshake. Each certificate has a type and a variable-length
905/// value containing the actual certificate data.
906///
907/// # Wire Format
908///
909/// ```text
910/// +----------+------------+------------------+
911/// | Type (1) | Length (2) | Value (Len bytes)|
912/// +----------+------------+------------------+
913/// ```
914///
915/// Note that the length field is 2 bytes (unlike Address which uses 1 byte).
916///
917/// # Example
918///
919/// ```rust
920/// use stem_rs::client::datatype::{Certificate, CertType};
921///
922/// // Create a certificate
923/// let cert = Certificate::new(CertType::Link, vec![0x01, 0x02, 0x03]);
924/// assert_eq!(cert.cert_type, CertType::Link);
925///
926/// // Pack and unpack
927/// let packed = cert.pack();
928/// let (unpacked, _) = Certificate::pop(&packed).unwrap();
929/// assert_eq!(cert, unpacked);
930/// ```
931#[derive(Debug, Clone, PartialEq, Eq)]
932pub struct Certificate {
933    /// The type of this certificate.
934    pub cert_type: CertType,
935    /// The raw type byte (preserved for unknown types).
936    pub type_int: u8,
937    /// The certificate data.
938    pub value: Vec<u8>,
939}
940
941impl Certificate {
942    /// Creates a new certificate with the given type and value.
943    ///
944    /// # Arguments
945    ///
946    /// * `cert_type` - The certificate type
947    /// * `value` - The certificate data
948    pub fn new(cert_type: CertType, value: Vec<u8>) -> Self {
949        Certificate {
950            type_int: cert_type.value(),
951            cert_type,
952            value,
953        }
954    }
955
956    /// Creates a certificate from a raw type byte and value.
957    ///
958    /// This is used when parsing certificates from the wire format.
959    ///
960    /// # Arguments
961    ///
962    /// * `cert_type` - The raw certificate type byte
963    /// * `value` - The certificate data
964    pub fn from_int(cert_type: u8, value: Vec<u8>) -> Self {
965        let (ctype, type_int) = CertType::get(cert_type);
966        Certificate {
967            cert_type: ctype,
968            type_int,
969            value,
970        }
971    }
972
973    /// Packs the certificate into its wire format.
974    ///
975    /// # Returns
976    ///
977    /// A `Vec<u8>` containing: `[type (1), length (2), value...]`
978    pub fn pack(&self) -> Vec<u8> {
979        let mut cell = Vec::new();
980        cell.push(self.type_int);
981        cell.extend_from_slice(&Size::Short.pack(self.value.len() as u64));
982        cell.extend_from_slice(&self.value);
983        cell
984    }
985
986    /// Unpacks a certificate from the start of a byte slice, returning the remainder.
987    ///
988    /// # Arguments
989    ///
990    /// * `content` - The byte slice to read from
991    ///
992    /// # Returns
993    ///
994    /// A tuple of `(Certificate, remainder)`.
995    ///
996    /// # Errors
997    ///
998    /// Returns [`Error::Protocol`] if:
999    /// - The data is too short for the header
1000    /// - The specified length exceeds the available data
1001    pub fn pop(content: &[u8]) -> Result<(Self, &[u8]), Error> {
1002        if content.is_empty() {
1003            return Err(Error::Protocol(
1004                "Certificate requires at least 1 byte".to_string(),
1005            ));
1006        }
1007        let (cert_type, content) = (content[0], &content[1..]);
1008        let (cert_size, content) = Size::Short.pop(content)?;
1009        let cert_size = cert_size as usize;
1010        if cert_size > content.len() {
1011            return Err(Error::Protocol(format!(
1012                "CERTS cell should have a certificate with {} bytes, but only had {} remaining",
1013                cert_size,
1014                content.len()
1015            )));
1016        }
1017        let (cert_bytes, content) = split(content, cert_size);
1018        Ok((
1019            Certificate::from_int(cert_type, cert_bytes.to_vec()),
1020            content,
1021        ))
1022    }
1023}
1024
1025/// Relay cell command types.
1026///
1027/// Commands used within relay cells to manage streams and circuits.
1028/// These commands have two characteristics:
1029///
1030/// - **Direction**: Forward commands originate from the client; backward
1031///   commands come from the relay.
1032/// - **Scope**: Stream commands affect individual streams; circuit commands
1033///   affect the entire circuit.
1034///
1035/// # Variants
1036///
1037/// | Command     | Value | Direction        | Scope   | Description                    |
1038/// |-------------|-------|------------------|---------|--------------------------------|
1039/// | `Begin`     | 1     | Forward          | Stream  | Begin a new stream             |
1040/// | `Data`      | 2     | Forward/Backward | Stream  | Transmit data                  |
1041/// | `End`       | 3     | Forward/Backward | Stream  | End a stream                   |
1042/// | `Connected` | 4     | Backward         | Stream  | Reply to BEGIN                 |
1043/// | `SendMe`    | 5     | Forward/Backward | Both    | Flow control acknowledgment    |
1044/// | `Extend`    | 6     | Forward          | Circuit | Extend circuit (legacy)        |
1045/// | `Extended`  | 7     | Backward         | Circuit | Reply to EXTEND                |
1046/// | `Truncate`  | 8     | Forward          | Circuit | Remove last hop                |
1047/// | `Truncated` | 9     | Backward         | Circuit | Reply to TRUNCATE              |
1048/// | `Drop`      | 10    | Forward/Backward | Circuit | Ignorable no-op                |
1049/// | `Resolve`   | 11    | Forward          | Stream  | DNS resolution request         |
1050/// | `Resolved`  | 12    | Backward         | Stream  | Reply to RESOLVE               |
1051/// | `BeginDir`  | 13    | Forward          | Stream  | Request directory info         |
1052/// | `Extend2`   | 14    | Forward          | Circuit | Extend circuit (ntor)          |
1053/// | `Extended2` | 15    | Backward         | Circuit | Reply to EXTEND2               |
1054/// | `Unknown`   | -     | -                | -       | Unrecognized command           |
1055///
1056/// # Example
1057///
1058/// ```rust
1059/// use stem_rs::client::datatype::RelayCommand;
1060///
1061/// let (cmd, raw) = RelayCommand::get(1);
1062/// assert_eq!(cmd, RelayCommand::Begin);
1063/// assert_eq!(format!("{}", cmd), "RELAY_BEGIN");
1064/// ```
1065#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1066pub enum RelayCommand {
1067    /// Begin a new stream (forward, stream).
1068    Begin = 1,
1069    /// Transmit data (forward/backward, stream).
1070    Data = 2,
1071    /// End a stream (forward/backward, stream).
1072    End = 3,
1073    /// Reply to BEGIN (backward, stream).
1074    Connected = 4,
1075    /// Flow control - ready for more cells (forward/backward, stream/circuit).
1076    SendMe = 5,
1077    /// Extend circuit through another relay - legacy (forward, circuit).
1078    Extend = 6,
1079    /// Reply to EXTEND (backward, circuit).
1080    Extended = 7,
1081    /// Remove last circuit hop (forward, circuit).
1082    Truncate = 8,
1083    /// Reply to TRUNCATE (backward, circuit).
1084    Truncated = 9,
1085    /// Ignorable no-op (forward/backward, circuit).
1086    Drop = 10,
1087    /// Request DNS resolution (forward, stream).
1088    Resolve = 11,
1089    /// Reply to RESOLVE (backward, stream).
1090    Resolved = 12,
1091    /// Request directory information (forward, stream).
1092    BeginDir = 13,
1093    /// Extend circuit - ntor handshake (forward, circuit).
1094    Extend2 = 14,
1095    /// Reply to EXTEND2 (backward, circuit).
1096    Extended2 = 15,
1097    /// Unrecognized command.
1098    Unknown,
1099}
1100
1101impl RelayCommand {
1102    /// Converts a raw byte value to a `RelayCommand` and its integer representation.
1103    ///
1104    /// # Arguments
1105    ///
1106    /// * `val` - The raw command byte from the relay cell
1107    ///
1108    /// # Returns
1109    ///
1110    /// A tuple of `(RelayCommand, u8)` where the second element is the original
1111    /// byte value.
1112    pub fn get(val: u8) -> (RelayCommand, u8) {
1113        match val {
1114            1 => (RelayCommand::Begin, 1),
1115            2 => (RelayCommand::Data, 2),
1116            3 => (RelayCommand::End, 3),
1117            4 => (RelayCommand::Connected, 4),
1118            5 => (RelayCommand::SendMe, 5),
1119            6 => (RelayCommand::Extend, 6),
1120            7 => (RelayCommand::Extended, 7),
1121            8 => (RelayCommand::Truncate, 8),
1122            9 => (RelayCommand::Truncated, 9),
1123            10 => (RelayCommand::Drop, 10),
1124            11 => (RelayCommand::Resolve, 11),
1125            12 => (RelayCommand::Resolved, 12),
1126            13 => (RelayCommand::BeginDir, 13),
1127            14 => (RelayCommand::Extend2, 14),
1128            15 => (RelayCommand::Extended2, 15),
1129            _ => (RelayCommand::Unknown, val),
1130        }
1131    }
1132
1133    /// Returns the integer value for this relay command.
1134    ///
1135    /// Returns 255 for `Unknown` commands.
1136    pub fn value(&self) -> u8 {
1137        match self {
1138            RelayCommand::Begin => 1,
1139            RelayCommand::Data => 2,
1140            RelayCommand::End => 3,
1141            RelayCommand::Connected => 4,
1142            RelayCommand::SendMe => 5,
1143            RelayCommand::Extend => 6,
1144            RelayCommand::Extended => 7,
1145            RelayCommand::Truncate => 8,
1146            RelayCommand::Truncated => 9,
1147            RelayCommand::Drop => 10,
1148            RelayCommand::Resolve => 11,
1149            RelayCommand::Resolved => 12,
1150            RelayCommand::BeginDir => 13,
1151            RelayCommand::Extend2 => 14,
1152            RelayCommand::Extended2 => 15,
1153            RelayCommand::Unknown => 255,
1154        }
1155    }
1156}
1157
1158impl fmt::Display for RelayCommand {
1159    /// Formats the relay command as its canonical string name.
1160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1161        match self {
1162            RelayCommand::Begin => write!(f, "RELAY_BEGIN"),
1163            RelayCommand::Data => write!(f, "RELAY_DATA"),
1164            RelayCommand::End => write!(f, "RELAY_END"),
1165            RelayCommand::Connected => write!(f, "RELAY_CONNECTED"),
1166            RelayCommand::SendMe => write!(f, "RELAY_SENDME"),
1167            RelayCommand::Extend => write!(f, "RELAY_EXTEND"),
1168            RelayCommand::Extended => write!(f, "RELAY_EXTENDED"),
1169            RelayCommand::Truncate => write!(f, "RELAY_TRUNCATE"),
1170            RelayCommand::Truncated => write!(f, "RELAY_TRUNCATED"),
1171            RelayCommand::Drop => write!(f, "RELAY_DROP"),
1172            RelayCommand::Resolve => write!(f, "RELAY_RESOLVE"),
1173            RelayCommand::Resolved => write!(f, "RELAY_RESOLVED"),
1174            RelayCommand::BeginDir => write!(f, "RELAY_BEGIN_DIR"),
1175            RelayCommand::Extend2 => write!(f, "RELAY_EXTEND2"),
1176            RelayCommand::Extended2 => write!(f, "RELAY_EXTENDED2"),
1177            RelayCommand::Unknown => write!(f, "UNKNOWN"),
1178        }
1179    }
1180}
1181
1182/// Reason for closing a circuit or stream.
1183///
1184/// These codes indicate why a relay closed a circuit or stream. They are
1185/// used in DESTROY cells and RELAY_END cells.
1186///
1187/// # Variants
1188///
1189/// | Reason          | Value | Description                                    |
1190/// |-----------------|-------|------------------------------------------------|
1191/// | `None`          | 0     | No reason given                                |
1192/// | `Protocol`      | 1     | Tor protocol violation                         |
1193/// | `Internal`      | 2     | Internal error                                 |
1194/// | `Requested`     | 3     | Client sent TRUNCATE command                   |
1195/// | `Hibernating`   | 4     | Relay suspended to save bandwidth              |
1196/// | `ResourceLimit` | 5     | Out of memory, sockets, or circuit IDs         |
1197/// | `ConnectFailed` | 6     | Unable to reach relay                          |
1198/// | `OrIdentity`    | 7     | Connected but OR identity was wrong            |
1199/// | `ChannelClosed` | 8     | Connection carrying this circuit died          |
1200/// | `Finished`      | 9     | Circuit expired (dirty or old)                 |
1201/// | `Timeout`       | 10    | Circuit construction took too long             |
1202/// | `Destroyed`     | 11    | Circuit destroyed without client TRUNCATE      |
1203/// | `NoSuchService` | 12    | Request for unknown hidden service             |
1204/// | `Unknown`       | -     | Unrecognized reason                            |
1205///
1206/// # Example
1207///
1208/// ```rust
1209/// use stem_rs::client::datatype::CloseReason;
1210///
1211/// let (reason, raw) = CloseReason::get(3);
1212/// assert_eq!(reason, CloseReason::Requested);
1213/// assert_eq!(format!("{}", reason), "REQUESTED");
1214/// ```
1215#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1216pub enum CloseReason {
1217    /// No reason given.
1218    None = 0,
1219    /// Tor protocol violation.
1220    Protocol = 1,
1221    /// Internal error.
1222    Internal = 2,
1223    /// Client sent a TRUNCATE command.
1224    Requested = 3,
1225    /// Relay suspended, trying to save bandwidth.
1226    Hibernating = 4,
1227    /// Out of memory, sockets, or circuit IDs.
1228    ResourceLimit = 5,
1229    /// Unable to reach relay.
1230    ConnectFailed = 6,
1231    /// Connected, but its OR identity was not as expected.
1232    OrIdentity = 7,
1233    /// Connection that was carrying this circuit died.
1234    ChannelClosed = 8,
1235    /// Circuit has expired for being dirty or old.
1236    Finished = 9,
1237    /// Circuit construction took too long.
1238    Timeout = 10,
1239    /// Circuit was destroyed without a client TRUNCATE.
1240    Destroyed = 11,
1241    /// Request was for an unknown hidden service.
1242    NoSuchService = 12,
1243    /// Unrecognized reason.
1244    Unknown,
1245}
1246
1247impl CloseReason {
1248    /// Converts a raw byte value to a `CloseReason` and its integer representation.
1249    ///
1250    /// # Arguments
1251    ///
1252    /// * `val` - The raw reason byte from the protocol
1253    ///
1254    /// # Returns
1255    ///
1256    /// A tuple of `(CloseReason, u8)` where the second element is the original
1257    /// byte value.
1258    pub fn get(val: u8) -> (CloseReason, u8) {
1259        match val {
1260            0 => (CloseReason::None, 0),
1261            1 => (CloseReason::Protocol, 1),
1262            2 => (CloseReason::Internal, 2),
1263            3 => (CloseReason::Requested, 3),
1264            4 => (CloseReason::Hibernating, 4),
1265            5 => (CloseReason::ResourceLimit, 5),
1266            6 => (CloseReason::ConnectFailed, 6),
1267            7 => (CloseReason::OrIdentity, 7),
1268            8 => (CloseReason::ChannelClosed, 8),
1269            9 => (CloseReason::Finished, 9),
1270            10 => (CloseReason::Timeout, 10),
1271            11 => (CloseReason::Destroyed, 11),
1272            12 => (CloseReason::NoSuchService, 12),
1273            _ => (CloseReason::Unknown, val),
1274        }
1275    }
1276
1277    /// Returns the integer value for this close reason.
1278    ///
1279    /// Returns 255 for `Unknown` reasons.
1280    pub fn value(&self) -> u8 {
1281        match self {
1282            CloseReason::None => 0,
1283            CloseReason::Protocol => 1,
1284            CloseReason::Internal => 2,
1285            CloseReason::Requested => 3,
1286            CloseReason::Hibernating => 4,
1287            CloseReason::ResourceLimit => 5,
1288            CloseReason::ConnectFailed => 6,
1289            CloseReason::OrIdentity => 7,
1290            CloseReason::ChannelClosed => 8,
1291            CloseReason::Finished => 9,
1292            CloseReason::Timeout => 10,
1293            CloseReason::Destroyed => 11,
1294            CloseReason::NoSuchService => 12,
1295            CloseReason::Unknown => 255,
1296        }
1297    }
1298}
1299
1300impl fmt::Display for CloseReason {
1301    /// Formats the close reason as its canonical string name.
1302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1303        match self {
1304            CloseReason::None => write!(f, "NONE"),
1305            CloseReason::Protocol => write!(f, "PROTOCOL"),
1306            CloseReason::Internal => write!(f, "INTERNAL"),
1307            CloseReason::Requested => write!(f, "REQUESTED"),
1308            CloseReason::Hibernating => write!(f, "HIBERNATING"),
1309            CloseReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1310            CloseReason::ConnectFailed => write!(f, "CONNECTFAILED"),
1311            CloseReason::OrIdentity => write!(f, "OR_IDENTITY"),
1312            CloseReason::ChannelClosed => write!(f, "CHANNEL_CLOSED"),
1313            CloseReason::Finished => write!(f, "FINISHED"),
1314            CloseReason::Timeout => write!(f, "TIMEOUT"),
1315            CloseReason::Destroyed => write!(f, "DESTROYED"),
1316            CloseReason::NoSuchService => write!(f, "NOSUCHSERVICE"),
1317            CloseReason::Unknown => write!(f, "UNKNOWN"),
1318        }
1319    }
1320}
1321
1322/// Method of communicating with a relay in a circuit.
1323///
1324/// Link specifiers describe how to connect to a relay when extending a circuit.
1325/// They are used in EXTEND2 cells to specify the next hop. Multiple specifiers
1326/// can be provided to give the extending relay options for how to connect.
1327///
1328/// For more information, see the
1329/// [EXTEND cell specification](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n975).
1330///
1331/// # Wire Format
1332///
1333/// ```text
1334/// +----------+--------+------------------+
1335/// | Type (1) | Len (1)| Value (Len bytes)|
1336/// +----------+--------+------------------+
1337/// ```
1338///
1339/// # Variants
1340///
1341/// | Type | Value Size | Description                          |
1342/// |------|------------|--------------------------------------|
1343/// | 0    | 6 bytes    | IPv4 address (4) + port (2)          |
1344/// | 1    | 18 bytes   | IPv6 address (16) + port (2)         |
1345/// | 2    | 20 bytes   | SHA-1 identity fingerprint           |
1346/// | 3    | 32 bytes   | Ed25519 identity fingerprint         |
1347/// | 4+   | variable   | Unknown/future types                 |
1348///
1349/// # Example
1350///
1351/// ```rust
1352/// use stem_rs::client::datatype::LinkSpecifier;
1353///
1354/// // Create an IPv4 link specifier
1355/// let spec = LinkSpecifier::IPv4 {
1356///     address: "192.168.1.1".to_string(),
1357///     port: 9001,
1358/// };
1359///
1360/// // Pack and unpack
1361/// let packed = spec.pack();
1362/// let (unpacked, _) = LinkSpecifier::pop(&packed).unwrap();
1363///
1364/// match unpacked {
1365///     LinkSpecifier::IPv4 { address, port } => {
1366///         assert_eq!(address, "192.168.1.1");
1367///         assert_eq!(port, 9001);
1368///     }
1369///     _ => panic!("Expected IPv4"),
1370/// }
1371/// ```
1372#[derive(Debug, Clone, PartialEq, Eq)]
1373pub enum LinkSpecifier {
1374    /// TLS connection to an IPv4 address.
1375    IPv4 {
1376        /// The relay's IPv4 address.
1377        address: String,
1378        /// The relay's ORPort.
1379        port: u16,
1380    },
1381    /// TLS connection to an IPv6 address.
1382    IPv6 {
1383        /// The relay's IPv6 address (fully expanded form).
1384        address: String,
1385        /// The relay's ORPort.
1386        port: u16,
1387    },
1388    /// SHA-1 identity fingerprint (20 bytes).
1389    Fingerprint {
1390        /// The relay's SHA-1 identity fingerprint.
1391        fingerprint: [u8; 20],
1392    },
1393    /// Ed25519 identity fingerprint (32 bytes).
1394    Ed25519 {
1395        /// The relay's Ed25519 identity fingerprint.
1396        fingerprint: [u8; 32],
1397    },
1398    /// Unrecognized link specifier type.
1399    Unknown {
1400        /// The raw link type byte.
1401        link_type: u8,
1402        /// The raw value bytes.
1403        value: Vec<u8>,
1404    },
1405}
1406
1407impl LinkSpecifier {
1408    /// Returns the link type byte for this specifier.
1409    ///
1410    /// | Type | Meaning     |
1411    /// |------|-------------|
1412    /// | 0    | IPv4        |
1413    /// | 1    | IPv6        |
1414    /// | 2    | Fingerprint |
1415    /// | 3    | Ed25519     |
1416    /// | 4+   | Unknown     |
1417    pub fn link_type(&self) -> u8 {
1418        match self {
1419            LinkSpecifier::IPv4 { .. } => 0,
1420            LinkSpecifier::IPv6 { .. } => 1,
1421            LinkSpecifier::Fingerprint { .. } => 2,
1422            LinkSpecifier::Ed25519 { .. } => 3,
1423            LinkSpecifier::Unknown { link_type, .. } => *link_type,
1424        }
1425    }
1426
1427    /// Returns the encoded value bytes for this specifier.
1428    ///
1429    /// The format depends on the specifier type:
1430    /// - IPv4: 4-byte address + 2-byte port
1431    /// - IPv6: 16-byte address + 2-byte port
1432    /// - Fingerprint: 20-byte SHA-1 hash
1433    /// - Ed25519: 32-byte public key
1434    pub fn value(&self) -> Vec<u8> {
1435        match self {
1436            LinkSpecifier::IPv4 { address, port } => {
1437                let mut value = pack_ipv4_address(address);
1438                value.extend_from_slice(&port.to_be_bytes());
1439                value
1440            }
1441            LinkSpecifier::IPv6 { address, port } => {
1442                let mut value = pack_ipv6_address(address);
1443                value.extend_from_slice(&port.to_be_bytes());
1444                value
1445            }
1446            LinkSpecifier::Fingerprint { fingerprint } => fingerprint.to_vec(),
1447            LinkSpecifier::Ed25519 { fingerprint } => fingerprint.to_vec(),
1448            LinkSpecifier::Unknown { value, .. } => value.clone(),
1449        }
1450    }
1451
1452    /// Packs the link specifier into its wire format.
1453    ///
1454    /// # Returns
1455    ///
1456    /// A `Vec<u8>` containing: `[type (1), length (1), value...]`
1457    pub fn pack(&self) -> Vec<u8> {
1458        let value = self.value();
1459        let mut cell = Vec::new();
1460        cell.push(self.link_type());
1461        cell.push(value.len() as u8);
1462        cell.extend_from_slice(&value);
1463        cell
1464    }
1465
1466    /// Unpacks a link specifier from its wire format.
1467    ///
1468    /// # Arguments
1469    ///
1470    /// * `data` - The packed link specifier bytes
1471    ///
1472    /// # Errors
1473    ///
1474    /// Returns [`Error::Protocol`] if the data is malformed.
1475    pub fn unpack(data: &[u8]) -> Result<Self, Error> {
1476        let (spec, _) = Self::pop(data)?;
1477        Ok(spec)
1478    }
1479
1480    /// Unpacks a link specifier from the start of a byte slice, returning the remainder.
1481    ///
1482    /// # Arguments
1483    ///
1484    /// * `packed` - The byte slice to read from
1485    ///
1486    /// # Returns
1487    ///
1488    /// A tuple of `(LinkSpecifier, remainder)`.
1489    ///
1490    /// # Errors
1491    ///
1492    /// Returns [`Error::Protocol`] if:
1493    /// - The data is too short for the header
1494    /// - The specified length exceeds the available data
1495    /// - The value size doesn't match the expected size for the type
1496    pub fn pop(packed: &[u8]) -> Result<(Self, &[u8]), Error> {
1497        if packed.len() < 2 {
1498            return Err(Error::Protocol(
1499                "Link specifier requires at least 2 bytes".to_string(),
1500            ));
1501        }
1502        let (link_type, packed) = (packed[0], &packed[1..]);
1503        let (value_size, packed) = (packed[0] as usize, &packed[1..]);
1504        if value_size > packed.len() {
1505            return Err(Error::Protocol(format!(
1506                "Link specifier should have {} bytes, but only had {} remaining",
1507                value_size,
1508                packed.len()
1509            )));
1510        }
1511        let (value, packed) = split(packed, value_size);
1512
1513        let specifier = match link_type {
1514            0 => {
1515                if value.len() != 6 {
1516                    return Err(Error::Protocol(format!(
1517                        "IPv4 link specifiers should be six bytes, but was {} instead",
1518                        value.len()
1519                    )));
1520                }
1521                let (addr, port_bytes) = split(value, 4);
1522                let address = format!("{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3]);
1523                let port = u16::from_be_bytes([port_bytes[0], port_bytes[1]]);
1524                LinkSpecifier::IPv4 { address, port }
1525            }
1526            1 => {
1527                if value.len() != 18 {
1528                    return Err(Error::Protocol(format!(
1529                        "IPv6 link specifiers should be eighteen bytes, but was {} instead",
1530                        value.len()
1531                    )));
1532                }
1533                let (addr, port_bytes) = split(value, 16);
1534                let address = unpack_ipv6_address(addr);
1535                let port = u16::from_be_bytes([port_bytes[0], port_bytes[1]]);
1536                LinkSpecifier::IPv6 { address, port }
1537            }
1538            2 => {
1539                if value.len() != 20 {
1540                    return Err(Error::Protocol(format!(
1541                        "Fingerprint link specifiers should be twenty bytes, but was {} instead",
1542                        value.len()
1543                    )));
1544                }
1545                let mut fingerprint = [0u8; 20];
1546                fingerprint.copy_from_slice(value);
1547                LinkSpecifier::Fingerprint { fingerprint }
1548            }
1549            3 => {
1550                if value.len() != 32 {
1551                    return Err(Error::Protocol(format!(
1552                        "Ed25519 link specifiers should be thirty two bytes, but was {} instead",
1553                        value.len()
1554                    )));
1555                }
1556                let mut fingerprint = [0u8; 32];
1557                fingerprint.copy_from_slice(value);
1558                LinkSpecifier::Ed25519 { fingerprint }
1559            }
1560            _ => LinkSpecifier::Unknown {
1561                link_type,
1562                value: value.to_vec(),
1563            },
1564        };
1565
1566        Ok((specifier, packed))
1567    }
1568}
1569
1570/// Packs an IPv4 address string into 4 bytes.
1571fn pack_ipv4_address(address: &str) -> Vec<u8> {
1572    address
1573        .split('.')
1574        .filter_map(|s| s.parse::<u8>().ok())
1575        .collect()
1576}
1577
1578/// Packs an IPv6 address string into 16 bytes.
1579fn pack_ipv6_address(address: &str) -> Vec<u8> {
1580    let mut result = Vec::with_capacity(16);
1581    for segment in address.split(':') {
1582        if let Ok(val) = u16::from_str_radix(segment, 16) {
1583            result.extend_from_slice(&val.to_be_bytes());
1584        }
1585    }
1586    result
1587}
1588
1589/// KDF-TOR derived key material.
1590///
1591/// Contains the cryptographic keys and digests derived from shared key material
1592/// during circuit creation. This implements the KDF-TOR key derivation function
1593/// as defined in tor-spec section 5.2.1.
1594///
1595/// The derivation uses SHA-1 in a counter mode:
1596/// ```text
1597/// K = H(K0 | [00]) | H(K0 | [01]) | H(K0 | [02]) | ...
1598/// ```
1599///
1600/// Where `K0` is the input key material and `H` is SHA-1.
1601///
1602/// # Fields
1603///
1604/// The derived key material is split into five parts:
1605///
1606/// | Field            | Size     | Purpose                              |
1607/// |------------------|----------|--------------------------------------|
1608/// | `key_hash`       | 20 bytes | Proves knowledge of shared key       |
1609/// | `forward_digest` | 20 bytes | Forward digest hash seed             |
1610/// | `backward_digest`| 20 bytes | Backward digest hash seed            |
1611/// | `forward_key`    | 16 bytes | Forward encryption key (AES-128)     |
1612/// | `backward_key`   | 16 bytes | Backward encryption key (AES-128)    |
1613///
1614/// # Example
1615///
1616/// ```rust
1617/// use stem_rs::client::datatype::KDF;
1618///
1619/// // Derive keys from shared secret (e.g., from CREATE_FAST handshake)
1620/// let key_material = b"shared_secret_from_handshake____";
1621/// let kdf = KDF::from_value(key_material);
1622///
1623/// // Use the derived keys for encryption
1624/// assert_eq!(kdf.forward_key.len(), 16);
1625/// assert_eq!(kdf.backward_key.len(), 16);
1626/// ```
1627///
1628/// # Security
1629///
1630/// This KDF is used with the TAP and CREATE_FAST handshakes. Modern Tor
1631/// circuits use the ntor handshake with a different KDF (HKDF-SHA256).
1632#[derive(Debug, Clone, PartialEq, Eq)]
1633pub struct KDF {
1634    /// Hash that proves knowledge of the shared key.
1635    ///
1636    /// This is compared with the value sent by the relay to verify
1637    /// both parties derived the same key material.
1638    pub key_hash: [u8; HASH_LEN],
1639    /// Forward digest hash seed.
1640    ///
1641    /// Used to initialize the running digest for cells sent from
1642    /// client to relay.
1643    pub forward_digest: [u8; HASH_LEN],
1644    /// Backward digest hash seed.
1645    ///
1646    /// Used to initialize the running digest for cells sent from
1647    /// relay to client.
1648    pub backward_digest: [u8; HASH_LEN],
1649    /// Forward encryption key (AES-128-CTR).
1650    ///
1651    /// Used to encrypt relay cells sent from client to relay.
1652    pub forward_key: [u8; KEY_LEN],
1653    /// Backward encryption key (AES-128-CTR).
1654    ///
1655    /// Used to decrypt relay cells received from relay.
1656    pub backward_key: [u8; KEY_LEN],
1657}
1658
1659impl KDF {
1660    /// Derives key material from a shared secret.
1661    ///
1662    /// Implements the KDF-TOR key derivation function from tor-spec section 5.2.1.
1663    /// The input key material is expanded using SHA-1 in counter mode to produce
1664    /// the required key material.
1665    ///
1666    /// # Arguments
1667    ///
1668    /// * `key_material` - The shared secret from the circuit handshake
1669    ///
1670    /// # Returns
1671    ///
1672    /// A `KDF` struct containing all derived keys and digests.
1673    ///
1674    /// # Algorithm
1675    ///
1676    /// ```text
1677    /// derived = H(key_material | 0x00) | H(key_material | 0x01) | ...
1678    /// key_hash       = derived[0..20]
1679    /// forward_digest = derived[20..40]
1680    /// backward_digest= derived[40..60]
1681    /// forward_key    = derived[60..76]
1682    /// backward_key   = derived[76..92]
1683    /// ```
1684    ///
1685    /// # Example
1686    ///
1687    /// ```rust
1688    /// use stem_rs::client::datatype::KDF;
1689    ///
1690    /// let shared_secret = b"example_shared_secret___________";
1691    /// let kdf = KDF::from_value(shared_secret);
1692    ///
1693    /// // All fields are populated
1694    /// assert_eq!(kdf.key_hash.len(), 20);
1695    /// assert_eq!(kdf.forward_key.len(), 16);
1696    /// ```
1697    pub fn from_value(key_material: &[u8]) -> Self {
1698        let mut derived_key = Vec::new();
1699        let mut counter: u8 = 0;
1700
1701        while derived_key.len() < KEY_LEN * 2 + HASH_LEN * 3 {
1702            let mut hasher = Sha1::new();
1703            hasher.update(key_material);
1704            hasher.update([counter]);
1705            derived_key.extend_from_slice(&hasher.finalize());
1706            counter += 1;
1707        }
1708
1709        let (key_hash, rest) = split(&derived_key, HASH_LEN);
1710        let (forward_digest, rest) = split(rest, HASH_LEN);
1711        let (backward_digest, rest) = split(rest, HASH_LEN);
1712        let (forward_key, rest) = split(rest, KEY_LEN);
1713        let (backward_key, _) = split(rest, KEY_LEN);
1714
1715        let mut kdf = KDF {
1716            key_hash: [0u8; HASH_LEN],
1717            forward_digest: [0u8; HASH_LEN],
1718            backward_digest: [0u8; HASH_LEN],
1719            forward_key: [0u8; KEY_LEN],
1720            backward_key: [0u8; KEY_LEN],
1721        };
1722
1723        kdf.key_hash.copy_from_slice(key_hash);
1724        kdf.forward_digest.copy_from_slice(forward_digest);
1725        kdf.backward_digest.copy_from_slice(backward_digest);
1726        kdf.forward_key.copy_from_slice(forward_key);
1727        kdf.backward_key.copy_from_slice(backward_key);
1728
1729        kdf
1730    }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735    use super::*;
1736
1737    #[test]
1738    fn test_size_attributes() {
1739        assert_eq!(1, Size::Char.size());
1740        assert_eq!(2, Size::Short.size());
1741        assert_eq!(4, Size::Long.size());
1742        assert_eq!(8, Size::LongLong.size());
1743    }
1744
1745    #[test]
1746    fn test_size_pack() {
1747        assert_eq!(vec![0x12], Size::Char.pack(18));
1748        assert_eq!(vec![0x00, 0x12], Size::Short.pack(18));
1749        assert_eq!(vec![0x00, 0x00, 0x00, 0x12], Size::Long.pack(18));
1750        assert_eq!(
1751            vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12],
1752            Size::LongLong.pack(18)
1753        );
1754    }
1755
1756    #[test]
1757    fn test_size_unpack() {
1758        assert_eq!(18, Size::Char.unpack(&[0x12]).unwrap());
1759        assert_eq!(18, Size::Short.unpack(&[0x00, 0x12]).unwrap());
1760        assert_eq!(18, Size::Long.unpack(&[0x00, 0x00, 0x00, 0x12]).unwrap());
1761        assert_eq!(
1762            18,
1763            Size::LongLong
1764                .unpack(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12])
1765                .unwrap()
1766        );
1767        assert_eq!(97, Size::Char.unpack(b"a").unwrap());
1768        assert_eq!(24930, Size::Short.unpack(b"ab").unwrap());
1769        assert!(Size::Char.unpack(&[0x00, 0x12]).is_err());
1770    }
1771
1772    #[test]
1773    fn test_size_pop() {
1774        assert_eq!((18, &[][..]), Size::Char.pop(&[0x12]).unwrap());
1775        assert_eq!((0, &[0x12][..]), Size::Char.pop(&[0x00, 0x12]).unwrap());
1776        assert_eq!((18, &[][..]), Size::Short.pop(&[0x00, 0x12]).unwrap());
1777        assert!(Size::Char.pop(&[]).is_err());
1778        assert!(Size::Short.pop(&[0x12]).is_err());
1779    }
1780
1781    #[test]
1782    fn test_link_protocol_attributes() {
1783        let protocol = LinkProtocol::new(1);
1784        assert_eq!(1, protocol.version);
1785        assert_eq!(Size::Short, protocol.circ_id_size);
1786        assert_eq!(512, protocol.fixed_cell_length);
1787        assert_eq!(0x01, protocol.first_circ_id);
1788
1789        let protocol = LinkProtocol::new(10);
1790        assert_eq!(10, protocol.version);
1791        assert_eq!(Size::Long, protocol.circ_id_size);
1792        assert_eq!(514, protocol.fixed_cell_length);
1793        assert_eq!(0x80000000, protocol.first_circ_id);
1794    }
1795
1796    #[test]
1797    fn test_link_protocol_equality() {
1798        let protocol = LinkProtocol::new(1);
1799        assert_eq!(LinkProtocol::new(1), protocol);
1800        assert_ne!(LinkProtocol::new(2), protocol);
1801        assert!(protocol == 1);
1802        assert!(protocol != 2);
1803    }
1804
1805    #[test]
1806    fn test_address_ipv4() {
1807        let addr = Address::new("127.0.0.1").unwrap();
1808        assert_eq!(AddrType::IPv4, addr.addr_type);
1809        assert_eq!(4, addr.type_int);
1810        assert_eq!(Some("127.0.0.1".to_string()), addr.value);
1811        assert_eq!(vec![127, 0, 0, 1], addr.value_bin);
1812    }
1813
1814    #[test]
1815    fn test_address_ipv6() {
1816        let addr = Address::new("2001:0db8:0000:0000:0000:ff00:0042:8329").unwrap();
1817        assert_eq!(AddrType::IPv6, addr.addr_type);
1818        assert_eq!(6, addr.type_int);
1819        assert_eq!(
1820            Some("2001:0db8:0000:0000:0000:ff00:0042:8329".to_string()),
1821            addr.value
1822        );
1823    }
1824
1825    #[test]
1826    fn test_address_invalid() {
1827        assert!(Address::new("nope").is_err());
1828    }
1829
1830    #[test]
1831    fn test_address_packing() {
1832        let addr = Address::new("127.0.0.1").unwrap();
1833        let packed = addr.pack();
1834        assert_eq!(vec![0x04, 0x04, 0x7f, 0x00, 0x00, 0x01], packed);
1835
1836        let unpacked = Address::unpack(&packed).unwrap();
1837        assert_eq!(addr, unpacked);
1838    }
1839
1840    #[test]
1841    fn test_address_pop() {
1842        let data = b"\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00";
1843        let (addr, content) = Address::pop(data).unwrap();
1844        assert_eq!(b"\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00", content);
1845        assert_eq!(AddrType::IPv4, addr.addr_type);
1846        assert_eq!(4, addr.type_int);
1847        assert_eq!(Some("127.0.0.1".to_string()), addr.value);
1848        assert_eq!(vec![0x7f, 0x00, 0x00, 0x01], addr.value_bin);
1849    }
1850
1851    #[test]
1852    fn test_certificate_pack_pop() {
1853        let cert = Certificate::from_int(1, vec![0x08]);
1854        let packed = cert.pack();
1855        assert_eq!(vec![0x01, 0x00, 0x01, 0x08], packed);
1856
1857        let (unpacked, remainder) = Certificate::pop(&packed).unwrap();
1858        assert_eq!(cert, unpacked);
1859        assert!(remainder.is_empty());
1860    }
1861
1862    #[test]
1863    fn test_kdf_from_value() {
1864        let key_material = b"\xec\xec.\xeb7R\xf2\n\xcb\xce\x97\xf4\x86\x82\x19#\x10\x0f\x08\xf0\xa2Z\xdeJ\x8f2\x8cc\xf6\xfa\x0e\t\x83f\xc5\xe2\xb3\x94\xa8\x13";
1865        let kdf = KDF::from_value(key_material);
1866
1867        assert_eq!(
1868            b"\xca+\x81\x05\x14\x9d)o\xa6\x82\xe9B\xa8?\xf2\xaf\x85\x1b]6",
1869            &kdf.key_hash
1870        );
1871        assert_eq!(
1872            b"\xac\xcc\xbc\x91\xb1\xaf\xd7\xe0\xe9\x9dF#\xd8\xdbz\xe8\xe6\xca\x83,",
1873            &kdf.forward_digest
1874        );
1875        assert_eq!(
1876            b"*\xe5scX\xbb+\xca \xcb\xa4\xbc\xad\x0f\x95\x0cO\xcc\xac\xf1",
1877            &kdf.backward_digest
1878        );
1879        assert_eq!(
1880            b"\xc3\xbe\xc9\xe1\xf4\x90f\xdai\xf3\xf3\xf5\x14\xb5\xb9\x03",
1881            &kdf.forward_key
1882        );
1883        assert_eq!(
1884            b"U\xaf\x1e\x1b\xb1q||\x86A<_\xf7\xa0%\x86",
1885            &kdf.backward_key
1886        );
1887    }
1888
1889    #[test]
1890    fn test_link_specifier_ipv4() {
1891        let data = b"\x00\x06\x01\x02\x03\x04#)";
1892        let (spec, _) = LinkSpecifier::pop(data).unwrap();
1893
1894        match spec {
1895            LinkSpecifier::IPv4 { address, port } => {
1896                assert_eq!("1.2.3.4", address);
1897                assert_eq!(9001, port);
1898            }
1899            _ => panic!("Expected IPv4 link specifier"),
1900        }
1901
1902        let spec = LinkSpecifier::IPv4 {
1903            address: "1.2.3.4".to_string(),
1904            port: 9001,
1905        };
1906        assert_eq!(data.to_vec(), spec.pack());
1907    }
1908
1909    #[test]
1910    fn test_link_specifier_ipv6() {
1911        let data = b"\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)";
1912        let (spec, _) = LinkSpecifier::pop(data).unwrap();
1913
1914        match spec {
1915            LinkSpecifier::IPv6 { address, port } => {
1916                assert_eq!("2600:0000:0000:0000:0000:0000:0000:0001", address);
1917                assert_eq!(9001, port);
1918            }
1919            _ => panic!("Expected IPv6 link specifier"),
1920        }
1921    }
1922
1923    #[test]
1924    fn test_link_specifier_fingerprint() {
1925        let data = b"\x02\x14CCCCCCCCCCCCCCCCCCCC";
1926        let (spec, _) = LinkSpecifier::pop(data).unwrap();
1927
1928        match spec {
1929            LinkSpecifier::Fingerprint { fingerprint } => {
1930                assert_eq!(b"CCCCCCCCCCCCCCCCCCCC", &fingerprint);
1931            }
1932            _ => panic!("Expected Fingerprint link specifier"),
1933        }
1934    }
1935
1936    #[test]
1937    fn test_link_specifier_ed25519() {
1938        let data = b"\x03\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1939        let (spec, _) = LinkSpecifier::pop(data).unwrap();
1940
1941        match spec {
1942            LinkSpecifier::Ed25519 { fingerprint } => {
1943                assert_eq!(b"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", &fingerprint);
1944            }
1945            _ => panic!("Expected Ed25519 link specifier"),
1946        }
1947    }
1948
1949    #[test]
1950    fn test_link_specifier_unknown() {
1951        let data = b"\x04\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1952        let (spec, _) = LinkSpecifier::pop(data).unwrap();
1953
1954        match spec {
1955            LinkSpecifier::Unknown { link_type, value } => {
1956                assert_eq!(4, link_type);
1957                assert_eq!(b"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(), value);
1958            }
1959            _ => panic!("Expected Unknown link specifier"),
1960        }
1961    }
1962
1963    #[test]
1964    fn test_link_specifier_wrong_size() {
1965        let data = b"\x04\x20CCCCCCC";
1966        assert!(LinkSpecifier::pop(data).is_err());
1967    }
1968
1969    #[test]
1970    fn test_link_specifier_pack_roundtrip() {
1971        let test_inputs = [
1972            b"\x03\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(),
1973            b"\x04\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(),
1974            b"\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)".to_vec(),
1975            b"\x00\x06\x01\x02\x03\x04#)".to_vec(),
1976        ];
1977
1978        for val in test_inputs {
1979            let (spec, _) = LinkSpecifier::pop(&val).unwrap();
1980            assert_eq!(val, spec.pack());
1981        }
1982    }
1983
1984    #[test]
1985    fn test_address_unknown_type() {
1986        let addr = Address::with_type(b"hello", 12).unwrap();
1987        assert_eq!(AddrType::Unknown, addr.addr_type);
1988        assert_eq!(12, addr.type_int);
1989        assert_eq!(None, addr.value);
1990        assert_eq!(b"hello".to_vec(), addr.value_bin);
1991    }
1992
1993    #[test]
1994    fn test_address_ipv6_collapsed() {
1995        let addr = Address::new("2001:0DB8:AC10:FE01::").unwrap();
1996        assert_eq!(AddrType::IPv6, addr.addr_type);
1997        assert_eq!(6, addr.type_int);
1998        assert_eq!(
1999            Some("2001:0db8:ac10:fe01:0000:0000:0000:0000".to_string()),
2000            addr.value
2001        );
2002    }
2003
2004    #[test]
2005    fn test_address_ipv4_wrong_size() {
2006        let result = Address::with_type(&[0x7f, 0x00], 4);
2007        assert!(result.is_err());
2008    }
2009
2010    #[test]
2011    fn test_address_ipv6_wrong_size() {
2012        let result = Address::with_type(&[0x7f, 0x00], 6);
2013        assert!(result.is_err());
2014    }
2015
2016    #[test]
2017    fn test_certificate_unknown_type() {
2018        let cert = Certificate::from_int(12, b"hello".to_vec());
2019        assert_eq!(CertType::Unknown, cert.cert_type);
2020        assert_eq!(12, cert.type_int);
2021        assert_eq!(b"hello".to_vec(), cert.value);
2022    }
2023
2024    #[test]
2025    fn test_certificate_all_types() {
2026        let test_data = [
2027            (1, CertType::Link),
2028            (2, CertType::Identity),
2029            (3, CertType::Authenticate),
2030            (4, CertType::Ed25519Signing),
2031            (5, CertType::LinkCert),
2032            (6, CertType::Ed25519Authenticate),
2033            (7, CertType::Ed25519Identity),
2034        ];
2035
2036        for (type_int, expected_type) in test_data {
2037            let cert = Certificate::from_int(type_int, vec![0x7f, 0x00, 0x00, 0x01]);
2038            assert_eq!(expected_type, cert.cert_type);
2039            assert_eq!(type_int, cert.type_int);
2040            assert_eq!(vec![0x7f, 0x00, 0x00, 0x01], cert.value);
2041        }
2042    }
2043
2044    #[test]
2045    fn test_addr_type_get() {
2046        assert_eq!((AddrType::IPv4, 4), AddrType::get(4));
2047        assert_eq!((AddrType::IPv6, 6), AddrType::get(6));
2048        assert_eq!((AddrType::Hostname, 0), AddrType::get(0));
2049        assert_eq!((AddrType::ErrorTransient, 16), AddrType::get(16));
2050        assert_eq!((AddrType::ErrorPermanent, 17), AddrType::get(17));
2051        assert_eq!((AddrType::Unknown, 25), AddrType::get(25));
2052    }
2053
2054    #[test]
2055    fn test_relay_command_get() {
2056        assert_eq!((RelayCommand::Begin, 1), RelayCommand::get(1));
2057        assert_eq!((RelayCommand::Data, 2), RelayCommand::get(2));
2058        assert_eq!((RelayCommand::End, 3), RelayCommand::get(3));
2059        assert_eq!((RelayCommand::BeginDir, 13), RelayCommand::get(13));
2060        assert_eq!((RelayCommand::Unknown, 99), RelayCommand::get(99));
2061    }
2062
2063    #[test]
2064    fn test_close_reason_get() {
2065        assert_eq!((CloseReason::None, 0), CloseReason::get(0));
2066        assert_eq!((CloseReason::Protocol, 1), CloseReason::get(1));
2067        assert_eq!((CloseReason::Requested, 3), CloseReason::get(3));
2068        assert_eq!((CloseReason::Finished, 9), CloseReason::get(9));
2069        assert_eq!((CloseReason::Unknown, 99), CloseReason::get(99));
2070    }
2071
2072    #[test]
2073    fn test_link_protocol_version_3_boundary() {
2074        let protocol = LinkProtocol::new(3);
2075        assert_eq!(Size::Short, protocol.circ_id_size);
2076        assert_eq!(0x01, protocol.first_circ_id);
2077
2078        let protocol = LinkProtocol::new(4);
2079        assert_eq!(Size::Long, protocol.circ_id_size);
2080        assert_eq!(0x80000000, protocol.first_circ_id);
2081    }
2082
2083    #[test]
2084    fn test_link_specifier_ipv4_wrong_size() {
2085        let data = b"\x00\x04\x01\x02\x03\x04";
2086        let result = LinkSpecifier::pop(data);
2087        assert!(result.is_err());
2088    }
2089
2090    #[test]
2091    fn test_link_specifier_ipv6_wrong_size() {
2092        let data = b"\x01\x10&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
2093        let result = LinkSpecifier::pop(data);
2094        assert!(result.is_err());
2095    }
2096
2097    #[test]
2098    fn test_link_specifier_fingerprint_wrong_size() {
2099        let data = b"\x02\x10CCCCCCCCCCCCCCCC";
2100        let result = LinkSpecifier::pop(data);
2101        assert!(result.is_err());
2102    }
2103
2104    #[test]
2105    fn test_link_specifier_ed25519_wrong_size() {
2106        let data = b"\x03\x10CCCCCCCCCCCCCCCC";
2107        let result = LinkSpecifier::pop(data);
2108        assert!(result.is_err());
2109    }
2110}