hashr 0.0.3

small library that aims to provide several hashing and related algorithms
Documentation
use crate::hash::HashFn;
use crate::hotp;
use crate::sha1::SHA1;

fn number_of_time_steps(t0: u64, current: u64, x: u64) -> u64 {
    (current - t0) / x
}

pub fn totp<const B: usize, const L: usize, H: HashFn<B, L>, F: Fn() -> H>(
    hash_new_fn: F,
    unix_time: u64,
    t0: u64,
    x: u64,
    digits: u32,
    key: &[u8],
) -> u32 {
    hotp::hotp(
        hash_new_fn,
        key,
        number_of_time_steps(t0, unix_time, x),
        digits,
    )
}

pub fn totp_default(unix_time: u64, key: &[u8]) -> u32 {
    totp(SHA1::new, unix_time, 0, 30, 6, key)
}

#[cfg(test)]
mod tests {
    use crate::{
        sha1::SHA1,
        totp::{number_of_time_steps, totp},
    };

    #[test]
    fn test_totp_rfc_vectors() {
        struct TestCase {
            time: u64,
            expected_t: u64,
            expected_totp_sha1: u32,
        }
        let test_cases = [
            TestCase {
                time: 59,
                expected_t: 0x0000000000000001,
                expected_totp_sha1: 94287082,
            },
            TestCase {
                time: 1111111109,
                expected_t: 0x00000000023523EC,
                expected_totp_sha1: 07081804,
            },
            TestCase {
                time: 1111111111,
                expected_t: 0x00000000023523ED,
                expected_totp_sha1: 14050471,
            },
            TestCase {
                time: 1234567890,
                expected_t: 0x000000000273EF07,
                expected_totp_sha1: 89005924,
            },
            TestCase {
                time: 2000000000,
                expected_t: 0x0000000003F940AA,
                expected_totp_sha1: 69279037,
            },
            TestCase {
                time: 20000000000,
                expected_t: 0x0000000027BC86AA,
                expected_totp_sha1: 65353130,
            },
        ];

        let secret = "12345678901234567890".as_bytes();

        for test_case in test_cases {
            assert!(number_of_time_steps(0, test_case.time, 30) == test_case.expected_t);
            assert!(
                totp(SHA1::new, test_case.time, 0, 30, 8, secret) == test_case.expected_totp_sha1
            )
        }
    }
}