1use crate::hashing::HashingBehavior;
6use crate::hashing::Sha256Hasher;
7use crate::signing::{generate, sign, verify};
8use crate::xdr;
9use crate::xdr::WriteXdr;
10use hex::FromHex;
11use rand_core::TryRngCore;
12use rand_core::{OsRng, RngCore};
13use sha2::Sha512;
14use std::str;
15use std::{error::Error, str::FromStr};
16use stellar_strkey::{
17 ed25519::{PrivateKey, PublicKey},
18 Strkey,
19};
20
21#[derive(Debug, Clone)]
22pub struct Keypair {
23 public_key: Vec<u8>,
24 secret_key: Option<Vec<u8>>,
25 secret_seed: Option<Vec<u8>>,
26}
27
28pub trait KeypairBehavior {
29 fn new(
31 public_key: Option<[u8; 32]>,
32 secret_key: Option<[u8; 32]>,
33 ) -> Result<Self, Box<dyn Error>>
34 where
35 Self: Sized;
36
37 fn new_from_secret_key(secret_seed: Vec<u8>) -> Result<Self, Box<dyn Error>>
39 where
40 Self: Sized;
41
42 fn new_from_public_key(public_key: Vec<u8>) -> Result<Self, Box<dyn Error>>
44 where
45 Self: Sized;
46
47 fn from_secret(secret: &str) -> Result<Self, Box<dyn Error>>
49 where
50 Self: Sized;
51
52 fn from_public_key(public_key: &str) -> Result<Self, Box<dyn Error>>
54 where
55 Self: Sized;
56
57 fn from_raw_ed25519_seed(seed: &[u8]) -> Result<Self, Box<dyn Error>>
59 where
60 Self: Sized;
61
62 fn raw_secret_key(&self) -> Option<Vec<u8>>;
64
65 fn raw_public_key(&self) -> &Vec<u8>;
67
68 fn secret_key(&self) -> Result<String, Box<dyn Error>>;
70
71 fn public_key(&self) -> String;
73
74 fn can_sign(&self) -> bool;
76
77 fn sign(&self, data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>>;
79
80 fn verify(&self, data: &[u8], signature: &[u8]) -> bool;
82
83 fn random() -> Result<Self, Box<dyn Error>>
85 where
86 Self: Sized;
87
88 fn master(network_passphrase: Option<&str>) -> Result<Self, Box<dyn Error>>
90 where
91 Self: Sized;
92
93 fn xdr_account_id(&self) -> xdr::AccountId;
95
96 fn xdr_public_key(&self) -> xdr::PublicKey;
98
99 fn xdr_muxed_account_id(&self, id: &str) -> xdr::MuxedAccount;
101
102 fn raw_pubkey(&self) -> [u8; 32];
104
105 fn signature_hint(&self) -> Option<Vec<u8>>;
107
108 fn sign_decorated(&self, data: &[u8]) -> xdr::DecoratedSignature;
110
111 fn sign_payload_decorated(&self, data: &[u8]) -> xdr::DecoratedSignature;
113}
114
115impl KeypairBehavior for Keypair {
116 fn new(
118 public_key: Option<[u8; 32]>,
119 secret_key: Option<[u8; 32]>,
120 ) -> Result<Self, Box<dyn Error>> {
121 if let Some(secret_key) = secret_key {
122 let sec_seed = secret_key;
123 let public_key_gen = generate(&sec_seed);
124 let mut secret_key = Vec::new();
125 secret_key.extend_from_slice(&sec_seed);
126 secret_key.extend_from_slice(&public_key_gen);
127
128 if let Some(public_key_arg) = public_key {
129 if public_key_arg != public_key_gen {
130 return Err("secretKey does not match publicKey".into());
131 }
132 }
133
134 Ok(Self {
135 secret_seed: Some(sec_seed.to_vec()),
136 public_key: public_key_gen.to_vec(),
137 secret_key: Some(secret_key),
138 })
139 } else {
140 Ok(Self {
141 secret_seed: None,
142 public_key: public_key.unwrap().to_vec(),
143 secret_key: None,
144 })
145 }
146 }
147
148 fn new_from_secret_key(secret_seed: Vec<u8>) -> Result<Self, Box<dyn Error>> {
150 if secret_seed.len() != 32 {
151 return Err("secret_key length is invalid".into());
152 }
153
154 let mut cloned_secret_key = secret_seed.clone();
155 let pkey = generate(&secret_seed);
156 let mut pk = pkey.clone().to_vec();
157
158 let mut secret_key = Vec::new();
159 secret_key.append(&mut cloned_secret_key);
160 secret_key.append(&mut pk);
161
162 Ok(Self {
163 secret_seed: Some(secret_seed),
164 public_key: pkey.to_vec(),
165 secret_key: Some(secret_key),
166 })
167 }
168
169 fn new_from_public_key(public_key: Vec<u8>) -> Result<Self, Box<dyn Error>> {
171 if public_key.len() != 32 {
172 return Err("public_key length is invalid".into());
173 }
174
175 Ok(Self {
176 public_key,
177 secret_key: None,
178 secret_seed: None,
179 })
180 }
181
182 fn from_secret(secret: &str) -> Result<Self, Box<dyn Error>> {
184 let raw_secret = PrivateKey::from_str(secret).unwrap().0;
185 Keypair::from_raw_ed25519_seed(&raw_secret)
186 }
187
188 fn from_public_key(public_key: &str) -> Result<Self, Box<dyn Error>> {
190 let decoded = PublicKey::from_str(public_key)?;
191 if decoded.0.len() != 32 {
192 return Err("Invalid Stellar public key".into());
193 }
194
195 Ok(Self {
196 public_key: decoded.0.to_vec(),
197 secret_seed: None,
198 secret_key: None,
199 })
200 }
201
202 fn from_raw_ed25519_seed(seed: &[u8]) -> Result<Self, Box<dyn Error>> {
204 if seed.len() >= 33 {
205 return Err("Invalid seed length".into());
206 }
207 Self::new_from_secret_key(seed.to_vec())
208 }
209
210 fn raw_secret_key(&self) -> Option<Vec<u8>> {
212 self.secret_seed.clone()
213 }
214
215 fn raw_public_key(&self) -> &Vec<u8> {
217 &self.public_key
218 }
219
220 fn secret_key(&self) -> Result<String, Box<dyn Error>> {
222 match &self.secret_seed {
223 None => Err("no secret_key available".into()),
224 Some(s) => Ok(PrivateKey::from_payload(s).unwrap().clone().to_string()),
225 }
226 }
227
228 fn public_key(&self) -> String {
230 PublicKey::from_payload(&self.public_key)
231 .unwrap()
232 .to_string()
233 }
234
235 fn can_sign(&self) -> bool {
237 self.secret_key.is_some()
238 }
239
240 fn sign(&self, data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
242 if !self.can_sign() {
243 return Err("cannot sign, no secret_key available".into());
244 }
245
246 if let Some(s) = &self.secret_key {
247 return Ok(sign(data, s).to_vec());
248 }
249
250 Err("error while signing".into())
251 }
252
253 fn verify(&self, data: &[u8], signature: &[u8]) -> bool {
255 verify(data, signature, self.public_key.as_slice())
256 }
257
258 fn random() -> Result<Self, Box<dyn Error>> {
260 let mut secret_seed = [0u8; 32];
261 let mut rng = OsRng;
262 rng.try_fill_bytes(&mut secret_seed);
263 Self::new_from_secret_key(secret_seed.to_vec())
264 }
265
266 fn master(network_passphrase: Option<&str>) -> Result<Self, Box<dyn Error>> {
268 if let Some(passphrase) = network_passphrase {
269 Ok(Self::from_raw_ed25519_seed(&Sha256Hasher::hash(passphrase)).unwrap())
270 } else {
271 Err("No network selected. Please pass a network argument, e.g. `Keypair::master(Some(Networks::PUBLIC))`.".into())
272 }
273 }
274 fn xdr_account_id(&self) -> xdr::AccountId {
276 xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
277 PublicKey::from_payload(&self.public_key).unwrap().0,
278 )))
279 }
280
281 fn xdr_public_key(&self) -> xdr::PublicKey {
283 xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
284 PublicKey::from_payload(&self.public_key).unwrap().0,
285 ))
286 }
287
288 fn xdr_muxed_account_id(&self, id: &str) -> xdr::MuxedAccount {
290 xdr::MuxedAccount::MuxedEd25519(xdr::MuxedAccountMed25519 {
291 id: xdr::Uint64::from_str(id).unwrap(),
292 ed25519: xdr::Uint256(PublicKey::from_payload(&self.public_key).unwrap().0),
293 })
294 }
295
296 fn raw_pubkey(&self) -> [u8; 32] {
297 let mut array: [u8; 32] = [0; 32];
298
299 for (i, &value) in self.public_key.iter().enumerate() {
300 array[i] = value;
301 }
302
303 array
304 }
305
306 fn signature_hint(&self) -> Option<Vec<u8>> {
308 let a = Self::xdr_account_id(self)
309 .to_xdr(xdr::Limits::none())
310 .unwrap();
311 if a.len() >= 4 {
312 let start_index = a.len() - 4;
313 Some(a[start_index..].to_vec())
314 } else {
315 None
316 }
317 }
318
319 fn sign_decorated(&self, data: &[u8]) -> xdr::DecoratedSignature {
321 let signature = Self::sign(self, data).unwrap();
322 let hint = Self::signature_hint(self).unwrap();
323 let mut hint_u8: [u8; 4] = [0; 4];
324 hint_u8.copy_from_slice(&hint[..4]);
325 let val = xdr::SignatureHint::from(hint_u8);
326 let signature_xdr = xdr::Signature::try_from(signature).unwrap();
327 xdr::DecoratedSignature {
328 hint: val,
329 signature: signature_xdr,
330 }
331 }
332
333 fn sign_payload_decorated(&self, data: &[u8]) -> xdr::DecoratedSignature {
335 let signature = Self::sign(self, data).unwrap();
336 let hint = Self::signature_hint(self).unwrap();
337 let mut key_hint_u8: [u8; 4] = [0; 4];
338 key_hint_u8.copy_from_slice(&hint[..4]);
339 let val = xdr::SignatureHint::from(key_hint_u8);
340 let signature_xdr = xdr::Signature::try_from(signature).unwrap();
341 let mut hint: [u8; 4] = [0; 4];
342
343 if data.len() >= 4 {
344 hint.copy_from_slice(&data[data.len() - 4..]);
345 } else {
346 hint[..data.len()].copy_from_slice(data);
347 #[allow(clippy::needless_range_loop)]
348 for i in data.len()..4 {
349 hint[i] = 0;
350 }
351 }
352
353 for i in 0..4 {
354 hint[i] ^= key_hint_u8[i];
355 }
356
357 let val = xdr::SignatureHint::from(hint);
358
359 xdr::DecoratedSignature {
360 hint: val,
361 signature: signature_xdr,
362 }
363 }
364}
365
366#[cfg(test)]
367mod tests {
368
369 use hex_literal::hex;
370 use sha2::digest::crypto_common::Key;
371
372 use super::*;
373
374 #[test]
375 fn keypair_constructor_fails_when_secret_key_does_not_match_public_key() {
376 let secret = "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36";
377 let kp = Keypair::from_secret(secret).unwrap();
378 let mut secret_key = kp.raw_secret_key().unwrap();
379 let c = secret_key.as_slice();
380 let mut public_key = PublicKey::from_str(kp.public_key().as_str()).unwrap().0;
381 public_key[0] = 0; let keypair = Keypair::new(Some(public_key), Some(c.try_into().unwrap()));
383 assert!(keypair.is_err());
384 assert_eq!(
385 keypair.err().unwrap().to_string(),
386 "secretKey does not match publicKey"
387 )
388 }
389
390 #[test]
391 fn test_create_keypair_from_secret() {
392 let secret = "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36";
393 let expected_public_key = "GDFQVQCYYB7GKCGSCUSIQYXTPLV5YJ3XWDMWGQMDNM4EAXAL7LITIBQ7";
394 let keypair = Keypair::from_secret(secret).unwrap();
395 assert_eq!(keypair.public_key().as_str(), expected_public_key);
396 assert_eq!(keypair.secret_key().unwrap().as_str(), secret);
397 }
398
399 #[test]
400 #[should_panic]
401 fn test_create_keypair_from_invalid_secret() {
402 let invalid_secrets = [
403 "hel0",
404 "SBWUBZ3SIPLLF5CCXLWUB2Z6UBTYAW34KVXOLRQ5HDAZG4ZY7MHNBWJ1",
405 "masterpassphrasemasterpassphrase",
406 "gsYRSEQhTffqA9opPepAENCr2WG6z5iBHHubxxbRzWaHf8FBWcu",
407 ];
408 Keypair::from_secret(invalid_secrets[0]).unwrap();
409 Keypair::from_secret(invalid_secrets[1]).unwrap();
410 Keypair::from_secret(invalid_secrets[2]).unwrap();
411 Keypair::from_secret(invalid_secrets[3]).unwrap();
412 }
413
414 #[test]
415 fn test_create_keypair_from_raw_ed25519_seed() {
416 let seed = "masterpassphrasemasterpassphrase";
417 let expected_public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH";
418 let expected_secret = "SBWWC43UMVZHAYLTONYGQ4TBONSW2YLTORSXE4DBONZXA2DSMFZWLP2R";
419 let expected_raw_public_key =
420 hex!("2e3c35010749c1de3d9a5bdd6a31c12458768da5ce87cca6aad63ebbaaef7432");
421 let keypair = Keypair::from_raw_ed25519_seed(seed.as_bytes()).unwrap();
422
423 assert_eq!(keypair.public_key(), expected_public_key);
424 assert_eq!(keypair.secret_key().unwrap().as_str(), expected_secret);
425 assert_eq!(keypair.raw_public_key().as_slice(), expected_raw_public_key);
426 }
427
428 #[test]
429 fn test_create_keypair_invalid_raw_ed25519_seed() {
430 Keypair::from_raw_ed25519_seed(b"masterpassphrasemasterpassphras").is_err();
431 Keypair::from_raw_ed25519_seed(b"masterpassphrasemasterpassphrase1").is_err();
432 Keypair::from_raw_ed25519_seed(b"").is_err();
433 Keypair::from_raw_ed25519_seed(b"\0").is_err();
434 }
435
436 #[test]
437 fn test_create_keypair_from_public_key() {
438 let public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH";
439 let expected_public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH";
440 let expected_raw_public_key =
441 hex!("2e3c35010749c1de3d9a5bdd6a31c12458768da5ce87cca6aad63ebbaaef7432");
442
443 let keypair = Keypair::from_public_key(public_key).unwrap();
444
445 assert_eq!(keypair.public_key().as_str(), expected_public_key);
446 assert_eq!(keypair.raw_public_key().as_slice(), expected_raw_public_key);
447 }
448
449 #[test]
450 fn test_create_keypair_from_invalid_public_key() {
451 let invalid_public_keys = [
452 "hel0",
453 "masterpassphrasemasterpassphrase",
454 "sfyjodTxbwLtRToZvi6yQ1KnpZriwTJ7n6nrASFR6goRviCU3Ff",
455 ];
456
457 Keypair::from_public_key(invalid_public_keys[0]).is_err();
458 Keypair::from_public_key(invalid_public_keys[1]).is_err();
459 Keypair::from_public_key(invalid_public_keys[2]).is_err();
460 }
461
462 #[test]
463 fn test_create_random_keypair() {
464 let keypair = Keypair::random().unwrap();
465 }
466
467 #[test]
468 fn test_xdr_muxed_account_with_ed25519_key_type() {
469 let public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH";
470 let keypair = Keypair::from_public_key(public_key).unwrap();
471 let muxed = keypair.xdr_muxed_account_id("1");
472 }
473
474 #[test]
475 fn test_sign_decorated() {
476 let the_secret = "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36";
477 let kp = Keypair::from_secret(the_secret).unwrap();
478 let message = "test post please ignore".as_bytes();
479 let sign: xdr::DecoratedSignature = kp.sign_decorated(message);
480 assert_eq!(sign.hint.0.to_vec(), vec![0x0B, 0xFA, 0xD1, 0x34]);
481 }
482}