dcrypt_sign/ecdsa/p192/
mod.rs1use crate::ecdsa::common::SignatureComponents;
9use dcrypt_algorithms::ec::p192 as ec; use dcrypt_algorithms::hash::sha2::Sha256; use dcrypt_algorithms::hash::HashFunction;
12use dcrypt_algorithms::mac::hmac::Hmac;
13use dcrypt_api::{error::Error as ApiError, Result as ApiResult, Signature as SignatureTrait};
14use dcrypt_internal::constant_time::ct_eq;
15use rand::{CryptoRng, RngCore};
16use zeroize::Zeroize;
17
18pub struct EcdsaP192;
20
21#[derive(Clone, Zeroize)]
23pub struct EcdsaP192PublicKey(pub [u8; ec::P192_POINT_UNCOMPRESSED_SIZE]);
24
25#[derive(Clone)]
27pub struct EcdsaP192SecretKey {
28 raw: ec::Scalar,
29 bytes: [u8; ec::P192_SCALAR_SIZE],
30}
31
32impl Zeroize for EcdsaP192SecretKey {
33 fn zeroize(&mut self) {
34 self.bytes.zeroize();
35 }
37}
38
39impl Drop for EcdsaP192SecretKey {
40 fn drop(&mut self) {
41 self.zeroize();
42 }
43}
44
45#[derive(Clone)]
47pub struct EcdsaP192Signature(pub Vec<u8>);
48
49impl AsRef<[u8]> for EcdsaP192PublicKey {
51 fn as_ref(&self) -> &[u8] {
52 &self.0
53 }
54}
55impl AsMut<[u8]> for EcdsaP192PublicKey {
56 fn as_mut(&mut self) -> &mut [u8] {
57 &mut self.0
58 }
59}
60impl AsRef<[u8]> for EcdsaP192SecretKey {
61 fn as_ref(&self) -> &[u8] {
62 &self.bytes
63 }
64}
65impl AsRef<[u8]> for EcdsaP192Signature {
67 fn as_ref(&self) -> &[u8] {
68 &self.0
69 }
70}
71impl AsMut<[u8]> for EcdsaP192Signature {
72 fn as_mut(&mut self) -> &mut [u8] {
73 &mut self.0
74 }
75}
76
77impl SignatureTrait for EcdsaP192 {
78 type PublicKey = EcdsaP192PublicKey;
79 type SecretKey = EcdsaP192SecretKey;
80 type SignatureData = EcdsaP192Signature;
81 type KeyPair = (Self::PublicKey, Self::SecretKey);
82
83 fn name() -> &'static str {
84 "ECDSA-P192"
85 }
86
87 fn keypair<R: CryptoRng + RngCore>(rng: &mut R) -> ApiResult<Self::KeyPair> {
88 let (sk_scalar, pk_point) = ec::generate_keypair(rng).map_err(ApiError::from)?;
89
90 let sk_bytes: [u8; ec::P192_SCALAR_SIZE] = sk_scalar.serialize();
91
92 if sk_scalar.is_zero() {
93 return Err(ApiError::InvalidParameter {
94 context: "ECDSA-P192 keypair",
95 #[cfg(feature = "std")]
96 message: "Generated secret key is zero".to_string(),
97 });
98 }
99
100 let secret_key = EcdsaP192SecretKey {
101 raw: sk_scalar,
102 bytes: sk_bytes,
103 };
104 let public_key = EcdsaP192PublicKey(pk_point.serialize_uncompressed());
105 Ok((public_key, secret_key))
106 }
107
108 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
109 keypair.0.clone()
110 }
111 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
112 keypair.1.clone()
113 }
114
115 fn sign(message: &[u8], secret_key: &Self::SecretKey) -> ApiResult<Self::SignatureData> {
116 let mut hasher = Sha256::new(); hasher.update(message).map_err(ApiError::from)?;
118 let hash_output = hasher.finalize().map_err(ApiError::from)?;
119
120 let mut z_bytes_fixed_size = [0u8; ec::P192_SCALAR_SIZE];
122 z_bytes_fixed_size.copy_from_slice(&hash_output.as_ref()[..ec::P192_SCALAR_SIZE]);
123 let z = reduce_bytes_to_scalar_p192(&z_bytes_fixed_size)?;
124
125 let d = secret_key.raw.clone();
126 let mut rng = rand::thread_rng();
127
128 loop {
129 let k = deterministic_k_hedged_p192::<Sha256, _>(&d, &z, &mut rng); let kg = ec::scalar_mult_base_g(&k).map_err(ApiError::from)?;
132
133 if kg.is_identity() {
134 continue;
135 }
136 let r_bytes = kg.x_coordinate_bytes();
137
138 let r = match reduce_bytes_to_scalar_p192(&r_bytes) {
139 Ok(scalar) if !scalar.is_zero() => scalar,
140 _ => continue,
141 };
142
143 let k_inv = k.inv_mod_n().map_err(ApiError::from)?;
144 let rd = r.mul_mod_n(&d).map_err(ApiError::from)?;
145 let z_plus_rd = z.add_mod_n(&rd).map_err(ApiError::from)?;
146 let s = k_inv.mul_mod_n(&z_plus_rd).map_err(ApiError::from)?;
147
148 if s.is_zero() {
149 continue;
150 }
151
152 let sig_comps = SignatureComponents {
153 r: r.serialize().to_vec(),
154 s: s.serialize().to_vec(),
155 };
156 return Ok(EcdsaP192Signature(sig_comps.to_der()));
157 }
158 }
159
160 fn verify(
161 message: &[u8],
162 signature: &Self::SignatureData,
163 public_key: &Self::PublicKey,
164 ) -> ApiResult<()> {
165 let sig_comps = SignatureComponents::from_der(&signature.0)?;
166
167 if sig_comps.r.len() > ec::P192_SCALAR_SIZE || sig_comps.s.len() > ec::P192_SCALAR_SIZE {
168 return Err(ApiError::InvalidSignature {
169 context: "ECDSA-P192 verify",
170 #[cfg(feature = "std")]
171 message: "Invalid signature component size".to_string(),
172 });
173 }
174
175 let mut r_bytes = [0u8; ec::P192_SCALAR_SIZE];
176 let mut s_bytes = [0u8; ec::P192_SCALAR_SIZE];
177 let r_offset = ec::P192_SCALAR_SIZE.saturating_sub(sig_comps.r.len());
178 let s_offset = ec::P192_SCALAR_SIZE.saturating_sub(sig_comps.s.len());
179 r_bytes[r_offset..].copy_from_slice(&sig_comps.r);
180 s_bytes[s_offset..].copy_from_slice(&sig_comps.s);
181
182 let r = ec::Scalar::new(r_bytes).map_err(|_| ApiError::InvalidSignature {
183 context: "ECDSA-P192 verify",
184 #[cfg(feature = "std")]
185 message: "Invalid r component".to_string(),
186 })?;
187 let s = ec::Scalar::new(s_bytes).map_err(|_| ApiError::InvalidSignature {
188 context: "ECDSA-P192 verify",
189 #[cfg(feature = "std")]
190 message: "Invalid s component".to_string(),
191 })?;
192
193 let mut hasher = Sha256::new(); hasher.update(message).map_err(ApiError::from)?;
195 let hash_output = hasher.finalize().map_err(ApiError::from)?;
196
197 let mut z_bytes_fixed_size = [0u8; ec::P192_SCALAR_SIZE];
198 z_bytes_fixed_size.copy_from_slice(&hash_output.as_ref()[..ec::P192_SCALAR_SIZE]); let z = reduce_bytes_to_scalar_p192(&z_bytes_fixed_size)?;
200
201 let s_inv = s.inv_mod_n().map_err(ApiError::from)?;
202 let u1 = z.mul_mod_n(&s_inv).map_err(ApiError::from)?;
203 let u2 = r.mul_mod_n(&s_inv).map_err(ApiError::from)?;
204
205 let q_point = ec::Point::deserialize_uncompressed(&public_key.0).map_err(ApiError::from)?;
206
207 if q_point.is_identity() {
208 return Err(ApiError::InvalidKey {
209 context: "ECDSA-P192 verify",
210 #[cfg(feature = "std")]
211 message: "Public key is the point at infinity".to_string(),
212 });
213 }
214
215 let u1g = ec::scalar_mult_base_g(&u1).map_err(ApiError::from)?;
216 let u2q = ec::scalar_mult(&u2, &q_point).map_err(ApiError::from)?;
217
218 let point = u1g.add(&u2q);
219
220 if point.is_identity() {
221 return Err(ApiError::InvalidSignature {
222 context: "ECDSA-P192 verify",
223 #[cfg(feature = "std")]
224 message: "Verification point is identity".to_string(),
225 });
226 }
227
228 let x1_bytes = point.x_coordinate_bytes();
229 let v = reduce_bytes_to_scalar_p192(&x1_bytes)?;
230
231 if !ct_eq(r.serialize(), v.serialize()) {
232 return Err(ApiError::InvalidSignature {
233 context: "ECDSA-P192 verify",
234 #[cfg(feature = "std")]
235 message: "Signature verification failed (r != v)".to_string(),
236 });
237 }
238 Ok(())
239 }
240}
241
242fn deterministic_k_hedged_p192<H: HashFunction + Clone, R: RngCore + CryptoRng>(
244 d: &ec::Scalar,
245 z: &ec::Scalar,
246 rng: &mut R,
247) -> ec::Scalar {
248 use zeroize::Zeroize;
249 let hash_len = H::output_size(); let hmac_block_len = H::block_size();
251
252 let mut rbuf = [0u8; ec::P192_SCALAR_SIZE]; rng.fill_bytes(&mut rbuf);
254
255 let mut v_hmac_block = vec![0x01u8; hmac_block_len];
256 let mut k_hmac_block = vec![0x00u8; hmac_block_len];
257
258 {
260 let mut mac = Hmac::<H>::new(&k_hmac_block).unwrap();
261 mac.update(&v_hmac_block).unwrap();
262 mac.update(&[0x00]).unwrap();
263 mac.update(&d.serialize()).unwrap();
264 mac.update(&z.serialize()).unwrap();
265 mac.update(&rbuf).unwrap();
266 let mac_res = mac.finalize().unwrap();
267 k_hmac_block[..hash_len].copy_from_slice(&mac_res);
268 k_hmac_block[hash_len..].fill(0);
269 }
270 let v_new_res = Hmac::<H>::mac(&k_hmac_block, &v_hmac_block).unwrap();
272 v_hmac_block[..hash_len].copy_from_slice(&v_new_res);
273 v_hmac_block[hash_len..].fill(0);
274 {
276 let mut mac = Hmac::<H>::new(&k_hmac_block).unwrap();
277 mac.update(&v_hmac_block).unwrap();
278 mac.update(&[0x01]).unwrap();
279 mac.update(&d.serialize()).unwrap();
280 mac.update(&z.serialize()).unwrap();
281 mac.update(&rbuf).unwrap();
282 let mac_res = mac.finalize().unwrap();
283 k_hmac_block[..hash_len].copy_from_slice(&mac_res);
284 k_hmac_block[hash_len..].fill(0);
285 }
286 let v_new_res = Hmac::<H>::mac(&k_hmac_block, &v_hmac_block).unwrap();
288 v_hmac_block[..hash_len].copy_from_slice(&v_new_res);
289 v_hmac_block[hash_len..].fill(0);
290
291 loop {
293 let v_new_res = Hmac::<H>::mac(&k_hmac_block, &v_hmac_block).unwrap();
294 v_hmac_block[..hash_len].copy_from_slice(&v_new_res);
295 v_hmac_block[hash_len..].fill(0);
296
297 let mut candidate_scalar_bytes = [0u8; ec::P192_SCALAR_SIZE];
298 candidate_scalar_bytes.copy_from_slice(&v_hmac_block[..ec::P192_SCALAR_SIZE]);
299
300 if let Ok(candidate) = ec::Scalar::new(candidate_scalar_bytes) {
301 rbuf.zeroize();
302 return candidate;
303 }
304
305 let mut mac = Hmac::<H>::new(&k_hmac_block).unwrap();
306 mac.update(&v_hmac_block).unwrap();
307 mac.update(&[0x00]).unwrap();
308 let mac_res = mac.finalize().unwrap();
309 k_hmac_block[..hash_len].copy_from_slice(&mac_res);
310 k_hmac_block[hash_len..].fill(0);
311
312 let v_new_res = Hmac::<H>::mac(&k_hmac_block, &v_hmac_block).unwrap();
313 v_hmac_block[..hash_len].copy_from_slice(&v_new_res);
314 v_hmac_block[hash_len..].fill(0);
315 }
316}
317
318fn reduce_bytes_to_scalar_p192(bytes: &[u8; ec::P192_SCALAR_SIZE]) -> ApiResult<ec::Scalar> {
319 ec::Scalar::new(*bytes).map_err(|algo_err| match algo_err {
320 dcrypt_algorithms::error::Error::Parameter {
321 ref name,
322 ref reason,
323 } if name.as_ref() == "P-192 Scalar"
324 && reason.as_ref().contains("Scalar cannot be zero") =>
325 {
326 ApiError::InvalidSignature {
327 context: "ECDSA-P192 scalar reduction",
328 #[cfg(feature = "std")]
329 message: "Computed scalar component is zero or invalid".to_string(),
330 }
331 }
332 _ => ApiError::from(algo_err),
333 })
334}
335
336#[cfg(test)]
337mod tests;