fancy_garbling/circuits/
hmac.rs1use crate::{
7 FancyBinary,
8 circuit::Circuit,
9 circuits::{binary::PairwiseXor, sha::Sha256},
10};
11use core::marker::PhantomData;
12use swanky_channel::Channel;
13use swanky_error::Result;
14
15#[derive(Default)]
29pub struct HmacSha256<'a>(PhantomData<&'a ()>);
30
31impl<'a> HmacSha256<'a> {
32 pub fn new() -> Self {
34 Default::default()
35 }
36
37 const IPAD_BYTE: &'static str = "00110110";
39
40 const OPAD_BYTE: &'static str = "01011100";
42}
43
44impl<'a, F: FancyBinary> Circuit<F> for HmacSha256<'a>
45where
46 F::Item: 'a,
47{
48 type Input = (&'a [F::Item; 512], &'a [F::Item]);
50 type Output = [F::Item; 256];
52
53 fn execute(
54 &self,
55 backend: &mut F,
56 inputs: Self::Input,
57 channel: &mut Channel,
58 ) -> Result<Self::Output> {
59 let (key, message) = inputs;
60
61 let zero = backend.constant(0, 2, channel)?;
62 let one = backend.constant(1, 2, channel)?;
63
64 let ipad: Vec<F::Item> = Self::IPAD_BYTE
66 .repeat(64) .chars()
68 .map(|c| if c == '1' { one.clone() } else { zero.clone() })
69 .collect();
70
71 let opad: Vec<F::Item> = Self::OPAD_BYTE
73 .repeat(64)
74 .chars()
75 .map(|c| if c == '1' { one.clone() } else { zero.clone() })
76 .collect();
77
78 let key_vec = key.to_vec();
80 let key_xor_ipad = PairwiseXor::new().execute(backend, (&key_vec, &ipad), channel)?;
81
82 let key_xor_opad = PairwiseXor::new().execute(backend, (&key_vec, &opad), channel)?;
84
85 let mut inner_input = key_xor_ipad;
87 inner_input.extend_from_slice(message);
88 let inner_hash = Sha256::new().execute(backend, inner_input, channel)?;
89
90 let mut outer_input = key_xor_opad;
92 outer_input.extend_from_slice(&inner_hash);
93 let hmac = Sha256::new().execute(backend, outer_input, channel)?;
94
95 Ok(hmac)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::dummy::{Dummy, DummyVal};
103
104 fn string_to_bool_vec(str: &str) -> Vec<DummyVal> {
105 str.chars()
106 .map(|c| match c {
107 '0' => DummyVal::new_bool(false),
108 '1' => DummyVal::new_bool(true),
109 _ => panic!("Unexpected character in boolean string"),
110 })
111 .collect()
112 }
113
114 #[test]
115 fn hmac_sha256_empty_message() {
116 let hmac = HmacSha256::new();
121 let key = [DummyVal::new_bool(false); 512];
122 let message = [];
123
124 let output = Dummy::eval(&hmac, (&key, &message)).unwrap();
125
126 assert_eq!(
129 output
130 .iter()
131 .map(|i| i.val().to_string())
132 .collect::<String>(),
133 "1011011000010011011001111001101000001000000101001101100111101100011101110010111110010101110101110111100011000011010111111100010111111111000101101001011111000100100100110111000101010110010100111100011011000111000100100001010001000010100100101100010110101101"
134 );
135 }
136
137 #[test]
138 fn hmac_sha256_test_message() {
139 let hmac = HmacSha256::new();
144 let key = [DummyVal::new_bool(false); 512];
145
146 let message = string_to_bool_vec("01110100011001010111001101110100");
152
153 let output = Dummy::eval(&hmac, (&key, &message[..])).unwrap();
154
155 assert_eq!(
158 output
159 .iter()
160 .map(|i| i.val().to_string())
161 .collect::<String>(),
162 "0100001110110000110011101111100110010010011001011111100111100011010011000001000011101010100111010011010100000001100100100110110100100111101100111001111101010111110001101101011001110100010101100001110110001011101000100011011011100111101010000001100111111011"
163 );
164 }
165
166 #[test]
167 fn hmac_sha256_with_key() {
168 let hmac = HmacSha256::new();
173
174 let mut key = string_to_bool_vec("011010110110010101111001");
179 key.resize(512, DummyVal::new_bool(false));
181 let key: [DummyVal; 512] = key.try_into().expect("Key should contain 512 elements");
182
183 let message = "The quick brown fox jumps over the lazy dog";
184 let message: Vec<DummyVal> = message
185 .bytes()
186 .flat_map(|b| {
187 (0..8)
188 .rev()
189 .map(move |i| DummyVal::new_bool((b >> i) & 1 == 1))
190 })
191 .collect();
192
193 let output = Dummy::eval(&hmac, (&key, &message[..])).unwrap();
194
195 assert_eq!(
198 output
199 .iter()
200 .map(|i| i.val().to_string())
201 .collect::<String>(),
202 "1111011110111100100000111111010000110000010100111000010000100100101100010011001010011000111001101010101001101111101100010100001111101111010011010101100110100001010010010100011000010111010110011001011101000111100111011011110000101101000110100011110011011000"
203 );
204 }
205}