1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//! Key management for the `Poly1305` MAC.
//!
//! This defines the key structures, traits, and associated functionalities required
//! for securely managing and utilizing cryptographic keys.
//!
//! # Key Structures
//!
//! - `Key`: Represents a 32-byte secret key used for MAC computations.
//! - `KeyRef`: A reference to a `Key`, allowing for efficient key handling without ownership.
//!
//! # Traits
//!
//! - `GenericKey`: A sealed trait for generic key types, providing a method to access the key's
//!   byte pointer.

use core::array::TryFromSliceError;
use zeroize::Zeroize;
use crate::sealed::Sealed;

/// The size of the Poly1305 key in bytes.
pub const KEY_SIZE: usize = KEY_SIZE_U32 as usize;

/// The size of the Poly1305 key as a `u32`.
pub(crate) const KEY_SIZE_U32: u32 = 32;


/// A sealed trait for generic key types used in Poly1305.
///
/// This trait is sealed and cannot be implemented outside of this crate.
pub trait GenericKey : Sealed {
    #[doc(hidden)]
    fn ptr(&self) -> *const u8;
}

/// Represents a 32-byte secret key for `Poly1305` and `ChaCha20Poly1305`.
///
/// This struct ensures that the key material is securely managed and zeroed from memory when
/// dropped.
#[repr(transparent)]
#[derive(Clone)]
pub struct Key {
    inner: [u8; KEY_SIZE]
}

impl Key {
    /// Creates a new `Key` from a 32-byte array.
    ///
    /// # Arguments
    ///
    /// * `inner` - A 32-byte array containing the key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::Key;
    ///
    /// let key_bytes = [0u8; 32];
    /// let key = Key::new(key_bytes);
    /// # drop(key);
    /// ```
    pub const fn new(inner: [u8; KEY_SIZE]) -> Self {
        Self { inner }
    }

    /// Returns a reference to the key as a `KeyRef`.
    ///
    /// # Returns
    ///
    /// * `KeyRef` - A reference to the key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::{Key, KeyRef};
    ///
    /// let key_bytes = [0u8; 32];
    /// let key = Key::new(key_bytes);
    /// let key_ref: KeyRef = key.as_ref();
    /// # drop(key_ref); drop(key);
    /// ```
    pub const fn as_ref(&self) -> KeyRef {
        KeyRef::new(&self.inner)
    }
}

impl Zeroize for Key {
    /// Zeroes the key material in memory.
    ///
    /// This method securely erases the key from memory to prevent leakage.
    #[inline]
    fn zeroize(&mut self) {
        self.inner.zeroize()
    }
}

opaque_dbg! { Key }
impl Sealed for Key {}
impl GenericKey for Key {
    #[doc(hidden)]
    #[inline]
    fn ptr(&self) -> *const u8 {
        self.inner.as_ptr()
    }
}

impl From<[u8; KEY_SIZE]> for Key {
    /// Converts a 32-byte array into a `Key`.
    ///
    /// # Arguments
    ///
    /// * `value` - A 32-byte array containing the key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::Key;
    ///
    /// let key_bytes = [1u8; 32];
    /// let key: Key = key_bytes.into();
    /// # drop(key);
    /// ```
    #[inline]
    fn from(value: [u8; KEY_SIZE]) -> Self {
        Self::new(value)
    }
}

impl Drop for Key {
    /// Drops the `Key`, ensuring that the key material is zeroed from memory.
    #[inline]
    fn drop(&mut self) {
        self.zeroize()
    }
}

/// A reference to a [`Key`], allowing for efficient key handling without ownership.
#[repr(transparent)]
pub struct KeyRef<'r> {
    inner: &'r [u8; KEY_SIZE]
}

impl<'r> KeyRef<'r> {
    /// Creates a new `KeyRef` from a reference to a 32-byte array.
    ///
    /// # Arguments
    ///
    /// * `inner` - A reference to a 32-byte array containing the key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::{Key, KeyRef};
    ///
    /// let key_bytes = [2u8; 32];
    /// let key = Key::new(key_bytes);
    /// let key_ref: KeyRef = key.as_ref();
    /// # drop(key_ref); drop(key);
    /// ```
    pub const fn new(inner: &'r [u8; KEY_SIZE]) -> Self {
        Self { inner }
    }

    /// Creates a copy of the key as a [`Key`].
    ///
    /// # Returns
    ///
    /// A new [`Key`] instance containing the same key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::{Key, KeyRef};
    ///
    /// let key_ref: KeyRef = (&[7u8; 32]).into();
    /// let owned_key = key_ref.copy();
    /// # drop(key_ref); drop(owned_key);
    /// ```
    pub const fn copy(&self) -> Key {
        Key::new(*self.inner)
    }
}

opaque_dbg! { KeyRef<'r> }

impl<'r> Sealed for KeyRef<'r> {}
impl<'r> GenericKey for KeyRef<'r> {
    #[doc(hidden)]
    #[inline]
    fn ptr(&self) -> *const u8 {
        self.inner.as_ptr()
    }
}

impl<'r> From<&'r [u8; KEY_SIZE]> for KeyRef<'r> {
    /// Converts a reference to a 32-byte array into a `KeyRef`.
    ///
    /// # Arguments
    ///
    /// * `value` - A reference to a 32-byte array containing the key material.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::{Key, KeyRef};
    ///
    /// let key_ref = KeyRef::from(&[2u8; 32]);
    /// # drop(key_ref);
    /// ```
    #[inline]
    fn from(value: &'r [u8; KEY_SIZE]) -> Self {
        Self::new(value)
    }
}

impl<'r> TryFrom<&'r [u8]> for KeyRef<'r> {
    type Error = TryFromSliceError;

    /// Attempts to convert a slice of bytes into a `KeyRef`.
    ///
    /// # Arguments
    ///
    /// * `value` - A slice of bytes to convert.
    ///
    /// # Errors
    ///
    /// Returns `TryFromSliceError` if the slice length is not exactly 32 bytes.
    ///
    /// # Example
    ///
    /// ```rust
    /// use wolf_crypto::mac::poly1305::KeyRef;
    ///
    /// let key_slice = &[5u8; 32];
    /// let key_ref = KeyRef::try_from(key_slice).unwrap();
    /// ```
    #[inline]
    fn try_from(value: &'r [u8]) -> Result<Self, Self::Error> {
        value.try_into().map(Self::new)
    }
}