multiversx_sdk/crypto/
private_key.rs

1use std::fmt::Display;
2
3use super::edwards25519::{sc_mul_add, sc_reduce};
4use crate::crypto::edwards25519::extended_group_element::ExtendedGroupElement;
5use anyhow::{Result, anyhow};
6use serde::{
7    de::{Deserialize, Deserializer},
8    ser::{Serialize, Serializer},
9};
10use sha2::{Digest, Sha512};
11
12pub const PRIVATE_KEY_LENGTH: usize = 64;
13pub const SIGNATURE_LENGTH: usize = 64;
14pub const SEED_LENGTH: usize = 32;
15
16#[derive(Copy, Clone, Debug)]
17pub struct PrivateKey(pub [u8; PRIVATE_KEY_LENGTH]);
18
19impl PrivateKey {
20    pub fn from_bytes(bytes: &[u8]) -> Result<PrivateKey> {
21        match bytes.len() {
22            SEED_LENGTH => {
23                let mut h: Sha512 = Sha512::new();
24                let mut hash: [u8; 64] = [0u8; 64];
25                let mut digest: [u8; 32] = [0u8; 32];
26
27                h.update(bytes);
28                hash.copy_from_slice(h.finalize().as_ref());
29
30                digest.copy_from_slice(&hash[..32]);
31
32                digest[0] &= 248;
33                digest[31] &= 127;
34                digest[31] |= 64;
35
36                let mut a = ExtendedGroupElement::default();
37                a.ge_scalar_mult_base(digest);
38                let public_key_bytes = a.to_bytes();
39
40                let merge: Vec<u8> = [bytes.to_vec(), public_key_bytes.to_vec()]
41                    .concat()
42                    .into_iter()
43                    .collect();
44                let mut bits: [u8; 64] = [0u8; 64];
45                bits.copy_from_slice(&merge[..64]);
46
47                Ok(PrivateKey(bits))
48            }
49            PRIVATE_KEY_LENGTH => {
50                let mut bits: [u8; 64] = [0u8; 64];
51                bits.copy_from_slice(&bytes[..64]);
52
53                Ok(PrivateKey(bits))
54            }
55            _ => Err(anyhow!("Invalid secret key length")),
56        }
57    }
58
59    pub fn from_hex_str(pk: &str) -> Result<Self> {
60        let bytes = hex::decode(pk)?;
61        PrivateKey::from_bytes(bytes.as_slice())
62    }
63
64    /// Currently not in use.
65    ///
66    /// Guarded by feature "wallet-full", to avoid unnecessarily importing `rand`.
67    #[cfg(feature = "wallet-full")]
68    pub fn generate<T>(r: &mut T) -> PrivateKey
69    where
70        T: rand::CryptoRng + rand::RngCore,
71    {
72        let mut secret_key = PrivateKey([0u8; 64]);
73
74        r.fill_bytes(&mut secret_key.0);
75
76        secret_key
77    }
78
79    pub fn to_bytes(&self) -> [u8; PRIVATE_KEY_LENGTH] {
80        self.0
81    }
82
83    pub fn as_bytes(&self) -> &[u8; PRIVATE_KEY_LENGTH] {
84        &self.0
85    }
86
87    pub fn sign(&self, message: Vec<u8>) -> [u8; 64] {
88        let mut h: Sha512 = Sha512::new();
89        h.update(&self.0[..32]);
90
91        let mut digest1 = [0u8; 64];
92        let mut message_digest = [0u8; 64];
93        let mut hram_digest = [0u8; 64];
94        let mut expanded_secret_key = [0u8; 32];
95
96        digest1.copy_from_slice(h.finalize_reset().as_ref());
97        expanded_secret_key.copy_from_slice(&digest1[..32]);
98        expanded_secret_key[0] &= 248;
99        expanded_secret_key[31] &= 63;
100        expanded_secret_key[31] |= 64;
101
102        h.update(&digest1[32..]);
103        h.update(&message);
104        message_digest.copy_from_slice(h.finalize_reset().as_ref());
105
106        let message_digest_reduced = sc_reduce(message_digest);
107        let mut r = ExtendedGroupElement::default();
108        r.ge_scalar_mult_base(message_digest_reduced);
109
110        let encoded_r = r.to_bytes();
111
112        h.update(encoded_r);
113        h.update(&self.0[32..]);
114        h.update(&message);
115        hram_digest.copy_from_slice(h.finalize_reset().as_ref());
116
117        let hram_digest_reduced = sc_reduce(hram_digest);
118
119        let s = sc_mul_add(
120            hram_digest_reduced,
121            expanded_secret_key,
122            message_digest_reduced,
123        );
124
125        let mut signature = [0u8; 64];
126
127        signature[..32].copy_from_slice(&encoded_r);
128        signature[32..].copy_from_slice(&s);
129
130        signature
131    }
132}
133
134impl Display for PrivateKey {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        hex::encode(&self.0[..32]).fmt(f)
137    }
138}
139
140impl Serialize for PrivateKey {
141    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
142    where
143        S: Serializer,
144    {
145        serializer.serialize_str(self.to_string().as_str())
146    }
147}
148
149impl<'de> Deserialize<'de> for PrivateKey {
150    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
151    where
152        D: Deserializer<'de>,
153    {
154        let s = String::deserialize(deserializer)?;
155        Ok(Self::from_hex_str(s.as_str()).unwrap())
156    }
157}