use std::collections::BTreeMap;
use threshold_crypto::{
PublicKeySet, PublicKeyShare, SecretKeySet, SecretKeyShare, Signature, SignatureShare,
};
type UserId = usize;
type NodeId = usize;
type Msg = String;
type MsgDatabase = BTreeMap<UserId, BTreeMap<Msg, Vec<NodeSignature>>>;
type ChatLog = Vec<(UserId, Msg, Signature)>;
struct ChatNetwork {
pk_set: PublicKeySet,
nodes: Vec<Node>,
chat_log: ChatLog,
n_users: usize,
}
impl ChatNetwork {
fn new(n_nodes: 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 nodes = (0..n_nodes)
.map(|id| {
let sk_share = sk_set.secret_key_share(id);
let pk_share = pk_set.public_key_share(id);
Node::new(id, sk_share, pk_share)
})
.collect();
ChatNetwork {
pk_set,
nodes,
chat_log: vec![],
n_users: 0,
}
}
fn create_user(&mut self) -> User {
let user_id = self.n_users;
let user = User::new(user_id);
self.n_users += 1;
user
}
fn get_node(&self, id: NodeId) -> &Node {
self.nodes.get(id).expect("No `Node` exists with that ID")
}
fn get_mut_node(&mut self, id: NodeId) -> &mut Node {
self.nodes
.get_mut(id)
.expect("No `Node` exists with that ID")
}
fn step(&mut self) {
if let Some(block) = self.run_consensus() {
self.chat_log.push(block);
}
}
fn run_consensus(&self) -> Option<(UserId, Msg, Signature)> {
let all_pending: MsgDatabase =
self.nodes
.iter()
.fold(BTreeMap::new(), |mut all_pending, node| {
for (user_id, signed_msgs) in &node.pending {
let user_msgs = all_pending.entry(*user_id).or_insert_with(BTreeMap::new);
for (msg, sigs) in signed_msgs.iter() {
let sigs = sigs.iter().cloned();
user_msgs
.entry(msg.to_string())
.or_insert_with(Vec::new)
.extend(sigs);
}
}
all_pending
});
for (user_id, signed_msgs) in &all_pending {
for (msg, sigs) in signed_msgs.iter() {
let sigs = sigs.iter().filter_map(|node_sig| {
let node_sig_is_valid = self
.get_node(node_sig.node_id)
.pk_share
.verify(&node_sig.sig, msg.as_bytes());
if node_sig_is_valid {
Some((node_sig.node_id, &node_sig.sig))
} else {
None
}
});
if let Ok(sig) = self.pk_set.combine_signatures(sigs) {
return Some((*user_id, msg.clone(), sig));
}
}
}
None
}
}
struct Node {
id: NodeId,
sk_share: SecretKeyShare,
pk_share: PublicKeyShare,
pending: MsgDatabase,
}
impl Node {
fn new(id: NodeId, sk_share: SecretKeyShare, pk_share: PublicKeyShare) -> Self {
Node {
id,
sk_share,
pk_share,
pending: BTreeMap::new(),
}
}
fn recv(&mut self, user_id: UserId, msg: Msg) {
let sig = NodeSignature {
node_id: self.id,
sig: self.sk_share.sign(msg.as_bytes()),
};
self.pending
.entry(user_id)
.or_insert_with(BTreeMap::new)
.entry(msg)
.or_insert_with(Vec::new)
.push(sig);
}
}
#[derive(Clone, Debug)]
struct NodeSignature {
node_id: NodeId,
sig: SignatureShare,
}
struct User {
id: UserId,
}
impl User {
fn new(id: UserId) -> Self {
User { id }
}
fn send(&self, node: &mut Node, msg: Msg) {
node.recv(self.id, msg);
}
}
fn main() {
let mut network = ChatNetwork::new(3, 1);
let node1 = network.get_node(0).id;
let node2 = network.get_node(1).id;
let alice = network.create_user();
let alice_greeting = "hey, this is alice".to_string();
alice.send(network.get_mut_node(node1), alice_greeting.clone());
network.step();
assert!(network.chat_log.is_empty());
alice.send(network.get_mut_node(node2), alice_greeting);
network.step();
assert_eq!(network.chat_log.len(), 1);
}