I've been writing a hobbyist AES library in Rust and I've run into the problem of eccessive boilerplate code. Basically I represent an AES key with the following struct:
pub struct AesKey<const N: usize> {
data: [u32; N],
}
N can be any of the following values:
- 4 for 128 bits
- 6 for 192 bits
- 8 for 256 bits
This struct then needs to implement the following trait
pub trait AesKeyOps<const N: usize, const N_ROUND_KEYS: usize> {
// ...
}
for each of the possible values of N.
And for each of those implementations it needs to implement even more traits for padding, block modes and other implementation logic.
I originally used const generics in my code to make components more reusable, but at a certain point the impl blocks just started to grow exponentially, even though they all contained basically the same code with just some minor tweaks (9 impl blocks for the different padding schemes [3 schemes * 3 key sizes] and the only difference between them are the values for the generics). I tried using an enum as a generic, as that would be able to contain all of the necessary data, but they aren't allowed as any type of generic.
What can I do to avoid repeating code this much while using generics in rust?