rosetta_client/
signer.rs

1use crate::crypto::{
2    address::Address,
3    bip32::{DerivedPublicKey, DerivedSecretKey},
4    bip39::Mnemonic,
5    bip44::ChildNumber,
6    Algorithm,
7};
8use crate::types::{AccountIdentifier, CurveType, PublicKey};
9use anyhow::Result;
10
11/// Signer derives keys from a mnemonic.
12pub struct Signer {
13    secp256k1: DerivedSecretKey,
14    secp256k1_recoverable: DerivedSecretKey,
15    secp256r1: DerivedSecretKey,
16    ed25519: DerivedSecretKey,
17    sr25519: DerivedSecretKey,
18}
19
20impl Signer {
21    /// Creates a new signer from a mnemonic and password.
22    pub fn new(mnemonic: &Mnemonic, password: &str) -> Result<Self> {
23        let secp256k1 = DerivedSecretKey::new(mnemonic, password, Algorithm::EcdsaSecp256k1)?;
24        let secp256k1_recoverable =
25            DerivedSecretKey::new(mnemonic, password, Algorithm::EcdsaRecoverableSecp256k1)?;
26        let secp256r1 = DerivedSecretKey::new(mnemonic, password, Algorithm::EcdsaSecp256r1)?;
27        let ed25519 = DerivedSecretKey::new(mnemonic, password, Algorithm::Ed25519)?;
28        let sr25519 = DerivedSecretKey::new(mnemonic, password, Algorithm::Sr25519)?;
29        Ok(Self {
30            secp256k1,
31            secp256k1_recoverable,
32            secp256r1,
33            ed25519,
34            sr25519,
35        })
36    }
37
38    /// Creates a new ephemeral signer.
39    pub fn generate() -> Result<Self> {
40        let mnemonic = crate::mnemonic::generate_mnemonic()?;
41        Self::new(&mnemonic, "")
42    }
43
44    /// Derives a master key from a mnemonic.
45    pub fn master_key(&self, algorithm: Algorithm) -> Result<&DerivedSecretKey> {
46        Ok(match algorithm {
47            Algorithm::EcdsaSecp256k1 => &self.secp256k1,
48            Algorithm::EcdsaRecoverableSecp256k1 => &self.secp256k1_recoverable,
49            Algorithm::EcdsaSecp256r1 => &self.secp256r1,
50            Algorithm::Ed25519 => &self.ed25519,
51            Algorithm::Sr25519 => &self.sr25519,
52        })
53    }
54
55    /// Derives a bip44 key from a mnemonic.
56    pub fn bip44_account(
57        &self,
58        algorithm: Algorithm,
59        coin: u32,
60        account: u32,
61    ) -> Result<DerivedSecretKey> {
62        self.master_key(algorithm)?
63            .derive(ChildNumber::hardened_from_u32(44))?
64            .derive(ChildNumber::hardened_from_u32(coin))?
65            .derive(ChildNumber::hardened_from_u32(account))?
66            .derive(ChildNumber::non_hardened_from_u32(0))
67    }
68}
69
70/// Conversion trait for public keys.
71pub trait RosettaPublicKey {
72    /// Returns a rosetta public key.
73    fn to_rosetta(&self) -> PublicKey;
74}
75
76impl RosettaPublicKey for DerivedPublicKey {
77    fn to_rosetta(&self) -> PublicKey {
78        PublicKey {
79            curve_type: match self.public_key().algorithm() {
80                Algorithm::EcdsaSecp256k1 => CurveType::Secp256k1,
81                Algorithm::EcdsaRecoverableSecp256k1 => CurveType::Secp256k1,
82                Algorithm::EcdsaSecp256r1 => CurveType::Secp256r1,
83                Algorithm::Ed25519 => CurveType::Edwards25519,
84                Algorithm::Sr25519 => CurveType::Schnorrkel,
85            },
86            hex_bytes: hex::encode(self.public_key().to_bytes()),
87        }
88    }
89}
90
91/// Conversion trait for account identifiers.
92pub trait RosettaAccount {
93    /// Returns a rosetta account identifier.
94    fn to_rosetta(&self) -> AccountIdentifier;
95}
96
97impl RosettaAccount for Address {
98    fn to_rosetta(&self) -> AccountIdentifier {
99        AccountIdentifier {
100            address: self.address().into(),
101            sub_account: None,
102            metadata: None,
103        }
104    }
105}