seedtool-cli 0.4.0

A command-line tool for generating and transforming cryptographic seeds.
#![allow(dead_code)]

use anyhow::{Result, bail};

pub fn data_to_hex(bytes: &[u8]) -> String { hex::encode(bytes) }

pub fn hex_to_data(hex: &str) -> Result<Vec<u8>> { Ok(hex::decode(hex)?) }

pub fn data_to_base(buf: &[u8], base: usize) -> Vec<u8> {
    buf.iter()
        .map(|b| (((*b as f64) / 255.0) * ((base - 1) as f64)).round() as u8)
        .collect()
}

pub fn data_to_alphabet(
    buf: &[u8],
    base: usize,
    to_alphabet: fn(usize) -> String,
) -> String {
    let data = data_to_base(buf, base);
    data.iter().map(|b| to_alphabet((*b).into())).collect()
}

pub fn parse_ints(input: &str) -> Result<Vec<u8>> {
    let mut result = Vec::new();
    for s in input.split_whitespace() {
        let i = s.parse::<usize>()?;
        if !(0..=255).contains(&i) {
            bail!("Integer out of range. Allowed: [0-255]");
        }
        result.push(i as u8);
    }
    Ok(result)
}

pub fn data_to_ints(
    buf: &[u8],
    low: usize,
    high: usize,
    separator: &str,
) -> Result<String> {
    if !(low < high && high <= 255) {
        bail!("Int conversion range must be in 0 <= low < high <= 255.");
    }
    let base = high - low + 1;
    let data = data_to_base(buf, base);
    let result = data
        .iter()
        .map(|b| (b + (low as u8)).to_string())
        .collect::<Vec<String>>()
        .join(separator);
    Ok(result)
}

pub fn digits_to_data(
    in_str: &str,
    low: usize,
    high: usize,
) -> Result<Vec<u8>> {
    let mut result = Vec::new();
    for c in in_str.chars() {
        let n = (c as i32) - ('0' as i32);
        if n < (low as i32) || n > (high as i32) {
            bail!("Invalid digit.");
        }
        result.push(n as u8);
    }
    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_data_to_hex() {
        let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert_eq!(data_to_hex(&data), "00010203040506070809");
    }

    #[test]
    fn test_hex_to_data() {
        let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert_eq!(hex_to_data("00010203040506070809").unwrap(), data);
    }

    #[test]
    fn test_data_to_base() {
        let data = vec![0, 50, 100, 150, 200, 250, 255];
        let expected = vec![0, 1, 2, 3, 4, 5, 5];
        assert_eq!(data_to_base(&data, 6), expected);
    }

    #[test]
    fn test_data_to_alphabet() {
        let data = vec![0, 50, 100, 150, 200, 250, 255];
        let to_alphabet = |n| (((n as u8) + b'a') as char).to_string();
        assert_eq!(data_to_alphabet(&data, 6, to_alphabet), "abcdeff");
    }

    #[test]
    fn test_data_to_ints() {
        let data = vec![0, 50, 100, 150, 200, 250, 255];
        assert_eq!(data_to_ints(&data, 1, 6, ",").unwrap(), "1,2,3,4,5,6,6");
    }

    #[test]
    fn test_digits_to_data() {
        let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert_eq!(digits_to_data("0123456789", 0, 9).unwrap(), data);
    }
}