stellar_base/crypto/dalek/
keypair.rs

1use 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/// The secret key of the account.
10#[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    /// Return the inner keypair.
29    pub fn inner(&self) -> &ed25519_dalek::SigningKey {
30        &self.signing_key
31    }
32
33    /// Return the secret key as String, starting with `S`.
34    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    /// Create the key pair from the secret seed, e.g. `SDAKFNYEIAORZKKCYRILFQKLLOCNPL5SWJ3YY5NM3ZH6GJSZGXHZEPQS`.
47    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    /// Create a random key pair.
53    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    /// Create a key pair from the `network` passphrase.
63    pub fn from_network(network: &Network) -> Result<DalekKeyPair> {
64        let bytes = network.network_id();
65        Self::from_seed_bytes(&bytes)
66    }
67
68    /// Create a key pair from raw bytes.
69    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    /// Return the secret key.
79    pub fn secret_key(&self) -> &SecretKey {
80        &self.0.signer.signing_key
81    }
82
83    /// Return the public key
84    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}