finish PSZ payloads
@@ -19,7 +19,7 @@ use rand::seq::SliceRandom;
use rand::{CryptoRng, Rng, RngCore};
use scuttlebutt::{cointoss, AbstractChannel, Block, Block512, SemiHonest};
use sha2::Sha256;
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
const NHASHES: usize = 3;
@@ -184,7 +184,43 @@ impl Receiver {
> {
let payload_len = channel.read_usize()?;
let (tbl, outputs) = self.perform_oprfs(channel, inputs, rng)?;
- unimplemented!()
+ let n = inputs.len();
+ let masksize = compute_masksize(n)?;
+
+ // Receive all the sets from the sender. These come in paired with H(F(x)), which
+ // allows tree searching without learning the Sender's F(x) values (which are used
+ // to encrypt the payloads).
+ let mut hs = vec![HashMap::with_capacity(n); NHASHES];
+ for h in hs.iter_mut() {
+ for _ in 0..n {
+ let mut tag = [0_u8; 32];
+ let mut iv = [0_u8; 16];
+ channel.read_bytes(&mut tag)?;
+ channel.read_bytes(&mut iv)?;
+ let ct = channel.read_vec(payload_len)?;
+ h.insert(tag, (iv, ct));
+ }
+ }
+
+ // Iterate through each input/output pair and see whether it exists in
+ // the appropriate set.
+ let mut intersection = Vec::with_capacity(n);
+
+ for (opt_item, output) in tbl.items.iter().zip(outputs.into_iter()) {
+ if let Some(item) = opt_item {
+ // compute tag = H(F(x))
+ let tag: [u8;32] = Sha256::digest(output.prefix(masksize)).into();
+
+ // if the tag is present, decrypt the payload using F(x).
+ if let Some((iv, ct)) = hs[item.hash_index].get(&tag) {
+ let val = inputs[item.input_index].clone();
+ let payload = openssl::symm::decrypt(openssl::symm::Cipher::aes_128_ctr(), output.prefix(16), Some(iv), ct)?;
+ intersection.push((val, payload));
+ }
+ }
+ }
+
+ Ok(intersection)
}
// Helper to do computation common to both receive and receive_payloads
