1use crate::ecdsa::common::SignatureComponents;
8use dcrypt_algorithms::ec::p521 as ec;
9use dcrypt_algorithms::hash::sha2::Sha512;
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 EcdsaP521;
22
23#[derive(Clone, Zeroize)]
27pub struct EcdsaP521PublicKey(pub [u8; ec::P521_POINT_UNCOMPRESSED_SIZE]);
28
29#[derive(Clone)]
35pub struct EcdsaP521SecretKey {
36 raw: ec::Scalar,
37 bytes: [u8; ec::P521_SCALAR_SIZE],
38}
39
40impl Zeroize for EcdsaP521SecretKey {
42 fn zeroize(&mut self) {
43 self.bytes.zeroize();
45 }
48}
49
50impl Drop for EcdsaP521SecretKey {
52 fn drop(&mut self) {
53 self.zeroize();
54 }
55}
56
57#[derive(Clone)]
61pub struct EcdsaP521Signature(pub Vec<u8>);
62
63impl AsRef<[u8]> for EcdsaP521PublicKey {
65 fn as_ref(&self) -> &[u8] {
66 &self.0
67 }
68}
69
70impl AsMut<[u8]> for EcdsaP521PublicKey {
71 fn as_mut(&mut self) -> &mut [u8] {
72 &mut self.0
73 }
74}
75
76impl AsRef<[u8]> for EcdsaP521SecretKey {
77 fn as_ref(&self) -> &[u8] {
78 &self.bytes
79 }
80}
81
82impl AsRef<[u8]> for EcdsaP521Signature {
88 fn as_ref(&self) -> &[u8] {
89 &self.0
90 }
91}
92
93impl AsMut<[u8]> for EcdsaP521Signature {
94 fn as_mut(&mut self) -> &mut [u8] {
95 &mut self.0
96 }
97}
98
99impl SignatureTrait for EcdsaP521 {
100 type PublicKey = EcdsaP521PublicKey;
101 type SecretKey = EcdsaP521SecretKey;
102 type SignatureData = EcdsaP521Signature;
103 type KeyPair = (Self::PublicKey, Self::SecretKey);
104
105 fn name() -> &'static str {
106 "ECDSA-P521"
107 }
108
109 fn keypair<R: CryptoRng + RngCore>(rng: &mut R) -> ApiResult<Self::KeyPair> {
116 let (sk_scalar, pk_point) = ec::generate_keypair(rng).map_err(ApiError::from)?;
118
119 let sk_bytes: [u8; ec::P521_SCALAR_SIZE] = sk_scalar.serialize();
121
122 if sk_bytes.iter().all(|&b| b == 0) {
124 return Err(ApiError::InvalidParameter {
125 context: "ECDSA-P521 keypair",
126 #[cfg(feature = "std")]
127 message: "Generated secret key is zero (internal error)".to_string(),
128 });
129 }
130
131 let secret_key = EcdsaP521SecretKey {
133 raw: sk_scalar,
134 bytes: sk_bytes,
135 };
136
137 let public_key = EcdsaP521PublicKey(pk_point.serialize_uncompressed());
139
140 Ok((public_key, secret_key))
141 }
142
143 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
144 keypair.0.clone()
145 }
146
147 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
148 keypair.1.clone()
149 }
150
151 fn sign(message: &[u8], secret_key: &Self::SecretKey) -> ApiResult<Self::SignatureData> {
166 let mut hasher = Sha512::new();
168 hasher.update(message).map_err(ApiError::from)?;
169 let hash_output = hasher.finalize().map_err(ApiError::from)?;
170
171 let mut z_bytes = [0u8; ec::P521_SCALAR_SIZE];
175 z_bytes[ec::P521_SCALAR_SIZE - 64..].copy_from_slice(hash_output.as_ref());
177 let z = reduce_bytes_to_scalar(&z_bytes)?;
178
179 let d = secret_key.raw.clone();
181
182 let mut rng = rand::thread_rng();
184
185 loop {
186 let k = deterministic_k_hedged(&d, &z, &mut rng);
188
189 let kg = ec::scalar_mult_base_g(&k).map_err(ApiError::from)?;
191 let r_bytes = kg.x_coordinate_bytes();
192
193 let r = match reduce_bytes_to_scalar(&r_bytes) {
195 Ok(scalar) => scalar,
196 Err(_) => continue, };
198
199 let k_inv = k.inv_mod_n().map_err(ApiError::from)?;
201
202 let rd = r.mul_mod_n(&d).map_err(ApiError::from)?;
204
205 let z_plus_rd = z.add_mod_n(&rd).map_err(ApiError::from)?;
206
207 let s = k_inv.mul_mod_n(&z_plus_rd).map_err(ApiError::from)?;
208
209 if s.is_zero() {
211 continue;
212 }
213
214 let sig = SignatureComponents {
216 r: r.serialize().to_vec(),
217 s: s.serialize().to_vec(),
218 };
219
220 let der_sig = sig.to_der();
222
223 return Ok(EcdsaP521Signature(der_sig));
224 }
225 }
226
227 fn verify(
243 message: &[u8],
244 signature: &Self::SignatureData,
245 public_key: &Self::PublicKey,
246 ) -> ApiResult<()> {
247 let sig = SignatureComponents::from_der(&signature.0)?;
249
250 if sig.r.len() > ec::P521_SCALAR_SIZE || sig.s.len() > ec::P521_SCALAR_SIZE {
252 return Err(ApiError::InvalidSignature {
253 context: "ECDSA-P521 verify",
254 #[cfg(feature = "std")]
255 message: "Invalid signature component size".to_string(),
256 });
257 }
258
259 let mut r_bytes = [0u8; ec::P521_SCALAR_SIZE];
261 let mut s_bytes = [0u8; ec::P521_SCALAR_SIZE];
262 r_bytes[ec::P521_SCALAR_SIZE - sig.r.len()..].copy_from_slice(&sig.r);
263 s_bytes[ec::P521_SCALAR_SIZE - sig.s.len()..].copy_from_slice(&sig.s);
264
265 let r = ec::Scalar::new(r_bytes).map_err(|_| ApiError::InvalidSignature {
266 context: "ECDSA-P521 verify",
267 #[cfg(feature = "std")]
268 message: "Invalid r component".to_string(),
269 })?;
270
271 let s = ec::Scalar::new(s_bytes).map_err(|_| ApiError::InvalidSignature {
272 context: "ECDSA-P521 verify",
273 #[cfg(feature = "std")]
274 message: "Invalid s component".to_string(),
275 })?;
276
277 let mut hasher = Sha512::new();
279 hasher.update(message).map_err(ApiError::from)?;
280 let hash_output = hasher.finalize().map_err(ApiError::from)?;
281
282 let mut z_bytes = [0u8; ec::P521_SCALAR_SIZE];
284 z_bytes[ec::P521_SCALAR_SIZE - 64..].copy_from_slice(hash_output.as_ref());
285 let z = reduce_bytes_to_scalar(&z_bytes)?;
286
287 let s_inv = s.inv_mod_n().map_err(ApiError::from)?;
289
290 let u1 = z.mul_mod_n(&s_inv).map_err(ApiError::from)?;
292 let u2 = r.mul_mod_n(&s_inv).map_err(ApiError::from)?;
293
294 let q = ec::Point::deserialize_uncompressed(&public_key.0).map_err(ApiError::from)?;
296
297 let u1g = ec::scalar_mult_base_g(&u1).map_err(ApiError::from)?;
299
300 let u2q = ec::scalar_mult(&u2, &q).map_err(ApiError::from)?;
301
302 let point = u1g.add(&u2q);
303
304 if point.is_identity() {
306 return Err(ApiError::InvalidSignature {
307 context: "ECDSA-P521 verify",
308 #[cfg(feature = "std")]
309 message: "Invalid signature: verification point is identity".to_string(),
310 });
311 }
312
313 let x1_bytes = point.x_coordinate_bytes();
315 let x1 = reduce_bytes_to_scalar(&x1_bytes)?;
316
317 if !ct_eq(r.serialize(), x1.serialize()) {
319 return Err(ApiError::InvalidSignature {
320 context: "ECDSA-P521 verify",
321 #[cfg(feature = "std")]
322 message: "Signature verification failed".to_string(),
323 });
324 }
325
326 Ok(())
327 }
328}
329
330fn deterministic_k_hedged<R: RngCore + CryptoRng>(
341 d: &ec::Scalar,
342 z: &ec::Scalar,
343 rng: &mut R,
344) -> ec::Scalar {
345 use zeroize::Zeroize;
346
347 let mut rbuf = [0u8; 66];
348 rng.fill_bytes(&mut rbuf); let mut v = [0x01u8; 128];
352 let mut k = [0x00u8; 128];
353
354 {
357 let mut mac = Hmac::<Sha512>::new(&k).unwrap();
358 mac.update(&v).unwrap();
359 mac.update(&[0x00]).unwrap();
360 mac.update(&d.serialize()).unwrap();
361 mac.update(&z.serialize()).unwrap();
362 mac.update(&rbuf).unwrap();
363 let mac_output = mac.finalize().unwrap();
364 k[..64].copy_from_slice(&mac_output);
366 k[64..].fill(0);
367 }
368
369 let v_new = Hmac::<Sha512>::mac(&k, &v).unwrap();
372 v[..64].copy_from_slice(&v_new);
373 v[64..].fill(0);
374
375 {
378 let mut mac = Hmac::<Sha512>::new(&k).unwrap();
379 mac.update(&v).unwrap();
380 mac.update(&[0x01]).unwrap();
381 mac.update(&d.serialize()).unwrap();
382 mac.update(&z.serialize()).unwrap();
383 mac.update(&rbuf).unwrap();
384 let mac_output = mac.finalize().unwrap();
385 k[..64].copy_from_slice(&mac_output);
386 k[64..].fill(0);
387 }
388
389 let v_new = Hmac::<Sha512>::mac(&k, &v).unwrap();
392 v[..64].copy_from_slice(&v_new);
393 v[64..].fill(0);
394
395 loop {
398 let v_new = Hmac::<Sha512>::mac(&k, &v).unwrap();
399 v[..64].copy_from_slice(&v_new);
400 v[64..].fill(0);
401
402 let mut candidate_bytes = [0u8; 66];
404 candidate_bytes.copy_from_slice(&v[..66]);
405
406 if let Ok(candidate) = ec::Scalar::new(candidate_bytes) {
407 if !candidate.is_zero() {
408 rbuf.zeroize(); return candidate;
410 }
411 }
412
413 let mut mac = Hmac::<Sha512>::new(&k).unwrap();
415 mac.update(&v).unwrap();
416 mac.update(&[0x00]).unwrap();
417 let mac_output = mac.finalize().unwrap();
418 k[..64].copy_from_slice(&mac_output);
419 k[64..].fill(0);
420
421 let v_new = Hmac::<Sha512>::mac(&k, &v).unwrap();
422 v[..64].copy_from_slice(&v_new);
423 v[64..].fill(0);
424 }
425}
426
427const N_BE: [u8; 66] = [
433 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
434 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
435 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
436 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
437 0x64, 0x09,
438];
439
440fn ge_be(a: &[u8], b: &[u8]) -> bool {
442 for (&ai, &bi) in a.iter().zip(b) {
443 if ai > bi {
444 return true;
445 }
446 if ai < bi {
447 return false;
448 }
449 }
450 true
451}
452
453fn sub_mod_n(candidate: &mut [u8], n_be: &[u8]) {
455 let mut borrow = 0u16;
456 for i in (0..candidate.len()).rev() {
457 let tmp = (candidate[i] as i16) - (n_be[i] as i16) - (borrow as i16);
458 if tmp < 0 {
459 candidate[i] = (tmp + 256) as u8;
460 borrow = 1;
461 } else {
462 candidate[i] = tmp as u8;
463 borrow = 0;
464 }
465 }
466}
467
468fn reduce_bytes_to_scalar(bytes: &[u8; 66]) -> ApiResult<ec::Scalar> {
473 let mut candidate = *bytes;
474
475 while ge_be(&candidate, &N_BE) {
477 sub_mod_n(&mut candidate, &N_BE);
478 }
479
480 ec::Scalar::new(candidate).map_err(ApiError::from)
481}
482
483#[cfg(test)]
484mod tests;