1#[cfg(feature = "alloc")]
100use alloc::vec::Vec;
101use core::fmt;
102
103#[cfg(feature = "serde")]
104use serde::{Deserialize, Serialize};
105use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
106
107use crate::classic::crypto_sign::{
108 SignerState, crypto_sign_ed25519_sk_to_pk, crypto_sign_ed25519_sk_to_seed,
109 crypto_sign_final_verify, crypto_sign_init, crypto_sign_keypair_inplace,
110 crypto_sign_seed_keypair_inplace, crypto_sign_update, crypto_sign_verify_detached,
111};
112use crate::classic::crypto_sign_ed25519::{
113 crypto_sign_ed25519_detached, crypto_sign_ed25519ph_final_create,
114};
115use crate::constants::{
116 CRYPTO_SIGN_BYTES, CRYPTO_SIGN_PUBLICKEYBYTES, CRYPTO_SIGN_SECRETKEYBYTES,
117 CRYPTO_SIGN_SEEDBYTES,
118};
119use crate::error::{Error, ErrorContext};
120use crate::types::*;
121use crate::utils::{ct_eq_bytes, split_prefix};
122
123pub type PublicKey = StackByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
125pub type SecretKey = StackByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
127pub type Seed = StackByteArray<CRYPTO_SIGN_SEEDBYTES>;
129pub type Signature = StackByteArray<CRYPTO_SIGN_BYTES>;
131#[cfg(feature = "alloc")]
133pub type Message = Vec<u8>;
134pub type StackSigningKeyPair = SigningKeyPair<PublicKey, SecretKey>;
136
137#[must_use]
152pub fn is_valid_public_key<PK: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(key: &PK) -> bool {
153 crate::classic::crypto_core::crypto_core_ed25519_is_valid_point(key.as_array())
154}
155
156#[must_use]
158pub fn secret_key_to_seed<
159 SeedOut: NewByteArray<CRYPTO_SIGN_SEEDBYTES>,
160 SigningSecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
161>(
162 secret_key: &SigningSecretKey,
163) -> SeedOut {
164 let mut seed = SeedOut::new_byte_array();
165 crypto_sign_ed25519_sk_to_seed(seed.as_mut_array(), secret_key.as_array());
166 seed
167}
168
169#[must_use]
171pub fn secret_key_to_public_key<
172 PublicKeyOut: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
173 SigningSecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
174>(
175 secret_key: &SigningSecretKey,
176) -> PublicKeyOut {
177 let mut public_key = PublicKeyOut::new_byte_array();
178 crypto_sign_ed25519_sk_to_pk(public_key.as_mut_array(), secret_key.as_array());
179 public_key
180}
181
182#[derive(Zeroize, ZeroizeOnDrop, Clone)]
183#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
184pub struct SigningKeyPair<
191 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
192 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
193> {
194 pub public_key: PublicKey,
196 pub secret_key: SecretKey,
198}
199
200impl<
201 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
202 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
203> fmt::Debug for SigningKeyPair<PublicKey, SecretKey>
204{
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("SigningKeyPair")
207 .field("public_key", &"[REDACTED]")
208 .field("secret_key", &"[REDACTED]")
209 .finish()
210 }
211}
212
213impl<
214 PublicKey: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
215 SecretKey: NewByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
216> SigningKeyPair<PublicKey, SecretKey>
217{
218 #[must_use]
220 pub fn generate() -> Self {
221 let mut public_key = PublicKey::new_byte_array();
222 let mut secret_key = SecretKey::new_byte_array();
223 crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
224 Self {
225 public_key,
226 secret_key,
227 }
228 }
229
230 #[must_use]
234 pub fn from_secret_key(mut secret_key: SecretKey) -> Self {
235 let mut seed = Zeroizing::new([0u8; 32]);
236 seed.copy_from_slice(&secret_key.as_slice()[..32]);
237 secret_key.zeroize();
238
239 Self::from_seed(&*seed)
240 }
241
242 #[must_use]
245 pub fn from_seed<Seed: ByteArray<CRYPTO_SIGN_SEEDBYTES>>(seed: &Seed) -> Self {
246 let mut public_key = PublicKey::new_byte_array();
247 let mut secret_key = SecretKey::new_byte_array();
248
249 crypto_sign_seed_keypair_inplace(
250 public_key.as_mut_array(),
251 secret_key.as_mut_array(),
252 seed.as_array(),
253 );
254
255 Self {
256 public_key,
257 secret_key,
258 }
259 }
260}
261
262impl<
263 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
264 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
265> SigningKeyPair<PublicKey, SecretKey>
266{
267 #[must_use]
269 pub fn to_seed<SeedOut: NewByteArray<CRYPTO_SIGN_SEEDBYTES>>(&self) -> SeedOut {
270 secret_key_to_seed(&self.secret_key)
271 }
272
273 #[must_use]
275 pub fn to_public_key<PublicKeyOut: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(
276 &self,
277 ) -> PublicKeyOut {
278 secret_key_to_public_key(&self.secret_key)
279 }
280}
281
282impl<
283 'a,
284 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + core::convert::TryFrom<&'a [u8]> + Zeroize,
285 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + core::convert::TryFrom<&'a [u8]> + Zeroize,
286> SigningKeyPair<PublicKey, SecretKey>
287{
288 pub fn from_slices(public_key: &'a [u8], secret_key: &'a [u8]) -> Result<Self, Error> {
296 validate_length!(
297 exact CRYPTO_SIGN_PUBLICKEYBYTES,
298 public_key.len(),
299 crate::ErrorContext::PublicKey
300 );
301 validate_length!(
302 exact CRYPTO_SIGN_SECRETKEYBYTES,
303 secret_key.len(),
304 crate::ErrorContext::SecretKey
305 );
306
307 Ok(Self {
308 public_key: PublicKey::try_from(public_key)
309 .map_err(|_| Error::invalid_key(crate::ErrorContext::PublicKey))?,
310 secret_key: SecretKey::try_from(secret_key)
311 .map_err(|_| Error::invalid_key(crate::ErrorContext::SecretKey))?,
312 })
313 }
314}
315
316#[cfg(any(
317 all(feature = "protected", any(unix, windows)),
318 all(doc, not(doctest), feature = "std")
319))]
320#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
321pub mod protected {
322 use super::*;
355 pub use crate::protected::*;
356
357 pub type PublicKey = HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
360 pub type SecretKey = HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
363 pub type Seed = HeapByteArray<CRYPTO_SIGN_SEEDBYTES>;
366 pub type Signature = HeapByteArray<CRYPTO_SIGN_BYTES>;
369 pub type Message = HeapBytes;
372
373 pub type LockedSigningKeyPair = SigningKeyPair<Locked<PublicKey>, Locked<SecretKey>>;
376 pub type LockedROSigningKeyPair = SigningKeyPair<LockedRO<PublicKey>, LockedRO<SecretKey>>;
379 pub type LockedSignedMessage = SignedMessage<Locked<Signature>, Locked<Message>>;
382
383 impl
384 SigningKeyPair<
385 Locked<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
386 Locked<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
387 >
388 {
389 pub fn generate_locked_keypair() -> Result<Self, Error> {
401 let mut res = Self {
402 public_key: HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?,
403 secret_key: HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?,
404 };
405
406 crypto_sign_keypair_inplace(
407 res.public_key.as_mut_array(),
408 res.secret_key.as_mut_array(),
409 );
410
411 Ok(res)
412 }
413 }
414
415 impl
416 SigningKeyPair<
417 LockedRO<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
418 LockedRO<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
419 >
420 {
421 pub fn generate_readonly_locked_keypair() -> Result<Self, Error> {
434 let mut public_key = HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?;
435 let mut secret_key = HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?;
436
437 crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
438
439 let public_key = public_key.mprotect_readonly()?;
440 let secret_key = secret_key.mprotect_readonly()?;
441
442 Ok(Self {
443 public_key,
444 secret_key,
445 })
446 }
447 }
448}
449
450#[derive(Zeroize, Clone, Debug)]
451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
452pub struct SignedMessage<
454 Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize,
455 Message: Bytes + Zeroize,
456> {
457 signature: Signature,
458 message: Message,
459}
460
461#[cfg(feature = "alloc")]
463pub type VecSignedMessage = SignedMessage<Signature, Vec<u8>>;
464
465impl<
466 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
467 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
468> SigningKeyPair<PublicKey, SecretKey>
469{
470 #[must_use]
474 pub fn sign<Signature: NewByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>(
475 &self,
476 message: Message,
477 ) -> SignedMessage<Signature, Message> {
478 let mut signature = Signature::new_byte_array();
479 crypto_sign_ed25519_detached(
480 signature.as_mut_array(),
481 message.as_slice(),
482 self.secret_key.as_array(),
483 );
484
485 SignedMessage::<Signature, Message> { signature, message }
486 }
487
488 #[cfg(feature = "alloc")]
491 #[must_use]
492 pub fn sign_to_vecbox<Message: Bytes + ?Sized>(&self, message: &Message) -> VecSignedMessage {
493 self.sign(Vec::from(message.as_slice()))
494 }
495}
496
497pub struct Ed25519phSigner {
510 state: SignerState,
511}
512
513impl Ed25519phSigner {
514 #[must_use]
516 pub fn new() -> Self {
517 Self {
518 state: crypto_sign_init(),
519 }
520 }
521
522 pub fn update<Message: Bytes + ?Sized>(&mut self, message: &Message) {
524 crypto_sign_update(&mut self.state, message.as_slice())
525 }
526
527 #[must_use]
530 pub fn finalize<
531 Signature: NewByteArray<CRYPTO_SIGN_BYTES>,
532 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
533 >(
534 self,
535 secret_key: &SecretKey,
536 ) -> Signature {
537 let mut signature = Signature::new_byte_array();
538
539 crypto_sign_ed25519ph_final_create(
540 self.state.state,
541 signature.as_mut_array(),
542 secret_key.as_array(),
543 );
544
545 signature
546 }
547
548 pub fn verify<
557 Signature: ByteArray<CRYPTO_SIGN_BYTES>,
558 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
559 >(
560 self,
561 signature: &Signature,
562 public_key: &PublicKey,
563 ) -> Result<(), Error> {
564 crypto_sign_final_verify(self.state, signature.as_array(), public_key.as_array())?;
565
566 Ok(())
567 }
568}
569
570impl Default for Ed25519phSigner {
571 fn default() -> Self {
572 Self::new()
573 }
574}
575
576impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
577 SignedMessage<Signature, Message>
578{
579 pub fn verify<PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(
586 &self,
587 public_key: &PublicKey,
588 ) -> Result<(), Error> {
589 crypto_sign_verify_detached(
590 self.signature.as_array(),
591 self.message.as_slice(),
592 public_key.as_array(),
593 )
594 }
595}
596
597impl<
598 'a,
599 Signature: ByteArray<CRYPTO_SIGN_BYTES> + core::convert::TryFrom<&'a [u8]> + Zeroize,
600 Message: Bytes + From<&'a [u8]> + Zeroize,
601> SignedMessage<Signature, Message>
602{
603 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
612 let (signature, message) =
613 split_prefix(bytes, CRYPTO_SIGN_BYTES, ErrorContext::SignedMessage)?;
614 Ok(Self {
615 signature: Signature::try_from(signature)
616 .map_err(|_| Error::invalid_encoding(ErrorContext::Signature))?,
617 message: Message::from(message),
618 })
619 }
620}
621
622impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
623 SignedMessage<Signature, Message>
624{
625 #[must_use]
628 pub fn from_parts(signature: Signature, message: Message) -> Self {
629 Self { signature, message }
630 }
631
632 pub fn signature(&self) -> &Signature {
634 &self.signature
635 }
636
637 pub fn message(&self) -> &Message {
639 &self.message
640 }
641
642 #[cfg(feature = "alloc")]
644 #[must_use]
645 pub fn to_vec(&self) -> Vec<u8> {
646 self.to_bytes()
647 }
648
649 #[must_use]
652 pub fn into_parts(self) -> (Signature, Message) {
653 (self.signature, self.message)
654 }
655
656 #[must_use]
658 pub fn to_bytes<Bytes: NewBytes + ResizableBytes>(&self) -> Bytes {
659 concat_bytes(self.signature.as_array(), self.message.as_slice())
660 }
661}
662
663impl<
664 PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
665 SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
666> PartialEq<SigningKeyPair<PublicKey, SecretKey>> for SigningKeyPair<PublicKey, SecretKey>
667{
668 fn eq(&self, other: &Self) -> bool {
669 ct_eq_bytes(self.public_key.as_slice(), other.public_key.as_slice())
670 && ct_eq_bytes(self.secret_key.as_slice(), other.secret_key.as_slice())
671 }
672}
673
674impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
675 PartialEq<SignedMessage<Signature, Message>> for SignedMessage<Signature, Message>
676{
677 fn eq(&self, other: &Self) -> bool {
678 ct_eq_bytes(self.signature.as_slice(), other.signature.as_slice())
679 && ct_eq_bytes(self.message.as_slice(), other.message.as_slice())
680 }
681}
682
683#[cfg(all(test, feature = "alloc"))]
684mod tests {
685 use super::*;
686
687 #[test]
688 fn signing_keypair_debug_redacts_keys_and_secret_key_reconstructs_keypair() {
689 let keypair = StackSigningKeyPair::generate();
690 let debug = format!("{keypair:?}");
691 let reconstructed = SigningKeyPair::from_secret_key(keypair.secret_key.clone());
692
693 assert_eq!(
694 debug,
695 "SigningKeyPair { public_key: \"[REDACTED]\", secret_key: \"[REDACTED]\" }"
696 );
697 assert_eq!(reconstructed, keypair);
698 }
699
700 #[test]
701 fn test_message_signing() {
702 let keypair = StackSigningKeyPair::generate();
703 let message = b"hello my frens";
704
705 let signed_message = keypair.sign_to_vecbox(message);
706
707 signed_message
708 .verify(&keypair.public_key)
709 .expect("verification failed");
710 }
711
712 #[test]
713 fn test_is_valid_public_key() {
714 use crate::edwards25519::test_vectors::{IDENTITY, NONCANONICAL_IDENTITY};
715
716 let keypair = StackSigningKeyPair::generate();
717 assert!(
718 is_valid_public_key(&keypair.public_key),
719 "generated Ed25519 key should pass validation"
720 );
721 let (valid_pk, _) = crate::classic::crypto_sign::crypto_sign_keypair();
722 assert!(
723 is_valid_public_key(&valid_pk),
724 "Ed25519 key from crypto_sign_keypair should pass validation"
725 );
726
727 let mut negative_basepoint =
728 curve25519_dalek::constants::ED25519_BASEPOINT_COMPRESSED.to_bytes();
729 negative_basepoint[31] |= 0x80;
730 assert!(
731 is_valid_public_key(&negative_basepoint),
732 "the Ed25519 x-coordinate sign bit should be accepted"
733 );
734
735 assert!(
736 !is_valid_public_key(&PublicKey::default()),
737 "zero key should be invalid"
738 );
739
740 assert!(
741 !is_valid_public_key(&IDENTITY),
742 "identity element should be invalid"
743 );
744
745 assert!(
746 !is_valid_public_key(&NONCANONICAL_IDENTITY),
747 "noncanonical identity encoding should be invalid"
748 );
749
750 let mut mixed_order = [0x99; CRYPTO_SIGN_PUBLICKEYBYTES];
751 mixed_order[0] = 0x95;
752 assert!(
753 !is_valid_public_key(&mixed_order),
754 "mixed-order Ed25519 key should fail the prime-subgroup policy"
755 );
756 }
757
758 #[test]
759 fn test_secret_key_extraction() {
760 let seed = Seed::generate();
761 let keypair = StackSigningKeyPair::from_seed(&seed);
762
763 let extracted_seed: Seed = keypair.to_seed();
764 let extracted_public_key: PublicKey = keypair.to_public_key();
765 assert_eq!(extracted_seed, seed);
766 assert_eq!(extracted_public_key, keypair.public_key);
767
768 let extracted_seed_array: [u8; CRYPTO_SIGN_SEEDBYTES] =
769 secret_key_to_seed(&keypair.secret_key);
770 let extracted_public_key_array: [u8; CRYPTO_SIGN_PUBLICKEYBYTES] =
771 secret_key_to_public_key(&keypair.secret_key);
772 assert_eq!(&extracted_seed_array, seed.as_array());
773 assert_eq!(&extracted_public_key_array, keypair.public_key.as_array());
774 }
775
776 const RFC8032_ED25519: [(&str, &str, &str, &str); 3] = [
779 (
780 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
781 "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
782 "",
783 concat!(
784 "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155",
785 "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b",
786 ),
787 ),
788 (
789 "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
790 "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
791 "72",
792 concat!(
793 "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da",
794 "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00",
795 ),
796 ),
797 (
798 "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
799 "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
800 "af82",
801 concat!(
802 "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac",
803 "18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a",
804 ),
805 ),
806 ];
807 const RFC8032_ED25519PH: (&str, &str, &str, &str) = (
808 "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
809 "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
810 "616263",
811 concat!(
812 "98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae41",
813 "31f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406",
814 ),
815 );
816
817 fn array<const N: usize>(hex: &str) -> StackByteArray<N> {
818 StackByteArray::try_from(hex::decode(hex).expect("hex").as_slice()).expect("length")
819 }
820
821 fn rfc_keypair(seed: &str, public_key: &str) -> SigningKeyPair<PublicKey, SecretKey> {
822 let keypair = SigningKeyPair::from_seed(&array::<CRYPTO_SIGN_SEEDBYTES>(seed));
823 assert_eq!(
824 keypair.public_key,
825 array::<CRYPTO_SIGN_PUBLICKEYBYTES>(public_key)
826 );
827 assert_eq!(
828 keypair.to_seed::<Seed>(),
829 array::<CRYPTO_SIGN_SEEDBYTES>(seed)
830 );
831 keypair
832 }
833
834 #[test]
835 fn rfc8032_detached_signatures_and_signed_message_wire_format() {
836 for (seed, public_key, message, signature) in RFC8032_ED25519 {
837 let keypair = rfc_keypair(seed, public_key);
838 let message = hex::decode(message).expect("hex");
839 let expected: Signature = array(signature);
840
841 let signed = keypair.sign_to_vecbox(message.as_slice());
842 assert_eq!(signed.signature, expected);
843 assert_eq!(signed.message, message);
844 signed.verify(&keypair.public_key).expect("verify failed");
845
846 let mut wire = expected.to_vec();
847 wire.extend_from_slice(&message);
848 assert_eq!(signed.to_vec(), wire);
849 let parsed = VecSignedMessage::from_bytes(&wire).expect("parse");
850 assert_eq!(parsed, signed);
851 parsed.verify(&keypair.public_key).expect("verify failed");
852
853 let (parsed_signature, parsed_message) = parsed.into_parts();
854 assert_eq!(parsed_signature, expected);
855 assert_eq!(parsed_message, message);
856 let rebuilt = VecSignedMessage::from_parts(parsed_signature, parsed_message);
857 assert_eq!(rebuilt.to_bytes::<Vec<u8>>(), wire);
858 rebuilt.verify(&keypair.public_key).expect("verify failed");
859
860 let signed_array: SignedMessage<Signature, Vec<u8>> = keypair.sign(message.clone());
862 assert_eq!(signed_array, signed);
863
864 assert_eq!(keypair.to_public_key::<PublicKey>(), keypair.public_key);
866 assert_eq!(
867 SigningKeyPair::from_secret_key(keypair.secret_key.clone()),
868 keypair
869 );
870 }
871 }
872
873 #[test]
874 fn rfc8032_ed25519ph_vector_through_incremental_signer() {
875 let (seed, public_key, message, signature) = RFC8032_ED25519PH;
876 let keypair = rfc_keypair(seed, public_key);
877 let message = hex::decode(message).expect("hex");
878 let expected: Signature = array(signature);
879
880 let splits: [&[&[u8]]; 4] = [
881 &[&message],
882 &[&message[..1], &message[1..]],
883 &[&[], &message[..2], &message[2..], &[]],
884 &[&message[..1], &message[1..2], &message[2..]],
885 ];
886 for parts in splits {
887 let mut signer = Ed25519phSigner::new();
888 for part in parts {
889 signer.update(part);
890 }
891 let actual: Signature = signer.finalize(&keypair.secret_key);
892 assert_eq!(actual, expected, "split {parts:?}");
893
894 let mut verifier = Ed25519phSigner::default();
895 for part in parts {
896 verifier.update(part);
897 }
898 verifier
899 .verify(&expected, &keypair.public_key)
900 .expect("verify failed");
901 }
902
903 let pure = keypair.sign_to_vecbox(message.as_slice());
906 assert_ne!(pure.signature, expected);
907 let mut verifier = Ed25519phSigner::new();
908 verifier.update(&message);
909 assert!(matches!(
910 verifier.verify(&pure.signature, &keypair.public_key),
911 Err(Error::AuthenticationFailed)
912 ));
913 assert!(matches!(
914 VecSignedMessage::from_parts(expected, message).verify(&keypair.public_key),
915 Err(Error::AuthenticationFailed)
916 ));
917 }
918
919 #[test]
920 fn tampered_signatures_messages_and_wrong_keys_are_rejected() {
921 let (seed, public_key, message, _) = RFC8032_ED25519[2];
922 let keypair = rfc_keypair(seed, public_key);
923 let other = rfc_keypair(RFC8032_ED25519[1].0, RFC8032_ED25519[1].1);
924 let message = hex::decode(message).expect("hex");
925 let signed = keypair.sign_to_vecbox(message.as_slice());
926
927 assert!(matches!(
928 signed.verify(&other.public_key),
929 Err(Error::AuthenticationFailed)
930 ));
931
932 for index in [0, 31, 32, CRYPTO_SIGN_BYTES - 1] {
933 let mut tampered = signed.clone();
934 tampered.signature[index] ^= 0x01;
935 assert!(matches!(
936 tampered.verify(&keypair.public_key),
937 Err(Error::AuthenticationFailed)
938 ));
939 }
940
941 let mut tampered = signed.clone();
942 tampered.message[0] ^= 0x80;
943 assert!(matches!(
944 tampered.verify(&keypair.public_key),
945 Err(Error::AuthenticationFailed)
946 ));
947 let mut truncated = signed.clone();
948 truncated.message.pop();
949 assert!(truncated.verify(&keypair.public_key).is_err());
950 let mut extended = signed.clone();
951 extended.message.push(0);
952 assert!(extended.verify(&keypair.public_key).is_err());
953
954 let ph: Signature = {
957 let mut signer = Ed25519phSigner::new();
958 signer.update(&message);
959 signer.finalize(&keypair.secret_key)
960 };
961 let mut verifier = Ed25519phSigner::new();
962 verifier.update(&message[..1]);
963 assert!(verifier.verify(&ph, &keypair.public_key).is_err());
964 let mut verifier = Ed25519phSigner::new();
965 verifier.update(&message);
966 assert!(matches!(
967 verifier.verify(&ph, &other.public_key),
968 Err(Error::AuthenticationFailed)
969 ));
970
971 signed.verify(&keypair.public_key).expect("verify failed");
973 }
974
975 #[test]
976 fn signed_message_from_bytes_requires_a_full_signature() {
977 for len in [0, 1, CRYPTO_SIGN_BYTES - 1] {
978 assert!(matches!(
979 VecSignedMessage::from_bytes(&vec![0u8; len]),
980 Err(Error::InvalidLength {
981 context: ErrorContext::SignedMessage,
982 actual,
983 ..
984 }) if actual == len
985 ));
986 }
987 let bare = VecSignedMessage::from_bytes(&[0x5au8; CRYPTO_SIGN_BYTES])
988 .expect("a lone signature is an empty message");
989 assert!(bare.message.is_empty());
990 assert_eq!(bare.signature.as_slice(), &[0x5au8; CRYPTO_SIGN_BYTES]);
991 }
992
993 #[test]
994 fn from_slices_accepts_exact_lengths_and_reports_the_short_side() {
995 let (seed, public_key, message, signature) = RFC8032_ED25519[0];
996 let keypair = rfc_keypair(seed, public_key);
997 let rebuilt = StackSigningKeyPair::from_slices(
998 keypair.public_key.as_slice(),
999 keypair.secret_key.as_slice(),
1000 )
1001 .expect("from_slices failed");
1002 assert_eq!(rebuilt, keypair);
1003 let signed = rebuilt.sign_to_vecbox(hex::decode(message).expect("hex").as_slice());
1004 assert_eq!(signed.signature, array::<CRYPTO_SIGN_BYTES>(signature));
1005
1006 for len in [
1007 0,
1008 CRYPTO_SIGN_PUBLICKEYBYTES - 1,
1009 CRYPTO_SIGN_PUBLICKEYBYTES + 1,
1010 ] {
1011 assert!(matches!(
1012 StackSigningKeyPair::from_slices(
1013 &vec![0u8; len],
1014 keypair.secret_key.as_slice(),
1015 ),
1016 Err(Error::InvalidLength {
1017 context: ErrorContext::PublicKey,
1018 actual,
1019 ..
1020 }) if actual == len
1021 ));
1022 }
1023 for len in [
1024 0,
1025 CRYPTO_SIGN_SECRETKEYBYTES - 1,
1026 CRYPTO_SIGN_SECRETKEYBYTES + 1,
1027 ] {
1028 assert!(matches!(
1029 StackSigningKeyPair::from_slices(
1030 keypair.public_key.as_slice(),
1031 &vec![0u8; len],
1032 ),
1033 Err(Error::InvalidLength {
1034 context: ErrorContext::SecretKey,
1035 actual,
1036 ..
1037 }) if actual == len
1038 ));
1039 }
1040 }
1041
1042 #[cfg(feature = "serde")]
1043 #[test]
1044 fn serde_round_trips_reproduce_rfc8032_signatures() {
1045 let (seed, public_key, message, signature) = RFC8032_ED25519[1];
1046 let keypair = rfc_keypair(seed, public_key);
1047 let message = hex::decode(message).expect("hex");
1048 let expected: Signature = array(signature);
1049
1050 let json = serde_json::to_string(&keypair).expect("serialize keypair");
1051 let decoded: SigningKeyPair<PublicKey, SecretKey> =
1052 serde_json::from_str(&json).expect("deserialize keypair");
1053 assert_eq!(decoded, keypair);
1054 let signed = decoded.sign_to_vecbox(message.as_slice());
1055 assert_eq!(signed.signature, expected);
1056
1057 let json = serde_json::to_string(&signed).expect("serialize signed message");
1058 let decoded: VecSignedMessage =
1059 serde_json::from_str(&json).expect("deserialize signed message");
1060 assert_eq!(decoded, signed);
1061 decoded.verify(&keypair.public_key).expect("verify failed");
1062
1063 let tampered = json.replacen(
1065 &format!("{}", expected[0]),
1066 &format!("{}", expected[0] ^ 1),
1067 1,
1068 );
1069 let decoded: VecSignedMessage = serde_json::from_str(&tampered).expect("deserialize");
1070 assert!(decoded.verify(&keypair.public_key).is_err());
1071 }
1072
1073 #[cfg(dryoc_native_tests)]
1074 mod native_tests {
1075 use super::*;
1076 use crate::native_test_util as sodium;
1077 use crate::utils::test_util::XorShift64;
1078
1079 #[test]
1080 fn incremental_signer_matches_libsodium_ed25519ph_for_split_updates() {
1081 let mut rng = XorShift64::new(0x6564_3235_3531_3970);
1082 for round in 0..8 {
1083 let keypair = StackSigningKeyPair::from_seed(&rng.next_bytes32());
1084 let message: Vec<u8> = (0..(round * 97) % 1023)
1085 .map(|_| rng.next_u64() as u8)
1086 .collect();
1087 let split = message.len() / 3;
1088 let parts: [&[u8]; 3] = [
1089 &message[..split],
1090 &message[split..2 * split],
1091 &message[2 * split..],
1092 ];
1093
1094 let mut signer = Ed25519phSigner::new();
1095 for part in parts {
1096 signer.update(&part);
1097 }
1098 let signature: Signature = signer.finalize(&keypair.secret_key);
1099 assert_eq!(
1100 signature.as_array(),
1101 &sodium::sign_ed25519ph(&parts, &keypair.secret_key)
1102 );
1103 assert!(sodium::sign_ed25519ph_verify(
1104 &[&message],
1105 &signature,
1106 &keypair.public_key
1107 ));
1108
1109 let mut verifier = Ed25519phSigner::new();
1110 verifier.update(&message);
1111 verifier
1112 .verify(&signature, &keypair.public_key)
1113 .expect("verify failed");
1114 }
1115 }
1116
1117 #[test]
1118 fn detached_signatures_interoperate_with_libsodium() {
1119 let (seed, public_key, _, _) = RFC8032_ED25519PH;
1120 let keypair = rfc_keypair(seed, public_key);
1121 let (so_pk, so_sk) =
1122 sodium::sign_ed25519_seed_keypair(&hex::decode(seed).expect("hex"));
1123 assert_eq!(so_pk.as_slice(), keypair.public_key.as_slice());
1124 assert_eq!(so_sk.as_slice(), keypair.secret_key.as_slice());
1125
1126 let mut rng = XorShift64::new(0x7369_676e_6564_2121);
1127 for len in [0, 1, 63, 64, 65, 1023] {
1128 let message: Vec<u8> = (0..len).map(|_| rng.next_u64() as u8).collect();
1129 let signed = keypair.sign_to_vecbox(message.as_slice());
1130 let so_signature = sodium::sign_ed25519_detached(&message, &so_sk);
1131 assert_eq!(signed.signature.as_slice(), so_signature.as_slice());
1132 assert!(sodium::sign_ed25519_verify_detached(
1133 signed.signature.as_slice(),
1134 &message,
1135 &so_pk
1136 ));
1137
1138 let so_signed = sodium::sign_ed25519(&message, &so_sk);
1139 let parsed = VecSignedMessage::from_bytes(&so_signed).expect("parse");
1140 assert_eq!(parsed, signed);
1141 parsed.verify(&keypair.public_key).expect("verify failed");
1142 assert_eq!(
1143 sodium::sign_ed25519_open(&signed.to_vec(), &so_pk)
1144 .expect("sodium verify failed"),
1145 message
1146 );
1147 }
1148 }
1149 }
1150}