Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/rs-dpp/src/core_types/validator/v0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use dashcore::{ProTxHash, PubkeyHash};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::fmt::{Debug, Formatter};

use crate::bls_signatures::PublicKey as BlsPublicKey;
#[cfg(feature = "core-types-serde-conversion")]
Expand Down
7 changes: 6 additions & 1 deletion packages/rs-dpp/src/errors/consensus/basic/basic_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use crate::consensus::basic::identity::{
InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError,
InvalidInstantAssetLockProofError, InvalidInstantAssetLockProofSignatureError,
MissingMasterPublicKeyError, NotImplementedIdentityCreditWithdrawalTransitionPoolingError,
TooManyMasterPublicKeyError,
TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError,
};
use crate::consensus::basic::invalid_identifier_error::InvalidIdentifierError;
use crate::consensus::basic::state_transition::{
Expand Down Expand Up @@ -335,6 +335,11 @@ pub enum BasicError {
InvalidIdentityCreditWithdrawalTransitionOutputScriptError,
),

#[error(transparent)]
WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(
WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError,
),

#[error(transparent)]
InvalidIdentityCreditWithdrawalTransitionCoreFeeError(
InvalidIdentityCreditWithdrawalTransitionCoreFeeError,
Expand Down
2 changes: 2 additions & 0 deletions packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub use invalid_instant_asset_lock_proof_signature_error::*;
pub use missing_master_public_key_error::*;
pub use not_implemented_identity_credit_withdrawal_transition_pooling_error::*;
pub use too_many_master_public_key_error::*;
pub use withdrawal_output_script_not_allowed_when_signing_with_owner_key::*;

mod data_contract_bounds_not_present_error;
mod disabling_key_id_also_being_added_in_same_transition_error;
Expand Down Expand Up @@ -62,3 +63,4 @@ mod invalid_instant_asset_lock_proof_signature_error;
mod missing_master_public_key_error;
mod not_implemented_identity_credit_withdrawal_transition_pooling_error;
mod too_many_master_public_key_error;
mod withdrawal_output_script_not_allowed_when_signing_with_owner_key;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::errors::ProtocolError;
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use thiserror::Error;

use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use crate::identity::core_script::CoreScript;

use crate::identity::KeyID;
use bincode::{Decode, Encode};

#[derive(
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
)]
#[error("Withdrawal output script not allowed when signing with owner key {key_id}")]
#[platform_serialize(unversioned)]
pub struct WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError {
output_script: CoreScript,
key_id: KeyID,
}

/*

DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION

*/

impl WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError {
pub fn new(output_script: CoreScript, key_id: KeyID) -> Self {
Self {
output_script,
key_id,
}
}

pub fn output_script(&self) -> &CoreScript {
&self.output_script
}

pub fn key_id(&self) -> KeyID {
self.key_id
}
}
impl From<WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError> for ConsensusError {
fn from(err: WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError) -> Self {
Self::BasicError(
BasicError::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(err),
)
}
}
1 change: 1 addition & 0 deletions packages/rs-dpp/src/errors/consensus/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ impl ErrorWithCode for BasicError {
Self::MasterPublicKeyUpdateError(_) => 10529,
Self::IdentityAssetLockTransactionOutPointNotEnoughBalanceError(_) => 10530,
Self::IdentityAssetLockStateTransitionReplayError(_) => 10531,
Self::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(_) => 10532,

// State Transition Errors: 10600-10699
Self::InvalidStateTransitionTypeError { .. } => 10600,
Expand Down
24 changes: 17 additions & 7 deletions packages/rs-dpp/src/identity/identity_public_key/purpose.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::identity::Purpose::{AUTHENTICATION, DECRYPTION, ENCRYPTION, SYSTEM, TRANSFER, VOTING};
use crate::identity::Purpose::{
AUTHENTICATION, DECRYPTION, ENCRYPTION, OWNER, SYSTEM, TRANSFER, VOTING,
};
use anyhow::bail;
use bincode::{Decode, Encode};
#[cfg(feature = "cbor")]
Expand Down Expand Up @@ -37,6 +39,8 @@ pub enum Purpose {
SYSTEM = 4,
/// this key cannot be used for signing documents
VOTING = 5,
/// this key is used to prove ownership of a masternode or evonode
OWNER = 6,
}

impl From<Purpose> for [u8; 1] {
Expand All @@ -54,6 +58,7 @@ impl From<Purpose> for &'static [u8; 1] {
TRANSFER => &[3],
SYSTEM => &[4],
VOTING => &[5],
OWNER => &[6],
}
}
}
Expand All @@ -68,6 +73,7 @@ impl TryFrom<u8> for Purpose {
3 => Ok(TRANSFER),
4 => Ok(SYSTEM),
5 => Ok(VOTING),
6 => Ok(OWNER),
value => bail!("unrecognized purpose: {}", value),
}
}
Expand All @@ -83,6 +89,7 @@ impl TryFrom<i32> for Purpose {
3 => Ok(TRANSFER),
4 => Ok(SYSTEM),
5 => Ok(VOTING),
6 => Ok(OWNER),
value => bail!("unrecognized purpose: {}", value),
}
}
Expand All @@ -102,8 +109,15 @@ impl std::fmt::Display for Purpose {

impl Purpose {
/// The full range of purposes
pub fn full_range() -> [Purpose; 5] {
[AUTHENTICATION, ENCRYPTION, DECRYPTION, TRANSFER, VOTING]
pub fn full_range() -> [Purpose; 6] {
[
AUTHENTICATION,
ENCRYPTION,
DECRYPTION,
TRANSFER,
VOTING,
OWNER,
]
}
/// Just the authentication and withdraw purposes
pub fn searchable_purposes() -> [Purpose; 3] {
Expand All @@ -113,8 +127,4 @@ impl Purpose {
pub fn encryption_decryption() -> [Purpose; 2] {
[ENCRYPTION, DECRYPTION]
}
/// The last purpose
pub fn last() -> Purpose {
Self::TRANSFER
}
}
143 changes: 143 additions & 0 deletions packages/rs-dpp/src/identity/identity_public_key/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,149 @@ impl IdentityPublicKey {
}
}

/// Generates a random ECDSA critical-level authentication key for a masternode owner.
///
/// This function generates a random key that can be used for owner authentication in a masternode context.
/// The function accepts an optional seed for deterministic key generation, or uses entropy-based randomness if no seed is provided.
///
/// # Parameters
///
/// * `id`: The identifier (`KeyID`) for the masternode owner key.
/// * `seed`: An optional `u64` value used to seed the random number generator. If `None`, the RNG will be seeded from entropy.
/// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version.
///
/// # Returns
///
/// Returns a tuple containing the generated `IdentityPublicKey` for the masternode owner and the corresponding private key as a byte vector.
///
/// # Errors
///
/// Returns a `ProtocolError` if the platform version is not supported.
pub fn random_masternode_owner_key(
id: KeyID,
seed: Option<u64>,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
let mut rng = match seed {
None => StdRng::from_entropy(),
Some(seed_value) => StdRng::seed_from_u64(seed_value),
};
Self::random_masternode_owner_key_with_rng(id, &mut rng, platform_version)
}

/// Generates a random ECDSA critical-level authentication key for a masternode owner using a custom RNG.
///
/// This function generates a random key using a given random number generator (RNG). This is useful when specific control over the randomness is needed.
///
/// # Parameters
///
/// * `id`: The identifier (`KeyID`) for the masternode owner key.
/// * `rng`: A mutable reference to a `StdRng` instance used to generate randomness.
/// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version.
///
/// # Returns
///
/// Returns a tuple containing the generated `IdentityPublicKey` for the masternode owner and the corresponding private key as a byte vector.
///
/// # Errors
///
/// Returns a `ProtocolError` if the platform version is not supported.
pub fn random_masternode_owner_key_with_rng(
id: KeyID,
rng: &mut StdRng,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
match platform_version
.dpp
.identity_versions
.identity_key_structure_version
{
0 => {
let (key, private_key) =
IdentityPublicKeyV0::random_owner_key_with_rng(id, rng, platform_version)?;
Ok((key.into(), private_key))
}
version => Err(ProtocolError::UnknownVersionMismatch {
method: "IdentityPublicKey::random_masternode_owner_key_with_rng".to_string(),
known_versions: vec![0],
received: version,
}),
}
}

/// Generates a random ECDSA critical-level transfer key for a masternode.
///
/// This function generates a random key for use in transferring ownership of a masternode. An optional seed can be provided for deterministic key generation, or entropy-based randomness is used if no seed is given.
///
/// # Parameters
///
/// * `id`: The identifier (`KeyID`) for the masternode transfer key.
/// * `seed`: An optional `u64` value used to seed the random number generator. If `None`, the RNG will be seeded from entropy.
/// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version.
///
/// # Returns
///
/// Returns a tuple containing the generated `IdentityPublicKey` for the masternode transfer key and the corresponding private key as a byte vector.
///
/// # Errors
///
/// Returns a `ProtocolError` if the platform version is not supported.
pub fn random_masternode_transfer_key(
id: KeyID,
seed: Option<u64>,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
let mut rng = match seed {
None => StdRng::from_entropy(),
Some(seed_value) => StdRng::seed_from_u64(seed_value),
};
Self::random_masternode_transfer_key_with_rng(id, &mut rng, platform_version)
}

/// Generates a random ECDSA critical-level transfer key for a masternode using a custom RNG.
///
/// This function generates a random key for masternode transfers using a given random number generator (RNG).
///
/// # Parameters
///
/// * `id`: The identifier (`KeyID`) for the masternode transfer key.
/// * `rng`: A mutable reference to a `StdRng` instance used to generate randomness.
/// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version.
///
/// # Returns
///
/// Returns a tuple containing the generated `IdentityPublicKey` for the masternode transfer key and the corresponding private key as a byte vector.
///
/// # Errors
///
/// Returns a `ProtocolError` if the platform version is not supported.
pub fn random_masternode_transfer_key_with_rng(
id: KeyID,
rng: &mut StdRng,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
match platform_version
.dpp
.identity_versions
.identity_key_structure_version
{
0 => {
let (key, private_key) =
IdentityPublicKeyV0::random_masternode_transfer_key_with_rng(
id,
rng,
platform_version,
)?;
Ok((key.into(), private_key))
}
version => Err(ProtocolError::UnknownVersionMismatch {
method: "IdentityPublicKey::random_masternode_transfer_key_with_rng".to_string(),
known_versions: vec![0],
received: version,
}),
}
}

/// Generates a random ECDSA high-level authentication public key along with its corresponding private key.
///
/// This method constructs a random ECDSA (using the secp256k1 curve) high-level authentication public key
Expand Down
54 changes: 53 additions & 1 deletion packages/rs-dpp/src/identity/identity_public_key/v0/random.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::identity::contract_bounds::ContractBounds;
use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
use crate::identity::KeyType::{ECDSA_HASH160, ECDSA_SECP256K1};
use crate::identity::Purpose::{AUTHENTICATION, VOTING};
use crate::identity::Purpose::{AUTHENTICATION, OWNER, TRANSFER, VOTING};
use crate::identity::SecurityLevel::{CRITICAL, HIGH, MASTER, MEDIUM};
use crate::identity::{KeyCount, KeyID, KeyType, Purpose, SecurityLevel};
use crate::version::PlatformVersion;
Expand Down Expand Up @@ -245,6 +245,58 @@ impl IdentityPublicKeyV0 {
))
}

pub fn random_owner_key_with_rng(
id: KeyID,
rng: &mut StdRng,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
let key_type = ECDSA_HASH160;
let purpose = OWNER;
let security_level = CRITICAL;
let read_only = true;
let (data, private_data) =
key_type.random_public_and_private_key_data(rng, platform_version)?;
Ok((
IdentityPublicKeyV0 {
id,
key_type,
purpose,
security_level,
read_only,
disabled_at: None,
data: data.into(),
contract_bounds: None,
},
private_data,
))
}

pub fn random_masternode_transfer_key_with_rng(
id: KeyID,
rng: &mut StdRng,
platform_version: &PlatformVersion,
) -> Result<(Self, Vec<u8>), ProtocolError> {
let key_type = ECDSA_HASH160;
let purpose = TRANSFER;
let security_level = CRITICAL;
let read_only = true;
let (data, private_data) =
key_type.random_public_and_private_key_data(rng, platform_version)?;
Ok((
IdentityPublicKeyV0 {
id,
key_type,
purpose,
security_level,
read_only,
disabled_at: None,
data: data.into(),
contract_bounds: None,
},
private_data,
))
}

pub fn random_ecdsa_critical_level_authentication_key_with_rng(
id: KeyID,
rng: &mut StdRng,
Expand Down
Loading
Loading