Skip to main content

vcl_protocol/
packet.rs

1//! # VCL Packet
2//!
3//! Defines [`VCLPacket`] — the core unit of data transmission in VCL Protocol —
4//! and [`PacketType`] which determines how the connection layer routes each packet.
5//!
6//! Every packet is:
7//! - **Chained** — contains the SHA-256 hash of the previous packet in the same direction
8//! - **Signed** — Ed25519 signature over the packet hash
9//! - **Encrypted** — payload encrypted with XChaCha20-Poly1305
10
11use sha2::{Sha256, Digest};
12use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer, Verifier};
13use serde::{Serialize, Deserialize};
14use crate::error::VCLError;
15
16/// Determines how a [`VCLPacket`] is routed by the connection layer.
17///
18/// Users only interact with `Data` packets directly.
19/// `Ping`, `Pong`, `KeyRotation`, and `Fragment` are handled transparently inside `recv()`.
20#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
21pub enum PacketType {
22    /// A regular data packet — returned by [`VCLConnection::recv()`](crate::connection::VCLConnection::recv).
23    Data,
24    /// Liveness check sent by [`VCLConnection::ping()`](crate::connection::VCLConnection::ping).
25    Ping,
26    /// Automatic reply to a [`Ping`](PacketType::Ping). Handled inside `recv()`.
27    Pong,
28    /// Mid-session key rotation initiated by [`VCLConnection::rotate_keys()`](crate::connection::VCLConnection::rotate_keys).
29    KeyRotation,
30    /// A fragment of a larger message. Payload contains a serialized [`crate::fragment::Fragment`].
31    /// Reassembly is handled transparently inside `recv()`.
32    Fragment,
33}
34
35/// A single unit of data transmission in VCL Protocol.
36///
37/// Packets are created, signed, and serialized internally by [`VCLConnection`].
38/// After `recv()` returns, `payload` contains the **decrypted** data.
39///
40/// [`VCLConnection`]: crate::connection::VCLConnection
41#[derive(Serialize, Deserialize, Clone, Debug)]
42pub struct VCLPacket {
43    /// Protocol version. Currently `2`.
44    pub version: u8,
45    /// Routing type — see [`PacketType`].
46    pub packet_type: PacketType,
47    /// Monotonically increasing sequence number (per direction).
48    pub sequence: u64,
49    /// SHA-256 hash of the previous packet in the same direction.
50    /// All-zeros for the first packet.
51    pub prev_hash: Vec<u8>,
52    /// 24-byte XChaCha20 nonce used to encrypt this packet's payload.
53    pub nonce: [u8; 24],
54    /// After `recv()`: decrypted payload. On the wire: XChaCha20-Poly1305 ciphertext.
55    pub payload: Vec<u8>,
56    /// 64-byte Ed25519 signature over the packet hash.
57    pub signature: Vec<u8>,
58}
59
60impl VCLPacket {
61    /// Create a new [`PacketType::Data`] packet.
62    pub fn new(sequence: u64, prev_hash: Vec<u8>, payload: Vec<u8>, nonce: [u8; 24]) -> Self {
63        Self::new_typed(sequence, prev_hash, payload, nonce, PacketType::Data)
64    }
65
66    /// Create a packet with a specific [`PacketType`].
67    /// Used internally for Ping, Pong, KeyRotation, and Fragment packets.
68    pub fn new_typed(
69        sequence: u64,
70        prev_hash: Vec<u8>,
71        payload: Vec<u8>,
72        nonce: [u8; 24],
73        packet_type: PacketType,
74    ) -> Self {
75        VCLPacket {
76            version: 2,
77            packet_type,
78            sequence,
79            prev_hash,
80            nonce,
81            payload,
82            signature: Vec::new(),
83        }
84    }
85
86    /// Compute the SHA-256 hash of this packet.
87    /// Used for chain linking and signature generation.
88    pub fn compute_hash(&self) -> Vec<u8> {
89        let mut hasher = Sha256::new();
90        hasher.update(self.version.to_be_bytes());
91        hasher.update(self.sequence.to_be_bytes());
92        hasher.update(&self.prev_hash);
93        hasher.update(&self.nonce);
94        hasher.update(&self.payload);
95        hasher.finalize().to_vec()
96    }
97
98    /// Sign this packet with an Ed25519 `private_key` (32 bytes).
99    ///
100    /// # Errors
101    /// Returns [`VCLError::InvalidKey`] if `private_key` is not 32 bytes.
102    pub fn sign(&mut self, private_key: &[u8]) -> Result<(), VCLError> {
103        let key_bytes: &[u8; 32] = private_key
104            .try_into()
105            .map_err(|_| VCLError::InvalidKey("Private key must be 32 bytes".to_string()))?;
106        let signing_key = SigningKey::from_bytes(key_bytes);
107        let hash = self.compute_hash();
108        let signature: Signature = signing_key.sign(&hash);
109        self.signature = signature.to_bytes().to_vec();
110        Ok(())
111    }
112
113    /// Verify the Ed25519 signature against `public_key` (32 bytes).
114    ///
115    /// Returns `Ok(true)` if valid, `Ok(false)` if the signature does not match.
116    ///
117    /// # Errors
118    /// Returns [`VCLError::InvalidKey`] if `public_key` is malformed.
119    pub fn verify(&self, public_key: &[u8]) -> Result<bool, VCLError> {
120        if self.signature.len() != 64 {
121            return Ok(false);
122        }
123        let key_bytes: &[u8; 32] = public_key
124            .try_into()
125            .map_err(|_| VCLError::InvalidKey("Public key must be 32 bytes".to_string()))?;
126        let verifying_key = VerifyingKey::from_bytes(key_bytes)
127            .map_err(|e| VCLError::InvalidKey(format!("Invalid public key: {}", e)))?;
128        let sig_bytes: &[u8; 64] = self.signature
129            .as_slice()
130            .try_into()
131            .map_err(|_| VCLError::InvalidKey("Signature must be 64 bytes".to_string()))?;
132        let signature = Signature::from_bytes(sig_bytes);
133        let hash = self.compute_hash();
134        Ok(verifying_key.verify(&hash, &signature).is_ok())
135    }
136
137    /// Returns `true` if `self.prev_hash` matches `expected_prev_hash`.
138    pub fn validate_chain(&self, expected_prev_hash: &[u8]) -> bool {
139        self.prev_hash == expected_prev_hash
140    }
141
142    /// Serialize this packet to bytes using bincode.
143    pub fn serialize(&self) -> Vec<u8> {
144        bincode::serialize(self).unwrap()
145    }
146
147    /// Deserialize a packet from bytes.
148    ///
149    /// # Errors
150    /// Returns [`VCLError::SerializationError`] if the bytes are malformed.
151    pub fn deserialize(data: &[u8]) -> Result<Self, VCLError> {
152        bincode::deserialize(data).map_err(|e| VCLError::SerializationError(e.to_string()))
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use crate::crypto::KeyPair;
159    use super::*;
160
161    fn test_keypair() -> KeyPair {
162        KeyPair::generate()
163    }
164
165    #[test]
166    fn test_packet_new() {
167        let packet = VCLPacket::new(1, vec![0; 32], b"test".to_vec(), [0; 24]);
168        assert_eq!(packet.version, 2);
169        assert_eq!(packet.sequence, 1);
170        assert_eq!(packet.payload, b"test");
171        assert_eq!(packet.packet_type, PacketType::Data);
172    }
173
174    #[test]
175    fn test_compute_hash() {
176        let p1 = VCLPacket::new(1, vec![0; 32], b"A".to_vec(), [0; 24]);
177        let p2 = VCLPacket::new(1, vec![0; 32], b"B".to_vec(), [0; 24]);
178        assert_ne!(p1.compute_hash(), p2.compute_hash());
179    }
180
181    #[test]
182    fn test_sign_verify() {
183        let kp = test_keypair();
184        let mut packet = VCLPacket::new(1, vec![0; 32], b"test".to_vec(), [0; 24]);
185        packet.sign(&kp.private_key).unwrap();
186        assert!(packet.verify(&kp.public_key).unwrap());
187    }
188
189    #[test]
190    fn test_verify_wrong_key_fails() {
191        let kp1 = test_keypair();
192        let kp2 = test_keypair();
193        let mut packet = VCLPacket::new(1, vec![0; 32], b"test".to_vec(), [0; 24]);
194        packet.sign(&kp1.private_key).unwrap();
195        assert!(!packet.verify(&kp2.public_key).unwrap());
196    }
197
198    #[test]
199    fn test_validate_chain() {
200        let prev = vec![1, 2, 3];
201        let packet = VCLPacket::new(1, prev.clone(), b"test".to_vec(), [0; 24]);
202        assert!(packet.validate_chain(&prev));
203        assert!(!packet.validate_chain(&[4, 5, 6]));
204    }
205
206    #[test]
207    fn test_serialize_deserialize() {
208        let original = VCLPacket::new(42, vec![9; 32], b"payload".to_vec(), [7; 24]);
209        let bytes = original.serialize();
210        let restored = VCLPacket::deserialize(&bytes).unwrap();
211        assert_eq!(original.sequence, restored.sequence);
212        assert_eq!(original.payload, restored.payload);
213        assert_eq!(original.nonce, restored.nonce);
214        assert_eq!(restored.packet_type, PacketType::Data);
215    }
216
217    #[test]
218    fn test_packet_types() {
219        let ping = VCLPacket::new_typed(0, vec![0; 32], vec![], [0; 24], PacketType::Ping);
220        let pong = VCLPacket::new_typed(0, vec![0; 32], vec![], [0; 24], PacketType::Pong);
221        let rot  = VCLPacket::new_typed(0, vec![0; 32], vec![], [0; 24], PacketType::KeyRotation);
222        let frag = VCLPacket::new_typed(0, vec![0; 32], vec![], [0; 24], PacketType::Fragment);
223        assert_eq!(ping.packet_type, PacketType::Ping);
224        assert_eq!(pong.packet_type, PacketType::Pong);
225        assert_eq!(rot.packet_type,  PacketType::KeyRotation);
226        assert_eq!(frag.packet_type, PacketType::Fragment);
227    }
228}