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