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::{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}