bitbottle 0.9.1

a modern archive file format
Documentation

use blake2::Blake2s;
use cipher::consts::U32;
use cipher::generic_array::GenericArray;
use num_enum::TryFromPrimitive;
use sha2::{Digest, Sha256};

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum HashType {
    SHA256 = 0,
    BLAKE2 = 1,
    BLAKE3 = 2,
}

/// Pick your poison for secure hashing. The blake3 variant stores like 2KB
/// on the stack, but it's only created by the file scanner, which would need
/// to create it anyway.
#[allow(clippy::large_enum_variant)]
pub enum Hashing {
    Sha256(Sha256),
    Blake2(Blake2s),
    Blake3(blake3::Hasher),
}


pub type HashingOutput = GenericArray<u8, U32>;

impl Hashing {
    pub fn new(hash_type: HashType) -> Hashing {
        match hash_type {
            HashType::SHA256 => Hashing::Sha256(Sha256::new()),
            HashType::BLAKE2 => Hashing::Blake2(Blake2s::new()),
            HashType::BLAKE3 => Hashing::Blake3(blake3::Hasher::new()),
        }
    }

    pub fn update(&mut self, data: &[u8]) {
        match self {
            Hashing::Sha256(h) => { h.update(data); },
            Hashing::Blake2(h) => { h.update(data); },
            Hashing::Blake3(h) => { h.update(data); },
        }
    }

    pub fn finalize_reset(&mut self) -> HashingOutput {
        match self {
            Hashing::Sha256(h) => h.finalize_reset(),
            Hashing::Blake2(h) => h.finalize_reset(),
            Hashing::Blake3(h) => {
                let hash = h.finalize();
                h.reset();
                *HashingOutput::from_slice(hash.as_bytes())
            },
        }
    }
}