1#![warn(missing_docs)]
2use elgamal::Ciphertext;
20use hacspec_lib::{hacspec_helper::NatMod, Randomness};
21
22use super::coprf_setup::{BlindingPublicKey, CoPRFKey};
23use crate::{coprf::coprf_setup::CoPRFReceiverContext, p256_sha256, Error};
24use p256::P256Point;
25
26pub type Input<'a> = &'a [u8];
28pub type Output = P256Point;
31
32pub type BlindInput = Ciphertext;
35pub type BlindOutput = Ciphertext;
39
40pub fn blind(
45 bpk: BlindingPublicKey,
46 input: Input,
47 context_string: Vec<u8>,
48 randomness: &mut Randomness,
49) -> Result<BlindInput, Error> {
50 let inputElement = p256_sha256::hash_to_group(input, &context_string)?;
51
52 if inputElement == p256_sha256::identity() {
53 return Err(Error::InvalidInputError);
54 }
55
56 let blindInput = elgamal::encrypt(bpk, inputElement, randomness)?;
57
58 Ok(blindInput)
59}
60
61pub fn blind_evaluate(
66 key: CoPRFKey,
67 bpk: BlindingPublicKey,
68 blind_input: BlindInput,
69 randomness: &mut Randomness,
70) -> Result<BlindOutput, Error> {
71 let input_rerandomized = elgamal::rerandomize(bpk, blind_input, randomness)?;
72 elgamal::scalar_mul_ciphertext(key, input_rerandomized).map_err(|e| e.into())
73}
74
75pub fn finalize(
78 context: &CoPRFReceiverContext,
79 blind_output: BlindOutput,
80) -> Result<Output, Error> {
81 elgamal::decrypt(context.bsk, blind_output).map_err(|e| e.into())
82}
83
84pub fn prepare_blind_convert(
87 bpk: BlindingPublicKey,
88 y: Output,
89 randomness: &mut Randomness,
90) -> Result<BlindInput, Error> {
91 elgamal::encrypt(bpk, y, randomness).map_err(|e| e.into())
92}
93
94pub fn blind_convert(
99 bpk: BlindingPublicKey,
100 key_from: CoPRFKey,
101 key_to: CoPRFKey,
102 blind_input: BlindInput,
103 randomness: &mut Randomness,
104) -> Result<BlindOutput, Error> {
105 let delta = key_to * key_from.inv();
106 let ctx_rerandomized = elgamal::rerandomize(bpk, blind_input, randomness)?;
107 elgamal::scalar_mul_ciphertext(delta, ctx_rerandomized).map_err(|e| e.into())
108}
109
110#[cfg(test)]
111mod tests {
112 use crate::coprf::coprf_setup::{derive_key, CoPRFEvaluatorContext};
113
114 use super::*;
115
116 pub fn evaluate(context_string: &[u8], key: CoPRFKey, input: Input) -> Result<Output, Error> {
132 let inputElement = p256_sha256::hash_to_group(input, context_string)?;
133
134 if inputElement == P256Point::AtInfinity {
135 return Err(Error::InvalidInputError);
136 }
137
138 let evaluatedElement = p256::p256_point_mul(key, inputElement)?;
139
140 Ok(evaluatedElement)
141 }
142
143 pub fn convert(
157 key_origin: CoPRFKey,
158 key_destination: CoPRFKey,
159 y: Output,
160 ) -> Result<Output, Error> {
161 let delta = key_destination * key_origin.inv();
162 let result = p256::p256_point_mul(delta, y)?;
163
164 Ok(result)
165 }
166
167 fn generate_randomness() -> Randomness {
168 use rand::prelude::*;
169
170 let mut rng = rand::thread_rng();
171 let mut randomness = [0u8; 1000000];
172 rng.fill_bytes(&mut randomness);
173 let randomness = Randomness::new(randomness.to_vec());
174
175 randomness
176 }
177
178 #[test]
179 fn self_test_eval_convert() {
180 let mut randomness = generate_randomness();
181
182 let test_context = b"Test";
183 let test_input = b"TestInput";
184 let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
185
186 let key_origin1 = derive_key(&evaluator_context, b"1").unwrap();
187 let key_origin2 = derive_key(&evaluator_context, b"2").unwrap();
188 let key_destination = derive_key(&evaluator_context, b"3").unwrap();
189
190 let y_under_origin1 = evaluate(test_context, key_origin1, test_input).unwrap();
191 let y_under_origin2 = evaluate(test_context, key_origin2, test_input).unwrap();
192
193 let y_under_destination = evaluate(test_context, key_destination, test_input).unwrap();
194 let converted_y_from_1 = convert(key_origin1, key_destination, y_under_origin1).unwrap();
195 let converted_y_from_2 = convert(key_origin2, key_destination, y_under_origin2).unwrap();
196
197 debug_assert_eq!(converted_y_from_1, converted_y_from_2);
198 debug_assert_eq!(converted_y_from_1, y_under_destination);
199 }
200
201 #[test]
202 fn test_blind_evaluate() {
203 let mut randomness = generate_randomness();
204
205 let test_context = b"Test";
206 let test_input = b"TestInput";
207 let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
208 let receiver_context = CoPRFReceiverContext::new(&mut randomness);
209
210 let blind_input = blind(
211 receiver_context.get_bpk(),
212 test_input,
213 test_context.to_vec(),
214 &mut randomness,
215 )
216 .unwrap();
217
218 let evaluation_key = derive_key(&evaluator_context, b"TestKey").unwrap();
219 let blind_result = blind_evaluate(
220 evaluation_key,
221 receiver_context.get_bpk(),
222 blind_input,
223 &mut randomness,
224 )
225 .unwrap();
226
227 let unblinded_result = finalize(&receiver_context, blind_result).unwrap();
228
229 let expected_result = evaluate(test_context, evaluation_key, test_input).unwrap();
230
231 debug_assert_eq!(unblinded_result, expected_result);
232 }
233
234 #[test]
235 fn blind_convergence() {
236 let mut randomness = generate_randomness();
237
238 let test_context = b"Test";
239 let test_input = b"TestInput";
240 let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
241 let receiver_context = CoPRFReceiverContext::new(&mut randomness);
242
243 let key_origin1 = derive_key(&evaluator_context, b"1").unwrap();
244 let key_origin2 = derive_key(&evaluator_context, b"2").unwrap();
245 let key_destination = derive_key(&evaluator_context, b"3").unwrap();
246
247 let y_under_destination = evaluate(test_context, key_destination, test_input).unwrap();
248 let y1 = evaluate(test_context, key_origin1, test_input).unwrap();
249 let y2 = evaluate(test_context, key_origin2, test_input).unwrap();
250
251 let blind1 =
252 prepare_blind_convert(receiver_context.get_bpk(), y1, &mut randomness).unwrap();
253 let blind2 =
254 prepare_blind_convert(receiver_context.get_bpk(), y2, &mut randomness).unwrap();
255
256 let blind_result_1 = blind_convert(
257 receiver_context.get_bpk(),
258 key_origin1,
259 key_destination,
260 blind1,
261 &mut randomness,
262 )
263 .unwrap();
264
265 let blind_result_2 = blind_convert(
266 receiver_context.get_bpk(),
267 key_origin2,
268 key_destination,
269 blind2,
270 &mut randomness,
271 )
272 .unwrap();
273
274 let res1 = finalize(&receiver_context, blind_result_1).unwrap();
275 let res2 = finalize(&receiver_context, blind_result_2).unwrap();
276
277 debug_assert_eq!(res1, res2);
278 debug_assert_eq!(res1, y_under_destination);
279 }
280 #[test]
281 fn test_blind_conversion() {
282 let mut randomness = generate_randomness();
283
284 let test_context = b"Test";
285 let test_input = b"TestInput";
286 let evaluator_context = CoPRFEvaluatorContext::new(&mut randomness).unwrap();
287 let receiver_context = CoPRFReceiverContext::new(&mut randomness);
288
289 let blind_input = blind(
290 receiver_context.get_bpk(),
291 test_input,
292 test_context.to_vec(),
293 &mut randomness,
294 )
295 .unwrap();
296
297 let key_eval = derive_key(&evaluator_context, b"TestKey").unwrap();
298 let key_destination = derive_key(&evaluator_context, b"DestinationKey").unwrap();
299
300 let blind_result = blind_evaluate(
301 key_eval,
302 receiver_context.get_bpk(),
303 blind_input,
304 &mut randomness,
305 )
306 .unwrap();
307
308 let expected_result = evaluate(test_context, key_destination, test_input).unwrap();
309
310 let blind_converted_result = blind_convert(
312 receiver_context.get_bpk(),
313 key_eval,
314 key_destination,
315 blind_result,
316 &mut randomness,
317 )
318 .unwrap();
319
320 let unblinded_converted_result =
321 finalize(&receiver_context, blind_converted_result).unwrap();
322 debug_assert_eq!(expected_result, unblinded_converted_result);
323
324 let unblinded_intermediate_result = finalize(&receiver_context, blind_result).unwrap();
326
327 let prepped_input = prepare_blind_convert(
328 receiver_context.get_bpk(),
329 unblinded_intermediate_result,
330 &mut randomness,
331 )
332 .unwrap();
333
334 let blind_converted_result = blind_convert(
335 receiver_context.get_bpk(),
336 key_eval,
337 key_destination,
338 prepped_input,
339 &mut randomness,
340 )
341 .unwrap();
342
343 let unblinded_converted_result =
344 finalize(&receiver_context, blind_converted_result).unwrap();
345 debug_assert_eq!(expected_result, unblinded_converted_result);
346 }
347}