1#![allow(dead_code)]
6
7use crate::error::Unspecified;
10use crate::rand;
11use zeroize::Zeroize;
12
13pub const IV_LEN_128_BIT: usize = 16;
15
16pub struct FixedLength<const L: usize>([u8; L]);
19
20impl<const L: usize> FixedLength<L> {
21 #[allow(clippy::must_use_candidate)]
23 pub fn size(&self) -> usize {
24 L
25 }
26
27 pub fn new() -> Result<Self, Unspecified> {
33 let mut iv_bytes = [0u8; L];
34 rand::fill(&mut iv_bytes)?;
35 Ok(Self(iv_bytes))
36 }
37}
38
39impl<const L: usize> Drop for FixedLength<L> {
40 fn drop(&mut self) {
41 self.0.zeroize();
42 }
43}
44
45impl<const L: usize> AsRef<[u8; L]> for FixedLength<L> {
46 #[inline]
47 fn as_ref(&self) -> &[u8; L] {
48 &self.0
49 }
50}
51
52impl<const L: usize> From<&[u8; L]> for FixedLength<L> {
53 #[inline]
54 fn from(bytes: &[u8; L]) -> Self {
55 FixedLength(bytes.to_owned())
56 }
57}
58
59impl<const L: usize> From<[u8; L]> for FixedLength<L> {
60 #[inline]
61 fn from(bytes: [u8; L]) -> Self {
62 FixedLength(bytes)
63 }
64}
65
66impl<const L: usize> TryFrom<&[u8]> for FixedLength<L> {
67 type Error = Unspecified;
68
69 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
70 let value: &[u8; L] = value.try_into()?;
71 Ok(Self::from(*value))
72 }
73}
74
75impl<const L: usize> TryFrom<FixedLength<L>> for [u8; L] {
76 type Error = Unspecified;
77
78 fn try_from(value: FixedLength<L>) -> Result<Self, Self::Error> {
79 Ok(value.0)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use crate::iv::FixedLength;
86
87 #[test]
88 fn test_size() {
89 let fixed = FixedLength::from([0u8; 16]);
90 assert_eq!(16, fixed.size());
91
92 let array = [0u8; 12];
93 let fixed = FixedLength::<12>::try_from(array.as_slice()).unwrap();
94 assert_eq!(12, fixed.size());
95
96 assert!(FixedLength::<16>::try_from(array.as_slice()).is_err());
97
98 assert!(TryInto::<[u8; 12]>::try_into(fixed).is_ok());
99 }
100}