dcrypt_sign/eddsa/ed25519/
mod.rs1use super::constants::{ED25519_PUBLIC_KEY_SIZE, ED25519_SECRET_KEY_SIZE, ED25519_SIGNATURE_SIZE};
7use dcrypt_algorithms::hash::sha2::Sha512;
8use dcrypt_algorithms::hash::HashFunction;
9use dcrypt_api::{error::Error as ApiError, Result as ApiResult, Signature as SignatureTrait};
10use dcrypt_internal::constant_time::ct_eq;
11use rand::{CryptoRng, RngCore};
12use zeroize::{Zeroize, Zeroizing};
13
14use super::operations;
16
17pub struct Ed25519;
27
28#[derive(Clone, Zeroize)]
36pub struct Ed25519PublicKey(pub [u8; ED25519_PUBLIC_KEY_SIZE]);
37
38impl core::fmt::Debug for Ed25519PublicKey {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 f.debug_struct("Ed25519PublicKey")
42 .field("algorithm", &"Ed25519")
43 .finish()
44 }
45}
46
47#[derive(Clone)]
60pub struct Ed25519SecretKey {
61 seed: [u8; ED25519_SECRET_KEY_SIZE],
63 expanded: [u8; 64],
65}
66
67impl Zeroize for Ed25519SecretKey {
68 fn zeroize(&mut self) {
69 self.seed.zeroize();
70 self.expanded.zeroize();
71 }
72}
73
74impl Drop for Ed25519SecretKey {
75 fn drop(&mut self) {
76 self.zeroize();
77 }
78}
79
80impl core::fmt::Debug for Ed25519SecretKey {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 f.debug_struct("Ed25519SecretKey")
84 .field("algorithm", &"Ed25519")
85 .finish()
86 }
87}
88
89#[derive(Clone, Zeroize)]
91pub struct Ed25519Signature(pub [u8; ED25519_SIGNATURE_SIZE]);
92
93impl core::fmt::Debug for Ed25519Signature {
94 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95 f.debug_struct("Ed25519Signature")
96 .field("length", &self.0.len())
97 .finish()
98 }
99}
100
101impl Ed25519PublicKey {
103 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
105 if bytes.len() != ED25519_PUBLIC_KEY_SIZE {
106 return Err(ApiError::InvalidKey {
107 context: "Ed25519PublicKey::from_bytes",
108 #[cfg(feature = "std")]
109 message: format!("Invalid key size: expected {}, got {}", ED25519_PUBLIC_KEY_SIZE, bytes.len()),
110 });
111 }
112 let mut key = [0u8; ED25519_PUBLIC_KEY_SIZE];
113 key.copy_from_slice(bytes);
114 Ok(Ed25519PublicKey(key))
115 }
116
117 pub fn to_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] {
119 self.0
120 }
121}
122
123impl Ed25519SecretKey {
125 pub fn from_seed(seed: &[u8; ED25519_SECRET_KEY_SIZE]) -> ApiResult<Self> {
160 let mut hasher = Sha512::new();
162 hasher.update(seed).map_err(ApiError::from)?;
163 let hash = hasher.finalize().map_err(ApiError::from)?;
164
165 let mut expanded = [0u8; 64];
166 expanded.copy_from_slice(hash.as_ref());
167
168 expanded[0] &= 248; expanded[31] &= 127; expanded[31] |= 64; Ok(Ed25519SecretKey {
174 seed: *seed,
175 expanded,
176 })
177 }
178
179 pub fn seed(&self) -> &[u8; ED25519_SECRET_KEY_SIZE] {
191 &self.seed
192 }
193
194 pub fn export_seed(&self) -> Zeroizing<Vec<u8>> {
196 Zeroizing::new(self.seed.to_vec())
197 }
198
199 pub fn public_key(&self) -> ApiResult<Ed25519PublicKey> {
227 Ed25519::derive_public_from_secret(self)
228 }
229}
230
231impl Ed25519Signature {
233 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
235 if bytes.len() != ED25519_SIGNATURE_SIZE {
236 return Err(ApiError::InvalidSignature {
237 context: "Ed25519Signature::from_bytes",
238 #[cfg(feature = "std")]
239 message: format!("Invalid signature size: expected {}, got {}", ED25519_SIGNATURE_SIZE, bytes.len()),
240 });
241 }
242 let mut sig = [0u8; ED25519_SIGNATURE_SIZE];
243 sig.copy_from_slice(bytes);
244 Ok(Ed25519Signature(sig))
245 }
246
247 pub fn to_bytes(&self) -> [u8; ED25519_SIGNATURE_SIZE] {
249 self.0
250 }
251}
252
253impl SignatureTrait for Ed25519 {
254 type PublicKey = Ed25519PublicKey;
255 type SecretKey = Ed25519SecretKey;
256 type SignatureData = Ed25519Signature;
257 type KeyPair = (Self::PublicKey, Self::SecretKey);
258
259 fn name() -> &'static str {
260 "Ed25519"
261 }
262
263 fn keypair<R: CryptoRng + RngCore>(rng: &mut R) -> ApiResult<Self::KeyPair> {
271 let mut seed = [0u8; ED25519_SECRET_KEY_SIZE];
273 rng.fill_bytes(&mut seed);
274
275 let mut hasher = Sha512::new();
277 hasher.update(&seed).map_err(ApiError::from)?;
278 let hash = hasher.finalize().map_err(ApiError::from)?;
279
280 let mut expanded = [0u8; 64];
281 expanded.copy_from_slice(hash.as_ref());
282
283 expanded[0] &= 248; expanded[31] &= 127; expanded[31] |= 64; let mut public_key = [0u8; ED25519_PUBLIC_KEY_SIZE];
290 operations::derive_public_key(&expanded[0..32], &mut public_key).map_err(|e| {
291 ApiError::InvalidParameter {
292 context: "Ed25519 keypair generation",
293 #[cfg(feature = "std")]
294 message: format!("Failed to derive public key: {}", e),
295 }
296 })?;
297
298 Ok((
299 Ed25519PublicKey(public_key),
300 Ed25519SecretKey { seed, expanded },
301 ))
302 }
303
304 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
305 keypair.0.clone()
306 }
307
308 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
309 keypair.1.clone()
310 }
311
312 fn sign(message: &[u8], secret_key: &Self::SecretKey) -> ApiResult<Self::SignatureData> {
321 let scalar = &secret_key.expanded[0..32];
323 let prefix = &secret_key.expanded[32..64];
324
325 let mut hasher = Sha512::new();
327 hasher.update(prefix).map_err(ApiError::from)?;
328 hasher.update(message).map_err(ApiError::from)?;
329 let r_hash = hasher.finalize().map_err(ApiError::from)?;
330
331 let mut r = [0u8; 32];
332 operations::reduce_512_to_scalar(r_hash.as_ref(), &mut r);
333
334 let r_point = operations::scalar_mult_base(&r);
336
337 let mut public_key = [0u8; 32];
339 operations::derive_public_key(scalar, &mut public_key).map_err(|e| {
340 ApiError::InvalidParameter {
341 context: "Ed25519 signing",
342 #[cfg(feature = "std")]
343 message: format!("Failed to derive public key: {}", e),
344 }
345 })?;
346
347 let mut hasher = Sha512::new();
349 hasher.update(&r_point).map_err(ApiError::from)?;
350 hasher.update(&public_key).map_err(ApiError::from)?;
351 hasher.update(message).map_err(ApiError::from)?;
352 let k_hash = hasher.finalize().map_err(ApiError::from)?;
353
354 let mut k = [0u8; 32];
355 operations::reduce_512_to_scalar(k_hash.as_ref(), &mut k);
356
357 let mut s = [0u8; 32];
359 operations::compute_s(&r, &k, scalar, &mut s);
360
361 let mut signature = [0u8; ED25519_SIGNATURE_SIZE];
363 signature[0..32].copy_from_slice(&r_point);
364 signature[32..64].copy_from_slice(&s);
365
366 Ok(Ed25519Signature(signature))
367 }
368
369 fn verify(
375 message: &[u8],
376 signature: &Self::SignatureData,
377 public_key: &Self::PublicKey,
378 ) -> ApiResult<()> {
379 if public_key.0.len() != ED25519_PUBLIC_KEY_SIZE {
381 return Err(ApiError::InvalidKey {
382 context: "Ed25519 verify",
383 #[cfg(feature = "std")]
384 message: "Invalid public key size".to_string(),
385 });
386 }
387
388 if signature.0.len() != ED25519_SIGNATURE_SIZE {
389 return Err(ApiError::InvalidSignature {
390 context: "Ed25519 verify",
391 #[cfg(feature = "std")]
392 message: "Invalid signature size".to_string(),
393 });
394 }
395
396 let r_bytes = &signature.0[0..32];
398 let s_bytes = &signature.0[32..64];
399
400 if s_bytes.iter().all(|&b| b == 0) {
402 return Err(ApiError::InvalidSignature {
403 context: "Ed25519 verify",
404 #[cfg(feature = "std")]
405 message: "Invalid s value in signature (all zeros)".to_string(),
406 });
407 }
408
409 let mut hasher = Sha512::new();
411 hasher.update(r_bytes).map_err(ApiError::from)?;
412 hasher.update(&public_key.0).map_err(ApiError::from)?;
413 hasher.update(message).map_err(ApiError::from)?;
414 let k_hash = hasher.finalize().map_err(ApiError::from)?;
415
416 let mut k = [0u8; 32];
417 operations::reduce_512_to_scalar(k_hash.as_ref(), &mut k);
418
419 let mut check = [0u8; 32];
421 operations::verify_equation(s_bytes, r_bytes, &k, &public_key.0, &mut check).map_err(
422 |e| ApiError::InvalidSignature {
423 context: "Ed25519 verify",
424 #[cfg(feature = "std")]
425 message: format!("Signature verification failed: {}", e),
426 },
427 )?;
428
429 if !ct_eq(check, [1u8; 32]) {
431 return Err(ApiError::InvalidSignature {
432 context: "Ed25519 verify",
433 #[cfg(feature = "std")]
434 message: "Signature verification equation failed".to_string(),
435 });
436 }
437
438 Ok(())
439 }
440}
441
442impl Ed25519 {
443 pub fn derive_public_from_secret(
467 secret_key: &Ed25519SecretKey
468 ) -> ApiResult<Ed25519PublicKey> {
469 let scalar = &secret_key.expanded[0..32];
471
472 let mut public_key_bytes = [0u8; ED25519_PUBLIC_KEY_SIZE];
474 operations::derive_public_key(scalar, &mut public_key_bytes)
475 .map_err(|e| ApiError::InvalidParameter {
476 context: "Ed25519::derive_public_from_secret",
477 #[cfg(feature = "std")]
478 message: format!("Failed to derive public key: {}", e),
479 })?;
480
481 Ok(Ed25519PublicKey(public_key_bytes))
482 }
483}
484
485#[cfg(feature = "serialization")]
487use dcrypt_api::SignatureSerialize;
488
489#[cfg(feature = "serialization")]
490impl SignatureSerialize for Ed25519 {
491 const PUBLIC_KEY_SIZE: usize = ED25519_PUBLIC_KEY_SIZE;
492 const SECRET_KEY_SIZE: usize = ED25519_SECRET_KEY_SIZE;
493 const SIGNATURE_SIZE: usize = ED25519_SIGNATURE_SIZE;
494
495 fn serialize_public_key(key: &Self::PublicKey) -> Vec<u8> {
496 key.0.to_vec()
497 }
498
499 fn deserialize_public_key(bytes: &[u8]) -> ApiResult<Self::PublicKey> {
500 Ed25519PublicKey::from_bytes(bytes)
501 }
502
503 fn serialize_secret_key(key: &Self::SecretKey) -> Zeroizing<Vec<u8>> {
504 key.export_seed()
505 }
506
507 fn deserialize_secret_key(bytes: &[u8]) -> ApiResult<Self::SecretKey> {
508 if bytes.len() != ED25519_SECRET_KEY_SIZE {
509 return Err(ApiError::InvalidKey {
510 context: "Ed25519::deserialize_secret_key",
511 #[cfg(feature = "std")]
512 message: format!("Invalid seed size: expected {}, got {}", ED25519_SECRET_KEY_SIZE, bytes.len()),
513 });
514 }
515 let mut seed = [0u8; ED25519_SECRET_KEY_SIZE];
516 seed.copy_from_slice(bytes);
517 Ed25519SecretKey::from_seed(&seed)
518 }
519
520 fn serialize_signature(sig: &Self::SignatureData) -> Vec<u8> {
521 sig.0.to_vec()
522 }
523
524 fn deserialize_signature(bytes: &[u8]) -> ApiResult<Self::SignatureData> {
525 Ed25519Signature::from_bytes(bytes)
526 }
527}
528
529#[cfg(feature = "key_derivation")]
531use dcrypt_api::SignatureDerive;
532
533#[cfg(feature = "key_derivation")]
534impl SignatureDerive for Ed25519 {
535 const MIN_SEED_SIZE: usize = ED25519_SECRET_KEY_SIZE;
536
537 fn derive_keypair(seed: &[u8]) -> ApiResult<Self::KeyPair> {
538 if seed.len() < Self::MIN_SEED_SIZE {
539 return Err(ApiError::InvalidParameter {
540 context: "Ed25519::derive_keypair",
541 #[cfg(feature = "std")]
542 message: format!("Seed too short: minimum {} bytes required", Self::MIN_SEED_SIZE),
543 });
544 }
545
546 let mut seed_array = [0u8; ED25519_SECRET_KEY_SIZE];
547 seed_array.copy_from_slice(&seed[..ED25519_SECRET_KEY_SIZE]);
548
549 let secret = Ed25519SecretKey::from_seed(&seed_array)?;
550 let public = secret.public_key()?;
551 Ok((public, secret))
552 }
553
554 fn derive_public_key(secret_key: &Self::SecretKey) -> ApiResult<Self::PublicKey> {
555 secret_key.public_key()
556 }
557}
558
559#[cfg(test)]
560mod tests;