fedimint_hbbft/
threshold_decrypt.rs1use std::collections::BTreeMap;
15use std::sync::Arc;
16
17use crate::crypto::{self, Ciphertext, DecryptionShare};
18use rand::Rng;
19use rand_derive::Rand;
20use serde::{Deserialize, Serialize};
21use thiserror::Error;
22
23use crate::fault_log::{self, Fault};
24use crate::{ConsensusProtocol, NetworkInfo, NodeIdT, Target};
25
26#[derive(Clone, Eq, PartialEq, Debug, Error)]
28pub enum Error {
29 #[error("Redundant input provided: {0:?}")]
31 MultipleInputs(Box<Ciphertext>),
32 #[error("Invalid ciphertext: {0:?}")]
34 InvalidCiphertext(Box<Ciphertext>),
35 #[error("Unknown sender")]
37 UnknownSender,
38 #[error("Decryption failed: {0:?}")]
40 Decryption(crypto::error::Error),
41 #[error("Tried to decrypt before setting ciphertext")]
43 CiphertextIsNone,
44}
45
46pub type Result<T> = ::std::result::Result<T, Error>;
48
49#[derive(Clone, Debug, Error, PartialEq, Eq)]
51pub enum FaultKind {
52 #[error("`ThresholdDecrypt` received multiple shares from the same sender.")]
54 MultipleDecryptionShares,
55 #[error("`HoneyBadger` received a decryption share from an unverified sender.")]
57 UnverifiedDecryptionShareSender,
58}
59
60pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
62
63#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Rand)]
65pub struct Message(pub DecryptionShare);
66
67#[derive(Debug)]
70pub struct ThresholdDecrypt<N> {
71 netinfo: Arc<NetworkInfo<N>>,
72 ciphertext: Option<Ciphertext>,
74 shares: BTreeMap<N, (usize, DecryptionShare)>,
76 had_input: bool,
78 terminated: bool,
80}
81
82pub type Step<N> = crate::CpStep<ThresholdDecrypt<N>>;
84
85impl<N: NodeIdT> ConsensusProtocol for ThresholdDecrypt<N> {
86 type NodeId = N;
87 type Input = ();
88 type Output = Vec<u8>;
89 type Message = Message;
90 type Error = Error;
91 type FaultKind = FaultKind;
92
93 fn handle_input<R: Rng>(&mut self, _input: (), _rng: &mut R) -> Result<Step<N>> {
94 self.start_decryption()
95 }
96
97 fn handle_message<R: Rng>(
98 &mut self,
99 sender_id: &Self::NodeId,
100 message: Message,
101 _rng: &mut R,
102 ) -> Result<Step<N>> {
103 self.handle_message(sender_id, message)
104 }
105
106 fn terminated(&self) -> bool {
107 self.terminated
108 }
109
110 fn our_id(&self) -> &N {
111 self.netinfo.our_id()
112 }
113}
114
115impl<N: NodeIdT> ThresholdDecrypt<N> {
116 pub fn new(netinfo: Arc<NetworkInfo<N>>) -> Self {
118 ThresholdDecrypt {
119 netinfo,
120 ciphertext: None,
121 shares: BTreeMap::new(),
122 had_input: false,
123 terminated: false,
124 }
125 }
126
127 pub fn new_with_ciphertext(netinfo: Arc<NetworkInfo<N>>, ct: Ciphertext) -> Result<Self> {
130 let mut td = ThresholdDecrypt::new(netinfo);
131 td.set_ciphertext(ct)?;
132 Ok(td)
133 }
134
135 pub fn set_ciphertext(&mut self, ct: Ciphertext) -> Result<()> {
139 if self.ciphertext.is_some() {
140 return Err(Error::MultipleInputs(Box::new(ct)));
141 }
142 if !ct.verify() {
143 return Err(Error::InvalidCiphertext(Box::new(ct)));
144 }
145 self.ciphertext = Some(ct);
146 Ok(())
147 }
148
149 pub fn start_decryption(&mut self) -> Result<Step<N>> {
152 if self.had_input {
153 return Ok(Step::default()); }
155 let ct = self.ciphertext.clone().ok_or(Error::CiphertextIsNone)?;
156 let mut step = Step::default();
157 step.fault_log.extend(self.remove_invalid_shares());
158 self.had_input = true;
159 let opt_idx = self.netinfo.node_index(self.our_id());
160 let (idx, share) = match (opt_idx, self.netinfo.secret_key_share()) {
161 (Some(idx), Some(sks)) => (idx, sks.decrypt_share_no_verify(&ct)),
162 (_, _) => return Ok(step.join(self.try_output()?)), };
164 let our_id = self.our_id().clone();
165 let msg = Target::all().message(Message(share.clone()));
166 step.messages.push(msg);
167 self.shares.insert(our_id, (idx, share));
168 step.extend(self.try_output()?);
169 Ok(step)
170 }
171
172 pub fn sender_ids(&self) -> impl Iterator<Item = &N> {
174 self.shares.keys()
175 }
176
177 pub fn handle_message(&mut self, sender_id: &N, message: Message) -> Result<Step<N>> {
183 if self.terminated {
184 return Ok(Step::default()); }
186 let idx = self
188 .netinfo
189 .node_index(sender_id)
190 .ok_or(Error::UnknownSender)?;
191 let Message(share) = message;
192 if !self.is_share_valid(sender_id, &share) {
193 let fault_kind = FaultKind::UnverifiedDecryptionShareSender;
194 return Ok(Fault::new(sender_id.clone(), fault_kind).into());
195 }
196 let entry = (idx, share);
197 if self.shares.insert(sender_id.clone(), entry).is_some() {
198 return Ok(Fault::new(sender_id.clone(), FaultKind::MultipleDecryptionShares).into());
199 }
200 self.try_output()
201 }
202
203 fn remove_invalid_shares(&mut self) -> FaultLog<N> {
205 let faulty_senders: Vec<N> = self
206 .shares
207 .iter()
208 .filter(|(id, (_, share))| !self.is_share_valid(id, share))
209 .map(|(id, _)| id.clone())
210 .collect();
211 let mut fault_log = FaultLog::default();
212 for id in faulty_senders {
213 self.shares.remove(&id);
214 fault_log.append(id, FaultKind::UnverifiedDecryptionShareSender);
215 }
216 fault_log
217 }
218
219 fn is_share_valid(&self, id: &N, share: &DecryptionShare) -> bool {
221 let ct = match self.ciphertext {
222 None => return true, Some(ref ct) => ct,
224 };
225 match self.netinfo.public_key_share(id) {
226 None => false, Some(pk) => pk.verify_decryption_share(share, ct),
228 }
229 }
230
231 fn try_output(&mut self) -> Result<Step<N>> {
233 if self.terminated || self.shares.len() <= self.netinfo.num_faulty() {
234 return Ok(Step::default()); }
236 let ct = match self.ciphertext {
237 None => return Ok(Step::default()), Some(ref ct) => ct.clone(),
239 };
240 self.terminated = true;
241 let step = self.start_decryption()?; let share_itr = self
243 .shares
244 .values()
245 .map(|&(ref idx, ref share)| (idx, share));
246 let plaintext = self
247 .netinfo
248 .public_key_set()
249 .decrypt(share_itr, &ct)
250 .map_err(Error::Decryption)?;
251 Ok(step.with_output(plaintext))
252 }
253}