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, ToEncodedPoint};
10use rand::rngs::OsRng;
11use serde_with::{DeserializeFromStr, SerializeDisplay};
12use sha2::Digest;
13
14use super::hd::{derive_ed25519_slip10, parse_hd_path};
15use crate::error::{ParseKeyError, SignerError};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
19#[repr(u8)]
20pub enum KeyType {
21 Ed25519 = 0,
23 Secp256k1 = 1,
25}
26
27impl KeyType {
28 pub fn as_str(&self) -> &'static str {
30 match self {
31 KeyType::Ed25519 => "ed25519",
32 KeyType::Secp256k1 => "secp256k1",
33 }
34 }
35
36 pub fn public_key_len(&self) -> usize {
38 match self {
39 KeyType::Ed25519 => 32,
40 KeyType::Secp256k1 => 64, }
42 }
43
44 pub fn signature_len(&self) -> usize {
46 match self {
47 KeyType::Ed25519 => 64,
48 KeyType::Secp256k1 => 65,
49 }
50 }
51}
52
53impl TryFrom<u8> for KeyType {
54 type Error = ParseKeyError;
55
56 fn try_from(value: u8) -> Result<Self, Self::Error> {
57 match value {
58 0 => Ok(KeyType::Ed25519),
59 1 => Ok(KeyType::Secp256k1),
60 _ => Err(ParseKeyError::UnknownKeyType(value.to_string())),
61 }
62 }
63}
64
65#[derive(Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr)]
71pub enum PublicKey {
72 Ed25519([u8; 32]),
74 Secp256k1([u8; 64]),
79}
80
81impl PublicKey {
82 pub fn ed25519_from_bytes(bytes: [u8; 32]) -> Self {
84 Self::Ed25519(bytes)
85 }
86
87 pub fn secp256k1_from_bytes(bytes: [u8; 64]) -> Self {
98 let mut uncompressed = [0u8; 65];
100 uncompressed[0] = 0x04;
101 uncompressed[1..].copy_from_slice(&bytes);
102 let encoded = k256::EncodedPoint::from_bytes(uncompressed.as_ref())
103 .expect("invalid secp256k1 SEC1 encoding");
104 let point = k256::AffinePoint::from_encoded_point(&encoded);
105 assert!(bool::from(point.is_some()), "invalid secp256k1 curve point");
106
107 Self::Secp256k1(bytes)
108 }
109
110 pub fn secp256k1_from_compressed(bytes: [u8; 33]) -> Self {
119 let encoded = k256::EncodedPoint::from_bytes(bytes.as_ref())
120 .expect("invalid secp256k1 SEC1 encoding");
121 let point = k256::AffinePoint::from_encoded_point(&encoded);
122 let point: k256::AffinePoint = Option::from(point).expect("invalid secp256k1 curve point");
123
124 let uncompressed = point.to_encoded_point(false);
126 let uncompressed_bytes: &[u8] = uncompressed.as_bytes();
127 assert_eq!(uncompressed_bytes.len(), 65);
128 assert_eq!(uncompressed_bytes[0], 0x04);
129
130 let mut result = [0u8; 64];
132 result.copy_from_slice(&uncompressed_bytes[1..]);
133 Self::Secp256k1(result)
134 }
135
136 pub fn secp256k1_from_uncompressed(bytes: [u8; 65]) -> Self {
146 let encoded = k256::EncodedPoint::from_bytes(bytes.as_ref())
147 .expect("invalid secp256k1 SEC1 encoding");
148 let point = k256::AffinePoint::from_encoded_point(&encoded);
149 assert!(bool::from(point.is_some()), "invalid secp256k1 curve point");
150
151 let mut result = [0u8; 64];
153 result.copy_from_slice(&bytes[1..]);
154 Self::Secp256k1(result)
155 }
156
157 pub fn key_type(&self) -> KeyType {
159 match self {
160 Self::Ed25519(_) => KeyType::Ed25519,
161 Self::Secp256k1(_) => KeyType::Secp256k1,
162 }
163 }
164
165 pub fn as_bytes(&self) -> &[u8] {
167 match self {
168 Self::Ed25519(bytes) => bytes.as_slice(),
169 Self::Secp256k1(bytes) => bytes.as_slice(),
170 }
171 }
172
173 pub fn as_ed25519_bytes(&self) -> Option<&[u8; 32]> {
175 match self {
176 Self::Ed25519(bytes) => Some(bytes),
177 _ => None,
178 }
179 }
180
181 pub fn as_secp256k1_bytes(&self) -> Option<&[u8; 64]> {
184 match self {
185 Self::Secp256k1(bytes) => Some(bytes),
186 _ => None,
187 }
188 }
189}
190
191impl FromStr for PublicKey {
192 type Err = ParseKeyError;
193
194 fn from_str(s: &str) -> Result<Self, Self::Err> {
195 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
196
197 let key_type = match key_type {
198 "ed25519" => KeyType::Ed25519,
199 "secp256k1" => KeyType::Secp256k1,
200 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
201 };
202
203 let data = bs58::decode(data_str)
204 .into_vec()
205 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
206
207 if data.len() != key_type.public_key_len() {
208 return Err(ParseKeyError::InvalidLength {
209 expected: key_type.public_key_len(),
210 actual: data.len(),
211 });
212 }
213
214 match key_type {
215 KeyType::Ed25519 => {
216 let bytes: [u8; 32] = data
217 .as_slice()
218 .try_into()
219 .map_err(|_| ParseKeyError::InvalidCurvePoint)?;
220 VerifyingKey::from_bytes(&bytes).map_err(|_| ParseKeyError::InvalidCurvePoint)?;
221 Ok(Self::Ed25519(bytes))
222 }
223 KeyType::Secp256k1 => {
224 let mut uncompressed = [0u8; 65];
226 uncompressed[0] = 0x04;
227 uncompressed[1..].copy_from_slice(&data);
228 let encoded = k256::EncodedPoint::from_bytes(uncompressed)
229 .map_err(|_| ParseKeyError::InvalidCurvePoint)?;
230 let point = k256::AffinePoint::from_encoded_point(&encoded);
231 if point.is_none().into() {
232 return Err(ParseKeyError::InvalidCurvePoint);
233 }
234 let bytes: [u8; 64] = data
235 .as_slice()
236 .try_into()
237 .map_err(|_| ParseKeyError::InvalidCurvePoint)?;
238 Ok(Self::Secp256k1(bytes))
239 }
240 }
241 }
242}
243
244impl TryFrom<&str> for PublicKey {
245 type Error = ParseKeyError;
246
247 fn try_from(s: &str) -> Result<Self, Self::Error> {
248 s.parse()
249 }
250}
251
252impl Display for PublicKey {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 write!(
255 f,
256 "{}:{}",
257 self.key_type().as_str(),
258 bs58::encode(self.as_bytes()).into_string()
259 )
260 }
261}
262
263impl Debug for PublicKey {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 write!(f, "PublicKey({})", self)
266 }
267}
268
269impl BorshSerialize for PublicKey {
270 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
271 borsh::BorshSerialize::serialize(&(self.key_type() as u8), writer)?;
272 writer.write_all(self.as_bytes())?;
273 Ok(())
274 }
275}
276
277impl BorshDeserialize for PublicKey {
278 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
279 let key_type_byte = u8::deserialize_reader(reader)?;
280 let key_type = KeyType::try_from(key_type_byte)
281 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
282
283 match key_type {
284 KeyType::Ed25519 => {
285 let mut bytes = [0u8; 32];
286 reader.read_exact(&mut bytes)?;
287 VerifyingKey::from_bytes(&bytes).map_err(|_| {
288 std::io::Error::new(
289 std::io::ErrorKind::InvalidData,
290 "invalid ed25519 curve point",
291 )
292 })?;
293 Ok(Self::Ed25519(bytes))
294 }
295 KeyType::Secp256k1 => {
296 let mut bytes = [0u8; 64];
297 reader.read_exact(&mut bytes)?;
298 let mut uncompressed = [0u8; 65];
300 uncompressed[0] = 0x04;
301 uncompressed[1..].copy_from_slice(&bytes);
302 let encoded = k256::EncodedPoint::from_bytes(uncompressed).map_err(|_| {
303 std::io::Error::new(
304 std::io::ErrorKind::InvalidData,
305 "invalid secp256k1 encoding",
306 )
307 })?;
308 let point = k256::AffinePoint::from_encoded_point(&encoded);
309 if point.is_none().into() {
310 return Err(std::io::Error::new(
311 std::io::ErrorKind::InvalidData,
312 "invalid secp256k1 curve point",
313 ));
314 }
315 Ok(Self::Secp256k1(bytes))
316 }
317 }
318 }
319}
320
321pub const DEFAULT_HD_PATH: &str = "m/44'/397'/0'";
324
325pub const DEFAULT_WORD_COUNT: usize = 12;
327
328#[derive(Clone, SerializeDisplay, DeserializeFromStr)]
330pub enum SecretKey {
331 Ed25519([u8; 32]),
333 Secp256k1([u8; 32]),
335}
336
337impl SecretKey {
338 pub fn generate_ed25519() -> Self {
340 let signing_key = SigningKey::generate(&mut OsRng);
341 Self::Ed25519(signing_key.to_bytes())
342 }
343
344 pub fn ed25519_from_bytes(bytes: [u8; 32]) -> Self {
346 Self::Ed25519(bytes)
347 }
348
349 pub fn generate_secp256k1() -> Self {
351 let secret_key = k256::SecretKey::random(&mut OsRng);
352 let mut bytes = [0u8; 32];
353 bytes.copy_from_slice(&secret_key.to_bytes());
354 Self::Secp256k1(bytes)
355 }
356
357 pub fn secp256k1_from_bytes(bytes: [u8; 32]) -> Result<Self, ParseKeyError> {
362 k256::SecretKey::from_bytes((&bytes).into()).map_err(|_| ParseKeyError::InvalidScalar)?;
363 Ok(Self::Secp256k1(bytes))
364 }
365
366 pub fn key_type(&self) -> KeyType {
368 match self {
369 Self::Ed25519(_) => KeyType::Ed25519,
370 Self::Secp256k1(_) => KeyType::Secp256k1,
371 }
372 }
373
374 pub fn as_bytes(&self) -> &[u8] {
376 match self {
377 Self::Ed25519(bytes) => bytes.as_slice(),
378 Self::Secp256k1(bytes) => bytes.as_slice(),
379 }
380 }
381
382 pub fn public_key(&self) -> PublicKey {
384 match self {
385 Self::Ed25519(bytes) => {
386 let signing_key = SigningKey::from_bytes(bytes);
387 let verifying_key = signing_key.verifying_key();
388 PublicKey::Ed25519(verifying_key.to_bytes())
389 }
390 Self::Secp256k1(bytes) => {
391 let secret_key =
392 k256::SecretKey::from_bytes(bytes.into()).expect("invalid secp256k1 key");
393 let public_key = secret_key.public_key();
394 let uncompressed = public_key.to_encoded_point(false);
396 let uncompressed_bytes: &[u8] = uncompressed.as_bytes();
397 assert_eq!(uncompressed_bytes.len(), 65);
398 let mut result = [0u8; 64];
400 result.copy_from_slice(&uncompressed_bytes[1..]);
401 PublicKey::Secp256k1(result)
402 }
403 }
404 }
405
406 pub fn sign(&self, message: &[u8]) -> Signature {
408 match self {
409 Self::Ed25519(bytes) => {
410 let signing_key = SigningKey::from_bytes(bytes);
411 let signature = signing_key.sign(message);
412 Signature::Ed25519(signature.to_bytes())
413 }
414 Self::Secp256k1(bytes) => {
415 let signing_key = k256::ecdsa::SigningKey::from_bytes(bytes.into())
416 .expect("invalid secp256k1 key");
417
418 let hash = sha2::Sha256::digest(message);
420 let (signature, recovery_id) = signing_key
421 .sign_prehash_recoverable(&hash)
422 .expect("secp256k1 signing failed");
423
424 let mut sig_bytes = [0u8; 65];
426 sig_bytes[..64].copy_from_slice(&signature.to_bytes());
427 sig_bytes[64] = recovery_id.to_byte();
428
429 Signature::Secp256k1(sig_bytes)
430 }
431 }
432 }
433
434 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
456 Self::from_seed_phrase_with_path(phrase, DEFAULT_HD_PATH)
457 }
458
459 pub fn from_seed_phrase_with_path(
478 phrase: impl AsRef<str>,
479 hd_path: impl AsRef<str>,
480 ) -> Result<Self, SignerError> {
481 Self::from_seed_phrase_with_path_and_passphrase(phrase, hd_path, None)
482 }
483
484 pub fn from_seed_phrase_with_path_and_passphrase(
508 phrase: impl AsRef<str>,
509 hd_path: impl AsRef<str>,
510 passphrase: Option<&str>,
511 ) -> Result<Self, SignerError> {
512 let normalized = phrase
514 .as_ref()
515 .trim()
516 .to_lowercase()
517 .split_whitespace()
518 .collect::<Vec<_>>()
519 .join(" ");
520
521 let mnemonic: Mnemonic = normalized
522 .parse()
523 .map_err(|_| SignerError::InvalidSeedPhrase)?;
524
525 let seed = mnemonic.to_seed(passphrase.unwrap_or(""));
527
528 let path = parse_hd_path(hd_path.as_ref())
530 .map_err(|e| SignerError::KeyDerivationFailed(format!("Invalid HD path: {e}")))?;
531 let derived = derive_ed25519_slip10(&seed, &path);
532
533 Ok(Self::ed25519_from_bytes(derived))
534 }
535
536 pub fn generate_with_seed_phrase() -> Result<(String, Self), SignerError> {
550 Self::generate_with_seed_phrase_custom(DEFAULT_WORD_COUNT, DEFAULT_HD_PATH, None)
551 }
552
553 pub fn generate_with_seed_phrase_words(
568 word_count: usize,
569 ) -> Result<(String, Self), SignerError> {
570 Self::generate_with_seed_phrase_custom(word_count, DEFAULT_HD_PATH, None)
571 }
572
573 pub fn generate_with_seed_phrase_custom(
581 word_count: usize,
582 hd_path: impl AsRef<str>,
583 passphrase: Option<&str>,
584 ) -> Result<(String, Self), SignerError> {
585 let phrase = generate_seed_phrase(word_count)?;
586 let secret_key =
587 Self::from_seed_phrase_with_path_and_passphrase(&phrase, hd_path, passphrase)?;
588 Ok((phrase, secret_key))
589 }
590}
591
592impl FromStr for SecretKey {
593 type Err = ParseKeyError;
594
595 fn from_str(s: &str) -> Result<Self, Self::Err> {
596 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
597
598 let key_type = match key_type {
599 "ed25519" => KeyType::Ed25519,
600 "secp256k1" => KeyType::Secp256k1,
601 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
602 };
603
604 let data = bs58::decode(data_str)
605 .into_vec()
606 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
607
608 let valid_len = match key_type {
611 KeyType::Ed25519 => data.len() == 32 || data.len() == 64,
612 KeyType::Secp256k1 => data.len() == 32,
613 };
614 if !valid_len {
615 return Err(ParseKeyError::InvalidLength {
616 expected: 32,
617 actual: data.len(),
618 });
619 }
620
621 let bytes: [u8; 32] = data[..32]
623 .try_into()
624 .map_err(|_| ParseKeyError::InvalidFormat)?;
625
626 match key_type {
627 KeyType::Ed25519 => Ok(Self::Ed25519(bytes)),
628 KeyType::Secp256k1 => {
629 k256::SecretKey::from_bytes((&bytes).into())
631 .map_err(|_| ParseKeyError::InvalidScalar)?;
632 Ok(Self::Secp256k1(bytes))
633 }
634 }
635 }
636}
637
638impl TryFrom<&str> for SecretKey {
639 type Error = ParseKeyError;
640
641 fn try_from(s: &str) -> Result<Self, Self::Error> {
642 s.parse()
643 }
644}
645
646impl Display for SecretKey {
647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648 write!(
649 f,
650 "{}:{}",
651 self.key_type().as_str(),
652 bs58::encode(self.as_bytes()).into_string()
653 )
654 }
655}
656
657impl Debug for SecretKey {
658 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
659 write!(f, "SecretKey({}:***)", self.key_type().as_str())
660 }
661}
662
663#[derive(Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr)]
665pub enum Signature {
666 Ed25519([u8; 64]),
668 Secp256k1([u8; 65]),
670}
671
672impl Signature {
673 pub fn ed25519_from_bytes(bytes: [u8; 64]) -> Self {
675 Self::Ed25519(bytes)
676 }
677
678 pub fn secp256k1_from_bytes(bytes: [u8; 65]) -> Self {
683 Self::Secp256k1(bytes)
684 }
685
686 pub fn key_type(&self) -> KeyType {
688 match self {
689 Self::Ed25519(_) => KeyType::Ed25519,
690 Self::Secp256k1(_) => KeyType::Secp256k1,
691 }
692 }
693
694 pub fn as_bytes(&self) -> &[u8] {
696 match self {
697 Self::Ed25519(bytes) => bytes.as_slice(),
698 Self::Secp256k1(bytes) => bytes.as_slice(),
699 }
700 }
701
702 pub fn verify(&self, message: &[u8], public_key: &PublicKey) -> bool {
704 match (self, public_key) {
705 (Self::Ed25519(sig_bytes), PublicKey::Ed25519(pk_bytes)) => {
706 let Ok(verifying_key) = VerifyingKey::from_bytes(pk_bytes) else {
707 return false;
708 };
709 let signature = ed25519_dalek::Signature::from_bytes(sig_bytes);
710 verifying_key.verify_strict(message, &signature).is_ok()
711 }
712 (Self::Secp256k1(sig_bytes), PublicKey::Secp256k1(pk_bytes)) => {
713 let mut uncompressed = [0u8; 65];
715 uncompressed[0] = 0x04;
716 uncompressed[1..].copy_from_slice(pk_bytes);
717 let Ok(verifying_key) = k256::ecdsa::VerifyingKey::from_sec1_bytes(&uncompressed)
718 else {
719 return false;
720 };
721
722 let v = sig_bytes[64];
724 if v > 3 {
725 return false;
726 }
727
728 let Ok(signature) = k256::ecdsa::Signature::from_bytes((&sig_bytes[..64]).into())
729 else {
730 return false;
731 };
732
733 let hash = sha2::Sha256::digest(message);
735 use k256::ecdsa::signature::hazmat::PrehashVerifier;
736 verifying_key.verify_prehash(&hash, &signature).is_ok()
737 }
738 _ => false,
740 }
741 }
742}
743
744impl FromStr for Signature {
745 type Err = ParseKeyError;
746
747 fn from_str(s: &str) -> Result<Self, Self::Err> {
748 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
749
750 let key_type = match key_type {
751 "ed25519" => KeyType::Ed25519,
752 "secp256k1" => KeyType::Secp256k1,
753 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
754 };
755
756 let data = bs58::decode(data_str)
757 .into_vec()
758 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
759
760 if data.len() != key_type.signature_len() {
761 return Err(ParseKeyError::InvalidLength {
762 expected: key_type.signature_len(),
763 actual: data.len(),
764 });
765 }
766
767 match key_type {
768 KeyType::Ed25519 => {
769 let bytes: [u8; 64] = data
770 .as_slice()
771 .try_into()
772 .map_err(|_| ParseKeyError::InvalidFormat)?;
773 Ok(Self::Ed25519(bytes))
774 }
775 KeyType::Secp256k1 => {
776 let bytes: [u8; 65] = data
777 .as_slice()
778 .try_into()
779 .map_err(|_| ParseKeyError::InvalidFormat)?;
780 Ok(Self::Secp256k1(bytes))
781 }
782 }
783 }
784}
785
786impl Display for Signature {
787 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788 write!(
789 f,
790 "{}:{}",
791 self.key_type().as_str(),
792 bs58::encode(self.as_bytes()).into_string()
793 )
794 }
795}
796
797impl Debug for Signature {
798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
799 write!(f, "Signature({})", self)
800 }
801}
802
803impl BorshSerialize for Signature {
804 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
805 borsh::BorshSerialize::serialize(&(self.key_type() as u8), writer)?;
806 writer.write_all(self.as_bytes())?;
807 Ok(())
808 }
809}
810
811impl BorshDeserialize for Signature {
812 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
813 let key_type_byte = u8::deserialize_reader(reader)?;
814 let key_type = KeyType::try_from(key_type_byte)
815 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
816
817 match key_type {
818 KeyType::Ed25519 => {
819 let mut bytes = [0u8; 64];
820 reader.read_exact(&mut bytes)?;
821 Ok(Self::Ed25519(bytes))
822 }
823 KeyType::Secp256k1 => {
824 let mut bytes = [0u8; 65];
825 reader.read_exact(&mut bytes)?;
826 Ok(Self::Secp256k1(bytes))
827 }
828 }
829 }
830}
831
832pub fn generate_seed_phrase(word_count: usize) -> Result<String, SignerError> {
851 use rand::RngCore;
852
853 let entropy_bytes = match word_count {
855 12 => 16,
856 15 => 20,
857 18 => 24,
858 21 => 28,
859 24 => 32,
860 _ => {
861 return Err(SignerError::KeyDerivationFailed(format!(
862 "Invalid word count: {}. Must be 12, 15, 18, 21, or 24",
863 word_count
864 )));
865 }
866 };
867
868 let mut entropy = vec![0u8; entropy_bytes];
869 OsRng.fill_bytes(&mut entropy);
870
871 let mnemonic = Mnemonic::from_entropy(&entropy).map_err(|e| {
872 SignerError::KeyDerivationFailed(format!("Failed to generate mnemonic: {}", e))
873 })?;
874
875 Ok(mnemonic.to_string())
876}
877
878#[derive(Clone)]
906pub struct KeyPair {
907 pub secret_key: SecretKey,
909 pub public_key: PublicKey,
911}
912
913impl KeyPair {
914 pub fn random() -> Self {
926 Self::random_ed25519()
927 }
928
929 pub fn random_ed25519() -> Self {
940 let secret_key = SecretKey::generate_ed25519();
941 let public_key = secret_key.public_key();
942 Self {
943 secret_key,
944 public_key,
945 }
946 }
947
948 pub fn random_secp256k1() -> Self {
959 let secret_key = SecretKey::generate_secp256k1();
960 let public_key = secret_key.public_key();
961 Self {
962 secret_key,
963 public_key,
964 }
965 }
966
967 pub fn from_secret_key(secret_key: SecretKey) -> Self {
978 let public_key = secret_key.public_key();
979 Self {
980 secret_key,
981 public_key,
982 }
983 }
984
985 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
996 let secret_key = SecretKey::from_seed_phrase(phrase)?;
997 Ok(Self::from_secret_key(secret_key))
998 }
999
1000 pub fn random_with_seed_phrase() -> Result<(String, Self), SignerError> {
1014 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase()?;
1015 Ok((phrase, Self::from_secret_key(secret_key)))
1016 }
1017}
1018
1019impl std::fmt::Debug for KeyPair {
1020 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1021 f.debug_struct("KeyPair")
1022 .field("public_key", &self.public_key)
1023 .field("secret_key", &"***")
1024 .finish()
1025 }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030 use super::*;
1031
1032 #[test]
1033 fn test_generate_and_sign() {
1034 let secret = SecretKey::generate_ed25519();
1035 let public = secret.public_key();
1036 let message = b"hello world";
1037
1038 let signature = secret.sign(message);
1039 assert!(signature.verify(message, &public));
1040 assert!(!signature.verify(b"wrong message", &public));
1041 }
1042
1043 #[test]
1044 fn test_public_key_roundtrip() {
1045 let secret = SecretKey::generate_ed25519();
1046 let public = secret.public_key();
1047 let s = public.to_string();
1048 let parsed: PublicKey = s.parse().unwrap();
1049 assert_eq!(public, parsed);
1050 }
1051
1052 #[test]
1053 fn test_secret_key_roundtrip() {
1054 let secret = SecretKey::generate_ed25519();
1055 let s = secret.to_string();
1056 let parsed: SecretKey = s.parse().unwrap();
1057 assert_eq!(secret.public_key(), parsed.public_key());
1058 }
1059
1060 #[test]
1061 fn test_ed25519_secret_key_64_byte_expanded_form() {
1062 let secret = SecretKey::generate_ed25519();
1065 let public = secret.public_key();
1066 let seed_bytes = secret.as_bytes();
1067
1068 let mut expanded = Vec::with_capacity(64);
1070 expanded.extend_from_slice(seed_bytes);
1071 expanded.extend_from_slice(public.as_bytes());
1072 let expanded_b58 = bs58::encode(&expanded).into_string();
1073 let expanded_str = format!("ed25519:{}", expanded_b58);
1074
1075 let parsed: SecretKey = expanded_str.parse().unwrap();
1077 assert_eq!(parsed.public_key(), public);
1078
1079 let reserialized = parsed.to_string();
1081 assert_eq!(reserialized, secret.to_string());
1082 }
1083
1084 #[test]
1089 fn test_generate_seed_phrase_12_words() {
1090 let phrase = generate_seed_phrase(12).unwrap();
1091 assert_eq!(phrase.split_whitespace().count(), 12);
1092 }
1093
1094 #[test]
1095 fn test_generate_seed_phrase_24_words() {
1096 let phrase = generate_seed_phrase(24).unwrap();
1097 assert_eq!(phrase.split_whitespace().count(), 24);
1098 }
1099
1100 #[test]
1101 fn test_generate_seed_phrase_invalid_word_count() {
1102 let result = generate_seed_phrase(13);
1103 assert!(result.is_err());
1104 }
1105
1106 const TEST_PHRASE: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
1108
1109 #[test]
1110 fn test_from_seed_phrase_known_vector() {
1111 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1113
1114 let secret_key2 = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1116 assert_eq!(secret_key.public_key(), secret_key2.public_key());
1117 }
1118
1119 #[test]
1120 fn test_from_seed_phrase_whitespace_normalization() {
1121 let phrase1 = TEST_PHRASE;
1122 let phrase2 = " abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ";
1123 let phrase3 = "ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABOUT";
1124
1125 let key1 = SecretKey::from_seed_phrase(phrase1).unwrap();
1126 let key2 = SecretKey::from_seed_phrase(phrase2).unwrap();
1127 let key3 = SecretKey::from_seed_phrase(phrase3).unwrap();
1128
1129 assert_eq!(key1.public_key(), key2.public_key());
1130 assert_eq!(key1.public_key(), key3.public_key());
1131 }
1132
1133 #[test]
1134 fn test_from_seed_phrase_invalid() {
1135 let result = SecretKey::from_seed_phrase("invalid words that are not a mnemonic");
1136 assert!(result.is_err());
1137 }
1138
1139 #[test]
1140 fn test_from_seed_phrase_different_paths() {
1141 let key1 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/0'").unwrap();
1142 let key2 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/1'").unwrap();
1143
1144 assert_ne!(key1.public_key(), key2.public_key());
1146 }
1147
1148 #[test]
1149 fn test_from_seed_phrase_with_passphrase() {
1150 let key_no_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1151 TEST_PHRASE,
1152 DEFAULT_HD_PATH,
1153 None,
1154 )
1155 .unwrap();
1156
1157 let key_with_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1158 TEST_PHRASE,
1159 DEFAULT_HD_PATH,
1160 Some("my-password"),
1161 )
1162 .unwrap();
1163
1164 assert_ne!(key_no_pass.public_key(), key_with_pass.public_key());
1166 }
1167
1168 #[test]
1169 fn test_generate_with_seed_phrase() {
1170 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase().unwrap();
1171
1172 assert_eq!(phrase.split_whitespace().count(), 12);
1174
1175 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1177 assert_eq!(secret_key.public_key(), derived.public_key());
1178 }
1179
1180 #[test]
1181 fn test_generate_with_seed_phrase_24_words() {
1182 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase_words(24).unwrap();
1183
1184 assert_eq!(phrase.split_whitespace().count(), 24);
1185
1186 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1187 assert_eq!(secret_key.public_key(), derived.public_key());
1188 }
1189
1190 #[test]
1191 fn test_seed_phrase_key_can_sign() {
1192 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1193
1194 let message = b"test message";
1195 let signature = secret_key.sign(message);
1196 let public_key = secret_key.public_key();
1197
1198 assert!(signature.verify(message, &public_key));
1199 }
1200
1201 #[test]
1206 fn test_secp256k1_invalid_curve_point_rejected() {
1207 let invalid_key = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj";
1210 let result: Result<PublicKey, _> = invalid_key.parse();
1211 assert!(result.is_err());
1212 assert!(matches!(
1213 result.unwrap_err(),
1214 ParseKeyError::InvalidCurvePoint | ParseKeyError::InvalidLength { .. }
1215 ));
1216 }
1217
1218 #[test]
1219 fn test_secp256k1_valid_curve_point_accepted() {
1220 let valid_key = "secp256k1:5r22SrjrDvgY3wdQsnjgxkeAbU1VcM71FYvALEQWihjM3Xk4Be1CpETTqFccChQr4iJwDroSDVmgaWZv2AcXvYeL";
1223 let result: Result<PublicKey, _> = valid_key.parse();
1224 assert!(result.is_ok());
1226 }
1227
1228 #[test]
1229 fn test_ed25519_valid_key_accepted() {
1230 let valid_key = "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp";
1232 let result: Result<PublicKey, _> = valid_key.parse();
1233 assert!(result.is_ok());
1234 }
1235
1236 #[test]
1237 fn test_ed25519_invalid_curve_point_rejected() {
1238 let invalid_bytes = [
1247 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1248 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1249 0xFF, 0xFF, 0xFF, 0x7F,
1250 ];
1251 let encoded = bs58::encode(&invalid_bytes).into_string();
1252 let invalid_key = format!("ed25519:{}", encoded);
1253 let result: Result<PublicKey, _> = invalid_key.parse();
1254 if let Err(err) = result {
1255 assert!(matches!(err, ParseKeyError::InvalidCurvePoint));
1256 } else {
1257 eprintln!(
1259 "Note: ed25519 point decompression accepted test bytes - validation may be too lenient"
1260 );
1261 }
1262 }
1263
1264 #[test]
1265 fn test_borsh_deserialize_validates_curve_point() {
1266 use borsh::BorshDeserialize;
1267
1268 let mut invalid_bytes = vec![1u8]; invalid_bytes.extend_from_slice(&[0u8; 64]); let result = PublicKey::try_from_slice(&invalid_bytes);
1274 assert!(result.is_err());
1275 }
1276
1277 #[test]
1278 fn test_signature_from_str_roundtrip() {
1279 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1280 let sig: Signature = sig_str.parse().unwrap();
1281 assert_eq!(sig.key_type(), KeyType::Ed25519);
1282 assert_eq!(sig.as_bytes().len(), 64);
1283 assert_eq!(sig.to_string(), sig_str);
1284 }
1285
1286 #[test]
1287 fn test_signature_from_str_invalid_format() {
1288 assert!("no_colon".parse::<Signature>().is_err());
1289 assert!("unknown:abc".parse::<Signature>().is_err());
1290 assert!("ed25519:invalid!!!".parse::<Signature>().is_err());
1291 assert!("ed25519:AAAA".parse::<Signature>().is_err()); }
1293
1294 #[test]
1295 fn test_signature_serde_roundtrip() {
1296 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1297 let sig: Signature = sig_str.parse().unwrap();
1298 let json = serde_json::to_value(&sig).unwrap();
1299 assert_eq!(json.as_str().unwrap(), sig_str);
1300 let parsed: Signature = serde_json::from_value(json).unwrap();
1301 assert_eq!(sig, parsed);
1302 }
1303
1304 #[test]
1309 fn test_secp256k1_generate_and_sign_verify() {
1310 let secret = SecretKey::generate_secp256k1();
1311 let public = secret.public_key();
1312 let message = b"hello world";
1313
1314 assert_eq!(secret.key_type(), KeyType::Secp256k1);
1315 assert_eq!(public.key_type(), KeyType::Secp256k1);
1316
1317 let signature = secret.sign(message);
1318 assert_eq!(signature.key_type(), KeyType::Secp256k1);
1319 assert_eq!(signature.as_bytes().len(), 65);
1320
1321 assert!(signature.verify(message, &public));
1322 assert!(!signature.verify(b"wrong message", &public));
1323 }
1324
1325 #[test]
1326 fn test_secp256k1_public_key_is_64_bytes() {
1327 let secret = SecretKey::generate_secp256k1();
1328 let public = secret.public_key();
1329
1330 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1332 assert_eq!(pk_bytes.len(), 64);
1333 }
1334
1335 #[test]
1336 fn test_secp256k1_secret_key_to_public_key_derivation() {
1337 let bytes = [42u8; 32];
1339 let sk1 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1340 let sk2 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1341 assert_eq!(sk1.public_key(), sk2.public_key());
1342
1343 let bytes2 = [43u8; 32];
1345 let sk3 = SecretKey::secp256k1_from_bytes(bytes2).unwrap();
1346 assert_ne!(sk1.public_key(), sk3.public_key());
1347 }
1348
1349 #[test]
1350 fn test_secp256k1_public_key_string_roundtrip() {
1351 let secret = SecretKey::generate_secp256k1();
1352 let public = secret.public_key();
1353 let s = public.to_string();
1354 assert!(s.starts_with("secp256k1:"));
1355 let parsed: PublicKey = s.parse().unwrap();
1356 assert_eq!(public, parsed);
1357 }
1358
1359 #[test]
1360 fn test_secp256k1_secret_key_string_roundtrip() {
1361 let secret = SecretKey::generate_secp256k1();
1362 let s = secret.to_string();
1363 assert!(s.starts_with("secp256k1:"));
1364 let parsed: SecretKey = s.parse().unwrap();
1365 assert_eq!(secret.public_key(), parsed.public_key());
1366 }
1367
1368 #[test]
1369 fn test_secp256k1_keypair_random() {
1370 let keypair = KeyPair::random_secp256k1();
1371 assert_eq!(keypair.public_key.key_type(), KeyType::Secp256k1);
1372 assert_eq!(keypair.secret_key.key_type(), KeyType::Secp256k1);
1373 assert!(keypair.public_key.to_string().starts_with("secp256k1:"));
1374
1375 let message = b"keypair test";
1377 let signature = keypair.secret_key.sign(message);
1378 assert!(signature.verify(message, &keypair.public_key));
1379 }
1380
1381 #[test]
1382 fn test_secp256k1_cross_type_verify_fails() {
1383 let ed_secret = SecretKey::generate_ed25519();
1385 let secp_secret = SecretKey::generate_secp256k1();
1386
1387 let message = b"cross type test";
1388 let ed_sig = ed_secret.sign(message);
1389 let secp_sig = secp_secret.sign(message);
1390
1391 assert!(!ed_sig.verify(message, &secp_secret.public_key()));
1392 assert!(!secp_sig.verify(message, &ed_secret.public_key()));
1393 }
1394
1395 #[test]
1396 fn test_secp256k1_invalid_scalar_rejected() {
1397 let zero_bytes = [0u8; 32];
1399 let result = SecretKey::secp256k1_from_bytes(zero_bytes);
1400 assert!(result.is_err());
1401 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1402 }
1403
1404 #[test]
1405 fn test_secp256k1_invalid_scalar_rejected_from_str() {
1406 let zero_bytes = [0u8; 32];
1408 let encoded = bs58::encode(&zero_bytes).into_string();
1409 let key_str = format!("secp256k1:{}", encoded);
1410 let result: Result<SecretKey, _> = key_str.parse();
1411 assert!(result.is_err());
1412 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1413 }
1414
1415 #[test]
1416 fn test_secp256k1_invalid_recovery_id_rejected() {
1417 let secret = SecretKey::generate_secp256k1();
1418 let public = secret.public_key();
1419 let message = b"test message";
1420 let signature = secret.sign(message);
1421
1422 if let Signature::Secp256k1(mut sig_bytes) = signature.clone() {
1424 sig_bytes[64] = 4; let tampered = Signature::Secp256k1(sig_bytes);
1426 assert!(!tampered.verify(message, &public));
1427
1428 sig_bytes[64] = 255;
1429 let tampered = Signature::Secp256k1(sig_bytes);
1430 assert!(!tampered.verify(message, &public));
1431 } else {
1432 panic!("Expected Secp256k1 signature");
1433 }
1434 }
1435
1436 #[test]
1437 fn test_secp256k1_from_compressed() {
1438 let secret = SecretKey::generate_secp256k1();
1439 let public = secret.public_key();
1440
1441 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1443 let mut uncompressed = [0u8; 65];
1444 uncompressed[0] = 0x04;
1445 uncompressed[1..].copy_from_slice(pk_bytes);
1446 let encoded =
1447 k256::EncodedPoint::from_bytes(uncompressed.as_ref()).expect("valid encoded point");
1448 let point = k256::AffinePoint::from_encoded_point(&encoded).expect("valid point on curve");
1449 let compressed = point.to_encoded_point(true);
1450 let compressed_bytes: [u8; 33] = compressed
1451 .as_bytes()
1452 .try_into()
1453 .expect("compressed should be 33 bytes");
1454
1455 let public2 = PublicKey::secp256k1_from_compressed(compressed_bytes);
1457 assert_eq!(public, public2);
1458 }
1459
1460 #[test]
1461 fn test_ed25519_borsh_roundtrip() {
1462 use borsh::BorshDeserialize;
1463
1464 let secret = SecretKey::generate_ed25519();
1465 let public = secret.public_key();
1466 let serialized = borsh::to_vec(&public).unwrap();
1467 assert_eq!(serialized.len(), 33);
1469 assert_eq!(serialized[0], 0); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1471 assert_eq!(public, deserialized);
1472 }
1473
1474 #[test]
1475 fn test_secp256k1_borsh_roundtrip() {
1476 use borsh::BorshDeserialize;
1477
1478 let secret = SecretKey::generate_secp256k1();
1479 let public = secret.public_key();
1480 let serialized = borsh::to_vec(&public).unwrap();
1481 assert_eq!(serialized.len(), 65);
1483 assert_eq!(serialized[0], 1); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1485 assert_eq!(public, deserialized);
1486 }
1487
1488 #[test]
1489 fn test_signature_borsh_roundtrip() {
1490 use borsh::BorshDeserialize;
1491
1492 let secret = SecretKey::generate_ed25519();
1493 let sig = secret.sign(b"test");
1494 let serialized = borsh::to_vec(&sig).unwrap();
1495 assert_eq!(serialized.len(), 65); let deserialized = Signature::try_from_slice(&serialized).unwrap();
1497 assert_eq!(sig, deserialized);
1498 }
1499
1500 #[test]
1501 fn test_enum_variants_match_expected_types() {
1502 let ed_secret = SecretKey::generate_ed25519();
1503 let ed_public = ed_secret.public_key();
1504
1505 assert!(matches!(ed_public, PublicKey::Ed25519(_)));
1506 assert!(matches!(ed_secret, SecretKey::Ed25519(_)));
1507
1508 let secp_secret = SecretKey::generate_secp256k1();
1509 let secp_public = secp_secret.public_key();
1510
1511 assert!(matches!(secp_public, PublicKey::Secp256k1(_)));
1512 assert!(matches!(secp_secret, SecretKey::Secp256k1(_)));
1513 }
1514}