Skip to main content

tecdsa_core/sign/
server.rs

1//! Server side of Protocol 3.
2use alloc::vec::Vec;
3use k256::{ProjectivePoint, Scalar};
4use rand_core::CryptoRng;
5use zeroize::ZeroizeOnDrop;
6
7use super::{Signature, ecdsa_verify, finalize, hedged_nonce, nonce_challenge, tx_base};
8use crate::{
9    arith::sbig::{SBig, resized},
10    curve::{decode_point, encode_point, encode_scalar, sbig_to_scalar, x_coord},
11    error::{Error, Result},
12    hd::HdPath,
13    keygen::{ServerKeyShare, canonical_uint},
14    messages::{SignMsg1, SignMsg2, SignMsg3},
15    paillier::PaillierSk,
16    params::Params,
17    setup::VerifiedSetup,
18    ssid::Ssid,
19    zk::sig::{SigProof, SigStatement},
20};
21
22/// Entry point: step 1 of the server.
23pub struct ServerSign0;
24
25impl ServerSign0 {
26    /// Samples `k₂`, returns the session state and `SignMsg1` (envelope bytes).
27    /// Sessions are independent; `setup` is only read (FR-G5).
28    pub fn start<R: CryptoRng + ?Sized>(
29        rng: &mut R,
30        setup: &VerifiedSetup,
31        share: &ServerKeyShare,
32        client_id: &[u8],
33        digest: &[u8; 32],
34        hd: Option<&HdPath>,
35    ) -> Result<(ServerSign1, Vec<u8>)> {
36        let params = *setup.params();
37        super::check_digest(digest)?;
38        let x2 = *share.secret();
39        let x2_pub = ProjectivePoint::GENERATOR * x2;
40        let (x_sign, delta) = super::signing_key(share.public_key(), hd)?;
41        // client's (shifted) public share: X₁ + δ·G
42        let x1_pub = *share.public_key() - x2_pub + ProjectivePoint::GENERATOR * delta;
43        let key_id = share.key_id();
44        let mut ctx = Vec::with_capacity(64 + client_id.len());
45        ctx.extend_from_slice(&key_id);
46        ctx.extend_from_slice(digest);
47        ctx.extend_from_slice(client_id);
48        let k2 = hedged_nonce(rng, "k2", &x2, &ctx);
49        let r2 = ProjectivePoint::GENERATOR * k2;
50        let y = x1_pub * k2;
51        let ssid = Ssid::sign(
52            setup.hash(),
53            setup.server_id(),
54            client_id,
55            &key_id,
56            digest,
57            &encode_point(&r2),
58            &encode_point(&x_sign),
59        )?;
60        let msg = SignMsg1 {
61            r2: encode_point(&r2).to_vec(),
62            y: encode_point(&y).to_vec(),
63        }
64        .encode(&params)?;
65        Ok((
66            ServerSign1 {
67                params,
68                ssid,
69                k2,
70                x_pub: x_sign,
71                e_bytes: share.e_bytes().to_vec(),
72                digest: *digest,
73            },
74            msg,
75        ))
76    }
77}
78
79/// State after `SignMsg1`; consumed by [`ServerSign1::finish`], so `k₂` cannot be reused.
80#[derive(ZeroizeOnDrop)]
81pub struct ServerSign1 {
82    #[zeroize(skip)]
83    params: Params,
84    #[zeroize(skip)]
85    ssid: Ssid,
86    k2: Scalar,
87    #[zeroize(skip)]
88    x_pub: ProjectivePoint,
89    #[zeroize(skip)]
90    e_bytes: Vec<u8>,
91    #[zeroize(skip)]
92    digest: [u8; 32],
93}
94
95impl ServerSign1 {
96    /// Step 3: checks `SignMsg2`, decrypts and returns the signature plus an optional `SignMsg3`.
97    pub fn finish(
98        self,
99        setup: &VerifiedSetup,
100        sk: &PaillierSk,
101        msg2: &[u8],
102    ) -> Result<(Signature, Vec<u8>)> {
103        let params = &self.params;
104        let m = SignMsg2::decode(msg2, params)?;
105        let r1 = decode_point(&m.r1)?;
106        let r_pt = decode_point(&m.r)?;
107        let pk = setup.paillier_pk();
108        let s_len = (2 * params.n_rsa as usize).div_ceil(8);
109        let s_int = canonical_uint(&m.s_ct, s_len, pk.mod_n2().modulus().as_ref())?;
110        let s_ct = pk.check_ciphertext(&s_int)?;
111        if r_pt != r1 * self.k2 {
112            return Err(Error::VerificationFailed);
113        }
114        let e_int = canonical_uint(&self.e_bytes, s_len, pk.mod_n2().modulus().as_ref())?;
115        let e_ct = pk.check_ciphertext(&e_int)?;
116        let psi = SigProof::decode(&m.psi_sig, params)?;
117        let stmt = SigStatement {
118            h: setup.h(),
119            f: setup.f(),
120            pk,
121            df: setup.df(),
122            e_ct: &e_ct,
123            s_ct: &s_ct,
124            rho_table: setup.rho_table(),
125        };
126        psi.verify(&tx_base(params, &self.ssid, "C"), params, &stmt)?;
127
128        let e = nonce_challenge(params, &self.ssid, &self.x_pub, &r1, &r_pt, &self.digest);
129        let kk = self.k2 + e;
130        let nonce_point = r1 * kk;
131        let r = x_coord(&nonce_point);
132        let kk_inv = Option::<Scalar>::from(k256::elliptic_curve::Field::invert(&kk))
133            .ok_or(Error::VerificationFailed)?;
134
135        // dec(S) = u + x₂′·v mod N, a signed integer: values above N/2 are negative.
136        let dec = sk.dec(&s_ct)?;
137        let n = pk.n();
138        let bits = n.bits_precision().max(dec.bits_precision());
139        let (dec, n_w) = (resized(&dec, bits), resized(n, bits));
140        let half = n_w.shr_vartime(1).ok_or(Error::OutOfRange)?;
141        let signed = if dec.cmp_vartime(&half) == core::cmp::Ordering::Greater {
142            SBig::from_uint(dec).sub(&SBig::from_uint(n_w))
143        } else {
144            SBig::from_uint(dec)
145        };
146        let sigma = sbig_to_scalar(&signed)? * kk_inv;
147        if bool::from(k256::elliptic_curve::Field::is_zero(&sigma))
148            || bool::from(k256::elliptic_curve::Field::is_zero(&r))
149        {
150            return Err(Error::VerificationFailed);
151        }
152        let sig = finalize(&nonce_point, r, sigma);
153        // The result must be an ordinary valid ECDSA signature (Protocol 3, S's output).
154        ecdsa_verify(&self.x_pub, &self.digest, &sig)?;
155        let msg3 = SignMsg3 {
156            r: encode_scalar(&sig.r).to_vec(),
157            s: encode_scalar(&sig.s).to_vec(),
158            recid: sig.recid,
159        }
160        .encode(params)?;
161        Ok((sig, msg3))
162    }
163}
164
165#[cfg(test)]
166impl ServerSign1 {
167    pub(crate) fn test_clone(&self) -> Self {
168        Self {
169            params: self.params,
170            ssid: self.ssid.clone(),
171            k2: self.k2,
172            x_pub: self.x_pub,
173            e_bytes: self.e_bytes.clone(),
174            digest: self.digest,
175        }
176    }
177}