1use alloc::vec::Vec;
3use k256::{ProjectivePoint, Scalar};
4use rand_core::CryptoRng;
5use subtle::ConstantTimeEq;
6use zeroize::ZeroizeOnDrop;
7
8use super::{
9 ClientKeyShare, Clock, KEYGEN_TIMEOUT_MS, canonical_uint, commitment, encode_client_tuple,
10 tx_base,
11};
12use crate::{
13 curve::{decode_point, encode_point, random_nonzero_scalar},
14 error::{Error, Result},
15 messages::{KgMsg1, KgMsg2, KgMsg3},
16 paillier::PaillierPk,
17 params::Params,
18 rsa::tough::sample_df_client,
19 setup::VerifiedSetup,
20 ssid::Ssid,
21 zk::{
22 df::{DfStatement, DfWitness},
23 df_star::DfStarProof,
24 dlenc::{DlencProof, DlencStatement},
25 dlog::DlogProof,
26 },
27};
28
29pub struct ClientKeygen0;
31
32impl ClientKeygen0 {
33 pub fn on_msg1<R: CryptoRng + ?Sized, C: Clock>(
36 rng: &mut R,
37 clock: &C,
38 setup: &VerifiedSetup,
39 client_id: &[u8],
40 msg1: &[u8],
41 ) -> Result<(ClientKeygen1, Vec<u8>)> {
42 let params = *setup.params();
43 let m1 = KgMsg1::decode(msg1, ¶ms)?;
44 let nonce: [u8; 32] = m1
45 .kg_nonce
46 .as_slice()
47 .try_into()
48 .map_err(|_| Error::InvalidEncoding)?;
49 let b: [u8; 32] =
50 m1.b.as_slice()
51 .try_into()
52 .map_err(|_| Error::InvalidEncoding)?;
53 let ssid = Ssid::keygen(setup.hash(), setup.server_id(), client_id, &nonce)?;
54
55 let x1 = random_nonzero_scalar(rng);
56 let x1_pub = ProjectivePoint::GENERATOR * x1;
57 let tuple = sample_df_client(rng, ¶ms)?;
58 let client = DfStatement::client(&tuple.n_hat, &tuple.t, &tuple.s1, &tuple.s2)?;
59 let tx_c = tx_base(¶ms, &ssid, "C");
60 let psi_df = DfStarProof::prove(
61 rng,
62 &tx_c,
63 ¶ms,
64 &client,
65 &DfWitness::from_secret(&tuple.secret),
66 )?;
67 drop(tuple);
69 let psi_dlog = DlogProof::prove(rng, &tx_c, ¶ms, &x1_pub, &x1)?;
70
71 let [m_hat, v, u1, u2] = encode_client_tuple(¶ms, &client)?;
72 let msg2 = KgMsg2 {
73 x1: encode_point(&x1_pub).to_vec(),
74 m_hat,
75 v,
76 u1,
77 u2,
78 psi_df_star: psi_df.encode(¶ms)?,
79 psi_dlog: psi_dlog.encode(¶ms)?,
80 }
81 .encode(¶ms)?;
82 let state = ClientKeygen1 {
83 params,
84 ssid,
85 pk: setup.paillier_pk().clone(),
86 b,
87 x1,
88 x1_pub,
89 client,
90 sent_at_ms: clock.now_ms(),
91 };
92 Ok((state, msg2))
93 }
94}
95
96#[derive(ZeroizeOnDrop)]
98pub struct ClientKeygen1 {
99 #[zeroize(skip)]
100 params: Params,
101 #[zeroize(skip)]
102 ssid: Ssid,
103 #[zeroize(skip)]
104 pk: PaillierPk,
105 #[zeroize(skip)]
106 b: [u8; 32],
107 x1: Scalar,
108 #[zeroize(skip)]
109 x1_pub: ProjectivePoint,
110 #[zeroize(skip)]
111 client: DfStatement,
112 #[zeroize(skip)]
113 sent_at_ms: u64,
114}
115
116impl ClientKeygen1 {
117 pub fn on_msg3<C: Clock>(self, clock: &C, msg3: &[u8]) -> Result<ClientKeyShare> {
119 let params = &self.params;
120 if clock.now_ms().saturating_sub(self.sent_at_ms) > KEYGEN_TIMEOUT_MS {
121 return Err(Error::Timeout);
122 }
123 let m = KgMsg3::decode(msg3, params)?;
124 let x2_pub = decode_point(&m.x2)?;
125 if !bool::from(commitment(params, &self.ssid, &x2_pub).ct_eq(&self.b)) {
126 return Err(Error::VerificationFailed);
127 }
128 let e_len = (2 * params.n_rsa as usize).div_ceil(8);
129 let e_int = canonical_uint(&m.e, e_len, self.pk.mod_n2().modulus().as_ref())?;
130 let e_ct = self.pk.check_ciphertext(&e_int)?;
131 let psi = DlencProof::decode(&m.psi_dlenc, params)?;
132 let tx_s = tx_base(params, &self.ssid, "S");
133 let stmt = DlencStatement {
134 x_pub: &x2_pub,
135 e_ct: &e_ct,
136 pk: &self.pk,
137 client: &self.client,
138 };
139 psi.verify(&tx_s, params, &stmt)?;
140 Ok(ClientKeyShare::new(self.x1, self.x1_pub + x2_pub, m.e))
141 }
142}
143
144#[cfg(test)]
145impl ClientKeygen1 {
146 pub(crate) fn test_clone(&self) -> Self {
147 Self {
148 params: self.params,
149 ssid: self.ssid.clone(),
150 pk: self.pk.clone(),
151 b: self.b,
152 x1: self.x1,
153 x1_pub: self.x1_pub,
154 client: self.client.clone(),
155 sent_at_ms: self.sent_at_ms,
156 }
157 }
158}