1#![allow(clippy::from_over_into)]
2
3use crate::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
4use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
5#[cfg(feature = "json-conversion")]
6use crate::serialization::JsonConvertible;
7#[cfg(feature = "value-conversion")]
8use crate::serialization::ValueConvertible;
9use bincode::{Decode, Encode};
10use derive_more::From;
11use serde::{Deserialize, Serialize};
12
13mod key_type;
14mod purpose;
15mod security_level;
16pub use key_type::KeyType;
17pub use purpose::Purpose;
18pub use security_level::SecurityLevel;
19pub mod accessors;
20pub mod conversion;
21pub mod fields;
22pub mod v0;
23use crate::version::PlatformVersion;
24use crate::ProtocolError;
25pub use fields::*;
26use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
27
28pub mod methods;
29pub use methods::*;
30pub mod contract_bounds;
31#[cfg(feature = "random-public-keys")]
32mod random;
33
34pub type KeyID = u32;
35pub type KeyCount = KeyID;
36pub type TimestampMillis = u64;
37
38#[derive(
39 Debug,
40 Clone,
41 Eq,
42 PartialEq,
43 Serialize,
44 Deserialize,
45 Encode,
46 Decode,
47 PlatformDeserialize,
48 PlatformSerialize,
49 From,
50 Hash,
51 Ord,
52 PartialOrd,
53)]
54#[platform_serialize(limit = 2000, unversioned)] #[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
56#[serde(tag = "$formatVersion")]
57pub enum IdentityPublicKey {
58 #[serde(rename = "0")]
59 V0(IdentityPublicKeyV0),
60}
61
62#[cfg(feature = "json-conversion")]
63impl JsonConvertible for IdentityPublicKey {}
64
65#[cfg(all(
66 test,
67 feature = "json-conversion",
68 feature = "value-conversion",
69 feature = "serde-conversion"
70))]
71mod json_convertible_tests {
72 use super::*;
73 use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
74 use platform_value::{platform_value, BinaryData, Value};
75 use serde_json::json;
76
77 fn fixture() -> IdentityPublicKey {
78 IdentityPublicKey::V0(IdentityPublicKeyV0 {
79 id: 9,
80 key_type: KeyType::ECDSA_HASH160,
81 purpose: Purpose::TRANSFER,
82 security_level: SecurityLevel::CRITICAL,
83 contract_bounds: None,
84 read_only: true,
85 data: BinaryData::new(vec![0x55; 20]),
86 disabled_at: Some(1_700_000_000_000),
87 })
88 }
89
90 #[test]
91 fn json_round_trip_with_full_wire_shape() {
92 use crate::serialization::JsonConvertible;
93 let original = fixture();
94 let json = original.to_json().expect("to_json");
95 assert_eq!(
106 json,
107 json!({
108 "$formatVersion": "0",
109 "id": 9,
110 "purpose": 3,
111 "securityLevel": 1,
112 "contractBounds": serde_json::Value::Null,
113 "type": 2,
114 "readOnly": true,
115 "data": "VVVVVVVVVVVVVVVVVVVVVVVVVVU=",
116 "disabledAt": 1_700_000_000_000u64,
117 })
118 );
119 let recovered = IdentityPublicKey::from_json(json).expect("from_json");
120 assert_eq!(original, recovered);
121 }
122
123 #[test]
124 fn value_round_trip_with_full_wire_shape() {
125 use crate::serialization::ValueConvertible;
126 let original = fixture();
127 let value = original.to_object().expect("to_object");
128 assert_eq!(
137 value,
138 platform_value!({
139 "$formatVersion": "0",
140 "id": 9u32,
141 "purpose": 3u8,
142 "securityLevel": 1u8,
143 "contractBounds": Value::Null,
144 "type": 2u8,
145 "readOnly": true,
146 "data": Value::Bytes20([0x55; 20]),
147 "disabledAt": 1_700_000_000_000u64,
148 })
149 );
150 let recovered = IdentityPublicKey::from_object(value).expect("from_object");
151 assert_eq!(original, recovered);
152 }
153}
154
155impl IdentityPublicKey {
156 pub fn is_master(&self) -> bool {
158 self.security_level() == SecurityLevel::MASTER
159 }
160
161 pub fn max_possible_size_key(
176 id: KeyID,
177 platform_version: &PlatformVersion,
178 ) -> Result<Self, ProtocolError> {
179 match platform_version
180 .dpp
181 .identity_versions
182 .identity_key_structure_version
183 {
184 0 => Ok(IdentityPublicKeyV0::max_possible_size_key(id).into()),
185 version => Err(ProtocolError::UnknownVersionMismatch {
186 method: "IdentityPublicKey::max_possible_size_key".to_string(),
187 known_versions: vec![0],
188 received: version,
189 }),
190 }
191 }
192
193 pub fn default_versioned(platform_version: &PlatformVersion) -> Result<Self, ProtocolError> {
194 match platform_version
195 .dpp
196 .identity_versions
197 .identity_key_structure_version
198 {
199 0 => Ok(IdentityPublicKeyV0::default().into()),
200 version => Err(ProtocolError::UnknownVersionMismatch {
201 method: "IdentityPublicKey::default_versioned".to_string(),
202 known_versions: vec![0],
203 received: version,
204 }),
205 }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::identity::identity_public_key::accessors::v0::{
212 IdentityPublicKeyGettersV0, IdentityPublicKeySettersV0,
213 };
214 use crate::identity::identity_public_key::contract_bounds::ContractBounds;
215 use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
216 use crate::identity::{IdentityPublicKey, KeyType, Purpose, SecurityLevel};
217 use crate::serialization::{PlatformDeserializable, PlatformSerializable};
218 use platform_value::{BinaryData, Identifier};
219 use platform_version::version::LATEST_PLATFORM_VERSION;
220 use rand::SeedableRng;
221
222 #[test]
223 fn test_identity_key_serialization_deserialization() {
224 let mut rng = rand::rngs::StdRng::from_entropy();
225 let key: IdentityPublicKey =
226 IdentityPublicKeyV0::random_ecdsa_master_authentication_key_with_rng(
227 1,
228 &mut rng,
229 LATEST_PLATFORM_VERSION,
230 )
231 .expect("expected a random key")
232 .0
233 .into();
234 let serialized = key.serialize_to_bytes().expect("expected to serialize key");
235 let unserialized: IdentityPublicKey =
236 PlatformDeserializable::deserialize_from_bytes(serialized.as_slice())
237 .expect("expected to deserialize key");
238 assert_eq!(key, unserialized)
239 }
240
241 fn make_key_v0(security_level: SecurityLevel) -> IdentityPublicKey {
244 IdentityPublicKey::V0(IdentityPublicKeyV0 {
245 id: 42,
246 purpose: Purpose::AUTHENTICATION,
247 security_level,
248 contract_bounds: None,
249 key_type: KeyType::ECDSA_SECP256K1,
250 data: BinaryData::new(vec![0u8; 33]),
251 read_only: false,
252 disabled_at: None,
253 })
254 }
255
256 #[test]
257 fn test_is_master_true_when_security_level_master() {
258 let key = make_key_v0(SecurityLevel::MASTER);
259 assert!(key.is_master());
260 }
261
262 #[test]
263 fn test_is_master_false_for_other_levels() {
264 assert!(!make_key_v0(SecurityLevel::CRITICAL).is_master());
265 assert!(!make_key_v0(SecurityLevel::HIGH).is_master());
266 assert!(!make_key_v0(SecurityLevel::MEDIUM).is_master());
267 }
268
269 #[test]
272 fn test_max_possible_size_key_v0_returns_bls_sized_data() {
273 let key = IdentityPublicKey::max_possible_size_key(123, LATEST_PLATFORM_VERSION)
275 .expect("max_possible_size_key should work for v0");
276 assert_eq!(key.id(), 123);
277 assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
278 assert_eq!(key.security_level(), SecurityLevel::MASTER);
279 assert!(!key.read_only());
280 assert!(key.contract_bounds().is_none());
281 assert!(key.disabled_at().is_none());
282 assert_eq!(key.data().len(), key.key_type().default_size());
284 assert!(key.data().as_slice().iter().all(|b| *b == 0xff));
285 }
286
287 #[test]
290 fn test_default_versioned_returns_v0_default() {
291 let key = IdentityPublicKey::default_versioned(LATEST_PLATFORM_VERSION)
292 .expect("default_versioned should work for v0");
293 assert_eq!(key.id(), 0);
295 assert_eq!(key.purpose(), Purpose::default());
296 assert_eq!(key.security_level(), SecurityLevel::default());
297 assert_eq!(key.key_type(), KeyType::default());
298 }
299
300 #[test]
303 fn test_wrapper_getters_delegate_to_v0() {
304 let inner = IdentityPublicKeyV0 {
305 id: 7,
306 purpose: Purpose::TRANSFER,
307 security_level: SecurityLevel::CRITICAL,
308 contract_bounds: Some(ContractBounds::SingleContract {
309 id: Identifier::from([0x01u8; 32]),
310 }),
311 key_type: KeyType::BLS12_381,
312 data: BinaryData::new(vec![2u8; 48]),
313 read_only: true,
314 disabled_at: Some(1_700_000_000_000),
315 };
316 let key = IdentityPublicKey::V0(inner.clone());
317 assert_eq!(key.id(), 7);
318 assert_eq!(key.purpose(), Purpose::TRANSFER);
319 assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
320 assert_eq!(key.key_type(), KeyType::BLS12_381);
321 assert!(key.read_only());
322 assert_eq!(key.data().as_slice(), &vec![2u8; 48][..]);
323 assert_eq!(key.disabled_at(), Some(1_700_000_000_000));
324 assert!(key.is_disabled());
325 assert!(key.contract_bounds().is_some());
326
327 let cloned = key.clone();
329 assert_eq!(cloned.data_owned().as_slice(), &vec![2u8; 48][..]);
330 }
331
332 #[test]
333 fn test_wrapper_setters_delegate_to_v0() {
334 let mut key = make_key_v0(SecurityLevel::HIGH);
335 key.set_id(99);
336 key.set_purpose(Purpose::ENCRYPTION);
337 key.set_security_level(SecurityLevel::CRITICAL);
338 key.set_key_type(KeyType::BLS12_381);
339 key.set_read_only(true);
340 key.set_data(BinaryData::new(vec![0xABu8; 48]));
341 key.set_disabled_at(1234);
342
343 assert_eq!(key.id(), 99);
344 assert_eq!(key.purpose(), Purpose::ENCRYPTION);
345 assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
346 assert_eq!(key.key_type(), KeyType::BLS12_381);
347 assert!(key.read_only());
348 assert_eq!(key.data().as_slice(), &vec![0xABu8; 48][..]);
349 assert_eq!(key.disabled_at(), Some(1234));
350 assert!(key.is_disabled());
351
352 key.remove_disabled_at();
353 assert_eq!(key.disabled_at(), None);
354 assert!(!key.is_disabled());
355 }
356
357 #[test]
359 fn test_from_v0_into_wrapper() {
360 let v0 = IdentityPublicKeyV0 {
361 id: 5,
362 purpose: Purpose::VOTING,
363 security_level: SecurityLevel::MEDIUM,
364 contract_bounds: None,
365 key_type: KeyType::ECDSA_HASH160,
366 data: BinaryData::new(vec![0u8; 20]),
367 read_only: false,
368 disabled_at: None,
369 };
370 let wrapped: IdentityPublicKey = v0.clone().into();
371 assert_eq!(wrapped.id(), 5);
372 assert_eq!(wrapped.purpose(), Purpose::VOTING);
373 assert_eq!(wrapped.security_level(), SecurityLevel::MEDIUM);
374 assert_eq!(wrapped, IdentityPublicKey::V0(v0));
376 }
377
378 #[test]
380 fn test_v0_default_fields() {
381 let v0 = IdentityPublicKeyV0::default();
382 assert_eq!(v0.id, 0);
383 assert_eq!(v0.purpose, Purpose::default());
384 assert_eq!(v0.security_level, SecurityLevel::default());
385 assert_eq!(v0.key_type, KeyType::default());
386 assert!(!v0.read_only);
387 assert_eq!(v0.data.as_slice().len(), 0);
388 assert!(v0.disabled_at.is_none());
389 assert!(v0.contract_bounds.is_none());
390 }
391
392 #[test]
394 fn test_keys_are_orderable_and_cloneable() {
395 let a = IdentityPublicKey::V0(IdentityPublicKeyV0 {
396 id: 1,
397 ..Default::default()
398 });
399 let b = IdentityPublicKey::V0(IdentityPublicKeyV0 {
400 id: 2,
401 ..Default::default()
402 });
403 assert!(a < b);
404 let a_clone = a.clone();
405 assert_eq!(a, a_clone);
406 }
407}
408
409#[cfg(all(test, feature = "random-public-keys"))]
410mod random_tests {
411 use crate::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
412 use crate::identity::{IdentityPublicKey, KeyType, Purpose, SecurityLevel};
413 use platform_version::version::LATEST_PLATFORM_VERSION;
414
415 #[test]
418 fn test_random_key_with_seed_is_deterministic() {
419 let k1 = IdentityPublicKey::random_key(1, Some(42), LATEST_PLATFORM_VERSION);
420 let k2 = IdentityPublicKey::random_key(1, Some(42), LATEST_PLATFORM_VERSION);
421 assert_eq!(k1, k2);
422 }
423
424 #[test]
425 fn test_random_keys_returns_requested_count() {
426 let keys = IdentityPublicKey::random_keys(0, 5, Some(7), LATEST_PLATFORM_VERSION);
427 assert_eq!(keys.len(), 5);
428 let mut ids: Vec<_> = keys.iter().map(|k| k.id()).collect();
430 ids.sort();
431 assert_eq!(ids, vec![0, 1, 2, 3, 4]);
432 }
433
434 #[test]
435 fn test_random_authentication_key_is_always_authentication_purpose() {
436 for id in 0..5u32 {
437 let k = IdentityPublicKey::random_authentication_key(
438 id,
439 Some(id as u64),
440 LATEST_PLATFORM_VERSION,
441 );
442 assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
443 }
444 }
445
446 #[test]
447 fn test_random_authentication_keys_returns_requested_count_and_all_auth() {
448 let keys =
449 IdentityPublicKey::random_authentication_keys(0, 3, Some(11), LATEST_PLATFORM_VERSION);
450 assert_eq!(keys.len(), 3);
451 for k in &keys {
452 assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
453 }
454 }
455
456 #[test]
457 fn test_random_ecdsa_master_authentication_key_has_expected_attributes() {
458 let (key, _priv) = IdentityPublicKey::random_ecdsa_master_authentication_key(
459 0,
460 Some(1),
461 LATEST_PLATFORM_VERSION,
462 )
463 .expect("expected master authentication key");
464 assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
465 assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
466 assert_eq!(key.security_level(), SecurityLevel::MASTER);
467 assert!(!key.read_only());
468 assert_eq!(key.data().len(), 33);
469 }
470
471 #[test]
472 fn test_random_ecdsa_critical_level_authentication_key_attributes() {
473 let (key, _priv) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key(
474 1,
475 Some(2),
476 LATEST_PLATFORM_VERSION,
477 )
478 .expect("expected critical auth key");
479 assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
480 assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
481 assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
482 }
483
484 #[test]
485 fn test_random_ecdsa_high_level_authentication_key_attributes() {
486 let (key, _priv) = IdentityPublicKey::random_ecdsa_high_level_authentication_key(
487 2,
488 Some(3),
489 LATEST_PLATFORM_VERSION,
490 )
491 .expect("expected high-level auth key");
492 assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
493 assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
494 assert_eq!(key.security_level(), SecurityLevel::HIGH);
495 }
496
497 #[test]
498 fn test_random_masternode_owner_key_has_owner_purpose_and_is_read_only() {
499 let (key, _priv) =
500 IdentityPublicKey::random_masternode_owner_key(3, Some(4), LATEST_PLATFORM_VERSION)
501 .expect("expected masternode owner key");
502 assert_eq!(key.key_type(), KeyType::ECDSA_HASH160);
503 assert_eq!(key.purpose(), Purpose::OWNER);
504 assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
505 assert!(key.read_only());
506 }
507
508 #[test]
509 fn test_random_masternode_transfer_key_has_transfer_purpose_and_is_read_only() {
510 let (key, _priv) =
511 IdentityPublicKey::random_masternode_transfer_key(4, Some(5), LATEST_PLATFORM_VERSION)
512 .expect("expected masternode transfer key");
513 assert_eq!(key.key_type(), KeyType::ECDSA_HASH160);
514 assert_eq!(key.purpose(), Purpose::TRANSFER);
515 assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
516 assert!(key.read_only());
517 }
518
519 #[test]
520 fn test_main_keys_with_random_authentication_keys_errors_when_count_below_two() {
521 use rand::{rngs::StdRng, SeedableRng};
522 let mut rng = StdRng::seed_from_u64(1);
523 let err =
524 IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
525 1,
526 &mut rng,
527 LATEST_PLATFORM_VERSION,
528 )
529 .unwrap_err();
530 match err {
531 crate::ProtocolError::PublicKeyGenerationError(msg) => {
532 assert!(msg.contains("at least 2"));
533 }
534 other => panic!("expected PublicKeyGenerationError, got {:?}", other),
535 }
536 }
537
538 #[test]
539 fn test_main_keys_with_random_authentication_keys_count_two() {
540 use rand::{rngs::StdRng, SeedableRng};
541 let mut rng = StdRng::seed_from_u64(2);
542 let keys = IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
543 2,
544 &mut rng,
545 LATEST_PLATFORM_VERSION,
546 )
547 .expect("expected keys");
548 assert_eq!(keys.len(), 2);
549 assert_eq!(keys[0].0.security_level(), SecurityLevel::MASTER);
551 assert_eq!(keys[0].0.key_type(), KeyType::ECDSA_SECP256K1);
552 assert_eq!(keys[1].0.security_level(), SecurityLevel::HIGH);
553 assert_eq!(keys[1].0.key_type(), KeyType::ECDSA_SECP256K1);
554 }
555
556 #[test]
557 fn test_main_keys_with_random_authentication_keys_count_three() {
558 use rand::{rngs::StdRng, SeedableRng};
559 let mut rng = StdRng::seed_from_u64(3);
560 let keys = IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
561 3,
562 &mut rng,
563 LATEST_PLATFORM_VERSION,
564 )
565 .expect("expected keys");
566 assert_eq!(keys.len(), 3);
567 assert_eq!(keys[0].0.security_level(), SecurityLevel::MASTER);
568 assert_eq!(keys[1].0.security_level(), SecurityLevel::CRITICAL);
569 assert_eq!(keys[2].0.security_level(), SecurityLevel::HIGH);
570 }
571
572 #[test]
573 fn test_random_unique_keys_with_rng_matches_count() {
574 use rand::{rngs::StdRng, SeedableRng};
575 let mut rng = StdRng::seed_from_u64(9);
576 let keys =
577 IdentityPublicKey::random_unique_keys_with_rng(4, &mut rng, LATEST_PLATFORM_VERSION)
578 .expect("expected keys");
579 assert_eq!(keys.len(), 4);
580 let ids: Vec<_> = keys.iter().map(|k| k.id()).collect();
582 assert_eq!(ids, vec![0, 1, 2, 3]);
583 }
584
585 #[test]
586 fn test_random_keys_with_rng_returns_requested_count() {
587 use rand::{rngs::StdRng, SeedableRng};
588 let mut rng = StdRng::seed_from_u64(10);
589 let keys = IdentityPublicKey::random_keys_with_rng(3, &mut rng, LATEST_PLATFORM_VERSION);
590 assert_eq!(keys.len(), 3);
591 }
592
593 #[test]
594 fn test_random_authentication_keys_with_private_keys_with_rng_returns_pairs() {
595 use rand::{rngs::StdRng, SeedableRng};
596 let mut rng = StdRng::seed_from_u64(11);
597 let pairs = IdentityPublicKey::random_authentication_keys_with_private_keys_with_rng(
598 5,
599 3,
600 &mut rng,
601 LATEST_PLATFORM_VERSION,
602 )
603 .expect("expected pairs");
604 assert_eq!(pairs.len(), 3);
605 let ids: Vec<_> = pairs.iter().map(|(k, _)| k.id()).collect();
606 assert_eq!(ids, vec![5, 6, 7]);
607 for (k, _) in &pairs {
608 assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
609 }
610 }
611
612 #[test]
613 fn test_random_voting_key_with_rng_attributes() {
614 use rand::{rngs::StdRng, SeedableRng};
615 let mut rng = StdRng::seed_from_u64(13);
616 let (k, _priv) =
617 IdentityPublicKey::random_voting_key_with_rng(0, &mut rng, LATEST_PLATFORM_VERSION)
618 .expect("expected voting key");
619 assert_eq!(k.purpose(), Purpose::VOTING);
620 assert_eq!(k.key_type(), KeyType::ECDSA_HASH160);
621 assert_eq!(k.security_level(), SecurityLevel::MEDIUM);
622 }
623
624 #[test]
625 fn test_random_key_with_known_attributes_honors_inputs() {
626 use crate::identity::contract_bounds::ContractBounds;
627 use platform_value::Identifier;
628 use rand::{rngs::StdRng, SeedableRng};
629 let mut rng = StdRng::seed_from_u64(17);
630 let bounds = ContractBounds::SingleContract {
631 id: Identifier::from([0x77u8; 32]),
632 };
633 let (k, _priv) = IdentityPublicKey::random_key_with_known_attributes(
634 42,
635 &mut rng,
636 Purpose::TRANSFER,
637 SecurityLevel::CRITICAL,
638 KeyType::ECDSA_SECP256K1,
639 Some(bounds.clone()),
640 LATEST_PLATFORM_VERSION,
641 )
642 .expect("expected key");
643 assert_eq!(k.id(), 42);
644 assert_eq!(k.purpose(), Purpose::TRANSFER);
645 assert_eq!(k.security_level(), SecurityLevel::CRITICAL);
646 assert_eq!(k.key_type(), KeyType::ECDSA_SECP256K1);
647 assert_eq!(k.contract_bounds(), Some(&bounds));
648 }
649}