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