1use crate::ecdsa::common::SignatureComponents;
8use dcrypt_algorithms::ec::p384 as ec;
9use dcrypt_algorithms::hash::sha2::Sha384;
10use dcrypt_algorithms::hash::HashFunction;
11use dcrypt_algorithms::mac::hmac::Hmac;
12use dcrypt_api::{error::Error as ApiError, Result as ApiResult, Signature as SignatureTrait};
13use dcrypt_internal::constant_time::ct_eq;
14use rand::{CryptoRng, RngCore};
15use zeroize::Zeroize;
16
17pub struct EcdsaP384;
21
22#[derive(Clone, Zeroize)]
26pub struct EcdsaP384PublicKey(pub [u8; ec::P384_POINT_UNCOMPRESSED_SIZE]);
27
28#[derive(Clone)]
34pub struct EcdsaP384SecretKey {
35 raw: ec::Scalar,
36 bytes: [u8; ec::P384_SCALAR_SIZE],
37}
38
39impl Zeroize for EcdsaP384SecretKey {
41 fn zeroize(&mut self) {
42 self.bytes.zeroize();
44 }
47}
48
49impl Drop for EcdsaP384SecretKey {
51 fn drop(&mut self) {
52 self.zeroize();
53 }
54}
55
56#[derive(Clone)]
60pub struct EcdsaP384Signature(pub Vec<u8>);
61
62impl AsRef<[u8]> for EcdsaP384PublicKey {
64 fn as_ref(&self) -> &[u8] {
65 &self.0
66 }
67}
68
69impl AsMut<[u8]> for EcdsaP384PublicKey {
70 fn as_mut(&mut self) -> &mut [u8] {
71 &mut self.0
72 }
73}
74
75impl AsRef<[u8]> for EcdsaP384SecretKey {
76 fn as_ref(&self) -> &[u8] {
77 &self.bytes
78 }
79}
80
81impl AsRef<[u8]> for EcdsaP384Signature {
87 fn as_ref(&self) -> &[u8] {
88 &self.0
89 }
90}
91
92impl AsMut<[u8]> for EcdsaP384Signature {
93 fn as_mut(&mut self) -> &mut [u8] {
94 &mut self.0
95 }
96}
97
98impl SignatureTrait for EcdsaP384 {
99 type PublicKey = EcdsaP384PublicKey;
100 type SecretKey = EcdsaP384SecretKey;
101 type SignatureData = EcdsaP384Signature;
102 type KeyPair = (Self::PublicKey, Self::SecretKey);
103
104 fn name() -> &'static str {
105 "ECDSA-P384"
106 }
107
108 fn keypair<R: CryptoRng + RngCore>(rng: &mut R) -> ApiResult<Self::KeyPair> {
115 let (sk_scalar, pk_point) = ec::generate_keypair(rng).map_err(ApiError::from)?;
117
118 let sk_bytes: [u8; ec::P384_SCALAR_SIZE] = sk_scalar.serialize();
120
121 if sk_bytes.iter().all(|&b| b == 0) {
123 return Err(ApiError::InvalidParameter {
124 context: "ECDSA-P384 keypair",
125 #[cfg(feature = "std")]
126 message: "Generated secret key is zero (internal error)".to_string(),
127 });
128 }
129
130 let secret_key = EcdsaP384SecretKey {
132 raw: sk_scalar,
133 bytes: sk_bytes,
134 };
135
136 let public_key = EcdsaP384PublicKey(pk_point.serialize_uncompressed());
138
139 Ok((public_key, secret_key))
140 }
141
142 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
143 keypair.0.clone()
144 }
145
146 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
147 keypair.1.clone()
148 }
149
150 fn sign(message: &[u8], secret_key: &Self::SecretKey) -> ApiResult<Self::SignatureData> {
165 let mut hasher = Sha384::new();
167 hasher.update(message).map_err(ApiError::from)?;
168 let hash_output = hasher.finalize().map_err(ApiError::from)?;
169
170 let mut h_bytes = [0u8; ec::P384_SCALAR_SIZE];
173 h_bytes.copy_from_slice(hash_output.as_ref());
174 let z = reduce_bytes_to_scalar(&h_bytes)?;
175
176 let d = secret_key.raw.clone();
178
179 let mut rng = rand::thread_rng();
181
182 loop {
183 let k = deterministic_k_hedged(&d, &z, &mut rng);
185
186 let kg = ec::scalar_mult_base_g(&k).map_err(ApiError::from)?;
188 let r_bytes = kg.x_coordinate_bytes();
189
190 let r = match reduce_bytes_to_scalar(&r_bytes) {
192 Ok(scalar) => scalar,
193 Err(_) => continue, };
195
196 let k_inv = k.inv_mod_n().map_err(ApiError::from)?;
198
199 let rd = r.mul_mod_n(&d).map_err(ApiError::from)?;
201
202 let z_plus_rd = z.add_mod_n(&rd).map_err(ApiError::from)?;
203
204 let s = k_inv.mul_mod_n(&z_plus_rd).map_err(ApiError::from)?;
205
206 if s.is_zero() {
208 continue;
209 }
210
211 let sig = SignatureComponents {
213 r: r.serialize().to_vec(),
214 s: s.serialize().to_vec(),
215 };
216
217 let der_sig = sig.to_der();
219
220 return Ok(EcdsaP384Signature(der_sig));
221 }
222 }
223
224 fn verify(
240 message: &[u8],
241 signature: &Self::SignatureData,
242 public_key: &Self::PublicKey,
243 ) -> ApiResult<()> {
244 let sig = SignatureComponents::from_der(&signature.0)?;
246
247 if sig.r.len() > ec::P384_SCALAR_SIZE || sig.s.len() > ec::P384_SCALAR_SIZE {
249 return Err(ApiError::InvalidSignature {
250 context: "ECDSA-P384 verify",
251 #[cfg(feature = "std")]
252 message: "Invalid signature component size".to_string(),
253 });
254 }
255
256 let mut r_bytes = [0u8; ec::P384_SCALAR_SIZE];
258 let mut s_bytes = [0u8; ec::P384_SCALAR_SIZE];
259 r_bytes[ec::P384_SCALAR_SIZE - sig.r.len()..].copy_from_slice(&sig.r);
260 s_bytes[ec::P384_SCALAR_SIZE - sig.s.len()..].copy_from_slice(&sig.s);
261
262 let r = ec::Scalar::new(r_bytes).map_err(|_| ApiError::InvalidSignature {
263 context: "ECDSA-P384 verify",
264 #[cfg(feature = "std")]
265 message: "Invalid r component".to_string(),
266 })?;
267
268 let s = ec::Scalar::new(s_bytes).map_err(|_| ApiError::InvalidSignature {
269 context: "ECDSA-P384 verify",
270 #[cfg(feature = "std")]
271 message: "Invalid s component".to_string(),
272 })?;
273
274 let mut hasher = Sha384::new();
276 hasher.update(message).map_err(ApiError::from)?;
277 let hash_output = hasher.finalize().map_err(ApiError::from)?;
278
279 let mut h_bytes = [0u8; ec::P384_SCALAR_SIZE];
281 h_bytes.copy_from_slice(hash_output.as_ref());
282 let z = reduce_bytes_to_scalar(&h_bytes)?;
283
284 let s_inv = s.inv_mod_n().map_err(ApiError::from)?;
286
287 let u1 = z.mul_mod_n(&s_inv).map_err(ApiError::from)?;
289 let u2 = r.mul_mod_n(&s_inv).map_err(ApiError::from)?;
290
291 let q = ec::Point::deserialize_uncompressed(&public_key.0).map_err(ApiError::from)?;
293
294 let u1g = ec::scalar_mult_base_g(&u1).map_err(ApiError::from)?;
296
297 let u2q = ec::scalar_mult(&u2, &q).map_err(ApiError::from)?;
298
299 let point = u1g.add(&u2q);
300
301 if point.is_identity() {
303 return Err(ApiError::InvalidSignature {
304 context: "ECDSA-P384 verify",
305 #[cfg(feature = "std")]
306 message: "Invalid signature: verification point is identity".to_string(),
307 });
308 }
309
310 let x1_bytes = point.x_coordinate_bytes();
312 let x1 = reduce_bytes_to_scalar(&x1_bytes)?;
313
314 if !ct_eq(r.serialize(), x1.serialize()) {
316 return Err(ApiError::InvalidSignature {
317 context: "ECDSA-P384 verify",
318 #[cfg(feature = "std")]
319 message: "Signature verification failed".to_string(),
320 });
321 }
322
323 Ok(())
324 }
325}
326
327fn deterministic_k_hedged<R: RngCore + CryptoRng>(
338 d: &ec::Scalar,
339 z: &ec::Scalar,
340 rng: &mut R,
341) -> ec::Scalar {
342 use zeroize::Zeroize;
343
344 let mut rbuf = [0u8; 48];
345 rng.fill_bytes(&mut rbuf); let mut v = [0x01u8; 48];
348 let mut k = [0x00u8; 48];
349
350 {
353 let mut mac = Hmac::<Sha384>::new(&k).unwrap();
354 mac.update(&v).unwrap();
355 mac.update(&[0x00]).unwrap();
356 mac.update(&d.serialize()).unwrap();
357 mac.update(&z.serialize()).unwrap();
358 mac.update(&rbuf).unwrap();
359 k.copy_from_slice(&mac.finalize().unwrap());
360 }
361
362 let v_new = Hmac::<Sha384>::mac(&k, &v).unwrap();
365 v.copy_from_slice(&v_new);
366
367 {
370 let mut mac = Hmac::<Sha384>::new(&k).unwrap();
371 mac.update(&v).unwrap();
372 mac.update(&[0x01]).unwrap();
373 mac.update(&d.serialize()).unwrap();
374 mac.update(&z.serialize()).unwrap();
375 mac.update(&rbuf).unwrap();
376 k.copy_from_slice(&mac.finalize().unwrap());
377 }
378
379 let v_new = Hmac::<Sha384>::mac(&k, &v).unwrap();
382 v.copy_from_slice(&v_new);
383
384 loop {
387 let v_new = Hmac::<Sha384>::mac(&k, &v).unwrap();
388 v.copy_from_slice(&v_new);
389
390 if let Ok(candidate) = ec::Scalar::new(v) {
392 if !candidate.is_zero() {
393 rbuf.zeroize(); return candidate;
395 }
396 }
397
398 let mut mac = Hmac::<Sha384>::new(&k).unwrap();
400 mac.update(&v).unwrap();
401 mac.update(&[0x00]).unwrap();
402 k.copy_from_slice(&mac.finalize().unwrap());
403 let v_new = Hmac::<Sha384>::mac(&k, &v).unwrap();
404 v.copy_from_slice(&v_new);
405 }
406}
407
408const N_BE: [u8; 48] = [
414 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
415 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
416 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73,
417];
418
419fn ge_be(a: &[u8], b: &[u8]) -> bool {
421 for (&ai, &bi) in a.iter().zip(b) {
422 if ai > bi {
423 return true;
424 }
425 if ai < bi {
426 return false;
427 }
428 }
429 true
430}
431
432fn sub_mod_n(candidate: &mut [u8], n_be: &[u8]) {
434 let mut borrow = 0u16;
435 for i in (0..candidate.len()).rev() {
436 let tmp = (candidate[i] as i16) - (n_be[i] as i16) - (borrow as i16);
437 if tmp < 0 {
438 candidate[i] = (tmp + 256) as u8;
439 borrow = 1;
440 } else {
441 candidate[i] = tmp as u8;
442 borrow = 0;
443 }
444 }
445}
446
447fn reduce_bytes_to_scalar(bytes: &[u8; 48]) -> ApiResult<ec::Scalar> {
452 let mut candidate = *bytes;
453
454 while ge_be(&candidate, &N_BE) {
456 sub_mod_n(&mut candidate, &N_BE);
457 }
458
459 ec::Scalar::new(candidate).map_err(ApiError::from)
460}
461
462#[cfg(test)]
463mod tests;