Skip to main content

ctr/flavors/
ctr128.rs

1//! 128-bit counter flavors.
2use super::CtrFlavor;
3use cipher::{
4    array::{Array, ArraySize},
5    typenum::{PartialDiv, PartialQuot, U16, Unsigned},
6};
7use core::fmt;
8
9type ChunkSize = U16;
10type Chunks<B> = PartialQuot<B, ChunkSize>;
11const CS: usize = ChunkSize::USIZE;
12
13#[derive(Clone)]
14pub struct CtrNonce128<N: ArraySize> {
15    ctr: u128,
16    nonce: Array<u128, N>,
17}
18
19impl<N: ArraySize> fmt::Debug for CtrNonce128<N> {
20    #[inline]
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        f.write_str("CtrNonce128 { ... }")
23    }
24}
25
26impl<N: ArraySize> Drop for CtrNonce128<N> {
27    fn drop(&mut self) {
28        #[cfg(feature = "zeroize")]
29        {
30            use cipher::zeroize::Zeroize;
31            self.ctr.zeroize();
32            self.nonce.zeroize();
33        }
34    }
35}
36
37#[cfg(feature = "zeroize")]
38impl<N: ArraySize> cipher::zeroize::ZeroizeOnDrop for CtrNonce128<N> {}
39
40/// 128-bit big endian counter flavor.
41#[derive(Clone, Copy, Debug)]
42pub enum Ctr128BE {}
43
44impl<B> CtrFlavor<B> for Ctr128BE
45where
46    B: ArraySize + PartialDiv<ChunkSize>,
47    Chunks<B>: ArraySize,
48{
49    type CtrNonce = CtrNonce128<Chunks<B>>;
50    type Backend = u128;
51    const NAME: &'static str = "128BE";
52
53    #[inline]
54    fn remaining(cn: &Self::CtrNonce) -> Option<usize> {
55        (u128::MAX - cn.ctr).try_into().ok()
56    }
57
58    #[inline(always)]
59    fn current_block(cn: &Self::CtrNonce) -> Array<u8, B> {
60        let mut block = Array::<u8, B>::default();
61        for i in 0..Chunks::<B>::USIZE {
62            let t = if i == Chunks::<B>::USIZE - 1 {
63                cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes()
64            } else {
65                cn.nonce[i].to_ne_bytes()
66            };
67            block[CS * i..][..CS].copy_from_slice(&t);
68        }
69        block
70    }
71
72    #[inline]
73    fn next_block(cn: &mut Self::CtrNonce) -> Array<u8, B> {
74        let block = Self::current_block(cn);
75        cn.ctr = cn.ctr.wrapping_add(1);
76        block
77    }
78
79    #[inline]
80    fn from_nonce(block: &Array<u8, B>) -> Self::CtrNonce {
81        let mut nonce = Array::<u128, Chunks<B>>::default();
82        for i in 0..Chunks::<B>::USIZE {
83            let chunk = block[CS * i..][..CS]
84                .try_into()
85                .expect("should be the correct size");
86            nonce[i] = if i == Chunks::<B>::USIZE - 1 {
87                u128::from_be_bytes(chunk)
88            } else {
89                u128::from_ne_bytes(chunk)
90            }
91        }
92        let ctr = 0;
93        Self::CtrNonce { ctr, nonce }
94    }
95
96    #[inline]
97    fn as_backend(cn: &Self::CtrNonce) -> Self::Backend {
98        cn.ctr
99    }
100
101    #[inline]
102    fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) {
103        cn.ctr = v;
104    }
105}
106
107/// 128-bit little endian counter flavor.
108#[derive(Clone, Copy, Debug)]
109pub enum Ctr128LE {}
110
111impl<B> CtrFlavor<B> for Ctr128LE
112where
113    B: ArraySize + PartialDiv<ChunkSize>,
114    Chunks<B>: ArraySize,
115{
116    type CtrNonce = CtrNonce128<Chunks<B>>;
117    type Backend = u128;
118    const NAME: &'static str = "128LE";
119
120    #[inline]
121    fn remaining(cn: &Self::CtrNonce) -> Option<usize> {
122        (u128::MAX - cn.ctr).try_into().ok()
123    }
124
125    #[inline(always)]
126    fn current_block(cn: &Self::CtrNonce) -> Array<u8, B> {
127        let mut block = Array::<u8, B>::default();
128        for i in 0..Chunks::<B>::USIZE {
129            let t = if i == 0 {
130                cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes()
131            } else {
132                cn.nonce[i].to_ne_bytes()
133            };
134            block[CS * i..][..CS].copy_from_slice(&t);
135        }
136        block
137    }
138
139    #[inline]
140    fn next_block(cn: &mut Self::CtrNonce) -> Array<u8, B> {
141        let block = Self::current_block(cn);
142        cn.ctr = cn.ctr.wrapping_add(1);
143        block
144    }
145
146    #[inline]
147    fn from_nonce(block: &Array<u8, B>) -> Self::CtrNonce {
148        let mut nonce = Array::<u128, Chunks<B>>::default();
149        for i in 0..Chunks::<B>::USIZE {
150            let chunk = block[CS * i..][..CS]
151                .try_into()
152                .expect("should be the correct size");
153            nonce[i] = if i == 0 {
154                u128::from_le_bytes(chunk)
155            } else {
156                u128::from_ne_bytes(chunk)
157            }
158        }
159        let ctr = 0;
160        Self::CtrNonce { ctr, nonce }
161    }
162
163    #[inline]
164    fn as_backend(cn: &Self::CtrNonce) -> Self::Backend {
165        cn.ctr
166    }
167
168    #[inline]
169    fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) {
170        cn.ctr = v;
171    }
172}