in protocol/src/suid_create/merger.rs [288:397]
fn calculate_suids(&self) -> Result<(), ProtocolError> {
match (
self.sharer_pub_key_reuse.clone().read(),
self.from_shuffler.clone().read(),
self.to_shuffler.clone().write(),
) {
(Ok(sharer_pub_key_reuse), Ok(from_s), Ok(mut to_s)) => {
// Decrypt and unflatten keys
let keys = {
// El Gamal decrypt
let m = elgamal_decrypt(
self.ec_cipher.to_points(&from_s.0),
self.ec_cipher.to_points(&from_s.1),
self.keypair_m.0,
);
unflatten_vec(&m, &from_s.2)
};
// Generate sets to find SUID
let mut s_map = HashMap::<Vec<u8>, Vec<usize>>::new();
// We map every entry in keys to a hash table. Each entry is
// a vector. We hash each entry in this vector to a hash
// table entry. The value is the index of this entry. In
// case of a collision we add the index. Thus we end up with
// a hashmap of vectors of indices.
// In subsequent steps we will use the Union Find algorithm
// to merge intersecting sets
for (i, e_o) in keys.iter().enumerate() {
for e_i in e_o.iter() {
let x = e_i.compress().to_bytes().to_vec();
let v = s_map.entry(x).or_insert_with(Vec::<usize>::new);
v.push(i);
}
}
// Merge sets created above with union find
let mut part = UnionFind::new();
// Make singleton set in union find data structure
let max_index = keys.len();
for i in 0..max_index {
part.make_group(i);
}
// Merge singletons to create sets that are disjoint
// 1. Iterate over keys in hashmap and retrieve corresponding
// vector of indices. By construction this vector has set
// property ie all indices within a vector are unique
// 2. For each index in list, find the root of the tree containing
// it in the Union Find data structure. These roots are
// collected in a vector called leaders
// 3. Iterate over leaders to merge the trees corresponding to
// the leaders into one tree
for key in s_map.keys() {
let list = s_map.get(key).unwrap();
let mut leaders = Vec::<usize>::new();
for &x in list.iter() {
leaders.push(part.find(x));
}
// All elements in this list should be in one union
if leaders.len() > 1 {
for i in (1..leaders.len()).rev() {
leaders[0] = part.union(leaders[i], leaders[0]);
}
}
}
// Find leader for indices and project to Ristretto point
// Note path_to_leader has no path compression - this will likely
// help parallelization later.
// Here we convert leader to string to convert it to a RistrettoPoint
let leaders = {
let x = (0..max_index)
.collect::<Vec<usize>>()
.iter()
.map(|&i| {
let (leader, _) = part.path_to_leader(i);
println!("SHUBHO Debug: leader {}", leader);
leader.to_string()
})
.collect::<Vec<_>>();
self.ec_cipher.hash(&x)
};
// 2 out of 2 threshold El Gamal - so keys need to be added
let p_key = self.keypair_reuse.1 + (*sharer_pub_key_reuse);
let (mut c1_buf, mut c2_buf) = {
let (c1, c2) = elgamal_encrypt(leaders, &p_key);
(self.ec_cipher.to_bytes(&c1), self.ec_cipher.to_bytes(&c2))
};
to_s.0.clear();
to_s.1.clear();
to_s.0.append(&mut c1_buf);
to_s.1.append(&mut c2_buf);
Ok(())
}
_ => {
error!("Cannot calculate SUID ");
Err(ProtocolError::ErrorCalculateSUID(
"cannot calculate SUID".to_string(),
))
}
}
}