mpc_engine/primitives/
mac.rs1use hacspec_lib::Randomness;
4use hmac::hkdf_extract;
5
6use crate::COMPUTATIONAL_SECURITY;
7
8pub const MAC_LENGTH: usize = COMPUTATIONAL_SECURITY;
10
11pub type Mac = [u8; MAC_LENGTH];
13pub type MacKey = [u8; MAC_LENGTH];
15
16pub 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
25pub 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
34pub 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
44pub 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
56pub 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}