use std::collections::BTreeMap;
use threshold_crypto::{
Ciphertext, DecryptionShare, PublicKey, PublicKeySet, PublicKeyShare, SecretKeySet,
SecretKeyShare,
};
struct SecretSociety {
actors: Vec<Actor>,
pk_set: PublicKeySet,
}
impl SecretSociety {
fn new(n_actors: usize, threshold: usize) -> Self {
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(threshold, &mut rng);
let pk_set = sk_set.public_keys();
let actors = (0..n_actors)
.map(|id| {
let sk_share = sk_set.secret_key_share(id);
let pk_share = pk_set.public_key_share(id);
Actor::new(id, sk_share, pk_share)
})
.collect();
SecretSociety { actors, pk_set }
}
fn publish_public_key(&self) -> PublicKey {
self.pk_set.public_key()
}
fn get_actor(&mut self, id: usize) -> &mut Actor {
self.actors
.get_mut(id)
.expect("No `Actor` exists with that ID")
}
fn start_decryption_meeting(&self) -> DecryptionMeeting {
DecryptionMeeting {
pk_set: self.pk_set.clone(),
ciphertext: None,
dec_shares: BTreeMap::new(),
}
}
}
#[derive(Clone, Debug)]
struct Actor {
id: usize,
sk_share: SecretKeyShare,
pk_share: PublicKeyShare,
msg_inbox: Option<Ciphertext>,
}
impl Actor {
fn new(id: usize, sk_share: SecretKeyShare, pk_share: PublicKeyShare) -> Self {
Actor {
id,
sk_share,
pk_share,
msg_inbox: None,
}
}
}
fn send_msg(actor: &mut Actor, enc_msg: Ciphertext) {
actor.msg_inbox = Some(enc_msg);
}
struct DecryptionMeeting {
pk_set: PublicKeySet,
ciphertext: Option<Ciphertext>,
dec_shares: BTreeMap<usize, DecryptionShare>,
}
impl DecryptionMeeting {
fn accept_decryption_share(&mut self, actor: &mut Actor) {
let ciphertext = actor.msg_inbox.take().unwrap();
if let Some(ref meeting_ciphertext) = self.ciphertext {
if ciphertext != *meeting_ciphertext {
return;
}
} else {
self.ciphertext = Some(ciphertext.clone());
}
let dec_share = actor.sk_share.decrypt_share(&ciphertext).unwrap();
let dec_share_is_valid = actor
.pk_share
.verify_decryption_share(&dec_share, &ciphertext);
assert!(dec_share_is_valid);
self.dec_shares.insert(actor.id, dec_share);
}
fn decrypt_message(&self) -> Result<Vec<u8>, ()> {
let ciphertext = self.ciphertext.clone().unwrap();
self.pk_set
.decrypt(&self.dec_shares, &ciphertext)
.map_err(|_| ())
}
}
fn main() {
let mut society = SecretSociety::new(3, 1);
let pk = society.publish_public_key();
let alice = society.get_actor(0).id;
let bob = society.get_actor(1).id;
let clara = society.get_actor(2).id;
let msg = b"let's get pizza";
let ciphertext = pk.encrypt(msg);
send_msg(society.get_actor(alice), ciphertext.clone());
send_msg(society.get_actor(bob), ciphertext.clone());
send_msg(society.get_actor(clara), ciphertext);
let mut meeting = society.start_decryption_meeting();
meeting.accept_decryption_share(society.get_actor(alice));
assert!(meeting.decrypt_message().is_err());
meeting.accept_decryption_share(society.get_actor(bob));
let mut res = meeting.decrypt_message();
assert!(res.is_ok());
assert_eq!(msg, res.unwrap().as_slice());
meeting.accept_decryption_share(society.get_actor(clara));
res = meeting.decrypt_message();
assert!(res.is_ok());
assert_eq!(msg, res.unwrap().as_slice());
}