nym_sphinx_params/
packet_version.rs

1// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::{Deserialize, Serialize};
5use std::fmt::{Display, Formatter};
6use thiserror::Error;
7
8// wait, wait, but why are we starting with version 7?
9// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
10// - packet_version (starting with v1.1.0)
11// - packet_size indicator
12// - packet_type
13// - sphinx key rotation (starting with v1.13.0 - the Dolcelatte release)
14
15// it also just so happens that the only valid values for packet_size indicator include values 1-6
16// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
17// otherwise we should treat it as legacy
18/// Increment it whenever we perform any breaking change in the wire format!
19pub const INITIAL_PACKET_VERSION_NUMBER: u8 = 7;
20pub const KEY_ROTATION_VERSION_NUMBER: u8 = 8;
21pub const CURRENT_PACKET_VERSION_NUMBER: u8 = KEY_ROTATION_VERSION_NUMBER;
22pub const CURRENT_PACKET_VERSION: PacketVersion =
23    PacketVersion::unchecked(CURRENT_PACKET_VERSION_NUMBER);
24
25pub const LEGACY_PACKET_VERSION: PacketVersion =
26    PacketVersion::unchecked(INITIAL_PACKET_VERSION_NUMBER);
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
29pub struct PacketVersion(u8);
30
31impl Display for PacketVersion {
32    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
33        self.0.fmt(f)
34    }
35}
36
37#[derive(Debug, Error)]
38#[error("attempted to use legacy packet version")]
39pub struct InvalidPacketVersion;
40
41impl PacketVersion {
42    pub fn new() -> Self {
43        PacketVersion(CURRENT_PACKET_VERSION_NUMBER)
44    }
45
46    pub fn is_initial(&self) -> bool {
47        self.0 == INITIAL_PACKET_VERSION_NUMBER
48    }
49
50    const fn unchecked(version: u8) -> PacketVersion {
51        PacketVersion(version)
52    }
53
54    pub fn as_u8(&self) -> u8 {
55        (*self).into()
56    }
57}
58
59impl TryFrom<u8> for PacketVersion {
60    type Error = InvalidPacketVersion;
61
62    fn try_from(value: u8) -> Result<Self, Self::Error> {
63        if value < INITIAL_PACKET_VERSION_NUMBER {
64            return Err(InvalidPacketVersion);
65        }
66        Ok(PacketVersion(value))
67    }
68}
69
70impl From<PacketVersion> for u8 {
71    fn from(packet_version: PacketVersion) -> Self {
72        packet_version.0
73    }
74}
75
76impl Default for PacketVersion {
77    fn default() -> Self {
78        PacketVersion::new()
79    }
80}