Skip to main content

tecdsa_core/keygen/
server.rs

1//! Server side of Protocol 2.
2use alloc::vec::Vec;
3use k256::ProjectivePoint;
4use rand_core::CryptoRng;
5use zeroize::ZeroizeOnDrop;
6
7use super::{ServerKeyShare, commitment, decode_client_tuple, tx_base};
8use crate::{
9    arith::sbig::{SBig, SRange},
10    curve::{decode_point, encode_point, sbig_to_scalar},
11    error::Result,
12    messages::{KgMsg1, KgMsg2, KgMsg3},
13    paillier::PaillierPk,
14    params::Params,
15    setup::SetupData,
16    ssid::Ssid,
17    transcript::uint_to_be,
18    zk::{
19        df_star::DfStarProof,
20        dlenc::{DlencProof, DlencStatement, DlencWitness},
21        dlog::DlogProof,
22    },
23};
24
25/// Entry point: step 1 of the server.
26pub struct ServerKeygen0;
27
28impl ServerKeygen0 {
29    /// Samples `x₂′ ← ±2^{n_x}`, returns the state and `KgMsg1` (envelope bytes).
30    pub fn start<R: CryptoRng + ?Sized>(
31        rng: &mut R,
32        params: &Params,
33        setup: &SetupData,
34        client_id: &[u8],
35    ) -> Result<(ServerKeygen1, Vec<u8>)> {
36        let pk = setup.paillier_pk()?;
37        let mut nonce = [0u8; 32];
38        rng.fill_bytes(&mut nonce);
39        let ssid = Ssid::keygen(setup.hash()?, &setup.server_id, client_id, &nonce)?;
40        let x2p = SBig::random_in(rng, SRange::pm_pow2(params.n_x()));
41        let x2_pub = ProjectivePoint::GENERATOR * sbig_to_scalar(&x2p)?;
42        let b = commitment(params, &ssid, &x2_pub);
43        let msg = KgMsg1 {
44            kg_nonce: nonce.to_vec(),
45            b: b.to_vec(),
46        }
47        .encode(params)?;
48        Ok((
49            ServerKeygen1 {
50                params: *params,
51                ssid,
52                pk,
53                x2p,
54                x2_pub,
55            },
56            msg,
57        ))
58    }
59}
60
61/// State after `KgMsg1` was sent; consumed by [`ServerKeygen1::on_msg2`].
62#[derive(ZeroizeOnDrop)]
63pub struct ServerKeygen1 {
64    #[zeroize(skip)]
65    params: Params,
66    #[zeroize(skip)]
67    ssid: Ssid,
68    #[zeroize(skip)]
69    pk: PaillierPk,
70    x2p: SBig,
71    #[zeroize(skip)]
72    x2_pub: ProjectivePoint,
73}
74
75impl ServerKeygen1 {
76    /// Steps 2–3: verifies `ψ_df*` and `ψ_dlog`, produces `KgMsg3` and the server's key share.
77    pub fn on_msg2<R: CryptoRng + ?Sized>(
78        self,
79        rng: &mut R,
80        msg2: &[u8],
81    ) -> Result<(ServerKeyShare, Vec<u8>)> {
82        let params = &self.params;
83        let m = KgMsg2::decode(msg2, params)?;
84        let x1_pub = decode_point(&m.x1)?;
85        let client = decode_client_tuple(params, &m.m_hat, &m.v, &m.u1, &m.u2)?;
86        let psi_df = DfStarProof::decode(&m.psi_df_star, params)?;
87        let psi_dlog = DlogProof::decode(&m.psi_dlog, params)?;
88
89        let tx_c = tx_base(params, &self.ssid, "C");
90        psi_df.verify(&tx_c, params, &client)?;
91        psi_dlog.verify(&tx_c, params, &x1_pub)?;
92
93        let beta = SBig::random_in(rng, SRange::pm_pow2(params.n_lambda()));
94        let e_ct = self.pk.enc(&self.x2p, &beta, params.n_lambda())?;
95        let tx_s = tx_base(params, &self.ssid, "S");
96        let stmt = DlencStatement {
97            x_pub: &self.x2_pub,
98            e_ct: &e_ct,
99            pk: &self.pk,
100            client: &client,
101        };
102        let psi = DlencProof::prove(
103            rng,
104            &tx_s,
105            params,
106            &stmt,
107            &DlencWitness::new(self.x2p.clone(), beta),
108        )?;
109
110        let e_len = (2 * params.n_rsa as usize).div_ceil(8);
111        let e_bytes = uint_to_be(&e_ct.retrieve(), e_len)?;
112        let msg3 = KgMsg3 {
113            x2: encode_point(&self.x2_pub).to_vec(),
114            e: e_bytes.clone(),
115            psi_dlenc: psi.encode(params)?,
116        }
117        .encode(params)?;
118        let share = ServerKeyShare::new(sbig_to_scalar(&self.x2p)?, x1_pub + self.x2_pub, e_bytes);
119        Ok((share, msg3))
120    }
121}
122
123#[cfg(test)]
124impl ServerKeygen1 {
125    pub(crate) fn test_clone(&self) -> Self {
126        Self {
127            params: self.params,
128            ssid: self.ssid.clone(),
129            pk: self.pk.clone(),
130            x2p: self.x2p.clone(),
131            x2_pub: self.x2_pub,
132        }
133    }
134}