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