Skip to main content

dpp/identity/identity_public_key/
mod.rs

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 = "value-conversion")]
6use crate::serialization::ValueConvertible;
7use bincode::{Decode, Encode};
8use derive_more::From;
9use serde::{Deserialize, Serialize};
10
11mod key_type;
12mod purpose;
13mod security_level;
14pub use key_type::KeyType;
15pub use purpose::Purpose;
16pub use security_level::SecurityLevel;
17pub mod accessors;
18pub mod conversion;
19pub mod fields;
20pub mod v0;
21use crate::version::PlatformVersion;
22use crate::ProtocolError;
23pub use fields::*;
24use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
25
26pub mod methods;
27pub use methods::*;
28pub mod contract_bounds;
29#[cfg(feature = "random-public-keys")]
30mod random;
31
32pub type KeyID = u32;
33pub type KeyCount = KeyID;
34pub type TimestampMillis = u64;
35
36#[derive(
37    Debug,
38    Clone,
39    Eq,
40    PartialEq,
41    Serialize,
42    Deserialize,
43    Encode,
44    Decode,
45    PlatformDeserialize,
46    PlatformSerialize,
47    From,
48    Hash,
49    Ord,
50    PartialOrd,
51)]
52#[platform_serialize(limit = 2000, unversioned)] //This is not platform versioned automatically
53#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
54#[serde(tag = "$formatVersion")]
55pub enum IdentityPublicKey {
56    #[serde(rename = "0")]
57    V0(IdentityPublicKeyV0),
58}
59
60impl IdentityPublicKey {
61    /// Checks if public key security level is MASTER
62    pub fn is_master(&self) -> bool {
63        self.security_level() == SecurityLevel::MASTER
64    }
65
66    /// Generates an identity public key with the maximum possible size based on the platform version.
67    ///
68    /// This method constructs a key of the largest possible size for the given platform version.
69    /// This can be useful for stress testing or benchmarking purposes.
70    ///
71    /// # Parameters
72    ///
73    /// * `id`: The `KeyID` for the generated key.
74    /// * `platform_version`: The platform version which determines the structure of the identity key.
75    ///
76    /// # Returns
77    ///
78    /// * `Self`: An instance of the `IdentityPublicKey` struct.
79    ///
80    pub fn max_possible_size_key(
81        id: KeyID,
82        platform_version: &PlatformVersion,
83    ) -> Result<Self, ProtocolError> {
84        match platform_version
85            .dpp
86            .identity_versions
87            .identity_key_structure_version
88        {
89            0 => Ok(IdentityPublicKeyV0::max_possible_size_key(id).into()),
90            version => Err(ProtocolError::UnknownVersionMismatch {
91                method: "IdentityPublicKey::max_possible_size_key".to_string(),
92                known_versions: vec![0],
93                received: version,
94            }),
95        }
96    }
97
98    pub fn default_versioned(platform_version: &PlatformVersion) -> Result<Self, ProtocolError> {
99        match platform_version
100            .dpp
101            .identity_versions
102            .identity_key_structure_version
103        {
104            0 => Ok(IdentityPublicKeyV0::default().into()),
105            version => Err(ProtocolError::UnknownVersionMismatch {
106                method: "IdentityPublicKey::default_versioned".to_string(),
107                known_versions: vec![0],
108                received: version,
109            }),
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use crate::identity::identity_public_key::accessors::v0::{
117        IdentityPublicKeyGettersV0, IdentityPublicKeySettersV0,
118    };
119    use crate::identity::identity_public_key::contract_bounds::ContractBounds;
120    use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
121    use crate::identity::{IdentityPublicKey, KeyType, Purpose, SecurityLevel};
122    use crate::serialization::{PlatformDeserializable, PlatformSerializable};
123    use platform_value::{BinaryData, Identifier};
124    use platform_version::version::LATEST_PLATFORM_VERSION;
125    use rand::SeedableRng;
126
127    #[test]
128    fn test_identity_key_serialization_deserialization() {
129        let mut rng = rand::rngs::StdRng::from_entropy();
130        let key: IdentityPublicKey =
131            IdentityPublicKeyV0::random_ecdsa_master_authentication_key_with_rng(
132                1,
133                &mut rng,
134                LATEST_PLATFORM_VERSION,
135            )
136            .expect("expected a random key")
137            .0
138            .into();
139        let serialized = key.serialize_to_bytes().expect("expected to serialize key");
140        let unserialized: IdentityPublicKey =
141            PlatformDeserializable::deserialize_from_bytes(serialized.as_slice())
142                .expect("expected to deserialize key");
143        assert_eq!(key, unserialized)
144    }
145
146    // -- is_master --
147
148    fn make_key_v0(security_level: SecurityLevel) -> IdentityPublicKey {
149        IdentityPublicKey::V0(IdentityPublicKeyV0 {
150            id: 42,
151            purpose: Purpose::AUTHENTICATION,
152            security_level,
153            contract_bounds: None,
154            key_type: KeyType::ECDSA_SECP256K1,
155            data: BinaryData::new(vec![0u8; 33]),
156            read_only: false,
157            disabled_at: None,
158        })
159    }
160
161    #[test]
162    fn test_is_master_true_when_security_level_master() {
163        let key = make_key_v0(SecurityLevel::MASTER);
164        assert!(key.is_master());
165    }
166
167    #[test]
168    fn test_is_master_false_for_other_levels() {
169        assert!(!make_key_v0(SecurityLevel::CRITICAL).is_master());
170        assert!(!make_key_v0(SecurityLevel::HIGH).is_master());
171        assert!(!make_key_v0(SecurityLevel::MEDIUM).is_master());
172    }
173
174    // -- max_possible_size_key --
175
176    #[test]
177    fn test_max_possible_size_key_v0_returns_bls_sized_data() {
178        // BLS12_381 has the largest default size (48 bytes).
179        let key = IdentityPublicKey::max_possible_size_key(123, LATEST_PLATFORM_VERSION)
180            .expect("max_possible_size_key should work for v0");
181        assert_eq!(key.id(), 123);
182        assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
183        assert_eq!(key.security_level(), SecurityLevel::MASTER);
184        assert!(!key.read_only());
185        assert!(key.contract_bounds().is_none());
186        assert!(key.disabled_at().is_none());
187        // data should be default_size() bytes filled with 0xff.
188        assert_eq!(key.data().len(), key.key_type().default_size());
189        assert!(key.data().as_slice().iter().all(|b| *b == 0xff));
190    }
191
192    // -- default_versioned --
193
194    #[test]
195    fn test_default_versioned_returns_v0_default() {
196        let key = IdentityPublicKey::default_versioned(LATEST_PLATFORM_VERSION)
197            .expect("default_versioned should work for v0");
198        // The V0 Default should have id=0 and default purpose/security_level/key_type.
199        assert_eq!(key.id(), 0);
200        assert_eq!(key.purpose(), Purpose::default());
201        assert_eq!(key.security_level(), SecurityLevel::default());
202        assert_eq!(key.key_type(), KeyType::default());
203    }
204
205    // -- accessors on the IdentityPublicKey enum wrapper --
206
207    #[test]
208    fn test_wrapper_getters_delegate_to_v0() {
209        let inner = IdentityPublicKeyV0 {
210            id: 7,
211            purpose: Purpose::TRANSFER,
212            security_level: SecurityLevel::CRITICAL,
213            contract_bounds: Some(ContractBounds::SingleContract {
214                id: Identifier::from([0x01u8; 32]),
215            }),
216            key_type: KeyType::BLS12_381,
217            data: BinaryData::new(vec![2u8; 48]),
218            read_only: true,
219            disabled_at: Some(1_700_000_000_000),
220        };
221        let key = IdentityPublicKey::V0(inner.clone());
222        assert_eq!(key.id(), 7);
223        assert_eq!(key.purpose(), Purpose::TRANSFER);
224        assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
225        assert_eq!(key.key_type(), KeyType::BLS12_381);
226        assert!(key.read_only());
227        assert_eq!(key.data().as_slice(), &vec![2u8; 48][..]);
228        assert_eq!(key.disabled_at(), Some(1_700_000_000_000));
229        assert!(key.is_disabled());
230        assert!(key.contract_bounds().is_some());
231
232        // data_owned returns the underlying data.
233        let cloned = key.clone();
234        assert_eq!(cloned.data_owned().as_slice(), &vec![2u8; 48][..]);
235    }
236
237    #[test]
238    fn test_wrapper_setters_delegate_to_v0() {
239        let mut key = make_key_v0(SecurityLevel::HIGH);
240        key.set_id(99);
241        key.set_purpose(Purpose::ENCRYPTION);
242        key.set_security_level(SecurityLevel::CRITICAL);
243        key.set_key_type(KeyType::BLS12_381);
244        key.set_read_only(true);
245        key.set_data(BinaryData::new(vec![0xABu8; 48]));
246        key.set_disabled_at(1234);
247
248        assert_eq!(key.id(), 99);
249        assert_eq!(key.purpose(), Purpose::ENCRYPTION);
250        assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
251        assert_eq!(key.key_type(), KeyType::BLS12_381);
252        assert!(key.read_only());
253        assert_eq!(key.data().as_slice(), &vec![0xABu8; 48][..]);
254        assert_eq!(key.disabled_at(), Some(1234));
255        assert!(key.is_disabled());
256
257        key.remove_disabled_at();
258        assert_eq!(key.disabled_at(), None);
259        assert!(!key.is_disabled());
260    }
261
262    // -- From<IdentityPublicKeyV0> for IdentityPublicKey --
263    #[test]
264    fn test_from_v0_into_wrapper() {
265        let v0 = IdentityPublicKeyV0 {
266            id: 5,
267            purpose: Purpose::VOTING,
268            security_level: SecurityLevel::MEDIUM,
269            contract_bounds: None,
270            key_type: KeyType::ECDSA_HASH160,
271            data: BinaryData::new(vec![0u8; 20]),
272            read_only: false,
273            disabled_at: None,
274        };
275        let wrapped: IdentityPublicKey = v0.clone().into();
276        assert_eq!(wrapped.id(), 5);
277        assert_eq!(wrapped.purpose(), Purpose::VOTING);
278        assert_eq!(wrapped.security_level(), SecurityLevel::MEDIUM);
279        // Equality on the enum variant.
280        assert_eq!(wrapped, IdentityPublicKey::V0(v0));
281    }
282
283    // -- IdentityPublicKeyV0::default basic invariants --
284    #[test]
285    fn test_v0_default_fields() {
286        let v0 = IdentityPublicKeyV0::default();
287        assert_eq!(v0.id, 0);
288        assert_eq!(v0.purpose, Purpose::default());
289        assert_eq!(v0.security_level, SecurityLevel::default());
290        assert_eq!(v0.key_type, KeyType::default());
291        assert!(!v0.read_only);
292        assert_eq!(v0.data.as_slice().len(), 0);
293        assert!(v0.disabled_at.is_none());
294        assert!(v0.contract_bounds.is_none());
295    }
296
297    // -- Ordering is derived: Clone + Eq + PartialOrd --
298    #[test]
299    fn test_keys_are_orderable_and_cloneable() {
300        let a = IdentityPublicKey::V0(IdentityPublicKeyV0 {
301            id: 1,
302            ..Default::default()
303        });
304        let b = IdentityPublicKey::V0(IdentityPublicKeyV0 {
305            id: 2,
306            ..Default::default()
307        });
308        assert!(a < b);
309        let a_clone = a.clone();
310        assert_eq!(a, a_clone);
311    }
312}
313
314#[cfg(all(test, feature = "random-public-keys"))]
315mod random_tests {
316    use crate::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
317    use crate::identity::{IdentityPublicKey, KeyType, Purpose, SecurityLevel};
318    use platform_version::version::LATEST_PLATFORM_VERSION;
319
320    // -- random_key and random_keys with a seed are deterministic. --
321
322    #[test]
323    fn test_random_key_with_seed_is_deterministic() {
324        let k1 = IdentityPublicKey::random_key(1, Some(42), LATEST_PLATFORM_VERSION);
325        let k2 = IdentityPublicKey::random_key(1, Some(42), LATEST_PLATFORM_VERSION);
326        assert_eq!(k1, k2);
327    }
328
329    #[test]
330    fn test_random_keys_returns_requested_count() {
331        let keys = IdentityPublicKey::random_keys(0, 5, Some(7), LATEST_PLATFORM_VERSION);
332        assert_eq!(keys.len(), 5);
333        // Each should have a distinct id in [0, 5).
334        let mut ids: Vec<_> = keys.iter().map(|k| k.id()).collect();
335        ids.sort();
336        assert_eq!(ids, vec![0, 1, 2, 3, 4]);
337    }
338
339    #[test]
340    fn test_random_authentication_key_is_always_authentication_purpose() {
341        for id in 0..5u32 {
342            let k = IdentityPublicKey::random_authentication_key(
343                id,
344                Some(id as u64),
345                LATEST_PLATFORM_VERSION,
346            );
347            assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
348        }
349    }
350
351    #[test]
352    fn test_random_authentication_keys_returns_requested_count_and_all_auth() {
353        let keys =
354            IdentityPublicKey::random_authentication_keys(0, 3, Some(11), LATEST_PLATFORM_VERSION);
355        assert_eq!(keys.len(), 3);
356        for k in &keys {
357            assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
358        }
359    }
360
361    #[test]
362    fn test_random_ecdsa_master_authentication_key_has_expected_attributes() {
363        let (key, _priv) = IdentityPublicKey::random_ecdsa_master_authentication_key(
364            0,
365            Some(1),
366            LATEST_PLATFORM_VERSION,
367        )
368        .expect("expected master authentication key");
369        assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
370        assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
371        assert_eq!(key.security_level(), SecurityLevel::MASTER);
372        assert!(!key.read_only());
373        assert_eq!(key.data().len(), 33);
374    }
375
376    #[test]
377    fn test_random_ecdsa_critical_level_authentication_key_attributes() {
378        let (key, _priv) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key(
379            1,
380            Some(2),
381            LATEST_PLATFORM_VERSION,
382        )
383        .expect("expected critical auth key");
384        assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
385        assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
386        assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
387    }
388
389    #[test]
390    fn test_random_ecdsa_high_level_authentication_key_attributes() {
391        let (key, _priv) = IdentityPublicKey::random_ecdsa_high_level_authentication_key(
392            2,
393            Some(3),
394            LATEST_PLATFORM_VERSION,
395        )
396        .expect("expected high-level auth key");
397        assert_eq!(key.key_type(), KeyType::ECDSA_SECP256K1);
398        assert_eq!(key.purpose(), Purpose::AUTHENTICATION);
399        assert_eq!(key.security_level(), SecurityLevel::HIGH);
400    }
401
402    #[test]
403    fn test_random_masternode_owner_key_has_owner_purpose_and_is_read_only() {
404        let (key, _priv) =
405            IdentityPublicKey::random_masternode_owner_key(3, Some(4), LATEST_PLATFORM_VERSION)
406                .expect("expected masternode owner key");
407        assert_eq!(key.key_type(), KeyType::ECDSA_HASH160);
408        assert_eq!(key.purpose(), Purpose::OWNER);
409        assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
410        assert!(key.read_only());
411    }
412
413    #[test]
414    fn test_random_masternode_transfer_key_has_transfer_purpose_and_is_read_only() {
415        let (key, _priv) =
416            IdentityPublicKey::random_masternode_transfer_key(4, Some(5), LATEST_PLATFORM_VERSION)
417                .expect("expected masternode transfer key");
418        assert_eq!(key.key_type(), KeyType::ECDSA_HASH160);
419        assert_eq!(key.purpose(), Purpose::TRANSFER);
420        assert_eq!(key.security_level(), SecurityLevel::CRITICAL);
421        assert!(key.read_only());
422    }
423
424    #[test]
425    fn test_main_keys_with_random_authentication_keys_errors_when_count_below_two() {
426        use rand::{rngs::StdRng, SeedableRng};
427        let mut rng = StdRng::seed_from_u64(1);
428        let err =
429            IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
430                1,
431                &mut rng,
432                LATEST_PLATFORM_VERSION,
433            )
434            .unwrap_err();
435        match err {
436            crate::ProtocolError::PublicKeyGenerationError(msg) => {
437                assert!(msg.contains("at least 2"));
438            }
439            other => panic!("expected PublicKeyGenerationError, got {:?}", other),
440        }
441    }
442
443    #[test]
444    fn test_main_keys_with_random_authentication_keys_count_two() {
445        use rand::{rngs::StdRng, SeedableRng};
446        let mut rng = StdRng::seed_from_u64(2);
447        let keys = IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
448            2,
449            &mut rng,
450            LATEST_PLATFORM_VERSION,
451        )
452        .expect("expected keys");
453        assert_eq!(keys.len(), 2);
454        // Position 0 must be Master ECDSA, position 1 must be High ECDSA.
455        assert_eq!(keys[0].0.security_level(), SecurityLevel::MASTER);
456        assert_eq!(keys[0].0.key_type(), KeyType::ECDSA_SECP256K1);
457        assert_eq!(keys[1].0.security_level(), SecurityLevel::HIGH);
458        assert_eq!(keys[1].0.key_type(), KeyType::ECDSA_SECP256K1);
459    }
460
461    #[test]
462    fn test_main_keys_with_random_authentication_keys_count_three() {
463        use rand::{rngs::StdRng, SeedableRng};
464        let mut rng = StdRng::seed_from_u64(3);
465        let keys = IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
466            3,
467            &mut rng,
468            LATEST_PLATFORM_VERSION,
469        )
470        .expect("expected keys");
471        assert_eq!(keys.len(), 3);
472        assert_eq!(keys[0].0.security_level(), SecurityLevel::MASTER);
473        assert_eq!(keys[1].0.security_level(), SecurityLevel::CRITICAL);
474        assert_eq!(keys[2].0.security_level(), SecurityLevel::HIGH);
475    }
476
477    #[test]
478    fn test_random_unique_keys_with_rng_matches_count() {
479        use rand::{rngs::StdRng, SeedableRng};
480        let mut rng = StdRng::seed_from_u64(9);
481        let keys =
482            IdentityPublicKey::random_unique_keys_with_rng(4, &mut rng, LATEST_PLATFORM_VERSION)
483                .expect("expected keys");
484        assert_eq!(keys.len(), 4);
485        // IDs should be 0..4.
486        let ids: Vec<_> = keys.iter().map(|k| k.id()).collect();
487        assert_eq!(ids, vec![0, 1, 2, 3]);
488    }
489
490    #[test]
491    fn test_random_keys_with_rng_returns_requested_count() {
492        use rand::{rngs::StdRng, SeedableRng};
493        let mut rng = StdRng::seed_from_u64(10);
494        let keys = IdentityPublicKey::random_keys_with_rng(3, &mut rng, LATEST_PLATFORM_VERSION);
495        assert_eq!(keys.len(), 3);
496    }
497
498    #[test]
499    fn test_random_authentication_keys_with_private_keys_with_rng_returns_pairs() {
500        use rand::{rngs::StdRng, SeedableRng};
501        let mut rng = StdRng::seed_from_u64(11);
502        let pairs = IdentityPublicKey::random_authentication_keys_with_private_keys_with_rng(
503            5,
504            3,
505            &mut rng,
506            LATEST_PLATFORM_VERSION,
507        )
508        .expect("expected pairs");
509        assert_eq!(pairs.len(), 3);
510        let ids: Vec<_> = pairs.iter().map(|(k, _)| k.id()).collect();
511        assert_eq!(ids, vec![5, 6, 7]);
512        for (k, _) in &pairs {
513            assert_eq!(k.purpose(), Purpose::AUTHENTICATION);
514        }
515    }
516
517    #[test]
518    fn test_random_voting_key_with_rng_attributes() {
519        use rand::{rngs::StdRng, SeedableRng};
520        let mut rng = StdRng::seed_from_u64(13);
521        let (k, _priv) =
522            IdentityPublicKey::random_voting_key_with_rng(0, &mut rng, LATEST_PLATFORM_VERSION)
523                .expect("expected voting key");
524        assert_eq!(k.purpose(), Purpose::VOTING);
525        assert_eq!(k.key_type(), KeyType::ECDSA_HASH160);
526        assert_eq!(k.security_level(), SecurityLevel::MEDIUM);
527    }
528
529    #[test]
530    fn test_random_key_with_known_attributes_honors_inputs() {
531        use crate::identity::contract_bounds::ContractBounds;
532        use platform_value::Identifier;
533        use rand::{rngs::StdRng, SeedableRng};
534        let mut rng = StdRng::seed_from_u64(17);
535        let bounds = ContractBounds::SingleContract {
536            id: Identifier::from([0x77u8; 32]),
537        };
538        let (k, _priv) = IdentityPublicKey::random_key_with_known_attributes(
539            42,
540            &mut rng,
541            Purpose::TRANSFER,
542            SecurityLevel::CRITICAL,
543            KeyType::ECDSA_SECP256K1,
544            Some(bounds.clone()),
545            LATEST_PLATFORM_VERSION,
546        )
547        .expect("expected key");
548        assert_eq!(k.id(), 42);
549        assert_eq!(k.purpose(), Purpose::TRANSFER);
550        assert_eq!(k.security_level(), SecurityLevel::CRITICAL);
551        assert_eq!(k.key_type(), KeyType::ECDSA_SECP256K1);
552        assert_eq!(k.contract_bounds(), Some(&bounds));
553    }
554}