/src/data-encoding/lib/fuzz/src/spec.rs
Line | Count | Source |
1 | | //! Reference implementation of the specification. |
2 | | |
3 | | use data_encoding::{BitOrder, Specification}; |
4 | | |
5 | 9.07k | pub fn encode(spec: &Specification, input: &[u8]) -> String { |
6 | | // Make sure the specification is valid. |
7 | 9.07k | assert!(spec.encoding().is_ok()); |
8 | | // Define short variables. |
9 | 9.07k | let symbols = spec.symbols.as_bytes(); |
10 | 9.07k | let bit = symbols.len().trailing_zeros() as usize; |
11 | 9.07k | let msb = spec.bit_order == BitOrder::MostSignificantFirst; |
12 | | // Convert from base256 to binary and from binary to baseX. |
13 | 9.07k | let mut output = bits_value(bit, msb, &value_bits(8, msb, input)); |
14 | | // Convert from values to symbols. |
15 | 833M | output.iter_mut().for_each(|x| *x = symbols[*x as usize]); |
16 | | // Pad to the next `dec(bit)` boundary, if needed. |
17 | 9.07k | if let Some(pad) = spec.padding { |
18 | 7.88k | while !output.len().is_multiple_of(dec(bit)) { |
19 | 5.44k | output.push(pad as u8); |
20 | 5.44k | } |
21 | 6.63k | } |
22 | | // Wrap every `width` bytes with `separator`, if needed. Including a possibly partial last row. |
23 | 9.07k | if spec.wrap.width != 0 { |
24 | 25.9M | for row in std::mem::take(&mut output).chunks(spec.wrap.width) { |
25 | 25.9M | output.extend_from_slice(row); |
26 | 25.9M | output.extend_from_slice(spec.wrap.separator.as_bytes()); |
27 | 25.9M | } |
28 | 3.44k | } |
29 | | // Cast the symbols to a string. |
30 | 9.07k | String::from_utf8(output).unwrap() |
31 | 9.07k | } |
32 | | |
33 | 8.65k | pub fn decode(spec: &Specification, input: &[u8]) -> Option<Vec<u8>> { |
34 | | // Make sure the specification is valid. |
35 | 8.65k | assert!(spec.encoding().is_ok()); |
36 | | // Define short variables. |
37 | 8.65k | let symbols = spec.symbols.as_bytes(); |
38 | 8.65k | let bit = symbols.len().trailing_zeros() as usize; |
39 | 8.65k | let xlate = &spec.translate; |
40 | | // Make sure we also ignore the separators. |
41 | 8.65k | let mut ignore = spec.ignore.as_bytes().to_vec(); |
42 | 8.65k | ignore.extend_from_slice(spec.wrap.separator.as_bytes()); |
43 | | // Translate and ignore bytes as needed. Only symbols and padding are left (for valid input). |
44 | 8.65k | let input: Vec<u8> = input |
45 | 8.65k | .iter() |
46 | 2.97G | .map(|&x| xlate.from.bytes().position(|y| y == x).map_or(x, |i| xlate.to.as_bytes()[i])) |
47 | 442M | .filter(|x| !ignore.contains(x)) |
48 | 8.65k | .collect(); |
49 | | // Decode by blocks of `dec(bit)` bytes. Only the last one may be partial. |
50 | 8.65k | let mut output = Vec::new(); |
51 | 9.90M | for block in input.chunks(dec(bit)) { |
52 | 9.90M | output.extend_from_slice(&decode_block(spec, block)?); |
53 | | } |
54 | 1.33k | Some(output) |
55 | 8.65k | } |
56 | | |
57 | 9.90M | fn decode_block(spec: &Specification, mut input: &[u8]) -> Option<Vec<u8>> { |
58 | | // Define short variables. |
59 | 9.90M | let bit = spec.symbols.len().trailing_zeros() as usize; |
60 | 9.90M | let msb = spec.bit_order == BitOrder::MostSignificantFirst; |
61 | | // Remove padding, if needed. |
62 | 9.90M | if let Some(pad) = spec.padding { |
63 | | // There are no partial blocks with padding. |
64 | 1.77M | if input.len() != dec(bit) { |
65 | 1.09k | return None; |
66 | 1.77M | } |
67 | | // Repeatedly remove last byte, if padding. |
68 | 2.01M | while *input.last()? == pad as u8 { |
69 | 237k | input = &input[.. input.len() - 1]; |
70 | 237k | } |
71 | 8.12M | } |
72 | | // Convert from symbols to values. |
73 | 46.6M | let input = input.iter().map(|&x| value_symbol(spec, x)).collect::<Option<Vec<u8>>>()?; |
74 | | // Convert from baseX to binary. |
75 | 9.89M | let mut bits = value_bits(bit, msb, &input); |
76 | | // Check trailing bits (leading bits of the binary number that don't form a full byte). |
77 | 9.89M | let trail = bits.len() % 8; |
78 | 9.89M | if 0 < trail { |
79 | | // The trailing bits should not contain a full symbol. |
80 | 55.9k | if bit <= trail { |
81 | 494 | return None; |
82 | 55.4k | } |
83 | | // The trailing bits should be zero, if checked. |
84 | 55.4k | let trail = bits.split_off(bits.len() - trail); |
85 | 55.4k | if spec.check_trailing_bits && trail.iter().any(|x| *x) { |
86 | 272 | return None; |
87 | 55.1k | } |
88 | 9.83M | } |
89 | | // A block cannot be composed of padding only. |
90 | 9.89M | if bits.is_empty() { |
91 | 0 | return None; |
92 | 9.89M | } |
93 | | // Convert from binary to base256. |
94 | 9.89M | Some(bits_value(8, msb, &bits)) |
95 | 9.90M | } |
96 | | |
97 | 46.6M | fn value_symbol(spec: &Specification, symbol: u8) -> Option<u8> { |
98 | | // The value of a symbol is its position in the specification. |
99 | 623M | spec.symbols.bytes().position(|x| x == symbol).map(|x| x as u8) |
100 | 46.6M | } |
101 | | |
102 | 9.90M | fn value_bits(bit: usize, msb: bool, input: &[u8]) -> Vec<bool> { |
103 | | // Convert from binary to baseX. |
104 | 9.90M | let mut output = Vec::new(); |
105 | 385M | for &x in input { |
106 | 2.83G | for i in order(msb, bit) { |
107 | 2.83G | output.push(x & (1 << i) != 0); |
108 | 2.83G | } |
109 | | } |
110 | 9.90M | output |
111 | 9.90M | } |
112 | | |
113 | 9.90M | fn bits_value(bit: usize, msb: bool, input: &[bool]) -> Vec<u8> { |
114 | | // Convert from baseX to binary. |
115 | 9.90M | let mut output = Vec::new(); |
116 | 858M | for bits in input.chunks(bit) { |
117 | 2.83G | output.push(order(msb, bit).zip(bits).map(|(i, &b)| (b as u8) << i).sum()); |
118 | | } |
119 | 9.90M | output |
120 | 9.90M | } |
121 | | |
122 | 1.23G | fn order(msb: bool, n: usize) -> Box<dyn Iterator<Item = usize>> { |
123 | | // Iterate from 0 to n - 1, or the opposite if most significant bit first. |
124 | 1.23G | if msb { |
125 | 623M | Box::new((0 .. n).rev()) |
126 | | } else { |
127 | 611M | Box::new(0 .. n) |
128 | | } |
129 | 1.23G | } |
130 | | |
131 | 1.79M | fn enc(bit: usize) -> usize { |
132 | | // Input block size for encoding, output block size for decoding. |
133 | 1.79M | match bit { |
134 | 2.57k | 1 | 2 | 4 => 1, |
135 | 924k | 3 | 6 => 3, |
136 | 863k | 5 => 5, |
137 | 0 | _ => unreachable!(), |
138 | | } |
139 | 1.79M | } |
140 | | |
141 | 1.79M | fn dec(bit: usize) -> usize { |
142 | | // Input block size for decoding, output block size for encoding. |
143 | 1.79M | enc(bit) * 8 / bit |
144 | 1.79M | } |
145 | | |
146 | | #[cfg(test)] |
147 | | mod tests { |
148 | | use super::*; |
149 | | |
150 | | #[test] |
151 | | fn value_bits_ok() { |
152 | | #[track_caller] |
153 | | fn test(bit: usize, msb: bool, values: &[u8], bits: &[u8]) { |
154 | | let bits: Vec<_> = bits.into_iter().map(|&x| x == 1).collect(); |
155 | | assert_eq!(value_bits(bit, msb, values), bits); |
156 | | assert_eq!(bits_value(bit, msb, &bits), values); |
157 | | } |
158 | | test(8, true, &[0xc5, 0x69], &[1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1]); |
159 | | test(8, false, &[0xc5, 0x69], &[1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0]); |
160 | | test(6, true, &[0x36, 0x2c], &[1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0]); |
161 | | test(6, false, &[0x36, 0x2c], &[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1]); |
162 | | } |
163 | | } |