Skip to main content

lib_unknown/types/
bytes.rs

1//! 定容字节容器:栈上(`StackBytes`)与堆上(`HeapBytes`,需 `alloc`)实现,`Drop` 与显式擦除均经易失写清零。
2//!
3//! 需要启用 `"types-bytes"` 特性。
4#![allow(unused_qualifications)]
5#![allow(clippy::similar_names)]
6#![allow(unused)]
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11use core::fmt;
12use core::hint::black_box;
13use core::sync::atomic::{Ordering, compiler_fence};
14
15/// 字节容器的错误类型。未来可能新增变体/字段,请勿依赖穷尽匹配。
16///
17/// # Feature Requirement
18///
19/// 需要启用 `"types-bytes"` 特性。
20///
21/// # Examples
22///
23/// ```rust
24/// use lib_unknown::types::bytes::{Bytes, StackBytes};
25///
26/// let mut b = StackBytes::<4>::new();
27/// let err = b.extend_from_slice(b"toolong").unwrap_err();
28/// assert!(matches!(err, lib_unknown::types::bytes::BytesError::CapacityExceeded { .. }));
29/// ```
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[non_exhaustive]
32pub enum BytesError {
33    /// 请求长度超出容器容量。
34    CapacityExceeded {
35        /// 请求的总长度(字节)。
36        requested: usize,
37        /// 容器支持的最大长度(字节)。
38        max: usize,
39    },
40}
41
42impl fmt::Display for BytesError {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            Self::CapacityExceeded { requested, max } => write!(
46                f,
47                "capacity exceeded: requested {requested} bytes, max supported {max} bytes"
48            ),
49        }
50    }
51}
52
53impl core::error::Error for BytesError {}
54
55/// 字节容器操作的统一返回类型。
56///
57/// # Feature Requirement
58///
59/// 需要启用 `"types-bytes"` 特性。
60///
61/// # Errors
62///
63/// - 当请求长度超出容器容量时返回 [`BytesError::CapacityExceeded`]。
64pub type BytesResult<T = ()> = Result<T, BytesError>;
65
66#[inline(always)]
67pub(crate) fn volatile_zero(buf: &mut [u8]) {
68    for byte in black_box(buf.iter_mut()) {
69        // SAFETY: `byte` 为 `buf` 的独占借用派生的有效可写引用,`write_volatile` 写入对齐的 `u8`。
70        unsafe {
71            let _: () = core::ptr::write_volatile(black_box(byte), 0);
72            black_box(());
73        }
74    }
75    compiler_fence(Ordering::SeqCst);
76}
77
78/// 定容字节容器的统一接口:写入、擦除与向更大容器搬运。
79///
80/// 所有实现([`StackBytes`] / `HeapBytes`)在 `Drop` 与显式擦除时经易失写清零。
81///
82/// # Feature Requirement
83///
84/// 需要启用 `"types-bytes"` 特性。
85///
86/// # Examples
87///
88/// ```rust
89/// use lib_unknown::types::bytes::{Bytes, StackBytes};
90///
91/// let mut b = StackBytes::<8>::new();
92/// b.extend_from_slice(b"hi").unwrap();
93/// assert_eq!(b.as_slice(), b"hi");
94/// b.wipe_data();
95/// assert!(b.is_empty());
96/// ```
97pub trait Bytes:
98    core::ops::Deref<Target = [u8]> + core::ops::DerefMut + AsRef<[u8]> + AsMut<[u8]> + Default + Sized
99{
100    /// 返回容器容量(字节),与已写入长度无关。
101    ///
102    /// # Feature Requirement
103    ///
104    /// 需要启用 `"types-bytes"` 特性。
105    fn capacity(&self) -> usize;
106    /// 返回已写入数据的长度(字节)。
107    ///
108    /// # Feature Requirement
109    ///
110    /// 需要启用 `"types-bytes"` 特性。
111    fn len(&self) -> usize;
112
113    /// 已写入数据是否为空。
114    ///
115    /// # Feature Requirement
116    ///
117    /// 需要启用 `"types-bytes"` 特性。
118    fn is_empty(&self) -> bool {
119        self.len() == 0
120    }
121
122    /// 追加 `other` 的全部字节。
123    ///
124    /// # Feature Requirement
125    ///
126    /// 需要启用 `"types-bytes"` 特性。
127    ///
128    /// # Examples
129    ///
130    /// ```rust
131    /// use lib_unknown::types::bytes::{Bytes, StackBytes};
132    ///
133    /// let mut b = StackBytes::<8>::new();
134    /// b.extend_from_slice(b"hi").unwrap();
135    /// assert_eq!(b.len(), 2);
136    /// ```
137    ///
138    /// # Errors
139    ///
140    /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`],容器内容不变。
141    fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult;
142
143    /// 清零全部底层存储并将长度置 0。
144    ///
145    /// # Feature Requirement
146    ///
147    /// 需要启用 `"types-bytes"` 特性。
148    fn wipe_data(&mut self);
149
150    /// 以不可变切片查看已写入数据。
151    ///
152    /// # Feature Requirement
153    ///
154    /// 需要启用 `"types-bytes"` 特性。
155    fn as_slice(&self) -> &[u8] {
156        self.as_ref()
157    }
158
159    /// 以可变切片访问已写入数据(不改变长度)。
160    ///
161    /// # Feature Requirement
162    ///
163    /// 需要启用 `"types-bytes"` 特性。
164    fn as_mut_slice(&mut self) -> &mut [u8] {
165        self.as_mut()
166    }
167
168    /// 将自身内容与 `other` 先后写入新容器,并擦除自身。
169    ///
170    /// # Feature Requirement
171    ///
172    /// 需要启用 `"types-bytes"` 特性。
173    ///
174    /// # Examples
175    ///
176    /// ```rust
177    /// use lib_unknown::types::bytes::{Bytes, StackBytes};
178    ///
179    /// let mut b = StackBytes::<8>::new();
180    /// b.extend_from_slice(b"hi").unwrap();
181    /// let c: StackBytes<8> = b.extend_into(b"!").unwrap();
182    /// assert_eq!(c.as_slice(), b"hi!");
183    /// ```
184    ///
185    /// # Errors
186    ///
187    /// - 当任一写入超出目标容器容量时返回 [`BytesError::CapacityExceeded`]。
188    fn extend_into<T>(mut self, other: &[u8]) -> BytesResult<T>
189    where
190        Self: Sized,
191        T: Bytes + Default,
192    {
193        let mut new_buf = T::default();
194        new_buf.extend_from_slice(self.as_slice())?;
195        new_buf.extend_from_slice(other)?;
196        self.wipe_data();
197
198        Ok(new_buf)
199    }
200
201    /// 将 `source` 内容追加到自身,成功后清零 `source`;失败时 `source` 保持不变。
202    ///
203    /// # Feature Requirement
204    ///
205    /// 需要启用 `"types-bytes"` 特性。
206    ///
207    /// # Examples
208    ///
209    /// ```rust
210    /// use lib_unknown::types::bytes::{Bytes, StackBytes};
211    ///
212    /// let mut b = StackBytes::<8>::new();
213    /// let mut secret = *b"hi";
214    /// b.extend_and_wipe(&mut secret).unwrap();
215    /// assert_eq!(secret, [0u8; 2]);
216    /// ```
217    ///
218    /// # Errors
219    ///
220    /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`]。
221    fn extend_and_wipe<T>(&mut self, mut source: T) -> BytesResult
222    where
223        Self: Sized,
224        T: AsRef<[u8]> + AsMut<[u8]>,
225    {
226        let res = self.extend_from_slice(source.as_ref());
227        if res.is_ok() {
228            volatile_zero(source.as_mut());
229        }
230        res
231    }
232}
233
234macro_rules! impl_secure_buffer {
235    ($name:ident) => {
236        impl<const N: usize> $name<N> {
237            /// 将内容搬运到容量为 `M` 的同类容器中。
238            ///
239            /// # Feature Requirement
240            ///
241            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
242            ///
243            /// # Examples
244            ///
245            /// ```rust
246            /// use lib_unknown::types::bytes::StackBytes;
247            ///
248            /// let mut b = StackBytes::<4>::new();
249            /// b.extend_from_slice(b"hi").unwrap();
250            /// let c = b.try_grow::<8>().unwrap();
251            /// assert_eq!(c.capacity(), 8);
252            /// ```
253            ///
254            /// # Errors
255            ///
256            /// - 当已有长度超出 `M` 时返回 [`BytesError::CapacityExceeded`]。
257            pub fn try_grow<const M: usize>(self) -> BytesResult<$name<M>> {
258                if self.len > M {
259                    return Err(BytesError::CapacityExceeded {
260                        requested: self.len,
261                        max: M,
262                    });
263                }
264                let mut out = $name::<M>::new();
265                out.data[..self.len].copy_from_slice(&self.data[..self.len]);
266                out.len = self.len;
267                Ok(out)
268            }
269
270            /// 返回容器容量(字节),恒为 `N`。
271            ///
272            /// # Feature Requirement
273            ///
274            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
275            #[inline(always)]
276            pub fn capacity(&self) -> usize {
277                N
278            }
279
280            /// 返回已写入数据的长度(字节)。
281            ///
282            /// # Feature Requirement
283            ///
284            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
285            #[inline(always)]
286            pub fn len(&self) -> usize {
287                self.len
288            }
289
290            /// 已写入数据是否为空。
291            ///
292            /// # Feature Requirement
293            ///
294            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
295            #[inline(always)]
296            pub fn is_empty(&self) -> bool {
297                self.len == 0
298            }
299
300            /// 以不可变切片查看已写入数据。
301            ///
302            /// # Feature Requirement
303            ///
304            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
305            #[inline(always)]
306            pub fn as_slice(&self) -> &[u8] {
307                self.as_ref()
308            }
309
310            /// 以可变切片访问已写入数据(不改变长度)。
311            ///
312            /// # Feature Requirement
313            ///
314            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
315            #[inline(always)]
316            pub fn as_mut_slice(&mut self) -> &mut [u8] {
317                self.as_mut()
318            }
319
320            /// 追加 `other` 的全部字节。
321            ///
322            /// # Feature Requirement
323            ///
324            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
325            ///
326            /// # Examples
327            ///
328            /// ```rust
329            /// use lib_unknown::types::bytes::StackBytes;
330            ///
331            /// let mut b = StackBytes::<4>::new();
332            /// b.extend_from_slice(b"hi").unwrap();
333            /// assert!(b.extend_from_slice(b"toolong").is_err());
334            /// ```
335            ///
336            /// # Errors
337            ///
338            /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`],容器内容不变。
339            pub fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult {
340                let new_len =
341                    self.len
342                        .checked_add(other.len())
343                        .ok_or(BytesError::CapacityExceeded {
344                            requested: usize::MAX,
345                            max: N,
346                        })?;
347                if new_len > N {
348                    return Err(BytesError::CapacityExceeded {
349                        requested: new_len,
350                        max: N,
351                    });
352                }
353                self.data[self.len..new_len].copy_from_slice(other);
354                self.len = new_len;
355                Ok(())
356            }
357
358            /// 清零全部底层存储并将长度置 0。
359            ///
360            /// # Feature Requirement
361            ///
362            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
363            pub fn wipe_data(&mut self) {
364                volatile_zero(&mut self.data[..]);
365                self.len = 0;
366            }
367
368            /// 将自身内容与 `other` 先后写入新容器,并擦除自身。
369            ///
370            /// # Feature Requirement
371            ///
372            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
373            ///
374            /// # Examples
375            ///
376            /// ```rust
377            /// use lib_unknown::types::bytes::StackBytes;
378            ///
379            /// let mut b = StackBytes::<8>::new();
380            /// b.extend_from_slice(b"hi").unwrap();
381            /// let c: StackBytes<8> = b.extend_into(b"!").unwrap();
382            /// assert_eq!(c.as_slice(), b"hi!");
383            /// ```
384            ///
385            /// # Errors
386            ///
387            /// - 当任一写入超出目标容器容量时返回 [`BytesError::CapacityExceeded`]。
388            pub fn extend_into<T>(mut self, other: &[u8]) -> BytesResult<T>
389            where
390                T: Bytes + Default,
391            {
392                let mut new_buf = T::default();
393                new_buf.extend_from_slice(self.as_slice())?;
394                new_buf.extend_from_slice(other)?;
395                self.wipe_data();
396                Ok(new_buf)
397            }
398
399            /// 将 `source` 内容追加到自身,成功后清零 `source`;失败时 `source` 保持不变。
400            ///
401            /// # Feature Requirement
402            ///
403            /// 需要启用 `"types-bytes"` 特性(`HeapBytes` 相关还需 `"alloc"` 特性)。
404            ///
405            /// # Examples
406            ///
407            /// ```rust
408            /// use lib_unknown::types::bytes::StackBytes;
409            ///
410            /// let mut b = StackBytes::<8>::new();
411            /// let mut src = *b"hi";
412            /// b.extend_and_wipe(&mut src).unwrap();
413            /// assert_eq!(src, [0u8; 2]);
414            /// ```
415            ///
416            /// # Errors
417            ///
418            /// - 当追加后总长度超出容量时返回 [`BytesError::CapacityExceeded`]。
419            pub fn extend_and_wipe<T>(&mut self, mut source: T) -> BytesResult
420            where
421                T: AsRef<[u8]> + AsMut<[u8]>,
422            {
423                let res = self.extend_from_slice(source.as_ref());
424                if res.is_ok() {
425                    volatile_zero(source.as_mut());
426                }
427                res
428            }
429        }
430
431        impl<const N: usize> Default for $name<N> {
432            fn default() -> Self {
433                Self::new()
434            }
435        }
436
437        impl<const N: usize> Drop for $name<N> {
438            fn drop(&mut self) {
439                volatile_zero(&mut self.data[..]);
440            }
441        }
442
443        impl<const N: usize> AsRef<[u8]> for $name<N> {
444            fn as_ref(&self) -> &[u8] {
445                &self.data[..self.len]
446            }
447        }
448
449        impl<const N: usize> AsMut<[u8]> for $name<N> {
450            fn as_mut(&mut self) -> &mut [u8] {
451                &mut self.data[..self.len]
452            }
453        }
454
455        impl<const N: usize> core::ops::Deref for $name<N> {
456            type Target = [u8];
457            fn deref(&self) -> &Self::Target {
458                &self.data[..self.len]
459            }
460        }
461
462        impl<const N: usize> core::ops::DerefMut for $name<N> {
463            fn deref_mut(&mut self) -> &mut Self::Target {
464                &mut self.data[..self.len]
465            }
466        }
467
468        impl<const N: usize> fmt::Debug for $name<N> {
469            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470                f.debug_struct(stringify!($name))
471                    .field("len", &self.len)
472                    .field("capacity", &N)
473                    .finish()
474            }
475        }
476
477        impl<const N: usize> Bytes for $name<N> {
478            #[inline(always)]
479            fn capacity(&self) -> usize {
480                self.capacity()
481            }
482            #[inline(always)]
483            fn len(&self) -> usize {
484                self.len()
485            }
486            #[inline(always)]
487            fn is_empty(&self) -> bool {
488                self.is_empty()
489            }
490            #[inline(always)]
491            fn as_slice(&self) -> &[u8] {
492                self.as_slice()
493            }
494            #[inline(always)]
495            fn as_mut_slice(&mut self) -> &mut [u8] {
496                self.as_mut_slice()
497            }
498            #[inline(always)]
499            fn extend_from_slice(&mut self, other: &[u8]) -> BytesResult {
500                self.extend_from_slice(other)
501            }
502            #[inline(always)]
503            fn wipe_data(&mut self) {
504                self.wipe_data()
505            }
506            #[inline(always)]
507            fn extend_into<T>(self, other: &[u8]) -> BytesResult<T>
508            where
509                Self: Sized,
510                T: Bytes + Default,
511            {
512                self.extend_into(other)
513            }
514            #[inline(always)]
515            fn extend_and_wipe<T>(&mut self, source: T) -> BytesResult
516            where
517                Self: Sized,
518                T: AsRef<[u8]> + AsMut<[u8]>,
519            {
520                self.extend_and_wipe(source)
521            }
522        }
523    };
524}
525
526/// 栈上定容字节容器,`Drop` 时自动清零,适用于短密钥、非对称 nonce 等小敏感数据。
527///
528/// # Feature Requirement
529///
530/// 需要启用 `"types-bytes"` 特性。
531///
532/// # Examples
533///
534/// ```rust
535/// use lib_unknown::types::bytes::{Bytes, StackBytes};
536///
537/// let mut b = StackBytes::<16>::new();
538/// b.extend_from_slice(b"secret").unwrap();
539/// assert_eq!(b.len(), 6);
540/// ```
541pub struct StackBytes<const N: usize> {
542    len: usize,
543    data: [u8; N],
544}
545impl<const N: usize> StackBytes<N> {
546    /// 创建长度为 0、内容全零的容器。
547    ///
548    /// # Feature Requirement
549    ///
550    /// 需要启用 `"types-bytes"` 特性。
551    pub const fn new() -> Self {
552        Self {
553            len: 0,
554            data: [0u8; N],
555        }
556    }
557}
558impl_secure_buffer!(StackBytes);
559
560/// 堆上定容字节容器,语义与 [`StackBytes`] 一致,适用于超过栈承载的较大敏感数据。
561///
562/// # Feature Requirement
563///
564/// 需要启用 `"types-bytes"` 与 `"alloc"` 特性。
565///
566/// # Examples
567///
568/// ```rust
569/// use lib_unknown::types::bytes::{Bytes, HeapBytes};
570///
571/// let mut b = HeapBytes::<64>::new();
572/// b.extend_from_slice(b"secret").unwrap();
573/// assert_eq!(b.len(), 6);
574/// ```
575#[cfg(feature = "alloc")]
576pub struct HeapBytes<const N: usize> {
577    len: usize,
578    data: alloc::boxed::Box<[u8; N]>,
579}
580
581#[cfg(feature = "alloc")]
582fn zeroed_box<const N: usize>() -> alloc::boxed::Box<[u8; N]> {
583    // SAFETY: `[u8; N]` 全零为合法值,`assume_init` 安全。
584    unsafe { alloc::boxed::Box::<[u8; N]>::new_zeroed().assume_init() }
585}
586
587#[cfg(feature = "alloc")]
588impl<const N: usize> HeapBytes<N> {
589    /// 创建长度为 0、内容全零的容器。
590    ///
591    /// # Feature Requirement
592    ///
593    /// 需要启用 `"types-bytes"` 与 `"alloc"` 特性。
594    pub fn new() -> Self {
595        Self {
596            len: 0,
597            data: zeroed_box::<N>(),
598        }
599    }
600}
601#[cfg(feature = "alloc")]
602impl_secure_buffer!(HeapBytes);
603
604#[cfg(test)]
605#[allow(clippy::unwrap_used, clippy::expect_used)]
606mod tests {
607    use super::*;
608
609    #[test]
610    fn test_stack_buffer() {
611        let mut d = StackBytes::<32>::new();
612
613        let mut secret_data = *b"super_secret_password";
614        d.extend_and_wipe(&mut secret_data).unwrap();
615
616        assert_eq!(&secret_data, &[0u8; 21]);
617        assert_eq!(d.as_slice(), b"super_secret_password");
618    }
619
620    #[cfg(feature = "alloc")]
621    #[test]
622    fn test_heap_buffer() {
623        let mut d = StackBytes::<32>::new();
624
625        let mut secret_data = *b"super_secret_password";
626        d.extend_and_wipe(&mut secret_data).unwrap();
627
628        let extra_data = b"_suffix";
629        let mut x = d.extend_into::<HeapBytes<512>>(extra_data).unwrap();
630
631        fn aaa(d: &impl Bytes) {
632            assert!(d.capacity() >= 512);
633        }
634        aaa(&x);
635
636        assert_eq!(x.as_slice(), b"super_secret_password_suffix");
637        assert!(x.starts_with(b"super_secret"));
638
639        x[0] = b'S';
640        assert_eq!(x.as_slice(), b"Super_secret_password_suffix");
641
642        fn requires_slice(s: &[u8]) {
643            assert_eq!(s.len(), 28);
644        }
645        requires_slice(&x);
646
647        fn bbb(d: impl Bytes) {
648            assert!(d.capacity() >= 512);
649        }
650        bbb(x);
651    }
652}