Skip to main content

zkboo_hmac/
lib.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2
3//! HMAC (Hash-based Message Authentication Code) primitive for the [zkboo] crate.
4//!
5//! See <https://datatracker.ietf.org/doc/html/rfc2104> for details.
6
7#![no_std]
8extern crate alloc;
9
10use alloc::vec::Vec;
11use zkboo::{
12    backend::{Allocator, Backend, WordRef},
13    word::Word,
14};
15
16/// Computes the HMAC for given key and message,
17/// using the provided hash function and block size.
18pub 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.append(&mut allocator.alloc_vec(&vec![0u8; block_size - key.len()]));
43        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}