1#![no_std]
8extern crate alloc;
9
10use alloc::vec::Vec;
11use zkboo::{
12 backend::{Allocator, Backend, WordRef},
13 word::Word,
14};
15
16pub fn hmac<
19 B: Backend,
20 W: Word,
21 const M: usize,
22 H: FnMut(Allocator<B>, Vec<WordRef<B, u8>>) -> [WordRef<B, W>; M],
23>(
24 allocator: Allocator<B>,
25 mut key: Vec<WordRef<B, u8>>,
26 mut msg: Vec<WordRef<B, u8>>,
27 mut hash_fn: H,
28 block_size: usize,
29) -> [WordRef<B, W>; M] {
30 assert!(
31 block_size * 8 >= M * W::WIDTH as usize,
32 "blocksize must be at least output size"
33 );
34 if key.len() > block_size {
35 let digest = hash_fn(allocator.clone(), key);
36 key = digest
37 .into_iter()
38 .flat_map(WordRef::<B, W>::into_be_bytes)
39 .collect();
40 }
41 if key.len() < block_size {
42 key.extend((0..block_size - key.len()).map(|_| allocator.alloc(0u8)));
44 }
45 let mut inner: Vec<WordRef<B, u8>> = key.iter().map(|w| w.clone() ^ 0x36).collect();
46 let mut outer: Vec<WordRef<B, u8>> = key.into_iter().map(|w| w ^ 0x5c).collect();
47 inner.append(&mut msg);
48 let mut inner_digest: Vec<WordRef<B, u8>> = hash_fn(allocator.clone(), inner)
49 .into_iter()
50 .flat_map(WordRef::<B, W>::into_be_bytes)
51 .collect();
52 outer.append(&mut inner_digest);
53 return hash_fn(allocator, outer);
54}