1use crate::{ContentAddress, Signature, Word};
4pub use hex::FromHexError;
5
6pub fn words_from_hex_str(str: &str) -> Result<Vec<Word>, FromHexError> {
8 Ok(hex::decode(str)?
9 .chunks_exact(8)
10 .map(|chunk| word_from_bytes(chunk.try_into().expect("Word is always 8 bytes")))
11 .collect())
12}
13
14pub fn hex_str_from_words(words: &[Word]) -> String {
16 hex::encode(
17 words
18 .iter()
19 .flat_map(|word| bytes_from_word(*word))
20 .collect::<Vec<u8>>(),
21 )
22}
23
24pub fn bytes_from_word(w: Word) -> [u8; 8] {
26 w.to_be_bytes()
27}
28
29pub fn word_from_bytes(bytes: [u8; 8]) -> Word {
31 Word::from_be_bytes(bytes)
32}
33
34pub fn word_from_bytes_slice(bytes: &[u8]) -> Word {
38 let mut word = [0; core::mem::size_of::<Word>()];
39 let len = bytes.len().min(word.len());
40 word[..len].copy_from_slice(&bytes[..len]);
41 word_from_bytes(word)
42}
43
44#[rustfmt::skip]
46pub fn word_4_from_u8_32(bytes: [u8; 32]) -> [Word; 4] {
47 let [
50 b0, b1, b2, b3, b4, b5, b6, b7,
51 b8, b9, b10, b11, b12, b13, b14, b15,
52 b16, b17, b18, b19, b20, b21, b22, b23,
53 b24, b25, b26, b27, b28, b29, b30, b31,
54 ] = bytes;
55 [
56 word_from_bytes([b0, b1, b2, b3, b4, b5, b6, b7]),
57 word_from_bytes([b8, b9, b10, b11, b12, b13, b14, b15]),
58 word_from_bytes([b16, b17, b18, b19, b20, b21, b22, b23]),
59 word_from_bytes([b24, b25, b26, b27, b28, b29, b30, b31]),
60 ]
61}
62
63#[rustfmt::skip]
65pub fn word_8_from_u8_64(bytes: [u8; 64]) -> [Word; 8] {
66 let [
69 b0, b1, b2, b3, b4, b5, b6, b7,
70 b8, b9, b10, b11, b12, b13, b14, b15,
71 b16, b17, b18, b19, b20, b21, b22, b23,
72 b24, b25, b26, b27, b28, b29, b30, b31,
73 b32, b33, b34, b35, b36, b37, b38, b39,
74 b40, b41, b42, b43, b44, b45, b46, b47,
75 b48, b49, b50, b51, b52, b53, b54, b55,
76 b56, b57, b58, b59, b60, b61, b62, b63,
77 ] = bytes;
78 [
79 word_from_bytes([b0, b1, b2, b3, b4, b5, b6, b7]),
80 word_from_bytes([b8, b9, b10, b11, b12, b13, b14, b15]),
81 word_from_bytes([b16, b17, b18, b19, b20, b21, b22, b23]),
82 word_from_bytes([b24, b25, b26, b27, b28, b29, b30, b31]),
83 word_from_bytes([b32, b33, b34, b35, b36, b37, b38, b39]),
84 word_from_bytes([b40, b41, b42, b43, b44, b45, b46, b47]),
85 word_from_bytes([b48, b49, b50, b51, b52, b53, b54, b55]),
86 word_from_bytes([b56, b57, b58, b59, b60, b61, b62, b63]),
87 ]
88}
89
90#[rustfmt::skip]
92pub fn u8_32_from_word_4(words: [Word; 4]) -> [u8; 32] {
93 let [w0, w1, w2, w3] = words;
96 let [b0, b1, b2, b3, b4, b5, b6, b7] = bytes_from_word(w0);
97 let [b8, b9, b10, b11, b12, b13, b14, b15] = bytes_from_word(w1);
98 let [b16, b17, b18, b19, b20, b21, b22, b23] = bytes_from_word(w2);
99 let [b24, b25, b26, b27, b28, b29, b30, b31] = bytes_from_word(w3);
100 [
101 b0, b1, b2, b3, b4, b5, b6, b7,
102 b8, b9, b10, b11, b12, b13, b14, b15,
103 b16, b17, b18, b19, b20, b21, b22, b23,
104 b24, b25, b26, b27, b28, b29, b30, b31,
105 ]
106}
107
108#[rustfmt::skip]
110pub fn u8_64_from_word_8(words: [Word; 8]) -> [u8; 64] {
111 let [w0, w1, w2, w3, w4, w5, w6, w7] = words;
114 let [b0, b1, b2, b3, b4, b5, b6, b7] = bytes_from_word(w0);
115 let [b8, b9, b10, b11, b12, b13, b14, b15] = bytes_from_word(w1);
116 let [b16, b17, b18, b19, b20, b21, b22, b23] = bytes_from_word(w2);
117 let [b24, b25, b26, b27, b28, b29, b30, b31] = bytes_from_word(w3);
118 let [b32, b33, b34, b35, b36, b37, b38, b39] = bytes_from_word(w4);
119 let [b40, b41, b42, b43, b44, b45, b46, b47] = bytes_from_word(w5);
120 let [b48, b49, b50, b51, b52, b53, b54, b55] = bytes_from_word(w6);
121 let [b56, b57, b58, b59, b60, b61, b62, b63] = bytes_from_word(w7);
122 [
123 b0, b1, b2, b3, b4, b5, b6, b7,
124 b8, b9, b10, b11, b12, b13, b14, b15,
125 b16, b17, b18, b19, b20, b21, b22, b23,
126 b24, b25, b26, b27, b28, b29, b30, b31,
127 b32, b33, b34, b35, b36, b37, b38, b39,
128 b40, b41, b42, b43, b44, b45, b46, b47,
129 b48, b49, b50, b51, b52, b53, b54, b55,
130 b56, b57, b58, b59, b60, b61, b62, b63,
131 ]
132}
133
134pub fn bool_from_word(word: Word) -> Option<bool> {
138 match word {
139 0 => Some(false),
140 1 => Some(true),
141 _ => None,
142 }
143}
144
145impl From<ContentAddress> for [Word; 4] {
146 fn from(address: ContentAddress) -> Self {
147 word_4_from_u8_32(address.0)
148 }
149}
150
151impl From<ContentAddress> for [u8; 32] {
152 fn from(address: ContentAddress) -> Self {
153 address.0
154 }
155}
156
157impl From<[Word; 4]> for ContentAddress {
158 fn from(address: [Word; 4]) -> Self {
159 Self(u8_32_from_word_4(address))
160 }
161}
162
163impl From<[u8; 32]> for ContentAddress {
164 fn from(address: [u8; 32]) -> Self {
165 Self(address)
166 }
167}
168
169impl From<Signature> for [u8; 65] {
170 #[rustfmt::skip]
171 fn from(sig: Signature) -> Self {
172 let [
173 b0, b1, b2, b3, b4, b5, b6, b7,
174 b8, b9, b10, b11, b12, b13, b14, b15,
175 b16, b17, b18, b19, b20, b21, b22, b23,
176 b24, b25, b26, b27, b28, b29, b30, b31,
177 b32, b33, b34, b35, b36, b37, b38, b39,
178 b40, b41, b42, b43, b44, b45, b46, b47,
179 b48, b49, b50, b51, b52, b53, b54, b55,
180 b56, b57, b58, b59, b60, b61, b62, b63,
181 ] = sig.0;
182 [
183 b0, b1, b2, b3, b4, b5, b6, b7,
184 b8, b9, b10, b11, b12, b13, b14, b15,
185 b16, b17, b18, b19, b20, b21, b22, b23,
186 b24, b25, b26, b27, b28, b29, b30, b31,
187 b32, b33, b34, b35, b36, b37, b38, b39,
188 b40, b41, b42, b43, b44, b45, b46, b47,
189 b48, b49, b50, b51, b52, b53, b54, b55,
190 b56, b57, b58, b59, b60, b61, b62, b63,
191 sig.1,
192 ]
193 }
194}
195
196impl From<[u8; 65]> for Signature {
197 #[rustfmt::skip]
198 fn from(bytes: [u8; 65]) -> Self {
199 let [
200 b0, b1, b2, b3, b4, b5, b6, b7,
201 b8, b9, b10, b11, b12, b13, b14, b15,
202 b16, b17, b18, b19, b20, b21, b22, b23,
203 b24, b25, b26, b27, b28, b29, b30, b31,
204 b32, b33, b34, b35, b36, b37, b38, b39,
205 b40, b41, b42, b43, b44, b45, b46, b47,
206 b48, b49, b50, b51, b52, b53, b54, b55,
207 b56, b57, b58, b59, b60, b61, b62, b63,
208 id,
209 ] = bytes;
210 let sig = [
211 b0, b1, b2, b3, b4, b5, b6, b7,
212 b8, b9, b10, b11, b12, b13, b14, b15,
213 b16, b17, b18, b19, b20, b21, b22, b23,
214 b24, b25, b26, b27, b28, b29, b30, b31,
215 b32, b33, b34, b35, b36, b37, b38, b39,
216 b40, b41, b42, b43, b44, b45, b46, b47,
217 b48, b49, b50, b51, b52, b53, b54, b55,
218 b56, b57, b58, b59, b60, b61, b62, b63,
219 ];
220 Signature(sig, id)
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 const WORD_SAMPLE: Word = 0x123456789ABCDEF0;
230 const BYTES_SAMPLE: [u8; 8] = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
231 const U8_32_SAMPLE: [u8; 32] = [
232 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
233 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
234 0x1E, 0x1F,
235 ];
236 const U8_64_SAMPLE: [u8; 64] = [
237 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
238 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
239 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
240 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
241 0x3C, 0x3D, 0x3E, 0x3F,
242 ];
243
244 #[test]
245 fn test_bytes_from_word() {
246 assert_eq!(bytes_from_word(WORD_SAMPLE), BYTES_SAMPLE);
247 }
248
249 #[test]
250 fn test_word_from_bytes() {
251 assert_eq!(word_from_bytes(BYTES_SAMPLE), WORD_SAMPLE);
252 }
253
254 #[test]
255 fn test_word_4_from_u8_32() {
256 let expected_words = [
257 Word::from_be_bytes([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
258 Word::from_be_bytes([0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
259 Word::from_be_bytes([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]),
260 Word::from_be_bytes([0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F]),
261 ];
262 assert_eq!(word_4_from_u8_32(U8_32_SAMPLE), expected_words);
263 }
264
265 #[test]
266 fn test_u8_32_from_word_4() {
267 let words = [
268 Word::from_be_bytes([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
269 Word::from_be_bytes([0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
270 Word::from_be_bytes([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]),
271 Word::from_be_bytes([0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F]),
272 ];
273 assert_eq!(u8_32_from_word_4(words), U8_32_SAMPLE);
274 }
275
276 #[test]
277 fn test_word_8_from_u8_64() {
278 let expected_words = [
279 Word::from_be_bytes([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
280 Word::from_be_bytes([0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
281 Word::from_be_bytes([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]),
282 Word::from_be_bytes([0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F]),
283 Word::from_be_bytes([0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27]),
284 Word::from_be_bytes([0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F]),
285 Word::from_be_bytes([0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37]),
286 Word::from_be_bytes([0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F]),
287 ];
288 assert_eq!(word_8_from_u8_64(U8_64_SAMPLE), expected_words);
289 }
290
291 #[test]
292 fn test_u8_64_from_word_8() {
293 let words = [
294 Word::from_be_bytes([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
295 Word::from_be_bytes([0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]),
296 Word::from_be_bytes([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]),
297 Word::from_be_bytes([0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F]),
298 Word::from_be_bytes([0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27]),
299 Word::from_be_bytes([0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F]),
300 Word::from_be_bytes([0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37]),
301 Word::from_be_bytes([0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F]),
302 ];
303 assert_eq!(u8_64_from_word_8(words), U8_64_SAMPLE);
304 }
305}