dup_crypto/bases/
b16.rs

1//  Copyright (C) 2020 Éloïs SANCHEZ.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16//! Provide base16 convertion tools
17
18use crate::bases::BaseConversionError;
19
20/// Convert a hexadecimal string in an array of 32 bytes.
21///
22/// The hex string must only contains hex characters
23/// and produce a 32 bytes value.
24pub fn str_hex_to_32bytes(text: &str) -> Result<[u8; 32], BaseConversionError> {
25    if text.len() != 64 {
26        Err(BaseConversionError::InvalidLength {
27            expected: 64,
28            found: text.len(),
29        })
30    } else {
31        let mut bytes = [0u8; 32];
32
33        let chars = text.as_bytes();
34
35        for i in 0..64 {
36            if i % 2 != 0 {
37                continue;
38            }
39
40            let byte1 = hex_char_byte_to_byte(chars[i], i)?;
41            let byte2 = hex_char_byte_to_byte(chars[i + 1], i + 1)?;
42
43            bytes[i / 2] = (byte1 << 4) | byte2;
44        }
45
46        Ok(bytes)
47    }
48}
49
50/// Convert a hexadecimal string in an array of 64 bytes.
51///
52/// The hex string must only contains hex characters
53/// and produce a 64 bytes value.
54pub fn str_hex_to_64bytes(text: &str) -> Result<[u8; 64], BaseConversionError> {
55    if text.len() != 128 {
56        Err(BaseConversionError::InvalidLength {
57            expected: 128,
58            found: text.len(),
59        })
60    } else {
61        let mut bytes = [0u8; 64];
62
63        let chars = text.as_bytes();
64
65        for i in 0..128 {
66            if i % 2 != 0 {
67                continue;
68            }
69
70            let byte1 = hex_char_byte_to_byte(chars[i], i)?;
71            let byte2 = hex_char_byte_to_byte(chars[i + 1], i + 1)?;
72
73            bytes[i / 2] = (byte1 << 4) | byte2;
74        }
75
76        Ok(bytes)
77    }
78}
79
80fn hex_char_byte_to_byte(hex_char: u8, pos: usize) -> Result<u8, BaseConversionError> {
81    match hex_char {
82        b'0' => Ok(0),
83        b'1' => Ok(1),
84        b'2' => Ok(2),
85        b'3' => Ok(3),
86        b'4' => Ok(4),
87        b'5' => Ok(5),
88        b'6' => Ok(6),
89        b'7' => Ok(7),
90        b'8' => Ok(8),
91        b'9' => Ok(9),
92        b'A' => Ok(10),
93        b'B' => Ok(11),
94        b'C' => Ok(12),
95        b'D' => Ok(13),
96        b'E' => Ok(14),
97        b'F' => Ok(15),
98        c => Err(BaseConversionError::InvalidCharacter {
99            character: c as char,
100            offset: pos,
101        }),
102    }
103}