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;
13use slipped10::{BIP32Path, Curve};
14
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: BIP32Path = hd_path
530 .as_ref()
531 .parse()
532 .map_err(|e| SignerError::KeyDerivationFailed(format!("Invalid HD path: {}", e)))?;
533
534 let derived =
536 slipped10::derive_key_from_path(&seed, Curve::Ed25519, &path).map_err(|e| {
537 SignerError::KeyDerivationFailed(format!("SLIP-10 derivation failed: {:?}", e))
538 })?;
539
540 Ok(Self::ed25519_from_bytes(derived.key))
541 }
542
543 pub fn generate_with_seed_phrase() -> Result<(String, Self), SignerError> {
557 Self::generate_with_seed_phrase_custom(DEFAULT_WORD_COUNT, DEFAULT_HD_PATH, None)
558 }
559
560 pub fn generate_with_seed_phrase_words(
575 word_count: usize,
576 ) -> Result<(String, Self), SignerError> {
577 Self::generate_with_seed_phrase_custom(word_count, DEFAULT_HD_PATH, None)
578 }
579
580 pub fn generate_with_seed_phrase_custom(
588 word_count: usize,
589 hd_path: impl AsRef<str>,
590 passphrase: Option<&str>,
591 ) -> Result<(String, Self), SignerError> {
592 let phrase = generate_seed_phrase(word_count)?;
593 let secret_key =
594 Self::from_seed_phrase_with_path_and_passphrase(&phrase, hd_path, passphrase)?;
595 Ok((phrase, secret_key))
596 }
597}
598
599impl FromStr for SecretKey {
600 type Err = ParseKeyError;
601
602 fn from_str(s: &str) -> Result<Self, Self::Err> {
603 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
604
605 let key_type = match key_type {
606 "ed25519" => KeyType::Ed25519,
607 "secp256k1" => KeyType::Secp256k1,
608 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
609 };
610
611 let data = bs58::decode(data_str)
612 .into_vec()
613 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
614
615 let valid_len = match key_type {
618 KeyType::Ed25519 => data.len() == 32 || data.len() == 64,
619 KeyType::Secp256k1 => data.len() == 32,
620 };
621 if !valid_len {
622 return Err(ParseKeyError::InvalidLength {
623 expected: 32,
624 actual: data.len(),
625 });
626 }
627
628 let bytes: [u8; 32] = data[..32]
630 .try_into()
631 .map_err(|_| ParseKeyError::InvalidFormat)?;
632
633 match key_type {
634 KeyType::Ed25519 => Ok(Self::Ed25519(bytes)),
635 KeyType::Secp256k1 => {
636 k256::SecretKey::from_bytes((&bytes).into())
638 .map_err(|_| ParseKeyError::InvalidScalar)?;
639 Ok(Self::Secp256k1(bytes))
640 }
641 }
642 }
643}
644
645impl TryFrom<&str> for SecretKey {
646 type Error = ParseKeyError;
647
648 fn try_from(s: &str) -> Result<Self, Self::Error> {
649 s.parse()
650 }
651}
652
653impl Display for SecretKey {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 write!(
656 f,
657 "{}:{}",
658 self.key_type().as_str(),
659 bs58::encode(self.as_bytes()).into_string()
660 )
661 }
662}
663
664impl Debug for SecretKey {
665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666 write!(f, "SecretKey({}:***)", self.key_type().as_str())
667 }
668}
669
670#[derive(Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr)]
672pub enum Signature {
673 Ed25519([u8; 64]),
675 Secp256k1([u8; 65]),
677}
678
679impl Signature {
680 pub fn ed25519_from_bytes(bytes: [u8; 64]) -> Self {
682 Self::Ed25519(bytes)
683 }
684
685 pub fn secp256k1_from_bytes(bytes: [u8; 65]) -> Self {
690 Self::Secp256k1(bytes)
691 }
692
693 pub fn key_type(&self) -> KeyType {
695 match self {
696 Self::Ed25519(_) => KeyType::Ed25519,
697 Self::Secp256k1(_) => KeyType::Secp256k1,
698 }
699 }
700
701 pub fn as_bytes(&self) -> &[u8] {
703 match self {
704 Self::Ed25519(bytes) => bytes.as_slice(),
705 Self::Secp256k1(bytes) => bytes.as_slice(),
706 }
707 }
708
709 pub fn verify(&self, message: &[u8], public_key: &PublicKey) -> bool {
711 match (self, public_key) {
712 (Self::Ed25519(sig_bytes), PublicKey::Ed25519(pk_bytes)) => {
713 let Ok(verifying_key) = VerifyingKey::from_bytes(pk_bytes) else {
714 return false;
715 };
716 let signature = ed25519_dalek::Signature::from_bytes(sig_bytes);
717 verifying_key.verify_strict(message, &signature).is_ok()
718 }
719 (Self::Secp256k1(sig_bytes), PublicKey::Secp256k1(pk_bytes)) => {
720 let mut uncompressed = [0u8; 65];
722 uncompressed[0] = 0x04;
723 uncompressed[1..].copy_from_slice(pk_bytes);
724 let Ok(verifying_key) = k256::ecdsa::VerifyingKey::from_sec1_bytes(&uncompressed)
725 else {
726 return false;
727 };
728
729 let v = sig_bytes[64];
731 if v > 3 {
732 return false;
733 }
734
735 let Ok(signature) = k256::ecdsa::Signature::from_bytes((&sig_bytes[..64]).into())
736 else {
737 return false;
738 };
739
740 let hash = sha2::Sha256::digest(message);
742 use k256::ecdsa::signature::hazmat::PrehashVerifier;
743 verifying_key.verify_prehash(&hash, &signature).is_ok()
744 }
745 _ => false,
747 }
748 }
749}
750
751impl FromStr for Signature {
752 type Err = ParseKeyError;
753
754 fn from_str(s: &str) -> Result<Self, Self::Err> {
755 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
756
757 let key_type = match key_type {
758 "ed25519" => KeyType::Ed25519,
759 "secp256k1" => KeyType::Secp256k1,
760 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
761 };
762
763 let data = bs58::decode(data_str)
764 .into_vec()
765 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
766
767 if data.len() != key_type.signature_len() {
768 return Err(ParseKeyError::InvalidLength {
769 expected: key_type.signature_len(),
770 actual: data.len(),
771 });
772 }
773
774 match key_type {
775 KeyType::Ed25519 => {
776 let bytes: [u8; 64] = data
777 .as_slice()
778 .try_into()
779 .map_err(|_| ParseKeyError::InvalidFormat)?;
780 Ok(Self::Ed25519(bytes))
781 }
782 KeyType::Secp256k1 => {
783 let bytes: [u8; 65] = data
784 .as_slice()
785 .try_into()
786 .map_err(|_| ParseKeyError::InvalidFormat)?;
787 Ok(Self::Secp256k1(bytes))
788 }
789 }
790 }
791}
792
793impl Display for Signature {
794 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795 write!(
796 f,
797 "{}:{}",
798 self.key_type().as_str(),
799 bs58::encode(self.as_bytes()).into_string()
800 )
801 }
802}
803
804impl Debug for Signature {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 write!(f, "Signature({})", self)
807 }
808}
809
810impl BorshSerialize for Signature {
811 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
812 borsh::BorshSerialize::serialize(&(self.key_type() as u8), writer)?;
813 writer.write_all(self.as_bytes())?;
814 Ok(())
815 }
816}
817
818impl BorshDeserialize for Signature {
819 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
820 let key_type_byte = u8::deserialize_reader(reader)?;
821 let key_type = KeyType::try_from(key_type_byte)
822 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
823
824 match key_type {
825 KeyType::Ed25519 => {
826 let mut bytes = [0u8; 64];
827 reader.read_exact(&mut bytes)?;
828 Ok(Self::Ed25519(bytes))
829 }
830 KeyType::Secp256k1 => {
831 let mut bytes = [0u8; 65];
832 reader.read_exact(&mut bytes)?;
833 Ok(Self::Secp256k1(bytes))
834 }
835 }
836 }
837}
838
839pub fn generate_seed_phrase(word_count: usize) -> Result<String, SignerError> {
858 use rand::RngCore;
859
860 let entropy_bytes = match word_count {
862 12 => 16,
863 15 => 20,
864 18 => 24,
865 21 => 28,
866 24 => 32,
867 _ => {
868 return Err(SignerError::KeyDerivationFailed(format!(
869 "Invalid word count: {}. Must be 12, 15, 18, 21, or 24",
870 word_count
871 )));
872 }
873 };
874
875 let mut entropy = vec![0u8; entropy_bytes];
876 OsRng.fill_bytes(&mut entropy);
877
878 let mnemonic = Mnemonic::from_entropy(&entropy).map_err(|e| {
879 SignerError::KeyDerivationFailed(format!("Failed to generate mnemonic: {}", e))
880 })?;
881
882 Ok(mnemonic.to_string())
883}
884
885#[derive(Clone)]
913pub struct KeyPair {
914 pub secret_key: SecretKey,
916 pub public_key: PublicKey,
918}
919
920impl KeyPair {
921 pub fn random() -> Self {
933 Self::random_ed25519()
934 }
935
936 pub fn random_ed25519() -> Self {
947 let secret_key = SecretKey::generate_ed25519();
948 let public_key = secret_key.public_key();
949 Self {
950 secret_key,
951 public_key,
952 }
953 }
954
955 pub fn random_secp256k1() -> Self {
966 let secret_key = SecretKey::generate_secp256k1();
967 let public_key = secret_key.public_key();
968 Self {
969 secret_key,
970 public_key,
971 }
972 }
973
974 pub fn from_secret_key(secret_key: SecretKey) -> Self {
985 let public_key = secret_key.public_key();
986 Self {
987 secret_key,
988 public_key,
989 }
990 }
991
992 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
1003 let secret_key = SecretKey::from_seed_phrase(phrase)?;
1004 Ok(Self::from_secret_key(secret_key))
1005 }
1006
1007 pub fn random_with_seed_phrase() -> Result<(String, Self), SignerError> {
1021 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase()?;
1022 Ok((phrase, Self::from_secret_key(secret_key)))
1023 }
1024}
1025
1026impl std::fmt::Debug for KeyPair {
1027 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1028 f.debug_struct("KeyPair")
1029 .field("public_key", &self.public_key)
1030 .field("secret_key", &"***")
1031 .finish()
1032 }
1033}
1034
1035#[cfg(test)]
1036mod tests {
1037 use super::*;
1038
1039 #[test]
1040 fn test_generate_and_sign() {
1041 let secret = SecretKey::generate_ed25519();
1042 let public = secret.public_key();
1043 let message = b"hello world";
1044
1045 let signature = secret.sign(message);
1046 assert!(signature.verify(message, &public));
1047 assert!(!signature.verify(b"wrong message", &public));
1048 }
1049
1050 #[test]
1051 fn test_public_key_roundtrip() {
1052 let secret = SecretKey::generate_ed25519();
1053 let public = secret.public_key();
1054 let s = public.to_string();
1055 let parsed: PublicKey = s.parse().unwrap();
1056 assert_eq!(public, parsed);
1057 }
1058
1059 #[test]
1060 fn test_secret_key_roundtrip() {
1061 let secret = SecretKey::generate_ed25519();
1062 let s = secret.to_string();
1063 let parsed: SecretKey = s.parse().unwrap();
1064 assert_eq!(secret.public_key(), parsed.public_key());
1065 }
1066
1067 #[test]
1068 fn test_ed25519_secret_key_64_byte_expanded_form() {
1069 let secret = SecretKey::generate_ed25519();
1072 let public = secret.public_key();
1073 let seed_bytes = secret.as_bytes();
1074
1075 let mut expanded = Vec::with_capacity(64);
1077 expanded.extend_from_slice(seed_bytes);
1078 expanded.extend_from_slice(public.as_bytes());
1079 let expanded_b58 = bs58::encode(&expanded).into_string();
1080 let expanded_str = format!("ed25519:{}", expanded_b58);
1081
1082 let parsed: SecretKey = expanded_str.parse().unwrap();
1084 assert_eq!(parsed.public_key(), public);
1085
1086 let reserialized = parsed.to_string();
1088 assert_eq!(reserialized, secret.to_string());
1089 }
1090
1091 #[test]
1096 fn test_generate_seed_phrase_12_words() {
1097 let phrase = generate_seed_phrase(12).unwrap();
1098 assert_eq!(phrase.split_whitespace().count(), 12);
1099 }
1100
1101 #[test]
1102 fn test_generate_seed_phrase_24_words() {
1103 let phrase = generate_seed_phrase(24).unwrap();
1104 assert_eq!(phrase.split_whitespace().count(), 24);
1105 }
1106
1107 #[test]
1108 fn test_generate_seed_phrase_invalid_word_count() {
1109 let result = generate_seed_phrase(13);
1110 assert!(result.is_err());
1111 }
1112
1113 const TEST_PHRASE: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
1115
1116 #[test]
1117 fn test_from_seed_phrase_known_vector() {
1118 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1120
1121 let secret_key2 = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1123 assert_eq!(secret_key.public_key(), secret_key2.public_key());
1124 }
1125
1126 #[test]
1127 fn test_from_seed_phrase_whitespace_normalization() {
1128 let phrase1 = TEST_PHRASE;
1129 let phrase2 = " abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ";
1130 let phrase3 = "ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABOUT";
1131
1132 let key1 = SecretKey::from_seed_phrase(phrase1).unwrap();
1133 let key2 = SecretKey::from_seed_phrase(phrase2).unwrap();
1134 let key3 = SecretKey::from_seed_phrase(phrase3).unwrap();
1135
1136 assert_eq!(key1.public_key(), key2.public_key());
1137 assert_eq!(key1.public_key(), key3.public_key());
1138 }
1139
1140 #[test]
1141 fn test_from_seed_phrase_invalid() {
1142 let result = SecretKey::from_seed_phrase("invalid words that are not a mnemonic");
1143 assert!(result.is_err());
1144 }
1145
1146 #[test]
1147 fn test_from_seed_phrase_different_paths() {
1148 let key1 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/0'").unwrap();
1149 let key2 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/1'").unwrap();
1150
1151 assert_ne!(key1.public_key(), key2.public_key());
1153 }
1154
1155 #[test]
1156 fn test_from_seed_phrase_with_passphrase() {
1157 let key_no_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1158 TEST_PHRASE,
1159 DEFAULT_HD_PATH,
1160 None,
1161 )
1162 .unwrap();
1163
1164 let key_with_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1165 TEST_PHRASE,
1166 DEFAULT_HD_PATH,
1167 Some("my-password"),
1168 )
1169 .unwrap();
1170
1171 assert_ne!(key_no_pass.public_key(), key_with_pass.public_key());
1173 }
1174
1175 #[test]
1176 fn test_generate_with_seed_phrase() {
1177 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase().unwrap();
1178
1179 assert_eq!(phrase.split_whitespace().count(), 12);
1181
1182 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1184 assert_eq!(secret_key.public_key(), derived.public_key());
1185 }
1186
1187 #[test]
1188 fn test_generate_with_seed_phrase_24_words() {
1189 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase_words(24).unwrap();
1190
1191 assert_eq!(phrase.split_whitespace().count(), 24);
1192
1193 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1194 assert_eq!(secret_key.public_key(), derived.public_key());
1195 }
1196
1197 #[test]
1198 fn test_seed_phrase_key_can_sign() {
1199 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1200
1201 let message = b"test message";
1202 let signature = secret_key.sign(message);
1203 let public_key = secret_key.public_key();
1204
1205 assert!(signature.verify(message, &public_key));
1206 }
1207
1208 #[test]
1213 fn test_secp256k1_invalid_curve_point_rejected() {
1214 let invalid_key = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj";
1217 let result: Result<PublicKey, _> = invalid_key.parse();
1218 assert!(result.is_err());
1219 assert!(matches!(
1220 result.unwrap_err(),
1221 ParseKeyError::InvalidCurvePoint | ParseKeyError::InvalidLength { .. }
1222 ));
1223 }
1224
1225 #[test]
1226 fn test_secp256k1_valid_curve_point_accepted() {
1227 let valid_key = "secp256k1:5r22SrjrDvgY3wdQsnjgxkeAbU1VcM71FYvALEQWihjM3Xk4Be1CpETTqFccChQr4iJwDroSDVmgaWZv2AcXvYeL";
1230 let result: Result<PublicKey, _> = valid_key.parse();
1231 assert!(result.is_ok());
1233 }
1234
1235 #[test]
1236 fn test_ed25519_valid_key_accepted() {
1237 let valid_key = "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp";
1239 let result: Result<PublicKey, _> = valid_key.parse();
1240 assert!(result.is_ok());
1241 }
1242
1243 #[test]
1244 fn test_ed25519_invalid_curve_point_rejected() {
1245 let invalid_bytes = [
1254 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1255 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1256 0xFF, 0xFF, 0xFF, 0x7F,
1257 ];
1258 let encoded = bs58::encode(&invalid_bytes).into_string();
1259 let invalid_key = format!("ed25519:{}", encoded);
1260 let result: Result<PublicKey, _> = invalid_key.parse();
1261 if let Err(err) = result {
1262 assert!(matches!(err, ParseKeyError::InvalidCurvePoint));
1263 } else {
1264 eprintln!(
1266 "Note: ed25519 point decompression accepted test bytes - validation may be too lenient"
1267 );
1268 }
1269 }
1270
1271 #[test]
1272 fn test_borsh_deserialize_validates_curve_point() {
1273 use borsh::BorshDeserialize;
1274
1275 let mut invalid_bytes = vec![1u8]; invalid_bytes.extend_from_slice(&[0u8; 64]); let result = PublicKey::try_from_slice(&invalid_bytes);
1281 assert!(result.is_err());
1282 }
1283
1284 #[test]
1285 fn test_signature_from_str_roundtrip() {
1286 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1287 let sig: Signature = sig_str.parse().unwrap();
1288 assert_eq!(sig.key_type(), KeyType::Ed25519);
1289 assert_eq!(sig.as_bytes().len(), 64);
1290 assert_eq!(sig.to_string(), sig_str);
1291 }
1292
1293 #[test]
1294 fn test_signature_from_str_invalid_format() {
1295 assert!("no_colon".parse::<Signature>().is_err());
1296 assert!("unknown:abc".parse::<Signature>().is_err());
1297 assert!("ed25519:invalid!!!".parse::<Signature>().is_err());
1298 assert!("ed25519:AAAA".parse::<Signature>().is_err()); }
1300
1301 #[test]
1302 fn test_signature_serde_roundtrip() {
1303 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1304 let sig: Signature = sig_str.parse().unwrap();
1305 let json = serde_json::to_value(&sig).unwrap();
1306 assert_eq!(json.as_str().unwrap(), sig_str);
1307 let parsed: Signature = serde_json::from_value(json).unwrap();
1308 assert_eq!(sig, parsed);
1309 }
1310
1311 #[test]
1316 fn test_secp256k1_generate_and_sign_verify() {
1317 let secret = SecretKey::generate_secp256k1();
1318 let public = secret.public_key();
1319 let message = b"hello world";
1320
1321 assert_eq!(secret.key_type(), KeyType::Secp256k1);
1322 assert_eq!(public.key_type(), KeyType::Secp256k1);
1323
1324 let signature = secret.sign(message);
1325 assert_eq!(signature.key_type(), KeyType::Secp256k1);
1326 assert_eq!(signature.as_bytes().len(), 65);
1327
1328 assert!(signature.verify(message, &public));
1329 assert!(!signature.verify(b"wrong message", &public));
1330 }
1331
1332 #[test]
1333 fn test_secp256k1_public_key_is_64_bytes() {
1334 let secret = SecretKey::generate_secp256k1();
1335 let public = secret.public_key();
1336
1337 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1339 assert_eq!(pk_bytes.len(), 64);
1340 }
1341
1342 #[test]
1343 fn test_secp256k1_secret_key_to_public_key_derivation() {
1344 let bytes = [42u8; 32];
1346 let sk1 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1347 let sk2 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1348 assert_eq!(sk1.public_key(), sk2.public_key());
1349
1350 let bytes2 = [43u8; 32];
1352 let sk3 = SecretKey::secp256k1_from_bytes(bytes2).unwrap();
1353 assert_ne!(sk1.public_key(), sk3.public_key());
1354 }
1355
1356 #[test]
1357 fn test_secp256k1_public_key_string_roundtrip() {
1358 let secret = SecretKey::generate_secp256k1();
1359 let public = secret.public_key();
1360 let s = public.to_string();
1361 assert!(s.starts_with("secp256k1:"));
1362 let parsed: PublicKey = s.parse().unwrap();
1363 assert_eq!(public, parsed);
1364 }
1365
1366 #[test]
1367 fn test_secp256k1_secret_key_string_roundtrip() {
1368 let secret = SecretKey::generate_secp256k1();
1369 let s = secret.to_string();
1370 assert!(s.starts_with("secp256k1:"));
1371 let parsed: SecretKey = s.parse().unwrap();
1372 assert_eq!(secret.public_key(), parsed.public_key());
1373 }
1374
1375 #[test]
1376 fn test_secp256k1_keypair_random() {
1377 let keypair = KeyPair::random_secp256k1();
1378 assert_eq!(keypair.public_key.key_type(), KeyType::Secp256k1);
1379 assert_eq!(keypair.secret_key.key_type(), KeyType::Secp256k1);
1380 assert!(keypair.public_key.to_string().starts_with("secp256k1:"));
1381
1382 let message = b"keypair test";
1384 let signature = keypair.secret_key.sign(message);
1385 assert!(signature.verify(message, &keypair.public_key));
1386 }
1387
1388 #[test]
1389 fn test_secp256k1_cross_type_verify_fails() {
1390 let ed_secret = SecretKey::generate_ed25519();
1392 let secp_secret = SecretKey::generate_secp256k1();
1393
1394 let message = b"cross type test";
1395 let ed_sig = ed_secret.sign(message);
1396 let secp_sig = secp_secret.sign(message);
1397
1398 assert!(!ed_sig.verify(message, &secp_secret.public_key()));
1399 assert!(!secp_sig.verify(message, &ed_secret.public_key()));
1400 }
1401
1402 #[test]
1403 fn test_secp256k1_invalid_scalar_rejected() {
1404 let zero_bytes = [0u8; 32];
1406 let result = SecretKey::secp256k1_from_bytes(zero_bytes);
1407 assert!(result.is_err());
1408 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1409 }
1410
1411 #[test]
1412 fn test_secp256k1_invalid_scalar_rejected_from_str() {
1413 let zero_bytes = [0u8; 32];
1415 let encoded = bs58::encode(&zero_bytes).into_string();
1416 let key_str = format!("secp256k1:{}", encoded);
1417 let result: Result<SecretKey, _> = key_str.parse();
1418 assert!(result.is_err());
1419 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1420 }
1421
1422 #[test]
1423 fn test_secp256k1_invalid_recovery_id_rejected() {
1424 let secret = SecretKey::generate_secp256k1();
1425 let public = secret.public_key();
1426 let message = b"test message";
1427 let signature = secret.sign(message);
1428
1429 if let Signature::Secp256k1(mut sig_bytes) = signature.clone() {
1431 sig_bytes[64] = 4; let tampered = Signature::Secp256k1(sig_bytes);
1433 assert!(!tampered.verify(message, &public));
1434
1435 sig_bytes[64] = 255;
1436 let tampered = Signature::Secp256k1(sig_bytes);
1437 assert!(!tampered.verify(message, &public));
1438 } else {
1439 panic!("Expected Secp256k1 signature");
1440 }
1441 }
1442
1443 #[test]
1444 fn test_secp256k1_from_compressed() {
1445 let secret = SecretKey::generate_secp256k1();
1446 let public = secret.public_key();
1447
1448 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1450 let mut uncompressed = [0u8; 65];
1451 uncompressed[0] = 0x04;
1452 uncompressed[1..].copy_from_slice(pk_bytes);
1453 let encoded =
1454 k256::EncodedPoint::from_bytes(uncompressed.as_ref()).expect("valid encoded point");
1455 let point = k256::AffinePoint::from_encoded_point(&encoded).expect("valid point on curve");
1456 let compressed = point.to_encoded_point(true);
1457 let compressed_bytes: [u8; 33] = compressed
1458 .as_bytes()
1459 .try_into()
1460 .expect("compressed should be 33 bytes");
1461
1462 let public2 = PublicKey::secp256k1_from_compressed(compressed_bytes);
1464 assert_eq!(public, public2);
1465 }
1466
1467 #[test]
1468 fn test_ed25519_borsh_roundtrip() {
1469 use borsh::BorshDeserialize;
1470
1471 let secret = SecretKey::generate_ed25519();
1472 let public = secret.public_key();
1473 let serialized = borsh::to_vec(&public).unwrap();
1474 assert_eq!(serialized.len(), 33);
1476 assert_eq!(serialized[0], 0); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1478 assert_eq!(public, deserialized);
1479 }
1480
1481 #[test]
1482 fn test_secp256k1_borsh_roundtrip() {
1483 use borsh::BorshDeserialize;
1484
1485 let secret = SecretKey::generate_secp256k1();
1486 let public = secret.public_key();
1487 let serialized = borsh::to_vec(&public).unwrap();
1488 assert_eq!(serialized.len(), 65);
1490 assert_eq!(serialized[0], 1); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1492 assert_eq!(public, deserialized);
1493 }
1494
1495 #[test]
1496 fn test_signature_borsh_roundtrip() {
1497 use borsh::BorshDeserialize;
1498
1499 let secret = SecretKey::generate_ed25519();
1500 let sig = secret.sign(b"test");
1501 let serialized = borsh::to_vec(&sig).unwrap();
1502 assert_eq!(serialized.len(), 65); let deserialized = Signature::try_from_slice(&serialized).unwrap();
1504 assert_eq!(sig, deserialized);
1505 }
1506
1507 #[test]
1508 fn test_enum_variants_match_expected_types() {
1509 let ed_secret = SecretKey::generate_ed25519();
1510 let ed_public = ed_secret.public_key();
1511
1512 assert!(matches!(ed_public, PublicKey::Ed25519(_)));
1513 assert!(matches!(ed_secret, SecretKey::Ed25519(_)));
1514
1515 let secp_secret = SecretKey::generate_secp256k1();
1516 let secp_public = secp_secret.public_key();
1517
1518 assert!(matches!(secp_public, PublicKey::Secp256k1(_)));
1519 assert!(matches!(secp_secret, SecretKey::Secp256k1(_)));
1520 }
1521}