multiversx_sdk/crypto/
private_key.rs1use 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 #[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}