1use crate::identity::identity_public_key::methods::hash::IdentityPublicKeyHashMethodsV0;
2use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
3use crate::identity::KeyType;
4use crate::util::hash::ripemd160_sha256;
5use crate::ProtocolError;
6use anyhow::anyhow;
7#[cfg(feature = "ed25519-dalek")]
8use dashcore::ed25519_dalek;
9use dashcore::hashes::Hash;
10use dashcore::key::Secp256k1;
11use dashcore::secp256k1::SecretKey;
12use dashcore::{Network, PublicKey as ECDSAPublicKey};
13use platform_value::{BinaryData, Bytes20};
14#[cfg(feature = "bls-signatures")]
15use {crate::bls_signatures, dashcore::blsful::Bls12381G2Impl};
16impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKeyV0 {
17 fn public_key_hash(&self) -> Result<[u8; 20], ProtocolError> {
19 public_key_hash_for_key_data(self.key_type, &self.data)
20 }
21
22 fn validate_private_key_bytes(
23 &self,
24 private_key_bytes: &[u8; 32],
25 network: Network,
26 ) -> Result<bool, ProtocolError> {
27 validate_private_key_bytes_for_key_data(
28 self.key_type,
29 &self.data,
30 private_key_bytes,
31 network,
32 )
33 }
34}
35
36pub(in crate::identity::identity_public_key) fn public_key_hash_for_key_data(
38 key_type: KeyType,
39 data: &BinaryData,
40) -> Result<[u8; 20], ProtocolError> {
41 if data.is_empty() {
42 return Err(ProtocolError::EmptyPublicKeyDataError);
43 }
44
45 match key_type {
46 KeyType::ECDSA_SECP256K1 => {
47 let key = match data.len() {
48 65 | 33 => ECDSAPublicKey::from_slice(data.as_slice())
50 .map_err(|e| anyhow!("unable to create pub key - {}", e))?,
51 _ => {
52 return Err(ProtocolError::ParsingError(format!(
53 "the key length is invalid: {} Allowed sizes: 33 or 65 bytes for ecdsa key",
54 data.len()
55 )));
56 }
57 };
58 Ok(key.pubkey_hash().to_byte_array())
59 }
60 KeyType::BLS12_381 => {
61 if data.len() != 48 {
62 Err(ProtocolError::ParsingError(format!(
63 "the key length is invalid: {} Allowed sizes: 48 bytes for bls key",
64 data.len()
65 )))
66 } else {
67 Ok(ripemd160_sha256(data.as_slice()))
68 }
69 }
70 KeyType::ECDSA_HASH160 | KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => {
71 Ok(Bytes20::from_vec(data.to_vec())?.into_buffer())
72 }
73 }
74}
75
76pub(in crate::identity::identity_public_key) fn validate_private_key_bytes_for_key_data(
79 key_type: KeyType,
80 data: &BinaryData,
81 private_key_bytes: &[u8; 32],
82 network: Network,
83) -> Result<bool, ProtocolError> {
84 match key_type {
85 KeyType::ECDSA_SECP256K1 => {
86 let secp = Secp256k1::new();
87 let secret_key = match SecretKey::from_byte_array(private_key_bytes) {
88 Ok(secret_key) => secret_key,
89 Err(_) => return Ok(false),
90 };
91 let private_key = dashcore::PrivateKey::new(secret_key, network);
92
93 Ok(private_key.public_key(&secp).to_bytes() == data.as_slice())
94 }
95 KeyType::BLS12_381 => {
96 #[cfg(feature = "bls-signatures")]
97 {
98 let private_key: Option<bls_signatures::SecretKey<Bls12381G2Impl>> =
99 bls_signatures::SecretKey::<Bls12381G2Impl>::from_be_bytes(private_key_bytes)
100 .into();
101 if private_key.is_none() {
102 return Ok(false);
103 }
104 let private_key = private_key.expect("expected private key");
105
106 Ok(private_key.public_key().0.to_compressed() == data.as_slice())
107 }
108 #[cfg(not(feature = "bls-signatures"))]
109 return Err(ProtocolError::NotSupported(
110 "Converting a private key to a bls public key is not supported without the bls-signatures feature".to_string(),
111 ));
112 }
113 KeyType::ECDSA_HASH160 => {
114 let secp = Secp256k1::new();
115 let secret_key = match SecretKey::from_byte_array(private_key_bytes) {
116 Ok(secret_key) => secret_key,
117 Err(_) => return Ok(false),
118 };
119 let private_key = dashcore::PrivateKey::new(secret_key, network);
120
121 Ok(
122 ripemd160_sha256(private_key.public_key(&secp).to_bytes().as_slice()).as_slice()
123 == data.as_slice(),
124 )
125 }
126 KeyType::EDDSA_25519_HASH160 => {
127 #[cfg(feature = "ed25519-dalek")]
128 {
129 let key_pair = ed25519_dalek::SigningKey::from_bytes(private_key_bytes);
130 Ok(
131 ripemd160_sha256(key_pair.verifying_key().to_bytes().as_slice()).as_slice()
132 == data.as_slice(),
133 )
134 }
135 #[cfg(not(feature = "ed25519-dalek"))]
136 return Err(ProtocolError::NotSupported(
137 "Converting a private key to a eddsa hash 160 is not supported without the ed25519-dalek feature".to_string(),
138 ));
139 }
140 KeyType::BIP13_SCRIPT_HASH => Err(ProtocolError::NotSupported(
141 "Converting a private key to a script hash is not supported".to_string(),
142 )),
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::identity::{Purpose, SecurityLevel};
150 use dashcore::blsful::{Bls12381G2Impl, Pairing, Signature, SignatureSchemes};
151 use dashcore::Network;
152 use dpp::version::PlatformVersion;
153 use rand::rngs::StdRng;
154 use rand::SeedableRng;
155
156 #[test]
157 fn test_bls_serialization_deserialization() {
158 let mut rng = StdRng::seed_from_u64(5);
159 let (public_key_data, secret_key) = KeyType::BLS12_381
160 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest())
161 .expect("expected to get keys");
162 let decoded_secret_key =
163 dashcore::blsful::SecretKey::<Bls12381G2Impl>::from_be_bytes(&secret_key)
164 .expect("expected to get secret key");
165 let public_key = decoded_secret_key.public_key();
166 let decoded_public_key_data = public_key.0.to_compressed();
167 assert_eq!(
168 public_key_data.as_slice(),
169 decoded_public_key_data.as_slice()
170 )
171 }
172
173 #[test]
174 fn test_bls_serialization_deserialization_signature() {
175 let mut rng = StdRng::seed_from_u64(5);
176 let (_, secret_key) = KeyType::BLS12_381
177 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest())
178 .expect("expected to get keys");
179 let decoded_secret_key =
180 dashcore::blsful::SecretKey::<Bls12381G2Impl>::from_be_bytes(&secret_key)
181 .expect("expected to get secret key");
182 let signature = decoded_secret_key
183 .sign(SignatureSchemes::Basic, b"hello")
184 .expect("expected to sign");
185 let compressed = signature.as_raw_value().to_compressed();
186 let g2 = <Bls12381G2Impl as Pairing>::Signature::from_compressed(&compressed)
187 .expect("G2 projective");
188 let decoded_signature = Signature::<Bls12381G2Impl>::Basic(g2);
189 assert_eq!(
190 compressed.as_slice(),
191 decoded_signature.as_raw_value().to_compressed().as_slice()
192 )
193 }
194
195 #[cfg(feature = "random-public-keys")]
196 #[test]
197 fn test_validate_private_key_bytes_with_random_keys() {
198 let platform_version = PlatformVersion::latest();
199 let mut rng = StdRng::from_entropy();
200
201 let key_type = KeyType::ECDSA_SECP256K1;
203 let (public_key_data, private_key_data) = key_type
204 .random_public_and_private_key_data(&mut rng, platform_version)
205 .expect("expected to generate random keys");
206
207 let identity_public_key = IdentityPublicKeyV0 {
208 id: 1,
209 purpose: Purpose::AUTHENTICATION,
210 security_level: SecurityLevel::HIGH,
211 contract_bounds: None,
212 key_type,
213 data: public_key_data.into(),
214 read_only: false,
215 disabled_at: None,
216 };
217
218 assert!(identity_public_key
220 .validate_private_key_bytes(&private_key_data, Network::Testnet)
221 .unwrap(),);
222
223 let invalid_private_key_bytes = [0u8; 32];
225 assert!(!identity_public_key
226 .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
227 .unwrap());
228 }
229
230 #[cfg(all(feature = "random-public-keys", feature = "bls-signatures"))]
231 #[test]
232 fn test_validate_private_key_bytes_with_random_keys_bls12_381() {
233 let platform_version = PlatformVersion::latest();
234 let mut rng = StdRng::from_entropy();
235
236 let key_type = KeyType::BLS12_381;
238 let (public_key_data, private_key_data) = key_type
239 .random_public_and_private_key_data(&mut rng, platform_version)
240 .expect("expected to generate random keys");
241
242 let identity_public_key = IdentityPublicKeyV0 {
243 id: 2,
244 purpose: Purpose::AUTHENTICATION,
245 security_level: SecurityLevel::HIGH,
246 contract_bounds: None,
247 key_type,
248 data: public_key_data.into(),
249 read_only: false,
250 disabled_at: None,
251 };
252
253 assert!(identity_public_key
255 .validate_private_key_bytes(&private_key_data, Network::Testnet)
256 .unwrap());
257
258 let invalid_private_key_bytes = [0u8; 32];
260 assert!(!identity_public_key
261 .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
262 .unwrap());
263 }
264
265 #[test]
268 fn test_public_key_hash_empty_data_errors() {
269 use platform_value::BinaryData;
270 let key = IdentityPublicKeyV0 {
271 id: 0,
272 purpose: Purpose::AUTHENTICATION,
273 security_level: SecurityLevel::HIGH,
274 contract_bounds: None,
275 key_type: KeyType::ECDSA_SECP256K1,
276 data: BinaryData::new(vec![]),
277 read_only: false,
278 disabled_at: None,
279 };
280 let err = key.public_key_hash().unwrap_err();
281 assert!(matches!(err, ProtocolError::EmptyPublicKeyDataError));
282 }
283
284 #[test]
285 fn test_public_key_hash_ecdsa_wrong_length_errors() {
286 use platform_value::BinaryData;
287 let key = IdentityPublicKeyV0 {
289 id: 0,
290 purpose: Purpose::AUTHENTICATION,
291 security_level: SecurityLevel::HIGH,
292 contract_bounds: None,
293 key_type: KeyType::ECDSA_SECP256K1,
294 data: BinaryData::new(vec![1u8; 32]),
295 read_only: false,
296 disabled_at: None,
297 };
298 let err = key.public_key_hash().unwrap_err();
299 match err {
300 ProtocolError::ParsingError(msg) => assert!(msg.contains("key length is invalid")),
301 other => panic!("expected ParsingError, got {:?}", other),
302 }
303 }
304
305 #[test]
306 fn test_public_key_hash_bls_wrong_length_errors() {
307 use platform_value::BinaryData;
308 let key = IdentityPublicKeyV0 {
310 id: 0,
311 purpose: Purpose::AUTHENTICATION,
312 security_level: SecurityLevel::HIGH,
313 contract_bounds: None,
314 key_type: KeyType::BLS12_381,
315 data: BinaryData::new(vec![1u8; 40]),
316 read_only: false,
317 disabled_at: None,
318 };
319 let err = key.public_key_hash().unwrap_err();
320 match err {
321 ProtocolError::ParsingError(msg) => assert!(msg.contains("48 bytes for bls key")),
322 other => panic!("expected ParsingError, got {:?}", other),
323 }
324 }
325
326 #[test]
327 fn test_public_key_hash_bls_returns_ripemd160_sha256_of_data() {
328 use crate::util::hash::ripemd160_sha256;
329 use platform_value::BinaryData;
330 let data = vec![7u8; 48];
331 let key = IdentityPublicKeyV0 {
332 id: 0,
333 purpose: Purpose::AUTHENTICATION,
334 security_level: SecurityLevel::HIGH,
335 contract_bounds: None,
336 key_type: KeyType::BLS12_381,
337 data: BinaryData::new(data.clone()),
338 read_only: false,
339 disabled_at: None,
340 };
341 let hash = key
342 .public_key_hash()
343 .expect("expected hash for 48-byte bls");
344 assert_eq!(hash, ripemd160_sha256(data.as_slice()));
345 }
346
347 #[test]
348 fn test_public_key_hash_ecdsa_hash160_returns_data_itself() {
349 use platform_value::BinaryData;
350 let data = vec![9u8; 20];
351 let key = IdentityPublicKeyV0 {
352 id: 0,
353 purpose: Purpose::AUTHENTICATION,
354 security_level: SecurityLevel::HIGH,
355 contract_bounds: None,
356 key_type: KeyType::ECDSA_HASH160,
357 data: BinaryData::new(data.clone()),
358 read_only: false,
359 disabled_at: None,
360 };
361 let hash = key.public_key_hash().expect("expected hash");
362 assert_eq!(hash.as_slice(), data.as_slice());
363 }
364
365 #[test]
366 fn test_public_key_hash_bip13_script_hash_returns_data_itself() {
367 use platform_value::BinaryData;
368 let data = vec![3u8; 20];
369 let key = IdentityPublicKeyV0 {
370 id: 0,
371 purpose: Purpose::AUTHENTICATION,
372 security_level: SecurityLevel::HIGH,
373 contract_bounds: None,
374 key_type: KeyType::BIP13_SCRIPT_HASH,
375 data: BinaryData::new(data.clone()),
376 read_only: false,
377 disabled_at: None,
378 };
379 let hash = key.public_key_hash().expect("expected hash");
380 assert_eq!(hash.as_slice(), data.as_slice());
381 }
382
383 #[test]
384 fn test_public_key_hash_hash160_wrong_length_errors() {
385 use platform_value::BinaryData;
386 let key = IdentityPublicKeyV0 {
388 id: 0,
389 purpose: Purpose::AUTHENTICATION,
390 security_level: SecurityLevel::HIGH,
391 contract_bounds: None,
392 key_type: KeyType::ECDSA_HASH160,
393 data: BinaryData::new(vec![0u8; 19]),
394 read_only: false,
395 disabled_at: None,
396 };
397 assert!(key.public_key_hash().is_err());
398 }
399
400 #[test]
402 fn test_validate_private_key_bytes_bip13_script_hash_is_unsupported() {
403 use platform_value::BinaryData;
404 let key = IdentityPublicKeyV0 {
405 id: 0,
406 purpose: Purpose::AUTHENTICATION,
407 security_level: SecurityLevel::HIGH,
408 contract_bounds: None,
409 key_type: KeyType::BIP13_SCRIPT_HASH,
410 data: BinaryData::new(vec![0u8; 20]),
411 read_only: false,
412 disabled_at: None,
413 };
414 let err = key
415 .validate_private_key_bytes(&[0u8; 32], Network::Testnet)
416 .unwrap_err();
417 match err {
418 ProtocolError::NotSupported(msg) => {
419 assert!(msg.contains("script hash"));
420 }
421 other => panic!("expected NotSupported, got {:?}", other),
422 }
423 }
424
425 #[test]
427 fn test_validate_private_key_bytes_ecdsa_secret_key_parse_error_returns_false() {
428 use platform_value::BinaryData;
429 let key = IdentityPublicKeyV0 {
432 id: 0,
433 purpose: Purpose::AUTHENTICATION,
434 security_level: SecurityLevel::HIGH,
435 contract_bounds: None,
436 key_type: KeyType::ECDSA_SECP256K1,
437 data: BinaryData::new(vec![0u8; 33]),
440 read_only: false,
441 disabled_at: None,
442 };
443 let ok = key
444 .validate_private_key_bytes(&[0u8; 32], Network::Testnet)
445 .unwrap();
446 assert!(!ok);
447 }
448
449 #[test]
450 fn test_validate_private_key_bytes_ecdsa_hash160_secret_key_parse_error_returns_false() {
451 use platform_value::BinaryData;
452 let key = IdentityPublicKeyV0 {
453 id: 0,
454 purpose: Purpose::AUTHENTICATION,
455 security_level: SecurityLevel::HIGH,
456 contract_bounds: None,
457 key_type: KeyType::ECDSA_HASH160,
458 data: BinaryData::new(vec![0u8; 20]),
459 read_only: false,
460 disabled_at: None,
461 };
462 let ok = key
463 .validate_private_key_bytes(&[0u8; 32], Network::Testnet)
464 .unwrap();
465 assert!(!ok);
466 }
467
468 #[cfg(all(feature = "random-public-keys", feature = "ed25519-dalek"))]
469 #[test]
470 fn test_validate_private_key_bytes_with_random_keys_eddsa_25519_hash160() {
471 let platform_version = PlatformVersion::latest();
472 let mut rng = StdRng::from_entropy();
473
474 let key_type = KeyType::EDDSA_25519_HASH160;
476 let (public_key_data, private_key_data) = key_type
477 .random_public_and_private_key_data(&mut rng, platform_version)
478 .expect("expected to generate random keys");
479
480 let identity_public_key = IdentityPublicKeyV0 {
481 id: 3,
482 purpose: Purpose::AUTHENTICATION,
483 security_level: SecurityLevel::HIGH,
484 contract_bounds: None,
485 key_type,
486 data: public_key_data.into(),
487 read_only: false,
488 disabled_at: None,
489 };
490
491 assert!(identity_public_key
493 .validate_private_key_bytes(&private_key_data, Network::Testnet)
494 .unwrap());
495
496 let invalid_private_key_bytes = [0u8; 32];
498 assert!(!identity_public_key
499 .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
500 .unwrap());
501 }
502}