1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
// Milestone 1, as far as it currently reaches.
//
// `Error`, `decoded_len` and `decode_nibble` are base16ct 1.0.0 verbatim.
// `decode_into` is NOT: base16ct writes that loop as
// for (src, dst) in src.chunks_exact(2).zip(dst.iter_mut())
// and `chunks_exact`/`zip`/`iter_mut` are not implemented yet, so the loop is
// rewritten with indexing. The arithmetic under test -- the constant-time
// nibble decode, its i16 wrapping and arithmetic shift, and the `err` accumulator
// -- is unchanged, and that is the part the other transpiler could not represent.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum Error {
InvalidEncoding,
InvalidLength,
}
pub type Result<T> = core::result::Result<T, Error>;
pub fn decoded_len(bytes: &[u8]) -> Result<usize> {
if bytes.len() & 1 == 0 {
Ok(bytes.len() / 2)
} else {
Err(Error::InvalidLength)
}
}
fn decode_nibble(src: u8) -> u16 {
let byte = src as i16;
let mut ret: i16 = -1;
ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47);
ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54);
ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86);
ret as u16
}
fn decode_into(src: &[u8], dst: &mut [u8]) -> Result<usize> {
let n: usize = decoded_len(src)?;
if dst.len() < n {
return Err(Error::InvalidLength);
}
let mut err: u16 = 0;
let mut i: usize = 0;
while i < n {
let byte = (decode_nibble(src[i * 2]) << 4) | decode_nibble(src[i * 2 + 1]);
err |= byte >> 8;
dst[i] = byte as u8;
i += 1;
}
match err {
0 => Ok(n),
_ => Err(Error::InvalidEncoding),
}
}
fn show(hex: &[u8]) {
let mut buf: Vec<u8> = vec![0u8; 16];
match decode_into(hex, &mut buf) {
Ok(n) => {
let mut i: usize = 0;
while i < n {
print!("{:02x}", buf[i]);
i += 1;
}
println!(" ({} bytes)", n);
}
Err(e) => println!("error {:?}", e),
}
}
fn main() {
show(b"abcd1234");
show(b"ABCD1234");
show(b"abCD1234");
show(b"00ff7f80");
show(b"abc");
show(b"zzzz");
show(b"");
let mut c: u8 = 0;
while c < 128 {
print!("{} ", decode_nibble(c));
c += 1;
}
println!("");
}
|