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