In RustCrypto we have a generic implementation of the CCM mode. This mode is generic over two integer parameters (tag and nonce sizes) and the algorithm is defined only for a number of them. With typenum
which we currently use defining this restriction is easy enough, we simply introduce (sealed) traits implemented only for valid sizes. But what should we do with a hypothetical migration to const generics?
One way is to abuse the proposed const_evaluatable_checked
syntax:
struct Ccm<C, const N: usize, const M: usize>
where
C: BlockCipher,
[(); is_valid_nonce_size(N)]: Sized,
[(), is_valid_tag_size(M)]: Sized,
{ .. }
const fn is_valid_nonce_size(n: usize) -> usize {
match n {
7..=13 => 0,
_ => panic!("invalid CCM nonce size"),
}
}
The code can be improved a bit by introduction of hypothetical require
clauses:
struct Ccm<C: BlockCipher, const N: usize, const M: usize>
where C: BlockCipher
require is_valid_nonce_size(N), is_valid_tag_size(M)
{ .. }
const fn is_valid_nonce_size(n: usize) -> bool { ... }
But it still feels quite weird to restrict space of valid constant parameters using const fn
s. We effectively use imperative approach instead of the usual declarative one. Also this approach does not allow extension of allowed const parameters in third-party crates (we don't need it in the CCM's case, but it could be really useful in some use cases).
Const parameters behave as types in many regards, so how about allowing trait bounds on const parameters?
struct Ccm<C: BlockCipher, const N: usize, const M: usize>
where C: BlockCipher, N: NonceSize, M: TagSize
{ .. }
trait NonceSize {
// potential helper methods tied to a constant.
// constants will not be able to implement traits with
// methods containing `self` parameters.
fn foo();
}
impl NonceSize for const 4usize { .. }
Of course, this method is only practical when number of accepted values is relatively small.
Unresolved questions:
- Should we distinguish between general traits and those intended for being implemented by constants in their definition?
- Calling syntax for trait methods on constants.