1use std::{
39 fmt,
40 io::{Cursor, Write},
41 str::FromStr,
42};
43
44use lexe_byte_array::ByteArray;
45use lexe_hex::hex::{self, FromHex};
46use lexe_serde::impl_serde_hexstr_or_bytes;
47use lexe_sha256::sha256;
48use lexe_std::const_utils;
49use ref_cast::RefCast;
50use ring::signature::KeyPair as _;
51use serde_core::{de::Deserialize, ser::Serialize};
52
53#[cfg(doc)]
54use crate::ed25519;
55use crate::rng::{Crng, RngExt};
56
57pub const SECRET_KEY_LEN: usize = 32;
58pub const PUBLIC_KEY_LEN: usize = 32;
59pub const SIGNATURE_LEN: usize = 64;
60
61pub const SIGNED_STRUCT_OVERHEAD: usize = PUBLIC_KEY_LEN + SIGNATURE_LEN;
64
65pub struct KeyPair {
71 key_pair: ring::signature::Ed25519KeyPair,
73
74 seed: [u8; 32],
78}
79
80#[derive(Copy, Clone, Eq, Hash, PartialEq, RefCast)]
82#[repr(transparent)]
83pub struct PublicKey([u8; 32]);
84
85impl_serde_hexstr_or_bytes!(PublicKey);
86
87#[derive(Copy, Clone, Eq, PartialEq, RefCast)]
89#[repr(transparent)]
90pub struct Signature([u8; 64]);
91
92#[derive(Debug, Eq, PartialEq)]
95#[must_use]
96pub struct Signed<T: Signable> {
97 signer: PublicKey,
98 sig: Signature,
99 inner: T,
100}
101
102#[derive(Debug)]
103pub enum Error {
104 InvalidPkLength,
105 UnexpectedAlgorithm,
106 KeyDeserializeError,
107 PublicKeyMismatch,
108 InvalidSignature,
109 BcsDeserialize,
110 SignedTooShort,
111 UnexpectedSigner,
112}
113
114#[derive(Debug)]
115pub struct InvalidSignature;
116
117pub trait Signable {
124 const DOMAIN_SEPARATOR: [u8; 32];
127}
128
129impl<T: Signable> Signable for &T {
131 const DOMAIN_SEPARATOR: [u8; 32] = T::DOMAIN_SEPARATOR;
132}
133
134pub fn accept_any_signer(_: &PublicKey) -> bool {
139 true
140}
141
142pub fn verify_signed_struct<'msg, T, F>(
149 is_expected_signer: F,
150 serialized: &'msg [u8],
151) -> Result<Signed<T>, Error>
152where
153 T: Signable + Deserialize<'msg>,
154 F: FnOnce(&'msg PublicKey) -> bool,
155{
156 let (signer, sig, ser_struct) = deserialize_signed_struct(serialized)?;
157
158 if !is_expected_signer(signer) {
160 return Err(Error::UnexpectedSigner);
161 }
162
163 verify_signed_struct_inner(signer, sig, ser_struct, &T::DOMAIN_SEPARATOR)
166 .map_err(|_| Error::InvalidSignature)?;
167
168 let inner: T =
170 bcs::from_bytes(ser_struct).map_err(|_| Error::BcsDeserialize)?;
171
172 Ok(Signed {
175 signer: *signer,
176 sig: *sig,
177 inner,
178 })
179}
180
181fn deserialize_signed_struct(
185 serialized: &[u8],
186) -> Result<(&PublicKey, &Signature, &[u8]), Error> {
187 if serialized.len() < SIGNED_STRUCT_OVERHEAD {
188 return Err(Error::SignedTooShort);
189 }
190
191 let (signer, serialized) = serialized
193 .split_first_chunk::<PUBLIC_KEY_LEN>()
194 .expect("serialized.len() checked above");
195 let signer = PublicKey::from_ref(signer);
196
197 let (sig, ser_struct) = serialized
199 .split_first_chunk::<SIGNATURE_LEN>()
200 .expect("serialized.len() checked above");
201 let sig = Signature::from_ref(sig);
202
203 Ok((signer, sig, ser_struct))
204}
205
206fn verify_signed_struct_inner(
207 signer: &PublicKey,
208 sig: &Signature,
209 ser_struct: &[u8],
210 domain_separator: &[u8; 32],
211) -> Result<(), InvalidSignature> {
212 let msg = sha256::digest_many(&[domain_separator.as_slice(), ser_struct]);
216 signer.verify_raw(msg.as_slice(), sig)
217}
218
219impl KeyPair {
222 pub fn from_seed(seed: &[u8; 32]) -> Self {
226 let key_pair = ring::signature::Ed25519KeyPair::from_seed_unchecked(
227 seed,
228 )
229 .expect("This should never fail, as the seed is exactly 32 bytes");
230 Self {
231 seed: *seed,
232 key_pair,
233 }
234 }
235
236 pub fn from_seed_owned(seed: [u8; 32]) -> Self {
237 let key_pair = ring::signature::Ed25519KeyPair::from_seed_unchecked(
238 &seed,
239 )
240 .expect("This should never fail, as the seed is exactly 32 bytes");
241 Self { seed, key_pair }
242 }
243
244 pub fn from_seed_and_pubkey(
248 seed: &[u8; 32],
249 expected_pubkey: &[u8; 32],
250 ) -> Result<Self, Error> {
251 let key_pair =
252 ring::signature::Ed25519KeyPair::from_seed_and_public_key(
253 seed.as_slice(),
254 expected_pubkey.as_slice(),
255 )
256 .map_err(|_| Error::PublicKeyMismatch)?;
257 Ok(Self {
258 seed: *seed,
259 key_pair,
260 })
261 }
262
263 pub fn from_rng(mut rng: &mut dyn Crng) -> Self {
268 Self::from_seed_owned(rng.gen_bytes())
269 }
270
271 pub fn to_ring(&self) -> ring::signature::Ed25519KeyPair {
277 let pkcs8_bytes = self.serialize_pkcs8_der();
278 ring::signature::Ed25519KeyPair::from_pkcs8(&pkcs8_bytes).unwrap()
279 }
280
281 pub fn into_ring(self) -> ring::signature::Ed25519KeyPair {
285 self.key_pair
286 }
287
288 pub fn for_test(id: u64) -> Self {
292 const LEN: usize = std::mem::size_of::<u64>();
293
294 let mut seed = [0u8; 32];
295 seed[0..LEN].copy_from_slice(id.to_le_bytes().as_slice());
296 Self::from_seed(&seed)
297 }
298
299 pub fn serialize_pkcs8_der(&self) -> [u8; PKCS_LEN] {
301 serialize_keypair_pkcs8_der(&self.seed, self.public_key().as_inner())
302 }
303
304 pub fn deserialize_pkcs8_der(bytes: &[u8]) -> Result<Self, Error> {
306 let (seed, expected_pubkey) = deserialize_keypair_pkcs8_der(bytes)
307 .ok_or(Error::KeyDeserializeError)?;
308 Self::from_seed_and_pubkey(seed, expected_pubkey)
309 }
310
311 pub fn secret_key(&self) -> &[u8; 32] {
313 &self.seed
314 }
315
316 pub fn public_key(&self) -> &PublicKey {
318 let pubkey_bytes =
319 <&[u8; 32]>::try_from(self.key_pair.public_key().as_ref()).unwrap();
320 PublicKey::from_ref(pubkey_bytes)
321 }
322
323 pub fn sign_raw(&self, msg: &[u8]) -> Signature {
325 let sig = self.key_pair.sign(msg);
326 Signature::try_from(sig.as_ref()).unwrap()
327 }
328
329 pub fn sign_struct<'a, T: Signable + Serialize>(
342 &self,
343 value: &'a T,
344 ) -> Result<(Vec<u8>, Signed<&'a T>), bcs::Error> {
345 let signer = self.public_key();
346
347 let struct_ser_len =
348 bcs::serialized_size(value)? + SIGNED_STRUCT_OVERHEAD;
349 let mut out = Vec::with_capacity(struct_ser_len);
350
351 out.extend_from_slice(signer.as_slice());
354 out.extend_from_slice([0u8; 64].as_slice());
355 bcs::serialize_into(&mut out, value)?;
356
357 let sig = self.sign_struct_inner(
360 &out[SIGNED_STRUCT_OVERHEAD..],
361 &T::DOMAIN_SEPARATOR,
362 );
363 out[PUBLIC_KEY_LEN..SIGNED_STRUCT_OVERHEAD]
364 .copy_from_slice(sig.as_slice());
365
366 Ok((
367 out,
368 Signed {
369 signer: *signer,
370 sig,
371 inner: value,
372 },
373 ))
374 }
375
376 fn sign_struct_inner(
379 &self,
380 serialized: &[u8],
381 domain_separator: &[u8],
382 ) -> Signature {
383 let msg = sha256::digest_many(&[domain_separator, serialized]);
384 self.sign_raw(msg.as_slice())
385 }
386}
387
388impl fmt::Debug for KeyPair {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 f.debug_struct("ed25519::KeyPair")
391 .field("sk", &"..")
392 .field("pk", &hex::display(self.public_key().as_slice()))
393 .finish()
394 }
395}
396
397impl FromHex for KeyPair {
398 fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
399 <[u8; 32]>::from_hex(s).map(Self::from_seed_owned)
400 }
401}
402
403impl FromStr for KeyPair {
404 type Err = hex::DecodeError;
405 #[inline]
406 fn from_str(s: &str) -> Result<Self, Self::Err> {
407 Self::from_hex(s)
408 }
409}
410
411impl PublicKey {
414 pub const fn new(bytes: [u8; 32]) -> Self {
415 Self(bytes)
418 }
419
420 pub const fn from_ref(bytes: &[u8; 32]) -> &Self {
421 const_utils::const_ref_cast(bytes)
422 }
423
424 pub const fn as_slice(&self) -> &[u8] {
425 self.0.as_slice()
426 }
427
428 pub const fn into_inner(self) -> [u8; 32] {
429 self.0
430 }
431
432 pub const fn as_inner(&self) -> &[u8; 32] {
433 &self.0
434 }
435
436 pub fn verify_raw(
438 &self,
439 msg: &[u8],
440 sig: &Signature,
441 ) -> Result<(), InvalidSignature> {
442 ring::signature::UnparsedPublicKey::new(
443 &ring::signature::ED25519,
444 self.as_slice(),
445 )
446 .verify(msg, sig.as_slice())
447 .map_err(|_| InvalidSignature)
448 }
449
450 pub fn verify_self_signed_struct<'msg, T: Signable + Deserialize<'msg>>(
453 &self,
454 serialized: &'msg [u8],
455 ) -> Result<Signed<T>, Error> {
456 let accept_self_signer = |signer| signer == self;
457 verify_signed_struct(accept_self_signer, serialized)
458 }
459}
460
461impl TryFrom<&[u8]> for PublicKey {
462 type Error = Error;
463
464 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
465 let pk =
466 <[u8; 32]>::try_from(bytes).map_err(|_| Error::InvalidPkLength)?;
467 Ok(Self::new(pk))
468 }
469}
470
471impl AsRef<[u8]> for PublicKey {
472 fn as_ref(&self) -> &[u8] {
473 self.as_slice()
474 }
475}
476
477impl AsRef<[u8; 32]> for PublicKey {
478 fn as_ref(&self) -> &[u8; 32] {
479 self.as_inner()
480 }
481}
482
483impl FromHex for PublicKey {
484 fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
485 <[u8; 32]>::from_hex(s).map(Self::new)
486 }
487}
488
489impl FromStr for PublicKey {
490 type Err = hex::DecodeError;
491 #[inline]
492 fn from_str(s: &str) -> Result<Self, Self::Err> {
493 Self::from_hex(s)
494 }
495}
496
497impl fmt::Display for PublicKey {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 write!(f, "{}", hex::display(self.as_slice()))
500 }
501}
502
503impl fmt::Debug for PublicKey {
504 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505 f.debug_tuple("ed25519::PublicKey")
506 .field(&hex::display(self.as_slice()))
507 .finish()
508 }
509}
510
511impl Signature {
514 pub const fn new(sig: [u8; 64]) -> Self {
515 Self(sig)
516 }
517
518 pub const fn from_ref(sig: &[u8; 64]) -> &Self {
519 const_utils::const_ref_cast(sig)
520 }
521
522 pub const fn as_slice(&self) -> &[u8] {
523 self.0.as_slice()
524 }
525
526 pub const fn into_inner(self) -> [u8; 64] {
527 self.0
528 }
529
530 pub const fn as_inner(&self) -> &[u8; 64] {
531 &self.0
532 }
533}
534
535impl AsRef<[u8]> for Signature {
536 fn as_ref(&self) -> &[u8] {
537 self.as_slice()
538 }
539}
540
541impl AsRef<[u8; 64]> for Signature {
542 fn as_ref(&self) -> &[u8; 64] {
543 self.as_inner()
544 }
545}
546
547impl TryFrom<&[u8]> for Signature {
548 type Error = Error;
549 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
550 <[u8; 64]>::try_from(value)
551 .map(Signature)
552 .map_err(|_| Error::InvalidSignature)
553 }
554}
555
556impl FromHex for Signature {
557 fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
558 <[u8; 64]>::from_hex(s).map(Self::new)
559 }
560}
561
562impl FromStr for Signature {
563 type Err = hex::DecodeError;
564 #[inline]
565 fn from_str(s: &str) -> Result<Self, Self::Err> {
566 Self::from_hex(s)
567 }
568}
569
570impl fmt::Display for Signature {
571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572 write!(f, "{}", hex::display(self.as_slice()))
573 }
574}
575
576impl fmt::Debug for Signature {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578 f.debug_tuple("ed25519::Signature")
579 .field(&hex::display(self.as_slice()))
580 .finish()
581 }
582}
583
584impl<T: Signable> Signed<T> {
587 pub fn into_parts(self) -> (PublicKey, Signature, T) {
588 (self.signer, self.sig, self.inner)
589 }
590
591 pub fn inner(&self) -> &T {
592 &self.inner
593 }
594
595 pub fn signer(&self) -> &PublicKey {
596 &self.signer
597 }
598
599 pub fn signature(&self) -> &Signature {
600 &self.sig
601 }
602
603 pub fn as_ref(&self) -> Signed<&T> {
604 Signed {
605 signer: self.signer,
606 sig: self.sig,
607 inner: &self.inner,
608 }
609 }
610}
611
612impl<T: Signable + Serialize> Signed<T> {
613 pub fn serialize(&self) -> Result<Vec<u8>, bcs::Error> {
614 let len = bcs::serialized_size(&self.inner)? + SIGNED_STRUCT_OVERHEAD;
615 let mut out = Vec::with_capacity(len);
616 let mut writer = Cursor::new(&mut out);
617
618 writer.write_all(self.signer.as_slice()).unwrap();
621 writer.write_all(self.sig.as_slice()).unwrap();
622 bcs::serialize_into(&mut writer, &self.inner)?;
623
624 Ok(out)
625 }
626}
627
628impl<T: Signable + Clone> Signed<&T> {
629 pub fn cloned(&self) -> Signed<T> {
630 Signed {
631 signer: self.signer,
632 sig: self.sig,
633 inner: self.inner.clone(),
634 }
635 }
636}
637
638impl<T: Signable + Clone> Clone for Signed<T> {
639 fn clone(&self) -> Self {
640 Self {
641 signer: self.signer,
642 sig: self.sig,
643 inner: self.inner.clone(),
644 }
645 }
646}
647
648impl std::error::Error for Error {}
651
652impl fmt::Display for Error {
653 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654 let msg = match self {
655 Self::InvalidPkLength =>
656 "ed25519 public key must be exactly 32 bytes",
657 Self::UnexpectedAlgorithm =>
658 "the algorithm OID doesn't match the standard ed25519 OID",
659 Self::KeyDeserializeError =>
660 "failed deserializing PKCS#8-encoded key pair",
661 Self::PublicKeyMismatch =>
662 "derived public key doesn't match expected public key",
663 Self::InvalidSignature => "invalid signature",
664 Self::BcsDeserialize =>
665 "error deserializing inner struct to verify",
666 Self::SignedTooShort => "signed struct is too short",
667 Self::UnexpectedSigner =>
668 "message was signed with a different key pair than expected",
669 };
670 f.write_str(msg)
671 }
672}
673
674impl std::error::Error for InvalidSignature {}
677
678impl fmt::Display for InvalidSignature {
679 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680 f.write_str("invalid signature")
681 }
682}
683
684#[cfg(any(test, feature = "test-utils"))]
685mod arbitrary_impls {
686 use proptest::{
687 arbitrary::{Arbitrary, any},
688 strategy::{BoxedStrategy, Strategy},
689 };
690
691 use super::*;
692
693 impl Arbitrary for KeyPair {
694 type Parameters = ();
695 type Strategy = BoxedStrategy<Self>;
696 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
697 any::<[u8; 32]>()
698 .prop_map(|seed| Self::from_seed(&seed))
699 .boxed()
700 }
701 }
702
703 impl Arbitrary for PublicKey {
704 type Parameters = ();
705 type Strategy = BoxedStrategy<Self>;
706 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
707 any::<[u8; 32]>().prop_map(Self::new).boxed()
708 }
709 }
710}
711
712const PKCS_TEMPLATE_PREFIX: &[u8] = &[
737 0x30, 0x51, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
738 0x04, 0x22, 0x04, 0x20,
739];
740const PKCS_TEMPLATE_PREFIX_BAD: &[u8] = &[
741 0x30, 0x53, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
742 0x04, 0x22, 0x04, 0x20,
743];
744const PKCS_TEMPLATE_MIDDLE_BAD: &[u8] = &[0xa1, 0x23, 0x03, 0x21, 0x00];
745const PKCS_TEMPLATE_MIDDLE: &[u8] = &[0x81, 0x21, 0x00];
746const PKCS_TEMPLATE_KEY_IDX: usize = 16;
747
748const PKCS_LEN: usize = PKCS_TEMPLATE_PREFIX.len()
751 + SECRET_KEY_LEN
752 + PKCS_TEMPLATE_MIDDLE.len()
753 + PUBLIC_KEY_LEN;
754const PKCS_LEN_BAD: usize = PKCS_TEMPLATE_PREFIX_BAD.len()
755 + SECRET_KEY_LEN
756 + PKCS_TEMPLATE_MIDDLE_BAD.len()
757 + PUBLIC_KEY_LEN;
758
759lexe_std::const_assert_usize_eq!(PKCS_LEN, 83);
761lexe_std::const_assert_usize_eq!(PKCS_LEN_BAD, 85);
762
763fn serialize_keypair_pkcs8_der(
769 secret_key: &[u8; 32],
770 public_key: &[u8; 32],
771) -> [u8; PKCS_LEN] {
772 let mut out = [0u8; PKCS_LEN];
773 let key_start_idx = PKCS_TEMPLATE_KEY_IDX;
774
775 let prefix = PKCS_TEMPLATE_PREFIX;
776 let middle = PKCS_TEMPLATE_MIDDLE;
777
778 let key_end_idx = key_start_idx + secret_key.len();
779 out[..key_start_idx].copy_from_slice(prefix);
780 out[key_start_idx..key_end_idx].copy_from_slice(secret_key);
781 out[key_end_idx..(key_end_idx + middle.len())].copy_from_slice(middle);
782 out[(key_end_idx + middle.len())..].copy_from_slice(public_key);
783
784 out
785}
786
787fn deserialize_keypair_pkcs8_der(
793 bytes: &[u8],
794) -> Option<(&[u8; 32], &[u8; 32])> {
795 let (seed, pubkey) = if bytes.len() == PKCS_LEN {
796 let seed_mid_pubkey = bytes.strip_prefix(PKCS_TEMPLATE_PREFIX)?;
797 let (seed, mid_pubkey) = seed_mid_pubkey.split_at(SECRET_KEY_LEN);
798 let pubkey = mid_pubkey.strip_prefix(PKCS_TEMPLATE_MIDDLE)?;
799 (seed, pubkey)
800 } else if bytes.len() == PKCS_LEN_BAD {
801 let seed_mid_pubkey = bytes.strip_prefix(PKCS_TEMPLATE_PREFIX_BAD)?;
803 let (seed, mid_pubkey) = seed_mid_pubkey.split_at(SECRET_KEY_LEN);
804 let pubkey = mid_pubkey.strip_prefix(PKCS_TEMPLATE_MIDDLE_BAD)?;
805 (seed, pubkey)
806 } else {
807 return None;
808 };
809
810 let seed = <&[u8; 32]>::try_from(seed).unwrap();
811 let pubkey = <&[u8; 32]>::try_from(pubkey).unwrap();
812
813 Some((seed, pubkey))
814}
815
816#[cfg(test)]
817mod test {
818 use lexe_std::array;
819 use proptest::{arbitrary::any, prop_assume, proptest, strategy::Strategy};
820 use proptest_derive::Arbitrary;
821 use serde::{Deserialize, Serialize};
822
823 use super::*;
824 use crate::rng::FastRng;
825
826 #[derive(Arbitrary, Serialize, Deserialize)]
827 struct SignableBytes(Vec<u8>);
828
829 impl Signable for SignableBytes {
830 const DOMAIN_SEPARATOR: [u8; 32] =
831 array::pad(*b"LEXE-REALM::SignableBytes");
832 }
833
834 impl fmt::Debug for SignableBytes {
835 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
836 f.debug_tuple("SignableBytes")
837 .field(&hex::display(&self.0))
838 .finish()
839 }
840 }
841
842 #[test]
843 fn test_serde_pkcs8_roundtrip() {
844 proptest!(|(seed in any::<[u8; 32]>())| {
845 let key_pair1 = KeyPair::from_seed(&seed);
846 let key_pair_bytes = key_pair1.serialize_pkcs8_der();
847 let key_pair2 =
848 KeyPair::deserialize_pkcs8_der(key_pair_bytes.as_slice())
849 .unwrap();
850
851 assert_eq!(key_pair1.secret_key(), key_pair2.secret_key());
852 assert_eq!(key_pair1.public_key(), key_pair2.public_key());
853 });
854 }
855
856 #[test]
857 fn test_pkcs8_der_snapshot() {
858 #[track_caller]
859 fn assert_pkcs8_roundtrip(hexstr: &str) {
860 let der = hex::decode(hexstr).unwrap();
861 let _ = KeyPair::deserialize_pkcs8_der(&der).unwrap();
862 }
863
864 assert_pkcs8_roundtrip(
866 "3053020101300506032b657004220420244ae26baa35db07ed4ea37908f111a8fa4cb81109f9897a133b8a8de6e800dca1230321007dc65033bee5975aab9bb06e1e514d29533173511446adc5a73a9540d2addbac",
867 );
868
869 assert_pkcs8_roundtrip(
871 "3051020101300506032b657004220420244ae26baa35db07ed4ea37908f111a8fa4cb81109f9897a133b8a8de6e800dc8121007dc65033bee5975aab9bb06e1e514d29533173511446adc5a73a9540d2addbac",
872 );
873 }
874
875 #[ignore]
879 #[test]
880 fn pkcs8_der_snapshot_data() {
881 let mut rng = FastRng::from_u64(202510211432);
882 let key = KeyPair::from_seed_owned(rng.gen_bytes());
883 println!("{}", hex::display(key.serialize_pkcs8_der().as_slice()));
884 }
885
886 #[test]
887 fn test_deserialize_pkcs8_different_lengths() {
888 for size in 0..=256 {
889 let bytes = vec![0x42_u8; size];
890 let _ = deserialize_keypair_pkcs8_der(&bytes);
891 }
892 }
893
894 #[test]
896 fn test_ed25519_test_vector() {
897 let sk: [u8; 32] = hex::decode_const(
898 b"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
899 );
900 let pk: [u8; 32] = hex::decode_const(
901 b"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
902 );
903 let msg: [u8; 2] = hex::decode_const(b"af82");
904 let sig: [u8; 64] = hex::decode_const(b"6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a");
905
906 let key_pair = KeyPair::from_seed(&sk);
907 let pubkey = key_pair.public_key();
908 assert_eq!(pubkey.as_inner(), &pk);
909
910 let sig2 = key_pair.sign_raw(&msg);
911 assert_eq!(&sig, sig2.as_inner());
912
913 pubkey.verify_raw(&msg, &sig2).unwrap();
914 }
915
916 #[test]
918 fn test_reject_truncated_sig() {
919 proptest!(|(
920 key_pair in any::<KeyPair>(),
921 msg in any::<SignableBytes>()
922 )| {
923 let pubkey = key_pair.public_key();
924
925 let (sig, signed) = key_pair.sign_struct(&msg).unwrap();
926 let sig2 = signed.serialize().unwrap();
927 assert_eq!(&sig, &sig2);
928
929 let _ = pubkey
930 .verify_self_signed_struct::<SignableBytes>(&sig)
931 .unwrap();
932
933 for trunc_len in 0..SIGNED_STRUCT_OVERHEAD {
934 pubkey
935 .verify_self_signed_struct::<SignableBytes>(&sig[..trunc_len])
936 .unwrap_err();
937 pubkey
938 .verify_self_signed_struct::<SignableBytes>(&sig[(trunc_len+1)..])
939 .unwrap_err();
940 }
941 });
942 }
943
944 #[test]
947 fn test_reject_pad_sig() {
948 let cfg = proptest::test_runner::Config::with_cases(50);
949 proptest!(cfg, |(
950 key_pair in any::<KeyPair>(),
951 msg in any::<SignableBytes>(),
952 padding in any::<Vec<u8>>(),
953 )| {
954 prop_assume!(!padding.is_empty());
955
956 let pubkey = key_pair.public_key();
957
958 let (sig, signed) = key_pair.sign_struct(&msg).unwrap();
959 let sig2 = signed.serialize().unwrap();
960 assert_eq!(&sig, &sig2);
961
962 let _ = pubkey
963 .verify_self_signed_struct::<SignableBytes>(&sig)
964 .unwrap();
965
966 let mut sig2: Vec<u8> = Vec::with_capacity(sig.len() + padding.len());
967
968 for idx in 0..=sig.len() {
969 let (left, right) = sig.split_at(idx);
970
971 sig2.clear();
974 sig2.extend_from_slice(left);
975 sig2.extend_from_slice(&padding);
976 sig2.extend_from_slice(right);
977
978 pubkey
979 .verify_self_signed_struct::<SignableBytes>(&sig2)
980 .unwrap_err();
981 }
982 });
983 }
984
985 #[test]
988 fn test_reject_modified_sig() {
989 let arb_mutation = any::<Vec<u8>>()
990 .prop_filter("can't be empty or all zeroes", |m| {
991 !m.is_empty() && !m.iter().all(|x| x == &0u8)
992 });
993
994 proptest!(|(
995 key_pair in any::<KeyPair>(),
996 msg in any::<SignableBytes>(),
997 mut_offset in any::<usize>(),
998 mut mutation in arb_mutation,
999 )| {
1000 let pubkey = key_pair.public_key();
1001
1002 let (mut sig, signed) = key_pair.sign_struct(&msg).unwrap();
1003 let sig2 = signed.serialize().unwrap();
1004 assert_eq!(&sig, &sig2);
1005
1006 mutation.truncate(sig.len());
1007 prop_assume!(!mutation.is_empty() && !mutation.iter().all(|x| x == &0));
1008
1009 let _ = pubkey
1010 .verify_self_signed_struct::<SignableBytes>(&sig)
1011 .unwrap();
1012
1013 for (idx_mut, m) in mutation.into_iter().enumerate() {
1016 let idx_sig = idx_mut.wrapping_add(mut_offset) % sig.len();
1017 sig[idx_sig] ^= m;
1018 }
1019
1020 pubkey.verify_self_signed_struct::<SignableBytes>(&sig).unwrap_err();
1021 });
1022 }
1023
1024 #[test]
1025 fn test_sign_verify() {
1026 proptest!(|(key_pair in any::<KeyPair>(), msg in any::<Vec<u8>>())| {
1027 let pubkey = key_pair.public_key();
1028
1029 let sig = key_pair.sign_raw(&msg);
1030 pubkey.verify_raw(&msg, &sig).unwrap();
1031 });
1032 }
1033
1034 #[test]
1035 fn test_sign_verify_struct() {
1036 #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
1037 struct Foo(u32);
1038
1039 impl Signable for Foo {
1040 const DOMAIN_SEPARATOR: [u8; 32] = array::pad(*b"LEXE-REALM::Foo");
1041 }
1042
1043 #[derive(Debug, Serialize, Deserialize)]
1044 struct Bar(u32);
1045
1046 impl Signable for Bar {
1047 const DOMAIN_SEPARATOR: [u8; 32] = array::pad(*b"LEXE-REALM::Bar");
1048 }
1049
1050 fn arb_foo() -> impl Strategy<Value = Foo> {
1051 any::<u32>().prop_map(Foo)
1052 }
1053
1054 proptest!(|(key_pair in any::<KeyPair>(), foo in arb_foo())| {
1055 let signer = key_pair.public_key();
1056 let (sig, signed) =
1057 key_pair.sign_struct::<Foo>(&foo).unwrap();
1058 let sig2 = signed.serialize().unwrap();
1059 assert_eq!(&sig, &sig2);
1060
1061 let signed2 =
1062 signer.verify_self_signed_struct::<Foo>(&sig).unwrap();
1063 assert_eq!(signed, signed2.as_ref());
1064
1065 signer.verify_self_signed_struct::<Bar>(&sig).unwrap_err();
1069 });
1070 }
1071}