hash_based_signatures/
utils.rs1use crate::signature::HashType;
2use anyhow::{bail, Result};
3use data_encoding::HEXLOWER;
4use ring::digest::{digest, SHA256};
5use ring::hmac::Key;
6use std::cmp::min;
7
8pub fn slice_to_hash(input_slice: &[u8]) -> HashType {
13 assert_eq!(input_slice.len(), 32);
14 let mut result = [0u8; 32];
15 result.copy_from_slice(input_slice);
16 result
17}
18
19pub fn hash(data: &[u8]) -> HashType {
21 slice_to_hash(digest(&SHA256, data).as_ref())
22}
23
24pub fn hmac(key: &HashType, data: &[u8]) -> HashType {
26 let hmac_key = Key::new(ring::hmac::HMAC_SHA256, key);
27 slice_to_hash(ring::hmac::sign(&hmac_key, data).as_ref())
28}
29
30pub fn string_to_hash_maybe(hash_string: &str) -> Result<HashType> {
31 let decoded = HEXLOWER.decode(hash_string.as_bytes())?;
32 if decoded.len() != 32 {
33 bail!("Invalid number of bytes!");
34 }
35 Ok(slice_to_hash(&decoded))
36}
37
38pub fn string_to_hash(hash_string: &str) -> HashType {
39 string_to_hash_maybe(hash_string).expect("Could not decode")
40}
41
42pub fn get_least_significant_bits(index: usize, bits: usize) -> Vec<bool> {
45 let mut result = Vec::new();
46 for i in (0..bits).rev() {
47 result.push((index & (1 << i)) != 0)
48 }
49 result
50}
51
52pub fn bits_to_unsigned_int(bits: &[bool]) -> u8 {
58 assert!(bits.len() <= 8);
59 let mut result = 0;
60 for i in 0..bits.len() {
61 if bits[i] {
62 result = result | (1 << (bits.len() - 1 - i));
63 }
64 }
65 result
66}
67
68pub fn bits_to_unsigned_ints(bits: &[bool]) -> Vec<u8> {
70 let size = (bits.len() as f32 / 8.0).ceil() as usize;
71 let mut result = Vec::with_capacity(size);
72 for i in 0..size {
73 let end_bit = min((i + 1) * 8, bits.len());
74 result.push(bits_to_unsigned_int(&bits[i * 8..end_bit]));
75 }
76 result
77}
78
79#[cfg(test)]
80mod tests {
81 use crate::signature::HashType;
82 use crate::utils::{
83 bits_to_unsigned_int, bits_to_unsigned_ints, get_least_significant_bits, string_to_hash,
84 };
85
86 #[test]
87 fn test_get_least_significant_bits() {
88 assert_eq!(
89 get_least_significant_bits(10, 5),
90 vec![false, true, false, true, false]
91 )
92 }
93
94 #[test]
95 fn test_bits_to_unsigned_int() {
96 assert_eq!(bits_to_unsigned_int(&[false, true, false, true, false]), 10)
97 }
98
99 #[test]
100 fn test_bits_to_unsigned_ints() {
101 assert_eq!(
102 bits_to_unsigned_ints(&[
103 false, false, false, false, true, false, true, false, true, false
104 ]),
105 vec![10, 2]
106 )
107 }
108
109 fn get_test_hash() -> (HashType, String) {
110 let mut hash = [0u8; 32];
111 for i in 0..32 {
112 hash[i] = i as u8;
113 }
114 (
115 hash,
116 String::from("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
117 )
118 }
119
120 #[test]
121 fn test_string_to_hash() {
122 let (test_hash, test_hash_string) = get_test_hash();
123 assert_eq!(string_to_hash(&test_hash_string), test_hash);
124 }
125
126 #[test]
127 #[should_panic]
128 fn test_string_to_hash_invalid_wrong_length() {
129 string_to_hash(&String::from("I have the wrong length"));
130 }
131
132 #[test]
133 #[should_panic]
134 fn test_string_to_hash_invalid_no_hex() {
135 let hash_string = "Right length but no valid hash! ";
136 string_to_hash(&String::from(hash_string));
137 }
138}