rsbx 2.0.0

Enhanced implementation of SeqBox in Rust
Documentation
#![allow(dead_code)]

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum HashType {
    SHA1,
    SHA2_256,     SHA256,
    SHA2_512_256,
    SHA2_512_512, SHA512,
    BLAKE2B_256,
    BLAKE2B_512,
    BLAKE2S_128,
    BLAKE2S_256
}

pub type HashBytes = (HashType, Box<[u8]>);

pub fn hash_type_to_string(hash_type : HashType) -> String {
    use self::HashType::*;

    match hash_type {
        SHA1                  => String::from("SHA1"),
        SHA2_256     | SHA256 => String::from("SHA256"),
        SHA2_512_256          => String::from("SHA2-512-256"),
        SHA2_512_512 | SHA512 => String::from("SHA512"),
        BLAKE2B_256           => String::from("BLAKE2B-256"),
        BLAKE2B_512           => String::from("BLAKE2B-512"),
        BLAKE2S_128           => String::from("BLAKE2S-128"),
        BLAKE2S_256           => String::from("BLAKE2S-256"),
    }
}

pub fn string_to_hash_type(string : &str) -> Result<HashType, ()> {
    let string = string.to_lowercase();

    use self::HashType::*;

    match string.as_str() {
        "sha1"                    => Ok(SHA1),
        "sha2-256"     | "sha256" => Ok(SHA256),
        "sha2-512-256"            => Ok(SHA2_512_256),
        "sha2-512-512" | "sha512" => Ok(SHA512),
        "blake2b-256"             => Ok(BLAKE2B_256),
        "blake2b-512"             => Ok(BLAKE2B_512),
        "blake2s-128"             => Ok(BLAKE2S_128),
        "blake2s-256"             => Ok(BLAKE2S_256),
        _                         => Err(())
    }
}

pub fn hash_bytes_to_bytes(hash_bytes : &HashBytes, buffer : &mut [u8]) {
    let param        = specs::Param::new(hash_bytes.0);
    let digest_bytes = &hash_bytes.1;
    for i in 0..param.hash_func_type.len() {
        buffer[i] = param.hash_func_type[i];
    }

    buffer[param.hash_func_type.len()] = param.digest_length;

    let offset = param.hash_func_type.len() + 1;

    for i in 0..param.digest_length as usize {
        buffer[i + offset] = digest_bytes[i];
    }
}

pub fn hash_bytes_into_bytes(hash_bytes : &HashBytes) -> Box<[u8]> {
    let param      = specs::Param::new(hash_bytes.0);
    let mut buffer = vec![0; param.total_length()].into_boxed_slice();

    hash_bytes_to_bytes(hash_bytes, &mut buffer);
    buffer
}

pub mod specs {
    use super::*;

    #[derive(Copy, Clone, Debug)]
    pub struct Param {
        pub hash_func_type : &'static [u8],
        pub digest_length  : u8,
    }

    macro_rules! param {
        (
            $func_type:ident; $len:expr
        ) => {
            Param { hash_func_type : &$func_type,
                    digest_length  : $len }
        }
    }

    static SHA1_HFT        : [u8; 1] = [0x11      ];
    static SHA256_HFT      : [u8; 1] = [0x12      ];
    static SHA512_HFT      : [u8; 1] = [0x13      ];
    static BLAKE2B_256_HFT : [u8; 2] = [0xb2, 0x20];
    static BLAKE2B_512_HFT : [u8; 2] = [0xb2, 0x40];
    static BLAKE2S_128_HFT : [u8; 2] = [0xb2, 0x50];
    static BLAKE2S_256_HFT : [u8; 2] = [0xb2, 0x60];

    pub static SHA1_PARAM         : Param = param!(SHA1_HFT;        0x14);
    pub static SHA256_PARAM       : Param = param!(SHA256_HFT;      0x20);
    pub static SHA2_512_256_PARAM : Param = param!(SHA512_HFT;      0x20);
    pub static SHA512_PARAM       : Param = param!(SHA512_HFT;      0x40);
    pub static BLAKE2B_256_PARAM  : Param = param!(BLAKE2B_256_HFT; 0x20);
    pub static BLAKE2B_512_PARAM  : Param = param!(BLAKE2B_512_HFT; 0x40);
    pub static BLAKE2S_128_PARAM  : Param = param!(BLAKE2S_128_HFT; 0x10);
    pub static BLAKE2S_256_PARAM  : Param = param!(BLAKE2S_256_HFT; 0x20);

    impl Param {
        pub fn new(hash_type : HashType) -> Param {
            use super::HashType::*;
            match hash_type {
                SHA1                  => SHA1_PARAM,
                SHA2_256     | SHA256 => SHA256_PARAM,
                SHA2_512_256          => SHA2_512_256_PARAM,
                SHA2_512_512 | SHA512 => SHA512_PARAM,
                BLAKE2B_256           => BLAKE2B_256_PARAM,
                BLAKE2B_512           => BLAKE2B_512_PARAM,
                BLAKE2S_128           => BLAKE2S_128_PARAM,
                BLAKE2S_256           => BLAKE2S_256_PARAM,
            }
        }

        pub fn total_length(&self) -> usize {
            self.hash_func_type.len() + 1 + self.digest_length as usize
        }
    }
}

pub mod hash {
    use sha1::Digest;
    use blake2_c::blake2b;

    use super::*;

    pub struct Ctx {
        ctx : _Ctx
    }

    #[allow(non_camel_case_types)]
    enum _Ctx {
        SHA1(sha1::Sha1),
        SHA256(sha2::Sha256),
        SHA512(sha2::Sha512),
        BLAKE2B_256(blake2b::State),
        BLAKE2B_512(blake2b::State)
    }

    pub fn hash_type_is_supported(hash_type : HashType) -> bool {
        match Ctx::new(hash_type) {
            Ok(_)  => true,
            Err(_) => false
        }
    }

    impl Ctx {
        pub fn new(hash_type : HashType) -> Result<Ctx, ()> {
            let ctx = match hash_type {
                HashType::SHA1                            =>
                    Some(_Ctx::SHA1(
                        sha1::Sha1::new())),
                HashType::SHA2_256     | HashType::SHA256 =>
                    Some(_Ctx::SHA256(
                        sha2::Sha256::new())),
                HashType::SHA2_512_256                    => None,
                HashType::SHA2_512_512 | HashType::SHA512 =>
                    Some(_Ctx::SHA512(
                        sha2::Sha512::new())),
                HashType::BLAKE2B_256                     =>
                    Some(_Ctx::BLAKE2B_256(
                        blake2b::State::new(specs::Param::new(hash_type).digest_length as usize))),
                HashType::BLAKE2B_512                     =>
                    Some(_Ctx::BLAKE2B_512(
                        blake2b::State::new(specs::Param::new(hash_type).digest_length as usize))),
                HashType::BLAKE2S_128                     => None,
                HashType::BLAKE2S_256                     => None,
            };
            match ctx {
                Some(ctx) => Ok(Ctx { ctx }),
                None      => Err(())
            }
        }

        pub fn hash_type(&self) -> HashType {
            match self.ctx {
                _Ctx::SHA1(_)        => HashType::SHA1,
                _Ctx::SHA256(_)      => HashType::SHA256,
                _Ctx::SHA512(_)      => HashType::SHA512,
                _Ctx::BLAKE2B_256(_) => HashType::BLAKE2B_256,
                _Ctx::BLAKE2B_512(_) => HashType::BLAKE2B_512
            }
        }

        pub fn update(&mut self, data : &[u8]) {
            match self.ctx {
                _Ctx::SHA1(ref mut ctx)        =>
                    ctx.input(data),
                _Ctx::SHA256(ref mut ctx)      =>
                    ctx.input(data),
                _Ctx::SHA512(ref mut ctx)      =>
                    ctx.input(data),
                _Ctx::BLAKE2B_256(ref mut ctx) => {
                    ctx.update(data); },
                _Ctx::BLAKE2B_512(ref mut ctx) => {
                    ctx.update(data); },
            }
        }

        pub fn finish_to_bytes(self, hashval : &mut [u8]) {
            match self.ctx {
                _Ctx::SHA1(ctx)            =>
                    hashval.copy_from_slice(ctx.result().as_ref()),
                _Ctx::SHA256(ctx)          =>
                    hashval.copy_from_slice(ctx.result().as_ref()),
                _Ctx::SHA512(ctx)          =>
                    hashval.copy_from_slice(ctx.result().as_ref()),
                _Ctx::BLAKE2B_256(mut ctx) =>
                    hashval.copy_from_slice(ctx.finalize().bytes.as_slice()),
                _Ctx::BLAKE2B_512(mut ctx) =>
                    hashval.copy_from_slice(ctx.finalize().bytes.as_slice()),
            }
        }

        pub fn finish_into_bytes(self) -> Box<[u8]> {
            let hash_type   = self.hash_type();
            let param       = specs::Param::new(hash_type);
            let digest_len  = param.digest_length;
            let mut hashval =
                vec![0; digest_len as usize]
                .into_boxed_slice();
            self.finish_to_bytes(&mut hashval);
            hashval
        }

        pub fn finish_to_hash_bytes(self, hash_bytes : &mut HashBytes) {
            hash_bytes.0  = self.hash_type();
            self.finish_to_bytes(&mut hash_bytes.1);
        }

        pub fn finish_into_hash_bytes(self) -> HashBytes {
            (self.hash_type(), self.finish_into_bytes())
        }
    }
}

pub mod parsers {
    use super::specs;
    use super::{HashBytes, HashType};
    use super::super::misc_utils;

    macro_rules! make_hash_parser_w_len {
        (
            $name:ident, $ht:path, $param:path
        ) => {
            named!($name <HashBytes>,
                   do_parse!(
                       _total_len : tag!(&[$param.total_length() as u8]) >>
                       _id : tag!($param.hash_func_type) >>
                           _n : tag!(&[$param.digest_length]) >>
                           res : take!($param.digest_length) >>
                           (($ht, misc_utils::slice_to_boxed(res)))
                   )
            );
        }
    }

    make_hash_parser_w_len!(sha1_w_len_p,
                            HashType::SHA1,         specs::SHA1_PARAM);
    make_hash_parser_w_len!(sha256_w_len_p,
                            HashType::SHA256,       specs::SHA256_PARAM);
    make_hash_parser_w_len!(sha2_512_256_w_len_p,
                            HashType::SHA2_512_256, specs::SHA2_512_256_PARAM);
    make_hash_parser_w_len!(sha512_w_len_p,
                            HashType::SHA512,       specs::SHA512_PARAM);
    make_hash_parser_w_len!(blake2b_256_w_len_p,
                            HashType::BLAKE2B_256,  specs::BLAKE2B_256_PARAM);
    make_hash_parser_w_len!(blake2b_512_w_len_p,
                            HashType::BLAKE2B_512,  specs::BLAKE2B_512_PARAM);
    make_hash_parser_w_len!(blake2s_128_w_len_p,
                            HashType::BLAKE2S_128,  specs::BLAKE2S_128_PARAM);
    make_hash_parser_w_len!(blake2s_256_w_len_p,
                            HashType::BLAKE2S_256,  specs::BLAKE2S_256_PARAM);

    named!(pub multihash_w_len_p <HashBytes>,
           alt_complete!(sha1_w_len_p         |
                         sha256_w_len_p       |
                         sha2_512_256_w_len_p |
                         sha512_w_len_p       |
                         blake2b_256_w_len_p  |
                         blake2b_512_w_len_p  |
                         blake2s_128_w_len_p  |
                         blake2s_256_w_len_p
           )
    );
}