dpp/identity/identity_public_key/v0/methods/
mod.rs

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::Bytes20;
14#[cfg(feature = "bls-signatures")]
15use {crate::bls_signatures, dashcore::blsful::Bls12381G2Impl};
16impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKeyV0 {
17    /// Get the original public key hash
18    fn public_key_hash(&self) -> Result<[u8; 20], ProtocolError> {
19        if self.data.is_empty() {
20            return Err(ProtocolError::EmptyPublicKeyDataError);
21        }
22
23        match self.key_type {
24            KeyType::ECDSA_SECP256K1 => {
25                let key = match self.data.len() {
26                    // TODO: We need to update schema and tests for 65 len keys
27                    65 | 33 => ECDSAPublicKey::from_slice(self.data.as_slice())
28                        .map_err(|e| anyhow!("unable to create pub key - {}", e))?,
29                    _ => {
30                        return Err(ProtocolError::ParsingError(format!(
31                            "the key length is invalid: {} Allowed sizes: 33 or 65 bytes for ecdsa key",
32                            self.data.len()
33                        )));
34                    }
35                };
36                Ok(key.pubkey_hash().to_byte_array())
37            }
38            KeyType::BLS12_381 => {
39                if self.data.len() != 48 {
40                    Err(ProtocolError::ParsingError(format!(
41                        "the key length is invalid: {} Allowed sizes: 48 bytes for bls key",
42                        self.data.len()
43                    )))
44                } else {
45                    Ok(ripemd160_sha256(self.data.as_slice()))
46                }
47            }
48            KeyType::ECDSA_HASH160 | KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => {
49                Ok(Bytes20::from_vec(self.data.to_vec())?.into_buffer())
50            }
51        }
52    }
53
54    fn validate_private_key_bytes(
55        &self,
56        private_key_bytes: &[u8; 32],
57        network: Network,
58    ) -> Result<bool, ProtocolError> {
59        match self.key_type {
60            KeyType::ECDSA_SECP256K1 => {
61                let secp = Secp256k1::new();
62                let secret_key = match SecretKey::from_byte_array(private_key_bytes) {
63                    Ok(secret_key) => secret_key,
64                    Err(_) => return Ok(false),
65                };
66                let private_key = dashcore::PrivateKey::new(secret_key, network);
67
68                Ok(private_key.public_key(&secp).to_bytes() == self.data.as_slice())
69            }
70            KeyType::BLS12_381 => {
71                #[cfg(feature = "bls-signatures")]
72                {
73                    let private_key: Option<bls_signatures::SecretKey<Bls12381G2Impl>> =
74                        bls_signatures::SecretKey::<Bls12381G2Impl>::from_be_bytes(
75                            private_key_bytes,
76                        )
77                        .into();
78                    if private_key.is_none() {
79                        return Ok(false);
80                    }
81                    let private_key = private_key.expect("expected private key");
82
83                    Ok(private_key.public_key().0.to_compressed() == self.data.as_slice())
84                }
85                #[cfg(not(feature = "bls-signatures"))]
86                return Err(ProtocolError::NotSupported(
87                    "Converting a private key to a bls public key is not supported without the bls-signatures feature".to_string(),
88                ));
89            }
90            KeyType::ECDSA_HASH160 => {
91                let secp = Secp256k1::new();
92                let secret_key = match SecretKey::from_byte_array(private_key_bytes) {
93                    Ok(secret_key) => secret_key,
94                    Err(_) => return Ok(false),
95                };
96                let private_key = dashcore::PrivateKey::new(secret_key, network);
97
98                Ok(
99                    ripemd160_sha256(private_key.public_key(&secp).to_bytes().as_slice())
100                        .as_slice()
101                        == self.data.as_slice(),
102                )
103            }
104            KeyType::EDDSA_25519_HASH160 => {
105                #[cfg(feature = "ed25519-dalek")]
106                {
107                    let key_pair = ed25519_dalek::SigningKey::from_bytes(private_key_bytes);
108                    Ok(
109                        ripemd160_sha256(key_pair.verifying_key().to_bytes().as_slice()).as_slice()
110                            == self.data.as_slice(),
111                    )
112                }
113                #[cfg(not(feature = "ed25519-dalek"))]
114                return Err(ProtocolError::NotSupported(
115                    "Converting a private key to a eddsa hash 160 is not supported without the ed25519-dalek feature".to_string(),
116                ));
117            }
118            KeyType::BIP13_SCRIPT_HASH => Err(ProtocolError::NotSupported(
119                "Converting a private key to a script hash is not supported".to_string(),
120            )),
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128    use crate::identity::{Purpose, SecurityLevel};
129    use dashcore::blsful::{Bls12381G2Impl, Pairing, Signature, SignatureSchemes};
130    use dashcore::Network;
131    use dpp::version::PlatformVersion;
132    use rand::rngs::StdRng;
133    use rand::SeedableRng;
134
135    #[test]
136    fn test_bls_serialization_deserialization() {
137        let mut rng = StdRng::seed_from_u64(5);
138        let (public_key_data, secret_key) = KeyType::BLS12_381
139            .random_public_and_private_key_data(&mut rng, PlatformVersion::latest())
140            .expect("expected to get keys");
141        let decoded_secret_key =
142            dashcore::blsful::SecretKey::<Bls12381G2Impl>::from_be_bytes(&secret_key)
143                .expect("expected to get secret key");
144        let public_key = decoded_secret_key.public_key();
145        let decoded_public_key_data = public_key.0.to_compressed();
146        assert_eq!(
147            public_key_data.as_slice(),
148            decoded_public_key_data.as_slice()
149        )
150    }
151
152    #[test]
153    fn test_bls_serialization_deserialization_signature() {
154        let mut rng = StdRng::seed_from_u64(5);
155        let (_, secret_key) = KeyType::BLS12_381
156            .random_public_and_private_key_data(&mut rng, PlatformVersion::latest())
157            .expect("expected to get keys");
158        let decoded_secret_key =
159            dashcore::blsful::SecretKey::<Bls12381G2Impl>::from_be_bytes(&secret_key)
160                .expect("expected to get secret key");
161        let signature = decoded_secret_key
162            .sign(SignatureSchemes::Basic, b"hello")
163            .expect("expected to sign");
164        let compressed = signature.as_raw_value().to_compressed();
165        let g2 = <Bls12381G2Impl as Pairing>::Signature::from_compressed(&compressed)
166            .expect("G2 projective");
167        let decoded_signature = Signature::<Bls12381G2Impl>::Basic(g2);
168        assert_eq!(
169            compressed.as_slice(),
170            decoded_signature.as_raw_value().to_compressed().as_slice()
171        )
172    }
173
174    #[cfg(feature = "random-public-keys")]
175    #[test]
176    fn test_validate_private_key_bytes_with_random_keys() {
177        let platform_version = PlatformVersion::latest();
178        let mut rng = StdRng::from_entropy();
179
180        // Test for ECDSA_SECP256K1
181        let key_type = KeyType::ECDSA_SECP256K1;
182        let (public_key_data, private_key_data) = key_type
183            .random_public_and_private_key_data(&mut rng, platform_version)
184            .expect("expected to generate random keys");
185
186        let identity_public_key = IdentityPublicKeyV0 {
187            id: 1,
188            purpose: Purpose::AUTHENTICATION,
189            security_level: SecurityLevel::HIGH,
190            contract_bounds: None,
191            key_type,
192            data: public_key_data.into(),
193            read_only: false,
194            disabled_at: None,
195        };
196
197        // Validate that the private key matches the public key
198        assert!(identity_public_key
199            .validate_private_key_bytes(&private_key_data, Network::Testnet)
200            .unwrap(),);
201
202        // Test with an invalid private key
203        let invalid_private_key_bytes = [0u8; 32];
204        assert!(!identity_public_key
205            .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
206            .unwrap());
207    }
208
209    #[cfg(all(feature = "random-public-keys", feature = "bls-signatures"))]
210    #[test]
211    fn test_validate_private_key_bytes_with_random_keys_bls12_381() {
212        let platform_version = PlatformVersion::latest();
213        let mut rng = StdRng::from_entropy();
214
215        // Test for BLS12_381
216        let key_type = KeyType::BLS12_381;
217        let (public_key_data, private_key_data) = key_type
218            .random_public_and_private_key_data(&mut rng, platform_version)
219            .expect("expected to generate random keys");
220
221        let identity_public_key = IdentityPublicKeyV0 {
222            id: 2,
223            purpose: Purpose::AUTHENTICATION,
224            security_level: SecurityLevel::HIGH,
225            contract_bounds: None,
226            key_type,
227            data: public_key_data.into(),
228            read_only: false,
229            disabled_at: None,
230        };
231
232        // Validate that the private key matches the public key
233        assert!(identity_public_key
234            .validate_private_key_bytes(&private_key_data, Network::Testnet)
235            .unwrap());
236
237        // Test with an invalid private key
238        let invalid_private_key_bytes = [0u8; 32];
239        assert!(!identity_public_key
240            .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
241            .unwrap());
242    }
243
244    #[cfg(all(feature = "random-public-keys", feature = "ed25519-dalek"))]
245    #[test]
246    fn test_validate_private_key_bytes_with_random_keys_eddsa_25519_hash160() {
247        let platform_version = PlatformVersion::latest();
248        let mut rng = StdRng::from_entropy();
249
250        // Test for EDDSA_25519_HASH160
251        let key_type = KeyType::EDDSA_25519_HASH160;
252        let (public_key_data, private_key_data) = key_type
253            .random_public_and_private_key_data(&mut rng, platform_version)
254            .expect("expected to generate random keys");
255
256        let identity_public_key = IdentityPublicKeyV0 {
257            id: 3,
258            purpose: Purpose::AUTHENTICATION,
259            security_level: SecurityLevel::HIGH,
260            contract_bounds: None,
261            key_type,
262            data: public_key_data.into(),
263            read_only: false,
264            disabled_at: None,
265        };
266
267        // Validate that the private key matches the public key
268        assert!(identity_public_key
269            .validate_private_key_bytes(&private_key_data, Network::Testnet)
270            .unwrap());
271
272        // Test with an invalid private key
273        let invalid_private_key_bytes = [0u8; 32];
274        assert!(!identity_public_key
275            .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet)
276            .unwrap());
277    }
278}