iota_sdk/client/secret/
private_key.rs

1// Copyright 2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! Implementation of [`PrivateKeySecretManager`].
5
6use std::ops::Range;
7
8use async_trait::async_trait;
9use crypto::{
10    hashes::{blake2b::Blake2b256, Digest},
11    keys::bip44::Bip44,
12    signatures::{
13        ed25519,
14        secp256k1_ecdsa::{self, EvmAddress},
15    },
16};
17use zeroize::{Zeroize, Zeroizing};
18
19use super::{GenerateAddressOptions, SecretManage};
20use crate::{
21    client::{api::PreparedTransactionData, Error},
22    types::block::{
23        address::Ed25519Address, payload::transaction::TransactionPayload, signature::Ed25519Signature, unlock::Unlocks,
24    },
25};
26
27/// Secret manager based on a single private key.
28pub struct PrivateKeySecretManager(ed25519::SecretKey);
29
30impl std::fmt::Debug for PrivateKeySecretManager {
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        f.debug_tuple("PrivateKeySecretManager").finish()
33    }
34}
35
36#[async_trait]
37impl SecretManage for PrivateKeySecretManager {
38    type Error = Error;
39
40    async fn generate_ed25519_addresses(
41        &self,
42        _coin_type: u32,
43        _account_index: u32,
44        _address_indexes: Range<u32>,
45        _options: impl Into<Option<GenerateAddressOptions>> + Send,
46    ) -> Result<Vec<Ed25519Address>, Self::Error> {
47        let public_key = self.0.public_key().to_bytes();
48
49        // Hash the public key to get the address
50        let result = Blake2b256::digest(public_key).into();
51
52        crate::client::Result::Ok(vec![Ed25519Address::new(result)])
53    }
54
55    async fn generate_evm_addresses(
56        &self,
57        _coin_type: u32,
58        _account_index: u32,
59        _address_indexes: Range<u32>,
60        _options: impl Into<Option<GenerateAddressOptions>> + Send,
61    ) -> Result<Vec<EvmAddress>, Self::Error> {
62        // TODO replace with a more fitting variant.
63        Err(Error::SecretManagerMismatch)
64    }
65
66    async fn sign_ed25519(&self, msg: &[u8], _chain: Bip44) -> Result<Ed25519Signature, Self::Error> {
67        let public_key = self.0.public_key();
68        let signature = self.0.sign(msg);
69
70        Ok(Ed25519Signature::new(public_key, signature))
71    }
72
73    async fn sign_secp256k1_ecdsa(
74        &self,
75        _msg: &[u8],
76        _chain: Bip44,
77    ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> {
78        // TODO replace with a more fitting variant.
79        Err(Error::SecretManagerMismatch)
80    }
81
82    async fn sign_transaction_essence(
83        &self,
84        prepared_transaction_data: &PreparedTransactionData,
85        time: Option<u32>,
86    ) -> Result<Unlocks, Self::Error> {
87        super::default_sign_transaction_essence(self, prepared_transaction_data, time).await
88    }
89
90    async fn sign_transaction(
91        &self,
92        prepared_transaction_data: PreparedTransactionData,
93    ) -> Result<TransactionPayload, Self::Error> {
94        super::default_sign_transaction(self, prepared_transaction_data).await
95    }
96}
97
98impl PrivateKeySecretManager {
99    /// Create a new [`PrivateKeySecretManager`] from a base 58 encoded private key.
100    pub fn try_from_b58<T: AsRef<[u8]>>(b58: T) -> Result<Self, Error> {
101        let mut bytes = [0u8; ed25519::SecretKey::LENGTH];
102
103        // TODO replace with a more fitting variant.
104        if bs58::decode(b58.as_ref())
105            .onto(&mut bytes)
106            .map_err(|_| crypto::Error::PrivateKeyError)?
107            != ed25519::SecretKey::LENGTH
108        {
109            // TODO replace with a more fitting variant.
110            return Err(crypto::Error::PrivateKeyError.into());
111        }
112
113        let private_key = Self(ed25519::SecretKey::from_bytes(&bytes));
114
115        bytes.zeroize();
116
117        Ok(private_key)
118    }
119
120    /// Create a new [`PrivateKeySecretManager`] from an hex encoded private key.
121    pub fn try_from_hex(hex: impl Into<Zeroizing<String>>) -> Result<Self, Error> {
122        let mut bytes = prefix_hex::decode(hex.into())?;
123
124        let private_key = Self(ed25519::SecretKey::from_bytes(&bytes));
125
126        bytes.zeroize();
127
128        Ok(private_key)
129    }
130}