Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(platform): replace bls library #2257

Open
wants to merge 18 commits into
base: v1.7-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1,436 changes: 815 additions & 621 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions packages/rs-dpp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ dashcore = { git = "https://github.com/dashpay/rust-dashcore", features = [
"rand",
"signer",
"serde",
"bls",
"eddsa",
], default-features = false, tag = "0.32.0" }
], default-features = false, tag = "0.34.0" }
env_logger = { version = "0.11" }
getrandom = { version = "0.2", features = ["js"] }
hex = { version = "0.4" }
Expand Down Expand Up @@ -60,7 +58,7 @@ derive_more = { version = "1.0", features = ["from", "display", "try_into"] }
nohash-hasher = "0.2.0"
rust_decimal = "1.29.1"
rust_decimal_macros = "1.29.1"
indexmap = { version = "2.0.2", features = ["serde"] }
indexmap = { version = "2.7.0", features = ["serde"] }
strum = { version = "0.26", features = ["derive"] }
json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator' }
once_cell = "1.19.0"
Expand Down
74 changes: 53 additions & 21 deletions packages/rs-dpp/src/bls/native_bls.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::bls_signatures::{
Bls12381G2Impl, Pairing, PublicKey, SecretKey, Signature, SignatureSchemes,
};
use crate::{BlsModule, ProtocolError, PublicKeyValidationError};
use anyhow::anyhow;
use dashcore::bls_signatures::{self, PrivateKey, PublicKey};
use std::array::TryFromSliceError;

Check warning on line 5 in packages/rs-dpp/src/bls/native_bls.rs

View workflow job for this annotation

GitHub Actions / Rust packages (dpp) / Linting

unused import: `std::array::TryFromSliceError`

warning: unused import: `std::array::TryFromSliceError` --> packages/rs-dpp/src/bls/native_bls.rs:5:5 | 5 | use std::array::TryFromSliceError; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check warning on line 5 in packages/rs-dpp/src/bls/native_bls.rs

View workflow job for this annotation

GitHub Actions / Rust packages (dash-sdk) / Linting

unused import: `std::array::TryFromSliceError`

warning: unused import: `std::array::TryFromSliceError` --> packages/rs-dpp/src/bls/native_bls.rs:5:5 | 5 | use std::array::TryFromSliceError; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check warning on line 5 in packages/rs-dpp/src/bls/native_bls.rs

View workflow job for this annotation

GitHub Actions / Rust packages (drive) / Linting

unused import: `std::array::TryFromSliceError`

warning: unused import: `std::array::TryFromSliceError` --> packages/rs-dpp/src/bls/native_bls.rs:5:5 | 5 | use std::array::TryFromSliceError; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check warning on line 5 in packages/rs-dpp/src/bls/native_bls.rs

View workflow job for this annotation

GitHub Actions / Rust packages (wasm-dpp) / Linting

unused import: `std::array::TryFromSliceError`

warning: unused import: `std::array::TryFromSliceError` --> packages/rs-dpp/src/bls/native_bls.rs:5:5 | 5 | use std::array::TryFromSliceError; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check warning on line 5 in packages/rs-dpp/src/bls/native_bls.rs

View workflow job for this annotation

GitHub Actions / Rust packages (drive-abci) / Linting

unused import: `std::array::TryFromSliceError`

warning: unused import: `std::array::TryFromSliceError` --> packages/rs-dpp/src/bls/native_bls.rs:5:5 | 5 | use std::array::TryFromSliceError; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import


#[derive(Default)]
pub struct NativeBlsModule;
impl BlsModule for NativeBlsModule {
fn validate_public_key(&self, pk: &[u8]) -> Result<(), PublicKeyValidationError> {
match PublicKey::from_bytes(pk) {
match PublicKey::<Bls12381G2Impl>::try_from(pk) {
Ok(_) => Ok(()),
Err(e) => Err(PublicKeyValidationError::new(e.to_string())),
}
Expand All @@ -18,31 +20,61 @@
data: &[u8],
public_key: &[u8],
) -> Result<bool, ProtocolError> {
let public_key = PublicKey::from_bytes(public_key).map_err(anyhow::Error::msg)?;
let signature =
bls_signatures::Signature::from_bytes(signature).map_err(anyhow::Error::msg)?;
match public_key.verify(&signature, data) {
true => Ok(true),
// TODO change to specific error type
false => Err(anyhow!("Verification failed").into()),
let public_key = PublicKey::<Bls12381G2Impl>::try_from(public_key)?;
let signature_96_bytes =
signature
.try_into()
.map_err(|_| ProtocolError::BlsSignatureSizeError {
got: signature.len() as u32,
})?;
let Some(g2_element) =
<Bls12381G2Impl as Pairing>::Signature::from_compressed(&signature_96_bytes)
.into_option()
else {
return Ok(false); // We should not error because the signature could be given by an invalid source
};

let signature = Signature::Basic(g2_element);

match signature.verify(&public_key, data) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}

fn private_key_to_public_key(&self, private_key: &[u8]) -> Result<Vec<u8>, ProtocolError> {
let fixed_len_key: [u8; 32] = private_key
.try_into()
.map_err(|_| anyhow!("the BLS private key must be 32 bytes long"))?;
let pk = PrivateKey::from_bytes(&fixed_len_key, false).map_err(anyhow::Error::msg)?;
let public_key = pk.g1_element().map_err(anyhow::Error::msg)?;
let public_key_bytes = public_key.to_bytes().to_vec();
let fixed_len_key: [u8; 32] =
private_key
.try_into()
.map_err(|_| ProtocolError::PrivateKeySizeError {
got: private_key.len() as u32,
})?;
let pk = SecretKey::<Bls12381G2Impl>::from_be_bytes(&fixed_len_key)
.into_option()
.ok_or(ProtocolError::InvalidBLSPrivateKeyError(
"key not valid".to_string(),
))?;
let public_key = pk.public_key();
let public_key_bytes = public_key.0.to_compressed().to_vec();
Ok(public_key_bytes)
}

fn sign(&self, data: &[u8], private_key: &[u8]) -> Result<Vec<u8>, ProtocolError> {
let fixed_len_key: [u8; 32] = private_key
.try_into()
.map_err(|_| anyhow!("the BLS private key must be 32 bytes long"))?;
let pk = PrivateKey::from_bytes(&fixed_len_key, false).map_err(anyhow::Error::msg)?;
Ok(pk.sign(data).to_bytes().to_vec())
let fixed_len_key: [u8; 32] =
private_key
.try_into()
.map_err(|_| ProtocolError::PrivateKeySizeError {
got: private_key.len() as u32,
})?;
let pk = SecretKey::<Bls12381G2Impl>::from_be_bytes(&fixed_len_key)
.into_option()
.ok_or(ProtocolError::InvalidBLSPrivateKeyError(
"key not valid".to_string(),
))?;
Ok(pk
.sign(SignatureSchemes::Basic, data)?
.as_raw_value()
.to_compressed()
.to_vec())
}
}
6 changes: 3 additions & 3 deletions packages/rs-dpp/src/core_types/validator/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::bls_signatures::PublicKey as BlsPublicKey;
use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey};
use crate::core_types::validator::v0::{ValidatorV0, ValidatorV0Getters, ValidatorV0Setters};
use dashcore::{ProTxHash, PubkeyHash};
#[cfg(feature = "core-types-serde-conversion")]
Expand All @@ -25,7 +25,7 @@ impl ValidatorV0Getters for Validator {
}
}

fn public_key(&self) -> &Option<BlsPublicKey> {
fn public_key(&self) -> &Option<BlsPublicKey<Bls12381G2Impl>> {
match self {
Validator::V0(v0) => v0.public_key(),
}
Expand Down Expand Up @@ -75,7 +75,7 @@ impl ValidatorV0Setters for Validator {
}
}

fn set_public_key(&mut self, public_key: Option<BlsPublicKey>) {
fn set_public_key(&mut self, public_key: Option<BlsPublicKey<Bls12381G2Impl>>) {
match self {
Validator::V0(v0) => v0.set_public_key(public_key),
}
Expand Down
29 changes: 18 additions & 11 deletions packages/rs-dpp/src/core_types/validator/v0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dashcore::{ProTxHash, PubkeyHash};
use std::fmt::{Debug, Formatter};

use crate::bls_signatures::PublicKey as BlsPublicKey;
use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey};
#[cfg(feature = "core-types-serde-conversion")]
use serde::{Deserialize, Serialize};

Expand All @@ -26,7 +26,7 @@ pub struct ValidatorV0 {
/// The proTxHash
pub pro_tx_hash: ProTxHash,
/// The public key share of this validator for this quorum
pub public_key: Option<BlsPublicKey>,
pub public_key: Option<BlsPublicKey<Bls12381G2Impl>>,
QuantumExplorer marked this conversation as resolved.
Show resolved Hide resolved
/// The node address
pub node_ip: String,
/// The node id
Expand Down Expand Up @@ -54,7 +54,7 @@ impl Encode for ValidatorV0 {
match &self.public_key {
Some(public_key) => {
true.encode(encoder)?; // Indicate that public_key is present
public_key.to_bytes().encode(encoder)?;
public_key.0.to_compressed().encode(encoder)?;
}
None => {
false.encode(encoder)?; // Indicate that public_key is not present
Expand Down Expand Up @@ -94,9 +94,12 @@ impl Decode for ValidatorV0 {
let has_public_key = bool::decode(decoder)?;
let public_key = if has_public_key {
let public_key_bytes = <[u8; 48]>::decode(decoder)?;
Some(BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
})?)

Some(
BlsPublicKey::try_from(public_key_bytes.as_slice()).map_err(|_| {
DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
})?,
)
} else {
None
};
Expand Down Expand Up @@ -150,7 +153,7 @@ pub trait ValidatorV0Getters {
/// Returns the proTxHash of the validator.
fn pro_tx_hash(&self) -> &ProTxHash;
/// Returns the public key share of this validator for this quorum.
fn public_key(&self) -> &Option<BlsPublicKey>;
fn public_key(&self) -> &Option<BlsPublicKey<Bls12381G2Impl>>;
/// Returns the node address of the validator.
fn node_ip(&self) -> &String;
/// Returns the node id of the validator.
Expand All @@ -170,7 +173,7 @@ pub trait ValidatorV0Setters {
/// Sets the proTxHash of the validator.
fn set_pro_tx_hash(&mut self, pro_tx_hash: ProTxHash);
/// Sets the public key share of this validator for this quorum.
fn set_public_key(&mut self, public_key: Option<BlsPublicKey>);
fn set_public_key(&mut self, public_key: Option<BlsPublicKey<Bls12381G2Impl>>);
/// Sets the node address of the validator.
fn set_node_ip(&mut self, node_ip: String);
/// Sets the node id of the validator.
Expand All @@ -190,7 +193,7 @@ impl ValidatorV0Getters for ValidatorV0 {
&self.pro_tx_hash
}

fn public_key(&self) -> &Option<BlsPublicKey> {
fn public_key(&self) -> &Option<BlsPublicKey<Bls12381G2Impl>> {
&self.public_key
}

Expand Down Expand Up @@ -224,7 +227,7 @@ impl ValidatorV0Setters for ValidatorV0 {
self.pro_tx_hash = pro_tx_hash;
}

fn set_public_key(&mut self, public_key: Option<BlsPublicKey>) {
fn set_public_key(&mut self, public_key: Option<BlsPublicKey<Bls12381G2Impl>>) {
self.public_key = public_key;
}

Expand Down Expand Up @@ -257,12 +260,16 @@ impl ValidatorV0Setters for ValidatorV0 {
mod tests {
use super::*;
use bincode::config;
use dashcore::blsful::SecretKey;
use rand::prelude::StdRng;
use rand::SeedableRng;

#[test]
fn test_serialize_deserialize_validator_v0() {
// Sample data for testing
let pro_tx_hash = ProTxHash::from_slice(&[1; 32]).unwrap();
let public_key = Some(BlsPublicKey::generate());
let mut rng = StdRng::seed_from_u64(0);
let public_key = Some(SecretKey::<Bls12381G2Impl>::random(&mut rng).public_key());
let node_ip = "127.0.0.1".to_string();
let node_id = PubkeyHash::from_slice(&[3; 20]).unwrap();
let core_port = 9999;
Expand Down
6 changes: 3 additions & 3 deletions packages/rs-dpp/src/core_types/validator_set/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::bls_signatures::PublicKey as BlsPublicKey;
use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey};
use crate::core_types::validator::v0::ValidatorV0;
QuantumExplorer marked this conversation as resolved.
Show resolved Hide resolved
use crate::core_types::validator_set::v0::{
ValidatorSetV0, ValidatorSetV0Getters, ValidatorSetV0Setters,
Expand Down Expand Up @@ -80,7 +80,7 @@ impl ValidatorSetV0Getters for ValidatorSet {
}
}

fn threshold_public_key(&self) -> &BlsPublicKey {
fn threshold_public_key(&self) -> &BlsPublicKey<Bls12381G2Impl> {
match self {
ValidatorSet::V0(v0) => v0.threshold_public_key(),
}
Expand Down Expand Up @@ -112,7 +112,7 @@ impl ValidatorSetV0Setters for ValidatorSet {
}
}

fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey) {
fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey<Bls12381G2Impl>) {
match self {
ValidatorSet::V0(v0) => v0.set_threshold_public_key(threshold_public_key),
}
Expand Down
45 changes: 28 additions & 17 deletions packages/rs-dpp/src/core_types/validator_set/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use bincode::enc::Encoder;
use bincode::error::EncodeError;
#[cfg(feature = "core-types-serialization")]
use bincode::{BorrowDecode, Decode, Encode};
use dashcore::blsful::Bls12381G2Impl;
use dashcore::hashes::Hash;
use dashcore::{ProTxHash, QuorumHash};
use itertools::Itertools;
Expand All @@ -34,7 +35,7 @@ pub struct ValidatorSetV0 {
/// The list of masternodes
pub members: BTreeMap<ProTxHash, ValidatorV0>,
/// The threshold quorum public key
pub threshold_public_key: BlsPublicKey,
pub threshold_public_key: BlsPublicKey<Bls12381G2Impl>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should define type BlsPublicKey = ... to simplify code and avoid breaking changes in future?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but it will work only in case if we have abstraction on top of implementation.

}

impl Display for ValidatorSetV0 {
Expand All @@ -61,7 +62,7 @@ impl Display for ValidatorSetV0 {
pro_tx_hash, validator.node_ip
))
.join(", "),
hex::encode(self.threshold_public_key.to_bytes().as_slice()) // Assuming BlsPublicKey is a byte array
hex::encode(self.threshold_public_key.0.to_compressed()) // Assuming BlsPublicKey is a byte array
QuantumExplorer marked this conversation as resolved.
Show resolved Hide resolved
)
}
}
Expand All @@ -85,7 +86,7 @@ impl Encode for ValidatorSetV0 {

// Custom encoding for BlsPublicKey if needed
// Assuming BlsPublicKey can be serialized to a byte slice
let public_key_bytes = *self.threshold_public_key.to_bytes();
let public_key_bytes = self.threshold_public_key.0.to_compressed();
QuantumExplorer marked this conversation as resolved.
Show resolved Hide resolved
public_key_bytes.encode(encoder)?;

Ok(())
Expand Down Expand Up @@ -118,9 +119,13 @@ impl Decode for ValidatorSetV0 {
let mut public_key_bytes = [0u8; 48];
let bytes = <[u8; 48]>::decode(decoder)?;
public_key_bytes.copy_from_slice(&bytes);
let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
bincode::error::DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
})?;
let threshold_public_key =
BlsPublicKey::try_from(public_key_bytes.as_slice()).map_err(|e| {
bincode::error::DecodeError::OtherString(format!(
"Failed to decode BlsPublicKey: {}",
e
))
})?;

Ok(ValidatorSetV0 {
quorum_hash: QuorumHash::from_byte_array(quorum_hash),
Expand Down Expand Up @@ -162,11 +167,13 @@ impl<'de> BorrowDecode<'de> for ValidatorSetV0 {
let mut public_key_bytes = [0u8; 48];
let bytes = <[u8; 48]>::decode(decoder)?;
public_key_bytes.copy_from_slice(&bytes);
let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
bincode::error::DecodeError::OtherString(
"Failed to decode BlsPublicKey in borrow decode".to_string(),
)
})?;
let threshold_public_key =
BlsPublicKey::try_from(public_key_bytes.as_slice()).map_err(|e| {
bincode::error::DecodeError::OtherString(format!(
"Failed to decode BlsPublicKey in borrow decode: {}",
e
))
})?;

Ok(ValidatorSetV0 {
quorum_hash: QuorumHash::from_byte_array(quorum_hash),
Expand Down Expand Up @@ -211,7 +218,7 @@ pub trait ValidatorSetV0Getters {
/// Returns the members of the validator set.
fn members_owned(self) -> BTreeMap<ProTxHash, ValidatorV0>;
/// Returns the threshold public key of the validator set.
fn threshold_public_key(&self) -> &BlsPublicKey;
fn threshold_public_key(&self) -> &BlsPublicKey<Bls12381G2Impl>;
}

/// Trait providing setter methods for `ValidatorSetV0` struct
Expand All @@ -225,7 +232,7 @@ pub trait ValidatorSetV0Setters {
/// Sets the members of the validator set.
fn set_members(&mut self, members: BTreeMap<ProTxHash, ValidatorV0>);
/// Sets the threshold public key of the validator set.
fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey);
fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey<Bls12381G2Impl>);
}

impl ValidatorSetV0Getters for ValidatorSetV0 {
Expand Down Expand Up @@ -253,7 +260,7 @@ impl ValidatorSetV0Getters for ValidatorSetV0 {
self.members
}

fn threshold_public_key(&self) -> &BlsPublicKey {
fn threshold_public_key(&self) -> &BlsPublicKey<Bls12381G2Impl> {
&self.threshold_public_key
}
}
Expand All @@ -275,7 +282,7 @@ impl ValidatorSetV0Setters for ValidatorSetV0 {
self.members = members;
}

fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey) {
fn set_threshold_public_key(&mut self, threshold_public_key: BlsPublicKey<Bls12381G2Impl>) {
self.threshold_public_key = threshold_public_key;
}
}
Expand All @@ -284,7 +291,10 @@ impl ValidatorSetV0Setters for ValidatorSetV0 {
mod tests {
use super::*;
use bincode::config;
use dashcore::blsful::SecretKey;
use dashcore::PubkeyHash;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::collections::BTreeMap;

#[test]
Expand All @@ -296,7 +306,8 @@ mod tests {

// Create a sample ProTxHash and ValidatorV0 instance
let pro_tx_hash = ProTxHash::from_slice(&[2; 32]).unwrap();
let public_key = Some(BlsPublicKey::generate());
let mut rng = StdRng::seed_from_u64(0);
let public_key = Some(SecretKey::<Bls12381G2Impl>::random(&mut rng).public_key());
let node_ip = "192.168.1.1".to_string();
let node_id = PubkeyHash::from_slice(&[4; 20]).unwrap();
let validator = ValidatorV0 {
Expand All @@ -315,7 +326,7 @@ mod tests {
members.insert(pro_tx_hash, validator);

// Create a sample threshold public key
let threshold_public_key = BlsPublicKey::generate();
let threshold_public_key = SecretKey::<Bls12381G2Impl>::random(&mut rng).public_key();

// Create the ValidatorSetV0 instance
let validator_set = ValidatorSetV0 {
Expand Down
Loading
Loading