substrate_stellar_sdk/
secret_key.rs

1//! Ed25519 keypairs and public keys
2
3use core::convert::{AsRef, TryInto};
4use sp_std::{prelude::*, vec, vec::Vec};
5
6use crate::StellarSdkError;
7
8use sodalite::{
9    sign_attached, sign_keypair_seed, SignPublicKey, SignSecretKey, SIGN_LEN, SIGN_PUBLIC_KEY_LEN, SIGN_SECRET_KEY_LEN,
10};
11
12use crate::{
13    types::{Curve25519Secret, PublicKey},
14    utils::key_encoding::{
15        decode_stellar_key, encode_stellar_key, ED25519_SECRET_SEED_BYTE_LENGTH, ED25519_SECRET_SEED_VERSION_BYTE,
16    },
17};
18
19pub use sodalite::Sign as Signature;
20
21pub trait IntoSecretKey {
22    fn into_secret_key(self) -> Result<SecretKey, StellarSdkError>;
23}
24
25impl IntoSecretKey for SecretKey {
26    fn into_secret_key(self) -> Result<SecretKey, StellarSdkError> {
27        Ok(self)
28    }
29}
30
31impl<T: AsRef<[u8]>> IntoSecretKey for T {
32    fn into_secret_key(self) -> Result<SecretKey, StellarSdkError> {
33        SecretKey::from_encoding(self)
34    }
35}
36
37/// An Ed25519 signing keypair
38///
39/// This type is used for signing Stellar transactions.
40/// ```
41/// let secret = "SCDSVACTNFNSD5LQZ5LWUWEY3UIAML2J7ALPFCD6ZX4D3TVJV7X243N3";
42/// let public = "GBIVKYSF6RP4U57KPZ524X47NGTQYYPZAZ4UX5ZFYAYBJWRFXHKHDQVL";
43/// let secret_key = substrate_stellar_sdk::SecretKey::from_encoding(secret);
44/// assert!(secret_key.is_ok());
45/// let secret_key = secret_key.unwrap();
46/// assert_eq!(&secret_key.to_encoding().as_slice(), &secret.as_bytes());
47/// assert_eq!(&secret_key.get_encoded_public().as_slice(), &public.as_bytes());
48/// ```
49#[derive(Clone, Eq, PartialEq, Debug)]
50pub struct SecretKey {
51    // the use of `signer_key` and `secret_seed` is quite confusing
52    // `signer_key` (512 bit) is what tweetnacl calls the signing secret key
53    // `secret_seed` (256 bit) is what Stellar calls the secret key
54    // we always have: signer_key = [..secret_seed, ..public] (in JS notation)
55    public: PublicKey,
56    secret_seed: Curve25519Secret,
57    signer_key: SignSecretKey,
58}
59
60impl SecretKey {
61    /// Generate a new keypair from a raw binary secret seed
62    pub fn from_binary(seed: [u8; ED25519_SECRET_SEED_BYTE_LENGTH]) -> SecretKey {
63        let mut public_key: SignPublicKey = [0; SIGN_PUBLIC_KEY_LEN];
64        let mut secret_key: SignSecretKey = [0; SIGN_SECRET_KEY_LEN];
65
66        sign_keypair_seed(&mut public_key, &mut secret_key, &seed);
67
68        SecretKey {
69            public: PublicKey::from_binary(public_key),
70            secret_seed: Curve25519Secret { key: seed },
71            signer_key: secret_key,
72        }
73    }
74
75    /// Return the raw binary key as a reference
76    pub fn as_binary(&self) -> &[u8; ED25519_SECRET_SEED_BYTE_LENGTH] {
77        &self.secret_seed.key
78    }
79
80    /// Turn into the raw binary key
81    pub fn into_binary(self) -> [u8; ED25519_SECRET_SEED_BYTE_LENGTH] {
82        *self.as_binary()
83    }
84
85    pub fn from_encoding<T: AsRef<[u8]>>(encoded_key: T) -> Result<Self, StellarSdkError> {
86        let decoded_key = decode_stellar_key(encoded_key, ED25519_SECRET_SEED_VERSION_BYTE)?;
87        Ok(Self::from_binary(decoded_key))
88    }
89
90    /// Return the key encoding as an ASCII string (given as `Vec<u8>`)
91    pub fn to_encoding(&self) -> Vec<u8> {
92        let key = self.as_binary();
93        encode_stellar_key(key, ED25519_SECRET_SEED_VERSION_BYTE)
94    }
95
96    /// Return the encoded public key
97    pub fn get_encoded_public(&self) -> Vec<u8> {
98        self.public.to_encoding()
99    }
100
101    /// Return the public key of the keypair as a `PublicKey`
102    pub fn get_public(&self) -> &PublicKey {
103        &self.public
104    }
105
106    /// Create a signature for the `message`
107    pub fn create_signature<T: AsRef<[u8]>>(&self, message: T) -> Signature {
108        let message = message.as_ref();
109        let mut signed_message: Vec<u8> = vec![0; message.len() + SIGN_LEN];
110        sign_attached(&mut signed_message[..], message, &self.signer_key);
111
112        signed_message.truncate(SIGN_LEN);
113        signed_message.try_into().unwrap()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use crate::secret_key::{PublicKey, SecretKey};
120
121    #[test]
122    fn keypair() {
123        let secret = "SCDSVACTNFNSD5LQZ5LWUWEY3UIAML2J7ALPFCD6ZX4D3TVJV7X243N3";
124        let public = "GBIVKYSF6RP4U57KPZ524X47NGTQYYPZAZ4UX5ZFYAYBJWRFXHKHDQVL";
125        let keypair = SecretKey::from_encoding(secret);
126        assert!(keypair.is_ok());
127        let keypair = keypair.unwrap();
128        assert_eq!(&keypair.to_encoding().as_slice(), &secret.as_bytes());
129        assert_eq!(&keypair.get_encoded_public().as_slice(), &public.as_bytes());
130    }
131
132    #[test]
133    fn public_key() {
134        let public = "GBIVKYSF6RP4U57KPZ524X47NGTQYYPZAZ4UX5ZFYAYBJWRFXHKHDQVL";
135        let public_key = PublicKey::from_encoding(public);
136        assert!(public_key.is_ok());
137        let public_key = public_key.unwrap();
138        assert_eq!(&public_key.to_encoding().as_slice(), &public.as_bytes());
139    }
140}