rc5_rs/word.rs
1use {
2 crate::error::Error,
3 num::{
4 traits::{WrappingAdd, WrappingSub},
5 Num,
6 NumCast,
7 PrimInt,
8 },
9 secrecy::Zeroize,
10 std::{fmt::Debug, mem::size_of, ops::BitXor},
11};
12
13/// RC5 Word
14///
15/// This is one of the parameters of the RC5 algorithm. It is the size
16/// of the words that the algorithm operates on. By default all sensible
17/// word sizes are implemented (16/32/64/128).
18///
19/// If you want to use a different word size to support more exotic
20/// architectures, you can implement this trait for the type that you want
21/// to use as a word.
22///
23/// the following operations are required to be implemented by any type
24/// that wants to act as a word:
25/// - zero
26/// - bitor
27/// - bitxor
28/// - wrapping_add
29/// - wrapping_sub
30/// - rotate_left
31/// - rotate_right
32/// - shr
33/// - shl
34///
35/// Luckily all those methods are implemented for all Rust primitive types by
36/// the num crate, so you can just use those.
37///
38/// Also the type must calculate it's P and Q magic numbers according to
39/// this formula:
40///
41/// P = Odd((e − 2)2^w)
42/// Q = Odd((φ − 1)2^w)
43///
44/// where e is the base of natural logarithms and φ is the golden ratio and w is
45/// the word size.
46pub trait Word:
47 Num + BitXor + WrappingAdd + WrappingSub + PrimInt + NumCast + Debug + Zeroize
48where
49 Self: Sized,
50{
51 /// This is the W parameter of the RC5 algorithm.
52 const BITS: usize = size_of::<Self>() * 8;
53
54 const P: Self; // Odd((e − 2)2^w)
55 const Q: Self; // Odd((φ − 1)2^w)
56
57 /// Converts a little endian byte slice to a word
58 fn from_le_bytes(bytes: &[u8]) -> Result<Self, Error>;
59
60 /// Converts a word to a little endian byte slice
61 fn to_le_bytes(&self) -> Vec<u8>;
62}
63
64macro_rules! impl_word {
65 ($typ:tt, $q:expr, $p:expr) => {
66 impl Word for $typ {
67 const P: $typ = $p;
68 const Q: $typ = $q;
69
70 fn from_le_bytes(bytes: &[u8]) -> Result<Self, Error> {
71 if bytes.len() != size_of::<Self>() {
72 return Err(Error::InvalidBytes);
73 }
74
75 Ok($typ::from_le_bytes(
76 bytes.try_into().map_err(|_| Error::InvalidBytes)?,
77 ))
78 }
79
80 fn to_le_bytes(&self) -> Vec<u8> {
81 $typ::to_le_bytes(*self).to_vec()
82 }
83 }
84 };
85}
86
87impl_word!(u16, 0x9E37, 0xB7E1);
88impl_word!(u32, 0x9E3779B9, 0xB7E15163);
89impl_word!(u64, 0x9E3779B97F4A7C15, 0xB7E151628AED2A6B);
90impl_word!(
91 u128,
92 0x9E3779B97F4A7C15F39CC0605CEDC835,
93 0xB7E151628AED2A6ABF7158809CF4F3C7
94);