1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3use core::fmt;
4use core::ops::{Deref, DerefMut};
5
6use subtle::ConstantTimeEq;
7use zeroize::{Zeroize, ZeroizeOnDrop};
8
9use crate::rng::copy_randombytes;
10use crate::utils::zeroize_bytes;
11
12#[derive(Clone)]
15pub struct StackByteArray<const LENGTH: usize>([u8; LENGTH]);
16
17impl<const LENGTH: usize> Zeroize for StackByteArray<LENGTH> {
18 fn zeroize(&mut self) {
19 zeroize_bytes(&mut self.0);
20 }
21}
22
23impl<const LENGTH: usize> Drop for StackByteArray<LENGTH> {
24 fn drop(&mut self) {
25 self.zeroize();
26 }
27}
28
29impl<const LENGTH: usize> ZeroizeOnDrop for StackByteArray<LENGTH> {}
30
31impl<const LENGTH: usize> fmt::Debug for StackByteArray<LENGTH> {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("StackByteArray")
34 .field("len", &LENGTH)
35 .field("contents", &"[REDACTED]")
36 .finish()
37 }
38}
39
40impl<const LENGTH: usize> PartialEq for StackByteArray<LENGTH> {
41 fn eq(&self, other: &Self) -> bool {
42 self.0.ct_eq(&other.0).into()
43 }
44}
45
46impl<const LENGTH: usize> Eq for StackByteArray<LENGTH> {}
47
48#[cfg_attr(feature = "alloc", doc = "```compile_fail,E0277")]
58#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
59#[cfg_attr(feature = "alloc", doc = "```compile_fail,E0277")]
68#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
69pub trait ByteArray<const LENGTH: usize>: Bytes {
77 fn as_array(&self) -> &[u8; LENGTH];
79}
80
81pub trait Bytes {
83 fn as_slice(&self) -> &[u8];
85 fn len(&self) -> usize;
87 fn is_empty(&self) -> bool;
89}
90
91pub trait MutByteArray<const LENGTH: usize>: ByteArray<LENGTH> + MutBytes {
93 fn as_mut_array(&mut self) -> &mut [u8; LENGTH];
95}
96
97pub trait NewByteArray<const LENGTH: usize>: MutByteArray<LENGTH> + NewBytes {
99 #[must_use]
101 fn new_byte_array() -> Self;
102 #[must_use]
104 fn generate() -> Self;
105}
106
107pub trait MutBytes: Bytes {
109 fn as_mut_slice(&mut self) -> &mut [u8];
111 fn copy_from_slice(&mut self, other: &[u8]);
114}
115
116pub trait NewBytes: MutBytes {
118 #[must_use]
123 fn new_bytes() -> Self;
124}
125
126pub trait ResizableBytes {
128 fn resize(&mut self, new_len: usize, value: u8);
131}
132
133pub(crate) fn gen_bytes<B: NewBytes + MutBytes>() -> B {
135 let mut res = B::new_bytes();
136 copy_randombytes(res.as_mut_slice());
137 res
138}
139
140pub(crate) fn concat_bytes<Output: NewBytes + ResizableBytes>(
142 prefix: &[u8],
143 data: &[u8],
144) -> Output {
145 let mut out = Output::new_bytes();
146 out.resize(prefix.len() + data.len(), 0);
147 let s = out.as_mut_slice();
148 s[..prefix.len()].copy_from_slice(prefix);
149 s[prefix.len()..].copy_from_slice(data);
150 out
151}
152
153impl<const LENGTH: usize> ByteArray<LENGTH> for StackByteArray<LENGTH> {
154 #[inline]
155 fn as_array(&self) -> &[u8; LENGTH] {
156 &self.0
157 }
158}
159
160impl<const LENGTH: usize> Bytes for StackByteArray<LENGTH> {
161 #[inline]
162 fn as_slice(&self) -> &[u8] {
163 &self.0
164 }
165
166 #[inline]
167 fn len(&self) -> usize {
168 self.0.len()
169 }
170
171 #[inline]
172 fn is_empty(&self) -> bool {
173 self.0.is_empty()
174 }
175}
176
177impl<const LENGTH: usize> NewBytes for StackByteArray<LENGTH> {
178 fn new_bytes() -> Self {
179 Self::default()
180 }
181}
182
183impl<const LENGTH: usize> NewByteArray<LENGTH> for StackByteArray<LENGTH> {
184 fn new_byte_array() -> Self {
185 Self::default()
186 }
187
188 fn generate() -> Self {
190 gen_bytes()
191 }
192}
193
194impl<const LENGTH: usize> MutByteArray<LENGTH> for StackByteArray<LENGTH> {
195 #[inline]
196 fn as_mut_array(&mut self) -> &mut [u8; LENGTH] {
197 &mut self.0
198 }
199}
200
201impl<const LENGTH: usize> MutBytes for StackByteArray<LENGTH> {
202 #[inline]
203 fn as_mut_slice(&mut self) -> &mut [u8] {
204 &mut self.0
205 }
206
207 fn copy_from_slice(&mut self, other: &[u8]) {
208 self.0.copy_from_slice(other)
209 }
210}
211
212impl<const LENGTH: usize> NewBytes for [u8; LENGTH] {
213 fn new_bytes() -> Self {
214 [0u8; LENGTH]
215 }
216}
217
218impl<const LENGTH: usize> NewByteArray<LENGTH> for [u8; LENGTH] {
219 fn new_byte_array() -> Self {
220 [0u8; LENGTH]
221 }
222
223 fn generate() -> Self {
225 gen_bytes()
226 }
227}
228
229impl<const LENGTH: usize> MutByteArray<LENGTH> for [u8; LENGTH] {
230 #[inline]
231 fn as_mut_array(&mut self) -> &mut [u8; LENGTH] {
232 self
233 }
234}
235
236impl<const LENGTH: usize> MutBytes for [u8; LENGTH] {
237 #[inline]
238 fn as_mut_slice(&mut self) -> &mut [u8] {
239 self
240 }
241
242 fn copy_from_slice(&mut self, other: &[u8]) {
243 <[u8]>::copy_from_slice(self, other)
244 }
245}
246
247#[cfg(feature = "alloc")]
248impl Bytes for Vec<u8> {
249 #[inline]
250 fn as_slice(&self) -> &[u8] {
251 self.as_slice()
252 }
253
254 #[inline]
255 fn len(&self) -> usize {
256 <[u8]>::len(self)
257 }
258
259 #[inline]
260 fn is_empty(&self) -> bool {
261 <[u8]>::is_empty(self)
262 }
263}
264
265#[cfg(feature = "alloc")]
266impl NewBytes for Vec<u8> {
267 fn new_bytes() -> Self {
268 vec![]
269 }
270}
271
272#[cfg(feature = "alloc")]
273impl MutBytes for Vec<u8> {
274 #[inline]
275 fn as_mut_slice(&mut self) -> &mut [u8] {
276 self.as_mut_slice()
277 }
278
279 fn copy_from_slice(&mut self, other: &[u8]) {
280 <[u8]>::copy_from_slice(self, other)
281 }
282}
283
284#[cfg(feature = "alloc")]
285impl ResizableBytes for Vec<u8> {
286 fn resize(&mut self, new_len: usize, value: u8) {
287 self.resize(new_len, value);
288 }
289}
290
291macro_rules! impl_bytes_for_slice {
296 ($($t:ty),*) => {
297 $(
298 impl Bytes for $t {
299 #[inline]
300 fn as_slice(&self) -> &[u8] {
301 self
302 }
303
304 #[inline]
305 fn len(&self) -> usize {
306 <[u8]>::len(self)
307 }
308
309 #[inline]
310 fn is_empty(&self) -> bool {
311 <[u8]>::is_empty(self)
312 }
313 }
314 )*
315 };
316}
317
318impl_bytes_for_slice!([u8], &[u8], &mut [u8]);
319
320macro_rules! impl_bytes_for_array {
323 ($($(#[$meta:meta])* $t:ty, |$a:ident| $this:expr;)*) => {$(
324 $(#[$meta])*
325 impl<const LENGTH: usize> Bytes for $t {
326 #[inline]
327 fn as_slice(&self) -> &[u8] {
328 let $a = self;
329 $this
330 }
331
332 #[inline]
333 fn len(&self) -> usize {
334 let $a = self;
335 <[u8]>::len($this)
336 }
337
338 #[inline]
339 fn is_empty(&self) -> bool {
340 let $a = self;
341 <[u8]>::is_empty($this)
342 }
343 }
344 )*};
345}
346
347impl_bytes_for_array! {
348 [u8; LENGTH], |a| a;
349 #[allow(suspicious_double_ref_op)] &[u8; LENGTH], |a| a.deref();
350}
351
352impl<const LENGTH: usize> ByteArray<LENGTH> for [u8; LENGTH] {
353 #[inline]
354 fn as_array(&self) -> &[u8; LENGTH] {
355 self
356 }
357}
358
359impl MutBytes for [u8] {
360 #[inline]
361 fn as_mut_slice(&mut self) -> &mut [u8] {
362 self
363 }
364
365 fn copy_from_slice(&mut self, other: &[u8]) {
366 self.copy_from_slice(other)
367 }
368}
369
370impl<const LENGTH: usize> core::convert::AsRef<[u8; LENGTH]> for StackByteArray<LENGTH> {
371 fn as_ref(&self) -> &[u8; LENGTH] {
372 &self.0
373 }
374}
375
376impl<const LENGTH: usize> core::convert::AsMut<[u8; LENGTH]> for StackByteArray<LENGTH> {
377 fn as_mut(&mut self) -> &mut [u8; LENGTH] {
378 &mut self.0
379 }
380}
381
382impl<const LENGTH: usize> core::convert::AsRef<[u8]> for StackByteArray<LENGTH> {
383 fn as_ref(&self) -> &[u8] {
384 self.0.as_ref()
385 }
386}
387
388impl<const LENGTH: usize> core::convert::AsMut<[u8]> for StackByteArray<LENGTH> {
389 fn as_mut(&mut self) -> &mut [u8] {
390 self.0.as_mut()
391 }
392}
393
394impl<const LENGTH: usize> Deref for StackByteArray<LENGTH> {
395 type Target = [u8];
396
397 fn deref(&self) -> &Self::Target {
398 &self.0
399 }
400}
401
402impl<const LENGTH: usize> DerefMut for StackByteArray<LENGTH> {
403 fn deref_mut(&mut self) -> &mut Self::Target {
404 &mut self.0
405 }
406}
407
408macro_rules! impl_slice_index {
413 (impl[$($generics:tt)*] $ty:ty, |$s:ident| $get:expr, |$sm:ident| $get_mut:expr) => {
414 impl<$($generics)*> core::ops::Index<usize> for $ty {
415 type Output = u8;
416
417 #[inline]
418 fn index(&self, index: usize) -> &Self::Output {
419 let $s = self;
420 &$get[index]
421 }
422 }
423 impl<$($generics)*> core::ops::IndexMut<usize> for $ty {
424 #[inline]
425 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
426 let $sm = self;
427 &mut $get_mut[index]
428 }
429 }
430 impl_slice_index!(@ranges impl[$($generics)*] $ty, |$s| $get, |$sm| $get_mut);
431 };
432 (@ranges impl[$($generics:tt)*] $ty:ty, |$s:ident| $get:expr, |$sm:ident| $get_mut:expr) => {
433 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::Range<usize>, |$s| $get, |$sm| $get_mut);
434 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::RangeFull, |$s| $get, |$sm| $get_mut);
435 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::RangeFrom<usize>, |$s| $get, |$sm| $get_mut);
436 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::RangeInclusive<usize>, |$s| $get, |$sm| $get_mut);
437 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::RangeTo<usize>, |$s| $get, |$sm| $get_mut);
438 impl_slice_index!(@range impl[$($generics)*] $ty, core::ops::RangeToInclusive<usize>, |$s| $get, |$sm| $get_mut);
439 };
440 (@range impl[$($generics:tt)*] $ty:ty, $range:ty, |$s:ident| $get:expr, |$sm:ident| $get_mut:expr) => {
441 impl<$($generics)*> core::ops::Index<$range> for $ty {
442 type Output = [u8];
443
444 #[inline]
445 fn index(&self, index: $range) -> &Self::Output {
446 let $s = self;
447 &$get[index]
448 }
449 }
450 impl<$($generics)*> core::ops::IndexMut<$range> for $ty {
451 #[inline]
452 fn index_mut(&mut self, index: $range) -> &mut Self::Output {
453 let $sm = self;
454 &mut $get_mut[index]
455 }
456 }
457 };
458}
459
460#[cfg(any(
463 all(feature = "protected", any(unix, windows)),
464 all(doc, not(doctest), feature = "std")
465))]
466pub(crate) use impl_slice_index;
467
468impl_slice_index!(impl[const LENGTH: usize] StackByteArray<LENGTH>, |s| s.0, |s| s.0);
469
470impl<const LENGTH: usize> Default for StackByteArray<LENGTH> {
471 fn default() -> Self {
472 Self([0u8; LENGTH])
473 }
474}
475
476impl<const LENGTH: usize> From<&[u8; LENGTH]> for StackByteArray<LENGTH> {
477 fn from(src: &[u8; LENGTH]) -> Self {
478 let mut arr = Self::default();
479 arr.0.copy_from_slice(src);
480 arr
481 }
482}
483
484impl<const LENGTH: usize> From<[u8; LENGTH]> for StackByteArray<LENGTH> {
485 fn from(src: [u8; LENGTH]) -> Self {
486 Self::from(&src)
487 }
488}
489
490impl<const LENGTH: usize> TryFrom<&[u8]> for StackByteArray<LENGTH> {
491 type Error = crate::error::Error;
492
493 fn try_from(src: &[u8]) -> Result<Self, Self::Error> {
494 validate_length!(exact LENGTH, src.len(), crate::ErrorContext::Slice);
495 let mut arr = Self::default();
496 arr.0.copy_from_slice(src);
497 Ok(arr)
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::*;
504 use crate::utils::test_util::assert_exact_slice_length_error;
505
506 const SRC: [u8; 6] = [10, 20, 30, 40, 50, 60];
507
508 #[test]
509 #[cfg(feature = "alloc")]
510 fn bytes_views_agree_with_the_source_for_every_container() {
511 fn check<B: Bytes + ?Sized>(bytes: &B, expected: &[u8]) {
512 assert_eq!(bytes.as_slice(), expected);
513 assert_eq!(bytes.len(), expected.len());
514 assert_eq!(bytes.is_empty(), expected.is_empty());
515 }
516
517 check(&SRC[..], &SRC);
518 check(&&SRC[..], &SRC);
519 let mut copy = SRC;
520 check(&&mut copy[..], &SRC);
521 check(&SRC.to_vec(), &SRC);
522 check(&SRC, &SRC);
523 check(&&SRC, &SRC);
524 check(&StackByteArray::from(SRC), &SRC);
525
526 check(&[][..], &[]);
527 check(&Vec::<u8>::new(), &[]);
528 check(&[0u8; 0], &[]);
529 check(&StackByteArray::<0>::default(), &[]);
530 }
531
532 #[test]
533 #[cfg(feature = "alloc")]
534 fn mut_bytes_copy_from_slice_and_mutation_reach_the_source() {
535 fn check<B: MutBytes + ?Sized>(bytes: &mut B) {
536 bytes.copy_from_slice(&SRC);
537 assert_eq!(bytes.as_slice(), &SRC);
538 bytes.as_mut_slice()[2] ^= 0xff;
539 assert_eq!(bytes.as_slice()[2], SRC[2] ^ 0xff);
540 assert_eq!(&bytes.as_slice()[3..], &SRC[3..]);
541 }
542
543 let mut vec = vec![0u8; 6];
544 check(&mut vec);
545 assert_eq!(vec[2], SRC[2] ^ 0xff);
546
547 let mut array = [0u8; 6];
548 check(&mut array);
549 assert_eq!(array[2], SRC[2] ^ 0xff);
550
551 let mut slice_backing = [0u8; 6];
552 check(&mut slice_backing[..]);
553 assert_eq!(slice_backing[2], SRC[2] ^ 0xff);
554
555 let mut stack = StackByteArray::<6>::default();
556 check(&mut stack);
557 assert_eq!(stack[2], SRC[2] ^ 0xff);
558 }
559
560 #[test]
561 #[cfg(feature = "alloc")]
562 fn new_bytes_and_new_byte_array_start_zeroed() {
563 assert!(<Vec<u8> as NewBytes>::new_bytes().is_empty());
564 assert_eq!(<[u8; 4] as NewBytes>::new_bytes(), [0; 4]);
565 assert_eq!(<[u8; 4] as NewByteArray<4>>::new_byte_array(), [0; 4]);
566 assert_eq!(
567 <StackByteArray<4> as NewBytes>::new_bytes().as_slice(),
568 &[0; 4]
569 );
570 assert_eq!(
571 <StackByteArray<4> as NewByteArray<4>>::new_byte_array().as_slice(),
572 &[0; 4]
573 );
574 }
575
576 #[test]
577 #[cfg(feature = "alloc")]
578 fn generate_fills_the_whole_fixed_length_array() {
579 let array = <[u8; 32] as NewByteArray<32>>::generate();
580 assert_ne!(array, [0; 32]);
581
582 let stack = <StackByteArray<32> as NewByteArray<32>>::generate();
583 assert_ne!(stack, StackByteArray::<32>::default());
584 assert_ne!(stack.as_slice(), array.as_slice());
585 }
586
587 #[test]
588 #[cfg(feature = "alloc")]
589 fn resizable_vec_concat_preserves_prefix_then_data() {
590 let out: Vec<u8> = concat_bytes(b"ab", b"cde");
591 assert_eq!(out, b"abcde");
592
593 let out: Vec<u8> = concat_bytes(b"", b"xyz");
594 assert_eq!(out, b"xyz");
595
596 let out: Vec<u8> = concat_bytes(b"xyz", b"");
597 assert_eq!(out, b"xyz");
598
599 let mut vec = vec![1u8, 2, 3];
600 ResizableBytes::resize(&mut vec, 5, 9);
601 assert_eq!(vec, [1, 2, 3, 9, 9]);
602 ResizableBytes::resize(&mut vec, 1, 0);
603 assert_eq!(vec, [1]);
604 }
605
606 #[test]
607 fn stack_byte_array_try_from_requires_exact_length() {
608 let ok = StackByteArray::<3>::try_from(&SRC[..3]).expect("exact length");
609 assert_eq!(ok.as_slice(), &SRC[..3]);
610
611 assert_exact_slice_length_error(StackByteArray::<3>::try_from(&SRC[..2]), 2, 3);
612 assert_exact_slice_length_error(StackByteArray::<3>::try_from(&SRC[..4]), 4, 3);
613 assert_exact_slice_length_error(StackByteArray::<3>::try_from(&[][..]), 0, 3);
614 assert_exact_slice_length_error(StackByteArray::<0>::try_from(&SRC[..1]), 1, 0);
615 }
616
617 #[test]
618 fn stack_byte_array_conversions_and_views() {
619 let from_owned = StackByteArray::from(SRC);
620 let from_ref = StackByteArray::from(&SRC);
621 assert_eq!(from_owned, from_ref);
622 assert_eq!(AsRef::<[u8; 6]>::as_ref(&from_owned), &SRC);
623 assert_eq!(AsRef::<[u8]>::as_ref(&from_owned), &SRC);
624 assert_eq!(&*from_owned, &SRC);
625 assert_eq!(from_owned[1], SRC[1]);
626 assert_eq!(&from_owned[1..3], &SRC[1..3]);
627 assert_eq!(&from_owned[..], &SRC);
628 assert_eq!(&from_owned[4..], &SRC[4..]);
629
630 let mut mutated = from_owned.clone();
631 AsMut::<[u8; 6]>::as_mut(&mut mutated)[0] = 1;
632 AsMut::<[u8]>::as_mut(&mut mutated)[1] = 2;
633 mutated[2] = 3;
634 mutated[3..5].copy_from_slice(&[4, 5]);
635 (*mutated)[5] = 6;
636 assert_eq!(mutated.as_slice(), &[1, 2, 3, 4, 5, 6]);
637 assert_ne!(mutated, from_owned);
638 assert_eq!(from_owned.as_slice(), &SRC);
639 }
640
641 #[test]
642 fn stack_byte_array_equality_is_by_value() {
643 let a = StackByteArray::from([1u8, 2, 3, 4]);
644 let mut b = StackByteArray::from([1u8, 2, 3, 4]);
645 assert_eq!(a, b);
646 b[3] = 5;
647 assert_ne!(a, b);
648 assert_ne!(StackByteArray::<4>::default(), a);
649 assert_eq!(
650 StackByteArray::<0>::default(),
651 StackByteArray::<0>::default()
652 );
653 }
654
655 #[test]
656 fn stack_byte_array_zeroize_clears_contents() {
657 let mut bytes = StackByteArray::from([0xabu8; 8]);
658 bytes.zeroize();
659 assert_eq!(bytes.as_slice(), &[0; 8]);
660 }
661
662 #[test]
663 fn stack_byte_array_debug_redacts_contents() {
664 let bytes = StackByteArray::from([0xabu8; 4]);
665 let debug = format!("{bytes:?}");
666
667 assert!(debug.contains("[REDACTED]"));
668 assert!(!debug.contains("171"));
669 }
670}