1use crate::{Otp, OtpResult, ToBytes};
2
3pub type Hotp = Otp<Counter>;
8
9impl Hotp {
10 pub fn new(key: String, initial_count: u64, length: u32) -> Self {
13 Otp {
14 key,
15 generator: Counter {
16 count: initial_count,
17 },
18 digits: length,
19 }
20 }
21}
22
23pub struct Counter {
26 count: u64,
27}
28
29impl ToBytes for Counter {
30 fn to_bytes(&mut self) -> OtpResult<[u8; 8]> {
31 let c = self.count;
32 self.count += 1;
33 Ok(c.to_be_bytes().into())
34 }
35}
36
37#[cfg(test)]
38mod test {
39 use test_case::test_case;
40
41 use crate::hotp::Hotp;
42
43 #[test_case(0, 755224)]
46 #[test_case(1, 287082)]
47 #[test_case(2, 359152)]
48 #[test_case(3, 969429)]
49 #[test_case(4, 338314)]
50 #[test_case(5, 254676)]
51 #[test_case(6, 287922)]
52 #[test_case(7, 162583)]
53 #[test_case(8, 399871)]
54 #[test_case(9, 520489)]
55 fn it_computes_correct_hotp(counter: u64, expected: u32) {
56 let key = "12345678901234567890".to_string();
57 let digits = 6;
58 let mut hotp = Hotp::new(key, counter, digits);
59 let actual = hotp.get().unwrap();
60 assert_eq!(actual, expected);
61 }
62
63 #[test]
64 fn it_increments_the_counter() {
65 let cases = vec![
66 755224, 287082, 359152, 969429, 338314, 254676, 287922, 162583, 399871, 520489,
67 ];
68 let key = "12345678901234567890".to_string();
69 let digits = 6;
70 let counter = 0;
71 let mut htop = Hotp::new(key, counter, digits);
72 for case in cases {
73 let actual = htop.get().unwrap();
74 assert_eq!(actual, case);
75 }
76 }
77}