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
57const SECRET_KEY_LEN: usize = 32;
58
59pub const SIGNED_STRUCT_OVERHEAD: usize = PublicKey::LEN + Signature::LEN;
62
63pub struct KeyPair {
71 key_pair: ring::signature::Ed25519KeyPair,
73
74 seed: [u8; 32],
78}
79
80#[derive(Copy, Clone, Eq, Hash, PartialEq, RefCast)]
85#[repr(transparent)]
86pub struct PublicKey([u8; 32]);
87
88impl_serde_hexstr_or_bytes!(PublicKey);
89
90#[derive(Copy, Clone, Eq, Hash, PartialEq, RefCast)]
92#[repr(transparent)]
93pub struct Signature([u8; 64]);
94
95#[derive(Debug, Eq, PartialEq)]
98#[must_use]
99pub struct Signed<T: Signable> {
100 signer: PublicKey,
101 sig: Signature,
102 inner: T,
103}
104
105#[derive(Debug)]
106pub enum Error {
107 InvalidPkLength,
108 UnexpectedAlgorithm,
109 KeyDeserializeError,
110 PublicKeyMismatch,
111 InvalidSignature,
112 BcsDeserialize,
113 SignedTooShort,
114 UnexpectedSigner,
115}
116
117#[derive(Debug)]
118pub struct InvalidSignature;
119
120pub trait Signable {
127 const DOMAIN_SEPARATOR: [u8; 32];
130}
131
132impl<T: Signable> Signable for &T {
134 const DOMAIN_SEPARATOR: [u8; 32] = T::DOMAIN_SEPARATOR;
135}
136
137pub mod verify {
141 use super::*;
142
143 pub fn signed_struct_by_signer<'msg, T: Signable + Deserialize<'msg>>(
146 signer: &PublicKey,
147 serialized: &'msg [u8],
148 ) -> Result<Signed<T>, Error> {
149 let accept_only_signer = |s| s == signer;
150 signed_struct_with_policy(accept_only_signer, serialized)
151 }
152
153 pub fn signed_struct_by_any_signer<
156 'msg,
157 T: Signable + Deserialize<'msg>,
158 >(
159 serialized: &'msg [u8],
160 ) -> Result<Signed<T>, Error> {
161 signed_struct_with_policy(accept_any_signer, serialized)
162 }
163
164 pub fn accept_any_signer(_: &PublicKey) -> bool {
167 true
168 }
169
170 pub fn signed_struct_with_policy<'msg, T, F>(
178 is_expected_signer: F,
179 serialized: &'msg [u8],
180 ) -> Result<Signed<T>, Error>
181 where
182 T: Signable + Deserialize<'msg>,
183 F: FnOnce(&'msg PublicKey) -> bool,
184 {
185 fn deserialize_signed_struct(
189 serialized: &[u8],
190 ) -> Result<(&PublicKey, &Signature, &[u8]), Error> {
191 if serialized.len() < SIGNED_STRUCT_OVERHEAD {
192 return Err(Error::SignedTooShort);
193 }
194
195 let (signer, serialized) = serialized
197 .split_first_chunk::<{ PublicKey::LEN }>()
198 .expect("serialized.len() checked above");
199 let signer = PublicKey::from_ref(signer);
200
201 let (sig, ser_struct) = serialized
203 .split_first_chunk::<{ Signature::LEN }>()
204 .expect("serialized.len() checked above");
205 let sig = Signature::from_ref(sig);
206
207 Ok((signer, sig, ser_struct))
208 }
209
210 fn verify_signed_struct_inner(
211 signer: &PublicKey,
212 sig: &Signature,
213 ser_struct: &[u8],
214 domain_separator: &[u8; 32],
215 ) -> Result<(), InvalidSignature> {
216 let msg =
221 sha256::digest_many(&[domain_separator.as_slice(), ser_struct]);
222 signed_bytes_by_signer(signer, msg.as_slice(), sig)
223 }
224
225 let (signer, sig, ser_struct) = deserialize_signed_struct(serialized)?;
226
227 if !is_expected_signer(signer) {
229 return Err(Error::UnexpectedSigner);
230 }
231
232 verify_signed_struct_inner(
235 signer,
236 sig,
237 ser_struct,
238 &T::DOMAIN_SEPARATOR,
239 )
240 .map_err(|_| Error::InvalidSignature)?;
241
242 let inner: T =
244 bcs::from_bytes(ser_struct).map_err(|_| Error::BcsDeserialize)?;
245
246 Ok(Signed {
249 signer: *signer,
250 sig: *sig,
251 inner,
252 })
253 }
254
255 pub fn signed_bytes_by_signer(
257 signer: &PublicKey,
258 msg: &[u8],
259 sig: &Signature,
260 ) -> Result<(), InvalidSignature> {
261 ring::signature::UnparsedPublicKey::new(
262 &ring::signature::ED25519,
263 signer.as_slice(),
264 )
265 .verify(msg, sig.as_slice())
266 .map_err(|_| InvalidSignature)
267 }
268}
269
270impl KeyPair {
273 pub fn from_seed(seed: &[u8; 32]) -> Self {
277 let key_pair = ring::signature::Ed25519KeyPair::from_seed_unchecked(
278 seed,
279 )
280 .expect("This should never fail, as the seed is exactly 32 bytes");
281 Self {
282 seed: *seed,
283 key_pair,
284 }
285 }
286
287 pub fn from_seed_owned(seed: [u8; 32]) -> Self {
288 let key_pair = ring::signature::Ed25519KeyPair::from_seed_unchecked(
289 &seed,
290 )
291 .expect("This should never fail, as the seed is exactly 32 bytes");
292 Self { seed, key_pair }
293 }
294
295 pub fn from_seed_and_pubkey(
299 seed: &[u8; 32],
300 expected_pubkey: &[u8; 32],
301 ) -> Result<Self, Error> {
302 let key_pair =
303 ring::signature::Ed25519KeyPair::from_seed_and_public_key(
304 seed.as_slice(),
305 expected_pubkey.as_slice(),
306 )
307 .map_err(|_| Error::PublicKeyMismatch)?;
308 Ok(Self {
309 seed: *seed,
310 key_pair,
311 })
312 }
313
314 pub fn from_rng(mut rng: &mut dyn Crng) -> Self {
319 Self::from_seed_owned(rng.gen_bytes())
320 }
321
322 pub fn to_ring(&self) -> ring::signature::Ed25519KeyPair {
328 let pkcs8_bytes = self.serialize_pkcs8_der();
329 ring::signature::Ed25519KeyPair::from_pkcs8(&pkcs8_bytes).unwrap()
330 }
331
332 pub fn into_ring(self) -> ring::signature::Ed25519KeyPair {
336 self.key_pair
337 }
338
339 pub fn for_test(id: u64) -> Self {
343 const LEN: usize = std::mem::size_of::<u64>();
344
345 let mut seed = [0u8; 32];
346 seed[0..LEN].copy_from_slice(id.to_le_bytes().as_slice());
347 Self::from_seed(&seed)
348 }
349
350 pub fn serialize_pkcs8_der(&self) -> [u8; PKCS_LEN] {
352 serialize_keypair_pkcs8_der(&self.seed, self.public_key().as_array())
353 }
354
355 pub fn deserialize_pkcs8_der(bytes: &[u8]) -> Result<Self, Error> {
357 let (seed, expected_pubkey) = deserialize_keypair_pkcs8_der(bytes)
358 .ok_or(Error::KeyDeserializeError)?;
359 Self::from_seed_and_pubkey(seed, expected_pubkey)
360 }
361
362 pub fn secret_key(&self) -> &[u8; 32] {
364 &self.seed
365 }
366
367 pub fn public_key(&self) -> &PublicKey {
369 let pubkey_bytes =
370 <&[u8; 32]>::try_from(self.key_pair.public_key().as_ref()).unwrap();
371 PublicKey::from_ref(pubkey_bytes)
372 }
373
374 pub fn sign_raw(&self, msg: &[u8]) -> Signature {
376 let sig = self.key_pair.sign(msg);
377 Signature::try_from(sig.as_ref()).unwrap()
378 }
379
380 pub fn sign_struct<'a, T: Signable + Serialize>(
393 &self,
394 value: &'a T,
395 ) -> Result<(Vec<u8>, Signed<&'a T>), bcs::Error> {
396 let signer = self.public_key();
397
398 let struct_ser_len =
399 bcs::serialized_size(value)? + SIGNED_STRUCT_OVERHEAD;
400 let mut out = Vec::with_capacity(struct_ser_len);
401
402 out.extend_from_slice(signer.as_slice());
405 out.extend_from_slice([0u8; 64].as_slice());
406 bcs::serialize_into(&mut out, value)?;
407
408 let sig = self.sign_struct_inner(
411 &out[SIGNED_STRUCT_OVERHEAD..],
412 &T::DOMAIN_SEPARATOR,
413 );
414 out[PublicKey::LEN..SIGNED_STRUCT_OVERHEAD]
415 .copy_from_slice(sig.as_slice());
416
417 Ok((
418 out,
419 Signed {
420 signer: *signer,
421 sig,
422 inner: value,
423 },
424 ))
425 }
426
427 fn sign_struct_inner(
430 &self,
431 serialized: &[u8],
432 domain_separator: &[u8],
433 ) -> Signature {
434 let msg = sha256::digest_many(&[domain_separator, serialized]);
435 self.sign_raw(msg.as_slice())
436 }
437}
438
439impl fmt::Debug for KeyPair {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 f.debug_struct("ed25519::KeyPair")
442 .field("sk", &"..")
443 .field("pk", &hex::display(self.public_key().as_slice()))
444 .finish()
445 }
446}
447
448impl FromHex for KeyPair {
449 fn from_hex(s: &str) -> Result<Self, hex::DecodeError> {
450 <[u8; 32]>::from_hex(s).map(Self::from_seed_owned)
451 }
452}
453
454impl FromStr for KeyPair {
455 type Err = hex::DecodeError;
456 #[inline]
457 fn from_str(s: &str) -> Result<Self, Self::Err> {
458 Self::from_hex(s)
459 }
460}
461
462lexe_byte_array::impl_byte_array!(PublicKey, 32);
465lexe_byte_array::impl_fromstr_fromhex!(PublicKey, 32);
466lexe_byte_array::impl_debug_display_as_hex!(PublicKey);
467
468impl PublicKey {
469 pub const fn new(bytes: [u8; 32]) -> Self {
470 Self(bytes)
473 }
474
475 pub const fn from_ref(bytes: &[u8; 32]) -> &Self {
476 const_utils::const_ref_cast(bytes)
477 }
478}
479
480impl TryFrom<&[u8]> for PublicKey {
481 type Error = Error;
482
483 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
484 let pk =
485 <[u8; 32]>::try_from(bytes).map_err(|_| Error::InvalidPkLength)?;
486 Ok(Self::new(pk))
487 }
488}
489
490lexe_byte_array::impl_byte_array!(Signature, 64);
493lexe_byte_array::impl_fromstr_fromhex!(Signature, 64);
494lexe_byte_array::impl_debug_display_as_hex!(Signature);
495
496impl Signature {
497 pub const fn new(sig: [u8; 64]) -> Self {
498 Self(sig)
499 }
500
501 pub const fn from_ref(sig: &[u8; 64]) -> &Self {
502 const_utils::const_ref_cast(sig)
503 }
504}
505
506impl TryFrom<&[u8]> for Signature {
507 type Error = Error;
508 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
509 <[u8; 64]>::try_from(value)
510 .map(Signature)
511 .map_err(|_| Error::InvalidSignature)
512 }
513}
514
515impl<T: Signable> Signed<T> {
518 pub fn into_parts(self) -> (PublicKey, Signature, T) {
519 (self.signer, self.sig, self.inner)
520 }
521
522 pub fn inner(&self) -> &T {
523 &self.inner
524 }
525
526 pub fn signer(&self) -> &PublicKey {
527 &self.signer
528 }
529
530 pub fn signature(&self) -> &Signature {
531 &self.sig
532 }
533
534 pub fn as_ref(&self) -> Signed<&T> {
535 Signed {
536 signer: self.signer,
537 sig: self.sig,
538 inner: &self.inner,
539 }
540 }
541}
542
543impl<T: Signable + Serialize> Signed<T> {
544 pub fn serialize(&self) -> Result<Vec<u8>, bcs::Error> {
545 let len = bcs::serialized_size(&self.inner)? + SIGNED_STRUCT_OVERHEAD;
546 let mut out = Vec::with_capacity(len);
547 let mut writer = Cursor::new(&mut out);
548
549 writer.write_all(self.signer.as_slice()).unwrap();
552 writer.write_all(self.sig.as_slice()).unwrap();
553 bcs::serialize_into(&mut writer, &self.inner)?;
554
555 Ok(out)
556 }
557}
558
559impl<T: Signable + Clone> Signed<&T> {
560 pub fn cloned(&self) -> Signed<T> {
561 Signed {
562 signer: self.signer,
563 sig: self.sig,
564 inner: self.inner.clone(),
565 }
566 }
567}
568
569impl<T: Signable + Clone> Clone for Signed<T> {
570 fn clone(&self) -> Self {
571 Self {
572 signer: self.signer,
573 sig: self.sig,
574 inner: self.inner.clone(),
575 }
576 }
577}
578
579impl std::error::Error for Error {}
582
583impl fmt::Display for Error {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 let msg = match self {
586 Self::InvalidPkLength =>
587 "ed25519 public key must be exactly 32 bytes",
588 Self::UnexpectedAlgorithm =>
589 "the algorithm OID doesn't match the standard ed25519 OID",
590 Self::KeyDeserializeError =>
591 "failed deserializing PKCS#8-encoded key pair",
592 Self::PublicKeyMismatch =>
593 "derived public key doesn't match expected public key",
594 Self::InvalidSignature => "invalid signature",
595 Self::BcsDeserialize =>
596 "error deserializing inner struct to verify",
597 Self::SignedTooShort => "signed struct is too short",
598 Self::UnexpectedSigner =>
599 "message was signed with a different key pair than expected",
600 };
601 f.write_str(msg)
602 }
603}
604
605impl std::error::Error for InvalidSignature {}
608
609impl fmt::Display for InvalidSignature {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 f.write_str("invalid signature")
612 }
613}
614
615#[cfg(any(test, feature = "test-utils"))]
616mod arbitrary_impls {
617 use proptest::{
618 arbitrary::{Arbitrary, any},
619 strategy::{BoxedStrategy, Strategy},
620 };
621
622 use super::*;
623
624 impl Arbitrary for KeyPair {
625 type Parameters = ();
626 type Strategy = BoxedStrategy<Self>;
627 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
628 any::<[u8; 32]>()
629 .prop_map(|seed| Self::from_seed(&seed))
630 .boxed()
631 }
632 }
633
634 impl Arbitrary for PublicKey {
635 type Parameters = ();
636 type Strategy = BoxedStrategy<Self>;
637 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
638 any::<[u8; 32]>().prop_map(Self::new).boxed()
639 }
640 }
641}
642
643const PKCS_TEMPLATE_PREFIX: &[u8] = &[
668 0x30, 0x51, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
669 0x04, 0x22, 0x04, 0x20,
670];
671const PKCS_TEMPLATE_PREFIX_BAD: &[u8] = &[
672 0x30, 0x53, 0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
673 0x04, 0x22, 0x04, 0x20,
674];
675const PKCS_TEMPLATE_MIDDLE_BAD: &[u8] = &[0xa1, 0x23, 0x03, 0x21, 0x00];
676const PKCS_TEMPLATE_MIDDLE: &[u8] = &[0x81, 0x21, 0x00];
677const PKCS_TEMPLATE_KEY_IDX: usize = 16;
678
679const PKCS_LEN: usize = PKCS_TEMPLATE_PREFIX.len()
682 + SECRET_KEY_LEN
683 + PKCS_TEMPLATE_MIDDLE.len()
684 + PublicKey::LEN;
685const PKCS_LEN_BAD: usize = PKCS_TEMPLATE_PREFIX_BAD.len()
686 + SECRET_KEY_LEN
687 + PKCS_TEMPLATE_MIDDLE_BAD.len()
688 + PublicKey::LEN;
689
690lexe_std::const_assert_usize_eq!(PKCS_LEN, 83);
692lexe_std::const_assert_usize_eq!(PKCS_LEN_BAD, 85);
693
694fn serialize_keypair_pkcs8_der(
700 secret_key: &[u8; 32],
701 public_key: &[u8; 32],
702) -> [u8; PKCS_LEN] {
703 let mut out = [0u8; PKCS_LEN];
704 let key_start_idx = PKCS_TEMPLATE_KEY_IDX;
705
706 let prefix = PKCS_TEMPLATE_PREFIX;
707 let middle = PKCS_TEMPLATE_MIDDLE;
708
709 let key_end_idx = key_start_idx + secret_key.len();
710 out[..key_start_idx].copy_from_slice(prefix);
711 out[key_start_idx..key_end_idx].copy_from_slice(secret_key);
712 out[key_end_idx..(key_end_idx + middle.len())].copy_from_slice(middle);
713 out[(key_end_idx + middle.len())..].copy_from_slice(public_key);
714
715 out
716}
717
718fn deserialize_keypair_pkcs8_der(
724 bytes: &[u8],
725) -> Option<(&[u8; 32], &[u8; 32])> {
726 let (seed, pubkey) = if bytes.len() == PKCS_LEN {
727 let seed_mid_pubkey = bytes.strip_prefix(PKCS_TEMPLATE_PREFIX)?;
728 let (seed, mid_pubkey) = seed_mid_pubkey.split_at(SECRET_KEY_LEN);
729 let pubkey = mid_pubkey.strip_prefix(PKCS_TEMPLATE_MIDDLE)?;
730 (seed, pubkey)
731 } else if bytes.len() == PKCS_LEN_BAD {
732 let seed_mid_pubkey = bytes.strip_prefix(PKCS_TEMPLATE_PREFIX_BAD)?;
734 let (seed, mid_pubkey) = seed_mid_pubkey.split_at(SECRET_KEY_LEN);
735 let pubkey = mid_pubkey.strip_prefix(PKCS_TEMPLATE_MIDDLE_BAD)?;
736 (seed, pubkey)
737 } else {
738 return None;
739 };
740
741 let seed = <&[u8; 32]>::try_from(seed).unwrap();
742 let pubkey = <&[u8; 32]>::try_from(pubkey).unwrap();
743
744 Some((seed, pubkey))
745}
746
747#[cfg(test)]
748mod test {
749 use lexe_std::array;
750 use proptest::{arbitrary::any, prop_assume, proptest, strategy::Strategy};
751 use proptest_derive::Arbitrary;
752 use serde::{Deserialize, Serialize};
753
754 use super::*;
755 use crate::rng::FastRng;
756
757 #[derive(Arbitrary, Serialize, Deserialize)]
758 struct SignableBytes(Vec<u8>);
759
760 impl Signable for SignableBytes {
761 const DOMAIN_SEPARATOR: [u8; 32] =
762 array::pad(*b"LEXE-REALM::SignableBytes");
763 }
764
765 impl fmt::Debug for SignableBytes {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 f.debug_tuple("SignableBytes")
768 .field(&hex::display(&self.0))
769 .finish()
770 }
771 }
772
773 #[test]
774 fn test_serde_pkcs8_roundtrip() {
775 proptest!(|(seed in any::<[u8; 32]>())| {
776 let key_pair1 = KeyPair::from_seed(&seed);
777 let key_pair_bytes = key_pair1.serialize_pkcs8_der();
778 let key_pair2 =
779 KeyPair::deserialize_pkcs8_der(key_pair_bytes.as_slice())
780 .unwrap();
781
782 assert_eq!(key_pair1.secret_key(), key_pair2.secret_key());
783 assert_eq!(key_pair1.public_key(), key_pair2.public_key());
784 });
785 }
786
787 #[test]
788 fn test_pkcs8_der_snapshot() {
789 #[track_caller]
790 fn assert_pkcs8_roundtrip(hexstr: &str) {
791 let der = hex::decode(hexstr).unwrap();
792 let _ = KeyPair::deserialize_pkcs8_der(&der).unwrap();
793 }
794
795 assert_pkcs8_roundtrip(
797 "3053020101300506032b657004220420244ae26baa35db07ed4ea37908f111a8fa4cb81109f9897a133b8a8de6e800dca1230321007dc65033bee5975aab9bb06e1e514d29533173511446adc5a73a9540d2addbac",
798 );
799
800 assert_pkcs8_roundtrip(
802 "3051020101300506032b657004220420244ae26baa35db07ed4ea37908f111a8fa4cb81109f9897a133b8a8de6e800dc8121007dc65033bee5975aab9bb06e1e514d29533173511446adc5a73a9540d2addbac",
803 );
804 }
805
806 #[ignore]
810 #[test]
811 fn pkcs8_der_snapshot_data() {
812 let mut rng = FastRng::from_u64(202510211432);
813 let key = KeyPair::from_seed_owned(rng.gen_bytes());
814 println!("{}", hex::display(key.serialize_pkcs8_der().as_slice()));
815 }
816
817 #[test]
818 fn test_deserialize_pkcs8_different_lengths() {
819 for size in 0..=256 {
820 let bytes = vec![0x42_u8; size];
821 let _ = deserialize_keypair_pkcs8_der(&bytes);
822 }
823 }
824
825 #[test]
827 fn test_ed25519_test_vector() {
828 let sk: [u8; 32] = hex::decode_const(
829 b"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
830 );
831 let pk: [u8; 32] = hex::decode_const(
832 b"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
833 );
834 let msg: [u8; 2] = hex::decode_const(b"af82");
835 let sig: [u8; 64] = hex::decode_const(b"6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a");
836
837 let key_pair = KeyPair::from_seed(&sk);
838 let pubkey = key_pair.public_key();
839 assert_eq!(pubkey.as_array(), &pk);
840
841 let sig2 = key_pair.sign_raw(&msg);
842 assert_eq!(&sig, sig2.as_array());
843
844 verify::signed_bytes_by_signer(pubkey, &msg, &sig2).unwrap();
845 }
846
847 #[test]
849 fn test_reject_truncated_sig() {
850 proptest!(|(
851 key_pair in any::<KeyPair>(),
852 msg in any::<SignableBytes>()
853 )| {
854 let pubkey = key_pair.public_key();
855
856 let (sig, signed) = key_pair.sign_struct(&msg).unwrap();
857 let sig2 = signed.serialize().unwrap();
858 assert_eq!(&sig, &sig2);
859
860 let _ = verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig)
861 .unwrap();
862
863 for trunc_len in 0..SIGNED_STRUCT_OVERHEAD {
864 verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig[..trunc_len])
865 .unwrap_err();
866 verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig[(trunc_len+1)..])
867 .unwrap_err();
868 }
869 });
870 }
871
872 #[test]
875 fn test_reject_pad_sig() {
876 let cfg = proptest::test_runner::Config::with_cases(50);
877 proptest!(cfg, |(
878 key_pair in any::<KeyPair>(),
879 msg in any::<SignableBytes>(),
880 padding in any::<Vec<u8>>(),
881 )| {
882 prop_assume!(!padding.is_empty());
883
884 let pubkey = key_pair.public_key();
885
886 let (sig, signed) = key_pair.sign_struct(&msg).unwrap();
887 let sig2 = signed.serialize().unwrap();
888 assert_eq!(&sig, &sig2);
889
890 let _ = verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig)
891 .unwrap();
892
893 let mut sig2: Vec<u8> = Vec::with_capacity(sig.len() + padding.len());
894
895 for idx in 0..=sig.len() {
896 let (left, right) = sig.split_at(idx);
897
898 sig2.clear();
901 sig2.extend_from_slice(left);
902 sig2.extend_from_slice(&padding);
903 sig2.extend_from_slice(right);
904
905 verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig2)
906 .unwrap_err();
907 }
908 });
909 }
910
911 #[test]
914 fn test_reject_modified_sig() {
915 let arb_mutation = any::<Vec<u8>>()
916 .prop_filter("can't be empty or all zeroes", |m| {
917 !m.is_empty() && !m.iter().all(|x| x == &0u8)
918 });
919
920 proptest!(|(
921 key_pair in any::<KeyPair>(),
922 msg in any::<SignableBytes>(),
923 mut_offset in any::<usize>(),
924 mut mutation in arb_mutation,
925 )| {
926 let pubkey = key_pair.public_key();
927
928 let (mut sig, signed) = key_pair.sign_struct(&msg).unwrap();
929 let sig2 = signed.serialize().unwrap();
930 assert_eq!(&sig, &sig2);
931
932 mutation.truncate(sig.len());
933 prop_assume!(!mutation.is_empty() && !mutation.iter().all(|x| x == &0));
934
935 let _ = verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig)
936 .unwrap();
937
938 for (idx_mut, m) in mutation.into_iter().enumerate() {
941 let idx_sig = idx_mut.wrapping_add(mut_offset) % sig.len();
942 sig[idx_sig] ^= m;
943 }
944
945 verify::signed_struct_by_signer::<SignableBytes>(pubkey, &sig).unwrap_err();
946 });
947 }
948
949 #[test]
950 fn test_sign_verify() {
951 proptest!(|(key_pair in any::<KeyPair>(), msg in any::<Vec<u8>>())| {
952 let pubkey = key_pair.public_key();
953
954 let sig = key_pair.sign_raw(&msg);
955 verify::signed_bytes_by_signer(pubkey, &msg, &sig).unwrap();
956 });
957 }
958
959 #[test]
960 fn test_sign_verify_struct() {
961 #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
962 struct Foo(u32);
963
964 impl Signable for Foo {
965 const DOMAIN_SEPARATOR: [u8; 32] = array::pad(*b"LEXE-REALM::Foo");
966 }
967
968 #[derive(Debug, Serialize, Deserialize)]
969 struct Bar(u32);
970
971 impl Signable for Bar {
972 const DOMAIN_SEPARATOR: [u8; 32] = array::pad(*b"LEXE-REALM::Bar");
973 }
974
975 fn arb_foo() -> impl Strategy<Value = Foo> {
976 any::<u32>().prop_map(Foo)
977 }
978
979 proptest!(|(key_pair in any::<KeyPair>(), foo in arb_foo())| {
980 let signer = key_pair.public_key();
981 let (sig, signed) =
982 key_pair.sign_struct::<Foo>(&foo).unwrap();
983 let sig2 = signed.serialize().unwrap();
984 assert_eq!(&sig, &sig2);
985
986 let signed2 =
987 verify::signed_struct_by_signer::<Foo>(signer, &sig).unwrap();
988 assert_eq!(signed, signed2.as_ref());
989
990 verify::signed_struct_by_signer::<Bar>(signer, &sig).unwrap_err();
994 });
995 }
996}