Skip to main content

mountpoint_s3_client/
checksums.rs

1//! Provides base64 encoding/decoding for various checksums.
2pub use mountpoint_s3_crt::checksums::crc32::{self, Crc32};
3pub use mountpoint_s3_crt::checksums::crc32c::{self, Crc32c};
4pub use mountpoint_s3_crt::checksums::crc64nvme::{self, Crc64nvme};
5pub use mountpoint_s3_crt::checksums::sha1::{self, Sha1};
6pub use mountpoint_s3_crt::checksums::sha256::{self, Sha256};
7
8use base64ct::Base64;
9use base64ct::Encoding;
10use thiserror::Error;
11
12/// The base64 encoding for this CRC64-NVME checksum value.
13pub fn crc64nvme_to_base64(checksum: &Crc64nvme) -> String {
14    Base64::encode_string(&checksum.value().to_be_bytes())
15}
16
17/// Create a CRC64-NVME checksum from a base64 encoding.
18pub fn crc64nvme_from_base64(base64_str: &str) -> Result<Crc64nvme, ParseError> {
19    let mut dec_buf = [0u8; std::mem::size_of::<u64>()];
20    let _ = Base64::decode(base64_str, &mut dec_buf)?;
21    Ok(Crc64nvme::new(u64::from_be_bytes(dec_buf)))
22}
23
24/// The base64 encoding for this CRC32C checksum value.
25pub fn crc32c_to_base64(checksum: &Crc32c) -> String {
26    Base64::encode_string(&checksum.value().to_be_bytes())
27}
28
29/// Create a CRC32C checksum from a base64 encoding.
30pub fn crc32c_from_base64(base64_str: &str) -> Result<Crc32c, ParseError> {
31    let mut dec_buf = [0u8; std::mem::size_of::<u32>()];
32    let _ = Base64::decode(base64_str, &mut dec_buf)?;
33    Ok(Crc32c::new(u32::from_be_bytes(dec_buf)))
34}
35
36/// The base64 encoding for this CRC32 checksum value.
37pub fn crc32_to_base64(checksum: &Crc32) -> String {
38    Base64::encode_string(&checksum.value().to_be_bytes())
39}
40
41/// Create a CRC32 checksum from a base64 encoding.
42pub fn crc32_from_base64(base64_str: &str) -> Result<Crc32, ParseError> {
43    let mut dec_buf = [0u8; std::mem::size_of::<u32>()];
44    let _ = Base64::decode(base64_str, &mut dec_buf)?;
45    Ok(Crc32::new(u32::from_be_bytes(dec_buf)))
46}
47
48/// The base64 encoding for this SHA1 checksum value.
49pub fn sha1_to_base64(checksum: &Sha1) -> String {
50    Base64::encode_string(checksum.value())
51}
52
53/// The base64 encoding for this SHA256 checksum value.
54pub fn sha256_to_base64(checksum: &Sha256) -> String {
55    Base64::encode_string(checksum.value())
56}
57
58/// Error parsing CRC32C checksums.
59#[derive(Error, Debug)]
60pub enum ParseError {
61    /// Error parsing base64 encoding.
62    #[error("Failed to parse base64 encoding")]
63    Base64ParseError(#[from] base64ct::Error),
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use test_case::test_case;
70
71    #[test]
72    fn test_crc64nvme_to_base64() {
73        let crc = Crc64nvme::new(0xAE8B14860A799888);
74        let base64 = crc64nvme_to_base64(&crc);
75        assert_eq!(&base64, "rosUhgp5mIg=");
76    }
77
78    #[test]
79    fn test_crc64nvme_from_base64() {
80        let base64 = "rosUhgp5mIg=";
81        let crc = crc64nvme_from_base64(base64).expect("parsing should succeeed");
82        assert_eq!(crc.value(), 0xAE8B14860A799888);
83    }
84
85    #[test]
86    fn test_crc32c_to_base64() {
87        let crc = Crc32c::new(1234);
88        let base64 = crc32c_to_base64(&crc);
89        assert_eq!(&base64, "AAAE0g==");
90    }
91
92    #[test]
93    fn test_crc32c_from_base64() {
94        let base64 = "AAAE0g==";
95        let crc = crc32c_from_base64(base64).expect("parsing should succeeed");
96        assert_eq!(crc.value(), 1234);
97    }
98
99    #[test_case("AAA")]
100    #[test_case("AAAE0g")]
101    #[test_case("AAAE0gAA==")]
102    fn test_crc32c_from_base64_error(invalid_base64: &str) {
103        let err = crc32c_from_base64(invalid_base64).expect_err("parsing should fail");
104        assert!(matches!(err, ParseError::Base64ParseError(_)));
105    }
106
107    #[test]
108    fn test_crc32_to_base64() {
109        let crc = Crc32::new(1234);
110        let base64 = crc32_to_base64(&crc);
111        assert_eq!(&base64, "AAAE0g==");
112    }
113
114    #[test]
115    fn test_crc32_from_base64() {
116        let base64 = "AAAE0g==";
117        let crc = crc32_from_base64(base64).expect("parsing should succeeed");
118        assert_eq!(crc.value(), 1234);
119    }
120
121    #[test_case("AAA")]
122    #[test_case("AAAE0g")]
123    #[test_case("AAAE0gAA==")]
124    fn test_crc32_from_base64_error(invalid_base64: &str) {
125        let err = crc32_from_base64(invalid_base64).expect_err("parsing should fail");
126        assert!(matches!(err, ParseError::Base64ParseError(_)));
127    }
128
129    #[test]
130    fn test_sha1_to_base64() {
131        let sha1 = Sha1::new([
132            247, 195, 188, 29, 128, 142, 4, 115, 42, 223, 103, 153, 101, 204, 195, 76, 167, 174, 52, 65,
133        ]);
134        let base64 = sha1_to_base64(&sha1);
135        assert_eq!(&base64, "98O8HYCOBHMq32eZZczDTKeuNEE=");
136    }
137
138    #[test]
139    fn test_sha256_to_base64() {
140        let sha256 = Sha256::new([
141            21, 226, 176, 211, 195, 56, 145, 235, 176, 241, 239, 96, 158, 196, 25, 66, 12, 32, 227, 32, 206, 148, 198,
142            95, 188, 140, 51, 18, 68, 142, 178, 37,
143        ]);
144        let base64 = sha256_to_base64(&sha256);
145        assert_eq!(&base64, "FeKw08M4keuw8e9gnsQZQgwg4yDOlMZfvIwzEkSOsiU=");
146    }
147}