race_client/
lib.rs

1use std::{
2    collections::{BTreeSet, HashMap},
3    sync::Arc,
4};
5
6use race_api::error::{Error, Result};
7use race_api::event::{CustomEvent, Event};
8use race_api::random::{RandomState, RandomStatus};
9use race_api::types::SecretShare;
10
11use race_core::{
12    connection::ConnectionT,
13    context::GameContext,
14    encryptor::EncryptorT,
15    secret::SecretState,
16    types::{
17        AttachGameParams, Ciphertext, ClientMode, DecisionId, RandomId, SecretIdent, SecretKey,
18        SubmitEventParams,
19    },
20};
21
22use race_core::transport::TransportT;
23
24/// Operation Ident
25///
26/// Each event can be recorded as one or more idents, we save these
27/// idents to avoid duplicated submission.
28#[derive(PartialEq, Eq, PartialOrd, Ord)]
29pub enum OpIdent {
30    RandomSecret {
31        random_id: RandomId,
32        to_addr: Option<String>,
33        index: usize,
34    },
35    AnswerSecret {
36        decision_id: DecisionId,
37    },
38    Lock {
39        random_id: RandomId,
40    },
41    Mask {
42        random_id: RandomId,
43    },
44}
45
46/// The client core for player, transactor and validator nodes.
47///
48/// It reads the updated context, generates events and sends them via
49/// connection.
50///
51/// # Client Mode
52///
53/// Three modes are supported:
54///
55/// | Mode      | Randomize | Decisions | Decryption |
56/// |-----------|-----------|-----------|------------|
57/// | Client    | x         | o         | o          |
58/// | Server    | o         | x         | o          |
59/// | Validator | o         | x         | o          |
60///
61pub struct Client {
62    pub encryptor: Arc<dyn EncryptorT>,
63    pub transport: Arc<dyn TransportT>,
64    pub connection: Arc<dyn ConnectionT>,
65    pub game_addr: String,
66    // The address of current node, player address or server address.
67    pub addr: String,
68    // The client mode could be player, validator or transactor.
69    // Only player can send custom events.
70    // Only transactor can send system events.
71    pub mode: ClientMode,
72    pub op_hist: BTreeSet<OpIdent>,
73    pub secret_state: SecretState,
74}
75
76impl Client {
77    pub fn new(
78        addr: String,
79        game_addr: String,
80        mode: ClientMode,
81        transport: Arc<dyn TransportT>,
82        encryptor: Arc<dyn EncryptorT>,
83        connection: Arc<dyn ConnectionT>,
84    ) -> Self {
85        Self {
86            addr,
87            game_addr,
88            mode,
89            op_hist: BTreeSet::new(),
90            secret_state: SecretState::new(encryptor.clone()),
91            transport,
92            encryptor,
93            connection,
94        }
95    }
96
97    pub async fn attach_game(&self) -> Result<()> {
98        let key = self.encryptor.export_public_key(None)?;
99        self.connection
100            .attach_game(
101                &self.game_addr,
102                AttachGameParams {
103                    key,
104                    signer: self.addr.clone(),
105                },
106            )
107            .await
108    }
109
110    pub async fn submit_event(&self, event: Event) -> Result<()> {
111        self.connection
112            .submit_event(&self.game_addr, SubmitEventParams { event })
113            .await
114    }
115
116    pub async fn submit_custom_event<S: CustomEvent>(&self, custom_event: S) -> Result<()> {
117        let event = Event::custom(&self.game_addr, &custom_event);
118        self.connection
119            .submit_event(&self.addr, SubmitEventParams { event })
120            .await
121    }
122
123    pub fn load_random_states(&mut self, game_context: &GameContext) -> Result<()> {
124        for random_state in game_context.list_random_states().iter() {
125            if !self.secret_state.is_random_loaded(random_state.id) {
126                self.secret_state
127                    .gen_random_secrets(random_state.id, random_state.size);
128            }
129        }
130        Ok(())
131    }
132
133    pub fn answer_event(&mut self, decision_id: DecisionId, value: String) -> Result<Event> {
134        let (ciphertext, digest) = self.secret_state.encrypt_answer(decision_id, value)?;
135        Ok(Event::AnswerDecision {
136            sender: self.addr.clone(),
137            decision_id,
138            ciphertext,
139            digest,
140        })
141    }
142
143    pub async fn answer(&mut self, decision_id: DecisionId, value: String) -> Result<()> {
144        let event = self.answer_event(decision_id, value)?;
145        self.connection
146            .submit_event(&self.game_addr, SubmitEventParams { event })
147            .await?;
148        Ok(())
149    }
150
151    pub fn handle_decision(&mut self, game_context: &GameContext) -> Result<Vec<Event>> {
152        let mut shares = Vec::new();
153
154        for state in game_context.list_decision_states() {
155            println!("[CLET] Decision state {:?}", state);
156            if state.get_owner().eq(&self.addr) {
157                let secret = self
158                    .secret_state
159                    .get_decision_secret(state.id)
160                    .ok_or(Error::MissingDecisionSecret(state.id))?;
161                shares.push(SecretShare::new_for_answer(
162                    state.id,
163                    self.addr.clone(),
164                    secret,
165                ));
166            }
167        }
168        if shares.is_empty() {
169            Ok(vec![])
170        } else {
171            Ok(vec![Event::ShareSecrets {
172                sender: self.addr.clone(),
173                shares,
174            }])
175        }
176    }
177
178    pub fn handle_random_waiting(&mut self, random_state: &RandomState) -> Result<Option<Event>> {
179        let required_idents: Vec<SecretIdent> = random_state
180            .list_required_secrets_by_from_addr(&self.addr)
181            .into_iter()
182            .filter_map(|idt| {
183                let op_ident = OpIdent::RandomSecret {
184                    random_id: idt.random_id,
185                    to_addr: idt.to_addr.clone(),
186                    index: idt.index,
187                };
188                if self.op_hist.contains(&op_ident) {
189                    None
190                } else {
191                    Some(idt)
192                }
193            })
194            .collect();
195
196        let mut op_hist = Vec::new();
197
198        let shares = required_idents
199            .into_iter()
200            .map(|idt| {
201                let secret = self
202                    .secret_state
203                    .get_random_lock(idt.random_id, idt.index)?;
204                op_hist.push(OpIdent::RandomSecret {
205                    random_id: random_state.id,
206                    index: idt.index,
207                    to_addr: idt.to_addr.clone(),
208                });
209                Ok(SecretShare::new_for_random(
210                    idt.random_id,
211                    idt.index,
212                    self.addr.clone(),
213                    idt.to_addr,
214                    secret,
215                ))
216            })
217            .collect::<Result<Vec<SecretShare>>>()?;
218
219        if shares.is_empty() {
220            Ok(None)
221        } else {
222            let event = Event::ShareSecrets {
223                sender: self.addr.clone(),
224                shares,
225            };
226            self.op_hist.extend(op_hist);
227            Ok(Some(event))
228        }
229    }
230
231    pub fn handle_random_masking(&mut self, random_state: &RandomState) -> Result<Option<Event>> {
232        let op_ident = OpIdent::Mask {
233            random_id: random_state.id,
234        };
235
236        if self.op_hist.contains(&op_ident) {
237            return Ok(None);
238        }
239
240        let origin = random_state
241            .ciphertexts
242            .iter()
243            .map(|c| c.ciphertext().to_owned())
244            .collect();
245
246        let mut masked = self
247            .secret_state
248            .mask(random_state.id, origin)
249            .map_err(|e| Error::RandomizationError(e.to_string()))?;
250
251        self.encryptor.shuffle(&mut masked);
252
253        let event = Event::Mask {
254            sender: self.addr.clone(),
255            random_id: random_state.id,
256            ciphertexts: masked,
257        };
258
259        self.op_hist.insert(op_ident);
260
261        Ok(Some(event))
262    }
263
264    pub fn handle_random_locking(&mut self, random_state: &RandomState) -> Result<Option<Event>> {
265        let op_ident = OpIdent::Lock {
266            random_id: random_state.id,
267        };
268
269        if self.op_hist.contains(&op_ident) {
270            return Ok(None);
271        }
272
273        let origin = random_state
274            .ciphertexts
275            .iter()
276            .map(|c| c.ciphertext().to_owned())
277            .collect();
278
279        let unmasked = self
280            .secret_state
281            .unmask(random_state.id, origin)
282            .map_err(|e| Error::RandomizationError(e.to_string()))?;
283
284        let locked = self
285            .secret_state
286            .lock(random_state.id, unmasked)
287            .map_err(|e| Error::RandomizationError(e.to_string()))?;
288
289        let event = Event::Lock {
290            sender: self.addr.clone(),
291            random_id: random_state.id,
292            ciphertexts_and_digests: locked,
293        };
294
295        self.op_hist.insert(op_ident);
296
297        Ok(Some(event))
298    }
299
300    pub fn handle_randomization(&mut self, game_context: &GameContext) -> Result<Vec<Event>> {
301        let mut events = vec![];
302        for random_state in game_context.list_random_states().iter() {
303            match random_state.status {
304                RandomStatus::Ready => (),
305                RandomStatus::Shared => (),
306                RandomStatus::WaitingSecrets => {
307                    if let Some(event) = self.handle_random_waiting(random_state)? {
308                        events.push(event);
309                    }
310                }
311                RandomStatus::Locking(ref addr) => {
312                    if self.addr.eq(addr) {
313                        if let Some(event) = self.handle_random_locking(random_state)? {
314                            events.push(event);
315                        }
316                    }
317                }
318                RandomStatus::Masking(ref addr) => {
319                    if self.addr.eq(addr) {
320                        if let Some(event) = self.handle_random_masking(random_state)? {
321                            events.push(event);
322                        }
323                    }
324                }
325            }
326        }
327
328        Ok(events)
329    }
330
331    pub fn handle_updated_context(&mut self, ctx: &GameContext) -> Result<Vec<Event>> {
332        let events = match self.mode {
333            ClientMode::Player => {
334                self.load_random_states(ctx)?;
335                self.handle_decision(ctx)?
336            }
337            ClientMode::Transactor | ClientMode::Validator => {
338                self.load_random_states(ctx)?;
339                self.handle_randomization(ctx)?
340            }
341        };
342        Ok(events)
343    }
344
345    pub fn flush_secret_states(&mut self) {
346        self.secret_state.clear();
347        self.op_hist.clear();
348    }
349
350    /// Decrypt the ciphertexts with shared secrets.
351    /// Return a mapping from mapping from indexes to decrypted value.
352    pub fn decrypt(
353        &self,
354        ctx: &GameContext,
355        random_id: RandomId,
356    ) -> Result<HashMap<usize, String>> {
357        let random_state = ctx.get_random_state(random_id)?;
358        let options = &random_state.options;
359
360        let mut revealed = decrypt_with_secrets(
361            &*self.encryptor,
362            random_state.list_revealed_ciphertexts(),
363            random_state.list_revealed_secrets()?,
364            options,
365        )?;
366
367        if self.mode == ClientMode::Player {
368            let assigned = decrypt_with_secrets(
369                &*self.encryptor,
370                random_state.list_assigned_ciphertexts(&self.addr),
371                random_state.list_shared_secrets(&self.addr)?,
372                options,
373            )?;
374            revealed.extend(assigned);
375        }
376
377        Ok(revealed)
378    }
379}
380
381fn decrypt_with_secrets(
382    encryptor: &dyn EncryptorT,
383    ciphertext_map: HashMap<usize, Ciphertext>,
384    mut secret_map: HashMap<usize, Vec<SecretKey>>,
385    options: &[String],
386) -> Result<HashMap<usize, String>> {
387    let mut ret = HashMap::new();
388    for (i, mut buf) in ciphertext_map.into_iter() {
389        if let Some(secrets) = secret_map.remove(&i) {
390            encryptor.apply_multi(secrets, &mut buf);
391            let value = String::from_utf8(buf).or(Err(Error::DecryptionFailed))?;
392            if !options.contains(&value) {
393                return Err(Error::InvalidDecryptedValue(value))?;
394            }
395            ret.insert(i, value);
396        } else {
397            return Err(Error::MissingSecret);
398        }
399    }
400    Ok(ret)
401}