chksum_hash_sha2_512/
digest.rs

1//! Module contains items related to the [`Digest`] structure.
2//!
3//! # Example
4//!
5//! ```rust
6//! use chksum_hash_sha2_512 as sha2_512;
7//!
8//! // Digest bytes
9//! #[rustfmt::skip]
10//! let digest = [
11//!     0xCF, 0x83, 0xE1, 0x35,
12//!     0x7E, 0xEF, 0xB8, 0xBD,
13//!     0xF1, 0x54, 0x28, 0x50,
14//!     0xD6, 0x6D, 0x80, 0x07,
15//!     0xD6, 0x20, 0xE4, 0x05,
16//!     0x0B, 0x57, 0x15, 0xDC,
17//!     0x83, 0xF4, 0xA9, 0x21,
18//!     0xD3, 0x6C, 0xE9, 0xCE,
19//!     0x47, 0xD0, 0xD1, 0x3C,
20//!     0x5D, 0x85, 0xF2, 0xB0,
21//!     0xFF, 0x83, 0x18, 0xD2,
22//!     0x87, 0x7E, 0xEC, 0x2F,
23//!     0x63, 0xB9, 0x31, 0xBD,
24//!     0x47, 0x41, 0x7A, 0x81,
25//!     0xA5, 0x38, 0x32, 0x7A,
26//!     0xF9, 0x27, 0xDA, 0x3E,
27//! ];
28//!
29//! // Create new digest
30//! let digest = sha2_512::digest::new(digest);
31//!
32//! // Print digest (by default it uses hex lowercase format)
33//! println!("digest {}", digest);
34//!
35//! // You can also specify which format you prefer
36//! println!("digest {:x}", digest);
37//! println!("digest {:X}", digest);
38//!
39//! // Turn into byte slice
40//! let bytes = digest.as_bytes();
41//!
42//! // Get inner bytes
43//! let digest = digest.into_inner();
44//!
45//! // Should be same
46//! assert_eq!(bytes, &digest[..]);
47//! ```
48
49use std::fmt::{self, Display, Formatter, LowerHex, UpperHex};
50use std::num::ParseIntError;
51
52use chksum_hash_core as core;
53
54/// Digest length in bits.
55pub const LENGTH_BITS: usize = 512;
56/// Digest length in bytes.
57pub const LENGTH_BYTES: usize = LENGTH_BITS / 8;
58/// Digest length in words (double bytes).
59pub const LENGTH_WORDS: usize = LENGTH_BYTES / 2;
60/// Digest length in double words (quadruple bytes).
61pub const LENGTH_DWORDS: usize = LENGTH_WORDS / 2;
62/// Digest length in quadruple words (octuple bytes).
63pub const LENGTH_QWORDS: usize = LENGTH_DWORDS / 2;
64/// Digest length in hexadecimal format.
65pub const LENGTH_HEX: usize = LENGTH_BYTES * 2;
66
67/// Creates a new [`Digest`].
68#[must_use]
69pub fn new(digest: [u8; LENGTH_BYTES]) -> Digest {
70    Digest::new(digest)
71}
72
73/// A hash digest.
74///
75/// Check [`digest`](self) module for usage examples.
76#[derive(Clone, Copy, Debug, Eq, PartialEq)]
77pub struct Digest([u8; LENGTH_BYTES]);
78
79impl Digest {
80    /// Creates a new digest.
81    #[must_use]
82    pub const fn new(digest: [u8; LENGTH_BYTES]) -> Self {
83        Self(digest)
84    }
85
86    /// Returns a byte slice of the digest's contents.
87    #[must_use]
88    pub const fn as_bytes(&self) -> &[u8] {
89        &self.0
90    }
91
92    /// Consumes the digest, returning the digest bytes.
93    #[must_use]
94    pub fn into_inner(self) -> [u8; LENGTH_BYTES] {
95        let Self(inner) = self;
96        inner
97    }
98
99    /// Returns a string in the lowercase hexadecimal representation.
100    ///
101    /// # Example
102    ///
103    /// ```rust
104    /// use chksum_hash_sha2_512 as sha2_512;
105    ///
106    /// #[rustfmt::skip]
107    /// let digest = [
108    ///     0xCF, 0x83, 0xE1, 0x35,
109    ///     0x7E, 0xEF, 0xB8, 0xBD,
110    ///     0xF1, 0x54, 0x28, 0x50,
111    ///     0xD6, 0x6D, 0x80, 0x07,
112    ///     0xD6, 0x20, 0xE4, 0x05,
113    ///     0x0B, 0x57, 0x15, 0xDC,
114    ///     0x83, 0xF4, 0xA9, 0x21,
115    ///     0xD3, 0x6C, 0xE9, 0xCE,
116    ///     0x47, 0xD0, 0xD1, 0x3C,
117    ///     0x5D, 0x85, 0xF2, 0xB0,
118    ///     0xFF, 0x83, 0x18, 0xD2,
119    ///     0x87, 0x7E, 0xEC, 0x2F,
120    ///     0x63, 0xB9, 0x31, 0xBD,
121    ///     0x47, 0x41, 0x7A, 0x81,
122    ///     0xA5, 0x38, 0x32, 0x7A,
123    ///     0xF9, 0x27, 0xDA, 0x3E,
124    /// ];
125    /// let digest = sha2_512::Digest::new(digest);
126    /// assert_eq!(
127    ///     digest.to_hex_lowercase(),
128    ///     "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
129    /// );
130    /// ```
131    #[must_use]
132    pub fn to_hex_lowercase(&self) -> String {
133        format!("{self:x}")
134    }
135
136    /// Returns a string in the uppercase hexadecimal representation.
137    ///
138    /// # Example
139    ///
140    /// ```rust
141    /// use chksum_hash_sha2_512 as sha2_512;
142    ///
143    /// #[rustfmt::skip]
144    /// let digest = [
145    ///     0xCF, 0x83, 0xE1, 0x35,
146    ///     0x7E, 0xEF, 0xB8, 0xBD,
147    ///     0xF1, 0x54, 0x28, 0x50,
148    ///     0xD6, 0x6D, 0x80, 0x07,
149    ///     0xD6, 0x20, 0xE4, 0x05,
150    ///     0x0B, 0x57, 0x15, 0xDC,
151    ///     0x83, 0xF4, 0xA9, 0x21,
152    ///     0xD3, 0x6C, 0xE9, 0xCE,
153    ///     0x47, 0xD0, 0xD1, 0x3C,
154    ///     0x5D, 0x85, 0xF2, 0xB0,
155    ///     0xFF, 0x83, 0x18, 0xD2,
156    ///     0x87, 0x7E, 0xEC, 0x2F,
157    ///     0x63, 0xB9, 0x31, 0xBD,
158    ///     0x47, 0x41, 0x7A, 0x81,
159    ///     0xA5, 0x38, 0x32, 0x7A,
160    ///     0xF9, 0x27, 0xDA, 0x3E,
161    /// ];
162    /// let digest = sha2_512::Digest::new(digest);
163    /// assert_eq!(
164    ///     digest.to_hex_uppercase(),
165    ///     "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"
166    /// );
167    /// ```
168    #[must_use]
169    pub fn to_hex_uppercase(&self) -> String {
170        format!("{self:X}")
171    }
172}
173
174impl core::Digest for Digest {}
175
176impl AsRef<[u8]> for Digest {
177    fn as_ref(&self) -> &[u8] {
178        self.as_bytes()
179    }
180}
181
182impl From<[u8; LENGTH_BYTES]> for Digest {
183    fn from(digest: [u8; LENGTH_BYTES]) -> Self {
184        Self::new(digest)
185    }
186}
187
188impl From<Digest> for [u8; LENGTH_BYTES] {
189    fn from(digest: Digest) -> Self {
190        digest.into_inner()
191    }
192}
193
194impl Display for Digest {
195    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
196        LowerHex::fmt(self, f)
197    }
198}
199
200impl LowerHex for Digest {
201    #[rustfmt::skip]
202    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
203        let digest = format!(
204            "{:02x}{:02x}{:02x}{:02x}\
205             {:02x}{:02x}{:02x}{:02x}\
206             {:02x}{:02x}{:02x}{:02x}\
207             {:02x}{:02x}{:02x}{:02x}\
208             {:02x}{:02x}{:02x}{:02x}\
209             {:02x}{:02x}{:02x}{:02x}\
210             {:02x}{:02x}{:02x}{:02x}\
211             {:02x}{:02x}{:02x}{:02x}\
212             {:02x}{:02x}{:02x}{:02x}\
213             {:02x}{:02x}{:02x}{:02x}\
214             {:02x}{:02x}{:02x}{:02x}\
215             {:02x}{:02x}{:02x}{:02x}\
216             {:02x}{:02x}{:02x}{:02x}\
217             {:02x}{:02x}{:02x}{:02x}\
218             {:02x}{:02x}{:02x}{:02x}\
219             {:02x}{:02x}{:02x}{:02x}",
220            self.0[0x00], self.0[0x01], self.0[0x02], self.0[0x03],
221            self.0[0x04], self.0[0x05], self.0[0x06], self.0[0x07],
222            self.0[0x08], self.0[0x09], self.0[0x0A], self.0[0x0B],
223            self.0[0x0C], self.0[0x0D], self.0[0x0E], self.0[0x0F],
224            self.0[0x10], self.0[0x11], self.0[0x12], self.0[0x13],
225            self.0[0x14], self.0[0x15], self.0[0x16], self.0[0x17],
226            self.0[0x18], self.0[0x19], self.0[0x1A], self.0[0x1B],
227            self.0[0x1C], self.0[0x1D], self.0[0x1E], self.0[0x1F],
228            self.0[0x20], self.0[0x21], self.0[0x22], self.0[0x23],
229            self.0[0x24], self.0[0x25], self.0[0x26], self.0[0x27],
230            self.0[0x28], self.0[0x29], self.0[0x2A], self.0[0x2B],
231            self.0[0x2C], self.0[0x2D], self.0[0x2E], self.0[0x2F],
232            self.0[0x30], self.0[0x31], self.0[0x32], self.0[0x33],
233            self.0[0x34], self.0[0x35], self.0[0x36], self.0[0x37],
234            self.0[0x38], self.0[0x39], self.0[0x3A], self.0[0x3B],
235            self.0[0x3C], self.0[0x3D], self.0[0x3E], self.0[0x3F],
236        );
237        if formatter.alternate() {
238            formatter.pad_integral(true, "0x", &digest)
239        } else {
240            formatter.pad(&digest)
241        }
242    }
243}
244
245impl UpperHex for Digest {
246    #[rustfmt::skip]
247    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
248        let digest = format!(
249            "{:02X}{:02X}{:02X}{:02X}\
250             {:02X}{:02X}{:02X}{:02X}\
251             {:02X}{:02X}{:02X}{:02X}\
252             {:02X}{:02X}{:02X}{:02X}\
253             {:02X}{:02X}{:02X}{:02X}\
254             {:02X}{:02X}{:02X}{:02X}\
255             {:02X}{:02X}{:02X}{:02X}\
256             {:02X}{:02X}{:02X}{:02X}\
257             {:02X}{:02X}{:02X}{:02X}\
258             {:02X}{:02X}{:02X}{:02X}\
259             {:02X}{:02X}{:02X}{:02X}\
260             {:02X}{:02X}{:02X}{:02X}\
261             {:02X}{:02X}{:02X}{:02X}\
262             {:02X}{:02X}{:02X}{:02X}\
263             {:02X}{:02X}{:02X}{:02X}\
264             {:02X}{:02X}{:02X}{:02X}",
265            self.0[0x00], self.0[0x01], self.0[0x02], self.0[0x03],
266            self.0[0x04], self.0[0x05], self.0[0x06], self.0[0x07],
267            self.0[0x08], self.0[0x09], self.0[0x0A], self.0[0x0B],
268            self.0[0x0C], self.0[0x0D], self.0[0x0E], self.0[0x0F],
269            self.0[0x10], self.0[0x11], self.0[0x12], self.0[0x13],
270            self.0[0x14], self.0[0x15], self.0[0x16], self.0[0x17],
271            self.0[0x18], self.0[0x19], self.0[0x1A], self.0[0x1B],
272            self.0[0x1C], self.0[0x1D], self.0[0x1E], self.0[0x1F],
273            self.0[0x20], self.0[0x21], self.0[0x22], self.0[0x23],
274            self.0[0x24], self.0[0x25], self.0[0x26], self.0[0x27],
275            self.0[0x28], self.0[0x29], self.0[0x2A], self.0[0x2B],
276            self.0[0x2C], self.0[0x2D], self.0[0x2E], self.0[0x2F],
277            self.0[0x30], self.0[0x31], self.0[0x32], self.0[0x33],
278            self.0[0x34], self.0[0x35], self.0[0x36], self.0[0x37],
279            self.0[0x38], self.0[0x39], self.0[0x3A], self.0[0x3B],
280            self.0[0x3C], self.0[0x3D], self.0[0x3E], self.0[0x3F],
281        );
282        if formatter.alternate() {
283            formatter.pad_integral(true, "0X", &digest)
284        } else {
285            formatter.pad(&digest)
286        }
287    }
288}
289
290impl TryFrom<&str> for Digest {
291    type Error = FormatError;
292
293    fn try_from(digest: &str) -> Result<Self, Self::Error> {
294        if digest.len() != LENGTH_HEX {
295            let error = Self::Error::InvalidLength {
296                value: digest.len(),
297                proper: LENGTH_HEX,
298            };
299            return Err(error);
300        }
301        let digest = [
302            u64::from_str_radix(&digest[0x00..0x10], 16)?.to_be_bytes(),
303            u64::from_str_radix(&digest[0x10..0x20], 16)?.to_be_bytes(),
304            u64::from_str_radix(&digest[0x20..0x30], 16)?.to_be_bytes(),
305            u64::from_str_radix(&digest[0x30..0x40], 16)?.to_be_bytes(),
306            u64::from_str_radix(&digest[0x40..0x50], 16)?.to_be_bytes(),
307            u64::from_str_radix(&digest[0x50..0x60], 16)?.to_be_bytes(),
308            u64::from_str_radix(&digest[0x60..0x70], 16)?.to_be_bytes(),
309            u64::from_str_radix(&digest[0x70..0x80], 16)?.to_be_bytes(),
310        ];
311        #[rustfmt::skip]
312        let digest = [
313            digest[0][0], digest[0][1], digest[0][2], digest[0][3],
314            digest[0][4], digest[0][5], digest[0][6], digest[0][7],
315            digest[1][0], digest[1][1], digest[1][2], digest[1][3],
316            digest[1][4], digest[1][5], digest[1][6], digest[1][7],
317            digest[2][0], digest[2][1], digest[2][2], digest[2][3],
318            digest[2][4], digest[2][5], digest[2][6], digest[2][7],
319            digest[3][0], digest[3][1], digest[3][2], digest[3][3],
320            digest[3][4], digest[3][5], digest[3][6], digest[3][7],
321            digest[4][0], digest[4][1], digest[4][2], digest[4][3],
322            digest[4][4], digest[4][5], digest[4][6], digest[4][7],
323            digest[5][0], digest[5][1], digest[5][2], digest[5][3],
324            digest[5][4], digest[5][5], digest[5][6], digest[5][7],
325            digest[6][0], digest[6][1], digest[6][2], digest[6][3],
326            digest[6][4], digest[6][5], digest[6][6], digest[6][7],
327            digest[7][0], digest[7][1], digest[7][2], digest[7][3],
328            digest[7][4], digest[7][5], digest[7][6], digest[7][7],
329        ];
330        let digest = Self::from(digest);
331        Ok(digest)
332    }
333}
334
335/// An error type for the digest conversion.
336#[derive(Debug, Eq, PartialEq, thiserror::Error)]
337pub enum FormatError {
338    /// Represents an invalid length error with detailed information.
339    #[error("Invalid length `{value}`, proper value `{proper}`")]
340    InvalidLength { value: usize, proper: usize },
341    /// Represents an error that occurs during parsing.
342    #[error(transparent)]
343    ParseError(#[from] ParseIntError),
344}
345
346#[cfg(test)]
347mod tests {
348    use super::*;
349
350    #[test]
351    fn as_bytes() {
352        #[rustfmt::skip]
353        let digest = [
354            0xCF, 0x83, 0xE1, 0x35,
355            0x7E, 0xEF, 0xB8, 0xBD,
356            0xF1, 0x54, 0x28, 0x50,
357            0xD6, 0x6D, 0x80, 0x07,
358            0xD6, 0x20, 0xE4, 0x05,
359            0x0B, 0x57, 0x15, 0xDC,
360            0x83, 0xF4, 0xA9, 0x21,
361            0xD3, 0x6C, 0xE9, 0xCE,
362            0x47, 0xD0, 0xD1, 0x3C,
363            0x5D, 0x85, 0xF2, 0xB0,
364            0xFF, 0x83, 0x18, 0xD2,
365            0x87, 0x7E, 0xEC, 0x2F,
366            0x63, 0xB9, 0x31, 0xBD,
367            0x47, 0x41, 0x7A, 0x81,
368            0xA5, 0x38, 0x32, 0x7A,
369            0xF9, 0x27, 0xDA, 0x3E,
370        ];
371        assert_eq!(Digest::new(digest).as_bytes(), &digest);
372    }
373
374    #[test]
375    fn as_ref() {
376        #[rustfmt::skip]
377        let digest = [
378            0xCF, 0x83, 0xE1, 0x35,
379            0x7E, 0xEF, 0xB8, 0xBD,
380            0xF1, 0x54, 0x28, 0x50,
381            0xD6, 0x6D, 0x80, 0x07,
382            0xD6, 0x20, 0xE4, 0x05,
383            0x0B, 0x57, 0x15, 0xDC,
384            0x83, 0xF4, 0xA9, 0x21,
385            0xD3, 0x6C, 0xE9, 0xCE,
386            0x47, 0xD0, 0xD1, 0x3C,
387            0x5D, 0x85, 0xF2, 0xB0,
388            0xFF, 0x83, 0x18, 0xD2,
389            0x87, 0x7E, 0xEC, 0x2F,
390            0x63, 0xB9, 0x31, 0xBD,
391            0x47, 0x41, 0x7A, 0x81,
392            0xA5, 0x38, 0x32, 0x7A,
393            0xF9, 0x27, 0xDA, 0x3E,
394        ];
395        assert_eq!(Digest::new(digest).as_ref(), &digest);
396    }
397
398    #[test]
399    fn format() {
400        #[rustfmt::skip]
401        let digest = Digest::new([
402            0xCF, 0x83, 0xE1, 0x35,
403            0x7E, 0xEF, 0xB8, 0xBD,
404            0xF1, 0x54, 0x28, 0x50,
405            0xD6, 0x6D, 0x80, 0x07,
406            0xD6, 0x20, 0xE4, 0x05,
407            0x0B, 0x57, 0x15, 0xDC,
408            0x83, 0xF4, 0xA9, 0x21,
409            0xD3, 0x6C, 0xE9, 0xCE,
410            0x47, 0xD0, 0xD1, 0x3C,
411            0x5D, 0x85, 0xF2, 0xB0,
412            0xFF, 0x83, 0x18, 0xD2,
413            0x87, 0x7E, 0xEC, 0x2F,
414            0x63, 0xB9, 0x31, 0xBD,
415            0x47, 0x41, 0x7A, 0x81,
416            0xA5, 0x38, 0x32, 0x7A,
417            0xF9, 0x27, 0xDA, 0x3E,
418        ]);
419        assert_eq!(
420            format!("{digest:x}"),
421            "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
422        );
423        assert_eq!(
424            format!("{digest:#x}"),
425            "0xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
426        );
427        assert_eq!(
428            format!("{digest:136x}"),
429            "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e        "
430        );
431        assert_eq!(
432            format!("{digest:>136x}"),
433            "        cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
434        );
435        assert_eq!(
436            format!("{digest:^136x}"),
437            "    cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e    "
438        );
439        assert_eq!(
440            format!("{digest:<136x}"),
441            "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e        "
442        );
443        assert_eq!(
444            format!("{digest:.^136x}"),
445            "....cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e...."
446        );
447        assert_eq!(format!("{digest:.8x}"), "cf83e135");
448        assert_eq!(
449            format!("{digest:X}"),
450            "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"
451        );
452        assert_eq!(
453            format!("{digest:#X}"),
454            "0XCF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"
455        );
456        assert_eq!(
457            format!("{digest:136X}"),
458            "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E        "
459        );
460        assert_eq!(
461            format!("{digest:>136X}"),
462            "        CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"
463        );
464        assert_eq!(
465            format!("{digest:^136X}"),
466            "    CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E    "
467        );
468        assert_eq!(
469            format!("{digest:<136X}"),
470            "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E        "
471        );
472        assert_eq!(
473            format!("{digest:.^136X}"),
474            "....CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E...."
475        );
476        assert_eq!(format!("{digest:.8X}"), "CF83E135");
477    }
478
479    #[test]
480    fn from() {
481        #[rustfmt::skip]
482        let digest = [
483            0xCF, 0x83, 0xE1, 0x35,
484            0x7E, 0xEF, 0xB8, 0xBD,
485            0xF1, 0x54, 0x28, 0x50,
486            0xD6, 0x6D, 0x80, 0x07,
487            0xD6, 0x20, 0xE4, 0x05,
488            0x0B, 0x57, 0x15, 0xDC,
489            0x83, 0xF4, 0xA9, 0x21,
490            0xD3, 0x6C, 0xE9, 0xCE,
491            0x47, 0xD0, 0xD1, 0x3C,
492            0x5D, 0x85, 0xF2, 0xB0,
493            0xFF, 0x83, 0x18, 0xD2,
494            0x87, 0x7E, 0xEC, 0x2F,
495            0x63, 0xB9, 0x31, 0xBD,
496            0x47, 0x41, 0x7A, 0x81,
497            0xA5, 0x38, 0x32, 0x7A,
498            0xF9, 0x27, 0xDA, 0x3E,
499        ];
500        assert_eq!(Digest::from(digest), Digest::new(digest));
501        assert_eq!(<[u8; 64]>::from(Digest::new(digest)), digest);
502    }
503
504    #[test]
505    fn to_hex() {
506        #[rustfmt::skip]
507        let digest = Digest::new([
508            0xCF, 0x83, 0xE1, 0x35,
509            0x7E, 0xEF, 0xB8, 0xBD,
510            0xF1, 0x54, 0x28, 0x50,
511            0xD6, 0x6D, 0x80, 0x07,
512            0xD6, 0x20, 0xE4, 0x05,
513            0x0B, 0x57, 0x15, 0xDC,
514            0x83, 0xF4, 0xA9, 0x21,
515            0xD3, 0x6C, 0xE9, 0xCE,
516            0x47, 0xD0, 0xD1, 0x3C,
517            0x5D, 0x85, 0xF2, 0xB0,
518            0xFF, 0x83, 0x18, 0xD2,
519            0x87, 0x7E, 0xEC, 0x2F,
520            0x63, 0xB9, 0x31, 0xBD,
521            0x47, 0x41, 0x7A, 0x81,
522            0xA5, 0x38, 0x32, 0x7A,
523            0xF9, 0x27, 0xDA, 0x3E,
524        ]);
525        #[rustfmt::skip]
526        assert_eq!(digest.to_hex_lowercase(), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
527        #[rustfmt::skip]
528        assert_eq!(digest.to_hex_uppercase(), "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E");
529    }
530
531    #[test]
532    fn try_from() {
533        assert_eq!(
534            Digest::try_from("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"),
535            Digest::try_from("CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E")
536        );
537        #[rustfmt::skip]
538        assert_eq!(
539            Digest::try_from("CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"),
540            Ok(Digest::new([
541                0xCF, 0x83, 0xE1, 0x35,
542                0x7E, 0xEF, 0xB8, 0xBD,
543                0xF1, 0x54, 0x28, 0x50,
544                0xD6, 0x6D, 0x80, 0x07,
545                0xD6, 0x20, 0xE4, 0x05,
546                0x0B, 0x57, 0x15, 0xDC,
547                0x83, 0xF4, 0xA9, 0x21,
548                0xD3, 0x6C, 0xE9, 0xCE,
549                0x47, 0xD0, 0xD1, 0x3C,
550                0x5D, 0x85, 0xF2, 0xB0,
551                0xFF, 0x83, 0x18, 0xD2,
552                0x87, 0x7E, 0xEC, 0x2F,
553                0x63, 0xB9, 0x31, 0xBD,
554                0x47, 0x41, 0x7A, 0x81,
555                0xA5, 0x38, 0x32, 0x7A,
556                0xF9, 0x27, 0xDA, 0x3E,
557            ]))
558        );
559        assert!(matches!(Digest::try_from("CF"), Err(FormatError::InvalidLength { .. })));
560        assert!(matches!(
561            Digest::try_from("CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3EXX"),
562            Err(FormatError::InvalidLength { .. })
563        ));
564        assert!(matches!(
565            Digest::try_from("CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DAXX"),
566            Err(FormatError::ParseError(_))
567        ));
568    }
569}