Skip to main content

rc5_block/
types.rs

1use rand::Rng;
2
3/// # RC5 version identifier
4///
5/// It represents RC5 control block parameters. These parameters are
6/// defined as follows:
7///
8/// 1. Algorithm version (1 for RC5)
9/// 2. Word-size in bits
10/// 3. Number of rounds.
11/// 4. Key length in bytes.
12///
13/// This is how these parameters are arranged in version string:
14///
15/// RC5-v<`Algorithm version`>/<`Word-size`>/<`Rounds`>/<`Key-length`>
16///
17/// This can be useful when asserting what parametric version of RC5 to
18/// use for certain applications.
19pub struct Version(Vec<u8>);
20
21impl Version {
22    /// Construct a new `Version` from a 4‑element parameter vector.
23    ///
24    /// Expects the vector to be exactly four bytes:
25    /// `[algorithm, word_bits, rounds, key_bytes]`.
26    pub fn from_parametric_vector(params: Vec<u8>) -> Self {
27        Self(params)
28    }
29
30    /// Render the RC5 version string in the form: `RC5-vA/B/C/D`.
31    ///
32    /// Where A,B,C,D correspond to the four parameters passed to `new`.
33    pub fn version(&self) -> String {
34        let params = &self.0;
35        format!(
36            "RC5-v{}/{}/{}/{}",
37            params[0], params[1], params[2], params[3]
38        )
39    }
40}
41
42/// A core trait to define a word in `N-sized` blocks of a block cipher. This
43/// word must support arithmatic and binary operations required for cryptographic
44/// functions.
45pub trait Word: Clone + Copy + std::ops::BitXor<Output = Self> {
46    /// A constant zero value for a `Word` type.
47    const ZERO: Self;
48
49    /// Number of bytes in this word
50    const BYTES: usize;
51
52    /// Magic constant `P` represented by this word to
53    /// be used in RC5 key expansion.
54    const P: Self;
55
56    /// Magic constant `Q` represented by this word to
57    /// be used in RC5 key expansion.
58    const Q: Self;
59
60    /// Cast a 8-bit value to this word type.
61    fn from_u8(val: u8) -> Self;
62
63    /// Parse this word from a little‐endian byte slice of length `BYTES`.
64    ///
65    /// Returns `None` if the slice length is not equal to `Word::BYTES`
66    fn from_bytes_slice(slice: &[u8]) -> Option<Self>;
67
68    /// Serialize this word to a little‐endian bytes list.
69    fn to_bytes_slice(&self) -> Vec<u8>;
70
71    /// Generate a random word using the given RNG.
72    fn random<R: Rng + ?Sized>(rng: &mut R) -> Self;
73
74    /// Wrapped addition
75    fn wrapping_add(self, val: Self) -> Self;
76
77    /// Wrapped subtraction
78    fn wrapping_sub(self, val: Self) -> Self;
79
80    /// Left bitwise rotation
81    fn rotate_left(self, bits: Self) -> Self;
82
83    /// Right bitwise rotation
84    fn rotate_right(self, bits: Self) -> Self;
85}
86
87macro_rules! magic_consts {
88    (u16) => {
89        const P: u16 = 0xb7e1;
90        const Q: u16 = 0x9e37;
91    };
92    (u32) => {
93        const P: u32 = 0xb7e15163;
94        const Q: u32 = 0x9e3779b9;
95    };
96    (u64) => {
97        const P: u64 = 0xb7e151628aed2a6b;
98        const Q: u64 = 0x9e3779b97f4a7c15;
99    };
100    (u128) => {
101        const P: u128 = 0x9E3779B97F4A7C15F39CC0605CEDC835;
102        const Q: u128 = 0xB7E151628AED2A6ABF7158809CF4F3C7;
103    };
104}
105
106macro_rules! impl_word_for_prim {
107    ($($t:ident),*) => {
108        $(
109            impl Word for $t {
110                const ZERO: $t = 0;
111                const BYTES: usize = (<$t>::BITS / 8) as usize;
112
113                magic_consts!($t);
114
115                #[inline]
116                fn from_u8(val: u8) -> Self {
117                    val as $t
118                }
119
120                #[inline]
121                fn from_bytes_slice(slice: &[u8]) -> Option<Self> {
122                    slice.try_into().ok().map(|b| <$t>::from_le_bytes(b))
123                }
124
125                fn to_bytes_slice(& self) -> Vec<u8> {
126                    self.to_le_bytes().to_vec()
127                }
128
129                #[inline]
130               fn random<R: Rng + ?Sized>(rng: &mut R) -> Self {
131                    rng.r#gen()
132               }
133
134                #[inline]
135                fn wrapping_add(self, other: Self) -> Self {
136                    <$t>::wrapping_add(self, other)
137                }
138
139                #[inline]
140                fn wrapping_sub(self, other: Self) -> Self {
141                    <$t>::wrapping_sub(self, other)
142                }
143
144                #[inline]
145                fn rotate_left(self, bits: Self) -> Self {
146                    self.rotate_left(bits as u32)
147                }
148
149                #[inline]
150                fn rotate_right(self, bits: Self) -> Self {
151                    self.rotate_right(bits as u32)
152                }
153            }
154        )*
155    }
156}
157
158impl_word_for_prim!(u16, u32, u64, u128);