mpc_engine/primitives/
mac.rs

1//! This module defines an information theoretic MAC for authenticating bits.
2
3use hacspec_lib::Randomness;
4use hmac::hkdf_extract;
5
6use crate::COMPUTATIONAL_SECURITY;
7
8/// The length in bytes of an information theoretic MAC, and of the MAC key.
9pub const MAC_LENGTH: usize = COMPUTATIONAL_SECURITY;
10
11/// A MAC on a bit.
12pub type Mac = [u8; MAC_LENGTH];
13/// A MAC key for authenticating a bit to another party.
14pub type MacKey = [u8; MAC_LENGTH];
15
16/// Hash the given input to the width of a MAC.
17///
18/// Instantiates a Random Oracle.
19pub fn hash_to_mac_width(dst: &[u8], input: &[u8]) -> [u8; 16] {
20    let mut hash = hkdf_extract(dst, input);
21    hash.truncate(16);
22    hash.try_into().unwrap()
23}
24
25/// XOR of two MAC-width byte arrays.
26pub fn xor_mac_width(left: &Mac, right: &Mac) -> Mac {
27    let mut result = [0u8; MAC_LENGTH];
28    for (index, byte) in result.iter_mut().enumerate() {
29        *byte = left[index] ^ right[index];
30    }
31    result
32}
33
34/// Generate a fresh MAC key.
35pub fn generate_mac_key(entropy: &mut Randomness) -> MacKey {
36    let k: [u8; MAC_LENGTH] = entropy
37        .bytes(MAC_LENGTH)
38        .expect("sufficient randomness should have been provided externally")
39        .try_into()
40        .expect("should have received the required number of bytes, because we requested them");
41    k
42}
43
44/// Authenticate a bit using the global MAC key.
45pub fn mac(bit: &bool, global_key: &MacKey, entropy: &mut Randomness) -> (Mac, MacKey) {
46    let key: [u8; MAC_LENGTH] = generate_mac_key(entropy);
47
48    let mut mac = [0u8; MAC_LENGTH];
49    for idx in 0..mac.len() {
50        mac[idx] = key[idx] ^ ((*bit as u8) * global_key[idx]);
51    }
52
53    (mac, key)
54}
55
56/// Verify a MAC on a given bit.
57pub fn verify_mac(bit: &bool, mac: &Mac, key: &MacKey, global_key: &MacKey) -> bool {
58    for idx in 0..mac.len() {
59        let recomputed = key[idx] ^ ((*bit as u8) * global_key[idx]);
60        if mac[idx] != recomputed {
61            return false;
62        }
63    }
64    true
65}
66
67#[test]
68fn simple() {
69    use rand::thread_rng;
70    use rand::RngCore;
71    let mut rng = thread_rng();
72    let mut random = vec![0; 2 * COMPUTATIONAL_SECURITY + 1];
73    rng.fill_bytes(&mut random);
74    let mut entropy = Randomness::new(random);
75
76    let b = entropy.bit().unwrap();
77    let delta = generate_mac_key(&mut entropy);
78    let (mac, key) = mac(&b, &delta, &mut entropy);
79    debug_assert!(verify_mac(&b, &mac, &key, &delta));
80    debug_assert!(!verify_mac(&!b, &mac, &key, &delta))
81}