1use std::fmt::{self, Debug, Display};
4use std::str::FromStr;
5
6use bip39::Mnemonic;
7use borsh::{BorshDeserialize, BorshSerialize};
8use ed25519_dalek::{Signer as _, SigningKey, VerifyingKey};
9use k256::elliptic_curve::sec1::FromEncodedPoint;
10use rand::rngs::OsRng;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use slipped10::{BIP32Path, Curve};
13
14use crate::error::{ParseKeyError, SignerError};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18#[repr(u8)]
19pub enum KeyType {
20 Ed25519 = 0,
22 Secp256k1 = 1,
24}
25
26impl KeyType {
27 pub fn as_str(&self) -> &'static str {
29 match self {
30 KeyType::Ed25519 => "ed25519",
31 KeyType::Secp256k1 => "secp256k1",
32 }
33 }
34
35 pub fn key_len(&self) -> usize {
37 match self {
38 KeyType::Ed25519 => 32,
39 KeyType::Secp256k1 => 33, }
41 }
42
43 pub fn signature_len(&self) -> usize {
45 match self {
46 KeyType::Ed25519 => 64,
47 KeyType::Secp256k1 => 65,
48 }
49 }
50}
51
52impl TryFrom<u8> for KeyType {
53 type Error = ParseKeyError;
54
55 fn try_from(value: u8) -> Result<Self, Self::Error> {
56 match value {
57 0 => Ok(KeyType::Ed25519),
58 1 => Ok(KeyType::Secp256k1),
59 _ => Err(ParseKeyError::UnknownKeyType(value.to_string())),
60 }
61 }
62}
63
64#[derive(Clone, PartialEq, Eq, Hash)]
66pub struct PublicKey {
67 key_type: KeyType,
68 data: Vec<u8>,
69}
70
71impl PublicKey {
72 pub fn ed25519_from_bytes(bytes: [u8; 32]) -> Self {
74 Self {
75 key_type: KeyType::Ed25519,
76 data: bytes.to_vec(),
77 }
78 }
79
80 pub fn key_type(&self) -> KeyType {
82 self.key_type
83 }
84
85 pub fn as_bytes(&self) -> &[u8] {
87 &self.data
88 }
89
90 pub fn as_ed25519_bytes(&self) -> Option<&[u8; 32]> {
92 if self.key_type == KeyType::Ed25519 && self.data.len() == 32 {
93 Some(self.data.as_slice().try_into().unwrap())
94 } else {
95 None
96 }
97 }
98}
99
100impl FromStr for PublicKey {
101 type Err = ParseKeyError;
102
103 fn from_str(s: &str) -> Result<Self, Self::Err> {
104 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
105
106 let key_type = match key_type {
107 "ed25519" => KeyType::Ed25519,
108 "secp256k1" => KeyType::Secp256k1,
109 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
110 };
111
112 let data = bs58::decode(data_str)
113 .into_vec()
114 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
115
116 if data.len() != key_type.key_len() {
117 return Err(ParseKeyError::InvalidLength {
118 expected: key_type.key_len(),
119 actual: data.len(),
120 });
121 }
122
123 match key_type {
125 KeyType::Ed25519 => {
126 let bytes: [u8; 32] = data
128 .as_slice()
129 .try_into()
130 .map_err(|_| ParseKeyError::InvalidCurvePoint)?;
131 VerifyingKey::from_bytes(&bytes).map_err(|_| ParseKeyError::InvalidCurvePoint)?;
132 }
133 KeyType::Secp256k1 => {
134 let encoded = k256::EncodedPoint::from_bytes(&data)
137 .map_err(|_| ParseKeyError::InvalidCurvePoint)?;
138 let point = k256::AffinePoint::from_encoded_point(&encoded);
139 if point.is_none().into() {
140 return Err(ParseKeyError::InvalidCurvePoint);
141 }
142 }
143 }
144
145 Ok(Self { key_type, data })
146 }
147}
148
149impl TryFrom<&str> for PublicKey {
150 type Error = ParseKeyError;
151
152 fn try_from(s: &str) -> Result<Self, Self::Error> {
153 s.parse()
154 }
155}
156
157impl Display for PublicKey {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 write!(
160 f,
161 "{}:{}",
162 self.key_type.as_str(),
163 bs58::encode(&self.data).into_string()
164 )
165 }
166}
167
168impl Debug for PublicKey {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 write!(f, "PublicKey({})", self)
171 }
172}
173
174impl Serialize for PublicKey {
175 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
176 s.serialize_str(&self.to_string())
177 }
178}
179
180impl<'de> Deserialize<'de> for PublicKey {
181 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
182 let s: String = serde::Deserialize::deserialize(d)?;
183 s.parse().map_err(serde::de::Error::custom)
184 }
185}
186
187impl BorshSerialize for PublicKey {
188 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
189 borsh::BorshSerialize::serialize(&(self.key_type as u8), writer)?;
190 writer.write_all(&self.data)?;
191 Ok(())
192 }
193}
194
195impl BorshDeserialize for PublicKey {
196 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
197 let key_type_byte = u8::deserialize_reader(reader)?;
198 let key_type = KeyType::try_from(key_type_byte)
199 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
200
201 let mut data = vec![0u8; key_type.key_len()];
202 reader.read_exact(&mut data)?;
203
204 match key_type {
206 KeyType::Ed25519 => {
207 let bytes: [u8; 32] = data.as_slice().try_into().map_err(|_| {
208 std::io::Error::new(
209 std::io::ErrorKind::InvalidData,
210 "invalid ed25519 key length",
211 )
212 })?;
213 VerifyingKey::from_bytes(&bytes).map_err(|_| {
214 std::io::Error::new(
215 std::io::ErrorKind::InvalidData,
216 "invalid ed25519 curve point",
217 )
218 })?;
219 }
220 KeyType::Secp256k1 => {
221 let encoded = k256::EncodedPoint::from_bytes(&data).map_err(|_| {
222 std::io::Error::new(
223 std::io::ErrorKind::InvalidData,
224 "invalid secp256k1 encoding",
225 )
226 })?;
227 let point = k256::AffinePoint::from_encoded_point(&encoded);
228 if point.is_none().into() {
229 return Err(std::io::Error::new(
230 std::io::ErrorKind::InvalidData,
231 "invalid secp256k1 curve point",
232 ));
233 }
234 }
235 }
236
237 Ok(Self { key_type, data })
238 }
239}
240
241pub const DEFAULT_HD_PATH: &str = "m/44'/397'/0'";
244
245pub const DEFAULT_WORD_COUNT: usize = 12;
247
248#[derive(Clone)]
250pub struct SecretKey {
251 key_type: KeyType,
252 data: Vec<u8>,
253}
254
255impl SecretKey {
256 pub fn generate_ed25519() -> Self {
258 let signing_key = SigningKey::generate(&mut OsRng);
259 Self {
260 key_type: KeyType::Ed25519,
261 data: signing_key.to_bytes().to_vec(),
262 }
263 }
264
265 pub fn ed25519_from_bytes(bytes: [u8; 32]) -> Self {
267 Self {
268 key_type: KeyType::Ed25519,
269 data: bytes.to_vec(),
270 }
271 }
272
273 pub fn key_type(&self) -> KeyType {
275 self.key_type
276 }
277
278 pub fn as_bytes(&self) -> &[u8] {
280 &self.data
281 }
282
283 pub fn public_key(&self) -> PublicKey {
285 match self.key_type {
286 KeyType::Ed25519 => {
287 let bytes: [u8; 32] = self
288 .data
289 .as_slice()
290 .try_into()
291 .expect("invalid ed25519 key");
292 let signing_key = SigningKey::from_bytes(&bytes);
293 let verifying_key = signing_key.verifying_key();
294 PublicKey::ed25519_from_bytes(verifying_key.to_bytes())
295 }
296 KeyType::Secp256k1 => {
297 unimplemented!("secp256k1 not yet supported")
298 }
299 }
300 }
301
302 pub fn sign(&self, message: &[u8]) -> Signature {
304 match self.key_type {
305 KeyType::Ed25519 => {
306 let bytes: [u8; 32] = self
307 .data
308 .as_slice()
309 .try_into()
310 .expect("invalid ed25519 key");
311 let signing_key = SigningKey::from_bytes(&bytes);
312 let signature = signing_key.sign(message);
313 Signature {
314 key_type: KeyType::Ed25519,
315 data: signature.to_bytes().to_vec(),
316 }
317 }
318 KeyType::Secp256k1 => {
319 unimplemented!("secp256k1 not yet supported")
320 }
321 }
322 }
323
324 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
346 Self::from_seed_phrase_with_path(phrase, DEFAULT_HD_PATH)
347 }
348
349 pub fn from_seed_phrase_with_path(
368 phrase: impl AsRef<str>,
369 hd_path: impl AsRef<str>,
370 ) -> Result<Self, SignerError> {
371 Self::from_seed_phrase_with_path_and_passphrase(phrase, hd_path, None)
372 }
373
374 pub fn from_seed_phrase_with_path_and_passphrase(
398 phrase: impl AsRef<str>,
399 hd_path: impl AsRef<str>,
400 passphrase: Option<&str>,
401 ) -> Result<Self, SignerError> {
402 let normalized = phrase
404 .as_ref()
405 .trim()
406 .to_lowercase()
407 .split_whitespace()
408 .collect::<Vec<_>>()
409 .join(" ");
410
411 let mnemonic: Mnemonic = normalized
412 .parse()
413 .map_err(|_| SignerError::InvalidSeedPhrase)?;
414
415 let seed = mnemonic.to_seed(passphrase.unwrap_or(""));
417
418 let path: BIP32Path = hd_path
420 .as_ref()
421 .parse()
422 .map_err(|e| SignerError::KeyDerivationFailed(format!("Invalid HD path: {}", e)))?;
423
424 let derived =
426 slipped10::derive_key_from_path(&seed, Curve::Ed25519, &path).map_err(|e| {
427 SignerError::KeyDerivationFailed(format!("SLIP-10 derivation failed: {:?}", e))
428 })?;
429
430 Ok(Self::ed25519_from_bytes(derived.key))
431 }
432
433 pub fn generate_with_seed_phrase() -> Result<(String, Self), SignerError> {
447 Self::generate_with_seed_phrase_custom(DEFAULT_WORD_COUNT, DEFAULT_HD_PATH, None)
448 }
449
450 pub fn generate_with_seed_phrase_words(
465 word_count: usize,
466 ) -> Result<(String, Self), SignerError> {
467 Self::generate_with_seed_phrase_custom(word_count, DEFAULT_HD_PATH, None)
468 }
469
470 pub fn generate_with_seed_phrase_custom(
478 word_count: usize,
479 hd_path: impl AsRef<str>,
480 passphrase: Option<&str>,
481 ) -> Result<(String, Self), SignerError> {
482 let phrase = generate_seed_phrase(word_count)?;
483 let secret_key =
484 Self::from_seed_phrase_with_path_and_passphrase(&phrase, hd_path, passphrase)?;
485 Ok((phrase, secret_key))
486 }
487}
488
489impl FromStr for SecretKey {
490 type Err = ParseKeyError;
491
492 fn from_str(s: &str) -> Result<Self, Self::Err> {
493 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
494
495 let key_type = match key_type {
496 "ed25519" => KeyType::Ed25519,
497 "secp256k1" => KeyType::Secp256k1,
498 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
499 };
500
501 let data = bs58::decode(data_str)
502 .into_vec()
503 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
504
505 let valid_len = match key_type {
508 KeyType::Ed25519 => data.len() == 32 || data.len() == 64,
509 KeyType::Secp256k1 => data.len() == 32,
510 };
511 if !valid_len {
512 return Err(ParseKeyError::InvalidLength {
513 expected: 32,
514 actual: data.len(),
515 });
516 }
517
518 let data = if data.len() == 64 {
520 data[..32].to_vec()
521 } else {
522 data
523 };
524
525 Ok(Self { key_type, data })
526 }
527}
528
529impl TryFrom<&str> for SecretKey {
530 type Error = ParseKeyError;
531
532 fn try_from(s: &str) -> Result<Self, Self::Error> {
533 s.parse()
534 }
535}
536
537impl Display for SecretKey {
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 write!(
540 f,
541 "{}:{}",
542 self.key_type.as_str(),
543 bs58::encode(&self.data).into_string()
544 )
545 }
546}
547
548impl Debug for SecretKey {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550 write!(f, "SecretKey({}:***)", self.key_type.as_str())
551 }
552}
553
554#[derive(Clone, PartialEq, Eq)]
556pub struct Signature {
557 key_type: KeyType,
558 data: Vec<u8>,
559}
560
561impl Signature {
562 pub fn ed25519_from_bytes(bytes: [u8; 64]) -> Self {
564 Self {
565 key_type: KeyType::Ed25519,
566 data: bytes.to_vec(),
567 }
568 }
569
570 pub fn key_type(&self) -> KeyType {
572 self.key_type
573 }
574
575 pub fn as_bytes(&self) -> &[u8] {
577 &self.data
578 }
579
580 pub fn verify(&self, message: &[u8], public_key: &PublicKey) -> bool {
582 if self.key_type != public_key.key_type() {
583 return false;
584 }
585
586 match self.key_type {
587 KeyType::Ed25519 => {
588 let Some(pk_bytes) = public_key.as_ed25519_bytes() else {
589 return false;
590 };
591 let Ok(verifying_key) = VerifyingKey::from_bytes(pk_bytes) else {
592 return false;
593 };
594 let sig_bytes: [u8; 64] = match self.data.as_slice().try_into() {
595 Ok(b) => b,
596 Err(_) => return false,
597 };
598 let signature = ed25519_dalek::Signature::from_bytes(&sig_bytes);
599 verifying_key.verify_strict(message, &signature).is_ok()
600 }
601 KeyType::Secp256k1 => false, }
603 }
604}
605
606impl FromStr for Signature {
607 type Err = ParseKeyError;
608
609 fn from_str(s: &str) -> Result<Self, Self::Err> {
610 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
611
612 let key_type = match key_type {
613 "ed25519" => KeyType::Ed25519,
614 "secp256k1" => KeyType::Secp256k1,
615 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
616 };
617
618 let data = bs58::decode(data_str)
619 .into_vec()
620 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
621
622 if data.len() != key_type.signature_len() {
623 return Err(ParseKeyError::InvalidLength {
624 expected: key_type.signature_len(),
625 actual: data.len(),
626 });
627 }
628
629 Ok(Self { key_type, data })
630 }
631}
632
633impl Display for Signature {
634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635 write!(
636 f,
637 "{}:{}",
638 self.key_type.as_str(),
639 bs58::encode(&self.data).into_string()
640 )
641 }
642}
643
644impl Debug for Signature {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 write!(f, "Signature({})", self)
647 }
648}
649
650impl Serialize for Signature {
651 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
652 s.serialize_str(&self.to_string())
653 }
654}
655
656impl<'de> Deserialize<'de> for Signature {
657 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
658 let s: String = serde::Deserialize::deserialize(d)?;
659 s.parse().map_err(serde::de::Error::custom)
660 }
661}
662
663impl BorshSerialize for Signature {
664 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
665 borsh::BorshSerialize::serialize(&(self.key_type as u8), writer)?;
666 writer.write_all(&self.data)?;
667 Ok(())
668 }
669}
670
671impl BorshDeserialize for Signature {
672 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
673 let key_type_byte = u8::deserialize_reader(reader)?;
674 let key_type = KeyType::try_from(key_type_byte)
675 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
676
677 let mut data = vec![0u8; key_type.signature_len()];
678 reader.read_exact(&mut data)?;
679
680 Ok(Self { key_type, data })
681 }
682}
683
684pub fn generate_seed_phrase(word_count: usize) -> Result<String, SignerError> {
703 use rand::RngCore;
704
705 let entropy_bytes = match word_count {
707 12 => 16,
708 15 => 20,
709 18 => 24,
710 21 => 28,
711 24 => 32,
712 _ => {
713 return Err(SignerError::KeyDerivationFailed(format!(
714 "Invalid word count: {}. Must be 12, 15, 18, 21, or 24",
715 word_count
716 )));
717 }
718 };
719
720 let mut entropy = vec![0u8; entropy_bytes];
721 OsRng.fill_bytes(&mut entropy);
722
723 let mnemonic = Mnemonic::from_entropy(&entropy).map_err(|e| {
724 SignerError::KeyDerivationFailed(format!("Failed to generate mnemonic: {}", e))
725 })?;
726
727 Ok(mnemonic.to_string())
728}
729
730#[derive(Clone)]
758pub struct KeyPair {
759 pub secret_key: SecretKey,
761 pub public_key: PublicKey,
763}
764
765impl KeyPair {
766 pub fn random() -> Self {
778 Self::random_ed25519()
779 }
780
781 pub fn random_ed25519() -> Self {
792 let secret_key = SecretKey::generate_ed25519();
793 let public_key = secret_key.public_key();
794 Self {
795 secret_key,
796 public_key,
797 }
798 }
799
800 pub fn from_secret_key(secret_key: SecretKey) -> Self {
811 let public_key = secret_key.public_key();
812 Self {
813 secret_key,
814 public_key,
815 }
816 }
817
818 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
829 let secret_key = SecretKey::from_seed_phrase(phrase)?;
830 Ok(Self::from_secret_key(secret_key))
831 }
832
833 pub fn random_with_seed_phrase() -> Result<(String, Self), SignerError> {
847 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase()?;
848 Ok((phrase, Self::from_secret_key(secret_key)))
849 }
850}
851
852impl std::fmt::Debug for KeyPair {
853 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
854 f.debug_struct("KeyPair")
855 .field("public_key", &self.public_key)
856 .field("secret_key", &"***")
857 .finish()
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use super::*;
864
865 #[test]
866 fn test_generate_and_sign() {
867 let secret = SecretKey::generate_ed25519();
868 let public = secret.public_key();
869 let message = b"hello world";
870
871 let signature = secret.sign(message);
872 assert!(signature.verify(message, &public));
873 assert!(!signature.verify(b"wrong message", &public));
874 }
875
876 #[test]
877 fn test_public_key_roundtrip() {
878 let secret = SecretKey::generate_ed25519();
879 let public = secret.public_key();
880 let s = public.to_string();
881 let parsed: PublicKey = s.parse().unwrap();
882 assert_eq!(public, parsed);
883 }
884
885 #[test]
886 fn test_secret_key_roundtrip() {
887 let secret = SecretKey::generate_ed25519();
888 let s = secret.to_string();
889 let parsed: SecretKey = s.parse().unwrap();
890 assert_eq!(secret.public_key(), parsed.public_key());
891 }
892
893 #[test]
898 fn test_generate_seed_phrase_12_words() {
899 let phrase = generate_seed_phrase(12).unwrap();
900 assert_eq!(phrase.split_whitespace().count(), 12);
901 }
902
903 #[test]
904 fn test_generate_seed_phrase_24_words() {
905 let phrase = generate_seed_phrase(24).unwrap();
906 assert_eq!(phrase.split_whitespace().count(), 24);
907 }
908
909 #[test]
910 fn test_generate_seed_phrase_invalid_word_count() {
911 let result = generate_seed_phrase(13);
912 assert!(result.is_err());
913 }
914
915 const TEST_PHRASE: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
917
918 #[test]
919 fn test_from_seed_phrase_known_vector() {
920 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
922
923 let secret_key2 = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
925 assert_eq!(secret_key.public_key(), secret_key2.public_key());
926 }
927
928 #[test]
929 fn test_from_seed_phrase_whitespace_normalization() {
930 let phrase1 = TEST_PHRASE;
931 let phrase2 = " abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ";
932 let phrase3 = "ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABOUT";
933
934 let key1 = SecretKey::from_seed_phrase(phrase1).unwrap();
935 let key2 = SecretKey::from_seed_phrase(phrase2).unwrap();
936 let key3 = SecretKey::from_seed_phrase(phrase3).unwrap();
937
938 assert_eq!(key1.public_key(), key2.public_key());
939 assert_eq!(key1.public_key(), key3.public_key());
940 }
941
942 #[test]
943 fn test_from_seed_phrase_invalid() {
944 let result = SecretKey::from_seed_phrase("invalid words that are not a mnemonic");
945 assert!(result.is_err());
946 }
947
948 #[test]
949 fn test_from_seed_phrase_different_paths() {
950 let key1 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/0'").unwrap();
951 let key2 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/1'").unwrap();
952
953 assert_ne!(key1.public_key(), key2.public_key());
955 }
956
957 #[test]
958 fn test_from_seed_phrase_with_passphrase() {
959 let key_no_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
960 TEST_PHRASE,
961 DEFAULT_HD_PATH,
962 None,
963 )
964 .unwrap();
965
966 let key_with_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
967 TEST_PHRASE,
968 DEFAULT_HD_PATH,
969 Some("my-password"),
970 )
971 .unwrap();
972
973 assert_ne!(key_no_pass.public_key(), key_with_pass.public_key());
975 }
976
977 #[test]
978 fn test_generate_with_seed_phrase() {
979 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase().unwrap();
980
981 assert_eq!(phrase.split_whitespace().count(), 12);
983
984 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
986 assert_eq!(secret_key.public_key(), derived.public_key());
987 }
988
989 #[test]
990 fn test_generate_with_seed_phrase_24_words() {
991 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase_words(24).unwrap();
992
993 assert_eq!(phrase.split_whitespace().count(), 24);
994
995 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
996 assert_eq!(secret_key.public_key(), derived.public_key());
997 }
998
999 #[test]
1000 fn test_seed_phrase_key_can_sign() {
1001 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1002
1003 let message = b"test message";
1004 let signature = secret_key.sign(message);
1005 let public_key = secret_key.public_key();
1006
1007 assert!(signature.verify(message, &public_key));
1008 }
1009
1010 #[test]
1015 fn test_secp256k1_invalid_curve_point_rejected() {
1016 let invalid_key = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj";
1019 let result: Result<PublicKey, _> = invalid_key.parse();
1020 assert!(result.is_err());
1021 assert!(matches!(
1022 result.unwrap_err(),
1023 ParseKeyError::InvalidCurvePoint | ParseKeyError::InvalidLength { .. }
1024 ));
1025 }
1026
1027 #[test]
1028 fn test_secp256k1_valid_curve_point_accepted() {
1029 let valid_key = "secp256k1:5r22SrjrDvgY3wdQsnjgxkeAbU1VcM71FYvALEQWihjM3Xk4Be1CpETTqFccChQr4iJwDroSDVmgaWZv2AcXvYeL";
1031 let result: Result<PublicKey, _> = valid_key.parse();
1032 assert!(result.is_err());
1035 }
1036
1037 #[test]
1038 fn test_ed25519_valid_key_accepted() {
1039 let valid_key = "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp";
1041 let result: Result<PublicKey, _> = valid_key.parse();
1042 assert!(result.is_ok());
1043 }
1044
1045 #[test]
1046 fn test_ed25519_invalid_curve_point_rejected() {
1047 let invalid_bytes = [
1056 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1057 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1058 0xFF, 0xFF, 0xFF, 0x7F,
1059 ];
1060 let encoded = bs58::encode(&invalid_bytes).into_string();
1061 let invalid_key = format!("ed25519:{}", encoded);
1062 let result: Result<PublicKey, _> = invalid_key.parse();
1063 if let Err(err) = result {
1064 assert!(matches!(err, ParseKeyError::InvalidCurvePoint));
1065 } else {
1066 eprintln!(
1068 "Note: ed25519 point decompression accepted test bytes - validation may be too lenient"
1069 );
1070 }
1071 }
1072
1073 #[test]
1074 fn test_borsh_deserialize_validates_curve_point() {
1075 use borsh::BorshDeserialize;
1076
1077 let mut invalid_bytes = vec![1u8]; invalid_bytes.extend_from_slice(&[0u8; 33]); let result = PublicKey::try_from_slice(&invalid_bytes);
1083 assert!(result.is_err());
1084 }
1085
1086 #[test]
1087 fn test_signature_from_str_roundtrip() {
1088 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1089 let sig: Signature = sig_str.parse().unwrap();
1090 assert_eq!(sig.key_type(), KeyType::Ed25519);
1091 assert_eq!(sig.as_bytes().len(), 64);
1092 assert_eq!(sig.to_string(), sig_str);
1093 }
1094
1095 #[test]
1096 fn test_signature_from_str_invalid_format() {
1097 assert!("no_colon".parse::<Signature>().is_err());
1098 assert!("unknown:abc".parse::<Signature>().is_err());
1099 assert!("ed25519:invalid!!!".parse::<Signature>().is_err());
1100 assert!("ed25519:AAAA".parse::<Signature>().is_err()); }
1102
1103 #[test]
1104 fn test_signature_serde_roundtrip() {
1105 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1106 let sig: Signature = sig_str.parse().unwrap();
1107 let json = serde_json::to_value(&sig).unwrap();
1108 assert_eq!(json.as_str().unwrap(), sig_str);
1109 let parsed: Signature = serde_json::from_value(json).unwrap();
1110 assert_eq!(sig, parsed);
1111 }
1112}