1use crate::BSVErrors;
2use crate::ECIESCiphertext;
3use crate::ECDSA;
4use crate::ECIES;
5use crate::{Hash, PublicKey, SigningHash};
6use crate::{Signature, ToHex};
7use elliptic_curve::sec1::ToEncodedPoint;
8use k256::SecretKey;
9use rand_core::OsRng;
10#[cfg(target_arch = "wasm32")]
11use wasm_bindgen::prelude::*;
12#[cfg(target_arch = "wasm32")]
13use wasm_bindgen::throw_str;
14
15#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen)]
16#[derive(Debug, Clone)]
17pub struct PrivateKey {
18 pub(crate) secret_key: SecretKey,
19 pub(crate) is_pub_key_compressed: bool,
20}
21
22impl PrivateKey {
26 pub(crate) fn sign_message_impl(&self, msg: &[u8]) -> Result<Signature, BSVErrors> {
30 ECDSA::sign_with_deterministic_k_impl(self, msg, SigningHash::Sha256, false)
31 }
32
33 pub(crate) fn to_wif_impl(&self) -> Result<String, BSVErrors> {
34 let priv_key_hex = self.to_hex();
36
37 let padded_hex = match self.is_pub_key_compressed {
40 true => format!("80{}01", priv_key_hex),
41 false => format!("80{}", priv_key_hex),
42 };
43
44 let bytes = hex::decode(padded_hex.clone())?;
46
47 let shad_hex = Hash::sha_256d(&bytes).to_bytes();
48
49 let checksum = shad_hex.to_vec()[0..4].to_hex();
51
52 let extended_key = format!("{}{}", padded_hex, checksum);
54
55 let extended_key_bytes = hex::decode(extended_key)?;
57
58 Ok(bs58::encode(extended_key_bytes).into_string())
59 }
60
61 pub(crate) fn from_bytes_impl(bytes: &[u8]) -> Result<PrivateKey, BSVErrors> {
62 let secret_key = SecretKey::from_be_bytes(bytes)?;
63
64 Ok(PrivateKey {
65 secret_key,
66 is_pub_key_compressed: true,
67 })
68 }
69
70 pub(crate) fn from_hex_impl(hex_str: &str) -> Result<PrivateKey, BSVErrors> {
71 let bytes = hex::decode(hex_str)?;
72
73 Self::from_bytes_impl(&bytes)
74 }
75
76 pub(crate) fn from_wif_impl(wif_string: &str) -> Result<PrivateKey, BSVErrors> {
77 let wif_bytes = bs58::decode(wif_string).into_vec()?;
79 let wif_without_checksum = wif_bytes[0..wif_bytes.len() - 4].to_vec();
80
81 let checksum = wif_bytes[wif_bytes.len() - 4..].to_hex();
83 let check_hash = Hash::sha_256d(&wif_without_checksum).to_bytes();
84 let check_string = check_hash.to_vec()[0..4].to_hex();
85
86 if check_string.ne(&checksum) {
87 return Err(BSVErrors::FromWIF("Checksum does not match!".into()));
88 }
89
90 fn is_compressed(unchecksum: &[u8]) -> bool {
92 if unchecksum.len() < 34 {
93 return false;
94 }
95
96 match unchecksum.last() {
97 Some(last_byte) => last_byte.eq(&1),
98 None => false,
99 }
100 }
101
102 let is_compressed_pub_key = is_compressed(&wif_without_checksum);
103 let private_key_hex = match is_compressed_pub_key {
105 true => wif_without_checksum[1..wif_without_checksum.len() - 1].to_hex(),
106 false => wif_without_checksum[1..].to_hex(),
107 };
108
109 Ok(PrivateKey::from_hex_impl(&private_key_hex)?.compress_public_key(is_compressed_pub_key))
110 }
111
112 pub(crate) fn to_public_key_impl(&self) -> Result<PublicKey, BSVErrors> {
113 let pub_key = PublicKey::from_private_key_impl(self);
114
115 if !self.is_pub_key_compressed {
116 return pub_key.to_decompressed_impl();
117 }
118
119 Ok(pub_key)
120 }
121
122 pub(crate) fn encrypt_message_impl(&self, message: &[u8]) -> Result<ECIESCiphertext, BSVErrors> {
126 ECIES::encrypt_impl(message, self, &self.to_public_key_impl()?, false)
127 }
128
129 pub(crate) fn decrypt_message_impl(&self, ciphertext: &ECIESCiphertext, sender_pub_key: &PublicKey) -> Result<Vec<u8>, BSVErrors> {
133 ECIES::decrypt_impl(ciphertext, self, sender_pub_key)
134 }
135}
136
137#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen)]
138impl PrivateKey {
139 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = toBytes))]
140 pub fn to_bytes(&self) -> Vec<u8> {
141 self.secret_key.to_be_bytes().to_vec()
142 }
143
144 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = toHex))]
145 pub fn to_hex(&self) -> String {
146 let secret_key_bytes = self.to_bytes();
147 hex::encode(secret_key_bytes)
148 }
149
150 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = fromRandom))]
151 pub fn from_random() -> PrivateKey {
152 let secret_key = k256::SecretKey::random(&mut OsRng);
153
154 PrivateKey {
155 secret_key,
156 is_pub_key_compressed: true,
157 }
158 }
159
160 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getPoint))]
161 pub fn get_point(&self) -> Vec<u8> {
165 self.secret_key.public_key().as_affine().to_encoded_point(self.is_pub_key_compressed).as_bytes().into()
166 }
167
168 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = compressPublicKey))]
169 pub fn compress_public_key(&self, should_compress: bool) -> PrivateKey {
170 let mut priv_key = self.clone();
171 priv_key.is_pub_key_compressed = should_compress;
172 priv_key
173 }
174}
175
176#[cfg(target_arch = "wasm32")]
180#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen)]
181impl PrivateKey {
182 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = fromWIF))]
183 pub fn from_wif(wif_string: &str) -> Result<PrivateKey, JsValue> {
184 match PrivateKey::from_wif_impl(wif_string) {
185 Ok(v) => Ok(v),
186 Err(e) => Err(JsValue::from_str(&e.to_string())),
187 }
188 }
189
190 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = fromHex))]
191 pub fn from_hex(hex_str: &str) -> Result<PrivateKey, JsValue> {
192 match PrivateKey::from_hex_impl(hex_str) {
193 Ok(v) => Ok(v),
194 Err(e) => Err(JsValue::from_str(&e.to_string())),
195 }
196 }
197
198 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = signMessage))]
199 pub fn sign_message(&self, msg: &[u8]) -> Result<Signature, JsValue> {
203 match PrivateKey::sign_message_impl(&self, msg) {
204 Ok(v) => Ok(v),
205 Err(e) => Err(JsValue::from_str(&e.to_string())),
206 }
207 }
208
209 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = toWIF))]
210 pub fn to_wif(&self) -> Result<String, JsValue> {
211 match PrivateKey::to_wif_impl(&self) {
212 Ok(v) => Ok(v),
213 Err(e) => Err(JsValue::from_str(&e.to_string())),
214 }
215 }
216
217 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = fromBytes))]
218 pub fn from_bytes(bytes: &[u8]) -> Result<PrivateKey, JsValue> {
219 match Self::from_bytes_impl(bytes) {
220 Ok(v) => Ok(v),
221 Err(e) => Err(JsValue::from_str(&e.to_string())),
222 }
223 }
224
225 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = toPublicKey))]
226 pub fn to_public_key(&self) -> Result<PublicKey, JsValue> {
227 match self.to_public_key_impl() {
228 Ok(v) => Ok(v),
229 Err(e) => Err(JsValue::from_str(&e.to_string())),
230 }
231 }
232
233 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = encryptMessage))]
237 pub fn encrypt_message(&self, message: &[u8]) -> Result<ECIESCiphertext, JsValue> {
238 match self.encrypt_message_impl(message) {
239 Ok(v) => Ok(v),
240 Err(e) => Err(JsValue::from_str(&e.to_string())),
241 }
242 }
243
244 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = decryptMessage))]
248 pub fn decrypt_message(&self, ciphertext: &ECIESCiphertext, sender_pub_key: &PublicKey) -> Result<Vec<u8>, JsValue> {
249 match self.decrypt_message_impl(ciphertext, sender_pub_key) {
250 Ok(v) => Ok(v),
251 Err(e) => Err(JsValue::from_str(&e.to_string())),
252 }
253 }
254}
255
256#[cfg(not(target_arch = "wasm32"))]
260impl PrivateKey {
261 pub fn to_wif(&self) -> Result<String, BSVErrors> {
262 PrivateKey::to_wif_impl(self)
263 }
264
265 pub fn from_wif(wif_string: &str) -> Result<PrivateKey, BSVErrors> {
266 PrivateKey::from_wif_impl(wif_string)
267 }
268
269 pub fn from_hex(hex_str: &str) -> Result<PrivateKey, BSVErrors> {
270 PrivateKey::from_hex_impl(hex_str)
271 }
272
273 pub fn sign_message(&self, msg: &[u8]) -> Result<Signature, BSVErrors> {
277 PrivateKey::sign_message_impl(self, msg)
278 }
279
280 pub fn from_bytes(bytes: &[u8]) -> Result<PrivateKey, BSVErrors> {
281 Self::from_bytes_impl(bytes)
282 }
283
284 pub fn to_public_key(&self) -> Result<PublicKey, BSVErrors> {
285 self.to_public_key_impl()
286 }
287
288 pub fn encrypt_message(&self, message: &[u8]) -> Result<ECIESCiphertext, BSVErrors> {
292 self.encrypt_message_impl(message)
293 }
294
295 pub fn decrypt_message(&self, ciphertext: &ECIESCiphertext, sender_pub_key: &PublicKey) -> Result<Vec<u8>, BSVErrors> {
299 self.decrypt_message_impl(ciphertext, sender_pub_key)
300 }
301}