1use std::rc::Rc;
2
3use bc_rand::fill_random_data;
4use dcbor::prelude::*;
5
6use crate::{Error, Result, tags};
7
8#[derive(Clone, Eq, PartialEq)]
76pub struct Nonce([u8; Self::NONCE_SIZE]);
77
78impl Nonce {
79 pub const NONCE_SIZE: usize = 12;
80
81 pub fn new() -> Self {
83 let mut data = [0u8; Self::NONCE_SIZE];
84 fill_random_data(&mut data);
85 Self(data)
86 }
87
88 pub const fn from_data(data: [u8; Self::NONCE_SIZE]) -> Self { Self(data) }
90
91 pub fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self> {
93 let data = data.as_ref();
94 if data.len() != Self::NONCE_SIZE {
95 return Err(Error::invalid_size(
96 "nonce",
97 Self::NONCE_SIZE,
98 data.len(),
99 ));
100 }
101 let mut arr = [0u8; Self::NONCE_SIZE];
102 arr.copy_from_slice(data);
103 Ok(Self::from_data(arr))
104 }
105
106 pub fn data(&self) -> &[u8; Self::NONCE_SIZE] { self.into() }
108
109 pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
111
112 pub fn from_hex(hex: impl AsRef<str>) -> Self {
117 Self::from_data_ref(hex::decode(hex.as_ref()).unwrap()).unwrap()
118 }
119
120 pub fn hex(&self) -> String { hex::encode(self.data()) }
122}
123
124impl AsRef<[u8]> for Nonce {
125 fn as_ref(&self) -> &[u8] { &self.0 }
126}
127
128impl Default for Nonce {
130 fn default() -> Self { Self::new() }
131}
132
133impl From<Rc<Nonce>> for Nonce {
135 fn from(value: Rc<Nonce>) -> Self { value.as_ref().clone() }
136}
137
138impl<'a> From<&'a Nonce> for &'a [u8; Nonce::NONCE_SIZE] {
140 fn from(value: &'a Nonce) -> Self { &value.0 }
141}
142
143impl AsRef<Nonce> for Nonce {
145 fn as_ref(&self) -> &Self { self }
146}
147
148impl CBORTagged for Nonce {
150 fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_NONCE]) }
151}
152
153impl From<Nonce> for CBOR {
155 fn from(value: Nonce) -> Self { value.tagged_cbor() }
156}
157
158impl CBORTaggedEncodable for Nonce {
160 fn untagged_cbor(&self) -> CBOR { CBOR::to_byte_string(self.data()) }
161}
162
163impl TryFrom<CBOR> for Nonce {
165 type Error = dcbor::Error;
166
167 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
168 Self::from_tagged_cbor(cbor)
169 }
170}
171
172impl CBORTaggedDecodable for Nonce {
174 fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
175 let data = CBOR::try_into_byte_string(untagged_cbor)?;
176 Ok(Self::from_data_ref(data)?)
177 }
178}
179
180impl std::fmt::Debug for Nonce {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "Nonce({})", self.hex())
184 }
185}
186
187impl From<&Nonce> for Nonce {
189 fn from(nonce: &Nonce) -> Self { nonce.clone() }
190}
191
192impl From<Nonce> for Vec<u8> {
194 fn from(nonce: Nonce) -> Self { nonce.0.to_vec() }
195}
196
197impl From<&Nonce> for Vec<u8> {
199 fn from(nonce: &Nonce) -> Self { nonce.0.to_vec() }
200}
201
202#[cfg(test)]
203mod test {
204 use dcbor::prelude::*;
205
206 use super::Nonce;
207
208 #[test]
209 fn test_nonce_raw() {
210 let nonce_raw = [0u8; Nonce::NONCE_SIZE];
211 let nonce = Nonce::from_data(nonce_raw);
212 assert_eq!(nonce.data(), &nonce_raw);
213 }
214
215 #[test]
216 fn test_nonce_from_raw_data() {
217 let raw_data = vec![0u8; Nonce::NONCE_SIZE];
218 let nonce = Nonce::from_data_ref(&raw_data).unwrap();
219 assert_eq!(nonce.data(), &raw_data[..]);
220 }
221
222 #[test]
223 fn test_nonce_size() {
224 let raw_data = vec![0u8; Nonce::NONCE_SIZE + 1];
225 let nonce = Nonce::from_data_ref(raw_data);
226 assert!(nonce.is_err());
227 }
228
229 #[test]
230 fn test_nonce_new() {
231 let nonce1 = Nonce::new();
232 let nonce2 = Nonce::new();
233 assert_ne!(nonce1.data(), nonce2.data());
234 }
235
236 #[test]
237 fn test_nonce_hex_roundtrip() {
238 let nonce = Nonce::new();
239 let hex_string = nonce.hex();
240 let nonce_from_hex = Nonce::from_hex(hex_string);
241 assert_eq!(nonce, nonce_from_hex);
242 }
243
244 #[test]
245 fn test_nonce_cbor_roundtrip() {
246 let nonce = Nonce::new();
247 let cbor: CBOR = nonce.clone().into();
248 let decoded_nonce = Nonce::try_from(cbor).unwrap();
249 assert_eq!(nonce, decoded_nonce);
250 }
251}