1use constant_time_eq::constant_time_eq;
2
3#[derive(Clone)]
7#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
8pub struct Bytes<const N: usize> {
9 bytes: [u8; N],
10 length: u16,
11}
12
13impl<const N: usize> Bytes<N> {
14 #[inline]
15 pub(crate) fn new() -> Bytes<N> {
16 assert!(N <= u16::MAX as usize);
17 return Bytes {
18 bytes: [0u8; N],
19 length: 0,
20 };
21 }
22
23 #[inline]
24 pub fn len(&self) -> usize {
25 return self.length as usize;
26 }
27
28 #[inline]
29 pub(crate) fn with_length(length: usize) -> Bytes<N> {
30 assert!(N <= u16::MAX as usize && length <= u16::MAX as usize);
31 assert!(length <= N, "length exceeds capacity");
32 return Bytes {
33 bytes: [0u8; N],
34 length: length as u16,
35 };
36 }
37
38 pub(crate) fn push(&mut self, byte: u8) {
39 assert!(self.length as usize + 1 <= N);
40 self.bytes[self.length as usize] = byte;
41 self.length += 1;
42 }
43
44 pub(crate) fn append(&mut self, data: &[u8]) {
45 assert!(self.length as usize + data.len() <= N);
46 self.bytes[self.length as usize..data.len() + self.length as usize].copy_from_slice(data);
47 self.length += data.len() as u16;
48 }
49}
50
51impl<const N: usize> PartialEq for Bytes<N> {
52 #[inline]
53 fn eq(&self, other: &Self) -> bool {
54 constant_time_eq(self.as_ref(), other.as_ref())
55 }
56}
57
58impl<const N: usize> Eq for Bytes<N> {}
59
60impl<const N: usize> AsRef<[u8]> for Bytes<N> {
61 #[inline]
62 fn as_ref(&self) -> &[u8] {
63 &self.bytes[..self.length as usize]
64 }
65}
66
67impl<const N: usize> AsMut<[u8]> for Bytes<N> {
68 #[inline]
69 fn as_mut(&mut self) -> &mut [u8] {
70 &mut self.bytes[..self.length as usize]
71 }
72}
73
74#[derive(Clone)]
78#[repr(transparent)]
79#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
80pub struct Hash(pub(crate) Bytes<64>);
81
82#[derive(Clone)]
86#[repr(transparent)]
87#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
88pub struct Tag(pub(crate) Bytes<32>);
89
90macro_rules! impl_bytes {
92 ($name:ident($inner:ty)) => {
93 impl $name {
94 #[inline]
95 pub fn len(&self) -> usize {
96 self.0.len()
97 }
98 }
99
100 impl AsRef<[u8]> for $name {
101 #[inline]
102 fn as_ref(&self) -> &[u8] {
103 self.0.as_ref()
104 }
105 }
106
107 impl AsMut<[u8]> for $name {
108 #[inline]
109 fn as_mut(&mut self) -> &mut [u8] {
110 self.0.as_mut()
111 }
112 }
113
114 impl PartialEq for $name {
115 #[inline]
116 fn eq(&self, other: &Self) -> bool {
117 self.0 == other.0
118 }
119 }
120
121 impl Eq for $name {}
122 };
123}
124
125impl_bytes!(Tag(Bytes<32>));
126impl_bytes!(Hash(Bytes<64>));