stellar_base/crypto/dalek/
keypair.rs1use std::convert::TryInto;
2
3use crate::crypto::{strkey, KeyPair};
4use crate::crypto::{Ed25519Signer, Signature};
5use crate::error::{Error, Result};
6use crate::network::Network;
7use crate::PublicKey;
8
9#[derive(Debug)]
11pub struct SecretKey {
12 signing_key: ed25519_dalek::SigningKey,
13}
14
15impl Ed25519Signer<Signature> for SecretKey {
16 fn try_sign(
17 &self,
18 msg: &[u8],
19 ) -> std::result::Result<ed25519::Signature, ed25519_dalek::SignatureError> {
20 self.signing_key.try_sign(msg)
21 }
22}
23
24#[derive(Debug)]
25pub struct DalekKeyPair(KeyPair<SecretKey, ed25519_dalek::VerifyingKey>);
26
27impl SecretKey {
28 pub fn inner(&self) -> &ed25519_dalek::SigningKey {
30 &self.signing_key
31 }
32
33 pub fn secret_seed(&self) -> String {
35 strkey::encode_secret_seed(self.signing_key.as_bytes())
36 }
37}
38
39impl AsRef<KeyPair<SecretKey, ed25519_dalek::VerifyingKey>> for DalekKeyPair {
40 fn as_ref(&self) -> &KeyPair<SecretKey, ed25519_dalek::VerifyingKey> {
41 &self.0
42 }
43}
44
45impl DalekKeyPair {
46 pub fn from_secret_seed(data: &str) -> Result<DalekKeyPair> {
48 let bytes = strkey::decode_secret_seed(data)?;
49 Self::from_seed_bytes(&bytes)
50 }
51
52 pub fn random() -> Result<DalekKeyPair> {
54 use rand::rngs::OsRng;
55 let mut rng = OsRng {};
56 let signing_key = ed25519_dalek::SigningKey::generate(&mut rng);
57 let verifier = signing_key.verifying_key();
58 let signer = SecretKey { signing_key };
59 Ok(DalekKeyPair(KeyPair::new(signer, verifier)))
60 }
61
62 pub fn from_network(network: &Network) -> Result<DalekKeyPair> {
64 let bytes = network.network_id();
65 Self::from_seed_bytes(&bytes)
66 }
67
68 pub fn from_seed_bytes(data: &[u8]) -> Result<DalekKeyPair> {
70 let secret_key: ed25519_dalek::SecretKey =
71 data.try_into().map_err(|_| Error::InvalidSeed)?;
72 let signing_key = ed25519_dalek::SigningKey::from_bytes(&secret_key);
73 let verifier = signing_key.verifying_key();
74 let signer = SecretKey { signing_key };
75 Ok(DalekKeyPair(KeyPair::new(signer, verifier)))
76 }
77
78 pub fn secret_key(&self) -> &SecretKey {
80 &self.0.signer.signing_key
81 }
82
83 pub fn public_key(&self) -> PublicKey {
85 PublicKey::from_slice(self.0.verifier.verify_key.as_bytes())
86 .expect("Ed25519 public key is not 32 bytes")
87 }
88
89 pub fn sign(&self, msg: &[u8]) -> Signature {
90 self.0.sign(msg)
91 }
92
93 pub fn verify(&self, sig: &Signature, msg: &[u8]) -> bool {
94 self.0.verify(msg, sig).is_ok_and(|_| true)
95 }
96}
97
98impl std::str::FromStr for DalekKeyPair {
99 type Err = crate::error::Error;
100
101 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
102 let sk = DalekKeyPair::from_secret_seed(s)?;
103 Ok(sk)
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::{DalekKeyPair, PublicKey};
110 use crate::network::Network;
111 use std::str::FromStr;
112
113 #[test]
114 fn test_from_secret_seed() {
115 let keypairs = [
116 (
117 "SCRG6SFG64YDEVGWDWTZBE6BWEW25WICOGOUTODVICCA3L3FOQIG26E6",
118 "GDRZ6UR4VI3DWATUKAXCGCGAUXGF3IJYG5T3CTJDUJ674TFLN4AR6RV4",
119 ),
120 (
121 "SCOHYGOOQBONAMHLFFTS3OHG2V45GHRVU6Q5HI7VZ2T4C3WRSVCUAWRN",
122 "GB5YW3UGJQ635LBGCXJVU3D2TXJIQRX7LRRWFMD2PKZLQ3G2OIZY4ZWO",
123 ),
124 (
125 "SD4IDUZJZKPWU2T2AJWB35AN42L3NADBRCXHL5HY4WXPWO43MQTMCIIF",
126 "GCEAKB6W342KSAQ6SVJYROF5W5FJTPZDDOSIOT3Y6CNQ3U2ZBAH7AQN3",
127 ),
128 (
129 "SBB3NC6JM6IT6RXXQKMWH5XBGWWVWXL2MDBVOUPWWKP52QRFB2ISF2IR",
130 "GCG5C6WXDSN55I25M7C6734EYVJ562KR4CKWEKK7RISUISNO36LX5J7G",
131 ),
132 (
133 "SDGLIKRUQX5WJCLKGJUSAG3XK7GW262H7SQMLCKV4K5RWXNOWFD5VFG6",
134 "GAGKPXZNQ7QDYKRMKE34IB7S5SUKPK4AWETZRBG6CYK3TNANV4HQHJGV",
135 ),
136 (
137 "SD3AXQQRD4HXWHWVX7R56UHPT7ZDJPADTYTC3UTGRYHZ2AR37O66OZQB",
138 "GD6KUX4TY4BFKCQBNAFK577IWNB3PNPASBG2JEBIJK6X4CSXNRWCINHU",
139 ),
140 (
141 "SBHRV6BPRPIMTY7EYWFOLUNILQDU3UP5KWQA43UPW7R6WBTWTUGCY446",
142 "GARHX6B4IAM2E3WUISLBWYY6TVWWQIWZPUYWXHSQ5BSSV5NKQX5CT4MC",
143 ),
144 (
145 "SA7M4FOPTIT3CNW3B44CQMQRA4A7ZJCAOVHRUEHAMGFVWWCLIA3UXULE",
146 "GASQUYLK6GRHBE6Z4A4HH5NHQPAHMHWAUSQP5N7D465QYYBEHDOPFXVP",
147 ),
148 (
149 "SBKNQCZGK2X2VDOIAZWWZ7H3J5XWSU23UGUU62IXVTMWC6AGVN4N3OX7",
150 "GD7EMEPGLBYDHUEDSJMAI64BS6HX46SAIPGIF3E5HI4CJ53VQ4OWEEBE",
151 ),
152 (
153 "SA7UGZLM6Q6RR4BC7252IMUAHCZJLDHGBJFKVENIE2HKQ66T7L4T4ZMF",
154 "GC22QEDRADRMZ2RPSBGY5N3RMGGSBKCMBQBFCJH3M4RZQ4KQQXUVQNID",
155 ),
156 ];
157
158 for &(secret, address) in keypairs.iter() {
159 let keypair = DalekKeyPair::from_secret_seed(secret).unwrap();
160 let keypair2 = DalekKeyPair::from_str(secret).unwrap();
161 assert_eq!(&keypair2.secret_key().secret_seed(), secret);
162 let account_id = keypair.public_key().account_id();
163 assert_eq!(&account_id, address);
164 let parsed = PublicKey::from_str(&account_id).unwrap();
165 assert_eq!(account_id, parsed.to_string());
166 }
167 }
168
169 #[test]
170 fn test_from_network() {
171 let network = Network::new_public();
172 let kp = DalekKeyPair::from_network(&network).unwrap();
173 let public = kp.public_key().account_id();
174 assert_eq!(
175 public,
176 "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7"
177 );
178 }
179
180 #[test]
181 fn test_sign_and_verify() {
182 let the_secret = "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36";
183 let kp = DalekKeyPair::from_secret_seed(the_secret).unwrap();
184 let message = "test post please ignore".as_bytes();
185 let sign = kp.sign(message);
186 let expected_sign = [
187 0x19, 0xDB, 0xFD, 0xAF, 0x0A, 0xA8, 0x4D, 0xF9, 0xA7, 0xFF, 0x6F, 0xE3, 0xC1, 0x0E,
188 0xBC, 0x1F, 0xE2, 0x14, 0xC5, 0x10, 0xB9, 0x5D, 0xB0, 0xD6, 0x33, 0xBE, 0xD9, 0x3D,
189 0xF9, 0x25, 0x6B, 0xA9, 0x92, 0xEF, 0x7D, 0x94, 0xB2, 0xA6, 0xE4, 0x54, 0xDE, 0x8F,
190 0x21, 0x9, 0x28, 0xCA, 0x96, 0x11, 0x39, 0x03, 0x29, 0xC8, 0x40, 0xC8, 0xE5, 0x64,
191 0xE7, 0xA0, 0x72, 0x16, 0x02, 0x7A, 0xB4, 0xA,
192 ];
193 assert_eq!(sign.to_bytes(), expected_sign[..]);
194 assert!(kp.verify(&sign, message));
195 }
196
197 #[test]
198 fn test_sign_decorated() {
199 let the_secret = "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36";
200 let kp = DalekKeyPair::from_secret_seed(the_secret).unwrap();
201 let message = "test post please ignore".as_bytes();
202 let sign = kp.as_ref().sign_decorated(message);
203 assert_eq!(sign.hint().to_vec(), vec![0x0B, 0xFA, 0xD1, 0x34]);
204 }
205}