-
Notifications
You must be signed in to change notification settings - Fork 72
/
threshold_enc.rs
175 lines (152 loc) · 6.55 KB
/
threshold_enc.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use std::collections::BTreeMap;
use threshold_crypto::{
Ciphertext, DecryptionShare, PublicKey, PublicKeySet, PublicKeyShare, SecretKeySet,
SecretKeyShare,
};
// In this example scenario, the `SecretSociety` is the "trusted key dealer". The trusted dealer is
// responsible for key generation. The society creates a master public-key, which anyone can use to
// encrypt a message to the society's members; the society is also responsible for giving each
// actor their respective share of the secret-key.
struct SecretSociety {
actors: Vec<Actor>,
pk_set: PublicKeySet,
}
impl SecretSociety {
// Creates a new `SecretSociety`.
//
// # Arguments
//
// `n_actors` - the number of actors (members) in the secret society.
// `threshold` - the number of actors that must collaborate to successfully
// decrypt a message must exceed this `threshold`.
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 }
}
// The secret society publishes its public-key to a publicly accessible key server.
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")
}
// Starts a new meeting of the secret society. Each time the set of actors receive an encrypted
// message, at least 2 of them (i.e. 1 more than the threshold) must work together to decrypt
// the ciphertext.
fn start_decryption_meeting(&self) -> DecryptionMeeting {
DecryptionMeeting {
pk_set: self.pk_set.clone(),
ciphertext: None,
dec_shares: BTreeMap::new(),
}
}
}
// A member of the secret society.
#[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,
}
}
}
// Sends an encrypted message to an `Actor`.
fn send_msg(actor: &mut Actor, enc_msg: Ciphertext) {
actor.msg_inbox = Some(enc_msg);
}
// A meeting of the secret society. At this meeting, actors collaborate to decrypt a shared
// ciphertext.
struct DecryptionMeeting {
pk_set: PublicKeySet,
ciphertext: Option<Ciphertext>,
dec_shares: BTreeMap<usize, DecryptionShare>,
}
impl DecryptionMeeting {
// An actor contributes their decryption share to the decryption process.
fn accept_decryption_share(&mut self, actor: &mut Actor) {
let ciphertext = actor.msg_inbox.take().unwrap();
// Check that the actor's ciphertext is the same ciphertext decrypted at the meeting.
// The first actor to arrive at the decryption meeting sets the meeting's ciphertext.
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);
}
// Tries to decrypt the shared ciphertext using the decryption shares.
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() {
// Create a `SecretSociety` with 3 actors. Any message encrypted with the society's public-key
// will require 2 or more actors working together to decrypt (i.e. the decryption threshold is
// 1). Once the secret society has created its master keys, it "deals" a secret-key share and
// public-key share to each of its actors. The secret society then publishes its public key
// to a publicly accessible key-server.
let mut society = SecretSociety::new(3, 1);
let pk = society.publish_public_key();
// Create a named alias for each actor in the secret society.
let alice = society.get_actor(0).id;
let bob = society.get_actor(1).id;
let clara = society.get_actor(2).id;
// I, the society's benevolent hacker, want to send an important message to each of my
// comrades. I encrypt my message with the society's public-key. I then send the ciphertext to
// each of the society's actors.
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);
// We start a meeting of the secret society. At the meeting, each actor contributes their
// share of the decryption process to decrypt the ciphertext that they each received.
let mut meeting = society.start_decryption_meeting();
// Alice is the first actor to arrive at the meeting, she provides her decryption share. One
// actor alone cannot decrypt the ciphertext, decryption fails.
meeting.accept_decryption_share(society.get_actor(alice));
assert!(meeting.decrypt_message().is_err());
// Bob joins the meeting and provides his decryption share. Alice and Bob are now collaborating
// to decrypt the ciphertext, they succeed because the society requires two or more actors for
// decryption.
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());
// Clara joins the meeting and provides her decryption share. We already are able to decrypt
// the ciphertext with 2 actors, but let's show that we can with 3 actors as well.
meeting.accept_decryption_share(society.get_actor(clara));
res = meeting.decrypt_message();
assert!(res.is_ok());
assert_eq!(msg, res.unwrap().as_slice());
}