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::{Deserialize, Deserializer, Serialize, Serializer};
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)]
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 Serialize for PublicKey {
270 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
271 s.serialize_str(&self.to_string())
272 }
273}
274
275impl<'de> Deserialize<'de> for PublicKey {
276 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
277 let s: String = serde::Deserialize::deserialize(d)?;
278 s.parse().map_err(serde::de::Error::custom)
279 }
280}
281
282impl BorshSerialize for PublicKey {
283 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
284 borsh::BorshSerialize::serialize(&(self.key_type() as u8), writer)?;
285 writer.write_all(self.as_bytes())?;
286 Ok(())
287 }
288}
289
290impl BorshDeserialize for PublicKey {
291 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
292 let key_type_byte = u8::deserialize_reader(reader)?;
293 let key_type = KeyType::try_from(key_type_byte)
294 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
295
296 match key_type {
297 KeyType::Ed25519 => {
298 let mut bytes = [0u8; 32];
299 reader.read_exact(&mut bytes)?;
300 VerifyingKey::from_bytes(&bytes).map_err(|_| {
301 std::io::Error::new(
302 std::io::ErrorKind::InvalidData,
303 "invalid ed25519 curve point",
304 )
305 })?;
306 Ok(Self::Ed25519(bytes))
307 }
308 KeyType::Secp256k1 => {
309 let mut bytes = [0u8; 64];
310 reader.read_exact(&mut bytes)?;
311 let mut uncompressed = [0u8; 65];
313 uncompressed[0] = 0x04;
314 uncompressed[1..].copy_from_slice(&bytes);
315 let encoded = k256::EncodedPoint::from_bytes(uncompressed).map_err(|_| {
316 std::io::Error::new(
317 std::io::ErrorKind::InvalidData,
318 "invalid secp256k1 encoding",
319 )
320 })?;
321 let point = k256::AffinePoint::from_encoded_point(&encoded);
322 if point.is_none().into() {
323 return Err(std::io::Error::new(
324 std::io::ErrorKind::InvalidData,
325 "invalid secp256k1 curve point",
326 ));
327 }
328 Ok(Self::Secp256k1(bytes))
329 }
330 }
331 }
332}
333
334pub const DEFAULT_HD_PATH: &str = "m/44'/397'/0'";
337
338pub const DEFAULT_WORD_COUNT: usize = 12;
340
341#[derive(Clone)]
343pub enum SecretKey {
344 Ed25519([u8; 32]),
346 Secp256k1([u8; 32]),
348}
349
350impl SecretKey {
351 pub fn generate_ed25519() -> Self {
353 let signing_key = SigningKey::generate(&mut OsRng);
354 Self::Ed25519(signing_key.to_bytes())
355 }
356
357 pub fn ed25519_from_bytes(bytes: [u8; 32]) -> Self {
359 Self::Ed25519(bytes)
360 }
361
362 pub fn generate_secp256k1() -> Self {
364 let secret_key = k256::SecretKey::random(&mut OsRng);
365 let mut bytes = [0u8; 32];
366 bytes.copy_from_slice(&secret_key.to_bytes());
367 Self::Secp256k1(bytes)
368 }
369
370 pub fn secp256k1_from_bytes(bytes: [u8; 32]) -> Result<Self, ParseKeyError> {
375 k256::SecretKey::from_bytes((&bytes).into()).map_err(|_| ParseKeyError::InvalidScalar)?;
376 Ok(Self::Secp256k1(bytes))
377 }
378
379 pub fn key_type(&self) -> KeyType {
381 match self {
382 Self::Ed25519(_) => KeyType::Ed25519,
383 Self::Secp256k1(_) => KeyType::Secp256k1,
384 }
385 }
386
387 pub fn as_bytes(&self) -> &[u8] {
389 match self {
390 Self::Ed25519(bytes) => bytes.as_slice(),
391 Self::Secp256k1(bytes) => bytes.as_slice(),
392 }
393 }
394
395 pub fn public_key(&self) -> PublicKey {
397 match self {
398 Self::Ed25519(bytes) => {
399 let signing_key = SigningKey::from_bytes(bytes);
400 let verifying_key = signing_key.verifying_key();
401 PublicKey::Ed25519(verifying_key.to_bytes())
402 }
403 Self::Secp256k1(bytes) => {
404 let secret_key =
405 k256::SecretKey::from_bytes(bytes.into()).expect("invalid secp256k1 key");
406 let public_key = secret_key.public_key();
407 let uncompressed = public_key.to_encoded_point(false);
409 let uncompressed_bytes: &[u8] = uncompressed.as_bytes();
410 assert_eq!(uncompressed_bytes.len(), 65);
411 let mut result = [0u8; 64];
413 result.copy_from_slice(&uncompressed_bytes[1..]);
414 PublicKey::Secp256k1(result)
415 }
416 }
417 }
418
419 pub fn sign(&self, message: &[u8]) -> Signature {
421 match self {
422 Self::Ed25519(bytes) => {
423 let signing_key = SigningKey::from_bytes(bytes);
424 let signature = signing_key.sign(message);
425 Signature::Ed25519(signature.to_bytes())
426 }
427 Self::Secp256k1(bytes) => {
428 let signing_key = k256::ecdsa::SigningKey::from_bytes(bytes.into())
429 .expect("invalid secp256k1 key");
430
431 let hash = sha2::Sha256::digest(message);
433 let (signature, recovery_id) = signing_key
434 .sign_prehash_recoverable(&hash)
435 .expect("secp256k1 signing failed");
436
437 let mut sig_bytes = [0u8; 65];
439 sig_bytes[..64].copy_from_slice(&signature.to_bytes());
440 sig_bytes[64] = recovery_id.to_byte();
441
442 Signature::Secp256k1(sig_bytes)
443 }
444 }
445 }
446
447 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
469 Self::from_seed_phrase_with_path(phrase, DEFAULT_HD_PATH)
470 }
471
472 pub fn from_seed_phrase_with_path(
491 phrase: impl AsRef<str>,
492 hd_path: impl AsRef<str>,
493 ) -> Result<Self, SignerError> {
494 Self::from_seed_phrase_with_path_and_passphrase(phrase, hd_path, None)
495 }
496
497 pub fn from_seed_phrase_with_path_and_passphrase(
521 phrase: impl AsRef<str>,
522 hd_path: impl AsRef<str>,
523 passphrase: Option<&str>,
524 ) -> Result<Self, SignerError> {
525 let normalized = phrase
527 .as_ref()
528 .trim()
529 .to_lowercase()
530 .split_whitespace()
531 .collect::<Vec<_>>()
532 .join(" ");
533
534 let mnemonic: Mnemonic = normalized
535 .parse()
536 .map_err(|_| SignerError::InvalidSeedPhrase)?;
537
538 let seed = mnemonic.to_seed(passphrase.unwrap_or(""));
540
541 let path: BIP32Path = hd_path
543 .as_ref()
544 .parse()
545 .map_err(|e| SignerError::KeyDerivationFailed(format!("Invalid HD path: {}", e)))?;
546
547 let derived =
549 slipped10::derive_key_from_path(&seed, Curve::Ed25519, &path).map_err(|e| {
550 SignerError::KeyDerivationFailed(format!("SLIP-10 derivation failed: {:?}", e))
551 })?;
552
553 Ok(Self::ed25519_from_bytes(derived.key))
554 }
555
556 pub fn generate_with_seed_phrase() -> Result<(String, Self), SignerError> {
570 Self::generate_with_seed_phrase_custom(DEFAULT_WORD_COUNT, DEFAULT_HD_PATH, None)
571 }
572
573 pub fn generate_with_seed_phrase_words(
588 word_count: usize,
589 ) -> Result<(String, Self), SignerError> {
590 Self::generate_with_seed_phrase_custom(word_count, DEFAULT_HD_PATH, None)
591 }
592
593 pub fn generate_with_seed_phrase_custom(
601 word_count: usize,
602 hd_path: impl AsRef<str>,
603 passphrase: Option<&str>,
604 ) -> Result<(String, Self), SignerError> {
605 let phrase = generate_seed_phrase(word_count)?;
606 let secret_key =
607 Self::from_seed_phrase_with_path_and_passphrase(&phrase, hd_path, passphrase)?;
608 Ok((phrase, secret_key))
609 }
610}
611
612impl FromStr for SecretKey {
613 type Err = ParseKeyError;
614
615 fn from_str(s: &str) -> Result<Self, Self::Err> {
616 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
617
618 let key_type = match key_type {
619 "ed25519" => KeyType::Ed25519,
620 "secp256k1" => KeyType::Secp256k1,
621 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
622 };
623
624 let data = bs58::decode(data_str)
625 .into_vec()
626 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
627
628 let valid_len = match key_type {
631 KeyType::Ed25519 => data.len() == 32 || data.len() == 64,
632 KeyType::Secp256k1 => data.len() == 32,
633 };
634 if !valid_len {
635 return Err(ParseKeyError::InvalidLength {
636 expected: 32,
637 actual: data.len(),
638 });
639 }
640
641 let bytes: [u8; 32] = data[..32]
643 .try_into()
644 .map_err(|_| ParseKeyError::InvalidFormat)?;
645
646 match key_type {
647 KeyType::Ed25519 => Ok(Self::Ed25519(bytes)),
648 KeyType::Secp256k1 => {
649 k256::SecretKey::from_bytes((&bytes).into())
651 .map_err(|_| ParseKeyError::InvalidScalar)?;
652 Ok(Self::Secp256k1(bytes))
653 }
654 }
655 }
656}
657
658impl TryFrom<&str> for SecretKey {
659 type Error = ParseKeyError;
660
661 fn try_from(s: &str) -> Result<Self, Self::Error> {
662 s.parse()
663 }
664}
665
666impl Display for SecretKey {
667 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668 write!(
669 f,
670 "{}:{}",
671 self.key_type().as_str(),
672 bs58::encode(self.as_bytes()).into_string()
673 )
674 }
675}
676
677impl Debug for SecretKey {
678 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679 write!(f, "SecretKey({}:***)", self.key_type().as_str())
680 }
681}
682
683#[derive(Clone, PartialEq, Eq)]
685pub enum Signature {
686 Ed25519([u8; 64]),
688 Secp256k1([u8; 65]),
690}
691
692impl Signature {
693 pub fn ed25519_from_bytes(bytes: [u8; 64]) -> Self {
695 Self::Ed25519(bytes)
696 }
697
698 pub fn secp256k1_from_bytes(bytes: [u8; 65]) -> Self {
703 Self::Secp256k1(bytes)
704 }
705
706 pub fn key_type(&self) -> KeyType {
708 match self {
709 Self::Ed25519(_) => KeyType::Ed25519,
710 Self::Secp256k1(_) => KeyType::Secp256k1,
711 }
712 }
713
714 pub fn as_bytes(&self) -> &[u8] {
716 match self {
717 Self::Ed25519(bytes) => bytes.as_slice(),
718 Self::Secp256k1(bytes) => bytes.as_slice(),
719 }
720 }
721
722 pub fn verify(&self, message: &[u8], public_key: &PublicKey) -> bool {
724 match (self, public_key) {
725 (Self::Ed25519(sig_bytes), PublicKey::Ed25519(pk_bytes)) => {
726 let Ok(verifying_key) = VerifyingKey::from_bytes(pk_bytes) else {
727 return false;
728 };
729 let signature = ed25519_dalek::Signature::from_bytes(sig_bytes);
730 verifying_key.verify_strict(message, &signature).is_ok()
731 }
732 (Self::Secp256k1(sig_bytes), PublicKey::Secp256k1(pk_bytes)) => {
733 let mut uncompressed = [0u8; 65];
735 uncompressed[0] = 0x04;
736 uncompressed[1..].copy_from_slice(pk_bytes);
737 let Ok(verifying_key) = k256::ecdsa::VerifyingKey::from_sec1_bytes(&uncompressed)
738 else {
739 return false;
740 };
741
742 let v = sig_bytes[64];
744 if v > 3 {
745 return false;
746 }
747
748 let Ok(signature) = k256::ecdsa::Signature::from_bytes((&sig_bytes[..64]).into())
749 else {
750 return false;
751 };
752
753 let hash = sha2::Sha256::digest(message);
755 use k256::ecdsa::signature::hazmat::PrehashVerifier;
756 verifying_key.verify_prehash(&hash, &signature).is_ok()
757 }
758 _ => false,
760 }
761 }
762}
763
764impl FromStr for Signature {
765 type Err = ParseKeyError;
766
767 fn from_str(s: &str) -> Result<Self, Self::Err> {
768 let (key_type, data_str) = s.split_once(':').ok_or(ParseKeyError::InvalidFormat)?;
769
770 let key_type = match key_type {
771 "ed25519" => KeyType::Ed25519,
772 "secp256k1" => KeyType::Secp256k1,
773 other => return Err(ParseKeyError::UnknownKeyType(other.to_string())),
774 };
775
776 let data = bs58::decode(data_str)
777 .into_vec()
778 .map_err(|e| ParseKeyError::InvalidBase58(e.to_string()))?;
779
780 if data.len() != key_type.signature_len() {
781 return Err(ParseKeyError::InvalidLength {
782 expected: key_type.signature_len(),
783 actual: data.len(),
784 });
785 }
786
787 match key_type {
788 KeyType::Ed25519 => {
789 let bytes: [u8; 64] = data
790 .as_slice()
791 .try_into()
792 .map_err(|_| ParseKeyError::InvalidFormat)?;
793 Ok(Self::Ed25519(bytes))
794 }
795 KeyType::Secp256k1 => {
796 let bytes: [u8; 65] = data
797 .as_slice()
798 .try_into()
799 .map_err(|_| ParseKeyError::InvalidFormat)?;
800 Ok(Self::Secp256k1(bytes))
801 }
802 }
803 }
804}
805
806impl Display for Signature {
807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
808 write!(
809 f,
810 "{}:{}",
811 self.key_type().as_str(),
812 bs58::encode(self.as_bytes()).into_string()
813 )
814 }
815}
816
817impl Debug for Signature {
818 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819 write!(f, "Signature({})", self)
820 }
821}
822
823impl Serialize for Signature {
824 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
825 s.serialize_str(&self.to_string())
826 }
827}
828
829impl<'de> Deserialize<'de> for Signature {
830 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
831 let s: String = serde::Deserialize::deserialize(d)?;
832 s.parse().map_err(serde::de::Error::custom)
833 }
834}
835
836impl BorshSerialize for Signature {
837 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
838 borsh::BorshSerialize::serialize(&(self.key_type() as u8), writer)?;
839 writer.write_all(self.as_bytes())?;
840 Ok(())
841 }
842}
843
844impl BorshDeserialize for Signature {
845 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
846 let key_type_byte = u8::deserialize_reader(reader)?;
847 let key_type = KeyType::try_from(key_type_byte)
848 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
849
850 match key_type {
851 KeyType::Ed25519 => {
852 let mut bytes = [0u8; 64];
853 reader.read_exact(&mut bytes)?;
854 Ok(Self::Ed25519(bytes))
855 }
856 KeyType::Secp256k1 => {
857 let mut bytes = [0u8; 65];
858 reader.read_exact(&mut bytes)?;
859 Ok(Self::Secp256k1(bytes))
860 }
861 }
862 }
863}
864
865pub fn generate_seed_phrase(word_count: usize) -> Result<String, SignerError> {
884 use rand::RngCore;
885
886 let entropy_bytes = match word_count {
888 12 => 16,
889 15 => 20,
890 18 => 24,
891 21 => 28,
892 24 => 32,
893 _ => {
894 return Err(SignerError::KeyDerivationFailed(format!(
895 "Invalid word count: {}. Must be 12, 15, 18, 21, or 24",
896 word_count
897 )));
898 }
899 };
900
901 let mut entropy = vec![0u8; entropy_bytes];
902 OsRng.fill_bytes(&mut entropy);
903
904 let mnemonic = Mnemonic::from_entropy(&entropy).map_err(|e| {
905 SignerError::KeyDerivationFailed(format!("Failed to generate mnemonic: {}", e))
906 })?;
907
908 Ok(mnemonic.to_string())
909}
910
911#[derive(Clone)]
939pub struct KeyPair {
940 pub secret_key: SecretKey,
942 pub public_key: PublicKey,
944}
945
946impl KeyPair {
947 pub fn random() -> Self {
959 Self::random_ed25519()
960 }
961
962 pub fn random_ed25519() -> Self {
973 let secret_key = SecretKey::generate_ed25519();
974 let public_key = secret_key.public_key();
975 Self {
976 secret_key,
977 public_key,
978 }
979 }
980
981 pub fn random_secp256k1() -> Self {
992 let secret_key = SecretKey::generate_secp256k1();
993 let public_key = secret_key.public_key();
994 Self {
995 secret_key,
996 public_key,
997 }
998 }
999
1000 pub fn from_secret_key(secret_key: SecretKey) -> Self {
1011 let public_key = secret_key.public_key();
1012 Self {
1013 secret_key,
1014 public_key,
1015 }
1016 }
1017
1018 pub fn from_seed_phrase(phrase: impl AsRef<str>) -> Result<Self, SignerError> {
1029 let secret_key = SecretKey::from_seed_phrase(phrase)?;
1030 Ok(Self::from_secret_key(secret_key))
1031 }
1032
1033 pub fn random_with_seed_phrase() -> Result<(String, Self), SignerError> {
1047 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase()?;
1048 Ok((phrase, Self::from_secret_key(secret_key)))
1049 }
1050}
1051
1052impl std::fmt::Debug for KeyPair {
1053 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1054 f.debug_struct("KeyPair")
1055 .field("public_key", &self.public_key)
1056 .field("secret_key", &"***")
1057 .finish()
1058 }
1059}
1060
1061#[cfg(test)]
1062mod tests {
1063 use super::*;
1064
1065 #[test]
1066 fn test_generate_and_sign() {
1067 let secret = SecretKey::generate_ed25519();
1068 let public = secret.public_key();
1069 let message = b"hello world";
1070
1071 let signature = secret.sign(message);
1072 assert!(signature.verify(message, &public));
1073 assert!(!signature.verify(b"wrong message", &public));
1074 }
1075
1076 #[test]
1077 fn test_public_key_roundtrip() {
1078 let secret = SecretKey::generate_ed25519();
1079 let public = secret.public_key();
1080 let s = public.to_string();
1081 let parsed: PublicKey = s.parse().unwrap();
1082 assert_eq!(public, parsed);
1083 }
1084
1085 #[test]
1086 fn test_secret_key_roundtrip() {
1087 let secret = SecretKey::generate_ed25519();
1088 let s = secret.to_string();
1089 let parsed: SecretKey = s.parse().unwrap();
1090 assert_eq!(secret.public_key(), parsed.public_key());
1091 }
1092
1093 #[test]
1094 fn test_ed25519_secret_key_64_byte_expanded_form() {
1095 let secret = SecretKey::generate_ed25519();
1098 let public = secret.public_key();
1099 let seed_bytes = secret.as_bytes();
1100
1101 let mut expanded = Vec::with_capacity(64);
1103 expanded.extend_from_slice(seed_bytes);
1104 expanded.extend_from_slice(public.as_bytes());
1105 let expanded_b58 = bs58::encode(&expanded).into_string();
1106 let expanded_str = format!("ed25519:{}", expanded_b58);
1107
1108 let parsed: SecretKey = expanded_str.parse().unwrap();
1110 assert_eq!(parsed.public_key(), public);
1111
1112 let reserialized = parsed.to_string();
1114 assert_eq!(reserialized, secret.to_string());
1115 }
1116
1117 #[test]
1122 fn test_generate_seed_phrase_12_words() {
1123 let phrase = generate_seed_phrase(12).unwrap();
1124 assert_eq!(phrase.split_whitespace().count(), 12);
1125 }
1126
1127 #[test]
1128 fn test_generate_seed_phrase_24_words() {
1129 let phrase = generate_seed_phrase(24).unwrap();
1130 assert_eq!(phrase.split_whitespace().count(), 24);
1131 }
1132
1133 #[test]
1134 fn test_generate_seed_phrase_invalid_word_count() {
1135 let result = generate_seed_phrase(13);
1136 assert!(result.is_err());
1137 }
1138
1139 const TEST_PHRASE: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
1141
1142 #[test]
1143 fn test_from_seed_phrase_known_vector() {
1144 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1146
1147 let secret_key2 = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1149 assert_eq!(secret_key.public_key(), secret_key2.public_key());
1150 }
1151
1152 #[test]
1153 fn test_from_seed_phrase_whitespace_normalization() {
1154 let phrase1 = TEST_PHRASE;
1155 let phrase2 = " abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ";
1156 let phrase3 = "ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABANDON ABOUT";
1157
1158 let key1 = SecretKey::from_seed_phrase(phrase1).unwrap();
1159 let key2 = SecretKey::from_seed_phrase(phrase2).unwrap();
1160 let key3 = SecretKey::from_seed_phrase(phrase3).unwrap();
1161
1162 assert_eq!(key1.public_key(), key2.public_key());
1163 assert_eq!(key1.public_key(), key3.public_key());
1164 }
1165
1166 #[test]
1167 fn test_from_seed_phrase_invalid() {
1168 let result = SecretKey::from_seed_phrase("invalid words that are not a mnemonic");
1169 assert!(result.is_err());
1170 }
1171
1172 #[test]
1173 fn test_from_seed_phrase_different_paths() {
1174 let key1 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/0'").unwrap();
1175 let key2 = SecretKey::from_seed_phrase_with_path(TEST_PHRASE, "m/44'/397'/1'").unwrap();
1176
1177 assert_ne!(key1.public_key(), key2.public_key());
1179 }
1180
1181 #[test]
1182 fn test_from_seed_phrase_with_passphrase() {
1183 let key_no_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1184 TEST_PHRASE,
1185 DEFAULT_HD_PATH,
1186 None,
1187 )
1188 .unwrap();
1189
1190 let key_with_pass = SecretKey::from_seed_phrase_with_path_and_passphrase(
1191 TEST_PHRASE,
1192 DEFAULT_HD_PATH,
1193 Some("my-password"),
1194 )
1195 .unwrap();
1196
1197 assert_ne!(key_no_pass.public_key(), key_with_pass.public_key());
1199 }
1200
1201 #[test]
1202 fn test_generate_with_seed_phrase() {
1203 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase().unwrap();
1204
1205 assert_eq!(phrase.split_whitespace().count(), 12);
1207
1208 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1210 assert_eq!(secret_key.public_key(), derived.public_key());
1211 }
1212
1213 #[test]
1214 fn test_generate_with_seed_phrase_24_words() {
1215 let (phrase, secret_key) = SecretKey::generate_with_seed_phrase_words(24).unwrap();
1216
1217 assert_eq!(phrase.split_whitespace().count(), 24);
1218
1219 let derived = SecretKey::from_seed_phrase(&phrase).unwrap();
1220 assert_eq!(secret_key.public_key(), derived.public_key());
1221 }
1222
1223 #[test]
1224 fn test_seed_phrase_key_can_sign() {
1225 let secret_key = SecretKey::from_seed_phrase(TEST_PHRASE).unwrap();
1226
1227 let message = b"test message";
1228 let signature = secret_key.sign(message);
1229 let public_key = secret_key.public_key();
1230
1231 assert!(signature.verify(message, &public_key));
1232 }
1233
1234 #[test]
1239 fn test_secp256k1_invalid_curve_point_rejected() {
1240 let invalid_key = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj";
1243 let result: Result<PublicKey, _> = invalid_key.parse();
1244 assert!(result.is_err());
1245 assert!(matches!(
1246 result.unwrap_err(),
1247 ParseKeyError::InvalidCurvePoint | ParseKeyError::InvalidLength { .. }
1248 ));
1249 }
1250
1251 #[test]
1252 fn test_secp256k1_valid_curve_point_accepted() {
1253 let valid_key = "secp256k1:5r22SrjrDvgY3wdQsnjgxkeAbU1VcM71FYvALEQWihjM3Xk4Be1CpETTqFccChQr4iJwDroSDVmgaWZv2AcXvYeL";
1256 let result: Result<PublicKey, _> = valid_key.parse();
1257 assert!(result.is_ok());
1259 }
1260
1261 #[test]
1262 fn test_ed25519_valid_key_accepted() {
1263 let valid_key = "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp";
1265 let result: Result<PublicKey, _> = valid_key.parse();
1266 assert!(result.is_ok());
1267 }
1268
1269 #[test]
1270 fn test_ed25519_invalid_curve_point_rejected() {
1271 let invalid_bytes = [
1280 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1281 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1282 0xFF, 0xFF, 0xFF, 0x7F,
1283 ];
1284 let encoded = bs58::encode(&invalid_bytes).into_string();
1285 let invalid_key = format!("ed25519:{}", encoded);
1286 let result: Result<PublicKey, _> = invalid_key.parse();
1287 if let Err(err) = result {
1288 assert!(matches!(err, ParseKeyError::InvalidCurvePoint));
1289 } else {
1290 eprintln!(
1292 "Note: ed25519 point decompression accepted test bytes - validation may be too lenient"
1293 );
1294 }
1295 }
1296
1297 #[test]
1298 fn test_borsh_deserialize_validates_curve_point() {
1299 use borsh::BorshDeserialize;
1300
1301 let mut invalid_bytes = vec![1u8]; invalid_bytes.extend_from_slice(&[0u8; 64]); let result = PublicKey::try_from_slice(&invalid_bytes);
1307 assert!(result.is_err());
1308 }
1309
1310 #[test]
1311 fn test_signature_from_str_roundtrip() {
1312 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1313 let sig: Signature = sig_str.parse().unwrap();
1314 assert_eq!(sig.key_type(), KeyType::Ed25519);
1315 assert_eq!(sig.as_bytes().len(), 64);
1316 assert_eq!(sig.to_string(), sig_str);
1317 }
1318
1319 #[test]
1320 fn test_signature_from_str_invalid_format() {
1321 assert!("no_colon".parse::<Signature>().is_err());
1322 assert!("unknown:abc".parse::<Signature>().is_err());
1323 assert!("ed25519:invalid!!!".parse::<Signature>().is_err());
1324 assert!("ed25519:AAAA".parse::<Signature>().is_err()); }
1326
1327 #[test]
1328 fn test_signature_serde_roundtrip() {
1329 let sig_str = "ed25519:3s1dvMqNDCByoMnDnkhB4GPjTSXCRt4nt3Af5n1RX8W7aJ2FC6MfRf5BNXZ52EBifNJnNVBsGvke6GRYuaEYJXt5";
1330 let sig: Signature = sig_str.parse().unwrap();
1331 let json = serde_json::to_value(&sig).unwrap();
1332 assert_eq!(json.as_str().unwrap(), sig_str);
1333 let parsed: Signature = serde_json::from_value(json).unwrap();
1334 assert_eq!(sig, parsed);
1335 }
1336
1337 #[test]
1342 fn test_secp256k1_generate_and_sign_verify() {
1343 let secret = SecretKey::generate_secp256k1();
1344 let public = secret.public_key();
1345 let message = b"hello world";
1346
1347 assert_eq!(secret.key_type(), KeyType::Secp256k1);
1348 assert_eq!(public.key_type(), KeyType::Secp256k1);
1349
1350 let signature = secret.sign(message);
1351 assert_eq!(signature.key_type(), KeyType::Secp256k1);
1352 assert_eq!(signature.as_bytes().len(), 65);
1353
1354 assert!(signature.verify(message, &public));
1355 assert!(!signature.verify(b"wrong message", &public));
1356 }
1357
1358 #[test]
1359 fn test_secp256k1_public_key_is_64_bytes() {
1360 let secret = SecretKey::generate_secp256k1();
1361 let public = secret.public_key();
1362
1363 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1365 assert_eq!(pk_bytes.len(), 64);
1366 }
1367
1368 #[test]
1369 fn test_secp256k1_secret_key_to_public_key_derivation() {
1370 let bytes = [42u8; 32];
1372 let sk1 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1373 let sk2 = SecretKey::secp256k1_from_bytes(bytes).unwrap();
1374 assert_eq!(sk1.public_key(), sk2.public_key());
1375
1376 let bytes2 = [43u8; 32];
1378 let sk3 = SecretKey::secp256k1_from_bytes(bytes2).unwrap();
1379 assert_ne!(sk1.public_key(), sk3.public_key());
1380 }
1381
1382 #[test]
1383 fn test_secp256k1_public_key_string_roundtrip() {
1384 let secret = SecretKey::generate_secp256k1();
1385 let public = secret.public_key();
1386 let s = public.to_string();
1387 assert!(s.starts_with("secp256k1:"));
1388 let parsed: PublicKey = s.parse().unwrap();
1389 assert_eq!(public, parsed);
1390 }
1391
1392 #[test]
1393 fn test_secp256k1_secret_key_string_roundtrip() {
1394 let secret = SecretKey::generate_secp256k1();
1395 let s = secret.to_string();
1396 assert!(s.starts_with("secp256k1:"));
1397 let parsed: SecretKey = s.parse().unwrap();
1398 assert_eq!(secret.public_key(), parsed.public_key());
1399 }
1400
1401 #[test]
1402 fn test_secp256k1_keypair_random() {
1403 let keypair = KeyPair::random_secp256k1();
1404 assert_eq!(keypair.public_key.key_type(), KeyType::Secp256k1);
1405 assert_eq!(keypair.secret_key.key_type(), KeyType::Secp256k1);
1406 assert!(keypair.public_key.to_string().starts_with("secp256k1:"));
1407
1408 let message = b"keypair test";
1410 let signature = keypair.secret_key.sign(message);
1411 assert!(signature.verify(message, &keypair.public_key));
1412 }
1413
1414 #[test]
1415 fn test_secp256k1_cross_type_verify_fails() {
1416 let ed_secret = SecretKey::generate_ed25519();
1418 let secp_secret = SecretKey::generate_secp256k1();
1419
1420 let message = b"cross type test";
1421 let ed_sig = ed_secret.sign(message);
1422 let secp_sig = secp_secret.sign(message);
1423
1424 assert!(!ed_sig.verify(message, &secp_secret.public_key()));
1425 assert!(!secp_sig.verify(message, &ed_secret.public_key()));
1426 }
1427
1428 #[test]
1429 fn test_secp256k1_invalid_scalar_rejected() {
1430 let zero_bytes = [0u8; 32];
1432 let result = SecretKey::secp256k1_from_bytes(zero_bytes);
1433 assert!(result.is_err());
1434 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1435 }
1436
1437 #[test]
1438 fn test_secp256k1_invalid_scalar_rejected_from_str() {
1439 let zero_bytes = [0u8; 32];
1441 let encoded = bs58::encode(&zero_bytes).into_string();
1442 let key_str = format!("secp256k1:{}", encoded);
1443 let result: Result<SecretKey, _> = key_str.parse();
1444 assert!(result.is_err());
1445 assert!(matches!(result.unwrap_err(), ParseKeyError::InvalidScalar));
1446 }
1447
1448 #[test]
1449 fn test_secp256k1_invalid_recovery_id_rejected() {
1450 let secret = SecretKey::generate_secp256k1();
1451 let public = secret.public_key();
1452 let message = b"test message";
1453 let signature = secret.sign(message);
1454
1455 if let Signature::Secp256k1(mut sig_bytes) = signature.clone() {
1457 sig_bytes[64] = 4; let tampered = Signature::Secp256k1(sig_bytes);
1459 assert!(!tampered.verify(message, &public));
1460
1461 sig_bytes[64] = 255;
1462 let tampered = Signature::Secp256k1(sig_bytes);
1463 assert!(!tampered.verify(message, &public));
1464 } else {
1465 panic!("Expected Secp256k1 signature");
1466 }
1467 }
1468
1469 #[test]
1470 fn test_secp256k1_from_compressed() {
1471 let secret = SecretKey::generate_secp256k1();
1472 let public = secret.public_key();
1473
1474 let pk_bytes = public.as_secp256k1_bytes().unwrap();
1476 let mut uncompressed = [0u8; 65];
1477 uncompressed[0] = 0x04;
1478 uncompressed[1..].copy_from_slice(pk_bytes);
1479 let encoded =
1480 k256::EncodedPoint::from_bytes(uncompressed.as_ref()).expect("valid encoded point");
1481 let point = k256::AffinePoint::from_encoded_point(&encoded).expect("valid point on curve");
1482 let compressed = point.to_encoded_point(true);
1483 let compressed_bytes: [u8; 33] = compressed
1484 .as_bytes()
1485 .try_into()
1486 .expect("compressed should be 33 bytes");
1487
1488 let public2 = PublicKey::secp256k1_from_compressed(compressed_bytes);
1490 assert_eq!(public, public2);
1491 }
1492
1493 #[test]
1494 fn test_ed25519_borsh_roundtrip() {
1495 use borsh::BorshDeserialize;
1496
1497 let secret = SecretKey::generate_ed25519();
1498 let public = secret.public_key();
1499 let serialized = borsh::to_vec(&public).unwrap();
1500 assert_eq!(serialized.len(), 33);
1502 assert_eq!(serialized[0], 0); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1504 assert_eq!(public, deserialized);
1505 }
1506
1507 #[test]
1508 fn test_secp256k1_borsh_roundtrip() {
1509 use borsh::BorshDeserialize;
1510
1511 let secret = SecretKey::generate_secp256k1();
1512 let public = secret.public_key();
1513 let serialized = borsh::to_vec(&public).unwrap();
1514 assert_eq!(serialized.len(), 65);
1516 assert_eq!(serialized[0], 1); let deserialized = PublicKey::try_from_slice(&serialized).unwrap();
1518 assert_eq!(public, deserialized);
1519 }
1520
1521 #[test]
1522 fn test_signature_borsh_roundtrip() {
1523 use borsh::BorshDeserialize;
1524
1525 let secret = SecretKey::generate_ed25519();
1526 let sig = secret.sign(b"test");
1527 let serialized = borsh::to_vec(&sig).unwrap();
1528 assert_eq!(serialized.len(), 65); let deserialized = Signature::try_from_slice(&serialized).unwrap();
1530 assert_eq!(sig, deserialized);
1531 }
1532
1533 #[test]
1534 fn test_enum_variants_match_expected_types() {
1535 let ed_secret = SecretKey::generate_ed25519();
1536 let ed_public = ed_secret.public_key();
1537
1538 assert!(matches!(ed_public, PublicKey::Ed25519(_)));
1539 assert!(matches!(ed_secret, SecretKey::Ed25519(_)));
1540
1541 let secp_secret = SecretKey::generate_secp256k1();
1542 let secp_public = secp_secret.public_key();
1543
1544 assert!(matches!(secp_public, PublicKey::Secp256k1(_)));
1545 assert!(matches!(secp_secret, SecretKey::Secp256k1(_)));
1546 }
1547}