From 53cae4bbaee21a88dd21b350edae73ead9df76b1 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 08:00:42 +0000 Subject: [PATCH 01/11] test(dpp): freeze BLS backend compatibility vectors Record signatures, secure aggregates, scalar boundary behavior, key generation and persisted validator bytes before replacing the BLS implementation. All eight compatibility tests pass on the original backend. Co-authored-by: Codex --- Cargo.lock | 1 + packages/rs-dpp/Cargo.toml | 2 + .../generate_bls_compatibility_vectors.rs | 146 +++++++ packages/rs-dpp/tests/bls_compatibility.rs | 358 ++++++++++++++++++ .../fixtures/bls_compatibility/README.md | 35 ++ .../fixtures/bls_compatibility/vectors.json | 328 ++++++++++++++++ 6 files changed, 870 insertions(+) create mode 100644 packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs create mode 100644 packages/rs-dpp/tests/bls_compatibility.rs create mode 100644 packages/rs-dpp/tests/fixtures/bls_compatibility/README.md create mode 100644 packages/rs-dpp/tests/fixtures/bls_compatibility/vectors.json diff --git a/Cargo.lock b/Cargo.lock index 90b2dc07644..79739cf0e44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2334,6 +2334,7 @@ dependencies = [ "chrono", "chrono-tz", "ciborium", + "dash-pkc", "dash-spv", "dashcore", "dashcore-rpc", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 1e74169571d..55ed2d601f4 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -81,6 +81,8 @@ tracing = { version = "0.1.41" } grovedb-commitment-tree = { workspace = true, optional = true } [dev-dependencies] +# Compare BLS behavior with the exact backend used by the pinned rust-dashcore. +dash-pkc = { git = "https://github.com/dashpay/base-sdk", rev = "e6402ced257c370a586ade9840ebbf545a4b7926", default-features = false, features = ["bls"] } tokio = { version = "1.40", features = ["full"] } pretty_assertions = { version = "1.4.1" } dpp = { path = ".", default-features = false, features = [ diff --git a/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs new file mode 100644 index 00000000000..d1449a97b4b --- /dev/null +++ b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs @@ -0,0 +1,146 @@ +//! Emit deterministic compatibility fixtures from DPP's current BLS backend. +//! Run with `cargo run -p dpp --example generate_bls_compatibility_vectors`. + +use dpp::bls_signatures::{ + AggregateSignature, Bls12381G2Impl, PublicKey, SecretKey, SerializationFormat, SignatureSchemes, +}; +use dpp::core_types::validator::v0::ValidatorV0; +use dpp::core_types::validator_set::v0::ValidatorSetV0; +use dpp::dashcore::{hashes::Hash, ProTxHash, PubkeyHash, QuorumHash}; +use serde_json::json; +use std::collections::BTreeMap; + +fn main() { + let key_generation: Vec<_> = [[0u8; 32], [1; 32], [255; 32]].iter().map(|ikm| { + let key = SecretKey::::from_hash(ikm); + json!({"ikm": hex::encode(ikm), "secret_key": hex::encode(key.to_be_bytes()), "public_key": hex::encode(key.public_key().0.to_compressed())}) + }).collect(); + // Public test material: unit scalars, asymmetric bytes and the last canonical scalar. + let keys: Vec<[u8; 32]> = [ + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + ] + .iter() + .map(|s| hex::decode(s).unwrap().try_into().unwrap()) + .collect(); + let mut basic = Vec::new(); + for bytes in &keys { + let key = SecretKey::::from_be_bytes(bytes).unwrap(); + for message in [ + vec![], + b"Dash Platform BLS compatibility".to_vec(), + vec![0; 32], + (0..=255).collect(), + ] { + let signature = key.sign(SignatureSchemes::Basic, &message).unwrap(); + basic.push(json!({ + "secret_key": hex::encode(bytes), "message": hex::encode(message), + "public_key": hex::encode(key.public_key().0.to_compressed()), + "legacy_public_key": hex::encode(key.public_key().to_bytes_with_mode(SerializationFormat::Legacy)), + "signature": hex::encode(signature.as_raw_value().to_compressed()) + })); + } + } + let mut secure_aggregation = Vec::new(); + for indexes in [ + vec![0], + vec![0, 1], + vec![0, 1, 2], + vec![2, 0, 1], + vec![0, 0], + ] { + let message = b"Dash Platform secure aggregation"; + let signers: Vec<_> = indexes + .iter() + .map(|&i| SecretKey::::from_be_bytes(&keys[i]).unwrap()) + .collect(); + let public_keys: Vec<_> = signers.iter().map(|key| key.public_key()).collect(); + let signatures: Vec<_> = signers + .iter() + .map(|key| key.sign(SignatureSchemes::Basic, message).unwrap()) + .collect(); + let AggregateSignature::Basic(point) = + AggregateSignature::from_signatures_secure(&signatures, &public_keys).unwrap() + else { + panic!("expected Basic signature"); + }; + secure_aggregation.push(json!({ + "secret_keys": indexes.iter().map(|&i| hex::encode(keys[i])).collect::>(), + "message": hex::encode(message), + "public_keys": public_keys.iter().map(|key| hex::encode(key.0.to_compressed())).collect::>(), + "signature": hex::encode(point.to_compressed()) + })); + } + let mut scalars = Vec::new(); + for (name, bytes) in [ + ("zero", [0; 32]), + ( + "order", + hex::decode("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001") + .unwrap() + .try_into() + .unwrap(), + ), + ( + "order_plus_one", + hex::decode("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002") + .unwrap() + .try_into() + .unwrap(), + ), + ("max", [255; 32]), + ] { + let key = SecretKey::::from_be_bytes(&bytes).into_option(); + scalars.push(json!({ + "name": name, "input": hex::encode(bytes), + "normalized": key.as_ref().map(|key| hex::encode(key.to_be_bytes())), + "public_key": key.as_ref().map(|key| hex::encode(key.public_key().0.to_compressed())), + "signature": key.as_ref().map(|key| hex::encode(key.sign(SignatureSchemes::Basic, b"scalar boundary").unwrap().as_raw_value().to_compressed())) + })); + } + let mut infinity = [0; 48]; + infinity[0] = 0xc0; + let public_key = SecretKey::::from_be_bytes(&keys[0]) + .unwrap() + .public_key(); + let mut storage = Vec::new(); + for (name, key) in [ + ("public_key", Some(public_key)), + ("absent", None), + ( + "infinity", + Some(PublicKey::try_from(infinity.as_slice()).unwrap()), + ), + ] { + let validator = ValidatorV0 { + pro_tx_hash: ProTxHash::from_byte_array([0x11; 32]), + public_key: key, + node_ip: "127.0.0.1".into(), + node_id: PubkeyHash::from_byte_array([0x22; 20]), + core_port: 19999, + platform_http_port: 1443, + platform_p2p_port: 26656, + is_banned: false, + }; + let config = bincode::config::standard().with_big_endian(); + let set = ValidatorSetV0 { + quorum_hash: QuorumHash::from_byte_array([0x33; 32]), + quorum_index: Some(2), + core_height: 123456, + members: BTreeMap::from([(validator.pro_tx_hash, validator.clone())]), + threshold_public_key: public_key, + }; + storage.push(json!({ + "name": name, "validator": serde_json::to_value(&validator).unwrap(), + "validator_bytes": hex::encode(bincode::encode_to_vec(&validator, config).unwrap()), + "validator_set": serde_json::to_value(&set).unwrap(), + "validator_set_bytes": hex::encode(bincode::encode_to_vec(&set, config).unwrap()) + })); + } + println!("{}", serde_json::to_string_pretty(&json!({ + "basic": basic, "secure_aggregation": secure_aggregation, "scalars": scalars, "storage": storage, + "key_generation": key_generation + })).unwrap()); +} diff --git a/packages/rs-dpp/tests/bls_compatibility.rs b/packages/rs-dpp/tests/bls_compatibility.rs new file mode 100644 index 00000000000..e37a11fa86b --- /dev/null +++ b/packages/rs-dpp/tests/bls_compatibility.rs @@ -0,0 +1,358 @@ +use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature}; +use dpp::bls_signatures::{ + AggregateSignature, Bls12381G2Impl, Pairing, PublicKey, SecretKey, Signature, SignatureSchemes, +}; +use dpp::core_types::validator::v0::ValidatorV0; +use dpp::core_types::validator_set::v0::ValidatorSetV0; +use dpp::native_bls::NativeBlsModule; +use dpp::{BlsModule, ProtocolError}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Corpus { + key_generation: Vec, + basic: Vec, + secure_aggregation: Vec, + scalars: Vec, + storage: Vec, +} + +#[derive(Deserialize)] +struct KeyGeneration { + ikm: String, + secret_key: String, + public_key: String, +} + +#[derive(Deserialize)] +struct Basic { + secret_key: String, + message: String, + public_key: String, + legacy_public_key: String, + signature: String, +} + +#[derive(Deserialize)] +struct Aggregate { + secret_keys: Vec, + message: String, + public_keys: Vec, + signature: String, +} + +#[derive(Deserialize)] +struct Scalar { + name: String, + input: String, + normalized: Option, + public_key: Option, + signature: Option, +} + +#[derive(Deserialize)] +struct Storage { + name: String, + validator: serde_json::Value, + validator_bytes: String, + validator_set: serde_json::Value, + validator_set_bytes: String, +} + +fn corpus() -> Corpus { + serde_json::from_str(include_str!("fixtures/bls_compatibility/vectors.json")).unwrap() +} + +fn bytes(hex: &str) -> [u8; N] { + hex::decode(hex).unwrap().try_into().unwrap() +} + +#[test] +fn should_preserve_key_generation_from_fixed_material() { + let vectors = corpus().key_generation; + assert_eq!(vectors.len(), 3); + for v in vectors { + let ikm = bytes::<32>(&v.ikm); + let current = SecretKey::::from_hash(ikm); + let candidate = BlsSecretKey::::from_ikm(&ikm).unwrap(); + assert_eq!(current.to_be_bytes(), bytes::<32>(&v.secret_key)); + assert_eq!(*candidate.to_bytes(), current.to_be_bytes()); + assert_eq!( + current.public_key().0.to_compressed(), + bytes::<48>(&v.public_key) + ); + assert_eq!( + candidate.public_key().to_bytes(), + bytes::<48>(&v.public_key) + ); + } +} + +#[test] +fn should_match_frozen_basic_signatures_in_both_backends() { + let vectors = corpus().basic; + assert_eq!(vectors.len(), 16); + for v in vectors { + let secret = bytes(&v.secret_key); + let message = hex::decode(v.message).unwrap(); + let public: [u8; 48] = bytes(&v.public_key); + let signature: [u8; 96] = bytes(&v.signature); + assert_eq!( + NativeBlsModule.private_key_to_public_key(&secret).unwrap(), + public + ); + assert_eq!(NativeBlsModule.sign(&message, &secret).unwrap(), signature); + assert!(NativeBlsModule + .verify_signature(&signature, &message, &public) + .unwrap()); + let candidate = BlsSecretKey::::from_bytes(&secret).unwrap(); + assert_eq!(candidate.public_key().to_bytes(), public); + assert_eq!(candidate.sign(&message).to_bytes(), signature); + let decoded = BlsSignature::::from_bytes(&signature).unwrap(); + assert!(candidate.public_key().verify(&message, &decoded).is_ok()); + assert_eq!( + candidate + .public_key() + .to_scheme::() + .unwrap() + .to_bytes(), + bytes::<48>(&v.legacy_public_key) + ); + let mut wrong_message = message.clone(); + wrong_message.push(1); + assert!(!NativeBlsModule + .verify_signature(&signature, &wrong_message, &public) + .unwrap()); + assert!(candidate + .public_key() + .verify(&wrong_message, &decoded) + .is_err()); + let mut other_secret = [0; 32]; + other_secret[31] = 3; + let other = BlsSecretKey::::from_bytes(&other_secret) + .unwrap() + .public_key(); + assert!(!NativeBlsModule + .verify_signature(&signature, &message, &other.to_bytes()) + .unwrap()); + assert!(other.verify(&message, &decoded).is_err()); + } +} + +#[test] +fn should_match_frozen_secure_aggregates_in_both_backends() { + let vectors = corpus().secure_aggregation; + assert_eq!(vectors.len(), 5); + for v in vectors { + let message = hex::decode(v.message).unwrap(); + let public_keys: Vec<_> = v + .public_keys + .iter() + .map(|key| PublicKey::::try_from(bytes::<48>(key).as_slice()).unwrap()) + .collect(); + let signatures: Vec<_> = v + .secret_keys + .iter() + .map(|key| { + SecretKey::::from_be_bytes(&bytes(key)) + .unwrap() + .sign(SignatureSchemes::Basic, &message) + .unwrap() + }) + .collect(); + let AggregateSignature::Basic(point) = + AggregateSignature::from_signatures_secure(&signatures, &public_keys).unwrap() + else { + panic!("expected Basic"); + }; + assert_eq!(point.to_compressed(), bytes::<96>(&v.signature)); + assert!(Signature::Basic(point) + .verify_secure(&public_keys, &message) + .is_ok()); + let candidate_keys: Vec<_> = v + .secret_keys + .iter() + .map(|key| BlsSecretKey::::from_bytes(&bytes(key)).unwrap()) + .collect(); + let pks: Vec<_> = candidate_keys.iter().map(|key| key.public_key()).collect(); + let sigs: Vec<_> = candidate_keys + .iter() + .map(|key| key.sign(&message)) + .collect(); + let refs: Vec<_> = pks.iter().collect(); + let candidate = + BlsSignature::secure_aggregate(&sigs.iter().collect::>(), &refs).unwrap(); + assert_eq!(candidate.to_bytes(), bytes::<96>(&v.signature)); + assert!(candidate.secure_verify_aggregates(&message, &refs).is_ok()); + let mut wrong_message = message; + wrong_message.push(1); + assert!(Signature::Basic(point) + .verify_secure(&public_keys, &wrong_message) + .is_err()); + assert!(candidate + .secure_verify_aggregates(&wrong_message, &refs) + .is_err()); + } +} + +#[test] +fn should_preserve_historical_scalar_reduction() { + let vectors = corpus().scalars; + assert_eq!(vectors.len(), 4); + for v in vectors { + let input = bytes(&v.input); + let key = SecretKey::::from_be_bytes(&input).into_option(); + assert_eq!( + key.as_ref().map(|key| hex::encode(key.to_be_bytes())), + v.normalized, + "{}", + v.name + ); + // The strict upstream constructor cannot replace the historical DPP parser directly. + assert!( + BlsSecretKey::::from_bytes(&input).is_err(), + "{}", + v.name + ); + if let Some(normalized) = v.normalized { + assert_eq!( + hex::encode(NativeBlsModule.private_key_to_public_key(&input).unwrap()), + v.public_key.unwrap() + ); + assert_eq!( + hex::encode(NativeBlsModule.sign(b"scalar boundary", &input).unwrap()), + v.signature.unwrap() + ); + let reduced = dash_pkc::bls::Fr::from_bendian_reduce(&input).unwrap(); + let candidate = BlsSecretKey::::try_from(reduced).unwrap(); + assert_eq!(*candidate.to_bytes(), bytes::<32>(&normalized)); + } else { + assert!(matches!( + NativeBlsModule.sign(b"scalar boundary", &input), + Err(ProtocolError::InvalidBLSPrivateKeyError(_)) + )); + assert!(matches!( + NativeBlsModule.private_key_to_public_key(&input), + Err(ProtocolError::InvalidBLSPrivateKeyError(_)) + )); + } + } +} + +#[test] +fn should_preserve_identity_key_parsing_without_accepting_identity_signatures() { + let mut public_key = [0; 48]; + public_key[0] = 0xc0; + let mut signature = [0; 96]; + signature[0] = 0xc0; + // This is historical parsing behavior, not permission to verify an identity signature. + assert!(NativeBlsModule.validate_public_key(&public_key).is_ok()); + assert!(BlsPublicKey::::from_bytes(&public_key).is_err()); + assert!(!NativeBlsModule + .verify_signature(&signature, b"identity", &public_key) + .unwrap()); + let valid = bytes::<48>(&corpus().basic[0].public_key); + assert!(!NativeBlsModule + .verify_signature(&signature, b"identity", &valid) + .unwrap()); +} + +#[test] +fn should_preserve_invalid_input_results_and_validation_order() { + let v = &corpus().basic[0]; + let public_key = bytes::<48>(&v.public_key); + let secret = bytes::<32>(&v.secret_key); + for len in [0, 31, 33] { + assert!( + matches!(NativeBlsModule.sign(b"", &vec![1;len]), Err(ProtocolError::PrivateKeySizeError { got }) if got == len as u32) + ); + assert!( + matches!(NativeBlsModule.private_key_to_public_key(&vec![1;len]), Err(ProtocolError::PrivateKeySizeError { got }) if got == len as u32) + ); + } + for len in [0, 95, 97] { + assert!( + matches!(NativeBlsModule.verify_signature(&vec![0;len], b"", &public_key), Err(ProtocolError::BlsSignatureSizeError { got }) if got == len as u32) + ); + assert!(matches!( + NativeBlsModule.verify_signature(&vec![0; len], b"", &[0; 48]), + Err(ProtocolError::BlsError(_)) + )); + } + for public in [vec![], vec![0; 47], vec![0; 48], vec![255; 48], vec![0; 49]] { + assert!(NativeBlsModule.validate_public_key(&public).is_err()); + assert!(matches!( + NativeBlsModule.verify_signature(&[0; 96], b"", &public), + Err(ProtocolError::BlsError(_)) + )); + } + for signature in [[0; 96], [255; 96]] { + assert!(!NativeBlsModule + .verify_signature(&signature, b"", &public_key) + .unwrap()); + assert!(BlsSignature::::from_bytes(&signature).is_err()); + } + assert!(NativeBlsModule.sign(b"", &secret).is_ok()); +} + +#[test] +fn should_reject_points_outside_the_prime_order_subgroup() { + // On-curve points x=4 in G1 and x=(2,0) in G2, in compressed IETF encoding. + let mut public_key = [0; 48]; + public_key[0] = 0x80; + public_key[47] = 4; + let mut signature = [0; 96]; + signature[0] = 0xa0; + signature[95] = 2; + assert!(NativeBlsModule.validate_public_key(&public_key).is_err()); + assert!(BlsPublicKey::::from_bytes(&public_key).is_err()); + assert!(bool::from( + ::Signature::from_compressed(&signature).is_none() + )); + let valid = bytes::<48>(&corpus().basic[0].public_key); + assert!(!NativeBlsModule + .verify_signature(&signature, b"", &valid) + .unwrap()); + assert!(BlsSignature::::from_bytes(&signature).is_err()); +} + +#[test] +fn should_read_and_reemit_frozen_validator_storage() { + let config = bincode::config::standard().with_big_endian(); + let vectors = corpus().storage; + assert_eq!(vectors.len(), 3); + for v in vectors { + let encoded = hex::decode(v.validator_bytes).unwrap(); + let (validator, consumed): (ValidatorV0, _) = + bincode::decode_from_slice(&encoded, config).unwrap(); + assert_eq!(consumed, encoded.len(), "{}", v.name); + assert_eq!(bincode::encode_to_vec(&validator, config).unwrap(), encoded); + assert_eq!(serde_json::to_value(&validator).unwrap(), v.validator); + assert_eq!( + serde_json::from_value::(v.validator.clone()).unwrap(), + validator + ); + assert_eq!( + bincode::decode_from_slice_untrusted::(&encoded, config) + .unwrap() + .0, + validator + ); + assert_eq!( + bincode::borrow_decode_from_slice_untrusted::(&encoded, config) + .unwrap() + .0, + validator + ); + let encoded = hex::decode(v.validator_set_bytes).unwrap(); + let (set, consumed): (ValidatorSetV0, _) = + bincode::decode_from_slice(&encoded, config).unwrap(); + assert_eq!(consumed, encoded.len()); + assert_eq!(bincode::encode_to_vec(&set, config).unwrap(), encoded); + assert_eq!(serde_json::to_value(&set).unwrap(), v.validator_set); + assert_eq!( + serde_json::from_value::(v.validator_set).unwrap(), + set + ); + } +} diff --git a/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md b/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md new file mode 100644 index 00000000000..ccc1c4d9452 --- /dev/null +++ b/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md @@ -0,0 +1,35 @@ +# BLS compatibility vectors + +These public test keys and fixtures were generated before the backend migration, +from Platform `c0b4b97f8a1a8626c2f51bc8d7baeab9c65e10da` (#5307): + +- `dashpay/agora-blsful` at `0c34a7a488a0bd1c9a9a2196e793b303ad35c900`; +- `blstrs_plus` 0.8.18; +- `blst` at `71a00877c75a482e7d44c4e6370c1a7fb82444be` (0.3.12); +- candidate: `dash-pkc` at `e6402ced257c370a586ade9840ebbf545a4b7926`, + the backend used by rust-dashcore `314f10600e35311f3d875a6e8740476ab6c79c0c`. + +`vectors.json` contains 16 Basic signatures (four canonical scalars × empty, +text, zero digest and 256-byte messages), five secure aggregates (one/two/three +signers, reordered keys and a duplicate key), three key-generation cases, four +scalar boundaries, and three validator/validator-set storage cases. Storage uses +`grovedb-bincode` 2.1.0 with `standard().with_big_endian()` and DPP's JSON schema. + +The scalar and infinity cases characterize **historical compatibility**, not +recommended validation for a new protocol. DPP accepts nonzero scalars reduced +modulo the group order and permits an identity public key to deserialize; an +identity signature still fails verification. Replacing those rules requires a +separate protocol decision. The strict dash-pkc key constructors differ here. + +The generator uses DPP only; it does not derive expected values from dash-pkc. +To inspect its output, run: + +```sh +cargo run -p dpp --example generate_bls_compatibility_vectors --locked +cargo test -p dpp --test bls_compatibility --locked +``` + +Keep the frozen fixture unchanged when migrating the implementation. These tests +cover the listed cases, not an exhaustive proof of equivalence or every persisted +Platform structure. They do not test legacy signature hashing; the legacy field +is the public-key encoding of the same point. diff --git a/packages/rs-dpp/tests/fixtures/bls_compatibility/vectors.json b/packages/rs-dpp/tests/fixtures/bls_compatibility/vectors.json new file mode 100644 index 00000000000..f6c1d09c051 --- /dev/null +++ b/packages/rs-dpp/tests/fixtures/bls_compatibility/vectors.json @@ -0,0 +1,328 @@ +{ + "basic": [ + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000001", + "message": "", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "a8aab303e33ed14f4a904004a92bd26ffc969c1d1e7d4b7f0c04150a73e1845a911e51a2b2d369d5cef06560c5ac9f5715c01566993d4469805df3e1f29b536481a832bf2751b6908faed6776d062d585521889232999d72b679d6e38bb5cfff" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000001", + "message": "4461736820506c6174666f726d20424c5320636f6d7061746962696c697479", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "885957c480db7a90ba694ab40ea93e30e7e74c95e4ca3be0a67cda09e6f29b0d3b82d4bf9f56d6d6c2d410ed57f060b812569fac5b13555b4bb799ee33b5efb3024480e84d68962ff5db13b156d05f65d56fceec528f8bb8f1d740484d7a72e0" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000001", + "message": "0000000000000000000000000000000000000000000000000000000000000000", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "b72f4d8dfacf216719bcebb8349312f6bce892587291ee672fc0c7b6d16f427002713a961d122633e2deda35e803e9c302b3fcbc9d36fbb5fdb644bd41ce296399a5ea115f0c6cd612ff7e8b08477993cf1a2412fd81bc07e7ecc7380cfd2876" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000001", + "message": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "8a527aa6d18e63de70f31c512406217224c99f5a087fd7bcea48737d40ab99bcff2ab6b20b197c1e16efaa9c3dceeb7b01be7de81f980049e69395369a96f994b18f8358f8ce52675dfd8262f69e738eab510a5bba303756955c7a7667b4b477" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000002", + "message": "", + "public_key": "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "legacy_public_key": "8572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "signature": "a17a941aa5c8600ed1558ec999ed9708a164624c01160a4a1f467bbff22df6db13bf07760b59d1c59f90a3d7e518e0100d65cdf14582f3b85176dd7b76960a655479e2d0a187ef3cf334051dbe0aae7fa1a0cf26297d7a221013e55dd0c0741d" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000002", + "message": "4461736820506c6174666f726d20424c5320636f6d7061746962696c697479", + "public_key": "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "legacy_public_key": "8572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "signature": "843df9b31366b4bee0b8cc9bacb9f2905b9fd87ce2df1f6a5bfd77ee0a67f3f851dbae7866aca20d0bdac74c5d1d1042089cb625364a87bafc81c4e9e582fb6d5400e2d350f6da811f35f647402597f8fc28ec4f4fcf1d9c611f4a5044b4b4ca" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000002", + "message": "0000000000000000000000000000000000000000000000000000000000000000", + "public_key": "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "legacy_public_key": "8572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "signature": "8be4ae3fc1c613d49655bcedd5945cc2f4eaf38122f4dfa50f38153b0461425a743b9b3fe8d175d0a41c725bea12ba05035c1c95c85ae567c6f5cd3c6a5975b17a67683dbe2eb70897e9b018e80ac123ec6bb843a614f277851fccc548a2f695" + }, + { + "secret_key": "0000000000000000000000000000000000000000000000000000000000000002", + "message": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "public_key": "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "legacy_public_key": "8572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "signature": "ac997b406ecf999caa44ca3a0e2b42ce77bc6782fc8ac02c54e59d723e128f24f0a1f88a71b21f9890a3282a76632aa1061d736d3d502d81a2a9a1c863752a372ae94a64115d12f2ff34362861e4bb768ad533d0c087906485e795abda688f8d" + }, + { + "secret_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "message": "", + "public_key": "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "legacy_public_key": "15fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "signature": "a01aa8ac3da427ac661695badf9bb4ef2031add7eda51556349cc30b75a2a7de800d4b18a36bad836f576f30225f52a40abc60004dd0e6a834caed027bb25c674181debcbe5d072d8f8758be29887a5a99deef10c04afaf3c3cefe65363636b4" + }, + { + "secret_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "message": "4461736820506c6174666f726d20424c5320636f6d7061746962696c697479", + "public_key": "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "legacy_public_key": "15fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "signature": "8b1b6663cd08c760736bd95d4196d6db75a50b87b639228f9fffa5b7bfa0f43ca29f1f4be87b44fd395f8afe3804b85b068cde11d73f3fed9b05b9c9f296a474ac23f437c85c3f1dc973262b19b02c6875ce2bd911d3ebb3b639aaef61f6a3ae" + }, + { + "secret_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "message": "0000000000000000000000000000000000000000000000000000000000000000", + "public_key": "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "legacy_public_key": "15fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "signature": "af47ffcd8490a3d28c82c6b8c050571ed3eef9b561d9889bce097bd1d0cffbde17b6d9e7aa0e1f2415b1f8bb7e07467614c4d45fae16611b45f9e3d763ab2192ed723f3ea01b146631e68f08cbb1c20ac09ef80dbc0145d9c805e4b4b9771acc" + }, + { + "secret_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "message": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "public_key": "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "legacy_public_key": "15fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "signature": "b7921607432c421102b45efd5c1c345b329b61ebaabd6efc99d65971a4b68e358f5f1b341b16cf56b451e7b424f53525172ea4279a3276a6d365d04e9eeb5503e1edb8ad467739d6dd7b82811324842d66088e5c211a3210acfa7cfc939441e6" + }, + { + "secret_key": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + "message": "", + "public_key": "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "88aab303e33ed14f4a904004a92bd26ffc969c1d1e7d4b7f0c04150a73e1845a911e51a2b2d369d5cef06560c5ac9f5715c01566993d4469805df3e1f29b536481a832bf2751b6908faed6776d062d585521889232999d72b679d6e38bb5cfff" + }, + { + "secret_key": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + "message": "4461736820506c6174666f726d20424c5320636f6d7061746962696c697479", + "public_key": "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "a85957c480db7a90ba694ab40ea93e30e7e74c95e4ca3be0a67cda09e6f29b0d3b82d4bf9f56d6d6c2d410ed57f060b812569fac5b13555b4bb799ee33b5efb3024480e84d68962ff5db13b156d05f65d56fceec528f8bb8f1d740484d7a72e0" + }, + { + "secret_key": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + "message": "0000000000000000000000000000000000000000000000000000000000000000", + "public_key": "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "972f4d8dfacf216719bcebb8349312f6bce892587291ee672fc0c7b6d16f427002713a961d122633e2deda35e803e9c302b3fcbc9d36fbb5fdb644bd41ce296399a5ea115f0c6cd612ff7e8b08477993cf1a2412fd81bc07e7ecc7380cfd2876" + }, + { + "secret_key": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + "message": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "public_key": "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "legacy_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "aa527aa6d18e63de70f31c512406217224c99f5a087fd7bcea48737d40ab99bcff2ab6b20b197c1e16efaa9c3dceeb7b01be7de81f980049e69395369a96f994b18f8358f8ce52675dfd8262f69e738eab510a5bba303756955c7a7667b4b477" + } + ], + "secure_aggregation": [ + { + "secret_keys": [ + "0000000000000000000000000000000000000000000000000000000000000001" + ], + "message": "4461736820506c6174666f726d20736563757265206167677265676174696f6e", + "public_keys": [ + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + ], + "signature": "a5b6cbc5a885310da739d03370f1ee5d71da922c1c4fbb9a340cae955f25c78fb773bada0601caaadfbeb7c8e9805a860012dae1841d8ad9266444fff8fd0c4783ba46d86d0844c099a5d87c9edf22c50d6b82b18f6ea8499e0d711238504668" + }, + { + "secret_keys": [ + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002" + ], + "message": "4461736820506c6174666f726d20736563757265206167677265676174696f6e", + "public_keys": [ + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e" + ], + "signature": "8921aa203d93e45302b404bc523295cc80d7d691b4f0a8081a1580752dbf68ea0acf681c52a74520d5c42a5739e6452102c928a29684b67eee818bf211bb019c9d3a7221975c0d1aa3b278bb3c6b86032b2d25c077b167907bc9ca6927bcab94" + }, + { + "secret_keys": [ + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + ], + "message": "4461736820506c6174666f726d20736563757265206167677265676174696f6e", + "public_keys": [ + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48" + ], + "signature": "8c456b1677371cd2648677f66761539fb5d9f09b8c1a3587f4b2c95f737d9e3c509e7f293aad71322a7156b7d4581e54110c58f8055863344bea1a3e51700d1e6d30605cbab292590cae730e375dc00e60d049c9ee726b315d9c81328d03bd5f" + }, + { + "secret_keys": [ + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002" + ], + "message": "4461736820506c6174666f726d20736563757265206167677265676174696f6e", + "public_keys": [ + "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e" + ], + "signature": "8c456b1677371cd2648677f66761539fb5d9f09b8c1a3587f4b2c95f737d9e3c509e7f293aad71322a7156b7d4581e54110c58f8055863344bea1a3e51700d1e6d30605cbab292590cae730e375dc00e60d049c9ee726b315d9c81328d03bd5f" + }, + { + "secret_keys": [ + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000001" + ], + "message": "4461736820506c6174666f726d20736563757265206167677265676174696f6e", + "public_keys": [ + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + ], + "signature": "a71e6905eb7fecd7fdf91a794a0140676c8e2f94aa5420a295c668d529b7e5306478a32cf9f50c230a94f9626d893e8304bb21490ee8c7471e893c632dae250c6a49a9efb8cd5c0e790e884516b41f4a0fb5c45804d1d7e56bb366f2e153973c" + } + ], + "scalars": [ + { + "name": "zero", + "input": "0000000000000000000000000000000000000000000000000000000000000000", + "normalized": null, + "public_key": null, + "signature": null + }, + { + "name": "order", + "input": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", + "normalized": null, + "public_key": null, + "signature": null + }, + { + "name": "order_plus_one", + "input": "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", + "normalized": "0000000000000000000000000000000000000000000000000000000000000001", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "signature": "b4ae0ce826b35665b1419394a212f47d9583fa453fd5096a655476cff885f8ad94418c7b9980d6b91c86b23a47a3beb510f6ceb0768fbee0bac279512d9627fe72d4d48d8a3efbef8f7652dd90836104c45cc9a680c82025c68eba5785b4c882" + }, + { + "name": "max", + "input": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "normalized": "1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffd", + "public_key": "96ea601ca88f7d3489479129b258960b4c1df37194d30803627c30c34252679a0ada1a51bc7a4006a4f0564050d31746", + "signature": "aeab9eed96af89a7f8a8d0103496b59c950368c76d0bb18e4d57df607b24f75e80f8a436871f7cf9bb6bbf3a81e0939317e5e56648c0ba4958102649229b8dbed297a9fd29e49c13e138e181ffe7f55062597c0e15cdb42a63fe48c12b4ccf0c" + } + ], + "storage": [ + { + "name": "public_key", + "validator": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + }, + "validator_bytes": "11111111111111111111111111111111111111111111111111111111111111110197f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb682000", + "validator_set": { + "quorum_hash": "3333333333333333333333333333333333333333333333333333333333333333", + "quorum_index": 2, + "core_height": 123456, + "members": { + "1111111111111111111111111111111111111111111111111111111111111111": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + } + }, + "threshold_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + }, + "validator_set_bytes": "33333333333333333333333333333333333333333333333333333333333333330102fc0001e2400120111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110197f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb68200097f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + }, + { + "name": "absent", + "validator": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": null, + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + }, + "validator_bytes": "111111111111111111111111111111111111111111111111111111111111111100093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb682000", + "validator_set": { + "quorum_hash": "3333333333333333333333333333333333333333333333333333333333333333", + "quorum_index": 2, + "core_height": 123456, + "members": { + "1111111111111111111111111111111111111111111111111111111111111111": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": null, + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + } + }, + "threshold_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + }, + "validator_set_bytes": "33333333333333333333333333333333333333333333333333333333333333330102fc0001e24001201111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb68200097f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + }, + { + "name": "infinity", + "validator": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + }, + "validator_bytes": "111111111111111111111111111111111111111111111111111111111111111101c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb682000", + "validator_set": { + "quorum_hash": "3333333333333333333333333333333333333333333333333333333333333333", + "quorum_index": 2, + "core_height": 123456, + "members": { + "1111111111111111111111111111111111111111111111111111111111111111": { + "pro_tx_hash": "1111111111111111111111111111111111111111111111111111111111111111", + "public_key": "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "node_ip": "127.0.0.1", + "node_id": "2222222222222222222222222222222222222222", + "core_port": 19999, + "platform_http_port": 1443, + "platform_p2p_port": 26656, + "is_banned": false + } + }, + "threshold_public_key": "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + }, + "validator_set_bytes": "33333333333333333333333333333333333333333333333333333333333333330102fc0001e24001201111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111101c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093132372e302e302e312222222222222222222222222222222222222222fb4e1ffb05a3fb68200097f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" + } + ], + "key_generation": [ + { + "ikm": "0000000000000000000000000000000000000000000000000000000000000000", + "secret_key": "4a353be3dac091a0a7e640620372f5e1e2e4401717c1e79cac6ffba8f6905604", + "public_key": "85695fcbc06cc4c4c9451f4dce21cbf8de3e5a13bf48f44cdbb18e2038ba7b8bb1632d7911ef1e2e08749bddbf165352" + }, + { + "ikm": "0101010101010101010101010101010101010101010101010101010101010101", + "secret_key": "6fc9d9a2b05fd1f0e51bc91041a03be8657081f272ec281aff731624f0d1c220", + "public_key": "aefe1789d6476f60439e1168f588ea16652dc321279f05a805fbc63933e88ae9c175d6c6ab182e54af562e1a0dce41bb" + }, + { + "ikm": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "secret_key": "4ecb8197b8a2af28bfadf88f8084662c078bed1fa6970fd89b95ed541e35b3be", + "public_key": "96a5412d094be0d2017da0b7f17fe32540ad8356e59d181aec873543cc01433cf8cb251d3e1f950adfeeca9075a7e89c" + } + ] +} From 0648a1d43ab8b83868fae4ddff18506484f45cb2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 08:30:15 +0000 Subject: [PATCH 02/11] refactor: share rust-dashcore BLS backend Preserve historical scalar reduction, infinity parsing, signature bytes and validator serialization with the previously committed compatibility vectors. Adapt repository consumers and replace the blst git patch with registry 0.3.17. Co-authored-by: Codex --- Cargo.lock | 283 +----------------- Cargo.toml | 4 - packages/rs-dpp/Cargo.toml | 7 +- .../generate_bls_compatibility_vectors.rs | 42 ++- packages/rs-dpp/src/bls/native_bls.rs | 39 +-- packages/rs-dpp/src/bls_signatures.rs | 268 +++++++++++++++++ .../rs-dpp/src/core_types/validator/mod.rs | 6 +- .../rs-dpp/src/core_types/validator/v0/mod.rs | 20 +- .../src/core_types/validator_set/mod.rs | 18 +- .../src/core_types/validator_set/v0/mod.rs | 23 +- .../identity/identity_public_key/key_type.rs | 21 +- .../identity_public_key/v0/methods/mod.rs | 37 +-- packages/rs-dpp/src/lib.rs | 2 +- .../src/serialization/dashcore/bls_pubkey.rs | 118 +------- .../rs-dpp/src/serialization/dashcore/mod.rs | 17 +- packages/rs-dpp/src/serialization/mod.rs | 4 +- packages/rs-dpp/src/signing.rs | 34 +-- packages/rs-dpp/tests/bls_compatibility.rs | 47 ++- .../fixtures/bls_compatibility/README.md | 4 +- .../block_end/validator_set_update/mod.rs | 8 +- .../update_operator_identity/v0/mod.rs | 18 +- .../update_masternode_list/mod.rs | 19 +- .../update_state_masternode_list/v1/mod.rs | 4 +- .../core_chain_lock/choose_quorum/mod.rs | 6 +- .../core_chain_lock/choose_quorum/v0/mod.rs | 12 +- .../verify_chain_lock_locally/v0/mod.rs | 19 +- .../verify_recent_signature_locally/v0/mod.rs | 10 +- .../storage/store_platform_state/v1/mod.rs | 4 +- packages/rs-drive-abci/src/mimic/mod.rs | 6 +- .../rs-drive-abci/src/mimic/test_quorum.rs | 14 +- .../src/platform_types/commit/mod.rs | 4 +- .../src/platform_types/commit/v0/mod.rs | 14 +- .../v0/for_saving_v0.rs | 6 +- .../v0/for_saving_v1.rs | 4 +- .../v0/quorum_set.rs | 7 +- .../v0/quorums.rs | 30 +- .../src/platform_types/validator/v0/mod.rs | 6 +- .../platform_types/validator_set/v0/mod.rs | 26 +- .../src/query/document_query/v1/tests.rs | 55 ++-- .../system/current_quorums_info/v0/mod.rs | 6 +- .../tests/strategy_tests/execution.rs | 24 +- .../masternode_list_item_helpers.rs | 11 +- .../tests/strategy_tests/masternodes.rs | 10 +- .../tests/strategy_tests/query.rs | 29 +- .../test_cases/address_tests.rs | 7 +- .../rs-drive-proof-verifier/src/unproved.rs | 9 +- .../rs-drive-proof-verifier/src/verify.rs | 36 +-- .../src/masternode/locator.rs | 18 +- .../src/masternode/update_service.rs | 33 +- .../system/queries/current_quorums_info.rs | 2 +- packages/simple-signer/src/signer.rs | 14 +- 51 files changed, 605 insertions(+), 860 deletions(-) create mode 100644 packages/rs-dpp/src/bls_signatures.rs diff --git a/Cargo.lock b/Cargo.lock index 79739cf0e44..8c00f2cbf8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,7 +15,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common 0.1.7", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -791,7 +791,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -809,7 +809,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -844,35 +844,11 @@ dependencies = [ "subtle", ] -[[package]] -name = "blsful" -version = "3.0.0" -source = "git+https://github.com/dashpay/agora-blsful?rev=0c34a7a488a0bd1c9a9a2196e793b303ad35c900#0c34a7a488a0bd1c9a9a2196e793b303ad35c900" -dependencies = [ - "anyhow", - "blstrs_plus", - "hex", - "hkdf", - "merlin", - "pairing", - "rand 0.8.6", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "serde", - "serde_bare", - "sha2 0.10.9", - "sha3", - "subtle", - "thiserror 2.0.18", - "uint-zigzag", - "vsss-rs", - "zeroize", -] - [[package]] name = "blst" -version = "0.3.12" -source = "git+https://github.com/supranational/blst?rev=71a00877c75a482e7d44c4e6370c1a7fb82444be#71a00877c75a482e7d44c4e6370c1a7fb82444be" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" dependencies = [ "cc", "glob", @@ -880,24 +856,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "blstrs_plus" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a16dd4b0d6b4538e1fa0388843acb186363082713a8fc8416d802a04d013818" -dependencies = [ - "arrayref", - "blst", - "elliptic-curve", - "ff 0.13.1", - "group 0.13.0", - "pairing", - "rand_core 0.6.4", - "serde", - "subtle", - "zeroize", -] - [[package]] name = "borsh" version = "1.6.1" @@ -1594,26 +1552,13 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array 0.14.7", - "rand_core 0.6.4", - "serdect", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "typenum", ] @@ -2328,7 +2273,6 @@ dependencies = [ "async-trait", "base64 0.22.1", "bech32 0.11.1", - "blsful", "bs58", "byteorder", "chrono", @@ -2381,6 +2325,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tracing", + "zeroize", ] [[package]] @@ -2606,41 +2551,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff 0.13.1", - "generic-array 0.14.7", - "group 0.13.0", - "hkdf", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "tap", - "zeroize", -] - -[[package]] -name = "elliptic-curve-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de2b6fae800f08032a6ea32995b52925b1d451bff9d445c8ab2932323277faf" -dependencies = [ - "elliptic-curve", - "heapless 0.8.0", - "hex", - "multiexp", - "serde", - "zeroize", -] - [[package]] name = "embedded-io" version = "0.4.0" @@ -3104,18 +3014,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", -] - -[[package]] -name = "generic-array" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351" -dependencies = [ - "rustversion", - "serde_core", - "typenum", ] [[package]] @@ -3226,9 +3124,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.1", "memuse", - "rand 0.8.6", "rand_core 0.6.4", - "rand_xorshift 0.3.0", "subtle", ] @@ -3605,15 +3501,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -3678,20 +3565,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", - "hash32 0.2.1", + "hash32", "rustc_version", "serde", - "spin 0.9.8", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32 0.3.1", + "spin", "stable_deref_trait", ] @@ -4167,7 +4044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -4452,15 +4329,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "keccak" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" -dependencies = [ - "cpufeatures 0.2.17", -] - [[package]] name = "key-wallet" version = "0.45.0" @@ -4548,7 +4416,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.9.8", + "spin", ] [[package]] @@ -4786,18 +4654,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.6.4", - "zeroize", -] - [[package]] name = "metrics" version = "0.24.6" @@ -4964,20 +4820,6 @@ dependencies = [ "pxfm", ] -[[package]] -name = "multiexp" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec2ce93a6f06ac6cae04c1da3f2a6a24fcfc1f0eb0b4e0f3d302f0df45326cb" -dependencies = [ - "ff 0.13.1", - "group 0.13.0", - "rand_core 0.6.4", - "rustversion", - "std-shims", - "zeroize", -] - [[package]] name = "multimap" version = "0.10.1" @@ -5069,8 +4911,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.6", - "serde", ] [[package]] @@ -5086,8 +4926,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", - "rand 0.8.6", - "serde", ] [[package]] @@ -5136,7 +4974,6 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "serde", ] [[package]] @@ -5314,15 +5151,6 @@ dependencies = [ "zip32", ] -[[package]] -name = "pairing" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" -dependencies = [ - "group 0.13.0", -] - [[package]] name = "parking" version = "2.2.1" @@ -5776,7 +5604,7 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", - "heapless 0.7.17", + "heapless", "serde", ] @@ -5906,7 +5734,7 @@ dependencies = [ "num-traits", "rand 0.9.4", "rand_chacha 0.9.0", - "rand_xorshift 0.4.0", + "rand_xorshift", "regex-syntax", "rusty-fork", "tempfile", @@ -6256,15 +6084,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core 0.6.4", -] - [[package]] name = "rand_xorshift" version = "0.4.0" @@ -7183,20 +7002,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array 0.14.7", - "pkcs8", - "subtle", - "zeroize", -] - [[package]] name = "secp256k1" version = "0.33.1" @@ -7277,15 +7082,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "serde_bare" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c55386eed0f1ae957b091dc2ca8122f287b60c79c774cbe3d5f2b69fded660" -dependencies = [ - "serde", -] - [[package]] name = "serde_bytes" version = "0.11.19" @@ -7510,16 +7306,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha3" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" -dependencies = [ - "digest 0.10.7", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -7681,12 +7467,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spin" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" - [[package]] name = "spki" version = "0.7.3" @@ -7730,17 +7510,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "std-shims" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227c4f8561598188d0df96dbe749824576174bba278b5b6bb2eacff1066067d0" -dependencies = [ - "hashbrown 0.16.1", - "rustversion", - "spin 0.10.1", -] - [[package]] name = "strategy-tests" version = "5.0.0-beta.2" @@ -8758,12 +8527,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "uint-zigzag" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61faa33dc26b2851a37da5390a1a4cac015887b1e97ecd77ce7b4f987431de9f" - [[package]] name = "unarray" version = "0.1.4" @@ -8949,24 +8712,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "vsss-rs" -version = "5.1.0" -source = "git+https://github.com/dashpay/vsss-rs?branch=main#668f1406bf25a4b9a95cd97c9069f7a1632897c3" -dependencies = [ - "crypto-bigint", - "elliptic-curve", - "elliptic-curve-tools", - "generic-array 1.4.3", - "hex", - "num", - "rand_core 0.6.4", - "serde", - "sha3", - "subtle", - "zeroize", -] - [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 0849257b982..34adc6786a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,10 +75,6 @@ dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "314f10 dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "314f10600e35311f3d875a6e8740476ab6c79c0c" } tokio-metrics = "0.5" -[patch.crates-io] -# Supply no_std aggregate verification while retaining blstrs_plus's exact 0.3.12 pin. -blst = { git = "https://github.com/supranational/blst", rev = "71a00877c75a482e7d44c4e6370c1a7fb82444be" } - # Size-tuned profile for the iOS `rs-unified-sdk-ffi` staticlib, which # otherwise ships huge. Inherits `release` and is ONLY used by the iOS # build (`build_ios.sh --profile release`) diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 55ed2d601f4..1a41858a72e 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -12,7 +12,8 @@ authors = [ ] [dependencies] -blsful = { git = "https://github.com/dashpay/agora-blsful", rev = "0c34a7a488a0bd1c9a9a2196e793b303ad35c900", optional = true } +dash-pkc = { git = "https://github.com/dashpay/base-sdk", rev = "e6402ced257c370a586ade9840ebbf545a4b7926", default-features = false, features = ["bls"], optional = true } +zeroize = { version = "1.9.0", optional = true } ed25519-dalek = { version = "=2.2.0", features = ["rand_core"], optional = true } anyhow = { version = "1.0.81" } async-trait = { version = "0.1.79" } @@ -81,8 +82,6 @@ tracing = { version = "0.1.41" } grovedb-commitment-tree = { workspace = true, optional = true } [dev-dependencies] -# Compare BLS behavior with the exact backend used by the pinned rust-dashcore. -dash-pkc = { git = "https://github.com/dashpay/base-sdk", rev = "e6402ced257c370a586ade9840ebbf545a4b7926", default-features = false, features = ["bls"] } tokio = { version = "1.40", features = ["full"] } pretty_assertions = { version = "1.4.1" } dpp = { path = ".", default-features = false, features = [ @@ -119,7 +118,7 @@ core_key_wallet_manager = ["dep:key-wallet-manager"] core_key_wallet_serde = ["dep:key-wallet", "key-wallet/serde"] core_spv = ["dep:dash-spv"] core_rpc_client = ["dep:dashcore-rpc"] -bls-signatures = ["dashcore/bls", "dep:blsful"] +bls-signatures = ["dashcore/bls", "dep:dash-pkc", "dep:zeroize"] ed25519-dalek = ["dashcore/eddsa", "dep:ed25519-dalek"] all_features = [ "json-conversion", diff --git a/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs index d1449a97b4b..47e8b217ea4 100644 --- a/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs +++ b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs @@ -1,9 +1,7 @@ //! Emit deterministic compatibility fixtures from DPP's current BLS backend. //! Run with `cargo run -p dpp --example generate_bls_compatibility_vectors`. -use dpp::bls_signatures::{ - AggregateSignature, Bls12381G2Impl, PublicKey, SecretKey, SerializationFormat, SignatureSchemes, -}; +use dpp::bls_signatures::{PublicKey, SecretKey, Signature}; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::{hashes::Hash, ProTxHash, PubkeyHash, QuorumHash}; @@ -12,8 +10,8 @@ use std::collections::BTreeMap; fn main() { let key_generation: Vec<_> = [[0u8; 32], [1; 32], [255; 32]].iter().map(|ikm| { - let key = SecretKey::::from_hash(ikm); - json!({"ikm": hex::encode(ikm), "secret_key": hex::encode(key.to_be_bytes()), "public_key": hex::encode(key.public_key().0.to_compressed())}) + let key = SecretKey::from_ikm(ikm).unwrap(); + json!({"ikm": hex::encode(ikm), "secret_key": hex::encode(key.to_be_bytes()), "public_key": hex::encode(key.public_key().to_bytes())}) }).collect(); // Public test material: unit scalars, asymmetric bytes and the last canonical scalar. let keys: Vec<[u8; 32]> = [ @@ -27,19 +25,19 @@ fn main() { .collect(); let mut basic = Vec::new(); for bytes in &keys { - let key = SecretKey::::from_be_bytes(bytes).unwrap(); + let key = SecretKey::from_be_bytes(bytes).unwrap(); for message in [ vec![], b"Dash Platform BLS compatibility".to_vec(), vec![0; 32], (0..=255).collect(), ] { - let signature = key.sign(SignatureSchemes::Basic, &message).unwrap(); + let signature = key.sign(&message).unwrap(); basic.push(json!({ "secret_key": hex::encode(bytes), "message": hex::encode(message), - "public_key": hex::encode(key.public_key().0.to_compressed()), - "legacy_public_key": hex::encode(key.public_key().to_bytes_with_mode(SerializationFormat::Legacy)), - "signature": hex::encode(signature.as_raw_value().to_compressed()) + "public_key": hex::encode(key.public_key().to_bytes()), + "legacy_public_key": hex::encode(key.public_key().to_legacy_bytes().unwrap()), + "signature": hex::encode(signature.to_bytes()) })); } } @@ -54,23 +52,19 @@ fn main() { let message = b"Dash Platform secure aggregation"; let signers: Vec<_> = indexes .iter() - .map(|&i| SecretKey::::from_be_bytes(&keys[i]).unwrap()) + .map(|&i| SecretKey::from_be_bytes(&keys[i]).unwrap()) .collect(); let public_keys: Vec<_> = signers.iter().map(|key| key.public_key()).collect(); let signatures: Vec<_> = signers .iter() - .map(|key| key.sign(SignatureSchemes::Basic, message).unwrap()) + .map(|key| key.sign(message).unwrap()) .collect(); - let AggregateSignature::Basic(point) = - AggregateSignature::from_signatures_secure(&signatures, &public_keys).unwrap() - else { - panic!("expected Basic signature"); - }; + let point = Signature::aggregate_secure(&signatures, &public_keys).unwrap(); secure_aggregation.push(json!({ "secret_keys": indexes.iter().map(|&i| hex::encode(keys[i])).collect::>(), "message": hex::encode(message), - "public_keys": public_keys.iter().map(|key| hex::encode(key.0.to_compressed())).collect::>(), - "signature": hex::encode(point.to_compressed()) + "public_keys": public_keys.iter().map(|key| hex::encode(key.to_bytes())).collect::>(), + "signature": hex::encode(point.to_bytes()) })); } let mut scalars = Vec::new(); @@ -92,19 +86,17 @@ fn main() { ), ("max", [255; 32]), ] { - let key = SecretKey::::from_be_bytes(&bytes).into_option(); + let key = SecretKey::from_be_bytes(&bytes); scalars.push(json!({ "name": name, "input": hex::encode(bytes), "normalized": key.as_ref().map(|key| hex::encode(key.to_be_bytes())), - "public_key": key.as_ref().map(|key| hex::encode(key.public_key().0.to_compressed())), - "signature": key.as_ref().map(|key| hex::encode(key.sign(SignatureSchemes::Basic, b"scalar boundary").unwrap().as_raw_value().to_compressed())) + "public_key": key.as_ref().map(|key| hex::encode(key.public_key().to_bytes())), + "signature": key.as_ref().map(|key| hex::encode(key.sign(b"scalar boundary").unwrap().to_bytes())) })); } let mut infinity = [0; 48]; infinity[0] = 0xc0; - let public_key = SecretKey::::from_be_bytes(&keys[0]) - .unwrap() - .public_key(); + let public_key = SecretKey::from_be_bytes(&keys[0]).unwrap().public_key(); let mut storage = Vec::new(); for (name, key) in [ ("public_key", Some(public_key)), diff --git a/packages/rs-dpp/src/bls/native_bls.rs b/packages/rs-dpp/src/bls/native_bls.rs index 3e1341bf9ab..a9d67ce0658 100644 --- a/packages/rs-dpp/src/bls/native_bls.rs +++ b/packages/rs-dpp/src/bls/native_bls.rs @@ -1,13 +1,11 @@ -use crate::bls_signatures::{ - Bls12381G2Impl, Pairing, PublicKey, SecretKey, Signature, SignatureSchemes, -}; +use crate::bls_signatures::{PublicKey, SecretKey, Signature}; use crate::{BlsModule, ProtocolError, PublicKeyValidationError}; #[derive(Default)] pub struct NativeBlsModule; impl BlsModule for NativeBlsModule { fn validate_public_key(&self, pk: &[u8]) -> Result<(), PublicKeyValidationError> { - match PublicKey::::try_from(pk) { + match PublicKey::try_from(pk) { Ok(_) => Ok(()), Err(e) => Err(PublicKeyValidationError::new(e.to_string())), } @@ -19,22 +17,17 @@ impl BlsModule for NativeBlsModule { data: &[u8], public_key: &[u8], ) -> Result { - let public_key = PublicKey::::try_from(public_key)?; + let public_key = PublicKey::try_from(public_key)?; let signature_96_bytes = signature .try_into() .map_err(|_| ProtocolError::BlsSignatureSizeError { got: signature.len() as u32, })?; - let Some(g2_element) = - ::Signature::from_compressed(&signature_96_bytes) - .into_option() - else { + let Some(signature) = Signature::from_compressed(&signature_96_bytes) 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), @@ -48,13 +41,11 @@ impl BlsModule for NativeBlsModule { .map_err(|_| ProtocolError::PrivateKeySizeError { got: private_key.len() as u32, })?; - let pk = SecretKey::::from_be_bytes(&fixed_len_key) - .into_option() - .ok_or(ProtocolError::InvalidBLSPrivateKeyError( - "key not valid".to_string(), - ))?; + let pk = SecretKey::from_be_bytes(&fixed_len_key).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(); + let public_key_bytes = public_key.to_bytes().to_vec(); Ok(public_key_bytes) } @@ -65,15 +56,9 @@ impl BlsModule for NativeBlsModule { .map_err(|_| ProtocolError::PrivateKeySizeError { got: private_key.len() as u32, })?; - let pk = SecretKey::::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()) + let pk = SecretKey::from_be_bytes(&fixed_len_key).ok_or( + ProtocolError::InvalidBLSPrivateKeyError("key not valid".to_string()), + )?; + Ok(pk.sign(data)?.to_bytes().to_vec()) } } diff --git a/packages/rs-dpp/src/bls_signatures.rs b/packages/rs-dpp/src/bls_signatures.rs new file mode 100644 index 00000000000..10e91705667 --- /dev/null +++ b/packages/rs-dpp/src/bls_signatures.rs @@ -0,0 +1,268 @@ +//! Platform BLS keys and Basic signatures backed by rust-dashcore's dash-pkc primitives. + +use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature, Fr}; +use rand::{CryptoRng, Rng, RngCore}; +use serde::ser::SerializeTuple; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; +use zeroize::Zeroizing; + +const fn infinity() -> [u8; N] { + let mut bytes = [0; N]; + bytes[0] = 0xc0; + bytes +} + +/// Errors exposed by Platform's BLS operations. +#[derive(Debug, Clone, thiserror::Error)] +pub enum BlsError { + /// An input has an invalid length or encoding. + #[error("invalid inputs: {0}")] + InvalidInputs(String), + /// The signature does not verify. + #[error("invalid signature")] + InvalidSignature, + /// A key or signature could not be decoded. + #[error("deserialization error: {0}")] + DeserializationError(String), +} + +/// A compressed G1 key, including the identity permitted by historical Platform parsing. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct PublicKey([u8; 48]); + +impl PublicKey { + /// Return the canonical compressed IETF encoding. + pub fn to_bytes(&self) -> [u8; 48] { + self.0 + } + + /// Re-encode a public key for Core's legacy wire format. + pub fn to_legacy_bytes(&self) -> Result<[u8; 48], BlsError> { + if self.0 == infinity() { + return Ok(infinity()); + } + self.validated()? + .to_scheme::() + .map(|key| key.to_bytes()) + .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into())) + } + + fn validated(&self) -> Result, BlsError> { + BlsPublicKey::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature) + } +} + +impl Default for PublicKey { + fn default() -> Self { + Self(infinity()) + } +} + +impl From<&SecretKey> for PublicKey { + fn from(key: &SecretKey) -> Self { + key.public_key() + } +} + +impl TryFrom<&[u8]> for PublicKey { + type Error = BlsError; + + fn try_from(value: &[u8]) -> Result { + let bytes = value.try_into().map_err(|_| { + BlsError::InvalidInputs(format!("Invalid length, expected 48, got {}", value.len())) + })?; + // Persisted state and shipped validation accept canonical infinity, but verification rejects it. + if bytes != infinity() { + BlsPublicKey::::from_bytes(&bytes) + .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into()))?; + } + Ok(Self(bytes)) + } +} + +impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&hex::encode(self.0)) + } +} + +impl fmt::Debug for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl Serialize for PublicKey { + fn serialize(&self, serializer: S) -> Result { + if serializer.is_human_readable() { + serializer.serialize_str(&hex::encode(self.0)) + } else { + let mut tuple = serializer.serialize_tuple(48)?; + for byte in self.0 { + tuple.serialize_element(&byte)?; + } + tuple.end() + } + } +} + +impl<'de> Deserialize<'de> for PublicKey { + fn deserialize>(deserializer: D) -> Result { + if deserializer.is_human_readable() { + crate::serialization::dashcore::bls_pubkey::deserialize(deserializer) + } else { + struct KeyVisitor; + impl<'de> serde::de::Visitor<'de> for KeyVisitor { + type Value = PublicKey; + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("48 compressed public key bytes") + } + fn visit_seq>( + self, + mut seq: A, + ) -> Result { + let mut bytes = [0; 48]; + for (i, byte) in bytes.iter_mut().enumerate() { + *byte = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?; + } + PublicKey::try_from(bytes.as_slice()).map_err(serde::de::Error::custom) + } + } + deserializer.deserialize_tuple(48, KeyVisitor) + } + } +} + +/// A secret scalar; the backend clears its storage on drop. +#[derive(Clone, Debug)] +pub struct SecretKey(BlsSecretKey); + +impl SecretKey { + /// Parse a big-endian scalar using Platform's historical nonzero reduction rule. + pub fn from_be_bytes(bytes: &[u8; 32]) -> Option { + let scalar = Zeroizing::new(Fr::from_bendian_reduce(bytes).ok()?); + BlsSecretKey::try_from(*scalar).ok().map(Self) + } + + /// Derive a key from at least 32 bytes of keying material using Core's keygen-v3. + pub fn from_ikm(ikm: &[u8]) -> Result { + BlsSecretKey::from_ikm(ikm) + .map(Self) + .map_err(|e| BlsError::InvalidInputs(e.to_string())) + } + + /// Draw keying material with Platform's rand interface and derive a secret key. + pub fn random(mut rng: impl RngCore + CryptoRng) -> Self { + loop { + let material = Zeroizing::new(rng.gen::<[u8; 32]>()); + if let Ok(key) = Self::from_ikm(material.as_ref()) { + return key; + } + } + } + + /// Return the canonical big-endian secret scalar. + pub fn to_be_bytes(&self) -> [u8; 32] { + *self.0.to_bytes() + } + + /// Derive the corresponding public key. + pub fn public_key(&self) -> PublicKey { + PublicKey(self.0.public_key().to_bytes()) + } + + /// Sign arbitrary message bytes with the Basic IETF domain separation tag. + pub fn sign(&self, message: &[u8]) -> Result { + Ok(Signature(self.0.sign(message).to_bytes())) + } +} + +/// A compressed G2 Basic signature. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Signature([u8; 96]); + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&hex::encode(self.0)) + } +} + +impl Signature { + /// Decode a subgroup point, including the identity rejected during verification. + pub fn from_compressed(bytes: &[u8; 96]) -> Option { + if *bytes != infinity() { + BlsSignature::::from_bytes(bytes).ok()?; + } + Some(Self(*bytes)) + } + + /// Return the compressed IETF encoding without a scheme tag. + pub fn to_bytes(&self) -> [u8; 96] { + self.0 + } + + /// Verify a Basic signature over arbitrary message bytes. + pub fn verify( + &self, + public_key: &PublicKey, + message: impl AsRef<[u8]>, + ) -> Result<(), BlsError> { + if self.0 == infinity() { + return Err(BlsError::InvalidInputs( + "signature is the identity point".into(), + )); + } + if public_key.0 == infinity() { + return Err(BlsError::InvalidInputs( + "public key is the identity point".into(), + )); + } + let key = public_key.validated()?; + let signature = + BlsSignature::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature)?; + key.verify(message.as_ref(), &signature) + .map_err(|_| BlsError::InvalidSignature) + } + + /// Aggregate signatures with deterministic public-key weights. + pub fn aggregate_secure( + signatures: &[Self], + public_keys: &[PublicKey], + ) -> Result { + let signatures: Result, _> = signatures + .iter() + .map(|sig| BlsSignature::::from_bytes(&sig.0)) + .collect(); + let signatures = signatures.map_err(|_| BlsError::InvalidSignature)?; + let keys: Vec<_> = public_keys + .iter() + .map(PublicKey::validated) + .collect::>()?; + BlsSignature::secure_aggregate( + &signatures.iter().collect::>(), + &keys.iter().collect::>(), + ) + .map(|signature| Self(signature.to_bytes())) + .map_err(|_| BlsError::InvalidSignature) + } + + /// Verify a secure aggregate over a common message. + pub fn verify_secure( + &self, + public_keys: &[PublicKey], + message: impl AsRef<[u8]>, + ) -> Result<(), BlsError> { + let keys: Vec<_> = public_keys + .iter() + .map(PublicKey::validated) + .collect::>()?; + let signature = + BlsSignature::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature)?; + signature + .secure_verify_aggregates(message.as_ref(), &keys.iter().collect::>()) + .map_err(|_| BlsError::InvalidSignature) + } +} diff --git a/packages/rs-dpp/src/core_types/validator/mod.rs b/packages/rs-dpp/src/core_types/validator/mod.rs index 5cc5681b205..4d9c687b582 100644 --- a/packages/rs-dpp/src/core_types/validator/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/mod.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use crate::bls_signatures::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::{ValidatorV0, ValidatorV0Getters, ValidatorV0Setters}; #[cfg(all(feature = "json-conversion", feature = "serde-conversion"))] use crate::serialization::JsonConvertible; @@ -37,7 +37,7 @@ impl ValidatorV0Getters for Validator { } } - fn public_key(&self) -> &Option> { + fn public_key(&self) -> &Option { match self { Validator::V0(v0) => v0.public_key(), } @@ -87,7 +87,7 @@ impl ValidatorV0Setters for Validator { } } - fn set_public_key(&mut self, public_key: Option>) { + fn set_public_key(&mut self, public_key: Option) { match self { Validator::V0(v0) => v0.set_public_key(public_key), } diff --git a/packages/rs-dpp/src/core_types/validator/v0/mod.rs b/packages/rs-dpp/src/core_types/validator/v0/mod.rs index dc4e9a9e3f3..e98278c7054 100644 --- a/packages/rs-dpp/src/core_types/validator/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/v0/mod.rs @@ -1,7 +1,7 @@ use dashcore::{ProTxHash, PubkeyHash}; use std::fmt::{Debug, Formatter}; -use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use crate::bls_signatures::PublicKey as BlsPublicKey; #[cfg(feature = "serde-conversion")] use serde::{Deserialize, Serialize}; @@ -21,14 +21,12 @@ pub struct ValidatorV0 { /// The proTxHash pub pro_tx_hash: ProTxHash, /// The public key share of this validator for this quorum - // `BlsPublicKey` is a dashcore type, so its serde wrapper lives in - // `serialization::dashcore::bls_pubkey` (now self-sufficient — no upstream - // dependency; accepts hex string or byte sequence through any deserializer). + // Tagged enum buffers can carry either hex strings or byte sequences. #[cfg_attr( feature = "serde-conversion", serde(with = "crate::serialization::dashcore::bls_pubkey::option") )] - pub public_key: Option>, + pub public_key: Option, /// The node address pub node_ip: String, /// The node id @@ -56,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.0.to_compressed().encode(encoder)?; + public_key.to_bytes().encode(encoder)?; } None => { false.encode(encoder)?; // Indicate that public_key is not present @@ -168,7 +166,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>; + fn public_key(&self) -> &Option; /// Returns the node address of the validator. fn node_ip(&self) -> &String; /// Returns the node id of the validator. @@ -188,7 +186,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>); + fn set_public_key(&mut self, public_key: Option); /// Sets the node address of the validator. fn set_node_ip(&mut self, node_ip: String); /// Sets the node id of the validator. @@ -208,7 +206,7 @@ impl ValidatorV0Getters for ValidatorV0 { &self.pro_tx_hash } - fn public_key(&self) -> &Option> { + fn public_key(&self) -> &Option { &self.public_key } @@ -242,7 +240,7 @@ impl ValidatorV0Setters for ValidatorV0 { self.pro_tx_hash = pro_tx_hash; } - fn set_public_key(&mut self, public_key: Option>) { + fn set_public_key(&mut self, public_key: Option) { self.public_key = public_key; } @@ -284,7 +282,7 @@ mod tests { // Sample data for testing let pro_tx_hash = ProTxHash::from_slice(&[1; 32]).unwrap(); let mut rng = StdRng::seed_from_u64(0); - let public_key = Some(SecretKey::::random(&mut rng).public_key()); + let public_key = Some(SecretKey::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; diff --git a/packages/rs-dpp/src/core_types/validator_set/mod.rs b/packages/rs-dpp/src/core_types/validator_set/mod.rs index 3b5928c00b8..666cb84b037 100644 --- a/packages/rs-dpp/src/core_types/validator_set/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/mod.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use crate::bls_signatures::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::ValidatorV0; use crate::core_types::validator_set::v0::{ ValidatorSetV0, ValidatorSetV0Getters, ValidatorSetV0Setters, @@ -101,7 +101,7 @@ impl ValidatorSetV0Getters for ValidatorSet { } } - fn threshold_public_key(&self) -> &BlsPublicKey { + fn threshold_public_key(&self) -> &BlsPublicKey { match self { ValidatorSet::V0(v0) => v0.threshold_public_key(), } @@ -133,7 +133,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) { match self { ValidatorSet::V0(v0) => v0.set_threshold_public_key(threshold_public_key), } @@ -148,7 +148,7 @@ impl ValidatorSetV0Setters for ValidatorSet { ))] mod json_convertible_tests { use super::*; - use crate::bls_signatures::{Bls12381G2Impl, SecretKey}; + use crate::bls_signatures::SecretKey; use crate::core_types::validator::v0::ValidatorV0; use crate::core_types::validator_set::v0::ValidatorSetV0; use dashcore::hashes::Hash; @@ -167,14 +167,10 @@ mod json_convertible_tests { /// `to_value`/`to_json` of the same pubkey objects we put in the fixture. /// (The dedicated `serialization::dashcore::bls_pubkey` unit tests /// independently cover the pubkey round-trip.) - fn build_fixture() -> ( - ValidatorSet, - BlsPublicKey, - BlsPublicKey, - ) { + fn build_fixture() -> (ValidatorSet, BlsPublicKey, BlsPublicKey) { let mut rng = StdRng::seed_from_u64(42); let pro_tx_hash = ProTxHash::from_byte_array([0x11; 32]); - let validator_pubkey = SecretKey::::random(&mut rng).public_key(); + let validator_pubkey = SecretKey::random(&mut rng).public_key(); let validator_v0 = ValidatorV0 { pro_tx_hash, public_key: Some(validator_pubkey), @@ -188,7 +184,7 @@ mod json_convertible_tests { let mut members = BTreeMap::new(); members.insert(pro_tx_hash, validator_v0); - let threshold_pubkey = SecretKey::::random(&mut rng).public_key(); + let threshold_pubkey = SecretKey::random(&mut rng).public_key(); let set = ValidatorSet::V0(ValidatorSetV0 { quorum_hash: QuorumHash::from_byte_array([0x33; 32]), quorum_index: Some(7), diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index 2384b186b22..3a736ac4cb6 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -1,4 +1,3 @@ -use crate::bls_signatures::Bls12381G2Impl; use crate::bls_signatures::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::ValidatorV0; #[cfg(feature = "core-types-serialization")] @@ -33,14 +32,12 @@ pub struct ValidatorSetV0 { /// The list of masternodes pub members: BTreeMap, /// The threshold quorum public key - // `BlsPublicKey` is a dashcore type, so its serde wrapper lives in - // `serialization::dashcore::bls_pubkey` (now self-sufficient — no upstream - // dependency; accepts hex string or byte sequence through any deserializer). + // Tagged enum buffers can carry either hex strings or byte sequences. #[cfg_attr( feature = "serde-conversion", serde(with = "crate::serialization::dashcore::bls_pubkey") )] - pub threshold_public_key: BlsPublicKey, + pub threshold_public_key: BlsPublicKey, } impl Display for ValidatorSetV0 { @@ -67,7 +64,7 @@ impl Display for ValidatorSetV0 { pro_tx_hash, validator.node_ip )) .join(", "), - hex::encode(self.threshold_public_key.0.to_compressed()) // Assuming BlsPublicKey is a byte array + hex::encode(self.threshold_public_key.to_bytes()) // Assuming BlsPublicKey is a byte array ) } } @@ -91,7 +88,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.0.to_compressed(); + let public_key_bytes = self.threshold_public_key.to_bytes(); public_key_bytes.encode(encoder)?; Ok(()) @@ -237,7 +234,7 @@ pub trait ValidatorSetV0Getters { /// Returns the members of the validator set. fn members_owned(self) -> BTreeMap; /// Returns the threshold public key of the validator set. - fn threshold_public_key(&self) -> &BlsPublicKey; + fn threshold_public_key(&self) -> &BlsPublicKey; } /// Trait providing setter methods for `ValidatorSetV0` struct @@ -251,7 +248,7 @@ pub trait ValidatorSetV0Setters { /// Sets the members of the validator set. fn set_members(&mut self, members: BTreeMap); /// 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); } impl ValidatorSetV0Getters for ValidatorSetV0 { @@ -279,7 +276,7 @@ impl ValidatorSetV0Getters for ValidatorSetV0 { self.members } - fn threshold_public_key(&self) -> &BlsPublicKey { + fn threshold_public_key(&self) -> &BlsPublicKey { &self.threshold_public_key } } @@ -301,7 +298,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) { self.threshold_public_key = threshold_public_key; } } @@ -326,7 +323,7 @@ mod tests { // Create a sample ProTxHash and ValidatorV0 instance let pro_tx_hash = ProTxHash::from_slice(&[2; 32]).unwrap(); let mut rng = StdRng::seed_from_u64(0); - let public_key = Some(SecretKey::::random(&mut rng).public_key()); + let public_key = Some(SecretKey::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 { @@ -345,7 +342,7 @@ mod tests { members.insert(pro_tx_hash, validator); // Create a sample threshold public key - let threshold_public_key = SecretKey::::random(&mut rng).public_key(); + let threshold_public_key = SecretKey::random(&mut rng).public_key(); // Create the ValidatorSetV0 instance let validator_set = ValidatorSetV0 { diff --git a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs index 78ff0224abe..33e98f830ba 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use lazy_static::lazy_static; #[cfg(feature = "bls-signatures")] -use crate::bls_signatures::{self as bls_signatures, Bls12381G2Impl, BlsError}; +use crate::bls_signatures::{self as bls_signatures, BlsError}; use crate::fee::Credits; use crate::version::PlatformVersion; use crate::ProtocolError; @@ -168,8 +168,8 @@ impl KeyType { private_key.public_key().to_bytes() } KeyType::BLS12_381 => { - let private_key = bls_signatures::SecretKey::::random(rng); - private_key.public_key().0.to_compressed().to_vec() + let private_key = bls_signatures::SecretKey::random(rng); + private_key.public_key().to_bytes().to_vec() } KeyType::ECDSA_HASH160 | KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => { (0..self.default_size()).map(|_| rng.gen::()).collect() @@ -217,18 +217,15 @@ impl KeyType { KeyType::BLS12_381 => { #[cfg(feature = "bls-signatures")] { - let private_key: Option> = - bls_signatures::SecretKey::::from_be_bytes( - private_key_bytes, - ) - .into(); + let private_key: Option = + bls_signatures::SecretKey::from_be_bytes(private_key_bytes); if private_key.is_none() { return Err(ProtocolError::BlsError(BlsError::DeserializationError( "private key bytes not a valid secret key".to_string(), ))); } let private_key = private_key.expect("expected private key"); - let public_key_bytes = private_key.public_key().0.to_compressed().to_vec(); + let public_key_bytes = private_key.public_key().to_bytes().to_vec(); Ok(public_key_bytes) } #[cfg(not(feature = "bls-signatures"))] @@ -277,9 +274,9 @@ impl KeyType { ) } KeyType::BLS12_381 => { - let private_key = crate::bls_signatures::SecretKey::::random(rng); - let public_key_bytes = private_key.public_key().0.to_compressed().to_vec(); - (public_key_bytes, private_key.0.to_be_bytes()) + let private_key = crate::bls_signatures::SecretKey::random(rng); + let public_key_bytes = private_key.public_key().to_bytes().to_vec(); + (public_key_bytes, private_key.to_be_bytes()) } KeyType::ECDSA_HASH160 => { let mut seed = [0u8; 32]; diff --git a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs index cee0986d364..255e01cd2a2 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "bls-signatures")] +use crate::bls_signatures; #[cfg(feature = "ed25519-dalek")] use crate::ed25519_dalek; use crate::identity::identity_public_key::methods::hash::IdentityPublicKeyHashMethodsV0; @@ -10,8 +12,6 @@ use dashcore::hashes::Hash; use dashcore::secp256k1::SecretKey; use dashcore::{Network, PublicKey as ECDSAPublicKey}; use platform_value::{BinaryData, Bytes20}; -#[cfg(feature = "bls-signatures")] -use {crate::bls_signatures, crate::bls_signatures::Bls12381G2Impl}; impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKeyV0 { /// Get the original public key hash fn public_key_hash(&self) -> Result<[u8; 20], ProtocolError> { @@ -93,15 +93,14 @@ pub(in crate::identity::identity_public_key) fn validate_private_key_bytes_for_k KeyType::BLS12_381 => { #[cfg(feature = "bls-signatures")] { - let private_key: Option> = - bls_signatures::SecretKey::::from_be_bytes(private_key_bytes) - .into(); + let private_key: Option = + bls_signatures::SecretKey::from_be_bytes(private_key_bytes); if private_key.is_none() { return Ok(false); } let private_key = private_key.expect("expected private key"); - Ok(private_key.public_key().0.to_compressed() == data.as_slice()) + Ok(private_key.public_key().to_bytes() == data.as_slice()) } #[cfg(not(feature = "bls-signatures"))] return Err(ProtocolError::NotSupported( @@ -143,7 +142,7 @@ pub(in crate::identity::identity_public_key) fn validate_private_key_bytes_for_k #[cfg(test)] mod tests { use super::*; - use crate::bls_signatures::{Bls12381G2Impl, Pairing, Signature, SignatureSchemes}; + use crate::bls_signatures::Signature; use crate::identity::{Purpose, SecurityLevel}; use dashcore::Network; use dpp::version::PlatformVersion; @@ -156,11 +155,10 @@ mod tests { let (public_key_data, secret_key) = KeyType::BLS12_381 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest()) .expect("expected to get keys"); - let decoded_secret_key = - crate::bls_signatures::SecretKey::::from_be_bytes(&secret_key) - .expect("expected to get secret key"); + let decoded_secret_key = crate::bls_signatures::SecretKey::from_be_bytes(&secret_key) + .expect("expected to get secret key"); let public_key = decoded_secret_key.public_key(); - let decoded_public_key_data = public_key.0.to_compressed(); + let decoded_public_key_data = public_key.to_bytes(); assert_eq!( public_key_data.as_slice(), decoded_public_key_data.as_slice() @@ -173,19 +171,14 @@ mod tests { let (_, secret_key) = KeyType::BLS12_381 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest()) .expect("expected to get keys"); - let decoded_secret_key = - crate::bls_signatures::SecretKey::::from_be_bytes(&secret_key) - .expect("expected to get secret key"); - let signature = decoded_secret_key - .sign(SignatureSchemes::Basic, b"hello") - .expect("expected to sign"); - let compressed = signature.as_raw_value().to_compressed(); - let g2 = ::Signature::from_compressed(&compressed) - .expect("G2 projective"); - let decoded_signature = Signature::::Basic(g2); + let decoded_secret_key = crate::bls_signatures::SecretKey::from_be_bytes(&secret_key) + .expect("expected to get secret key"); + let signature = decoded_secret_key.sign(b"hello").expect("expected to sign"); + let compressed = signature.to_bytes(); + let decoded_signature = Signature::from_compressed(&compressed).expect("valid signature"); assert_eq!( compressed.as_slice(), - decoded_signature.as_raw_value().to_compressed().as_slice() + decoded_signature.to_bytes().as_slice() ) } diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index 68ca1a36084..404916f7d9b 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -142,7 +142,7 @@ pub mod prelude { pub use bincode; pub use bincode::enc::Encode; #[cfg(feature = "bls-signatures")] -pub use blsful as bls_signatures; +pub mod bls_signatures; #[cfg(feature = "data-contracts")] pub use data_contracts; #[cfg(feature = "ed25519-dalek")] diff --git a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs b/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs index ccc6d8f852a..0c01d0df4eb 100644 --- a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs +++ b/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs @@ -1,122 +1,36 @@ -//! Local serde wrapper for `BlsPublicKey` that tolerates -//! owned-string sources (`serde_json::Value`, `platform_value::Value`, and -//! anything routed through serde's `ContentDeserializer` for tagged-enum -//! buffering). -//! -//! ## Why this exists -//! -//! Upstream `blstrs_plus` 0.8.18 (`src/serde_impl.rs:119`) implements the -//! human-readable deserialize path as: -//! -//! ```ignore -//! if d.is_human_readable() { -//! let hex_str = <&str>::deserialize(d)?; // borrowed-only -//! ... -//! } -//! ``` -//! -//! `<&str>::deserialize` only succeeds when the deserializer's visitor -//! receives `visit_borrowed_str` — which `serde_json::from_slice` / -//! `serde_json::from_str` provide, but `serde_json::from_value`, -//! `platform_value::from_value`, and `ContentDeserializer` do **not** (they -//! produce owned `String`). Round-tripping a `BlsPublicKey` through any -//! `Value` representation therefore fails with -//! `"invalid type: string ..., expected a borrowed string"`. -//! -//! This is technically a serde compatibility quirk rather than a single -//! crate's bug — but the leaf type is the only place to patch. See plan -//! §10b "Common pattern: serde's `ContentDeserializer` HR-quirk" for -//! the broader narrative. -//! -//! ## How the workaround works -//! -//! A single `deserialize_any` visitor accepts BOTH wire forms upstream emits: -//! the 96-char hex string (`visit_str`) and the 48-byte compressed-G1 form as -//! raw bytes or a `u8` sequence (`visit_bytes` / `visit_seq`). Either way it -//! hex/byte-decodes to the compressed-G1 representation, lifts it to -//! `G1Projective` via `to_curve`, and wraps into `PublicKey` -//! directly (the inner field is `pub`). -//! -//! Driving it via `deserialize_any` (rather than branching on -//! `is_human_readable()`) is what makes it robust to serde's internal-tag -//! `Content` buffer: that buffer's `is_human_readable()` does not reliably -//! match the original deserializer, so a `Value` (non-HR) pubkey could arrive -//! as a byte *sequence* while the old HR branch expected a *string* — which is -//! exactly why the `ValidatorSet` value round-trip test used to be `#[ignore]`d. -//! Accepting both shapes in one visitor sidesteps that, and also sidesteps the -//! upstream borrowed-only `<&str>::deserialize` HR path. Both serde_json and -//! platform_value are self-describing, so `deserialize_any` is safe; bincode -//! never reaches here (it goes through the separate derived `Decode`). -//! -//! Note: `BlsPublicKey` carries a public key on the G1 curve -//! (the `Bls12381G2Impl` name refers to where signatures live, not keys). -//! Compressed G1 = 48 bytes = 96 hex chars. -//! -//! ## When to remove this -//! -//! This wrapper is now self-sufficient (no behavioral dependency on an upstream -//! fix). Once upstream `blstrs_plus` accepts owned strings AND a byte-sequence -//! HR form on its own `Deserialize`, this wrapper and the `serde(with = ...)` -//! annotations on `Validator::public_key` / `ValidatorSetV0::threshold_public_key` -//! can simply be dropped. +//! Serde support for Platform BLS keys in hex, byte-sequence and tagged-enum inputs. -use crate::bls_signatures::inner_types::{G1Affine, GroupEncoding, PrimeCurveAffine}; -use crate::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use crate::bls_signatures::PublicKey as BlsPublicKey; use serde::de::Visitor; use serde::{Deserializer, Serialize, Serializer}; use std::fmt; -/// Compressed-G1 wire size for BLS12-381 (where the public key lives in -/// `Bls12381G2Impl`). +/// Size of a compressed BLS12-381 G1 public key. const COMPRESSED_G1_LEN: usize = 48; -pub fn serialize( - pk: &BlsPublicKey, - serializer: S, -) -> Result { - // Upstream serialize already produces a hex string in HR and a byte tuple - // in non-HR; both are correct on the wire. Nothing to override here. +pub fn serialize(pk: &BlsPublicKey, serializer: S) -> Result { pk.serialize(serializer) } -pub fn deserialize<'de, D: Deserializer<'de>>( - deserializer: D, -) -> Result, D::Error> { - // One visitor that accepts BOTH wire forms upstream emits: the - // human-readable 96-char hex string, and the non-HR 48-byte compressed-G1 - // form (as `bytes` or a `u8` sequence). Driving it via `deserialize_any` - // makes it robust to serde's internal-tag `Content` buffer, whose - // `is_human_readable()` does not always match the original deserializer — - // the bug that previously forced the ValidatorSet value round-trip test to - // be `#[ignore]`d (the non-HR bytes arrived while the old code's HR branch - // expected a string → "invalid type: sequence, expected a string"). It also - // sidesteps the upstream `<&str>::deserialize` borrowed-only HR path (the - // original reason this wrapper exists). Both serde_json and platform_value - // are self-describing, so `deserialize_any` is safe; bincode never reaches - // here (it goes through the separate derived `Decode`). +pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { + // Tagged enum buffers may supply either representation regardless of is_human_readable(). deserializer.deserialize_any(BlsPublicKeyVisitor) } -fn from_compressed_g1_bytes( - bytes: &[u8], -) -> Result, E> { +fn from_compressed_g1_bytes(bytes: &[u8]) -> Result { if bytes.len() != COMPRESSED_G1_LEN { return Err(E::custom(format!( "expected {COMPRESSED_G1_LEN} compressed-G1 bytes for public key, got {}", bytes.len() ))); } - let mut compressed = ::Repr::default(); - compressed.as_mut().copy_from_slice(bytes); - let affine = Option::::from(G1Affine::from_bytes(&compressed)) - .ok_or_else(|| E::custom("not a valid compressed G1 point"))?; - Ok(BlsPublicKey::(affine.to_curve())) + BlsPublicKey::try_from(bytes).map_err(|_| E::custom("not a valid compressed G1 point")) } struct BlsPublicKeyVisitor; impl<'de> Visitor<'de> for BlsPublicKeyVisitor { - type Value = BlsPublicKey; + type Value = BlsPublicKey; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( @@ -172,13 +86,13 @@ fn hex_nibble(c: u8) -> Result { } } -/// `Option>` variant for fields like +/// `Option` variant for fields like /// `Validator::public_key`. pub mod option { use super::*; pub fn serialize( - opt: &Option>, + opt: &Option, serializer: S, ) -> Result { // Option's built-in Serialize delegates to T's Serialize, which @@ -188,14 +102,14 @@ pub mod option { pub fn deserialize<'de, D: Deserializer<'de>>( deserializer: D, - ) -> Result>, D::Error> { + ) -> Result, D::Error> { struct OptionVisitor; impl<'de> Visitor<'de> for OptionVisitor { - type Value = Option>; + type Value = Option; fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Option>") + f.write_str("Option") } fn visit_none(self) -> Result { @@ -231,10 +145,10 @@ mod tests { // Newtypes that drive the `with` module(s) through serde. #[derive(Serialize, Deserialize)] - struct Wrap(#[serde(with = "super")] BlsPublicKey); + struct Wrap(#[serde(with = "super")] BlsPublicKey); #[derive(Serialize, Deserialize)] - struct OptWrap(#[serde(with = "super::option")] Option>); + struct OptWrap(#[serde(with = "super::option")] Option); #[test] fn json_hr_round_trip_is_the_hex_string() { diff --git a/packages/rs-dpp/src/serialization/dashcore/mod.rs b/packages/rs-dpp/src/serialization/dashcore/mod.rs index 14b8c22773e..becf7e56ac0 100644 --- a/packages/rs-dpp/src/serialization/dashcore/mod.rs +++ b/packages/rs-dpp/src/serialization/dashcore/mod.rs @@ -1,18 +1,5 @@ -//! Serde `with` wrappers for types owned by external (dashcore) crates. -//! -//! These live here — rather than next to their dpp consumers — because the -//! type being (de)serialized is **not** a dpp type; it belongs to dashcore or -//! the BLS implementation (e.g. `blstrs_plus`). Grouping them under -//! `serialization::dashcore` keeps "serde for out-of-crate types" in one place, -//! distinct from dpp-type-local serde (which lives next to its type). +//! Serde adapters for the Core types embedded in Platform state. -/// Compressed-G1 BLS public key (`BlsPublicKey` from `blsful`'s -/// `blstrs_plus`). Used via `#[serde(with = "crate::serialization::dashcore::bls_pubkey")]`. -/// -/// The wrapped type comes from `crate::bls_signatures`, which is only linked when the -/// `bls-signatures` feature is on. Its only consumers — -/// the `core_types` validator/validator-set structs — are themselves gated behind -/// `core-types`, which requires `bls-signatures`, so gating here keeps the module -/// from breaking builds that omit BLS (e.g. `wasm-drive-verify`). +/// Accept hex strings or byte sequences for Platform BLS public keys. #[cfg(feature = "bls-signatures")] pub mod bls_pubkey; diff --git a/packages/rs-dpp/src/serialization/mod.rs b/packages/rs-dpp/src/serialization/mod.rs index b50bf581cb3..a85bf4d5445 100644 --- a/packages/rs-dpp/src/serialization/mod.rs +++ b/packages/rs-dpp/src/serialization/mod.rs @@ -1,3 +1,5 @@ +#[cfg(any(feature = "serde-conversion", feature = "bls-signatures"))] +pub mod dashcore; #[cfg(feature = "json-conversion")] pub mod json; // Not gated behind `serde-conversion`: this fixed-size byte-array helper is @@ -5,8 +7,6 @@ pub mod json; // `block::extended_block_info::ExtendedBlockInfo`), so it must resolve in every // feature configuration. It only depends on `serde` and `base64`, both // non-optional dependencies. -#[cfg(feature = "serde-conversion")] -pub mod dashcore; pub mod serde_bytes; #[cfg(feature = "serde-conversion")] pub mod serde_bytes_var; diff --git a/packages/rs-dpp/src/signing.rs b/packages/rs-dpp/src/signing.rs index ef52bc65136..51250ecf48e 100644 --- a/packages/rs-dpp/src/signing.rs +++ b/packages/rs-dpp/src/signing.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "bls-signatures")] +use crate::bls_signatures::{self, Signature}; use crate::identity::KeyType; use crate::serialization::PlatformMessageSignable; #[cfg(feature = "message-signature-verification")] @@ -10,11 +12,6 @@ use crate::{ #[cfg(feature = "message-signing")] use crate::{BlsModule, ProtocolError}; use dashcore::signer; -#[cfg(feature = "bls-signatures")] -use { - crate::bls_signatures::{self, Signature}, - crate::bls_signatures::{Bls12381G2Impl, Pairing}, -}; impl PlatformMessageSignable for &[u8] { #[cfg(feature = "message-signature-verification")] @@ -44,17 +41,15 @@ impl PlatformMessageSignable for &[u8] { } } KeyType::BLS12_381 => { - let public_key = - match bls_signatures::PublicKey::::try_from(public_key_data) { - Ok(public_key) => public_key, - Err(e) => { - // dbg!(format!("bls public_key could not be recovered")); - return SimpleConsensusValidationResult::new_with_error( - SignatureError::BasicBLSError(BasicBLSError::new(e.to_string())) - .into(), - ); - } - }; + let public_key = match bls_signatures::PublicKey::try_from(public_key_data) { + Ok(public_key) => public_key, + Err(e) => { + // dbg!(format!("bls public_key could not be recovered")); + return SimpleConsensusValidationResult::new_with_error( + SignatureError::BasicBLSError(BasicBLSError::new(e.to_string())).into(), + ); + } + }; let signature_bytes: [u8; 96] = match signature.try_into() { Ok(bytes) => bytes, Err(_) => { @@ -67,11 +62,7 @@ impl PlatformMessageSignable for &[u8] { ) } }; - let g2 = match ::Signature::from_compressed( - &signature_bytes, - ) - .into_option() - { + let signature = match Signature::from_compressed(&signature_bytes) { Some(g2) => g2, None => { return SimpleConsensusValidationResult::new_with_error( @@ -79,7 +70,6 @@ impl PlatformMessageSignable for &[u8] { ); } }; - let signature = Signature::::Basic(g2); if signature.verify(&public_key, signable_data).is_err() { SimpleConsensusValidationResult::new_with_error( diff --git a/packages/rs-dpp/tests/bls_compatibility.rs b/packages/rs-dpp/tests/bls_compatibility.rs index e37a11fa86b..9854db45ad5 100644 --- a/packages/rs-dpp/tests/bls_compatibility.rs +++ b/packages/rs-dpp/tests/bls_compatibility.rs @@ -1,7 +1,5 @@ use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature}; -use dpp::bls_signatures::{ - AggregateSignature, Bls12381G2Impl, Pairing, PublicKey, SecretKey, Signature, SignatureSchemes, -}; +use dpp::bls_signatures::{PublicKey, SecretKey, Signature}; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::native_bls::NativeBlsModule; @@ -73,14 +71,11 @@ fn should_preserve_key_generation_from_fixed_material() { assert_eq!(vectors.len(), 3); for v in vectors { let ikm = bytes::<32>(&v.ikm); - let current = SecretKey::::from_hash(ikm); + let current = SecretKey::from_ikm(&ikm).unwrap(); let candidate = BlsSecretKey::::from_ikm(&ikm).unwrap(); assert_eq!(current.to_be_bytes(), bytes::<32>(&v.secret_key)); assert_eq!(*candidate.to_bytes(), current.to_be_bytes()); - assert_eq!( - current.public_key().0.to_compressed(), - bytes::<48>(&v.public_key) - ); + assert_eq!(current.public_key().to_bytes(), bytes::<48>(&v.public_key)); assert_eq!( candidate.public_key().to_bytes(), bytes::<48>(&v.public_key) @@ -148,27 +143,21 @@ fn should_match_frozen_secure_aggregates_in_both_backends() { let public_keys: Vec<_> = v .public_keys .iter() - .map(|key| PublicKey::::try_from(bytes::<48>(key).as_slice()).unwrap()) + .map(|key| PublicKey::try_from(bytes::<48>(key).as_slice()).unwrap()) .collect(); let signatures: Vec<_> = v .secret_keys .iter() .map(|key| { - SecretKey::::from_be_bytes(&bytes(key)) + SecretKey::from_be_bytes(&bytes(key)) .unwrap() - .sign(SignatureSchemes::Basic, &message) + .sign(&message) .unwrap() }) .collect(); - let AggregateSignature::Basic(point) = - AggregateSignature::from_signatures_secure(&signatures, &public_keys).unwrap() - else { - panic!("expected Basic"); - }; - assert_eq!(point.to_compressed(), bytes::<96>(&v.signature)); - assert!(Signature::Basic(point) - .verify_secure(&public_keys, &message) - .is_ok()); + let point = Signature::aggregate_secure(&signatures, &public_keys).unwrap(); + assert_eq!(point.to_bytes(), bytes::<96>(&v.signature)); + assert!(point.verify_secure(&public_keys, &message).is_ok()); let candidate_keys: Vec<_> = v .secret_keys .iter() @@ -186,9 +175,7 @@ fn should_match_frozen_secure_aggregates_in_both_backends() { assert!(candidate.secure_verify_aggregates(&message, &refs).is_ok()); let mut wrong_message = message; wrong_message.push(1); - assert!(Signature::Basic(point) - .verify_secure(&public_keys, &wrong_message) - .is_err()); + assert!(point.verify_secure(&public_keys, &wrong_message).is_err()); assert!(candidate .secure_verify_aggregates(&wrong_message, &refs) .is_err()); @@ -201,7 +188,7 @@ fn should_preserve_historical_scalar_reduction() { assert_eq!(vectors.len(), 4); for v in vectors { let input = bytes(&v.input); - let key = SecretKey::::from_be_bytes(&input).into_option(); + let key = SecretKey::from_be_bytes(&input); assert_eq!( key.as_ref().map(|key| hex::encode(key.to_be_bytes())), v.normalized, @@ -306,9 +293,7 @@ fn should_reject_points_outside_the_prime_order_subgroup() { signature[95] = 2; assert!(NativeBlsModule.validate_public_key(&public_key).is_err()); assert!(BlsPublicKey::::from_bytes(&public_key).is_err()); - assert!(bool::from( - ::Signature::from_compressed(&signature).is_none() - )); + assert!(Signature::from_compressed(&signature).is_none()); let valid = bytes::<48>(&corpus().basic[0].public_key); assert!(!NativeBlsModule .verify_signature(&signature, b"", &valid) @@ -328,6 +313,14 @@ fn should_read_and_reemit_frozen_validator_storage() { assert_eq!(consumed, encoded.len(), "{}", v.name); assert_eq!(bincode::encode_to_vec(&validator, config).unwrap(), encoded); assert_eq!(serde_json::to_value(&validator).unwrap(), v.validator); + if let Some(key) = &validator.public_key { + // QuorumForSavingV1 uses bincode(with_serde): exactly 48 bytes, with no length prefix. + let bytes = bincode::serde::encode_to_vec(key, config).unwrap(); + assert_eq!(bytes, key.to_bytes()); + let decoded = + bincode::serde::decode_from_slice::(&bytes, config).unwrap(); + assert_eq!(decoded, (*key, 48)); + } assert_eq!( serde_json::from_value::(v.validator.clone()).unwrap(), validator diff --git a/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md b/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md index ccc1c4d9452..752f676c763 100644 --- a/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md +++ b/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md @@ -21,7 +21,9 @@ modulo the group order and permits an identity public key to deserialize; an identity signature still fails verification. Replacing those rules requires a separate protocol decision. The strict dash-pkc key constructors differ here. -The generator uses DPP only; it does not derive expected values from dash-pkc. +The frozen expected values come from the original DPP backend listed above. +The generator calls the current DPP implementation; after a backend change, +compare its output with the frozen fixture rather than replacing the fixture. To inspect its output, run: ```sh diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs index 62f1cdfab8c..4b217a45e17 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs @@ -157,7 +157,7 @@ mod tests { use dpp::block::block_info::BlockInfo; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0; use dpp::block::extended_block_info::ExtendedBlockInfo; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::core_types::validator_set::ValidatorSet; @@ -185,13 +185,13 @@ mod tests { member_seeds: &[u8], rng: &mut StdRng, ) -> ValidatorSet { - let threshold_public_key = SecretKey::::random(&mut *rng).public_key(); + let threshold_public_key = SecretKey::random(&mut *rng).public_key(); let mut members = BTreeMap::new(); for &seed in member_seeds { let mut hash_bytes = [0u8; 32]; hash_bytes[31] = seed; let pro_tx_hash = ProTxHash::from_byte_array(hash_bytes); - let public_key = Some(SecretKey::::random(&mut *rng).public_key()); + let public_key = Some(SecretKey::random(&mut *rng).public_key()); let node_id = PubkeyHash::from_byte_array([seed; 20]); let validator = ValidatorV0 { pro_tx_hash, @@ -407,7 +407,7 @@ mod tests { let mut rng = StdRng::seed_from_u64(45); let qh = quorum_hash_from_seed(1); - let threshold_pk = SecretKey::::random(&mut rng).public_key(); + let threshold_pk = SecretKey::random(&mut rng).public_key(); let empty_vs = ValidatorSet::V0(ValidatorSetV0 { quorum_hash: qh, quorum_index: None, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs index f059b250783..d88a16ac73b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs @@ -391,7 +391,7 @@ mod tests { use crate::platform_types::platform_state::PlatformStateV0Methods; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::block::block_info::BlockInfo; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsPrivateKey}; + use dpp::bls_signatures::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::ProTxHash; use dpp::dashcore::Txid; @@ -433,11 +433,11 @@ mod tests { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let operator_key: IdentityPublicKey = IdentityPublicKeyV0 { id: 0, @@ -976,11 +976,11 @@ mod tests { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let new_pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state let masternode_list_item = MasternodeListItem { @@ -1072,7 +1072,7 @@ mod tests { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes .try_into() .expect("expected the secret key to be 32 bytes"), @@ -1080,7 +1080,7 @@ mod tests { .expect( "expected the conversion between bls signatures library and blsful to happen without failing", ); - let new_pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let new_operator_identifier = Identifier::create_operator_identifier( pro_tx_hash.as_byte_array(), @@ -1215,11 +1215,11 @@ mod tests { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let new_pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state with original public key operator let masternode_list_item = MasternodeListItem { diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs index 36279aad809..7185b28a8d7 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs @@ -92,7 +92,7 @@ mod test { use crate::platform_types::validator_set::{ValidatorSet, ValidatorSetExt}; use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{Network, ProTxHash, PubkeyHash, QuorumHash}; @@ -517,10 +517,8 @@ mod test { quorum_index: None, core_height: init_core_height, members: members.clone(), - threshold_public_key: SecretKey::::random( - &mut StdRng::seed_from_u64(1), - ) - .public_key(), + threshold_public_key: SecretKey::random(&mut StdRng::seed_from_u64(1)) + .public_key(), }), ); @@ -893,10 +891,7 @@ mod test { .into_iter() .map(|validator| (validator.pro_tx_hash, validator)) .collect(), - threshold_public_key: SecretKey::::random(&mut StdRng::seed_from_u64( - 1, - )) - .public_key(), + threshold_public_key: SecretKey::random(&mut StdRng::seed_from_u64(1)).public_key(), }) .to_update() .validator_updates @@ -960,10 +955,8 @@ mod test { quorum_index: None, core_height: *core_height, members, - threshold_public_key: SecretKey::::random( - &mut StdRng::seed_from_u64(1), - ) - .public_key(), + threshold_public_key: SecretKey::random(&mut StdRng::seed_from_u64(1)) + .public_key(), }), ); } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs index 996608f515f..86bc208bad2 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs @@ -301,7 +301,7 @@ mod tests { use crate::platform_types::validator_set::{ValidatorSet, ValidatorSetExt}; use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::hashes::Hash; @@ -652,7 +652,7 @@ mod tests { quorum_index: None, core_height: 1, members: BTreeMap::from([(pro_tx_hash, validator)]), - threshold_public_key: SecretKey::::random(&mut rng).public_key(), + threshold_public_key: SecretKey::random(&mut rng).public_key(), }), ); state.mark_saved(); diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs index 1b0ab684cfe..c890e09ab45 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs @@ -2,7 +2,7 @@ mod v0; use crate::error::execution::ExecutionError; use crate::error::Error; -use dpp::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use dpp::bls_signatures::PublicKey as BlsPublicKey; use dpp::dashcore::QuorumHash; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; @@ -24,10 +24,10 @@ where // TODO: use CoreQuorumSet.select_quorums instead pub fn choose_quorum<'a>( llmq_quorum_type: QuorumType, - quorums: &'a BTreeMap>, + quorums: &'a BTreeMap, request_id: &[u8; 32], platform_version: &PlatformVersion, - ) -> Result)>, Error> { + ) -> Result, Error> { match platform_version .drive_abci .methods diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs index 945868ec823..38b2a366fd3 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use dpp::bls_signatures::PublicKey as BlsPublicKey; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::QuorumHash; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; @@ -12,15 +12,11 @@ impl Platform { /// Based on DIP8 deterministically chooses a pseudorandom quorum from the list of quorums pub(super) fn choose_quorum_v0<'a>( llmq_quorum_type: QuorumType, - quorums: &'a BTreeMap>, + quorums: &'a BTreeMap, request_id: &[u8; 32], - ) -> Option<(ReversedQuorumHashBytes, &'a BlsPublicKey)> { + ) -> Option<(ReversedQuorumHashBytes, &'a BlsPublicKey)> { // Scoring system logic - let mut scores: Vec<( - ReversedQuorumHashBytes, - &BlsPublicKey, - [u8; 32], - )> = Vec::new(); + let mut scores: Vec<(ReversedQuorumHashBytes, &BlsPublicKey, [u8; 32])> = Vec::new(); for (quorum_hash, public_key) in quorums { let mut quorum_hash_bytes = quorum_hash.to_byte_array().to_vec(); diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs index 000d46582a2..4daa5b74cce 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls_signatures::Signature; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::{ChainLock, QuorumSigningRequestId}; @@ -38,11 +38,7 @@ where // First verify that the signature conforms to a signature - let decoded_sig = match ::Signature::from_compressed( - chain_lock.signature.as_bytes(), - ) - .into_option() - { + let signature = match Signature::from_compressed(chain_lock.signature.as_bytes()) { Some(signature) => signature, None => { tracing::error!( @@ -59,8 +55,6 @@ where } }; - let signature = Signature::Basic(decoded_sig); - // we attempt to verify the chain lock locally let chain_lock_height = chain_lock.block_height; @@ -237,7 +231,8 @@ where mod tests { use crate::execution::platform_events::core_chain_lock::verify_chain_lock_locally::v0::CHAIN_LOCK_REQUEST_ID_PREFIX; use crate::test::helpers::setup::TestPlatformBuilder; - use dpp::bls_signatures::{Bls12381G2Impl, Pairing}; + use dpp::bls_signatures::Signature; + use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::{BlockHash, ChainLock, QuorumSigningRequestId}; use dpp::version::PlatformVersion; @@ -327,11 +322,7 @@ mod tests { ]; for signature in signatures { - assert!( - ::Signature::from_compressed(&signature) - .into_option() - .is_some(), - ); + assert!(Signature::from_compressed(&signature).is_some()); } } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs index 2ed186f8a02..bc8d5e8ff42 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls_signatures::Signature; use std::fmt::{Debug, Formatter}; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; @@ -21,12 +21,8 @@ pub(super) fn verify_recent_instant_lock_signature_locally_v0( ) -> Result { // First verify that the signature conforms to a signature - let signature = match ::Signature::from_compressed( - instant_lock.signature.as_bytes(), - ) - .into_option() - { - Some(signature) => Signature::Basic(signature), + let signature = match Signature::from_compressed(instant_lock.signature.as_bytes()) { + Some(signature) => signature, None => { tracing::trace!( instant_lock = ?InstantLockDebug(instant_lock), "Invalid instant Lock {} signature format", instant_lock.txid, ); diff --git a/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs b/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs index c4919e1fd19..8db643609f0 100644 --- a/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs @@ -180,7 +180,7 @@ mod tests { use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::bincode::config; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::{ValidatorSetV0, ValidatorSetV0Getters}; use dpp::core_types::validator_set::ValidatorSet; @@ -259,7 +259,7 @@ mod tests { /// threshold key derived from `byte`. fn validator_set(byte: u8, core_height: u32) -> ValidatorSet { let mut rng = StdRng::seed_from_u64(byte as u64); - let threshold_public_key = SecretKey::::random(&mut rng).public_key(); + let threshold_public_key = SecretKey::random(&mut rng).public_key(); let member = ValidatorV0 { pro_tx_hash: pro_tx_hash(byte), public_key: None, diff --git a/packages/rs-drive-abci/src/mimic/mod.rs b/packages/rs-drive-abci/src/mimic/mod.rs index 9434a5572b9..a05b0f146c4 100644 --- a/packages/rs-drive-abci/src/mimic/mod.rs +++ b/packages/rs-drive-abci/src/mimic/mod.rs @@ -13,7 +13,7 @@ use crate::platform_types::withdrawal::unsigned_withdrawal_txs::v0::{ use crate::rpc::core::CoreRPCLike; use ciborium::Value as CborValue; use dpp::block::block_info::BlockInfo; -use dpp::bls_signatures::SignatureSchemes; + use dpp::consensus::ConsensusError; use dpp::dashcore::hashes::Hash; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; @@ -538,10 +538,10 @@ impl FullAbciApplication<'_, C> { ); let block_signature = current_quorum .private_key - .sign(SignatureSchemes::Basic, digest.as_slice()) + .sign(digest.as_slice()) .expect("expected to be able to sign"); - commit_info.block_signature = block_signature.as_raw_value().to_compressed().to_vec(); + commit_info.block_signature = block_signature.to_bytes().to_vec(); } else { commit_info.block_signature = [0u8; 96].to_vec(); } diff --git a/packages/rs-drive-abci/src/mimic/test_quorum.rs b/packages/rs-drive-abci/src/mimic/test_quorum.rs index 9521f88c46e..4da2a3684db 100644 --- a/packages/rs-drive-abci/src/mimic/test_quorum.rs +++ b/packages/rs-drive-abci/src/mimic/test_quorum.rs @@ -1,7 +1,7 @@ use crate::platform_types::validator::v0::ValidatorV0; use crate::platform_types::validator_set::v0::ValidatorSetV0; use dpp::bls_signatures::{ - Bls12381G2Impl, PublicKey as BlsPublicKey, PublicKey, SecretKey as BlsPrivateKey, SecretKey, + PublicKey as BlsPublicKey, PublicKey, SecretKey as BlsPrivateKey, SecretKey, }; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; @@ -18,9 +18,9 @@ pub struct ValidatorInQuorum { /// The hash of the transaction that identifies this validator in the network. pub pro_tx_hash: ProTxHash, /// The private key for this validator's BLS signature scheme. - pub private_key: BlsPrivateKey, + pub private_key: BlsPrivateKey, /// The public key for this validator's BLS signature scheme. - pub public_key: BlsPublicKey, + pub public_key: BlsPublicKey, /// The node address pub node_ip: String, /// The node id @@ -103,9 +103,9 @@ pub struct TestQuorumInfo { /// A map of validators indexed by their `ProTxHash` identifiers. pub validator_map: BTreeMap, /// The private key used to sign messages for the quorum (for testing purposes only). - pub private_key: BlsPrivateKey, + pub private_key: BlsPrivateKey, /// The public key corresponding to the private key used for signing. - pub public_key: BlsPublicKey, + pub public_key: BlsPublicKey, } fn random_ipv4_address(rng: &mut StdRng) -> Ipv4Addr { @@ -274,7 +274,7 @@ impl From<&TestQuorumInfo> for QuorumInfoResult { pro_tx_hash: *pro_tx_hash, pub_key_operator: vec![], //doesn't matter valid: true, - pub_key_share: Some(public_key.0.to_compressed().to_vec()), + pub_key_share: Some(public_key.to_bytes().to_vec()), } }) .collect(); @@ -285,7 +285,7 @@ impl From<&TestQuorumInfo> for QuorumInfoResult { quorum_index: 0, mined_block: vec![], members, - quorum_public_key: public_key.0.to_compressed().to_vec(), + quorum_public_key: public_key.to_bytes().to_vec(), secret_key_share: None, } } diff --git a/packages/rs-drive-abci/src/platform_types/commit/mod.rs b/packages/rs-drive-abci/src/platform_types/commit/mod.rs index 153de511e26..904cafa51d8 100644 --- a/packages/rs-drive-abci/src/platform_types/commit/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/commit/mod.rs @@ -4,7 +4,7 @@ use crate::error::Error; use crate::platform_types::cleaned_abci_messages::{cleaned_block_id, cleaned_commit_info}; use crate::platform_types::commit::v0::CommitV0; use dpp::bls_signatures; -use dpp::bls_signatures::Bls12381G2Impl; + use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::validation::SimpleValidationResult; use dpp::version::PlatformVersion; @@ -83,7 +83,7 @@ impl Commit { pub fn verify_signature( &self, signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls_signatures::PublicKey, ) -> SimpleValidationResult { match self { Commit::V0(v0) => v0.verify_signature(signature, public_key), diff --git a/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs index af9fdc918ce..9fc484ebc1a 100644 --- a/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs @@ -5,7 +5,7 @@ pub mod accessors; use crate::abci::AbciError; use crate::platform_types::cleaned_abci_messages::{cleaned_block_id, cleaned_commit_info}; use dpp::bls_signatures; -use dpp::bls_signatures::{Bls12381G2Impl, BlsError, Pairing, Signature}; +use dpp::bls_signatures::{BlsError, Signature}; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::validation::{SimpleValidationResult, ValidationResult}; use tenderdash_abci::proto; @@ -82,7 +82,7 @@ impl CommitV0 { pub(super) fn verify_signature( &self, signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls_signatures::PublicKey, ) -> SimpleValidationResult { if signature == &[0; 96] { return ValidationResult::new_with_error(AbciError::BadRequest( @@ -91,18 +91,16 @@ impl CommitV0 { } // We could have received a fake commit, so signature validation needs to be returned if error as a simple validation result - let g2_element = match ::Signature::from_compressed(signature) - .into_option() - .ok_or(AbciError::BlsErrorOfTenderdashThresholdMechanism( + let signature = match Signature::from_compressed(signature).ok_or( + AbciError::BlsErrorOfTenderdashThresholdMechanism( BlsError::InvalidSignature, "verification of a commit signature".to_string(), - )) { + ), + ) { Ok(signature) => signature, Err(e) => return ValidationResult::new_with_error(e), }; - let signature = Signature::Basic(g2_element); - //todo: maybe cache this to lower the chance of a hashing based attack (forcing the // same calculation each time) let quorum_hash = &self.inner.quorum_hash[..] diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs index 2800dc0683b..41fa8f66eba 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs @@ -134,10 +134,8 @@ impl From> for Vec { .map(|(hash, quorum)| QuorumForSavingV0 { hash: Bytes32::from(hash.as_byte_array()), #[cfg(feature = "bls-signatures")] - public_key: bls_signatures::PublicKey::from_bytes( - &quorum.public_key.0.to_compressed(), - ) - .expect("expected to convert between BLS key libraries (to chia)"), + public_key: bls_signatures::PublicKey::from_bytes(&quorum.public_key.to_bytes()) + .expect("expected to convert between BLS key libraries (to chia)"), index: quorum.index, }) .collect() diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs index f39d8f8411f..1d903b160a1 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs @@ -7,7 +7,7 @@ use crate::platform_types::signature_verification_quorum_set::{ ThresholdBlsPublicKey, VerificationQuorum, }; use bincode::{Decode, Encode}; -use dpp::bls_signatures::Bls12381G2Impl; + use dpp::dashcore::hashes::Hash; use dpp::dashcore::QuorumHash; use dpp::platform_value::Bytes32; @@ -68,7 +68,7 @@ impl From for SignatureVerificationQu pub struct QuorumForSavingV1 { hash: Bytes32, #[bincode(with_serde)] - public_key: ThresholdBlsPublicKey, + public_key: ThresholdBlsPublicKey, index: Option, } diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs index 881347bc6ae..560a3f31844 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs @@ -303,16 +303,15 @@ impl From for SignatureVerificationQuorumSetV0 { mod tests { use super::*; use crate::config::ChainLockConfig; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsPrivateKey}; + use dpp::bls_signatures::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore_rpc::json::QuorumType; - fn make_public_key(seed: u8) -> dpp::bls_signatures::PublicKey { + fn make_public_key(seed: u8) -> dpp::bls_signatures::PublicKey { let mut key_bytes = [0u8; 32]; key_bytes[0] = seed; key_bytes[31] = 1; - let sk = - BlsPrivateKey::::from_be_bytes(&key_bytes).expect("valid secret key"); + let sk = BlsPrivateKey::from_be_bytes(&key_bytes).expect("valid secret key"); sk.public_key() } diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs index 2781697e1dc..0e017f7a11e 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs @@ -1,7 +1,7 @@ use derive_more::{Deref, DerefMut, From}; use dpp::bls_signatures; pub use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; -use dpp::bls_signatures::{Bls12381G2Impl, SignatureSchemes}; + use dpp::dashcore::bls_sig_utils::BLSSignature; use dpp::dashcore::{QuorumHash, Txid}; use std::collections::BTreeMap; @@ -149,7 +149,7 @@ pub struct VerificationQuorum { /// Quorum threshold public key is used to verify /// signatures produced by corresponding quorum - pub public_key: ThresholdBlsPublicKey, + pub public_key: ThresholdBlsPublicKey, } impl Debug for VerificationQuorum { @@ -206,39 +206,33 @@ impl SigningQuorum { let message_digest = sha256d::Hash::from_engine(engine); - let private_key = - bls_signatures::SecretKey::::from_be_bytes(&self.private_key) - .into_option() - .ok_or(Error::BLSError( - dpp::bls_signatures::BlsError::DeserializationError( - "Could not deserialize private key".to_string(), - ), - ))?; + let private_key = bls_signatures::SecretKey::from_be_bytes(&self.private_key).ok_or( + Error::BLSError(dpp::bls_signatures::BlsError::DeserializationError( + "Could not deserialize private key".to_string(), + )), + )?; let signature = private_key - .sign( - SignatureSchemes::Basic, - message_digest.as_byte_array().as_slice(), - ) + .sign(message_digest.as_byte_array().as_slice()) .map_err(Error::BLSError)?; - Ok(BLSSignature::from(signature.as_raw_value().to_compressed())) + Ok(BLSSignature::from(signature.to_bytes())) } } #[cfg(test)] mod tests { use super::*; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsPrivateKey}; + use dpp::bls_signatures::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore_rpc::json::QuorumType; /// Helper: generate a deterministic BLS public key from a seed byte. - fn make_public_key(seed: u8) -> ThresholdBlsPublicKey { + fn make_public_key(seed: u8) -> ThresholdBlsPublicKey { let mut key_bytes = [0u8; 32]; key_bytes[0] = seed; key_bytes[31] = 1; // ensure nonzero - let sk = BlsPrivateKey::::from_be_bytes(&key_bytes) + let sk = BlsPrivateKey::from_be_bytes(&key_bytes) .expect("expected a valid secret key from test bytes"); sk.public_key() } diff --git a/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs index 2fbab063bd1..0f8c7f9e6ae 100644 --- a/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs @@ -1,6 +1,6 @@ use crate::platform_types::platform_state::PlatformState; use crate::platform_types::platform_state::PlatformStateV0Methods; -use dpp::bls_signatures::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use dpp::bls_signatures::PublicKey as BlsPublicKey; pub use dpp::core_types::validator::v0::*; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash}; @@ -8,7 +8,7 @@ use dpp::dashcore_rpc::json::{DMNState, MasternodeListItem}; pub(crate) trait NewValidatorIfMasternodeInState { fn new_validator_if_masternode_in_state( pro_tx_hash: ProTxHash, - public_key: Option>, + public_key: Option, state: &PlatformState, ) -> Option; } @@ -17,7 +17,7 @@ impl NewValidatorIfMasternodeInState for ValidatorV0 { /// Makes a validator if the masternode is in the list and is valid fn new_validator_if_masternode_in_state( pro_tx_hash: ProTxHash, - public_key: Option>, + public_key: Option, state: &PlatformState, ) -> Option { let MasternodeListItem { state, .. } = state.hpmn_masternode_list().get(&pro_tx_hash)?; diff --git a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs index 4d639f64c1a..8b7aa17d9be 100644 --- a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs @@ -58,8 +58,8 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { return Err(Error::Execution(ExecutionError::CorruptedCachedState( format!( "updating validator set doesn't match threshold public key ours: {} theirs: {}", - hex::encode(self.threshold_public_key.0.to_compressed()), - hex::encode(rhs.threshold_public_key.0.to_compressed()) + hex::encode(self.threshold_public_key.to_bytes()), + hex::encode(rhs.threshold_public_key.to_bytes()) ), ))); } @@ -97,7 +97,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { Some(Ok(abci::ValidatorUpdate { pub_key: (*public_key).map(|public_key| crypto::PublicKey { - sum: Some(Bls12381(public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(public_key.to_bytes().to_vec())), }), power: 100, pro_tx_hash: pro_tx_hash.as_byte_array().to_vec(), @@ -123,7 +123,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { Some(Ok(abci::ValidatorUpdate { pub_key: (*public_key).map(|public_key| crypto::PublicKey { - sum: Some(Bls12381(public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(public_key.to_bytes().to_vec())), }), power: 100, pro_tx_hash: pro_tx_hash.to_byte_array().to_vec(), @@ -139,9 +139,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { Ok(ValidatorSetUpdate { validator_updates, threshold_public_key: Some(crypto::PublicKey { - sum: Some(Bls12381( - self.threshold_public_key.0.to_compressed().to_vec(), - )), + sum: Some(Bls12381(self.threshold_public_key.to_bytes().to_vec())), }), quorum_hash: self.quorum_hash.to_byte_array().to_vec(), }) @@ -174,7 +172,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { let node_address = validator_node_address(node_id, node_ip, *platform_p2p_port); Some(abci::ValidatorUpdate { pub_key: public_key.as_ref().map(|public_key| crypto::PublicKey { - sum: Some(Bls12381(public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(public_key.to_bytes().to_vec())), }), power: 100, pro_tx_hash: pro_tx_hash.to_byte_array().to_vec(), @@ -183,7 +181,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { }) .collect(), threshold_public_key: Some(crypto::PublicKey { - sum: Some(Bls12381(threshold_public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(threshold_public_key.to_bytes().to_vec())), }), quorum_hash: quorum_hash.to_byte_array().to_vec(), } @@ -217,7 +215,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { Some(abci::ValidatorUpdate { pub_key: public_key.map(|public_key| crypto::PublicKey { - sum: Some(Bls12381(public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(public_key.to_bytes().to_vec())), }), power: 100, pro_tx_hash: pro_tx_hash.to_byte_array().to_vec(), @@ -226,7 +224,7 @@ impl ValidatorSetMethodsV0 for ValidatorSetV0 { }) .collect(), threshold_public_key: Some(crypto::PublicKey { - sum: Some(Bls12381(threshold_public_key.0.to_compressed().to_vec())), + sum: Some(Bls12381(threshold_public_key.to_bytes().to_vec())), }), quorum_hash: quorum_hash.to_byte_array().to_vec(), } @@ -315,7 +313,7 @@ fn validator_node_address(node_id: &PubkeyHash, node_ip: &str, platform_p2p_port #[cfg(test)] mod tests { use super::*; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; use rand::rngs::StdRng; @@ -323,7 +321,7 @@ mod tests { fn make_validator(pro_tx_hash: ProTxHash, is_banned: bool) -> ValidatorV0 { let mut rng = StdRng::seed_from_u64(1); - let public_key = Some(SecretKey::::random(&mut rng).public_key()); + let public_key = Some(SecretKey::random(&mut rng).public_key()); ValidatorV0 { pro_tx_hash, public_key, @@ -343,7 +341,7 @@ mod tests { members: BTreeMap, ) -> ValidatorSetV0 { let mut rng = StdRng::seed_from_u64(threshold_seed); - let threshold_public_key = SecretKey::::random(&mut rng).public_key(); + let threshold_public_key = SecretKey::random(&mut rng).public_key(); ValidatorSetV0 { quorum_hash: QuorumHash::from_slice(&[quorum_hash_seed; 32]).unwrap(), quorum_index: Some(1), diff --git a/packages/rs-drive-abci/src/query/document_query/v1/tests.rs b/packages/rs-drive-abci/src/query/document_query/v1/tests.rs index cf2f59b6f15..d2abf839d32 100644 --- a/packages/rs-drive-abci/src/query/document_query/v1/tests.rs +++ b/packages/rs-drive-abci/src/query/document_query/v1/tests.rs @@ -3933,7 +3933,7 @@ mod having_trust_boundary { use crate::rpc::core::MockCoreRPCLike; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; use dpp::block::block_info::BlockInfo; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey, SignatureSchemes}; + use dpp::bls_signatures::SecretKey; use dpp::dashcore::Network; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; @@ -4024,12 +4024,10 @@ mod having_trust_boundary { } /// A deterministic, valid BLS scalar — no RNG dependency. - pub(super) fn quorum_secret_key() -> SecretKey { + pub(super) fn quorum_secret_key() -> SecretKey { let mut bytes = [0u8; 32]; bytes[31] = 42; - SecretKey::::from_be_bytes(&bytes) - .into_option() - .expect("a small nonzero scalar is a valid secret key") + SecretKey::from_be_bytes(&bytes).expect("a small nonzero scalar is a valid secret key") } fn register_grades( @@ -4192,7 +4190,7 @@ mod having_trust_boundary { grovedb_proof: Vec, app_hash: &[u8; 32], mtd: &ResponseMetadata, - secret_key: &SecretKey, + secret_key: &SecretKey, quorum_hash: [u8; 32], ) -> Proof { let block_id_hash = [7u8; 32].to_vec(); @@ -4224,10 +4222,9 @@ mod having_trust_boundary { ) .expect("sign digest"); let signature = secret_key - .sign(SignatureSchemes::Basic, &sign_digest) + .sign(&sign_digest) .expect("signing with a valid key succeeds") - .as_raw_value() - .to_compressed() + .to_bytes() .to_vec(); Proof { grovedb_proof, @@ -4254,7 +4251,7 @@ mod having_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, quorum_hash); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let query = client_side_query(&contract); @@ -4291,7 +4288,7 @@ mod having_trust_boundary { quorum_hash, ); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let query = client_side_query(&contract); @@ -4316,7 +4313,7 @@ mod having_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, quorum_hash); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let mut tampered = mtd; @@ -4347,11 +4344,9 @@ mod having_trust_boundary { let mut other_bytes = [0u8; 32]; other_bytes[31] = 43; - let other_key = SecretKey::::from_be_bytes(&other_bytes) - .into_option() - .expect("valid scalar"); + let other_key = SecretKey::from_be_bytes(&other_bytes).expect("valid scalar"); let provider = TestQuorumProvider { - pubkey: other_key.public_key().0.to_compressed(), + pubkey: other_key.public_key().to_bytes(), }; let query = client_side_query(&contract); @@ -4665,7 +4660,7 @@ mod time_range_proof_verification { QUORUM_HASH, ); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; (signed, mtd, provider) } @@ -6711,7 +6706,7 @@ mod chained_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, quorum_hash); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let (verified, _mtd, _proof) = @@ -6754,14 +6749,10 @@ mod chained_trust_boundary { let other_key = { let mut bytes = [0u8; 32]; bytes[31] = 43; - dpp::bls_signatures::SecretKey::::from_be_bytes( - &bytes, - ) - .into_option() - .expect("valid scalar") + dpp::bls_signatures::SecretKey::from_be_bytes(&bytes).expect("valid scalar") }; let provider = TestQuorumProvider { - pubkey: other_key.public_key().0.to_compressed(), + pubkey: other_key.public_key().to_bytes(), }; let refused = @@ -6788,7 +6779,7 @@ mod chained_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, [5u8; 32]); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let mut tampered = mtd; tampered.height += 1; @@ -7048,7 +7039,7 @@ mod composite_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, quorum_hash); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let response = response_with(proof, mtd); @@ -7205,14 +7196,10 @@ mod composite_trust_boundary { let other_key = { let mut bytes = [0u8; 32]; bytes[31] = 44; - dpp::bls_signatures::SecretKey::::from_be_bytes( - &bytes, - ) - .into_option() - .expect("valid scalar") + dpp::bls_signatures::SecretKey::from_be_bytes(&bytes).expect("valid scalar") }; let provider = TestQuorumProvider { - pubkey: other_key.public_key().0.to_compressed(), + pubkey: other_key.public_key().to_bytes(), }; let refused = @@ -7240,7 +7227,7 @@ mod composite_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, [6u8; 32]); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let mut tampered = mtd; tampered.height += 1; @@ -7285,7 +7272,7 @@ mod composite_trust_boundary { let mtd = metadata(); let proof = signed_proof(grovedb_proof, &root_hash, &mtd, &secret_key, [6u8; 32]); let provider = TestQuorumProvider { - pubkey: secret_key.public_key().0.to_compressed(), + pubkey: secret_key.public_key().to_bytes(), }; let refused = diff --git a/packages/rs-drive-abci/src/query/system/current_quorums_info/v0/mod.rs b/packages/rs-drive-abci/src/query/system/current_quorums_info/v0/mod.rs index ee6fa018a85..b5c684c80f1 100644 --- a/packages/rs-drive-abci/src/query/system/current_quorums_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/system/current_quorums_info/v0/mod.rs @@ -41,11 +41,7 @@ impl Platform { quorum_hash: validator_set.quorum_hash().as_byte_array().to_vec(), core_height: validator_set.core_height(), members, - threshold_public_key: validator_set - .threshold_public_key() - .0 - .to_compressed() - .to_vec(), + threshold_public_key: validator_set.threshold_public_key().to_bytes().to_vec(), } }) .collect(); diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 6d25d111b30..57f34db3ad4 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -19,7 +19,7 @@ use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use strategy_tests::operations::FinalizeBlockOperation::IdentityAddKeys; -use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsPrivateKey, SignatureSchemes}; +use dpp::bls_signatures::SecretKey as BlsPrivateKey; use dpp::dashcore::consensus::Encodable; use dpp::dashcore::hashes::{sha256d, HashEngine}; use dpp::dashcore::{ChainLock, QuorumSigningRequestId, VarInt}; @@ -733,19 +733,15 @@ pub(crate) async fn run_chain_for_strategy<'a>( let message_digest = sha256d::Hash::from_engine(engine); - let quorum_private_key = - BlsPrivateKey::::from_be_bytes(quorum_private_key) - .expect("expected to have a valid private key"); + let quorum_private_key = BlsPrivateKey::from_be_bytes(quorum_private_key) + .expect("expected to have a valid private key"); let signature = quorum_private_key - .sign( - SignatureSchemes::Basic, - message_digest.as_byte_array().as_slice(), - ) + .sign(message_digest.as_byte_array().as_slice()) .expect("expected to sign"); let chain_lock = ChainLock { block_height, block_hash: BlockHash::from_byte_array(*block_hash), - signature: signature.as_raw_value().to_compressed().into(), + signature: signature.to_bytes().into(), }; Ok(chain_lock) @@ -860,9 +856,7 @@ pub(crate) async fn start_chain_for_strategy<'a>( .map( |validator_in_quorum| tenderdash_abci::proto::abci::ValidatorUpdate { pub_key: Some(tenderdash_abci::proto::crypto::PublicKey { - sum: Some(Bls12381( - validator_in_quorum.public_key.0.to_compressed().to_vec(), - )), + sum: Some(Bls12381(validator_in_quorum.public_key.to_bytes().to_vec())), }), power: 100, pro_tx_hash: validator_in_quorum.pro_tx_hash.to_byte_array().to_vec(), @@ -872,11 +866,7 @@ pub(crate) async fn start_chain_for_strategy<'a>( .collect(), threshold_public_key: Some(tenderdash_abci::proto::crypto::PublicKey { sum: Some(Bls12381( - current_quorum_with_test_info - .public_key - .0 - .to_compressed() - .to_vec(), + current_quorum_with_test_info.public_key.to_bytes().to_vec(), )), }), quorum_hash: current_validator_quorum_hash.to_byte_array().to_vec(), diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs index 3ada8f30353..d64b60a110a 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs @@ -1,5 +1,5 @@ use crate::BlsPrivateKey; -use dpp::bls_signatures::Bls12381G2Impl; + use dpp::dashcore_rpc::json::MasternodeListItem; use rand::prelude::IteratorRandom; use rand::rngs::StdRng; @@ -39,12 +39,11 @@ impl UpdateMasternodeListItem for MasternodeListItem { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let pub_key_operator = - private_key_operator.public_key().0.to_compressed().to_vec(); + let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); self.state.pub_key_operator = pub_key_operator; } 4 => { @@ -97,11 +96,11 @@ mod tests { .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Regular, pro_tx_hash, diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs index 60d53f8fabc..b55e06b865f 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs @@ -1,5 +1,5 @@ use crate::masternode_list_item_helpers::UpdateMasternodeListItem; -use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsPrivateKey}; +use dpp::bls_signatures::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, QuorumHash, Txid}; use dpp::dashcore_rpc::dashcore_rpc_json::{DMNState, MasternodeListItem, MasternodeType}; @@ -233,11 +233,11 @@ pub fn generate_test_masternodes( .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let pro_tx_hash = ProTxHash::from_byte_array(rng.gen::<[u8; 32]>()); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Regular, @@ -375,11 +375,11 @@ pub fn generate_test_masternodes( .expect("expected to generate a private key") .to_bytes() .to_vec(); - let private_key_operator = BlsPrivateKey::::from_be_bytes( + let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) .expect("expected the conversion between bls signatures library and blsful to happen without failing"); - let pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Evo, pro_tx_hash: ProTxHash::from_byte_array(rng.gen::<[u8; 32]>()), diff --git a/packages/rs-drive-abci/tests/strategy_tests/query.rs b/packages/rs-drive-abci/tests/strategy_tests/query.rs index a7b89ac350c..ac7f30fa85f 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/query.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/query.rs @@ -9,7 +9,7 @@ use dapi_grpc::platform::v0::{ get_identity_by_public_key_hash_request, get_identity_by_public_key_hash_response, GetIdentityByPublicKeyHashRequest, Proof, }; -use dpp::bls_signatures::{Bls12381G2Impl, BlsError, Pairing, Signature}; +use dpp::bls_signatures::{BlsError, Signature}; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; @@ -74,7 +74,7 @@ pub struct ProofVerification<'a> { pub signature: &'a [u8; 96], /// Threshold key used to verify the signature - pub public_key: &'a dpp::bls_signatures::PublicKey, + pub public_key: &'a dpp::bls_signatures::PublicKey, } impl ProofVerification<'_> { @@ -111,20 +111,17 @@ impl ProofVerification<'_> { Err(e) => return SimpleValidationResult::new_with_error(e.into()), }; // We could have received a fake commit, so signature validation needs to be returned if error as a simple validation result - let signature = - match ::Signature::from_compressed(self.signature) - .into_option() - { - Some(signature) => Signature::Basic(signature), - None => { - return SimpleValidationResult::new_with_error( - AbciError::BlsErrorOfTenderdashThresholdMechanism( - BlsError::InvalidSignature, - format!("malformed signature data: {}", hex::encode(self.signature)), - ), - ); - } - }; + let signature = match Signature::from_compressed(self.signature) { + Some(signature) => signature, + None => { + return SimpleValidationResult::new_with_error( + AbciError::BlsErrorOfTenderdashThresholdMechanism( + BlsError::InvalidSignature, + format!("malformed signature data: {}", hex::encode(self.signature)), + ), + ); + } + }; tracing::trace!( digest=hex::encode(&digest), ?state_id, diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs index e048c50ba76..ef3b61472ba 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs @@ -75,12 +75,7 @@ mod tests { .iter() .map(|(quorum_hash, quorum_info)| { let quorum_hash_bytes: [u8; 32] = *quorum_hash.as_raw_hash().as_byte_array(); - let public_key_bytes: [u8; 48] = quorum_info - .public_key - .0 - .to_compressed() - .try_into() - .expect("public key should be 48 bytes"); + let public_key_bytes: [u8; 48] = quorum_info.public_key.to_bytes(); ((quorum_hash_bytes, quorum_type), public_key_bytes) }) .collect(); diff --git a/packages/rs-drive-proof-verifier/src/unproved.rs b/packages/rs-drive-proof-verifier/src/unproved.rs index fde99cc3399..4bedaa3fd0a 100644 --- a/packages/rs-drive-proof-verifier/src/unproved.rs +++ b/packages/rs-drive-proof-verifier/src/unproved.rs @@ -315,7 +315,7 @@ mod tests { use dapi_grpc::platform::v0::{ get_current_quorums_info_response, get_status_response, ResponseMetadata, }; - use dpp::bls_signatures::{Bls12381G2Impl, SecretKey}; + use dpp::bls_signatures::SecretKey; use dpp::version::PlatformVersion; /// Generate a valid BLS public key as compressed bytes (48 bytes) from a @@ -323,11 +323,8 @@ mod tests { fn generate_valid_bls_public_key_bytes(seed: u8) -> Vec { let mut secret_bytes = [0u8; 32]; secret_bytes[31] = seed.max(1); // ensure nonzero - let sk: SecretKey = - SecretKey::::from_be_bytes(&secret_bytes) - .into_option() - .expect("valid secret key"); - sk.public_key().0.to_compressed().to_vec() + let sk: SecretKey = SecretKey::from_be_bytes(&secret_bytes).expect("valid secret key"); + sk.public_key().to_bytes().to_vec() } /// Helper: build a valid GetCurrentQuorumsInfoResponse with one quorum hash, diff --git a/packages/rs-drive-proof-verifier/src/verify.rs b/packages/rs-drive-proof-verifier/src/verify.rs index 13e5188b5e8..045b3f0a521 100644 --- a/packages/rs-drive-proof-verifier/src/verify.rs +++ b/packages/rs-drive-proof-verifier/src/verify.rs @@ -2,7 +2,7 @@ use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; use dpp::bls_signatures; use crate::Error; -use dpp::bls_signatures::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls_signatures::Signature; use tenderdash_abci::{ proto::types::{CanonicalVote, SignedMsgType, StateId}, signatures::{Hashable, Signable}, @@ -134,10 +134,11 @@ pub(crate) fn verify_tenderdash_signature( } })?; - let pubkey = bls_signatures::PublicKey::::try_from(pubkey_bytes.as_slice()) - .map_err(|e| Error::InvalidPublicKey { + let pubkey = bls_signatures::PublicKey::try_from(pubkey_bytes.as_slice()).map_err(|e| { + Error::InvalidPublicKey { error: e.to_string(), - })?; + } + })?; tracing::trace!( ?state_id, @@ -164,20 +165,17 @@ pub(crate) fn verify_tenderdash_signature( pub fn verify_signature_digest( sign_digest: &[u8], signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls_signatures::PublicKey, ) -> Result { if signature == &[0; 96] { return Err(Error::SignatureVerificationError { error: "empty signature".to_string(), }); } - let signature = Signature::Basic( - ::Signature::from_compressed(signature) - .into_option() - .ok_or(Error::SignatureVerificationError { - error: "Could not verify signature digest".to_string(), - })?, - ); + let signature = + Signature::from_compressed(signature).ok_or(Error::SignatureVerificationError { + error: "Could not verify signature digest".to_string(), + })?; Ok(signature.verify(public_key, sign_digest).is_ok()) } @@ -339,11 +337,13 @@ mod tests { } /// Helper: create a deterministic BLS key pair for testing. - fn test_keypair() -> ( - bls_signatures::SecretKey, - bls_signatures::PublicKey, - ) { - let sk = bls_signatures::SecretKey::::from_hash(b"test-key-seed"); + fn test_keypair() -> (bls_signatures::SecretKey, bls_signatures::PublicKey) { + let scalar = + hex::decode("659dc45452f29c17f96dda38ae1546e0e9e818423cdb8cc857f3728c518b4cb8") + .unwrap() + .try_into() + .unwrap(); + let sk = bls_signatures::SecretKey::from_be_bytes(&scalar).unwrap(); let pk = sk.public_key(); (sk, pk) } @@ -358,7 +358,7 @@ mod tests { impl ValidKeyContextProvider { fn new() -> Self { let (_, pk) = test_keypair(); - let pk_vec: Vec = (&pk).into(); + let pk_vec = pk.to_bytes().to_vec(); let mut pubkey_bytes = [0u8; 48]; pubkey_bytes.copy_from_slice(&pk_vec); Self { pubkey_bytes } diff --git a/packages/rs-platform-wallet/src/masternode/locator.rs b/packages/rs-platform-wallet/src/masternode/locator.rs index aea3f136a98..dee37b613e4 100644 --- a/packages/rs-platform-wallet/src/masternode/locator.rs +++ b/packages/rs-platform-wallet/src/masternode/locator.rs @@ -38,9 +38,7 @@ use dash_sdk::platform::Fetch; use dashcore::hashes::{hash160, Hash}; use dashcore::secp256k1::{PublicKey as SecpPublicKey, SecretKey as SecpSecretKey}; use dashcore::{Network, PrivateKey}; -use dpp::bls_signatures::{ - Bls12381G2Impl, PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, SerializationFormat, -}; +use dpp::bls_signatures::SecretKey as BlsSecretKey; use dpp::ed25519_dalek::SigningKey; use dpp::identifier::MasternodeIdentifiers; use dpp::identity::accessors::IdentityGettersV0; @@ -371,18 +369,10 @@ pub fn ecdsa_key_id(secret: &[u8; 32], compressed: bool) -> Option<[u8; 20]> { } /// `(basic, legacy)` 48-byte serializations of the BLS public key for -/// `secret`, or `None` when the scalar is not below the group order. +/// `secret`, or `None` when the scalar reduces to zero. pub fn bls_public_keys(secret: &[u8; 32]) -> Option<([u8; 48], [u8; 48])> { - let sk: BlsSecretKey = - Option::from(BlsSecretKey::::from_be_bytes(secret))?; - let pk = BlsPublicKey::from(&sk); - let basic: [u8; 48] = pk.to_bytes().as_slice().try_into().ok()?; - let legacy: [u8; 48] = pk - .to_bytes_with_mode(SerializationFormat::Legacy) - .as_slice() - .try_into() - .ok()?; - Some((basic, legacy)) + let pk = BlsSecretKey::from_be_bytes(secret)?.public_key(); + Some((pk.to_bytes(), pk.to_legacy_bytes().ok()?)) } /// Tenderdash node id for an ed25519 `seed`. diff --git a/packages/rs-platform-wallet/src/masternode/update_service.rs b/packages/rs-platform-wallet/src/masternode/update_service.rs index 673dcd9a3d8..39e59b5395f 100644 --- a/packages/rs-platform-wallet/src/masternode/update_service.rs +++ b/packages/rs-platform-wallet/src/masternode/update_service.rs @@ -26,7 +26,7 @@ use dashcore::hash_types::InputsHash; use dashcore::hashes::Hash; use dashcore::platform_node_id::PlatformNodeId; use dashcore::{Address as DashAddress, Network, Transaction, Txid}; -use dpp::bls_signatures::{Bls12381G2Impl, SecretKey as BlsSecretKey, SignatureSchemes}; +use dpp::bls_signatures::SecretKey as BlsSecretKey; use key_wallet::wallet::managed_wallet_info::transaction_builder::{ BuilderError, TransactionBuilder, TransactionSigner, }; @@ -405,25 +405,13 @@ pub(crate) fn finalize_update_service_payload( let mut finalized = placeholder.clone(); finalized.inputs_hash = unsigned.hash_inputs(); - let secret = Option::>::from( - BlsSecretKey::::from_be_bytes(operator_secret), - ) - .ok_or_else(|| { + let secret = BlsSecretKey::from_be_bytes(operator_secret).ok_or_else(|| { BuilderError::SigningFailed("the operator key is not a valid BLS secret".into()) })?; let signature = secret - .sign( - SignatureSchemes::Basic, - finalized.base_payload_hash().as_byte_array(), - ) + .sign(finalized.base_payload_hash().as_byte_array()) .map_err(|e| BuilderError::SigningFailed(format!("BLS payload signing failed: {e}")))?; - let signature_bytes: [u8; 96] = signature - .to_bytes_with_mode(dpp::bls_signatures::SerializationFormat::Modern) - .as_slice() - .try_into() - .map_err(|_| { - BuilderError::SigningFailed("BLS signature did not serialize to 96 bytes".into()) - })?; + let signature_bytes = signature.to_bytes(); finalized.payload_sig = BLSSignature::from(signature_bytes); Ok(TransactionPayload::ProviderUpdateServicePayloadType( finalized, @@ -801,17 +789,10 @@ mod tests { // The payload signature verifies under the basic scheme against the // operator public key, over base_payload_hash — the exact convention // `verify_message_digest` checks real mainnet signatures with. - let secret = Option::>::from( - BlsSecretKey::::from_be_bytes(&OPERATOR_SECRET), - ) - .expect("valid test scalar"); + let secret = BlsSecretKey::from_be_bytes(&OPERATOR_SECRET).expect("valid test scalar"); let public_key = BlsPublicKey::from(&secret); - let signature = BlsSignature::::from_bytes_with_mode( - payload.payload_sig.as_bytes(), - SignatureSchemes::Basic, - dpp::bls_signatures::SerializationFormat::Modern, - ) - .expect("compressed signature decodes"); + let signature = BlsSignature::from_compressed(payload.payload_sig.as_bytes()) + .expect("compressed signature decodes"); signature .verify(&public_key, payload.base_payload_hash().as_byte_array()) .expect("operator BLS signature verifies over base_payload_hash"); diff --git a/packages/rs-sdk-ffi/src/system/queries/current_quorums_info.rs b/packages/rs-sdk-ffi/src/system/queries/current_quorums_info.rs index 6105efcd5bc..d5580ebce62 100644 --- a/packages/rs-sdk-ffi/src/system/queries/current_quorums_info.rs +++ b/packages/rs-sdk-ffi/src/system/queries/current_quorums_info.rs @@ -105,7 +105,7 @@ fn get_current_quorums_info(sdk_handle: *const SDKHandle) -> Result for SimpleSigner { Ok(signature.to_vec().into()) } KeyType::BLS12_381 => { - let pk = bls_signatures::SecretKey::::from_be_bytes(private_key) - .into_option() - .ok_or(ProtocolError::Generic( - "bls private key from bytes isn't correct".to_string(), - ))?; + let pk = bls_signatures::SecretKey::from_be_bytes(private_key).ok_or( + ProtocolError::Generic("bls private key from bytes isn't correct".to_string()), + )?; let signature = pk - .sign(SignatureSchemes::Basic, data) + .sign(data) .map_err(|e| ProtocolError::Generic(format!("BLS signing failed {}", e)))?; - Ok(signature.as_raw_value().to_compressed().to_vec().into()) + Ok(signature.to_bytes().to_vec().into()) } KeyType::EDDSA_25519_HASH160 => { #[allow(clippy::unnecessary_fallible_conversions)] From 4eec83c41203ae94fd385b05d6b9d7b905ceea66 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 08:32:45 +0000 Subject: [PATCH 03/11] test: describe BLS fixture conversion without removed backend names Co-authored-by: Codex --- .../update_operator_identity/v0/mod.rs | 8 ++++---- .../tests/strategy_tests/masternode_list_item_helpers.rs | 4 ++-- .../rs-drive-abci/tests/strategy_tests/masternodes.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs index d88a16ac73b..ce2e5d4ade7 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs @@ -436,7 +436,7 @@ mod tests { let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let operator_key: IdentityPublicKey = IdentityPublicKeyV0 { @@ -979,7 +979,7 @@ mod tests { let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state @@ -1078,7 +1078,7 @@ mod tests { .expect("expected the secret key to be 32 bytes"), ) .expect( - "expected the conversion between bls signatures library and blsful to happen without failing", + "Core fixture public key must decode as a Platform BLS key", ); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); @@ -1218,7 +1218,7 @@ mod tests { let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state with original public key operator diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs index d64b60a110a..33b778c8098 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs @@ -42,7 +42,7 @@ impl UpdateMasternodeListItem for MasternodeListItem { let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); self.state.pub_key_operator = pub_key_operator; } @@ -99,7 +99,7 @@ mod tests { let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Regular, diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs index b55e06b865f..390b282aec0 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs @@ -236,7 +236,7 @@ pub fn generate_test_masternodes( let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let pro_tx_hash = ProTxHash::from_byte_array(rng.gen::<[u8; 32]>()); let masternode_list_item = MasternodeListItem { @@ -378,7 +378,7 @@ pub fn generate_test_masternodes( let private_key_operator = BlsPrivateKey::from_be_bytes( &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), ) - .expect("expected the conversion between bls signatures library and blsful to happen without failing"); + .expect("Core fixture public key must decode as a Platform BLS key"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Evo, From 734bd4eea749371d13af8d4cc84ec65a3c96f449 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 08:33:16 +0000 Subject: [PATCH 04/11] test: format secret key fixture assertions Co-authored-by: Codex --- .../update_operator_identity/v0/mod.rs | 22 +++++++++++-------- .../masternode_list_item_helpers.rs | 12 ++++++---- .../tests/strategy_tests/masternodes.rs | 12 ++++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs index ce2e5d4ade7..e0cc5edb6a8 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs @@ -434,9 +434,11 @@ mod tests { .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let operator_key: IdentityPublicKey = IdentityPublicKeyV0 { @@ -977,9 +979,11 @@ mod tests { .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state @@ -1077,9 +1081,7 @@ mod tests { .try_into() .expect("expected the secret key to be 32 bytes"), ) - .expect( - "Core fixture public key must decode as a Platform BLS key", - ); + .expect("Core fixture secret key must decode"); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let new_operator_identifier = Identifier::create_operator_identifier( @@ -1216,9 +1218,11 @@ mod tests { .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let new_pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); // Create an old masternode state with original public key operator diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs index 33b778c8098..c9dbe379d11 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs @@ -40,9 +40,11 @@ impl UpdateMasternodeListItem for MasternodeListItem { .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); self.state.pub_key_operator = pub_key_operator; } @@ -97,9 +99,11 @@ mod tests { .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Regular, diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs index 390b282aec0..b85fe47c5ac 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs @@ -234,9 +234,11 @@ pub fn generate_test_masternodes( .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let pro_tx_hash = ProTxHash::from_byte_array(rng.gen::<[u8; 32]>()); let masternode_list_item = MasternodeListItem { @@ -376,9 +378,11 @@ pub fn generate_test_masternodes( .to_bytes() .to_vec(); let private_key_operator = BlsPrivateKey::from_be_bytes( - &private_key_operator_bytes.try_into().expect("expected the secret key to be 32 bytes"), + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), ) - .expect("Core fixture public key must decode as a Platform BLS key"); + .expect("Core fixture secret key must decode"); let pub_key_operator = private_key_operator.public_key().to_bytes().to_vec(); let masternode_list_item = MasternodeListItem { node_type: MasternodeType::Evo, From 4ea09be343f1a31d65d24b1f4266baa997be6f0d Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 09:50:59 +0000 Subject: [PATCH 05/11] refactor(drive-abci): reject legacy BLS storage with upgrade instructions Reserve legacy enum tags while rejecting their payloads at deserialization. Require v4.0.0 to commit a block before opening older databases. Remove legacy readers and the default production dependency on bls-signatures; retain the dependency only for tests and explicit mocks. Test legacy rejection, supported storage tags, persisted-state round trips, and the existing serialization hash using a pre-removal fixture. Co-Authored-By: Codex --- packages/rs-drive-abci/Cargo.toml | 4 +- .../rs-drive-abci/src/platform_types/mod.rs | 2 + .../src/platform_types/platform_state/mod.rs | 78 +++++++--- .../platform_state_for_saving/mod.rs | 8 +- .../platform_state_for_saving/v0/mod.rs | 98 ------------ .../v0/old_structures/mod.rs | 122 --------------- .../signature_verification_quorum_set/mod.rs | 47 ++++-- .../v0/for_saving_v0.rs | 143 ------------------ .../v0/for_saving_v1.rs | 58 +------ .../v0/for_saving_v2.rs | 4 - .../v0/mod.rs | 1 - .../unsupported_legacy_bls_storage.rs | 28 ++++ .../test/fixture/platform_state_supported.hex | 1 + 13 files changed, 131 insertions(+), 463 deletions(-) delete mode 100644 packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs delete mode 100644 packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs delete mode 100644 packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs create mode 100644 packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs create mode 100644 packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 1d194f2416d..d4fb5c9b18f 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -129,8 +129,8 @@ grovedb-path = { workspace = true } grovedb-storage = { workspace = true } [features] -default = ["bls-signatures"] -mocks = ["mockall", "drive/fixtures-and-mocks", "bls-signatures"] +default = [] +mocks = ["mockall", "drive/fixtures-and-mocks", "dep:bls-signatures"] console = ["console-subscriber", "tokio/tracing"] testing-config = [] # Compiles in the shielded-pool seeder, the `snapshot-bake` subcommand, and diff --git a/packages/rs-drive-abci/src/platform_types/mod.rs b/packages/rs-drive-abci/src/platform_types/mod.rs index 0f3b33981de..86bab2f76cd 100644 --- a/packages/rs-drive-abci/src/platform_types/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/mod.rs @@ -24,6 +24,8 @@ pub mod required_identity_public_key_set; pub mod signature_verification_quorum_set; /// The state transition execution result as part of the block execution outcome pub mod state_transitions_processing_result; +/// Rejection of unsupported legacy BLS storage formats. +pub mod unsupported_legacy_bls_storage; /// The validator module /// A validator is a masternode that can participate in consensus by being part of a validator set pub mod validator; diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index f4467c9cce9..7f30883b653 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -323,18 +323,7 @@ impl TryFromPlatformVersioned for PlatformState { platform_version: &PlatformVersion, ) -> Result { match value { - PlatformStateForSaving::V0(v0) => { - match platform_version.drive_abci.structs.platform_state_structure { - 0 => Ok(PlatformState::from(v0)), - version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { - method: - "PlatformState::try_from_platform_versioned(PlatformStateForSavingV0)" - .to_string(), - known_versions: vec![0], - received: version, - })), - } - } + PlatformStateForSaving::V0(unsupported) => match unsupported {}, PlatformStateForSaving::V1(v1) => { match platform_version.drive_abci.structs.platform_state_structure { 0 => Ok(PlatformState::from(v1)), @@ -375,19 +364,32 @@ mod tests { use std::ops::Deref; #[test] - fn should_deserialize_state_stored_in_version_0_from_testnet() { + fn should_reject_legacy_bls_state_from_testnet_with_upgrade_instructions() { let serialized_state = hex::decode(PLATFORM_STATE_V3_TESTNET.deref()).expect("failed to decode hex"); - PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V3) - .expect("failed to deserialize state"); + let error = + match PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V3) + { + Ok(_) => panic!("legacy state must require an intermediate upgrade"), + Err(error) => error, + }; + assert!(matches!( + error, + ProtocolError::PlatformDeserializationError(_) + )); + assert!(error.to_string().contains("v4.0.0")); + assert!(error.to_string().contains("commit at least one block")); } /// Serializing through the borrowed conversion must preserve the saved format. #[test] fn should_preserve_pre_change_serialization_hash() { + // Re-serialized from PLATFORM_STATE_V8_DEVNET with commit 734bd4eea7, + // before removal of the legacy readers. Platform state V1, quorum V2. let serialized_state = - hex::decode(PLATFORM_STATE_V8_DEVNET.deref()).expect("failed to decode hex"); + hex::decode(include_str!("../../test/fixture/platform_state_supported.hex").trim()) + .expect("failed to decode hex"); let state = PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) @@ -404,12 +406,50 @@ mod tests { } #[test] - fn should_deserialize_state_stored_in_version_8_from_devnet() { + fn should_preserve_supported_storage_tags_and_bytes() { + let bytes = + hex::decode(include_str!("../../test/fixture/platform_state_supported.hex").trim()) + .unwrap(); + let state = PlatformState::versioned_deserialize_trusted(&bytes, &PLATFORM_V9).unwrap(); + let config = config::standard().with_big_endian(); + let v1 = PlatformStateForSavingV1::try_from(&state).unwrap(); + for quorums in [ + &v1.chain_lock_validating_quorums, + &v1.instant_lock_validating_quorums, + ] { + let encoded = bincode::encode_to_vec(quorums, config).unwrap(); + assert_eq!(encoded[0], 2, "quorum storage tag must remain V2"); + } + let v2 = PlatformStateForSavingV2::from(&state); + for (tag, record) in [ + (1, PlatformStateForSaving::V1(v1)), + (2, PlatformStateForSaving::V2(v2)), + ] { + let encoded = bincode::encode_to_vec(record, config).unwrap(); + assert_eq!(encoded[0], tag, "platform storage tag must not change"); + let (decoded, consumed): (PlatformStateForSaving, _) = + bincode::borrow_decode_from_slice(&encoded, config).unwrap(); + assert_eq!(consumed, encoded.len()); + assert_eq!(bincode::encode_to_vec(decoded, config).unwrap(), encoded); + } + } + + #[test] + fn should_reject_devnet_state_containing_legacy_quorums() { let serialized_state = hex::decode(PLATFORM_STATE_V8_DEVNET.deref()).expect("failed to decode hex"); - PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) - .expect("failed to deserialize state"); + let error = + match PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) + { + Ok(_) => panic!("legacy quorums must require an intermediate upgrade"), + Err(error) => error, + }; + assert!(matches!( + error, + ProtocolError::PlatformDeserializationError(_) + )); + assert!(error.to_string().contains("v4.0.0")); } } } diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs index c737c7a1a8b..2ee162a1ddb 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs @@ -1,12 +1,10 @@ -use crate::platform_types::platform_state::platform_state_for_saving::v0::PlatformStateForSavingV0; use crate::platform_types::platform_state::platform_state_for_saving::v1::PlatformStateForSavingV1; use crate::platform_types::platform_state::platform_state_for_saving::v2::PlatformStateForSavingV2; +use crate::platform_types::unsupported_legacy_bls_storage::UnsupportedLegacyBlsStorage; use bincode::Encode; use derive_more::From; use dpp::platform_serialization::de::Decode; -/// Structure 0 as first shipped. -pub mod v0; /// Structure 0 with the previous fee versions. pub mod v1; /// Structure 1: masternodes and validator sets as entries beside the record. @@ -15,8 +13,8 @@ pub mod v2; /// Platform state #[derive(Clone, Debug, Encode, Decode, From)] pub enum PlatformStateForSaving { - /// Version 0 - V0(PlatformStateForSavingV0), + /// Unsupported legacy format; its tag remains reserved. + V0(UnsupportedLegacyBlsStorage), /// Version 1 V1(PlatformStateForSavingV1), /// Version 2: the masternode list and the validator sets live as one aux diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs deleted file mode 100644 index 6db1974da24..00000000000 --- a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::platform_types::masternode::Masternode; -use crate::platform_types::platform_state::entry_changes::EntryChanges; -use crate::platform_types::platform_state::PlatformState; -use crate::platform_types::signature_verification_quorum_set::SignatureVerificationQuorumSetForSaving; -use bincode::Encode; -use dpp::block::block_info::BlockInfo; -use dpp::block::extended_block_info::ExtendedBlockInfo; -use dpp::dashcore::hashes::Hash; -use dpp::dashcore::{ProTxHash, QuorumHash}; -use dpp::fee::default_costs::CachedEpochIndexFeeVersionsFieldsBeforeVersion4; -use dpp::platform_serialization::de::Decode; -use dpp::platform_value::Bytes32; -use dpp::util::deserializer::ProtocolVersion; -use dpp::version::fee::FeeVersion; -use std::collections::BTreeMap; - -mod old_structures; - -/// Platform state -#[derive(Clone, Debug, Encode, Decode)] -pub struct PlatformStateForSavingV0 { - /// Information about the genesis block - pub genesis_block_info: Option, - /// Information about the last block - pub last_committed_block_info: Option, - /// Current Version - pub current_protocol_version_in_consensus: ProtocolVersion, - /// upcoming protocol version - pub next_epoch_protocol_version: ProtocolVersion, - /// current quorum - pub current_validator_set_quorum_hash: Bytes32, - /// next quorum - pub next_validator_set_quorum_hash: Option, - /// current validator set quorums - /// The validator set quorums are a subset of the quorums, but they also contain the list of - /// all members - #[bincode(with_serde)] - pub validator_sets: Vec<(Bytes32, old_structures::OldStructureValidatorSet)>, - - /// The quorums used for validating chain locks - pub chain_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, - - /// The quorums used for validating instant locks - pub instant_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, - - /// current full masternode list - pub full_masternode_list: BTreeMap, - - /// current HPMN masternode list - pub hpmn_masternode_list: BTreeMap, - - /// previous FeeVersions - pub previous_fee_versions: CachedEpochIndexFeeVersionsFieldsBeforeVersion4, -} - -impl From for PlatformState { - fn from(value: PlatformStateForSavingV0) -> Self { - PlatformState { - genesis_block_info: value.genesis_block_info, - last_committed_block_info: value.last_committed_block_info, - current_protocol_version_in_consensus: value.current_protocol_version_in_consensus, - next_epoch_protocol_version: value.next_epoch_protocol_version, - current_validator_set_quorum_hash: QuorumHash::from_byte_array( - value.current_validator_set_quorum_hash.to_buffer(), - ), - next_validator_set_quorum_hash: value - .next_validator_set_quorum_hash - .map(|bytes| QuorumHash::from_byte_array(bytes.to_buffer())), - validator_sets: value - .validator_sets - .into_iter() - .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v.into())) - .collect(), - chain_lock_validating_quorums: value.chain_lock_validating_quorums.into(), - instant_lock_validating_quorums: value.instant_lock_validating_quorums.into(), - full_masternode_list: value - .full_masternode_list - .into_iter() - .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) - .collect(), - hpmn_masternode_list: value - .hpmn_masternode_list - .into_iter() - .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) - .collect(), - previous_fee_versions: value - .previous_fee_versions - .into_keys() - .map(|epoch_index| (epoch_index, FeeVersion::first())) - .collect(), - // a state read back from disk has not been written in full since - heavy_fields_dirty: true, - // this record carried the collections itself, so no entries back it on disk - masternode_changes: EntryChanges::all(), - validator_set_changes: EntryChanges::all(), - } - } -} diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs deleted file mode 100644 index a5b7a11c78d..00000000000 --- a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs +++ /dev/null @@ -1,122 +0,0 @@ -#[cfg(feature = "bls-signatures")] -use dpp::bls_signatures::PublicKey; -use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum OldStructureValidatorSet { - /// Version 0 - V0(OldStructureValidatorSetV0), -} - -impl From for dpp::core_types::validator_set::ValidatorSet { - fn from(value: OldStructureValidatorSet) -> Self { - match value { - OldStructureValidatorSet::V0(v0) => { - dpp::core_types::validator_set::ValidatorSet::V0(v0.into()) - } - } - } -} - -/// The validator set is only slightly different from a quorum as it does not contain non valid -/// members -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct OldStructureValidatorSetV0 { - /// The quorum hash - pub quorum_hash: QuorumHash, - /// Rotation quorum index is available only for DIP24 quorums - pub quorum_index: Option, - /// Active height - pub core_height: u32, - /// The list of masternodes - pub members: BTreeMap, - /// The threshold quorum public key - #[cfg(feature = "bls-signatures")] - pub threshold_public_key: bls_signatures::PublicKey, - - /// Extra fields for forward compatibility. - #[cfg(not(feature = "bls-signatures"))] - #[serde(flatten)] - pub extra_fields: std::collections::HashMap, -} - -impl From for dpp::core_types::validator_set::v0::ValidatorSetV0 { - fn from(value: OldStructureValidatorSetV0) -> Self { - let OldStructureValidatorSetV0 { - quorum_hash, - quorum_index, - core_height, - members, - #[cfg(feature = "bls-signatures")] - threshold_public_key, - .. - } = value; - Self { - quorum_hash, - quorum_index, - core_height, - members: members - .into_iter() - .map(|(pro_tx_hash, validator)| (pro_tx_hash, validator.into())) - .collect(), - #[cfg(feature = "bls-signatures")] - threshold_public_key: PublicKey::try_from(threshold_public_key.to_bytes().as_slice()) - .expect("this should not be possible to error as the threshold_public_key was already verified on disk"), - #[cfg(not(feature = "bls-signatures"))] - threshold_public_key: Default::default(), - } - } -} - -/// A validator in the context of a quorum -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct ValidatorV0 { - /// The proTxHash - pub pro_tx_hash: ProTxHash, - /// The public key share of this validator for this quorum - #[cfg(feature = "bls-signatures")] - pub public_key: Option, - /// The node address - pub node_ip: String, - /// The node id - pub node_id: PubkeyHash, - /// Core port - pub core_port: u16, - /// Http port - pub platform_http_port: u16, - /// Tenderdash port - pub platform_p2p_port: u16, - /// Is the validator banned - pub is_banned: bool, -} - -impl From for dpp::core_types::validator::v0::ValidatorV0 { - fn from(value: ValidatorV0) -> Self { - let ValidatorV0 { - pro_tx_hash, - #[cfg(feature = "bls-signatures")] - public_key, - node_ip, - node_id, - core_port, - platform_http_port, - platform_p2p_port, - is_banned, - } = value; - Self { - pro_tx_hash, - #[cfg(feature = "bls-signatures")] - public_key: public_key.map(|pk| PublicKey::try_from(pk.to_bytes().as_slice()).expect("this should not be possible to error as the public_key was already verified on disk")), - #[cfg(not(feature = "bls-signatures"))] - public_key: None, - node_ip, - node_id, - core_port, - platform_http_port, - platform_p2p_port, - is_banned, - } - } -} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs index 1d4a9e71967..440aac01889 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs @@ -3,8 +3,6 @@ mod v0; use crate::config::QuorumLikeConfig; use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v0::SignatureVerificationQuorumSetForSavingV0; -use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v1::SignatureVerificationQuorumSetForSavingV1; use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v2::SignatureVerificationQuorumSetForSavingV2; pub use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::{ QuorumConfig, QuorumsWithConfig, SelectedQuorumSetIterator, SignatureVerificationQuorumSetV0, @@ -13,6 +11,7 @@ pub use crate::platform_types::signature_verification_quorum_set::v0::quorum_set pub use crate::platform_types::signature_verification_quorum_set::v0::quorums::{ Quorum, Quorums, SigningQuorum, ThresholdBlsPublicKey, VerificationQuorum, }; +use crate::platform_types::unsupported_legacy_bls_storage::UnsupportedLegacyBlsStorage; use bincode::{Decode, Encode}; use derive_more::From; use dpp::version::PlatformVersion; @@ -118,10 +117,10 @@ impl SignatureVerificationQuorumSetV0Methods for SignatureVerificationQuorumSet /// Core Quorum Set structure for saving to the database #[derive(Debug, Clone, Encode, Decode)] pub enum SignatureVerificationQuorumSetForSaving { - /// Version 0 of the signature verification quorums - V0(SignatureVerificationQuorumSetForSavingV0), - /// Version 1 of the signature verification quorums - V1(SignatureVerificationQuorumSetForSavingV1), + /// Unsupported legacy format; its tag remains reserved. + V0(UnsupportedLegacyBlsStorage), + /// Unsupported legacy format; its tag remains reserved. + V1(UnsupportedLegacyBlsStorage), /// Version 2 of the signature verification quorums V2(SignatureVerificationQuorumSetForSavingV2), } @@ -139,15 +138,39 @@ impl From for SignatureVerificationQuorumSetForS impl From for SignatureVerificationQuorumSet { fn from(value: SignatureVerificationQuorumSetForSaving) -> Self { match value { - SignatureVerificationQuorumSetForSaving::V0(v0) => { - SignatureVerificationQuorumSet::V0(v0.into()) - } - SignatureVerificationQuorumSetForSaving::V1(v1) => { - SignatureVerificationQuorumSet::V0(v1.into()) - } + SignatureVerificationQuorumSetForSaving::V0(unsupported) + | SignatureVerificationQuorumSetForSaving::V1(unsupported) => match unsupported {}, SignatureVerificationQuorumSetForSaving::V2(v2) => { SignatureVerificationQuorumSet::V0(v2.into()) } } } } + +#[cfg(test)] +mod legacy_storage_tests { + use super::SignatureVerificationQuorumSetForSaving; + use bincode::{config, error::DecodeError}; + + #[test] + fn should_reject_legacy_bls_quorum_formats_before_reading_their_payload() { + for version in [0u32, 1] { + let bytes = bincode::encode_to_vec(version, config::standard().with_big_endian()) + .expect("encode format tag"); + let error = bincode::decode_from_slice::( + &bytes, + config::standard().with_big_endian(), + ) + .expect_err("legacy quorum format must be rejected"); + let borrowed_error = bincode::borrow_decode_from_slice::< + SignatureVerificationQuorumSetForSaving, + _, + >(&bytes, config::standard().with_big_endian()) + .expect_err("borrowed decoding must reject legacy quorums too"); + assert_eq!(error.to_string(), borrowed_error.to_string()); + assert!(matches!(error, DecodeError::Other(_))); + assert!(error.to_string().contains("v4.0.0")); + assert!(error.to_string().contains("commit at least one block")); + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs deleted file mode 100644 index 41fa8f66eba..00000000000 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::platform_types::signature_verification_quorum_set::v0::quorum_config_for_saving_v0::QuorumConfigForSavingV0; -use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::PreviousPastQuorumsV0; -use crate::platform_types::signature_verification_quorum_set::{ - Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, - VerificationQuorum, -}; -use bincode::{Decode, Encode}; -use dpp::dashcore::hashes::Hash; -use dpp::dashcore::QuorumHash; -use dpp::platform_value::Bytes32; - -#[derive(Debug, Clone, Encode, Decode)] -pub struct SignatureVerificationQuorumSetForSavingV0 { - config: QuorumConfigForSavingV0, - current_quorums: Vec, - previous_quorums: Option, -} - -impl From for SignatureVerificationQuorumSetForSaving { - fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { - SignatureVerificationQuorumSetForSaving::V0(value) - } -} - -impl From for SignatureVerificationQuorumSetForSavingV0 { - fn from(value: SignatureVerificationQuorumSetV0) -> Self { - let SignatureVerificationQuorumSetV0 { - config, - current_quorums, - previous, - } = value; - - Self { - config: config.into(), - current_quorums: current_quorums.into(), - previous_quorums: previous.map(|previous| previous.into()), - } - } -} - -impl From for SignatureVerificationQuorumSetV0 { - fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { - let SignatureVerificationQuorumSetForSavingV0 { - config, - current_quorums, - previous_quorums, - } = value; - - Self { - config: config.into(), - current_quorums: current_quorums.into(), - previous: previous_quorums.map(|previous| previous.into()), - } - } -} - -#[derive(Debug, Clone, Encode, Decode)] -pub struct PreviousPastQuorumsForSavingV0 { - quorums: Vec, - last_active_core_height: u32, - updated_at_core_height: u32, - previous_change_height: Option, -} - -impl From for PreviousPastQuorumsForSavingV0 { - fn from(value: PreviousPastQuorumsV0) -> Self { - let PreviousPastQuorumsV0 { - quorums, - last_active_core_height, - updated_at_core_height, - previous_change_height, - } = value; - - Self { - quorums: quorums.into(), - last_active_core_height, - updated_at_core_height, - previous_change_height, - } - } -} - -impl From for PreviousPastQuorumsV0 { - fn from(value: PreviousPastQuorumsForSavingV0) -> Self { - let PreviousPastQuorumsForSavingV0 { - quorums, - last_active_core_height: active_core_height, - updated_at_core_height, - previous_change_height, - } = value; - - Self { - quorums: quorums.into(), - last_active_core_height: active_core_height, - updated_at_core_height, - previous_change_height, - } - } -} - -#[derive(Debug, Clone, Encode, Decode)] -pub struct QuorumForSavingV0 { - hash: Bytes32, - #[cfg(feature = "bls-signatures")] - #[bincode(with_serde)] - public_key: bls_signatures::PublicKey, - index: Option, -} - -impl From> for Quorums { - fn from(value: Vec) -> Self { - Quorums::from_iter(value.into_iter().map(|quorum| { - ( - QuorumHash::from_byte_array(quorum.hash.to_buffer()), - VerificationQuorum { - #[cfg(feature = "bls-signatures")] - public_key: dpp::bls_signatures::PublicKey::try_from( - quorum.public_key.to_bytes().as_slice(), - ) - .expect("expected to convert between BLS key libraries (from chia)"), - #[cfg(not(feature = "bls-signatures"))] - public_key: Default::default(), - index: quorum.index, - }, - ) - })) - } -} - -impl From> for Vec { - fn from(quorums: Quorums) -> Self { - quorums - .into_iter() - .map(|(hash, quorum)| QuorumForSavingV0 { - hash: Bytes32::from(hash.as_byte_array()), - #[cfg(feature = "bls-signatures")] - public_key: bls_signatures::PublicKey::from_bytes(&quorum.public_key.to_bytes()) - .expect("expected to convert between BLS key libraries (to chia)"), - index: quorum.index, - }) - .collect() - } -} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs index 1d903b160a1..01162ccf4cd 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs @@ -1,10 +1,6 @@ -#[cfg(feature = "bls-signatures")] -use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v0::PreviousPastQuorumsForSavingV0; -use crate::platform_types::signature_verification_quorum_set::v0::quorum_config_for_saving_v0::QuorumConfigForSavingV0; use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::PreviousPastQuorumsV0; use crate::platform_types::signature_verification_quorum_set::{ - Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, - ThresholdBlsPublicKey, VerificationQuorum, + Quorums, ThresholdBlsPublicKey, VerificationQuorum, }; use bincode::{Decode, Encode}; @@ -12,58 +8,6 @@ use dpp::dashcore::hashes::Hash; use dpp::dashcore::QuorumHash; use dpp::platform_value::Bytes32; -#[derive(Debug, Clone, Encode, Decode)] -pub struct SignatureVerificationQuorumSetForSavingV1 { - config: QuorumConfigForSavingV0, - current_quorums: Vec, - #[cfg(feature = "bls-signatures")] - previous_quorums: Option, -} - -impl From for SignatureVerificationQuorumSetForSaving { - fn from(value: SignatureVerificationQuorumSetForSavingV1) -> Self { - SignatureVerificationQuorumSetForSaving::V1(value) - } -} - -impl From for SignatureVerificationQuorumSetForSavingV1 { - fn from(value: SignatureVerificationQuorumSetV0) -> Self { - #[allow(unused_variables)] - let SignatureVerificationQuorumSetV0 { - config, - current_quorums, - previous, - } = value; - - Self { - config: config.into(), - current_quorums: current_quorums.into(), - #[cfg(feature = "bls-signatures")] - previous_quorums: previous.map(|previous| previous.into()), - } - } -} - -impl From for SignatureVerificationQuorumSetV0 { - fn from(value: SignatureVerificationQuorumSetForSavingV1) -> Self { - let SignatureVerificationQuorumSetForSavingV1 { - config, - current_quorums, - #[cfg(feature = "bls-signatures")] - previous_quorums, - } = value; - - Self { - config: config.into(), - current_quorums: current_quorums.into(), - #[cfg(feature = "bls-signatures")] - previous: previous_quorums.map(|previous| previous.into()), - #[cfg(not(feature = "bls-signatures"))] - previous: None, - } - } -} - #[derive(Debug, Clone, Encode, Decode)] pub struct QuorumForSavingV1 { hash: Bytes32, diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs index 60f0b4d7b9a..27cc8c656ef 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs @@ -7,10 +7,6 @@ use crate::platform_types::signature_verification_quorum_set::{ }; use bincode::{Decode, Encode}; -// We needed to introduce this V2 because the PreviousPastQuorumsForSavingV1 were using a QuorumForSavingV0 -// This was an oversight in SignatureVerificationQuorumSetForSavingV1. -// This would cause the previous quorums to still use the old BLS sigs library for serialization/deserialization. - #[derive(Debug, Clone, Encode, Decode)] pub struct SignatureVerificationQuorumSetForSavingV2 { config: QuorumConfigForSavingV0, diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs index bc4511bd4cf..52748e5f21d 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs @@ -1,4 +1,3 @@ -pub mod for_saving_v0; pub mod for_saving_v1; pub mod for_saving_v2; pub mod quorum_config_for_saving_v0; diff --git a/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs b/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs new file mode 100644 index 00000000000..b5441903cb1 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs @@ -0,0 +1,28 @@ +//! Rejection of database formats that require an intermediate Platform upgrade. + +use bincode::de::Decoder; +use bincode::enc::Encoder; +use bincode::error::{DecodeError, EncodeError}; +use bincode::{Decode, Encode}; + +/// Uninhabited payload reserving a legacy enum tag without accepting its data. +/// +/// Keeping the variant slot preserves the tags of supported storage formats. +#[derive(Clone, Debug)] +pub enum UnsupportedLegacyBlsStorage {} + +impl Encode for UnsupportedLegacyBlsStorage { + fn encode(&self, _encoder: &mut E) -> Result<(), EncodeError> { + match *self {} + } +} + +impl Decode for UnsupportedLegacyBlsStorage { + fn decode>(_decoder: &mut D) -> Result { + Err(DecodeError::Other( + "Unsupported legacy BLS state format. Run Platform v4.0.0 on this database and let it successfully commit at least one block before upgrading.", + )) + } +} + +bincode::impl_borrow_decode!(UnsupportedLegacyBlsStorage); diff --git a/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex b/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex new file mode 100644 index 00000000000..194d7ad1c7a --- /dev/null +++ b/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex @@ -0,0 +1 @@ +01000100fd00000196679379cde0fb4cf8335c28e2d5b81fe8563beff647c4a74bac7165d84276eb62dc46fd2cc6bfe53f6b00000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8741533fd4861a2205ac950c9f39bfcb92d75c30010cc6e83d23eee89792132cf78ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e51104418388bcb4a1798aebc9b25e3d444ff15e4b272c4ee5dbf51309147db28421f49a736a6fb0260ea8b075f8309331caed3f99b193410cee745b02ad9b93d16c22cc7bfac642917c93c288e2a1977f325fb0b76cc6c22447d363c43a20bb89c89d3253300080800000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8740004000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d900000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d900fb4ce00a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601b7536c30ebb2297379cce4e832c5c88828dba988b1b339ba403621a67cc26325baf14d809cbd4b30ef07c783a45749130d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001b6aa2516aa6e47c9824efc13422cccc45a73fbe0bab83334fc31122f99c2e6fc37f667928c20176702284a4211393f4e0d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1601a1f07095b3171384f7d7cd23d766cb5ef32cf1bc3808eb5dd6cbc4c910ee0e51d11f47f2673db173c166749f5c61f4790d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5101846f0ab803a4569eae1a616443456bf498f0493b9d32c919a59d6bb722bcd2200077e9439d9fb621d9f966bef1009bde0d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301b117767d537e5c34c7c459a76b97af529a1255e0bf2c61ea96316c347f2c13abf6755e52ae2e8ae41a41414617ed6afd0c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801abac813a50f33c5e2c53284e880a47b831c3683a63686991146f473ec129e324a80492f1bde63986f0564304e5bd36b30d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01ab9ecac6c4edbb91ec9b91347b3f0cdd9872c8278432f3f7550d3812f5b82afe7e1701984edd53b0b84f59fe56ebd66a0d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945018be3cda106e64ec22ab90dff0b9aebf399f64925ec460896683df9ebfe77a767315ceeb51a395fac87a3cecfd0d9f2580e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb01a342022a1ff0f2e8a9b42f0d031d3704fa89a6dc85e8bf31e88266f4dbcbc2d1f9255913b5dd51d7f96fc25b04af53100b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a01a612b7515f24806d24b34176383f3d73ac673eae61142860c2ceed761f8f1435d988f64a33d0fb9a529e870c68dd50990d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f3000ae243894aa11a2c9f1bb0464499864376b85c773c8ff5a7f5d57bfee2977459db996ce325d9bc4996582baa0f96b59b60000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce00fb4cc80a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab506018ebacd1b1061d80715fe840a199b6635830ad7abc379e1af869998c1b91257b4819935f1796d1c6bc86c79f263a64c430d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001ab5a092f14f019e1ae79ec037ebe88d3501139a82736521b2aabca4f078f934bbf9d136383c2386ce5739f6f9a5f9d490d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b16018aaabc36b1e2f42664abec989208b9821650b704323cb8d66be00095954a1d20194ef23c33c839e760f03f0ac0bcca350d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5101aa6bf2536b37af83b6e88a50b35216aebcf2e433758d419e150e00d19caf6ca6fcffa234d49c86a2905e400f41d5a3a50d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301aadc92e09655108cc8736b055e5abf288e060b06de527a4f6fc5b65516037e555ca0b9944c65ea678dc59348d6e138e70c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801b919077a4108af14570de90782408632b048b528df100076077598a8555758d656cae0fd3ec132b1fd113e18d3b623d50d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01a7553852f9a1692b7696cb063e49e173ca655b80e1fa95d8e03926dabb0a16f1ca4e7d7f32666e838d53d228e80bf5390d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945018babe479bf760cd34be2b57e088e9756d3eac5e92f5e978b5abdf3e8a4d3ea5f4bb93e3c5e6227d1c9174fd7e38ad5140e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb01b7be15daa0d2513874b47d5d4283563969a933bb473e21222c63271dfae2ddd560df3806172b9b897926b214542b73a40b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a0193d0baee082057cc2e7a17bf6cad8d3df0e4fc5438de2027ea77bb20a7910862ecc145b4631bcd58e39fd62a19e2ea150d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f30008028075a0cca9efbc93a7c50b3c670ed90c129b64705f1c3c2ccedc811ff5844ed6f1e34601a13a2b59bc94329b74606000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796800000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796800fb4cb00a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601aaac3862eed7b02ba53f7a019047849d5b492ec41c8f5541e4b81811ae989d703c200ca058226e9e78f081e07f0742b20d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001b57396d68a27a823604af7404e7fa28e9d0a559b42e94464eee8ee322a0f5b017d50827c0a460adb57d98555ac5d31ac0d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1601b45e2079572eea6d7890f5199ceef69fc7e71a353fa919a8a58a44b3aab65926b60fc10cfcb62b85b4f422f49d3e92e90d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc51018a47a2fe45a808aea52b26adfe15d75fa422762d9a8615bc8cdd9987c68e2b84bc06bbff4378f639f3aa57133a1aa81a0d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301aadf1764b8f7f60788cc90d95f0403b249acce9ee6e4bb31c90061d9dd5cfe32812b64249ec0b017bcf67f30e44c3bc50c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e51104418380185b29d05607cf79e2dbeff52d40751a30a2f1bd8fd63508b2c45ff75577f6f3f3c92951069690a8b4976ece9fedc966b0d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01a8e81b88af2eefb6ab3b39652a651a4ea57e0c82eedb90908769716ecd9928fe825fdd142c4938e7049dc31c43bda2e70d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194501ab750eb8ce4e3cb196dac1890bae03e6a1cdf9bf0b70a63ea6ca64f7ee1946b8fe02b8362290765cb9ffeda0e5088a0b0e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb019031840125574c094554c02649a65b9dec67285d6e0f89ebbae56b55eedd5393757bb81a4fec886422d8e3ac485dc2740b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a018f922fdc28078e252b6e221b3ccaa6f3451885b4413e7a21b4a7850eb924122cbed5fb366af8485bd1d8d67f185232d60d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f3000b887b3dbc961b87e02fd7e16929fe771133d6c76fa1faebb35c2b1da15d32292a314b477f60f4c6d02b46110c0ef6eec00000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8740000000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f87400fb4c980a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601a4037c6dc40a494e120de11721a221e876b75fd099c852bb1b44a2ba882bc4c25a0998d60e56ca29983abe918f15a2ad0d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001a12ace1e26c8ce82f2e736b26653f64a477ec58de0f964b8e79b67aea72b70c4c46d0e8c48a77b83fbde7d4e5b6b00910d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160181d6653d0930d0c17ae170c3a492abaed7790a43b064258684e520e47e8627c0e7f331fdb14cf8a303c6f472d8240c3b0d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc51019209cfef89be975385818843303544dbbdbe5e71fb035de048aa870972d83b0a2822ef1dc28f02f1e1d94e9e50a091790d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301b64f956fed0ea351b56e6271d9da59e5b053cc5b707ef057fc165ad23176e6bf5160bab2d8f5ad1abd45ac508856b8d40c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801a98cd5f09273c6a038b6a29af2eaff1570e62e03b25bbb6ba21354a01b96cfca07dca4ae4b3ae5496a4d62d63c1ec7cc0d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01acd8ed44c9de6126a9b683b915c85ec85ee67983603bba65f5427fbcf62d5460a89a91d03dbabb4b041d0585fa8a99200d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194501aab6f5e05fb6544513c6af9624c6d18b8dcca7eee3356d61631d718931630075811af66ed540b43baeab4b3a8339becc0e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb0185187e5ec226e3aa03eb2f6e157f042ef8e0aa444c80f018664956c895e45a894dcea801ed3f3acafe78be22051801600b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a018d0b0344f40beddbd946ae247a5617e3329894d88e84f94a56990a2af72d3ff67d05b86f8ec6145ff65578aae1d9a1730d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f30008cf580fb386270abfc216e3beb47d028c5c49dac56d706b2797ee9fb65322a680bb632a2a81191dfdea453569adf049e02070400180400000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8748c786a8a62110a49cf5032723429517beff088867f048c5ff795d394322aa5ae0d51f87fad5f5a3e7864aee139aef68a000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce84b18ace26a0084f94122e5b88c24a16d678efdb36ecec9088c81dc572ced080a8ebc5c2e35f80b48ffe5efab68890b600000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d98b5be5697a66e7fc3b1e0fb0e247f2be6f68096888b578ca1c35761a057e2ff9fc308d692c115f3cf252cea1423f2d1e00000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796893fba22ce69238d34733636602fc26e1b841da63dd37cc0af69efb1ba815cfcb3a7a5be870db4d2f1a940dc3ad407f7a00010400000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8748c786a8a62110a49cf5032723429517beff088867f048c5ff795d394322aa5ae0d51f87fad5f5a3e7864aee139aef68a00000003e208609aa86a58da32e5465fa6ae8ee72d2e2b3936f2d8cfafd52f058193c47178fa64592f11a32f7718bd518d90b3c847c7b8fa4bca6addaece93581dab9a3429ec2c7c7347ce920e88979e56000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce84b18ace26a0084f94122e5b88c24a16d678efdb36ecec9088c81dc572ced080a8ebc5c2e35f80b48ffe5efab68890b600000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796893fba22ce69238d34733636602fc26e1b841da63dd37cc0af69efb1ba815cfcb3a7a5be870db4d2f1a940dc3ad407f7a00fb4ceafb4ceb01fb4cd4020b020130020000057d6aec5a186ff690e13b41e10c938d06c9ba25046836c740549b0e3969b8faca3e409109d3549187247ab50bfe5843545c3064ef953653f52f5a0ddefb4b91325812def3cc26808067624327890101000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d9aac58025b9e50077a3edfe1aaab170fcdb6b15b3a500212460265cb756ea33cba57ca432916bca4c4ef72b1b172600c20100010200000074d7b31cf77817c30df933d80fa6e354b6582c29ef416799a508631039a8dc97e32336fe44d357d4936d196f08731328f15758cd7760fe584862869944556826905742737e3da542d782e57acb0101000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad67968b7f439f6c82070bd8a73313e98d228b9f11b1c0232a1b9733580155bfbd27a3c399ecc5babdd4a6cf2908a836ccba2720100fb4cebfb4cec01fb4cbe0a01e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50600012001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790356e79d2b2b0ac0761f6a4526b7d047d74e28f546000000000036cae714fb4e21fb101900000058127be0d801051a163bf0353cc5bb9defd2f57358127be0d801051a163bf0353cc5bb9defd2f573a986f69f8d9d9a073287487365e0c31a1a6ec33d30b104db07b513ef45b0da4c1379599b7c5981860fa588d7968cbc0408a1cc729fcb64b2c7586c9719caa7d33ddaccf42900019eb3c89309106d441cc1749640ab5613046f6ad001fb8f3001fb05a3122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080000120122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08020a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107906903790983928ee282b9644cbf9c8e6cee72efe90000000000012f6e315fb4e21fb10190000009b482e4b8f5da7583a15fc887928e6c404e17f9b9b482e4b8f5da7583a15fc887928e6c404e17f9ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b5c57edb1258f5c1cfdb21b6680de011ddeea93e797e5f597dedd0abb85eea27bf862ff95528ed80c9cb0bae3a2715fa0001a7822db397ca4e35b81d016ce52bdbaae74880ab01fb8f3001fb05a34838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160001204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079079150fb7c07cdbac70f458cd23487e212760de68500000000002cf7a034fb4e21fb1019000000579ecdebf8c2a3f347c301cd56f8d25a60821ebd579ecdebf8c2a3f347c301cd56f8d25a60821ebda986f69f8d9d9a073287487365e0c31a1a6ec33d30b455073ebdd660759753d3158e0af7038620bc484d5b206cc76cd517ccd4aaedff0a967d3a2245ca12dd39eaec565dc10001c6e2f8c23c3b847ae4b8f0c452408f843fe3afa601fb8f3001fb05a34c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc510001204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5120a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790ad2e5173d4d1f2ddab7848de87288ef7fea4a5bc2000000000036d64d6cfb4e21fb101900000032d019c0a0521635e2c50baa0639afde38128ca032d019c0a0521635e2c50baa0639afde38128ca0a986f69f8d9d9a073287487365e0c31a1a6ec33d3085918a1ce01bed79b0f2f73b4b9cf3d3beb0d79508801139611d488cd5ecd7184f72c5489eb78330d5f43caebc9a0a110001cca358aba0b27446e73f6cbc372d549de4039d4301fb8f3001fb05a3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3000120aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc320a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079089a27487a58654bceeacfd3fb1a2cda28642ddb2700000000002359f656fb4e21fb1019000000a4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b343c9b538cc9694dbb8cf3ecc288875ec6e53175c72d557c2ac5fad08659084a83a9aeb670d6aa484f293de2d85af33000120499e02a93241d54692c96b4ef147e46b12327501fb8f3001fb05a3ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838000120ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183820a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079057ba786e269da8db182526a7dd051b5b5dc231fb500000000002cf560a4fb4e21fb101900000081b0121840d749be5f287a4117515f4d8f3fd65f81b0121840d749be5f287a4117515f4d8f3fd65fa986f69f8d9d9a073287487365e0c31a1a6ec33d30b03a8cb594e95d4d3e9d993e5a2df17ef5161fcf67560bd91fff3bbd5d4a4fe26082c6c37fac5a73491dc93e1900b4950001acc20a8324d0b1f914a4ffe605d488f21a026cd601fb8f3001fb05a3c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb000120c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107902493372ccd17dea09c98b8c35077387b21f8ad28d000000000036cb745bfb4e21fb1019000000fcd87a7892e645ebba5647bd9eebc25b34ddde70fcd87a7892e645ebba5647bd9eebc25b34ddde70a986f69f8d9d9a073287487365e0c31a1a6ec33d30a2cff2a27595a6bc79ce79c4f360713a35e20350ec106f20d01a90d1374ac0c5ef709ce968bcc0a7888340f5871805040001f77c894ac83526befcc07157a82e52cc2b1697f101fb8f3001fb05a3d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945000120d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194520a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107904645e20b1c5090f6f05b601eec64d6c17cd88094a000000000022ded6aafb4e21fb1019000000d6cdf6df678342ca7e9d906e354dd9355445cb80d6cdf6df678342ca7e9d906e354dd9355445cb80a986f69f8d9d9a073287487365e0c31a1a6ec33d308c89302e7919585c6c9870d5ec60e89abe15bdc62e8043a7db8d47ecb15535711b290547a2a314cf6f1d931c62a8214300011e8d732727fff4006299e0b23d5d724fb0e688b301fb8f3001fb05a3ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb000120ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107909a18bfec024e4f56a56e3efee94d5b541a627b31c00000000003458102efb4e21fb10190000002cef49cf84da8e7fae2059188b7c4f3df078f4e22cef49cf84da8e7fae2059188b7c4f3df078f4e2a986f69f8d9d9a073287487365e0c31a1a6ec33d308144775a433e210fd111aa673239c996226c99555bb9aa4f96741ec57b78db0aaa69100f9f3fdfa9e90bcd0d3b25f59d0001da8a388088177826d85d98d2518a7a42bf04663f01fb8f3001fb05a3f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a000120f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079011fc39eaccf31144a236ca22c780d64a3b317b77d00000000003428baeafb4e21fb10190000000381536671c212e9666e5fb5d4a29fe0948773900381536671c212e9666e5fb5d4a29fe094877390a986f69f8d9d9a073287487365e0c31a1a6ec33d30b0ea9db0fa7191c90fbc55dcd984630f9a2892d3250add2ab807132845122644ad888ad2276d59600efdfaf2f4fbf9000001a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b401fb8f3001fb05a30a01e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50600012001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790356e79d2b2b0ac0761f6a4526b7d047d74e28f546000000000036cae714fb4e21fb101900000058127be0d801051a163bf0353cc5bb9defd2f57358127be0d801051a163bf0353cc5bb9defd2f573a986f69f8d9d9a073287487365e0c31a1a6ec33d30b104db07b513ef45b0da4c1379599b7c5981860fa588d7968cbc0408a1cc729fcb64b2c7586c9719caa7d33ddaccf42900019eb3c89309106d441cc1749640ab5613046f6ad001fb8f3001fb05a3122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080000120122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08020a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107906903790983928ee282b9644cbf9c8e6cee72efe90000000000012f6e315fb4e21fb10190000009b482e4b8f5da7583a15fc887928e6c404e17f9b9b482e4b8f5da7583a15fc887928e6c404e17f9ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b5c57edb1258f5c1cfdb21b6680de011ddeea93e797e5f597dedd0abb85eea27bf862ff95528ed80c9cb0bae3a2715fa0001a7822db397ca4e35b81d016ce52bdbaae74880ab01fb8f3001fb05a34838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160001204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079079150fb7c07cdbac70f458cd23487e212760de68500000000002cf7a034fb4e21fb1019000000579ecdebf8c2a3f347c301cd56f8d25a60821ebd579ecdebf8c2a3f347c301cd56f8d25a60821ebda986f69f8d9d9a073287487365e0c31a1a6ec33d30b455073ebdd660759753d3158e0af7038620bc484d5b206cc76cd517ccd4aaedff0a967d3a2245ca12dd39eaec565dc10001c6e2f8c23c3b847ae4b8f0c452408f843fe3afa601fb8f3001fb05a34c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc510001204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5120a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790ad2e5173d4d1f2ddab7848de87288ef7fea4a5bc2000000000036d64d6cfb4e21fb101900000032d019c0a0521635e2c50baa0639afde38128ca032d019c0a0521635e2c50baa0639afde38128ca0a986f69f8d9d9a073287487365e0c31a1a6ec33d3085918a1ce01bed79b0f2f73b4b9cf3d3beb0d79508801139611d488cd5ecd7184f72c5489eb78330d5f43caebc9a0a110001cca358aba0b27446e73f6cbc372d549de4039d4301fb8f3001fb05a3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3000120aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc320a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079089a27487a58654bceeacfd3fb1a2cda28642ddb2700000000002359f656fb4e21fb1019000000a4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b343c9b538cc9694dbb8cf3ecc288875ec6e53175c72d557c2ac5fad08659084a83a9aeb670d6aa484f293de2d85af33000120499e02a93241d54692c96b4ef147e46b12327501fb8f3001fb05a3ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838000120ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183820a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079057ba786e269da8db182526a7dd051b5b5dc231fb500000000002cf560a4fb4e21fb101900000081b0121840d749be5f287a4117515f4d8f3fd65f81b0121840d749be5f287a4117515f4d8f3fd65fa986f69f8d9d9a073287487365e0c31a1a6ec33d30b03a8cb594e95d4d3e9d993e5a2df17ef5161fcf67560bd91fff3bbd5d4a4fe26082c6c37fac5a73491dc93e1900b4950001acc20a8324d0b1f914a4ffe605d488f21a026cd601fb8f3001fb05a3c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb000120c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107902493372ccd17dea09c98b8c35077387b21f8ad28d000000000036cb745bfb4e21fb1019000000fcd87a7892e645ebba5647bd9eebc25b34ddde70fcd87a7892e645ebba5647bd9eebc25b34ddde70a986f69f8d9d9a073287487365e0c31a1a6ec33d30a2cff2a27595a6bc79ce79c4f360713a35e20350ec106f20d01a90d1374ac0c5ef709ce968bcc0a7888340f5871805040001f77c894ac83526befcc07157a82e52cc2b1697f101fb8f3001fb05a3d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945000120d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194520a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107904645e20b1c5090f6f05b601eec64d6c17cd88094a000000000022ded6aafb4e21fb1019000000d6cdf6df678342ca7e9d906e354dd9355445cb80d6cdf6df678342ca7e9d906e354dd9355445cb80a986f69f8d9d9a073287487365e0c31a1a6ec33d308c89302e7919585c6c9870d5ec60e89abe15bdc62e8043a7db8d47ecb15535711b290547a2a314cf6f1d931c62a8214300011e8d732727fff4006299e0b23d5d724fb0e688b301fb8f3001fb05a3ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb000120ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107909a18bfec024e4f56a56e3efee94d5b541a627b31c00000000003458102efb4e21fb10190000002cef49cf84da8e7fae2059188b7c4f3df078f4e22cef49cf84da8e7fae2059188b7c4f3df078f4e2a986f69f8d9d9a073287487365e0c31a1a6ec33d308144775a433e210fd111aa673239c996226c99555bb9aa4f96741ec57b78db0aaa69100f9f3fdfa9e90bcd0d3b25f59d0001da8a388088177826d85d98d2518a7a42bf04663f01fb8f3001fb05a3f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a000120f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079011fc39eaccf31144a236ca22c780d64a3b317b77d00000000003428baeafb4e21fb10190000000381536671c212e9666e5fb5d4a29fe0948773900381536671c212e9666e5fb5d4a29fe094877390a986f69f8d9d9a073287487365e0c31a1a6ec33d30b0ea9db0fa7191c90fbc55dcd984630f9a2892d3250add2ab807132845122644ad888ad2276d59600efdfaf2f4fbf9000001a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b401fb8f3001fb05a3013201 From f34d1c8495eb2577a076f92bac093d3ebde6aec0 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 09:58:05 +0000 Subject: [PATCH 06/11] refactor(dpp): expose BLS types through the bls module Move the signature implementation under bls and export PublicKey, SecretKey, Signature and BlsError from dpp::bls. Update all repository consumers and remove the former dpp::bls_signatures path. Co-Authored-By: Codex --- .../generate_bls_compatibility_vectors.rs | 2 +- packages/rs-dpp/src/{ => bls}/bls_signatures.rs | 0 packages/rs-dpp/src/bls/mod.rs | 4 ++++ packages/rs-dpp/src/bls/native_bls.rs | 2 +- packages/rs-dpp/src/core_types/validator/mod.rs | 2 +- .../rs-dpp/src/core_types/validator/v0/mod.rs | 4 ++-- .../rs-dpp/src/core_types/validator_set/mod.rs | 4 ++-- .../src/core_types/validator_set/v0/mod.rs | 4 ++-- packages/rs-dpp/src/errors/protocol_error.rs | 2 +- .../identity/identity_public_key/key_type.rs | 10 +++++----- .../identity_public_key/v0/methods/mod.rs | 16 ++++++++-------- packages/rs-dpp/src/lib.rs | 8 ++++---- .../src/serialization/dashcore/bls_pubkey.rs | 2 +- packages/rs-dpp/src/signing.rs | 4 ++-- packages/rs-dpp/tests/bls_compatibility.rs | 2 +- packages/rs-drive-abci/src/abci/error.rs | 2 +- packages/rs-drive-abci/src/error/execution.rs | 2 +- packages/rs-drive-abci/src/error/mod.rs | 2 +- .../block_end/validator_set_update/mod.rs | 2 +- .../update_operator_identity/v0/mod.rs | 2 +- .../update_masternode_list/mod.rs | 2 +- .../update_state_masternode_list/v1/mod.rs | 2 +- .../update_quorum_info/v0/mod.rs | 2 +- .../core_chain_lock/choose_quorum/mod.rs | 2 +- .../core_chain_lock/choose_quorum/v0/mod.rs | 4 ++-- .../verify_chain_lock_locally/v0/mod.rs | 12 +++++------- .../verify_recent_signature_locally/v0/mod.rs | 2 +- .../storage/store_platform_state/v1/mod.rs | 2 +- packages/rs-drive-abci/src/mimic/test_quorum.rs | 4 +--- .../src/platform_types/commit/mod.rs | 4 ++-- .../src/platform_types/commit/v0/mod.rs | 8 ++++---- .../v0/quorum_set.rs | 4 ++-- .../v0/quorums.rs | 10 +++++----- .../src/platform_types/validator/v0/mod.rs | 2 +- .../src/platform_types/validator_set/v0/mod.rs | 4 ++-- .../src/query/document_query/v1/tests.rs | 6 +++--- .../tests/strategy_tests/execution.rs | 2 +- .../rs-drive-abci/tests/strategy_tests/main.rs | 2 +- .../tests/strategy_tests/masternodes.rs | 2 +- .../rs-drive-abci/tests/strategy_tests/query.rs | 4 ++-- .../rs-drive-proof-verifier/src/unproved.rs | 4 ++-- packages/rs-drive-proof-verifier/src/verify.rs | 17 ++++++++--------- .../src/masternode/locator.rs | 2 +- .../src/masternode/update_service.rs | 4 ++-- packages/simple-signer/src/signer.rs | 5 +++-- 45 files changed, 94 insertions(+), 94 deletions(-) rename packages/rs-dpp/src/{ => bls}/bls_signatures.rs (100%) diff --git a/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs index 47e8b217ea4..f137030b63a 100644 --- a/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs +++ b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs @@ -1,7 +1,7 @@ //! Emit deterministic compatibility fixtures from DPP's current BLS backend. //! Run with `cargo run -p dpp --example generate_bls_compatibility_vectors`. -use dpp::bls_signatures::{PublicKey, SecretKey, Signature}; +use dpp::bls::{PublicKey, SecretKey, Signature}; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::{hashes::Hash, ProTxHash, PubkeyHash, QuorumHash}; diff --git a/packages/rs-dpp/src/bls_signatures.rs b/packages/rs-dpp/src/bls/bls_signatures.rs similarity index 100% rename from packages/rs-dpp/src/bls_signatures.rs rename to packages/rs-dpp/src/bls/bls_signatures.rs diff --git a/packages/rs-dpp/src/bls/mod.rs b/packages/rs-dpp/src/bls/mod.rs index a5501f4634d..3de89a047c0 100644 --- a/packages/rs-dpp/src/bls/mod.rs +++ b/packages/rs-dpp/src/bls/mod.rs @@ -1,4 +1,8 @@ #[cfg(feature = "bls-signatures")] +mod bls_signatures; +#[cfg(feature = "bls-signatures")] +pub use bls_signatures::{BlsError, PublicKey, SecretKey, Signature}; +#[cfg(feature = "bls-signatures")] pub mod native_bls; use crate::{ProtocolError, PublicKeyValidationError}; diff --git a/packages/rs-dpp/src/bls/native_bls.rs b/packages/rs-dpp/src/bls/native_bls.rs index a9d67ce0658..2bcd1dd4273 100644 --- a/packages/rs-dpp/src/bls/native_bls.rs +++ b/packages/rs-dpp/src/bls/native_bls.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::{PublicKey, SecretKey, Signature}; +use crate::bls::{PublicKey, SecretKey, Signature}; use crate::{BlsModule, ProtocolError, PublicKeyValidationError}; #[derive(Default)] diff --git a/packages/rs-dpp/src/core_types/validator/mod.rs b/packages/rs-dpp/src/core_types/validator/mod.rs index 4d9c687b582..7215cddba58 100644 --- a/packages/rs-dpp/src/core_types/validator/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/mod.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::PublicKey as BlsPublicKey; +use crate::bls::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::{ValidatorV0, ValidatorV0Getters, ValidatorV0Setters}; #[cfg(all(feature = "json-conversion", feature = "serde-conversion"))] use crate::serialization::JsonConvertible; diff --git a/packages/rs-dpp/src/core_types/validator/v0/mod.rs b/packages/rs-dpp/src/core_types/validator/v0/mod.rs index e98278c7054..02de617a2c4 100644 --- a/packages/rs-dpp/src/core_types/validator/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/v0/mod.rs @@ -1,7 +1,7 @@ use dashcore::{ProTxHash, PubkeyHash}; use std::fmt::{Debug, Formatter}; -use crate::bls_signatures::PublicKey as BlsPublicKey; +use crate::bls::PublicKey as BlsPublicKey; #[cfg(feature = "serde-conversion")] use serde::{Deserialize, Serialize}; @@ -272,7 +272,7 @@ impl ValidatorV0Setters for ValidatorV0 { #[cfg(test)] mod tests { use super::*; - use crate::bls_signatures::SecretKey; + use crate::bls::SecretKey; use bincode::config; use rand::prelude::StdRng; use rand::SeedableRng; diff --git a/packages/rs-dpp/src/core_types/validator_set/mod.rs b/packages/rs-dpp/src/core_types/validator_set/mod.rs index 666cb84b037..ece8d5cf608 100644 --- a/packages/rs-dpp/src/core_types/validator_set/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/mod.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::PublicKey as BlsPublicKey; +use crate::bls::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::ValidatorV0; use crate::core_types::validator_set::v0::{ ValidatorSetV0, ValidatorSetV0Getters, ValidatorSetV0Setters, @@ -148,7 +148,7 @@ impl ValidatorSetV0Setters for ValidatorSet { ))] mod json_convertible_tests { use super::*; - use crate::bls_signatures::SecretKey; + use crate::bls::SecretKey; use crate::core_types::validator::v0::ValidatorV0; use crate::core_types::validator_set::v0::ValidatorSetV0; use dashcore::hashes::Hash; diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index 3a736ac4cb6..58591815ac7 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -1,4 +1,4 @@ -use crate::bls_signatures::PublicKey as BlsPublicKey; +use crate::bls::PublicKey as BlsPublicKey; use crate::core_types::validator::v0::ValidatorV0; #[cfg(feature = "core-types-serialization")] use bincode::de::BorrowDecoder; @@ -306,7 +306,7 @@ impl ValidatorSetV0Setters for ValidatorSetV0 { #[cfg(test)] mod tests { use super::*; - use crate::bls_signatures::SecretKey; + use crate::bls::SecretKey; use bincode::config; use dashcore::PubkeyHash; use rand::rngs::StdRng; diff --git a/packages/rs-dpp/src/errors/protocol_error.rs b/packages/rs-dpp/src/errors/protocol_error.rs index 790b4ff887d..1cc5106db22 100644 --- a/packages/rs-dpp/src/errors/protocol_error.rs +++ b/packages/rs-dpp/src/errors/protocol_error.rs @@ -290,7 +290,7 @@ pub enum ProtocolError { /// BLS signature error #[cfg(feature = "bls-signatures")] #[error(transparent)] - BlsError(#[from] crate::bls_signatures::BlsError), + BlsError(#[from] crate::bls::BlsError), #[error("Private key wrong size: expected 32, got {got}")] PrivateKeySizeError { got: u32 }, diff --git a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs index 33e98f830ba..260fc6b3a9d 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use lazy_static::lazy_static; #[cfg(feature = "bls-signatures")] -use crate::bls_signatures::{self as bls_signatures, BlsError}; +use crate::bls::{self, BlsError}; use crate::fee::Credits; use crate::version::PlatformVersion; use crate::ProtocolError; @@ -168,7 +168,7 @@ impl KeyType { private_key.public_key().to_bytes() } KeyType::BLS12_381 => { - let private_key = bls_signatures::SecretKey::random(rng); + let private_key = bls::SecretKey::random(rng); private_key.public_key().to_bytes().to_vec() } KeyType::ECDSA_HASH160 | KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => { @@ -217,8 +217,8 @@ impl KeyType { KeyType::BLS12_381 => { #[cfg(feature = "bls-signatures")] { - let private_key: Option = - bls_signatures::SecretKey::from_be_bytes(private_key_bytes); + let private_key: Option = + bls::SecretKey::from_be_bytes(private_key_bytes); if private_key.is_none() { return Err(ProtocolError::BlsError(BlsError::DeserializationError( "private key bytes not a valid secret key".to_string(), @@ -274,7 +274,7 @@ impl KeyType { ) } KeyType::BLS12_381 => { - let private_key = crate::bls_signatures::SecretKey::random(rng); + let private_key = crate::bls::SecretKey::random(rng); let public_key_bytes = private_key.public_key().to_bytes().to_vec(); (public_key_bytes, private_key.to_be_bytes()) } diff --git a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs index 255e01cd2a2..2f7034433b9 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs @@ -1,5 +1,5 @@ #[cfg(feature = "bls-signatures")] -use crate::bls_signatures; +use crate::bls; #[cfg(feature = "ed25519-dalek")] use crate::ed25519_dalek; use crate::identity::identity_public_key::methods::hash::IdentityPublicKeyHashMethodsV0; @@ -93,8 +93,8 @@ pub(in crate::identity::identity_public_key) fn validate_private_key_bytes_for_k KeyType::BLS12_381 => { #[cfg(feature = "bls-signatures")] { - let private_key: Option = - bls_signatures::SecretKey::from_be_bytes(private_key_bytes); + let private_key: Option = + bls::SecretKey::from_be_bytes(private_key_bytes); if private_key.is_none() { return Ok(false); } @@ -142,7 +142,7 @@ pub(in crate::identity::identity_public_key) fn validate_private_key_bytes_for_k #[cfg(test)] mod tests { use super::*; - use crate::bls_signatures::Signature; + use crate::bls::Signature; use crate::identity::{Purpose, SecurityLevel}; use dashcore::Network; use dpp::version::PlatformVersion; @@ -155,8 +155,8 @@ mod tests { let (public_key_data, secret_key) = KeyType::BLS12_381 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest()) .expect("expected to get keys"); - let decoded_secret_key = crate::bls_signatures::SecretKey::from_be_bytes(&secret_key) - .expect("expected to get secret key"); + let decoded_secret_key = + crate::bls::SecretKey::from_be_bytes(&secret_key).expect("expected to get secret key"); let public_key = decoded_secret_key.public_key(); let decoded_public_key_data = public_key.to_bytes(); assert_eq!( @@ -171,8 +171,8 @@ mod tests { let (_, secret_key) = KeyType::BLS12_381 .random_public_and_private_key_data(&mut rng, PlatformVersion::latest()) .expect("expected to get keys"); - let decoded_secret_key = crate::bls_signatures::SecretKey::from_be_bytes(&secret_key) - .expect("expected to get secret key"); + let decoded_secret_key = + crate::bls::SecretKey::from_be_bytes(&secret_key).expect("expected to get secret key"); let signature = decoded_secret_key.sign(b"hello").expect("expected to sign"); let compressed = signature.to_bytes(); let decoded_signature = Signature::from_compressed(&compressed).expect("valid signature"); diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index 404916f7d9b..2a7ab144989 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -48,7 +48,7 @@ pub mod validation; #[cfg(feature = "client")] pub mod dash_platform_protocol; -mod bls; +pub mod bls; #[cfg(feature = "fixtures-and-mocks")] pub mod tests; @@ -86,7 +86,9 @@ pub mod withdrawal; pub use async_trait; -pub use bls::*; +#[cfg(feature = "bls-signatures")] +pub use bls::native_bls; +pub use bls::BlsModule; pub mod prelude { @@ -141,8 +143,6 @@ pub mod prelude { pub use bincode; pub use bincode::enc::Encode; -#[cfg(feature = "bls-signatures")] -pub mod bls_signatures; #[cfg(feature = "data-contracts")] pub use data_contracts; #[cfg(feature = "ed25519-dalek")] diff --git a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs b/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs index 0c01d0df4eb..aa1f09c891e 100644 --- a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs +++ b/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs @@ -1,6 +1,6 @@ //! Serde support for Platform BLS keys in hex, byte-sequence and tagged-enum inputs. -use crate::bls_signatures::PublicKey as BlsPublicKey; +use crate::bls::PublicKey as BlsPublicKey; use serde::de::Visitor; use serde::{Deserializer, Serialize, Serializer}; use std::fmt; diff --git a/packages/rs-dpp/src/signing.rs b/packages/rs-dpp/src/signing.rs index 51250ecf48e..ba2256dd17b 100644 --- a/packages/rs-dpp/src/signing.rs +++ b/packages/rs-dpp/src/signing.rs @@ -1,5 +1,5 @@ #[cfg(feature = "bls-signatures")] -use crate::bls_signatures::{self, Signature}; +use crate::bls::{self, Signature}; use crate::identity::KeyType; use crate::serialization::PlatformMessageSignable; #[cfg(feature = "message-signature-verification")] @@ -41,7 +41,7 @@ impl PlatformMessageSignable for &[u8] { } } KeyType::BLS12_381 => { - let public_key = match bls_signatures::PublicKey::try_from(public_key_data) { + let public_key = match bls::PublicKey::try_from(public_key_data) { Ok(public_key) => public_key, Err(e) => { // dbg!(format!("bls public_key could not be recovered")); diff --git a/packages/rs-dpp/tests/bls_compatibility.rs b/packages/rs-dpp/tests/bls_compatibility.rs index 9854db45ad5..651c3b37374 100644 --- a/packages/rs-dpp/tests/bls_compatibility.rs +++ b/packages/rs-dpp/tests/bls_compatibility.rs @@ -1,5 +1,5 @@ use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature}; -use dpp::bls_signatures::{PublicKey, SecretKey, Signature}; +use dpp::bls::{PublicKey, SecretKey, Signature}; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::native_bls::NativeBlsModule; diff --git a/packages/rs-drive-abci/src/abci/error.rs b/packages/rs-drive-abci/src/abci/error.rs index 306e0644956..54777e4ce3e 100644 --- a/packages/rs-drive-abci/src/abci/error.rs +++ b/packages/rs-drive-abci/src/abci/error.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::BlsError; +use dpp::bls::BlsError; use dpp::consensus::ConsensusError; use tenderdash_abci::proto::abci::ExtendVoteExtension; use tenderdash_abci::proto::types::VoteExtension; diff --git a/packages/rs-drive-abci/src/error/execution.rs b/packages/rs-drive-abci/src/error/execution.rs index 850ddd54717..10645c55941 100644 --- a/packages/rs-drive-abci/src/error/execution.rs +++ b/packages/rs-drive-abci/src/error/execution.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::BlsError; +use dpp::bls::BlsError; use dpp::dashcore::consensus::encode::Error as DashCoreConsensusEncodeError; use dpp::identity::TimestampMillis; use dpp::version::FeatureVersion; diff --git a/packages/rs-drive-abci/src/error/mod.rs b/packages/rs-drive-abci/src/error/mod.rs index 241d9e7b37e..8bc9d7c1b6d 100644 --- a/packages/rs-drive-abci/src/error/mod.rs +++ b/packages/rs-drive-abci/src/error/mod.rs @@ -2,7 +2,7 @@ use crate::abci::AbciError; use crate::error::execution::ExecutionError; use crate::error::serialization::SerializationError; use crate::logging; -use dpp::bls_signatures::BlsError; +use dpp::bls::BlsError; use dpp::dashcore_rpc::Error as CoreRpcError; use dpp::data_contract::errors::DataContractError; use dpp::platform_value::Error as ValueError; diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs index 4b217a45e17..c611ea2c0a1 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_end/validator_set_update/mod.rs @@ -157,7 +157,7 @@ mod tests { use dpp::block::block_info::BlockInfo; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0; use dpp::block::extended_block_info::ExtendedBlockInfo; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::core_types::validator_set::ValidatorSet; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs index e0cc5edb6a8..5089b6a5219 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs @@ -391,7 +391,7 @@ mod tests { use crate::platform_types::platform_state::PlatformStateV0Methods; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::block::block_info::BlockInfo; - use dpp::bls_signatures::SecretKey as BlsPrivateKey; + use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::ProTxHash; use dpp::dashcore::Txid; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs index 7185b28a8d7..4292296c059 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs @@ -92,7 +92,7 @@ mod test { use crate::platform_types::validator_set::{ValidatorSet, ValidatorSetExt}; use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{Network, ProTxHash, PubkeyHash, QuorumHash}; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs index 86bc208bad2..af7b64bbd84 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v1/mod.rs @@ -301,7 +301,7 @@ mod tests { use crate::platform_types::validator_set::{ValidatorSet, ValidatorSetExt}; use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::dashcore::hashes::Hash; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs index 2b2b6d1bd29..12fa611b15d 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs @@ -16,7 +16,7 @@ use crate::rpc::core::CoreRPCLike; use crate::platform_types::signature_verification_quorum_set::{ SignatureVerificationQuorumSet, SignatureVerificationQuorumSetV0Methods, VerificationQuorum, }; -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; use dpp::dashcore::QuorumHash; use tracing::Level; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs index c890e09ab45..bc48b50873a 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs @@ -2,7 +2,7 @@ mod v0; use crate::error::execution::ExecutionError; use crate::error::Error; -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; use dpp::dashcore::QuorumHash; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs index 38b2a366fd3..0c3be48ad63 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::QuorumHash; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; @@ -91,7 +91,7 @@ impl Platform { mod tests { use crate::platform_types::platform::Platform; use crate::rpc::core::MockCoreRPCLike; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::QuorumHash; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs index 4daa5b74cce..c924a8f3c74 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::Signature; +use dpp::bls::Signature; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::{ChainLock, QuorumSigningRequestId}; @@ -47,11 +47,9 @@ where platform_state.last_committed_block_height() + 1, round ); - return Err(Error::BLSError( - dpp::bls_signatures::BlsError::DeserializationError( - "chain lock signature was not deserializable".to_string(), - ), - )); + return Err(Error::BLSError(dpp::bls::BlsError::DeserializationError( + "chain lock signature was not deserializable".to_string(), + ))); } }; @@ -231,7 +229,7 @@ where mod tests { use crate::execution::platform_events::core_chain_lock::verify_chain_lock_locally::v0::CHAIN_LOCK_REQUEST_ID_PREFIX; use crate::test::helpers::setup::TestPlatformBuilder; - use dpp::bls_signatures::Signature; + use dpp::bls::Signature; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::{BlockHash, ChainLock, QuorumSigningRequestId}; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs index bc8d5e8ff42..dcf4160a1f0 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs @@ -1,4 +1,4 @@ -use dpp::bls_signatures::Signature; +use dpp::bls::Signature; use std::fmt::{Debug, Formatter}; use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; diff --git a/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs b/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs index 8db643609f0..c60fcc245a9 100644 --- a/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/storage/store_platform_state/v1/mod.rs @@ -180,7 +180,7 @@ mod tests { use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::bincode::config; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::{ValidatorSetV0, ValidatorSetV0Getters}; use dpp::core_types::validator_set::ValidatorSet; diff --git a/packages/rs-drive-abci/src/mimic/test_quorum.rs b/packages/rs-drive-abci/src/mimic/test_quorum.rs index 4da2a3684db..1adebbf840f 100644 --- a/packages/rs-drive-abci/src/mimic/test_quorum.rs +++ b/packages/rs-drive-abci/src/mimic/test_quorum.rs @@ -1,8 +1,6 @@ use crate::platform_types::validator::v0::ValidatorV0; use crate::platform_types::validator_set::v0::ValidatorSetV0; -use dpp::bls_signatures::{ - PublicKey as BlsPublicKey, PublicKey, SecretKey as BlsPrivateKey, SecretKey, -}; +use dpp::bls::{PublicKey as BlsPublicKey, PublicKey, SecretKey as BlsPrivateKey, SecretKey}; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; use dpp::dashcore_rpc::dashcore_rpc_json::{QuorumInfoResult, QuorumMember, QuorumType}; diff --git a/packages/rs-drive-abci/src/platform_types/commit/mod.rs b/packages/rs-drive-abci/src/platform_types/commit/mod.rs index 904cafa51d8..568c5028f5a 100644 --- a/packages/rs-drive-abci/src/platform_types/commit/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/commit/mod.rs @@ -3,7 +3,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::cleaned_abci_messages::{cleaned_block_id, cleaned_commit_info}; use crate::platform_types::commit::v0::CommitV0; -use dpp::bls_signatures; +use dpp::bls; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::validation::SimpleValidationResult; @@ -83,7 +83,7 @@ impl Commit { pub fn verify_signature( &self, signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls::PublicKey, ) -> SimpleValidationResult { match self { Commit::V0(v0) => v0.verify_signature(signature, public_key), diff --git a/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs index 9fc484ebc1a..7d131cc6be3 100644 --- a/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/commit/v0/mod.rs @@ -4,8 +4,8 @@ pub mod accessors; use crate::abci::AbciError; use crate::platform_types::cleaned_abci_messages::{cleaned_block_id, cleaned_commit_info}; -use dpp::bls_signatures; -use dpp::bls_signatures::{BlsError, Signature}; +use dpp::bls; +use dpp::bls::{BlsError, Signature}; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::validation::{SimpleValidationResult, ValidationResult}; use tenderdash_abci::proto; @@ -82,7 +82,7 @@ impl CommitV0 { pub(super) fn verify_signature( &self, signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls::PublicKey, ) -> SimpleValidationResult { if signature == &[0; 96] { return ValidationResult::new_with_error(AbciError::BadRequest( @@ -137,7 +137,7 @@ mod test { use super::CommitV0; use crate::platform_types::cleaned_abci_messages::cleaned_commit_info::v0::CleanedCommitInfo; - use dpp::bls_signatures::PublicKey; + use dpp::bls::PublicKey; use dpp::dashcore_rpc::{ dashcore::hashes::sha256, dashcore::hashes::Hash, dashcore_rpc_json::QuorumType, }; diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs index 560a3f31844..82bbab7fc46 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs @@ -303,11 +303,11 @@ impl From for SignatureVerificationQuorumSetV0 { mod tests { use super::*; use crate::config::ChainLockConfig; - use dpp::bls_signatures::SecretKey as BlsPrivateKey; + use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore_rpc::json::QuorumType; - fn make_public_key(seed: u8) -> dpp::bls_signatures::PublicKey { + fn make_public_key(seed: u8) -> dpp::bls::PublicKey { let mut key_bytes = [0u8; 32]; key_bytes[0] = seed; key_bytes[31] = 1; diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs index 0e017f7a11e..e51e16cc4aa 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs @@ -1,6 +1,6 @@ use derive_more::{Deref, DerefMut, From}; -use dpp::bls_signatures; -pub use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; +use dpp::bls; +pub use dpp::bls::PublicKey as ThresholdBlsPublicKey; use dpp::dashcore::bls_sig_utils::BLSSignature; use dpp::dashcore::{QuorumHash, Txid}; @@ -206,8 +206,8 @@ impl SigningQuorum { let message_digest = sha256d::Hash::from_engine(engine); - let private_key = bls_signatures::SecretKey::from_be_bytes(&self.private_key).ok_or( - Error::BLSError(dpp::bls_signatures::BlsError::DeserializationError( + let private_key = bls::SecretKey::from_be_bytes(&self.private_key).ok_or( + Error::BLSError(dpp::bls::BlsError::DeserializationError( "Could not deserialize private key".to_string(), )), )?; @@ -223,7 +223,7 @@ impl SigningQuorum { #[cfg(test)] mod tests { use super::*; - use dpp::bls_signatures::SecretKey as BlsPrivateKey; + use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore_rpc::json::QuorumType; diff --git a/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs index 0f8c7f9e6ae..810bb7013cb 100644 --- a/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator/v0/mod.rs @@ -1,6 +1,6 @@ use crate::platform_types::platform_state::PlatformState; use crate::platform_types::platform_state::PlatformStateV0Methods; -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; pub use dpp::core_types::validator::v0::*; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash}; diff --git a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs index 8b7aa17d9be..60fe3d57a3c 100644 --- a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs @@ -6,7 +6,7 @@ use dpp::dashcore::{ProTxHash, PubkeyHash}; use crate::platform_types::platform_state::PlatformState; use crate::platform_types::validator::v0::NewValidatorIfMasternodeInState; -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; use dpp::core_types::validator::v0::ValidatorV0; pub use dpp::core_types::validator_set::v0::*; use dpp::dashcore_rpc::json::QuorumInfoResult; @@ -313,7 +313,7 @@ fn validator_node_address(node_id: &PubkeyHash, node_ip: &str, platform_p2p_port #[cfg(test)] mod tests { use super::*; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; use rand::rngs::StdRng; diff --git a/packages/rs-drive-abci/src/query/document_query/v1/tests.rs b/packages/rs-drive-abci/src/query/document_query/v1/tests.rs index d2abf839d32..3f0ac25dda1 100644 --- a/packages/rs-drive-abci/src/query/document_query/v1/tests.rs +++ b/packages/rs-drive-abci/src/query/document_query/v1/tests.rs @@ -3933,7 +3933,7 @@ mod having_trust_boundary { use crate::rpc::core::MockCoreRPCLike; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; use dpp::block::block_info::BlockInfo; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::dashcore::Network; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; @@ -6749,7 +6749,7 @@ mod chained_trust_boundary { let other_key = { let mut bytes = [0u8; 32]; bytes[31] = 43; - dpp::bls_signatures::SecretKey::from_be_bytes(&bytes).expect("valid scalar") + dpp::bls::SecretKey::from_be_bytes(&bytes).expect("valid scalar") }; let provider = TestQuorumProvider { pubkey: other_key.public_key().to_bytes(), @@ -7196,7 +7196,7 @@ mod composite_trust_boundary { let other_key = { let mut bytes = [0u8; 32]; bytes[31] = 44; - dpp::bls_signatures::SecretKey::from_be_bytes(&bytes).expect("valid scalar") + dpp::bls::SecretKey::from_be_bytes(&bytes).expect("valid scalar") }; let provider = TestQuorumProvider { pubkey: other_key.public_key().to_bytes(), diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 57f34db3ad4..e0f3b4fac3e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -19,7 +19,7 @@ use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use strategy_tests::operations::FinalizeBlockOperation::IdentityAddKeys; -use dpp::bls_signatures::SecretKey as BlsPrivateKey; +use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::consensus::Encodable; use dpp::dashcore::hashes::{sha256d, HashEngine}; use dpp::dashcore::{ChainLock, QuorumSigningRequestId, VarInt}; diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 755fb41b856..10854de9c87 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -34,7 +34,7 @@ #![allow(unused_variables)] extern crate core; -use dpp::bls_signatures::SecretKey as BlsPrivateKey; +use dpp::bls::SecretKey as BlsPrivateKey; mod addresses_with_balance; mod execution; mod failures; diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs index b85fe47c5ac..10b786ded31 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs @@ -1,5 +1,5 @@ use crate::masternode_list_item_helpers::UpdateMasternodeListItem; -use dpp::bls_signatures::SecretKey as BlsPrivateKey; +use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{ProTxHash, QuorumHash, Txid}; use dpp::dashcore_rpc::dashcore_rpc_json::{DMNState, MasternodeListItem, MasternodeType}; diff --git a/packages/rs-drive-abci/tests/strategy_tests/query.rs b/packages/rs-drive-abci/tests/strategy_tests/query.rs index ac7f30fa85f..224a81325e9 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/query.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/query.rs @@ -9,7 +9,7 @@ use dapi_grpc::platform::v0::{ get_identity_by_public_key_hash_request, get_identity_by_public_key_hash_response, GetIdentityByPublicKeyHashRequest, Proof, }; -use dpp::bls_signatures::{BlsError, Signature}; +use dpp::bls::{BlsError, Signature}; use dpp::dashcore_rpc::dashcore_rpc_json::QuorumType; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; @@ -74,7 +74,7 @@ pub struct ProofVerification<'a> { pub signature: &'a [u8; 96], /// Threshold key used to verify the signature - pub public_key: &'a dpp::bls_signatures::PublicKey, + pub public_key: &'a dpp::bls::PublicKey, } impl ProofVerification<'_> { diff --git a/packages/rs-drive-proof-verifier/src/unproved.rs b/packages/rs-drive-proof-verifier/src/unproved.rs index 4bedaa3fd0a..e2a7aeea126 100644 --- a/packages/rs-drive-proof-verifier/src/unproved.rs +++ b/packages/rs-drive-proof-verifier/src/unproved.rs @@ -24,7 +24,7 @@ use dapi_grpc::platform::v0::ResponseMetadata; use dapi_grpc::platform::v0::{self as platform}; use dapi_grpc::platform::v0::get_contract_moderation_action_counts_response::get_contract_moderation_action_counts_response_v0::Result as ModerationActionCountsResult; use dapi_grpc::tonic::async_trait; -use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::bls::PublicKey as BlsPublicKey; use dpp::core_types::validator::v0::ValidatorV0; use dpp::core_types::validator_set::v0::ValidatorSetV0; use dpp::core_types::validator_set::ValidatorSet; @@ -315,7 +315,7 @@ mod tests { use dapi_grpc::platform::v0::{ get_current_quorums_info_response, get_status_response, ResponseMetadata, }; - use dpp::bls_signatures::SecretKey; + use dpp::bls::SecretKey; use dpp::version::PlatformVersion; /// Generate a valid BLS public key as compressed bytes (48 bytes) from a diff --git a/packages/rs-drive-proof-verifier/src/verify.rs b/packages/rs-drive-proof-verifier/src/verify.rs index 045b3f0a521..b60472b7a6d 100644 --- a/packages/rs-drive-proof-verifier/src/verify.rs +++ b/packages/rs-drive-proof-verifier/src/verify.rs @@ -1,8 +1,8 @@ use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; -use dpp::bls_signatures; +use dpp::bls; use crate::Error; -use dpp::bls_signatures::Signature; +use dpp::bls::Signature; use tenderdash_abci::{ proto::types::{CanonicalVote, SignedMsgType, StateId}, signatures::{Hashable, Signable}, @@ -134,11 +134,10 @@ pub(crate) fn verify_tenderdash_signature( } })?; - let pubkey = bls_signatures::PublicKey::try_from(pubkey_bytes.as_slice()).map_err(|e| { - Error::InvalidPublicKey { + let pubkey = + bls::PublicKey::try_from(pubkey_bytes.as_slice()).map_err(|e| Error::InvalidPublicKey { error: e.to_string(), - } - })?; + })?; tracing::trace!( ?state_id, @@ -165,7 +164,7 @@ pub(crate) fn verify_tenderdash_signature( pub fn verify_signature_digest( sign_digest: &[u8], signature: &[u8; 96], - public_key: &bls_signatures::PublicKey, + public_key: &bls::PublicKey, ) -> Result { if signature == &[0; 96] { return Err(Error::SignatureVerificationError { @@ -337,13 +336,13 @@ mod tests { } /// Helper: create a deterministic BLS key pair for testing. - fn test_keypair() -> (bls_signatures::SecretKey, bls_signatures::PublicKey) { + fn test_keypair() -> (bls::SecretKey, bls::PublicKey) { let scalar = hex::decode("659dc45452f29c17f96dda38ae1546e0e9e818423cdb8cc857f3728c518b4cb8") .unwrap() .try_into() .unwrap(); - let sk = bls_signatures::SecretKey::from_be_bytes(&scalar).unwrap(); + let sk = bls::SecretKey::from_be_bytes(&scalar).unwrap(); let pk = sk.public_key(); (sk, pk) } diff --git a/packages/rs-platform-wallet/src/masternode/locator.rs b/packages/rs-platform-wallet/src/masternode/locator.rs index dee37b613e4..81f482c7949 100644 --- a/packages/rs-platform-wallet/src/masternode/locator.rs +++ b/packages/rs-platform-wallet/src/masternode/locator.rs @@ -38,7 +38,7 @@ use dash_sdk::platform::Fetch; use dashcore::hashes::{hash160, Hash}; use dashcore::secp256k1::{PublicKey as SecpPublicKey, SecretKey as SecpSecretKey}; use dashcore::{Network, PrivateKey}; -use dpp::bls_signatures::SecretKey as BlsSecretKey; +use dpp::bls::SecretKey as BlsSecretKey; use dpp::ed25519_dalek::SigningKey; use dpp::identifier::MasternodeIdentifiers; use dpp::identity::accessors::IdentityGettersV0; diff --git a/packages/rs-platform-wallet/src/masternode/update_service.rs b/packages/rs-platform-wallet/src/masternode/update_service.rs index 39e59b5395f..a1e5be1c627 100644 --- a/packages/rs-platform-wallet/src/masternode/update_service.rs +++ b/packages/rs-platform-wallet/src/masternode/update_service.rs @@ -26,7 +26,7 @@ use dashcore::hash_types::InputsHash; use dashcore::hashes::Hash; use dashcore::platform_node_id::PlatformNodeId; use dashcore::{Address as DashAddress, Network, Transaction, Txid}; -use dpp::bls_signatures::SecretKey as BlsSecretKey; +use dpp::bls::SecretKey as BlsSecretKey; use key_wallet::wallet::managed_wallet_info::transaction_builder::{ BuilderError, TransactionBuilder, TransactionSigner, }; @@ -453,7 +453,7 @@ mod tests { use crate::test_support::{ funded_wallet_manager, funded_wallet_manager_with_outputs, WalletSigner, }; - use dpp::bls_signatures::{PublicKey as BlsPublicKey, Signature as BlsSignature}; + use dpp::bls::{PublicKey as BlsPublicKey, Signature as BlsSignature}; use key_wallet::account::StandardAccountType; use std::sync::{Arc, Mutex}; diff --git a/packages/simple-signer/src/signer.rs b/packages/simple-signer/src/signer.rs index 89f9c1cc30b..9a760c0db5e 100644 --- a/packages/simple-signer/src/signer.rs +++ b/packages/simple-signer/src/signer.rs @@ -4,6 +4,7 @@ use base64::Engine; use dpp::address_funds::{AddressWitness, PlatformAddress}; use dpp::bincode::{Decode, Encode}; +use dpp::bls; use dpp::dashcore::secp256k1::rand::SeedableRng; use dpp::dashcore::secp256k1::{PublicKey, SecretKey}; use dpp::dashcore::signer; @@ -14,7 +15,7 @@ use dpp::identity::{IdentityPublicKey, KeyType}; use dpp::platform_value::BinaryData; use dpp::state_transition::errors::InvalidIdentityPublicKeyTypeError; use dpp::util::hash::ripemd160_sha256; -use dpp::{bls_signatures, dashcore, ed25519_dalek, ProtocolError}; +use dpp::{dashcore, ed25519_dalek, ProtocolError}; use rand::RngCore; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; @@ -138,7 +139,7 @@ impl Signer for SimpleSigner { Ok(signature.to_vec().into()) } KeyType::BLS12_381 => { - let pk = bls_signatures::SecretKey::from_be_bytes(private_key).ok_or( + let pk = bls::SecretKey::from_be_bytes(private_key).ok_or( ProtocolError::Generic("bls private key from bytes isn't correct".to_string()), )?; let signature = pk From fe41b079b74cd5dd40b8cf488a76f771255f5af2 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 10:31:04 +0000 Subject: [PATCH 07/11] refactor(dpp): share BLS serde visitor and field adapters Move BLS Serde support under bls/serde.rs. Share key parsing between Deserialize and field adapters while retaining tuple decoding for bincode and deserialize_any for buffered tagged fields. Deprecate the old adapter re-export and retain its optional-key path. Co-Authored-By: Codex --- packages/rs-dpp/src/bls/bls_signatures.rs | 45 ------ packages/rs-dpp/src/bls/mod.rs | 3 + .../dashcore/bls_pubkey.rs => bls/serde.rs} | 128 +++++++++++++++--- .../rs-dpp/src/core_types/validator/v0/mod.rs | 2 +- .../src/core_types/validator_set/mod.rs | 6 +- .../src/core_types/validator_set/v0/mod.rs | 5 +- .../rs-dpp/src/serialization/dashcore/mod.rs | 5 +- 7 files changed, 122 insertions(+), 72 deletions(-) rename packages/rs-dpp/src/{serialization/dashcore/bls_pubkey.rs => bls/serde.rs} (53%) diff --git a/packages/rs-dpp/src/bls/bls_signatures.rs b/packages/rs-dpp/src/bls/bls_signatures.rs index 10e91705667..c3e4f9f2890 100644 --- a/packages/rs-dpp/src/bls/bls_signatures.rs +++ b/packages/rs-dpp/src/bls/bls_signatures.rs @@ -2,8 +2,6 @@ use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature, Fr}; use rand::{CryptoRng, Rng, RngCore}; -use serde::ser::SerializeTuple; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use zeroize::Zeroizing; @@ -93,49 +91,6 @@ impl fmt::Debug for PublicKey { } } -impl Serialize for PublicKey { - fn serialize(&self, serializer: S) -> Result { - if serializer.is_human_readable() { - serializer.serialize_str(&hex::encode(self.0)) - } else { - let mut tuple = serializer.serialize_tuple(48)?; - for byte in self.0 { - tuple.serialize_element(&byte)?; - } - tuple.end() - } - } -} - -impl<'de> Deserialize<'de> for PublicKey { - fn deserialize>(deserializer: D) -> Result { - if deserializer.is_human_readable() { - crate::serialization::dashcore::bls_pubkey::deserialize(deserializer) - } else { - struct KeyVisitor; - impl<'de> serde::de::Visitor<'de> for KeyVisitor { - type Value = PublicKey; - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("48 compressed public key bytes") - } - fn visit_seq>( - self, - mut seq: A, - ) -> Result { - let mut bytes = [0; 48]; - for (i, byte) in bytes.iter_mut().enumerate() { - *byte = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?; - } - PublicKey::try_from(bytes.as_slice()).map_err(serde::de::Error::custom) - } - } - deserializer.deserialize_tuple(48, KeyVisitor) - } - } -} - /// A secret scalar; the backend clears its storage on drop. #[derive(Clone, Debug)] pub struct SecretKey(BlsSecretKey); diff --git a/packages/rs-dpp/src/bls/mod.rs b/packages/rs-dpp/src/bls/mod.rs index 3de89a047c0..44b95b4a2bb 100644 --- a/packages/rs-dpp/src/bls/mod.rs +++ b/packages/rs-dpp/src/bls/mod.rs @@ -4,6 +4,9 @@ mod bls_signatures; pub use bls_signatures::{BlsError, PublicKey, SecretKey, Signature}; #[cfg(feature = "bls-signatures")] pub mod native_bls; +/// Serde implementations and field adapters for BLS public keys. +#[cfg(feature = "bls-signatures")] +pub mod serde; use crate::{ProtocolError, PublicKeyValidationError}; diff --git a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs b/packages/rs-dpp/src/bls/serde.rs similarity index 53% rename from packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs rename to packages/rs-dpp/src/bls/serde.rs index aa1f09c891e..205a1e71b8a 100644 --- a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs +++ b/packages/rs-dpp/src/bls/serde.rs @@ -1,23 +1,53 @@ //! Serde support for Platform BLS keys in hex, byte-sequence and tagged-enum inputs. use crate::bls::PublicKey as BlsPublicKey; -use serde::de::Visitor; -use serde::{Deserializer, Serialize, Serializer}; +use ::serde::de::Visitor; +use ::serde::ser::SerializeTuple; +use ::serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; /// Size of a compressed BLS12-381 G1 public key. const COMPRESSED_G1_LEN: usize = 48; +impl Serialize for BlsPublicKey { + fn serialize(&self, serializer: S) -> Result { + if serializer.is_human_readable() { + serializer.serialize_str(&hex::encode(self.to_bytes())) + } else { + let mut tuple = serializer.serialize_tuple(COMPRESSED_G1_LEN)?; + for byte in self.to_bytes() { + tuple.serialize_element(&byte)?; + } + tuple.end() + } + } +} + +impl<'de> Deserialize<'de> for BlsPublicKey { + fn deserialize>(deserializer: D) -> Result { + if deserializer.is_human_readable() { + deserializer.deserialize_any(BlsPublicKeyVisitor) + } else { + // Bincode needs the fixed tuple length and cannot use deserialize_any. + deserializer.deserialize_tuple(COMPRESSED_G1_LEN, BlsPublicKeyVisitor) + } + } +} + +/// Serialize a public-key field with the DPP key's standard representation. pub fn serialize(pk: &BlsPublicKey, serializer: S) -> Result { pk.serialize(serializer) } +/// Decode a field from self-describing or buffered tagged-enum data. +/// +/// For formats such as bincode, use the key's `Deserialize` implementation instead. pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { // Tagged enum buffers may supply either representation regardless of is_human_readable(). deserializer.deserialize_any(BlsPublicKeyVisitor) } -fn from_compressed_g1_bytes(bytes: &[u8]) -> Result { +fn from_compressed_g1_bytes(bytes: &[u8]) -> Result { if bytes.len() != COMPRESSED_G1_LEN { return Err(E::custom(format!( "expected {COMPRESSED_G1_LEN} compressed-G1 bytes for public key, got {}", @@ -41,7 +71,7 @@ impl<'de> Visitor<'de> for BlsPublicKeyVisitor { ) } - fn visit_str(self, s: &str) -> Result { + fn visit_str(self, s: &str) -> Result { if s.len() != COMPRESSED_G1_LEN * 2 { return Err(E::custom(format!( "expected {} hex chars for compressed G1 public key, got {}", @@ -58,18 +88,21 @@ impl<'de> Visitor<'de> for BlsPublicKeyVisitor { from_compressed_g1_bytes(&bytes) } - fn visit_bytes(self, v: &[u8]) -> Result { + fn visit_bytes(self, v: &[u8]) -> Result { from_compressed_g1_bytes(v) } - fn visit_seq>(self, mut seq: A) -> Result { + fn visit_seq>( + self, + mut seq: A, + ) -> Result { let mut bytes = Vec::with_capacity(COMPRESSED_G1_LEN); while let Some(b) = seq.next_element::()? { // A valid compressed-G1 public key is exactly COMPRESSED_G1_LEN // bytes; reject as soon as a hostile payload exceeds that rather // than allocating/parsing an arbitrarily long sequence first. if bytes.len() == COMPRESSED_G1_LEN { - return Err(serde::de::Error::invalid_length(bytes.len() + 1, &self)); + return Err(::serde::de::Error::invalid_length(bytes.len() + 1, &self)); } bytes.push(b); } @@ -95,8 +128,7 @@ pub mod option { opt: &Option, serializer: S, ) -> Result { - // Option's built-in Serialize delegates to T's Serialize, which - // is the upstream BlsPublicKey impl — already correct. + // Option delegates to the DPP public key's Serialize implementation. opt.serialize(serializer) } @@ -112,11 +144,11 @@ pub mod option { f.write_str("Option") } - fn visit_none(self) -> Result { + fn visit_none(self) -> Result { Ok(None) } - fn visit_unit(self) -> Result { + fn visit_unit(self) -> Result { Ok(None) } @@ -135,7 +167,7 @@ pub mod option { #[cfg(test)] mod tests { use super::*; - use serde::{Deserialize, Serialize}; + use ::serde::{Deserialize, Serialize}; use serde_json::json; // A known-valid compressed-G1 BLS public key (deterministic — the @@ -150,6 +182,70 @@ mod tests { #[derive(Serialize, Deserialize)] struct OptWrap(#[serde(with = "super::option")] Option); + #[test] + fn should_accept_the_same_json_representations_directly_and_through_the_adapter() { + let bytes = hex::decode(PK_HEX).unwrap(); + for value in [json!(PK_HEX), json!(PK_HEX.to_uppercase()), json!(bytes)] { + let direct: BlsPublicKey = serde_json::from_value(value.clone()).unwrap(); + let adapted: Wrap = serde_json::from_value(value).unwrap(); + assert_eq!(direct, adapted.0); + assert_eq!(direct.to_bytes().as_slice(), bytes); + } + } + + #[test] + fn should_reject_malformed_keys_directly_and_through_the_adapter() { + for value in [ + json!("ab"), + json!("z".repeat(96)), + json!(vec![0u8; 47]), + json!(vec![0u8; 49]), + json!(vec![0u8; 48]), + ] { + assert!(serde_json::from_value::(value.clone()).is_err()); + assert!(serde_json::from_value::(value).is_err()); + } + } + + #[test] + fn should_decode_bincode_keys_without_consuming_the_following_fields() { + let key: BlsPublicKey = serde_json::from_value(json!(PK_HEX)).unwrap(); + let record = (key, 0x21u8, Some(key)); + let config = bincode::config::standard().with_big_endian(); + let encoded = bincode::serde::encode_to_vec(record, config).unwrap(); + let mut expected = key.to_bytes().to_vec(); + expected.extend([0x21, 1]); + expected.extend(key.to_bytes()); + assert_eq!(encoded, expected); + let (decoded, consumed): ((BlsPublicKey, u8, Option), usize) = + bincode::serde::decode_from_slice(&encoded, config).unwrap(); + assert_eq!(decoded, record); + assert_eq!(consumed, encoded.len()); + assert!( + bincode::serde::decode_from_slice::(&encoded[..47], config).is_err() + ); + } + + #[test] + fn should_keep_legacy_field_adapter_paths_working() { + #[derive(Serialize, Deserialize)] + struct LegacyKey( + #[serde(with = "crate::serialization::dashcore::bls_pubkey")] BlsPublicKey, + ); + #[derive(Serialize, Deserialize)] + struct LegacyOption( + #[serde(with = "crate::serialization::dashcore::bls_pubkey::option")] + Option, + ); + + let key: LegacyKey = serde_json::from_value(json!(PK_HEX)).unwrap(); + assert_eq!(serde_json::to_value(key).unwrap(), json!(PK_HEX)); + for value in [json!(PK_HEX), json!(null)] { + let key: LegacyOption = serde_json::from_value(value.clone()).unwrap(); + assert_eq!(serde_json::to_value(key).unwrap(), value); + } + } + #[test] fn json_hr_round_trip_is_the_hex_string() { // Human-readable (serde_json::Value): hex in, identical hex out (visit_str). @@ -159,9 +255,7 @@ mod tests { #[test] fn json_borrowed_str_path_works() { - // `serde_json::from_str` yields borrowed strings — the path upstream's - // `<&str>::deserialize` handled but `from_value`/Content did not. Our - // `visit_str` takes `&str`, so both work. + // The shared visitor accepts borrowed strings as well as owned JSON values. let pk: Wrap = serde_json::from_str(&format!("\"{PK_HEX}\"")).expect("from_str"); assert_eq!(serde_json::to_value(&pk).expect("to json"), json!(PK_HEX)); } @@ -169,8 +263,8 @@ mod tests { #[test] fn value_non_hr_byte_seq_round_trip() { // Non-HR `platform_value` serializes the key as a 48-byte sequence; the - // `visit_seq` path (the bug the un-ignored ValidatorSet test exposed) - // must reconstruct it. Re-serialize to JSON to confirm the same key. + // shared visit_seq path must reconstruct it. Re-serialize to JSON to + // confirm the same key. let pk: Wrap = serde_json::from_value(json!(PK_HEX)).expect("from hex"); let value = platform_value::to_value(&pk).expect("to value"); let pk2: Wrap = platform_value::from_value(value).expect("from value seq"); diff --git a/packages/rs-dpp/src/core_types/validator/v0/mod.rs b/packages/rs-dpp/src/core_types/validator/v0/mod.rs index 02de617a2c4..eedbcb3dd1b 100644 --- a/packages/rs-dpp/src/core_types/validator/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/v0/mod.rs @@ -24,7 +24,7 @@ pub struct ValidatorV0 { // Tagged enum buffers can carry either hex strings or byte sequences. #[cfg_attr( feature = "serde-conversion", - serde(with = "crate::serialization::dashcore::bls_pubkey::option") + serde(with = "crate::bls::serde::option") )] pub public_key: Option, /// The node address diff --git a/packages/rs-dpp/src/core_types/validator_set/mod.rs b/packages/rs-dpp/src/core_types/validator_set/mod.rs index ece8d5cf608..0b517f4ed00 100644 --- a/packages/rs-dpp/src/core_types/validator_set/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/mod.rs @@ -165,7 +165,7 @@ mod json_convertible_tests { /// keys ARE deterministic, but the 96-char hex / 48-byte literal is too /// unwieldy to inline as a string constant, so we interpolate the actual /// `to_value`/`to_json` of the same pubkey objects we put in the fixture. - /// (The dedicated `serialization::dashcore::bls_pubkey` unit tests + /// (The dedicated `bls::serde` unit tests /// independently cover the pubkey round-trip.) fn build_fixture() -> (ValidatorSet, BlsPublicKey, BlsPublicKey) { let mut rng = StdRng::seed_from_u64(42); @@ -200,7 +200,7 @@ mod json_convertible_tests { // visible and verifiable in-place — neither path interpolates `to_json` / // `to_value` of the object under test. JSON (HR) uses the hex string // directly; the non-HR `Value` form is the *same* 48 bytes decoded into an - // `Array` of `U8` (blstrs serializes the pubkey through a `u8` tuple, which + // `Array` of `U8` (the DPP key serializes through a `u8` tuple, which // platform_value collects as `Array[U8]` — NOT a typed `Bytes` variant). const VALIDATOR_PK_HEX: &str = "85d81dd12c73cca83f7d1bf8b78fadb695e3a2bc21d53b35ff2f74eaa28c6e163c98d3d5f9bb7252b4d836e484c7cc60"; @@ -230,7 +230,7 @@ mod json_convertible_tests { // keyed by ProTxHash hex, hash fields as lowercase hex strings, // sized-int fields preserved. The inner Validator's own // `$formatVersion` tag (now applied) appears alongside its other - // snake_case fields. (`serialization::dashcore::bls_pubkey` additionally + // snake_case fields. (`bls::serde` additionally // has its own dedicated BLS round-trip tests.) assert_eq!( json, diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index 58591815ac7..b988a0a1f43 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -33,10 +33,7 @@ pub struct ValidatorSetV0 { pub members: BTreeMap, /// The threshold quorum public key // Tagged enum buffers can carry either hex strings or byte sequences. - #[cfg_attr( - feature = "serde-conversion", - serde(with = "crate::serialization::dashcore::bls_pubkey") - )] + #[cfg_attr(feature = "serde-conversion", serde(with = "crate::bls::serde"))] pub threshold_public_key: BlsPublicKey, } diff --git a/packages/rs-dpp/src/serialization/dashcore/mod.rs b/packages/rs-dpp/src/serialization/dashcore/mod.rs index becf7e56ac0..c21d6baa443 100644 --- a/packages/rs-dpp/src/serialization/dashcore/mod.rs +++ b/packages/rs-dpp/src/serialization/dashcore/mod.rs @@ -1,5 +1,6 @@ -//! Serde adapters for the Core types embedded in Platform state. +//! Compatibility re-exports for Serde field adapters. /// Accept hex strings or byte sequences for Platform BLS public keys. #[cfg(feature = "bls-signatures")] -pub mod bls_pubkey; +#[deprecated(note = "use dpp::bls::serde instead")] +pub use crate::bls::serde as bls_pubkey; From fe187d293ced9f7702e5c6bc44a3cc8d8dcd6630 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 10:35:05 +0000 Subject: [PATCH 08/11] refactor(drive-abci): retain legacy storage readers in BLS migration Restore Platform-state V0 and quorum-storage V0/V1 readers and their production dependency. Keep their removal separate from the backend migration so the compatibility policy can be discussed independently. Adapt restored imports to dpp::bls. Co-Authored-By: Codex --- packages/rs-drive-abci/Cargo.toml | 4 +- .../rs-drive-abci/src/platform_types/mod.rs | 2 - .../src/platform_types/platform_state/mod.rs | 78 +++------- .../platform_state_for_saving/mod.rs | 8 +- .../platform_state_for_saving/v0/mod.rs | 98 ++++++++++++ .../v0/old_structures/mod.rs | 122 +++++++++++++++ .../signature_verification_quorum_set/mod.rs | 47 ++---- .../v0/for_saving_v0.rs | 143 ++++++++++++++++++ .../v0/for_saving_v1.rs | 58 ++++++- .../v0/for_saving_v2.rs | 4 + .../v0/mod.rs | 1 + .../unsupported_legacy_bls_storage.rs | 28 ---- .../test/fixture/platform_state_supported.hex | 1 - 13 files changed, 463 insertions(+), 131 deletions(-) create mode 100644 packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs create mode 100644 packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs delete mode 100644 packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs delete mode 100644 packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index d4fb5c9b18f..1d194f2416d 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -129,8 +129,8 @@ grovedb-path = { workspace = true } grovedb-storage = { workspace = true } [features] -default = [] -mocks = ["mockall", "drive/fixtures-and-mocks", "dep:bls-signatures"] +default = ["bls-signatures"] +mocks = ["mockall", "drive/fixtures-and-mocks", "bls-signatures"] console = ["console-subscriber", "tokio/tracing"] testing-config = [] # Compiles in the shielded-pool seeder, the `snapshot-bake` subcommand, and diff --git a/packages/rs-drive-abci/src/platform_types/mod.rs b/packages/rs-drive-abci/src/platform_types/mod.rs index 86bab2f76cd..0f3b33981de 100644 --- a/packages/rs-drive-abci/src/platform_types/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/mod.rs @@ -24,8 +24,6 @@ pub mod required_identity_public_key_set; pub mod signature_verification_quorum_set; /// The state transition execution result as part of the block execution outcome pub mod state_transitions_processing_result; -/// Rejection of unsupported legacy BLS storage formats. -pub mod unsupported_legacy_bls_storage; /// The validator module /// A validator is a masternode that can participate in consensus by being part of a validator set pub mod validator; diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index 7f30883b653..f4467c9cce9 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -323,7 +323,18 @@ impl TryFromPlatformVersioned for PlatformState { platform_version: &PlatformVersion, ) -> Result { match value { - PlatformStateForSaving::V0(unsupported) => match unsupported {}, + PlatformStateForSaving::V0(v0) => { + match platform_version.drive_abci.structs.platform_state_structure { + 0 => Ok(PlatformState::from(v0)), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: + "PlatformState::try_from_platform_versioned(PlatformStateForSavingV0)" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } PlatformStateForSaving::V1(v1) => { match platform_version.drive_abci.structs.platform_state_structure { 0 => Ok(PlatformState::from(v1)), @@ -364,32 +375,19 @@ mod tests { use std::ops::Deref; #[test] - fn should_reject_legacy_bls_state_from_testnet_with_upgrade_instructions() { + fn should_deserialize_state_stored_in_version_0_from_testnet() { let serialized_state = hex::decode(PLATFORM_STATE_V3_TESTNET.deref()).expect("failed to decode hex"); - let error = - match PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V3) - { - Ok(_) => panic!("legacy state must require an intermediate upgrade"), - Err(error) => error, - }; - assert!(matches!( - error, - ProtocolError::PlatformDeserializationError(_) - )); - assert!(error.to_string().contains("v4.0.0")); - assert!(error.to_string().contains("commit at least one block")); + PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V3) + .expect("failed to deserialize state"); } /// Serializing through the borrowed conversion must preserve the saved format. #[test] fn should_preserve_pre_change_serialization_hash() { - // Re-serialized from PLATFORM_STATE_V8_DEVNET with commit 734bd4eea7, - // before removal of the legacy readers. Platform state V1, quorum V2. let serialized_state = - hex::decode(include_str!("../../test/fixture/platform_state_supported.hex").trim()) - .expect("failed to decode hex"); + hex::decode(PLATFORM_STATE_V8_DEVNET.deref()).expect("failed to decode hex"); let state = PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) @@ -406,50 +404,12 @@ mod tests { } #[test] - fn should_preserve_supported_storage_tags_and_bytes() { - let bytes = - hex::decode(include_str!("../../test/fixture/platform_state_supported.hex").trim()) - .unwrap(); - let state = PlatformState::versioned_deserialize_trusted(&bytes, &PLATFORM_V9).unwrap(); - let config = config::standard().with_big_endian(); - let v1 = PlatformStateForSavingV1::try_from(&state).unwrap(); - for quorums in [ - &v1.chain_lock_validating_quorums, - &v1.instant_lock_validating_quorums, - ] { - let encoded = bincode::encode_to_vec(quorums, config).unwrap(); - assert_eq!(encoded[0], 2, "quorum storage tag must remain V2"); - } - let v2 = PlatformStateForSavingV2::from(&state); - for (tag, record) in [ - (1, PlatformStateForSaving::V1(v1)), - (2, PlatformStateForSaving::V2(v2)), - ] { - let encoded = bincode::encode_to_vec(record, config).unwrap(); - assert_eq!(encoded[0], tag, "platform storage tag must not change"); - let (decoded, consumed): (PlatformStateForSaving, _) = - bincode::borrow_decode_from_slice(&encoded, config).unwrap(); - assert_eq!(consumed, encoded.len()); - assert_eq!(bincode::encode_to_vec(decoded, config).unwrap(), encoded); - } - } - - #[test] - fn should_reject_devnet_state_containing_legacy_quorums() { + fn should_deserialize_state_stored_in_version_8_from_devnet() { let serialized_state = hex::decode(PLATFORM_STATE_V8_DEVNET.deref()).expect("failed to decode hex"); - let error = - match PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) - { - Ok(_) => panic!("legacy quorums must require an intermediate upgrade"), - Err(error) => error, - }; - assert!(matches!( - error, - ProtocolError::PlatformDeserializationError(_) - )); - assert!(error.to_string().contains("v4.0.0")); + PlatformState::versioned_deserialize_trusted(&serialized_state, &PLATFORM_V9) + .expect("failed to deserialize state"); } } } diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs index 2ee162a1ddb..c737c7a1a8b 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/mod.rs @@ -1,10 +1,12 @@ +use crate::platform_types::platform_state::platform_state_for_saving::v0::PlatformStateForSavingV0; use crate::platform_types::platform_state::platform_state_for_saving::v1::PlatformStateForSavingV1; use crate::platform_types::platform_state::platform_state_for_saving::v2::PlatformStateForSavingV2; -use crate::platform_types::unsupported_legacy_bls_storage::UnsupportedLegacyBlsStorage; use bincode::Encode; use derive_more::From; use dpp::platform_serialization::de::Decode; +/// Structure 0 as first shipped. +pub mod v0; /// Structure 0 with the previous fee versions. pub mod v1; /// Structure 1: masternodes and validator sets as entries beside the record. @@ -13,8 +15,8 @@ pub mod v2; /// Platform state #[derive(Clone, Debug, Encode, Decode, From)] pub enum PlatformStateForSaving { - /// Unsupported legacy format; its tag remains reserved. - V0(UnsupportedLegacyBlsStorage), + /// Version 0 + V0(PlatformStateForSavingV0), /// Version 1 V1(PlatformStateForSavingV1), /// Version 2: the masternode list and the validator sets live as one aux diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs new file mode 100644 index 00000000000..6db1974da24 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/mod.rs @@ -0,0 +1,98 @@ +use crate::platform_types::masternode::Masternode; +use crate::platform_types::platform_state::entry_changes::EntryChanges; +use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::signature_verification_quorum_set::SignatureVerificationQuorumSetForSaving; +use bincode::Encode; +use dpp::block::block_info::BlockInfo; +use dpp::block::extended_block_info::ExtendedBlockInfo; +use dpp::dashcore::hashes::Hash; +use dpp::dashcore::{ProTxHash, QuorumHash}; +use dpp::fee::default_costs::CachedEpochIndexFeeVersionsFieldsBeforeVersion4; +use dpp::platform_serialization::de::Decode; +use dpp::platform_value::Bytes32; +use dpp::util::deserializer::ProtocolVersion; +use dpp::version::fee::FeeVersion; +use std::collections::BTreeMap; + +mod old_structures; + +/// Platform state +#[derive(Clone, Debug, Encode, Decode)] +pub struct PlatformStateForSavingV0 { + /// Information about the genesis block + pub genesis_block_info: Option, + /// Information about the last block + pub last_committed_block_info: Option, + /// Current Version + pub current_protocol_version_in_consensus: ProtocolVersion, + /// upcoming protocol version + pub next_epoch_protocol_version: ProtocolVersion, + /// current quorum + pub current_validator_set_quorum_hash: Bytes32, + /// next quorum + pub next_validator_set_quorum_hash: Option, + /// current validator set quorums + /// The validator set quorums are a subset of the quorums, but they also contain the list of + /// all members + #[bincode(with_serde)] + pub validator_sets: Vec<(Bytes32, old_structures::OldStructureValidatorSet)>, + + /// The quorums used for validating chain locks + pub chain_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, + + /// The quorums used for validating instant locks + pub instant_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, + + /// current full masternode list + pub full_masternode_list: BTreeMap, + + /// current HPMN masternode list + pub hpmn_masternode_list: BTreeMap, + + /// previous FeeVersions + pub previous_fee_versions: CachedEpochIndexFeeVersionsFieldsBeforeVersion4, +} + +impl From for PlatformState { + fn from(value: PlatformStateForSavingV0) -> Self { + PlatformState { + genesis_block_info: value.genesis_block_info, + last_committed_block_info: value.last_committed_block_info, + current_protocol_version_in_consensus: value.current_protocol_version_in_consensus, + next_epoch_protocol_version: value.next_epoch_protocol_version, + current_validator_set_quorum_hash: QuorumHash::from_byte_array( + value.current_validator_set_quorum_hash.to_buffer(), + ), + next_validator_set_quorum_hash: value + .next_validator_set_quorum_hash + .map(|bytes| QuorumHash::from_byte_array(bytes.to_buffer())), + validator_sets: value + .validator_sets + .into_iter() + .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v.into())) + .collect(), + chain_lock_validating_quorums: value.chain_lock_validating_quorums.into(), + instant_lock_validating_quorums: value.instant_lock_validating_quorums.into(), + full_masternode_list: value + .full_masternode_list + .into_iter() + .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) + .collect(), + hpmn_masternode_list: value + .hpmn_masternode_list + .into_iter() + .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) + .collect(), + previous_fee_versions: value + .previous_fee_versions + .into_keys() + .map(|epoch_index| (epoch_index, FeeVersion::first())) + .collect(), + // a state read back from disk has not been written in full since + heavy_fields_dirty: true, + // this record carried the collections itself, so no entries back it on disk + masternode_changes: EntryChanges::all(), + validator_set_changes: EntryChanges::all(), + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs new file mode 100644 index 00000000000..8ad16315f56 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/platform_state/platform_state_for_saving/v0/old_structures/mod.rs @@ -0,0 +1,122 @@ +#[cfg(feature = "bls-signatures")] +use dpp::bls::PublicKey; +use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum OldStructureValidatorSet { + /// Version 0 + V0(OldStructureValidatorSetV0), +} + +impl From for dpp::core_types::validator_set::ValidatorSet { + fn from(value: OldStructureValidatorSet) -> Self { + match value { + OldStructureValidatorSet::V0(v0) => { + dpp::core_types::validator_set::ValidatorSet::V0(v0.into()) + } + } + } +} + +/// The validator set is only slightly different from a quorum as it does not contain non valid +/// members +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct OldStructureValidatorSetV0 { + /// The quorum hash + pub quorum_hash: QuorumHash, + /// Rotation quorum index is available only for DIP24 quorums + pub quorum_index: Option, + /// Active height + pub core_height: u32, + /// The list of masternodes + pub members: BTreeMap, + /// The threshold quorum public key + #[cfg(feature = "bls-signatures")] + pub threshold_public_key: bls_signatures::PublicKey, + + /// Extra fields for forward compatibility. + #[cfg(not(feature = "bls-signatures"))] + #[serde(flatten)] + pub extra_fields: std::collections::HashMap, +} + +impl From for dpp::core_types::validator_set::v0::ValidatorSetV0 { + fn from(value: OldStructureValidatorSetV0) -> Self { + let OldStructureValidatorSetV0 { + quorum_hash, + quorum_index, + core_height, + members, + #[cfg(feature = "bls-signatures")] + threshold_public_key, + .. + } = value; + Self { + quorum_hash, + quorum_index, + core_height, + members: members + .into_iter() + .map(|(pro_tx_hash, validator)| (pro_tx_hash, validator.into())) + .collect(), + #[cfg(feature = "bls-signatures")] + threshold_public_key: PublicKey::try_from(threshold_public_key.to_bytes().as_slice()) + .expect("this should not be possible to error as the threshold_public_key was already verified on disk"), + #[cfg(not(feature = "bls-signatures"))] + threshold_public_key: Default::default(), + } + } +} + +/// A validator in the context of a quorum +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct ValidatorV0 { + /// The proTxHash + pub pro_tx_hash: ProTxHash, + /// The public key share of this validator for this quorum + #[cfg(feature = "bls-signatures")] + pub public_key: Option, + /// The node address + pub node_ip: String, + /// The node id + pub node_id: PubkeyHash, + /// Core port + pub core_port: u16, + /// Http port + pub platform_http_port: u16, + /// Tenderdash port + pub platform_p2p_port: u16, + /// Is the validator banned + pub is_banned: bool, +} + +impl From for dpp::core_types::validator::v0::ValidatorV0 { + fn from(value: ValidatorV0) -> Self { + let ValidatorV0 { + pro_tx_hash, + #[cfg(feature = "bls-signatures")] + public_key, + node_ip, + node_id, + core_port, + platform_http_port, + platform_p2p_port, + is_banned, + } = value; + Self { + pro_tx_hash, + #[cfg(feature = "bls-signatures")] + public_key: public_key.map(|pk| PublicKey::try_from(pk.to_bytes().as_slice()).expect("this should not be possible to error as the public_key was already verified on disk")), + #[cfg(not(feature = "bls-signatures"))] + public_key: None, + node_ip, + node_id, + core_port, + platform_http_port, + platform_p2p_port, + is_banned, + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs index 440aac01889..1d4a9e71967 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs @@ -3,6 +3,8 @@ mod v0; use crate::config::QuorumLikeConfig; use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v0::SignatureVerificationQuorumSetForSavingV0; +use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v1::SignatureVerificationQuorumSetForSavingV1; use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v2::SignatureVerificationQuorumSetForSavingV2; pub use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::{ QuorumConfig, QuorumsWithConfig, SelectedQuorumSetIterator, SignatureVerificationQuorumSetV0, @@ -11,7 +13,6 @@ pub use crate::platform_types::signature_verification_quorum_set::v0::quorum_set pub use crate::platform_types::signature_verification_quorum_set::v0::quorums::{ Quorum, Quorums, SigningQuorum, ThresholdBlsPublicKey, VerificationQuorum, }; -use crate::platform_types::unsupported_legacy_bls_storage::UnsupportedLegacyBlsStorage; use bincode::{Decode, Encode}; use derive_more::From; use dpp::version::PlatformVersion; @@ -117,10 +118,10 @@ impl SignatureVerificationQuorumSetV0Methods for SignatureVerificationQuorumSet /// Core Quorum Set structure for saving to the database #[derive(Debug, Clone, Encode, Decode)] pub enum SignatureVerificationQuorumSetForSaving { - /// Unsupported legacy format; its tag remains reserved. - V0(UnsupportedLegacyBlsStorage), - /// Unsupported legacy format; its tag remains reserved. - V1(UnsupportedLegacyBlsStorage), + /// Version 0 of the signature verification quorums + V0(SignatureVerificationQuorumSetForSavingV0), + /// Version 1 of the signature verification quorums + V1(SignatureVerificationQuorumSetForSavingV1), /// Version 2 of the signature verification quorums V2(SignatureVerificationQuorumSetForSavingV2), } @@ -138,39 +139,15 @@ impl From for SignatureVerificationQuorumSetForS impl From for SignatureVerificationQuorumSet { fn from(value: SignatureVerificationQuorumSetForSaving) -> Self { match value { - SignatureVerificationQuorumSetForSaving::V0(unsupported) - | SignatureVerificationQuorumSetForSaving::V1(unsupported) => match unsupported {}, + SignatureVerificationQuorumSetForSaving::V0(v0) => { + SignatureVerificationQuorumSet::V0(v0.into()) + } + SignatureVerificationQuorumSetForSaving::V1(v1) => { + SignatureVerificationQuorumSet::V0(v1.into()) + } SignatureVerificationQuorumSetForSaving::V2(v2) => { SignatureVerificationQuorumSet::V0(v2.into()) } } } } - -#[cfg(test)] -mod legacy_storage_tests { - use super::SignatureVerificationQuorumSetForSaving; - use bincode::{config, error::DecodeError}; - - #[test] - fn should_reject_legacy_bls_quorum_formats_before_reading_their_payload() { - for version in [0u32, 1] { - let bytes = bincode::encode_to_vec(version, config::standard().with_big_endian()) - .expect("encode format tag"); - let error = bincode::decode_from_slice::( - &bytes, - config::standard().with_big_endian(), - ) - .expect_err("legacy quorum format must be rejected"); - let borrowed_error = bincode::borrow_decode_from_slice::< - SignatureVerificationQuorumSetForSaving, - _, - >(&bytes, config::standard().with_big_endian()) - .expect_err("borrowed decoding must reject legacy quorums too"); - assert_eq!(error.to_string(), borrowed_error.to_string()); - assert!(matches!(error, DecodeError::Other(_))); - assert!(error.to_string().contains("v4.0.0")); - assert!(error.to_string().contains("commit at least one block")); - } - } -} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs new file mode 100644 index 00000000000..8c5345cc565 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs @@ -0,0 +1,143 @@ +use crate::platform_types::signature_verification_quorum_set::v0::quorum_config_for_saving_v0::QuorumConfigForSavingV0; +use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::PreviousPastQuorumsV0; +use crate::platform_types::signature_verification_quorum_set::{ + Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, + VerificationQuorum, +}; +use bincode::{Decode, Encode}; +use dpp::dashcore::hashes::Hash; +use dpp::dashcore::QuorumHash; +use dpp::platform_value::Bytes32; + +#[derive(Debug, Clone, Encode, Decode)] +pub struct SignatureVerificationQuorumSetForSavingV0 { + config: QuorumConfigForSavingV0, + current_quorums: Vec, + previous_quorums: Option, +} + +impl From for SignatureVerificationQuorumSetForSaving { + fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { + SignatureVerificationQuorumSetForSaving::V0(value) + } +} + +impl From for SignatureVerificationQuorumSetForSavingV0 { + fn from(value: SignatureVerificationQuorumSetV0) -> Self { + let SignatureVerificationQuorumSetV0 { + config, + current_quorums, + previous, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + previous_quorums: previous.map(|previous| previous.into()), + } + } +} + +impl From for SignatureVerificationQuorumSetV0 { + fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { + let SignatureVerificationQuorumSetForSavingV0 { + config, + current_quorums, + previous_quorums, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + previous: previous_quorums.map(|previous| previous.into()), + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct PreviousPastQuorumsForSavingV0 { + quorums: Vec, + last_active_core_height: u32, + updated_at_core_height: u32, + previous_change_height: Option, +} + +impl From for PreviousPastQuorumsForSavingV0 { + fn from(value: PreviousPastQuorumsV0) -> Self { + let PreviousPastQuorumsV0 { + quorums, + last_active_core_height, + updated_at_core_height, + previous_change_height, + } = value; + + Self { + quorums: quorums.into(), + last_active_core_height, + updated_at_core_height, + previous_change_height, + } + } +} + +impl From for PreviousPastQuorumsV0 { + fn from(value: PreviousPastQuorumsForSavingV0) -> Self { + let PreviousPastQuorumsForSavingV0 { + quorums, + last_active_core_height: active_core_height, + updated_at_core_height, + previous_change_height, + } = value; + + Self { + quorums: quorums.into(), + last_active_core_height: active_core_height, + updated_at_core_height, + previous_change_height, + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct QuorumForSavingV0 { + hash: Bytes32, + #[cfg(feature = "bls-signatures")] + #[bincode(with_serde)] + public_key: bls_signatures::PublicKey, + index: Option, +} + +impl From> for Quorums { + fn from(value: Vec) -> Self { + Quorums::from_iter(value.into_iter().map(|quorum| { + ( + QuorumHash::from_byte_array(quorum.hash.to_buffer()), + VerificationQuorum { + #[cfg(feature = "bls-signatures")] + public_key: dpp::bls::PublicKey::try_from( + quorum.public_key.to_bytes().as_slice(), + ) + .expect("expected to convert between BLS key libraries (from chia)"), + #[cfg(not(feature = "bls-signatures"))] + public_key: Default::default(), + index: quorum.index, + }, + ) + })) + } +} + +impl From> for Vec { + fn from(quorums: Quorums) -> Self { + quorums + .into_iter() + .map(|(hash, quorum)| QuorumForSavingV0 { + hash: Bytes32::from(hash.as_byte_array()), + #[cfg(feature = "bls-signatures")] + public_key: bls_signatures::PublicKey::from_bytes(&quorum.public_key.to_bytes()) + .expect("expected to convert between BLS key libraries (to chia)"), + index: quorum.index, + }) + .collect() + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs index 01162ccf4cd..1d903b160a1 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs @@ -1,6 +1,10 @@ +#[cfg(feature = "bls-signatures")] +use crate::platform_types::signature_verification_quorum_set::v0::for_saving_v0::PreviousPastQuorumsForSavingV0; +use crate::platform_types::signature_verification_quorum_set::v0::quorum_config_for_saving_v0::QuorumConfigForSavingV0; use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::PreviousPastQuorumsV0; use crate::platform_types::signature_verification_quorum_set::{ - Quorums, ThresholdBlsPublicKey, VerificationQuorum, + Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, + ThresholdBlsPublicKey, VerificationQuorum, }; use bincode::{Decode, Encode}; @@ -8,6 +12,58 @@ use dpp::dashcore::hashes::Hash; use dpp::dashcore::QuorumHash; use dpp::platform_value::Bytes32; +#[derive(Debug, Clone, Encode, Decode)] +pub struct SignatureVerificationQuorumSetForSavingV1 { + config: QuorumConfigForSavingV0, + current_quorums: Vec, + #[cfg(feature = "bls-signatures")] + previous_quorums: Option, +} + +impl From for SignatureVerificationQuorumSetForSaving { + fn from(value: SignatureVerificationQuorumSetForSavingV1) -> Self { + SignatureVerificationQuorumSetForSaving::V1(value) + } +} + +impl From for SignatureVerificationQuorumSetForSavingV1 { + fn from(value: SignatureVerificationQuorumSetV0) -> Self { + #[allow(unused_variables)] + let SignatureVerificationQuorumSetV0 { + config, + current_quorums, + previous, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + #[cfg(feature = "bls-signatures")] + previous_quorums: previous.map(|previous| previous.into()), + } + } +} + +impl From for SignatureVerificationQuorumSetV0 { + fn from(value: SignatureVerificationQuorumSetForSavingV1) -> Self { + let SignatureVerificationQuorumSetForSavingV1 { + config, + current_quorums, + #[cfg(feature = "bls-signatures")] + previous_quorums, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + #[cfg(feature = "bls-signatures")] + previous: previous_quorums.map(|previous| previous.into()), + #[cfg(not(feature = "bls-signatures"))] + previous: None, + } + } +} + #[derive(Debug, Clone, Encode, Decode)] pub struct QuorumForSavingV1 { hash: Bytes32, diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs index 27cc8c656ef..60f0b4d7b9a 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v2.rs @@ -7,6 +7,10 @@ use crate::platform_types::signature_verification_quorum_set::{ }; use bincode::{Decode, Encode}; +// We needed to introduce this V2 because the PreviousPastQuorumsForSavingV1 were using a QuorumForSavingV0 +// This was an oversight in SignatureVerificationQuorumSetForSavingV1. +// This would cause the previous quorums to still use the old BLS sigs library for serialization/deserialization. + #[derive(Debug, Clone, Encode, Decode)] pub struct SignatureVerificationQuorumSetForSavingV2 { config: QuorumConfigForSavingV0, diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs index 52748e5f21d..bc4511bd4cf 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs @@ -1,3 +1,4 @@ +pub mod for_saving_v0; pub mod for_saving_v1; pub mod for_saving_v2; pub mod quorum_config_for_saving_v0; diff --git a/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs b/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs deleted file mode 100644 index b5441903cb1..00000000000 --- a/packages/rs-drive-abci/src/platform_types/unsupported_legacy_bls_storage.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Rejection of database formats that require an intermediate Platform upgrade. - -use bincode::de::Decoder; -use bincode::enc::Encoder; -use bincode::error::{DecodeError, EncodeError}; -use bincode::{Decode, Encode}; - -/// Uninhabited payload reserving a legacy enum tag without accepting its data. -/// -/// Keeping the variant slot preserves the tags of supported storage formats. -#[derive(Clone, Debug)] -pub enum UnsupportedLegacyBlsStorage {} - -impl Encode for UnsupportedLegacyBlsStorage { - fn encode(&self, _encoder: &mut E) -> Result<(), EncodeError> { - match *self {} - } -} - -impl Decode for UnsupportedLegacyBlsStorage { - fn decode>(_decoder: &mut D) -> Result { - Err(DecodeError::Other( - "Unsupported legacy BLS state format. Run Platform v4.0.0 on this database and let it successfully commit at least one block before upgrading.", - )) - } -} - -bincode::impl_borrow_decode!(UnsupportedLegacyBlsStorage); diff --git a/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex b/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex deleted file mode 100644 index 194d7ad1c7a..00000000000 --- a/packages/rs-drive-abci/src/test/fixture/platform_state_supported.hex +++ /dev/null @@ -1 +0,0 @@ -01000100fd00000196679379cde0fb4cf8335c28e2d5b81fe8563beff647c4a74bac7165d84276eb62dc46fd2cc6bfe53f6b00000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8741533fd4861a2205ac950c9f39bfcb92d75c30010cc6e83d23eee89792132cf78ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e51104418388bcb4a1798aebc9b25e3d444ff15e4b272c4ee5dbf51309147db28421f49a736a6fb0260ea8b075f8309331caed3f99b193410cee745b02ad9b93d16c22cc7bfac642917c93c288e2a1977f325fb0b76cc6c22447d363c43a20bb89c89d3253300080800000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8740004000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d900000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d900fb4ce00a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601b7536c30ebb2297379cce4e832c5c88828dba988b1b339ba403621a67cc26325baf14d809cbd4b30ef07c783a45749130d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001b6aa2516aa6e47c9824efc13422cccc45a73fbe0bab83334fc31122f99c2e6fc37f667928c20176702284a4211393f4e0d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1601a1f07095b3171384f7d7cd23d766cb5ef32cf1bc3808eb5dd6cbc4c910ee0e51d11f47f2673db173c166749f5c61f4790d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5101846f0ab803a4569eae1a616443456bf498f0493b9d32c919a59d6bb722bcd2200077e9439d9fb621d9f966bef1009bde0d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301b117767d537e5c34c7c459a76b97af529a1255e0bf2c61ea96316c347f2c13abf6755e52ae2e8ae41a41414617ed6afd0c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801abac813a50f33c5e2c53284e880a47b831c3683a63686991146f473ec129e324a80492f1bde63986f0564304e5bd36b30d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01ab9ecac6c4edbb91ec9b91347b3f0cdd9872c8278432f3f7550d3812f5b82afe7e1701984edd53b0b84f59fe56ebd66a0d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945018be3cda106e64ec22ab90dff0b9aebf399f64925ec460896683df9ebfe77a767315ceeb51a395fac87a3cecfd0d9f2580e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb01a342022a1ff0f2e8a9b42f0d031d3704fa89a6dc85e8bf31e88266f4dbcbc2d1f9255913b5dd51d7f96fc25b04af53100b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a01a612b7515f24806d24b34176383f3d73ac673eae61142860c2ceed761f8f1435d988f64a33d0fb9a529e870c68dd50990d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f3000ae243894aa11a2c9f1bb0464499864376b85c773c8ff5a7f5d57bfee2977459db996ce325d9bc4996582baa0f96b59b60000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce00fb4cc80a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab506018ebacd1b1061d80715fe840a199b6635830ad7abc379e1af869998c1b91257b4819935f1796d1c6bc86c79f263a64c430d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001ab5a092f14f019e1ae79ec037ebe88d3501139a82736521b2aabca4f078f934bbf9d136383c2386ce5739f6f9a5f9d490d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b16018aaabc36b1e2f42664abec989208b9821650b704323cb8d66be00095954a1d20194ef23c33c839e760f03f0ac0bcca350d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5101aa6bf2536b37af83b6e88a50b35216aebcf2e433758d419e150e00d19caf6ca6fcffa234d49c86a2905e400f41d5a3a50d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301aadc92e09655108cc8736b055e5abf288e060b06de527a4f6fc5b65516037e555ca0b9944c65ea678dc59348d6e138e70c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801b919077a4108af14570de90782408632b048b528df100076077598a8555758d656cae0fd3ec132b1fd113e18d3b623d50d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01a7553852f9a1692b7696cb063e49e173ca655b80e1fa95d8e03926dabb0a16f1ca4e7d7f32666e838d53d228e80bf5390d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945018babe479bf760cd34be2b57e088e9756d3eac5e92f5e978b5abdf3e8a4d3ea5f4bb93e3c5e6227d1c9174fd7e38ad5140e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb01b7be15daa0d2513874b47d5d4283563969a933bb473e21222c63271dfae2ddd560df3806172b9b897926b214542b73a40b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a0193d0baee082057cc2e7a17bf6cad8d3df0e4fc5438de2027ea77bb20a7910862ecc145b4631bcd58e39fd62a19e2ea150d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f30008028075a0cca9efbc93a7c50b3c670ed90c129b64705f1c3c2ccedc811ff5844ed6f1e34601a13a2b59bc94329b74606000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796800000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796800fb4cb00a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601aaac3862eed7b02ba53f7a019047849d5b492ec41c8f5541e4b81811ae989d703c200ca058226e9e78f081e07f0742b20d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001b57396d68a27a823604af7404e7fa28e9d0a559b42e94464eee8ee322a0f5b017d50827c0a460adb57d98555ac5d31ac0d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1601b45e2079572eea6d7890f5199ceef69fc7e71a353fa919a8a58a44b3aab65926b60fc10cfcb62b85b4f422f49d3e92e90d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc51018a47a2fe45a808aea52b26adfe15d75fa422762d9a8615bc8cdd9987c68e2b84bc06bbff4378f639f3aa57133a1aa81a0d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301aadf1764b8f7f60788cc90d95f0403b249acce9ee6e4bb31c90061d9dd5cfe32812b64249ec0b017bcf67f30e44c3bc50c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e51104418380185b29d05607cf79e2dbeff52d40751a30a2f1bd8fd63508b2c45ff75577f6f3f3c92951069690a8b4976ece9fedc966b0d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01a8e81b88af2eefb6ab3b39652a651a4ea57e0c82eedb90908769716ecd9928fe825fdd142c4938e7049dc31c43bda2e70d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194501ab750eb8ce4e3cb196dac1890bae03e6a1cdf9bf0b70a63ea6ca64f7ee1946b8fe02b8362290765cb9ffeda0e5088a0b0e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb019031840125574c094554c02649a65b9dec67285d6e0f89ebbae56b55eedd5393757bb81a4fec886422d8e3ac485dc2740b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a018f922fdc28078e252b6e221b3ccaa6f3451885b4413e7a21b4a7850eb924122cbed5fb366af8485bd1d8d67f185232d60d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f3000b887b3dbc961b87e02fd7e16929fe771133d6c76fa1faebb35c2b1da15d32292a314b477f60f4c6d02b46110c0ef6eec00000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8740000000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f87400fb4c980a2001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50601a4037c6dc40a494e120de11721a221e876b75fd099c852bb1b44a2ba882bc4c25a0998d60e56ca29983abe918f15a2ad0d35342e3230322e3233312e32309eb3c89309106d441cc1749640ab5613046f6ad0fb4e21fb05a3fb8f300020122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08001a12ace1e26c8ce82f2e736b26653f64a477ec58de0f964b8e79b67aea72b70c4c46d0e8c48a77b83fbde7d4e5b6b00910d31382e3234362e3232372e3231a7822db397ca4e35b81d016ce52bdbaae74880abfb4e21fb05a3fb8f3000204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b164838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160181d6653d0930d0c17ae170c3a492abaed7790a43b064258684e520e47e8627c0e7f331fdb14cf8a303c6f472d8240c3b0d34342e3234372e3136302e3532c6e2f8c23c3b847ae4b8f0c452408f843fe3afa6fb4e21fb05a3fb8f3000204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc514c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc51019209cfef89be975385818843303544dbbdbe5e71fb035de048aa870972d83b0a2822ef1dc28f02f1e1d94e9e50a091790d35342e3231342e37372e313038cca358aba0b27446e73f6cbc372d549de4039d43fb4e21fb05a3fb8f300020aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc301b64f956fed0ea351b56e6271d9da59e5b053cc5b707ef057fc165ad23176e6bf5160bab2d8f5ad1abd45ac508856b8d40c33352e38392e3234362e383620499e02a93241d54692c96b4ef147e46b123275fb4e21fb05a3fb8f300020ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183801a98cd5f09273c6a038b6a29af2eaff1570e62e03b25bbb6ba21354a01b96cfca07dca4ae4b3ae5496a4d62d63c1ec7cc0d34342e3234352e39362e313634acc20a8324d0b1f914a4ffe605d488f21a026cd6fb4e21fb05a3fb8f300020c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fbc254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb01acd8ed44c9de6126a9b683b915c85ec85ee67983603bba65f5427fbcf62d5460a89a91d03dbabb4b041d0585fa8a99200d35342e3230332e3131362e3931f77c894ac83526befcc07157a82e52cc2b1697f1fb4e21fb05a3fb8f300020d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194501aab6f5e05fb6544513c6af9624c6d18b8dcca7eee3356d61631d718931630075811af66ed540b43baeab4b3a8339becc0e33342e3232322e3231342e3137301e8d732727fff4006299e0b23d5d724fb0e688b3fb4e21fb05a3fb8f300020ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408ebed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb0185187e5ec226e3aa03eb2f6e157f042ef8e0aa444c80f018664956c895e45a894dcea801ed3f3acafe78be22051801600b35322e38382e31362e3436da8a388088177826d85d98d2518a7a42bf04663ffb4e21fb05a3fb8f300020f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1af7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a018d0b0344f40beddbd946ae247a5617e3329894d88e84f94a56990a2af72d3ff67d05b86f8ec6145ff65578aae1d9a1730d35322e34302e3138362e323334a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b4fb4e21fb05a3fb8f30008cf580fb386270abfc216e3beb47d028c5c49dac56d706b2797ee9fb65322a680bb632a2a81191dfdea453569adf049e02070400180400000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8748c786a8a62110a49cf5032723429517beff088867f048c5ff795d394322aa5ae0d51f87fad5f5a3e7864aee139aef68a000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce84b18ace26a0084f94122e5b88c24a16d678efdb36ecec9088c81dc572ced080a8ebc5c2e35f80b48ffe5efab68890b600000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d98b5be5697a66e7fc3b1e0fb0e247f2be6f68096888b578ca1c35761a057e2ff9fc308d692c115f3cf252cea1423f2d1e00000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796893fba22ce69238d34733636602fc26e1b841da63dd37cc0af69efb1ba815cfcb3a7a5be870db4d2f1a940dc3ad407f7a00010400000299b14717769ec09ccd478a1f3c5f27ba04e6c5fe67b5c26d96ba54f8748c786a8a62110a49cf5032723429517beff088867f048c5ff795d394322aa5ae0d51f87fad5f5a3e7864aee139aef68a00000003e208609aa86a58da32e5465fa6ae8ee72d2e2b3936f2d8cfafd52f058193c47178fa64592f11a32f7718bd518d90b3c847c7b8fa4bca6addaece93581dab9a3429ec2c7c7347ce920e88979e56000000041ad2e1652e70ca1db2e3bcb39a5271b4862c4e2aa3197eafba20ec02ce84b18ace26a0084f94122e5b88c24a16d678efdb36ecec9088c81dc572ced080a8ebc5c2e35f80b48ffe5efab68890b600000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad6796893fba22ce69238d34733636602fc26e1b841da63dd37cc0af69efb1ba815cfcb3a7a5be870db4d2f1a940dc3ad407f7a00fb4ceafb4ceb01fb4cd4020b020130020000057d6aec5a186ff690e13b41e10c938d06c9ba25046836c740549b0e3969b8faca3e409109d3549187247ab50bfe5843545c3064ef953653f52f5a0ddefb4b91325812def3cc26808067624327890101000005c2a084bd68f4c908dfd772db63462a1a26be397eb1ad018bb9199cb8d9aac58025b9e50077a3edfe1aaab170fcdb6b15b3a500212460265cb756ea33cba57ca432916bca4c4ef72b1b172600c20100010200000074d7b31cf77817c30df933d80fa6e354b6582c29ef416799a508631039a8dc97e32336fe44d357d4936d196f08731328f15758cd7760fe584862869944556826905742737e3da542d782e57acb0101000017fd360e19c0346ceb923e43c1fc601153ba921ad0186320347d6ad67968b7f439f6c82070bd8a73313e98d228b9f11b1c0232a1b9733580155bfbd27a3c399ecc5babdd4a6cf2908a836ccba2720100fb4cebfb4cec01fb4cbe0a01e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50600012001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790356e79d2b2b0ac0761f6a4526b7d047d74e28f546000000000036cae714fb4e21fb101900000058127be0d801051a163bf0353cc5bb9defd2f57358127be0d801051a163bf0353cc5bb9defd2f573a986f69f8d9d9a073287487365e0c31a1a6ec33d30b104db07b513ef45b0da4c1379599b7c5981860fa588d7968cbc0408a1cc729fcb64b2c7586c9719caa7d33ddaccf42900019eb3c89309106d441cc1749640ab5613046f6ad001fb8f3001fb05a3122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080000120122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08020a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107906903790983928ee282b9644cbf9c8e6cee72efe90000000000012f6e315fb4e21fb10190000009b482e4b8f5da7583a15fc887928e6c404e17f9b9b482e4b8f5da7583a15fc887928e6c404e17f9ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b5c57edb1258f5c1cfdb21b6680de011ddeea93e797e5f597dedd0abb85eea27bf862ff95528ed80c9cb0bae3a2715fa0001a7822db397ca4e35b81d016ce52bdbaae74880ab01fb8f3001fb05a34838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160001204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079079150fb7c07cdbac70f458cd23487e212760de68500000000002cf7a034fb4e21fb1019000000579ecdebf8c2a3f347c301cd56f8d25a60821ebd579ecdebf8c2a3f347c301cd56f8d25a60821ebda986f69f8d9d9a073287487365e0c31a1a6ec33d30b455073ebdd660759753d3158e0af7038620bc484d5b206cc76cd517ccd4aaedff0a967d3a2245ca12dd39eaec565dc10001c6e2f8c23c3b847ae4b8f0c452408f843fe3afa601fb8f3001fb05a34c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc510001204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5120a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790ad2e5173d4d1f2ddab7848de87288ef7fea4a5bc2000000000036d64d6cfb4e21fb101900000032d019c0a0521635e2c50baa0639afde38128ca032d019c0a0521635e2c50baa0639afde38128ca0a986f69f8d9d9a073287487365e0c31a1a6ec33d3085918a1ce01bed79b0f2f73b4b9cf3d3beb0d79508801139611d488cd5ecd7184f72c5489eb78330d5f43caebc9a0a110001cca358aba0b27446e73f6cbc372d549de4039d4301fb8f3001fb05a3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3000120aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc320a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079089a27487a58654bceeacfd3fb1a2cda28642ddb2700000000002359f656fb4e21fb1019000000a4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b343c9b538cc9694dbb8cf3ecc288875ec6e53175c72d557c2ac5fad08659084a83a9aeb670d6aa484f293de2d85af33000120499e02a93241d54692c96b4ef147e46b12327501fb8f3001fb05a3ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838000120ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183820a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079057ba786e269da8db182526a7dd051b5b5dc231fb500000000002cf560a4fb4e21fb101900000081b0121840d749be5f287a4117515f4d8f3fd65f81b0121840d749be5f287a4117515f4d8f3fd65fa986f69f8d9d9a073287487365e0c31a1a6ec33d30b03a8cb594e95d4d3e9d993e5a2df17ef5161fcf67560bd91fff3bbd5d4a4fe26082c6c37fac5a73491dc93e1900b4950001acc20a8324d0b1f914a4ffe605d488f21a026cd601fb8f3001fb05a3c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb000120c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107902493372ccd17dea09c98b8c35077387b21f8ad28d000000000036cb745bfb4e21fb1019000000fcd87a7892e645ebba5647bd9eebc25b34ddde70fcd87a7892e645ebba5647bd9eebc25b34ddde70a986f69f8d9d9a073287487365e0c31a1a6ec33d30a2cff2a27595a6bc79ce79c4f360713a35e20350ec106f20d01a90d1374ac0c5ef709ce968bcc0a7888340f5871805040001f77c894ac83526befcc07157a82e52cc2b1697f101fb8f3001fb05a3d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945000120d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194520a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107904645e20b1c5090f6f05b601eec64d6c17cd88094a000000000022ded6aafb4e21fb1019000000d6cdf6df678342ca7e9d906e354dd9355445cb80d6cdf6df678342ca7e9d906e354dd9355445cb80a986f69f8d9d9a073287487365e0c31a1a6ec33d308c89302e7919585c6c9870d5ec60e89abe15bdc62e8043a7db8d47ecb15535711b290547a2a314cf6f1d931c62a8214300011e8d732727fff4006299e0b23d5d724fb0e688b301fb8f3001fb05a3ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb000120ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107909a18bfec024e4f56a56e3efee94d5b541a627b31c00000000003458102efb4e21fb10190000002cef49cf84da8e7fae2059188b7c4f3df078f4e22cef49cf84da8e7fae2059188b7c4f3df078f4e2a986f69f8d9d9a073287487365e0c31a1a6ec33d308144775a433e210fd111aa673239c996226c99555bb9aa4f96741ec57b78db0aaa69100f9f3fdfa9e90bcd0d3b25f59d0001da8a388088177826d85d98d2518a7a42bf04663f01fb8f3001fb05a3f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a000120f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079011fc39eaccf31144a236ca22c780d64a3b317b77d00000000003428baeafb4e21fb10190000000381536671c212e9666e5fb5d4a29fe0948773900381536671c212e9666e5fb5d4a29fe094877390a986f69f8d9d9a073287487365e0c31a1a6ec33d30b0ea9db0fa7191c90fbc55dcd984630f9a2892d3250add2ab807132845122644ad888ad2276d59600efdfaf2f4fbf9000001a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b401fb8f3001fb05a30a01e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50600012001e1f3c05fd243c23711ec8d9a220f4f0a6e757e06df7c8f80d32e110beab50620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790356e79d2b2b0ac0761f6a4526b7d047d74e28f546000000000036cae714fb4e21fb101900000058127be0d801051a163bf0353cc5bb9defd2f57358127be0d801051a163bf0353cc5bb9defd2f573a986f69f8d9d9a073287487365e0c31a1a6ec33d30b104db07b513ef45b0da4c1379599b7c5981860fa588d7968cbc0408a1cc729fcb64b2c7586c9719caa7d33ddaccf42900019eb3c89309106d441cc1749640ab5613046f6ad001fb8f3001fb05a3122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b080000120122be582d024c032d83575f04453b794fd7aaefef926cfc2664baa23c612b08020a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107906903790983928ee282b9644cbf9c8e6cee72efe90000000000012f6e315fb4e21fb10190000009b482e4b8f5da7583a15fc887928e6c404e17f9b9b482e4b8f5da7583a15fc887928e6c404e17f9ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b5c57edb1258f5c1cfdb21b6680de011ddeea93e797e5f597dedd0abb85eea27bf862ff95528ed80c9cb0bae3a2715fa0001a7822db397ca4e35b81d016ce52bdbaae74880ab01fb8f3001fb05a34838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b160001204838bb71ef5136100dbf35ee184370fe1e42d5d7b41fbcdd0652bbad7a705b1620a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079079150fb7c07cdbac70f458cd23487e212760de68500000000002cf7a034fb4e21fb1019000000579ecdebf8c2a3f347c301cd56f8d25a60821ebd579ecdebf8c2a3f347c301cd56f8d25a60821ebda986f69f8d9d9a073287487365e0c31a1a6ec33d30b455073ebdd660759753d3158e0af7038620bc484d5b206cc76cd517ccd4aaedff0a967d3a2245ca12dd39eaec565dc10001c6e2f8c23c3b847ae4b8f0c452408f843fe3afa601fb8f3001fb05a34c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc510001204c51cd612d4a8e94a5952037ebae6871c8ab623b01b8cd16c2aa9c814b78bc5120a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca10790ad2e5173d4d1f2ddab7848de87288ef7fea4a5bc2000000000036d64d6cfb4e21fb101900000032d019c0a0521635e2c50baa0639afde38128ca032d019c0a0521635e2c50baa0639afde38128ca0a986f69f8d9d9a073287487365e0c31a1a6ec33d3085918a1ce01bed79b0f2f73b4b9cf3d3beb0d79508801139611d488cd5ecd7184f72c5489eb78330d5f43caebc9a0a110001cca358aba0b27446e73f6cbc372d549de4039d4301fb8f3001fb05a3aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc3000120aa3577bdeb9a8e7b7ab09e3a1b3e2dd90444b17d9c4776f63aa540e1e1437bc320a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079089a27487a58654bceeacfd3fb1a2cda28642ddb2700000000002359f656fb4e21fb1019000000a4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba4639a40da95a2eca6bd0b821de9d45e6b4a2b2ba986f69f8d9d9a073287487365e0c31a1a6ec33d30b343c9b538cc9694dbb8cf3ecc288875ec6e53175c72d557c2ac5fad08659084a83a9aeb670d6aa484f293de2d85af33000120499e02a93241d54692c96b4ef147e46b12327501fb8f3001fb05a3ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e5110441838000120ba63e68b75a038508dccb221901b391a14737d9ae68beff0afb11e511044183820a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079057ba786e269da8db182526a7dd051b5b5dc231fb500000000002cf560a4fb4e21fb101900000081b0121840d749be5f287a4117515f4d8f3fd65f81b0121840d749be5f287a4117515f4d8f3fd65fa986f69f8d9d9a073287487365e0c31a1a6ec33d30b03a8cb594e95d4d3e9d993e5a2df17ef5161fcf67560bd91fff3bbd5d4a4fe26082c6c37fac5a73491dc93e1900b4950001acc20a8324d0b1f914a4ffe605d488f21a026cd601fb8f3001fb05a3c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb000120c254079a24a9041590b9a3fa01ad41dcccaaae8a0397e71497ceafd7a9b9b6fb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107902493372ccd17dea09c98b8c35077387b21f8ad28d000000000036cb745bfb4e21fb1019000000fcd87a7892e645ebba5647bd9eebc25b34ddde70fcd87a7892e645ebba5647bd9eebc25b34ddde70a986f69f8d9d9a073287487365e0c31a1a6ec33d30a2cff2a27595a6bc79ce79c4f360713a35e20350ec106f20d01a90d1374ac0c5ef709ce968bcc0a7888340f5871805040001f77c894ac83526befcc07157a82e52cc2b1697f101fb8f3001fb05a3d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc3771945000120d7f774f9156c2de6102f0e920b92ca04b02af8491ae8168634aa783dc377194520a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107904645e20b1c5090f6f05b601eec64d6c17cd88094a000000000022ded6aafb4e21fb1019000000d6cdf6df678342ca7e9d906e354dd9355445cb80d6cdf6df678342ca7e9d906e354dd9355445cb80a986f69f8d9d9a073287487365e0c31a1a6ec33d308c89302e7919585c6c9870d5ec60e89abe15bdc62e8043a7db8d47ecb15535711b290547a2a314cf6f1d931c62a8214300011e8d732727fff4006299e0b23d5d724fb0e688b301fb8f3001fb05a3ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb000120ed6b98d27580f4c7659889ff1e8a4490486b4d980caa2180693fbb76aa9408eb20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca107909a18bfec024e4f56a56e3efee94d5b541a627b31c00000000003458102efb4e21fb10190000002cef49cf84da8e7fae2059188b7c4f3df078f4e22cef49cf84da8e7fae2059188b7c4f3df078f4e2a986f69f8d9d9a073287487365e0c31a1a6ec33d308144775a433e210fd111aa673239c996226c99555bb9aa4f96741ec57b78db0aaa69100f9f3fdfa9e90bcd0d3b25f59d0001da8a388088177826d85d98d2518a7a42bf04663f01fb8f3001fb05a3f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a000120f7f8eaf6e911b3dc815b257465f4473a80ad70fe63bb6722c389ce286fc2ed1a20a425162eaa80ebcd6932b83d69ae21be306addaafa7cbf8a9f89722265ca1079011fc39eaccf31144a236ca22c780d64a3b317b77d00000000003428baeafb4e21fb10190000000381536671c212e9666e5fb5d4a29fe0948773900381536671c212e9666e5fb5d4a29fe094877390a986f69f8d9d9a073287487365e0c31a1a6ec33d30b0ea9db0fa7191c90fbc55dcd984630f9a2892d3250add2ab807132845122644ad888ad2276d59600efdfaf2f4fbf9000001a3f4164595cffe3fb0e79c3cf06a4ea1d5d474b401fb8f3001fb05a3013201 From 8ec53c19757189cd3c6e9e8714386ff575f0bd6d Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 12:45:57 +0000 Subject: [PATCH 09/11] perf(dpp): retain validated BLS points for verification Cover DPP legacy-key conversion with frozen vectors and preserve infinity rejection across basic and aggregate verification. Document the Rust API migration in the changelog. Co-Authored-By: Codex --- CHANGELOG.md | 11 ++ packages/rs-dpp/src/bls/bls_signatures.rs | 113 +++++++++++---------- packages/rs-dpp/tests/bls_compatibility.rs | 37 +++++++ 3 files changed, 105 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95020ebedad..78acb562cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [Unreleased] + +### Changed + +- **dpp (Rust API migration):** BLS types now live under `dpp::bls::{PublicKey, + SecretKey, Signature, BlsError}`; the generic `dpp::bls_signatures` re-export + is removed. Use `PublicKey::to_bytes()`, `SecretKey::from_be_bytes()` returning + `Option`, and Basic `sign(message)` / `Signature::from_compressed()`. The + `serialization::dashcore::bls_pubkey` Serde adapter remains a deprecated alias. + Serialized encodings and consensus rules are unchanged. See [#5320](https://github.com/dashpay/platform/pull/5320). + ## [5.0.0-beta.2](https://github.com/dashpay/platform/compare/v5.0.0-beta.1...v5.0.0-beta.2) (2026-10-06) diff --git a/packages/rs-dpp/src/bls/bls_signatures.rs b/packages/rs-dpp/src/bls/bls_signatures.rs index c3e4f9f2890..8ee4b8db475 100644 --- a/packages/rs-dpp/src/bls/bls_signatures.rs +++ b/packages/rs-dpp/src/bls/bls_signatures.rs @@ -25,35 +25,30 @@ pub enum BlsError { DeserializationError(String), } -/// A compressed G1 key, including the identity permitted by historical Platform parsing. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PublicKey([u8; 48]); +/// A validated G1 key, including the identity permitted by historical Platform parsing. +#[derive(Clone, Copy, Default, Eq, PartialEq)] +pub struct PublicKey(Option>); impl PublicKey { /// Return the canonical compressed IETF encoding. pub fn to_bytes(&self) -> [u8; 48] { self.0 + .as_ref() + .map_or_else(infinity, BlsPublicKey::to_bytes) } /// Re-encode a public key for Core's legacy wire format. pub fn to_legacy_bytes(&self) -> Result<[u8; 48], BlsError> { - if self.0 == infinity() { + let Some(key) = &self.0 else { return Ok(infinity()); - } - self.validated()? - .to_scheme::() + }; + key.to_scheme::() .map(|key| key.to_bytes()) .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into())) } - fn validated(&self) -> Result, BlsError> { - BlsPublicKey::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature) - } -} - -impl Default for PublicKey { - fn default() -> Self { - Self(infinity()) + fn validated(&self) -> Result<&BlsPublicKey, BlsError> { + self.0.as_ref().ok_or(BlsError::InvalidSignature) } } @@ -71,17 +66,18 @@ impl TryFrom<&[u8]> for PublicKey { BlsError::InvalidInputs(format!("Invalid length, expected 48, got {}", value.len())) })?; // Persisted state and shipped validation accept canonical infinity, but verification rejects it. - if bytes != infinity() { - BlsPublicKey::::from_bytes(&bytes) - .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into()))?; + if bytes == infinity() { + return Ok(Self(None)); } - Ok(Self(bytes)) + BlsPublicKey::from_bytes(&bytes) + .map(|key| Self(Some(key))) + .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into())) } } impl fmt::Display for PublicKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&hex::encode(self.0)) + f.write_str(&hex::encode(self.to_bytes())) } } @@ -126,37 +122,52 @@ impl SecretKey { /// Derive the corresponding public key. pub fn public_key(&self) -> PublicKey { - PublicKey(self.0.public_key().to_bytes()) + PublicKey(Some(self.0.public_key())) } /// Sign arbitrary message bytes with the Basic IETF domain separation tag. pub fn sign(&self, message: &[u8]) -> Result { - Ok(Signature(self.0.sign(message).to_bytes())) + Ok(Signature::from_validated(self.0.sign(message))) } } -/// A compressed G2 Basic signature. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Signature([u8; 96]); +/// A validated G2 Basic signature, with canonical infinity represented separately. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Signature(Option>); + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Signature").field(&self.to_bytes()).finish() + } +} impl fmt::Display for Signature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&hex::encode(self.0)) + f.write_str(&hex::encode(self.to_bytes())) } } impl Signature { /// Decode a subgroup point, including the identity rejected during verification. pub fn from_compressed(bytes: &[u8; 96]) -> Option { - if *bytes != infinity() { - BlsSignature::::from_bytes(bytes).ok()?; + if *bytes == infinity() { + return Some(Self(None)); } - Some(Self(*bytes)) + BlsSignature::from_bytes(bytes) + .ok() + .map(|signature| Self(Some(signature))) + } + + fn from_validated(signature: BlsSignature) -> Self { + // Aggregation can produce infinity; keep its historical parsing and verification policy. + Self((signature.to_bytes() != infinity()).then_some(signature)) } /// Return the compressed IETF encoding without a scheme tag. pub fn to_bytes(&self) -> [u8; 96] { self.0 + .as_ref() + .map_or_else(infinity, BlsSignature::to_bytes) } /// Verify a Basic signature over arbitrary message bytes. @@ -165,20 +176,15 @@ impl Signature { public_key: &PublicKey, message: impl AsRef<[u8]>, ) -> Result<(), BlsError> { - if self.0 == infinity() { - return Err(BlsError::InvalidInputs( - "signature is the identity point".into(), - )); - } - if public_key.0 == infinity() { - return Err(BlsError::InvalidInputs( - "public key is the identity point".into(), - )); - } - let key = public_key.validated()?; - let signature = - BlsSignature::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature)?; - key.verify(message.as_ref(), &signature) + let signature = self + .0 + .as_ref() + .ok_or_else(|| BlsError::InvalidInputs("signature is the identity point".into()))?; + let key = public_key + .0 + .as_ref() + .ok_or_else(|| BlsError::InvalidInputs("public key is the identity point".into()))?; + key.verify(message.as_ref(), signature) .map_err(|_| BlsError::InvalidSignature) } @@ -187,21 +193,17 @@ impl Signature { signatures: &[Self], public_keys: &[PublicKey], ) -> Result { - let signatures: Result, _> = signatures + let signatures: Vec<_> = signatures .iter() - .map(|sig| BlsSignature::::from_bytes(&sig.0)) - .collect(); - let signatures = signatures.map_err(|_| BlsError::InvalidSignature)?; + .map(|sig| sig.0.as_ref().ok_or(BlsError::InvalidSignature)) + .collect::>()?; let keys: Vec<_> = public_keys .iter() .map(PublicKey::validated) .collect::>()?; - BlsSignature::secure_aggregate( - &signatures.iter().collect::>(), - &keys.iter().collect::>(), - ) - .map(|signature| Self(signature.to_bytes())) - .map_err(|_| BlsError::InvalidSignature) + BlsSignature::secure_aggregate(&signatures, &keys) + .map(Self::from_validated) + .map_err(|_| BlsError::InvalidSignature) } /// Verify a secure aggregate over a common message. @@ -214,10 +216,9 @@ impl Signature { .iter() .map(PublicKey::validated) .collect::>()?; - let signature = - BlsSignature::from_bytes(&self.0).map_err(|_| BlsError::InvalidSignature)?; + let signature = self.0.as_ref().ok_or(BlsError::InvalidSignature)?; signature - .secure_verify_aggregates(message.as_ref(), &keys.iter().collect::>()) + .secure_verify_aggregates(message.as_ref(), &keys) .map_err(|_| BlsError::InvalidSignature) } } diff --git a/packages/rs-dpp/tests/bls_compatibility.rs b/packages/rs-dpp/tests/bls_compatibility.rs index 651c3b37374..c14ff906f7b 100644 --- a/packages/rs-dpp/tests/bls_compatibility.rs +++ b/packages/rs-dpp/tests/bls_compatibility.rs @@ -105,6 +105,21 @@ fn should_match_frozen_basic_signatures_in_both_backends() { assert_eq!(candidate.sign(&message).to_bytes(), signature); let decoded = BlsSignature::::from_bytes(&signature).unwrap(); assert!(candidate.public_key().verify(&message, &decoded).is_ok()); + assert_eq!( + PublicKey::try_from(public.as_slice()) + .unwrap() + .to_legacy_bytes() + .unwrap(), + bytes::<48>(&v.legacy_public_key) + ); + assert_eq!( + SecretKey::from_be_bytes(&secret) + .unwrap() + .public_key() + .to_legacy_bytes() + .unwrap(), + bytes::<48>(&v.legacy_public_key) + ); assert_eq!( candidate .public_key() @@ -242,6 +257,28 @@ fn should_preserve_identity_key_parsing_without_accepting_identity_signatures() assert!(!NativeBlsModule .verify_signature(&signature, b"identity", &valid) .unwrap()); + + let identity_key = PublicKey::try_from(public_key.as_slice()).unwrap(); + let identity_signature = Signature::from_compressed(&signature).unwrap(); + assert_eq!(identity_key, PublicKey::default()); + assert_eq!(identity_key.to_bytes(), public_key); + assert_eq!(identity_key.to_legacy_bytes().unwrap(), public_key); + assert_eq!(identity_signature.to_bytes(), signature); + + let v = &corpus().basic[0]; + let message = hex::decode(&v.message).unwrap(); + let valid_key = PublicKey::try_from(valid.as_slice()).unwrap(); + let valid_signature = Signature::from_compressed(&bytes(&v.signature)).unwrap(); + assert!(valid_signature.verify(&identity_key, &message).is_err()); + assert!(identity_signature.verify(&valid_key, &message).is_err()); + assert!(valid_signature + .verify_secure(&[identity_key], &message) + .is_err()); + assert!(identity_signature + .verify_secure(&[valid_key], &message) + .is_err()); + assert!(Signature::aggregate_secure(&[identity_signature], &[valid_key]).is_err()); + assert!(Signature::aggregate_secure(&[valid_signature], &[identity_key]).is_err()); } #[test] From 1d729f939c74db70c83f2fd4d2a8ac3c8cf08808 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:09:34 +0000 Subject: [PATCH 10/11] refactor(dpp): name the private BLS public key states Keep PublicKey opaque while representing infinity and validated backend points with a private enum. Preserve encodings and validation behavior. Co-Authored-By: Codex --- packages/rs-dpp/src/bls/bls_signatures.rs | 38 +++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/rs-dpp/src/bls/bls_signatures.rs b/packages/rs-dpp/src/bls/bls_signatures.rs index 8ee4b8db475..a3f9d3bb2b6 100644 --- a/packages/rs-dpp/src/bls/bls_signatures.rs +++ b/packages/rs-dpp/src/bls/bls_signatures.rs @@ -27,19 +27,27 @@ pub enum BlsError { /// A validated G1 key, including the identity permitted by historical Platform parsing. #[derive(Clone, Copy, Default, Eq, PartialEq)] -pub struct PublicKey(Option>); +pub struct PublicKey(PublicKeyPoint); + +#[derive(Clone, Copy, Default, Eq, PartialEq)] +enum PublicKeyPoint { + #[default] + Infinity, + Validated(BlsPublicKey), +} impl PublicKey { /// Return the canonical compressed IETF encoding. pub fn to_bytes(&self) -> [u8; 48] { - self.0 - .as_ref() - .map_or_else(infinity, BlsPublicKey::to_bytes) + match &self.0 { + PublicKeyPoint::Infinity => infinity(), + PublicKeyPoint::Validated(key) => key.to_bytes(), + } } /// Re-encode a public key for Core's legacy wire format. pub fn to_legacy_bytes(&self) -> Result<[u8; 48], BlsError> { - let Some(key) = &self.0 else { + let PublicKeyPoint::Validated(key) = &self.0 else { return Ok(infinity()); }; key.to_scheme::() @@ -48,7 +56,10 @@ impl PublicKey { } fn validated(&self) -> Result<&BlsPublicKey, BlsError> { - self.0.as_ref().ok_or(BlsError::InvalidSignature) + match &self.0 { + PublicKeyPoint::Infinity => Err(BlsError::InvalidSignature), + PublicKeyPoint::Validated(key) => Ok(key), + } } } @@ -67,10 +78,10 @@ impl TryFrom<&[u8]> for PublicKey { })?; // Persisted state and shipped validation accept canonical infinity, but verification rejects it. if bytes == infinity() { - return Ok(Self(None)); + return Ok(Self(PublicKeyPoint::Infinity)); } BlsPublicKey::from_bytes(&bytes) - .map(|key| Self(Some(key))) + .map(|key| Self(PublicKeyPoint::Validated(key))) .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into())) } } @@ -122,7 +133,7 @@ impl SecretKey { /// Derive the corresponding public key. pub fn public_key(&self) -> PublicKey { - PublicKey(Some(self.0.public_key())) + PublicKey(PublicKeyPoint::Validated(self.0.public_key())) } /// Sign arbitrary message bytes with the Basic IETF domain separation tag. @@ -180,10 +191,11 @@ impl Signature { .0 .as_ref() .ok_or_else(|| BlsError::InvalidInputs("signature is the identity point".into()))?; - let key = public_key - .0 - .as_ref() - .ok_or_else(|| BlsError::InvalidInputs("public key is the identity point".into()))?; + let PublicKeyPoint::Validated(key) = &public_key.0 else { + return Err(BlsError::InvalidInputs( + "public key is the identity point".into(), + )); + }; key.verify(message.as_ref(), signature) .map_err(|_| BlsError::InvalidSignature) } From 0fabd55d91662adbc333881101a9e0a62e9d0a74 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:52:40 +0000 Subject: [PATCH 11/11] test(drive-abci): restore frozen historical V0 quorum storage Decode pre-migration V0 bytes through the production storage enum and verify current and previous quorum keys, hashes, indexes, configuration and heights. Include fixture provenance and a reproducible historical generator. Co-Authored-By: Codex --- .../v0/fixtures/README.md | 35 +++++++++ .../v0/fixtures/generate-quorum-storage-v0.rs | 60 +++++++++++++++ .../v0/fixtures/quorum-storage-v0.hex | 1 + .../v0/for_saving_v0.rs | 76 +++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/README.md create mode 100644 packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/generate-quorum-storage-v0.rs create mode 100644 packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/quorum-storage-v0.hex diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/README.md b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/README.md new file mode 100644 index 00000000000..858e0c7c19a --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/README.md @@ -0,0 +1,35 @@ +# Historical V0 quorum storage + +`quorum-storage-v0.hex` contains a synthetic, complete +`SignatureVerificationQuorumSetForSaving::V0` encoded by Platform commit +`7c73e983b4c3cd9b5e2ead34bbe0360646b7b4d9`, before the DPP BLS backend migration. +It uses `grovedb-bincode` with `standard().with_big_endian().with_no_limit()` +and the C++ `bls-signatures` public-key Serde implementation at revision +`0842b17583888e8f46c252a4ee84cdfd58e0546f`. + +The hex file (including its final newline) has SHA-256 +`8a2c8e59633ca1b126e3c0cc358a9347667d0f54068a874b1ae1435b85af830f` +and encodes 350 bytes. + +The four public keys come from DPP's frozen BLS compatibility vectors. Current +quorums have repeated-byte hashes `11` and `22`, with indexes `None` and `Some(0)`; +previous quorums have hashes `33` and `44`, with indexes `Some(1)` and `None`. +The previous-quorum heights are 1000 (last active), 1008 (updated), and +`Some(900)` (previous change). Configuration is `Llmq400_60`, four active signers, +no rotation, and a 288-block window. + +The test decodes the production storage enum and converts it to the runtime +quorum set, exercising the historical C++-to-DPP key conversion for both lists. +Expected keys and metadata are asserted independently of the current writer. + +To reproduce, copy `generate-quorum-storage-v0.rs` from this directory to +`packages/rs-drive-abci/examples/generate_quorum_storage_v0.rs` in a separate +checkout of the commit above, then run from that checkout: + +```sh +cargo run -p drive-abci --example generate_quorum_storage_v0 --all-features --locked -- /data/tmp/quorum-storage-v0.hex +``` + +Compare the generated file with the committed fixture. Do not regenerate the +expected bytes with the migrated backend. The generator explicitly selects V0; +the ordinary runtime-to-storage conversion writes V2. diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/generate-quorum-storage-v0.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/generate-quorum-storage-v0.rs new file mode 100644 index 00000000000..12d3f4574a4 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/generate-quorum-storage-v0.rs @@ -0,0 +1,60 @@ +//! Run as a drive-abci example at the pre-migration revision documented in README.md. + +use dpp::dashcore::hashes::Hash; +use dpp::dashcore::QuorumHash; +use dpp::dashcore_rpc::json::QuorumType; +use drive_abci::config::ChainLockConfig; +use drive_abci::platform_types::signature_verification_quorum_set::{ + Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, + SignatureVerificationQuorumSetV0Methods, VerificationQuorum, +}; + +const PUBLIC_KEYS: [&str; 4] = [ + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", +]; + +fn quorums(entries: &[(u8, usize, Option)]) -> Quorums { + entries + .iter() + .map(|&(hash, key, index)| { + ( + QuorumHash::from_byte_array([hash; 32]), + VerificationQuorum { + public_key: hex::decode(PUBLIC_KEYS[key]) + .unwrap() + .as_slice() + .try_into() + .unwrap(), + index, + }, + ) + }) + .collect() +} + +fn main() { + let mut runtime = SignatureVerificationQuorumSetV0::new(&ChainLockConfig { + quorum_type: QuorumType::Llmq400_60, + quorum_size: 400, + quorum_window: 288, + quorum_active_signers: 4, + quorum_rotation: false, + }); + runtime.set_current_quorums(quorums(&[(0x11, 0, None), (0x22, 1, Some(0))])); + runtime.set_previous_past_quorums(Quorums::default(), 899, 900); + runtime.set_previous_past_quorums(quorums(&[(0x33, 2, Some(1)), (0x44, 3, None)]), 1000, 1008); + // The normal runtime conversion writes V2; explicitly select the historical V0 writer. + let stored = SignatureVerificationQuorumSetForSaving::V0(runtime.into()); + let bytes = bincode::encode_to_vec( + stored, + bincode::config::standard() + .with_big_endian() + .with_no_limit(), + ) + .unwrap(); + let destination = std::env::args().nth(1).expect("fixture output path"); + std::fs::write(destination, format!("{}\n", hex::encode(bytes))).unwrap(); +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/quorum-storage-v0.hex b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/quorum-storage-v0.hex new file mode 100644 index 00000000000..2e9333f44e3 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/fixtures/quorum-storage-v0.hex @@ -0,0 +1 @@ +00010400fb01200211111111111111111111111111111111111111111111111111111111111111113097f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00222222222222222222222222222222222222222222222222222222222222222230a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e0100010233333333333333333333333333333333333333333333333333333333333333333095fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe480101444444444444444444444444444444444444444444444444444444444444444430b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00fb03e8fb03f001fb0384 diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs index 8c5345cc565..26867dee202 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v0.rs @@ -141,3 +141,79 @@ impl From> for Vec { .collect() } } + +#[cfg(all(test, feature = "bls-signatures"))] +mod tests { + use super::*; + use crate::platform_types::signature_verification_quorum_set::SignatureVerificationQuorumSet; + use dpp::dashcore_rpc::json::QuorumType; + + fn assert_quorum( + quorums: &Quorums, + hash: u8, + public_key: &str, + index: Option, + ) { + let quorum = quorums + .get(&QuorumHash::from_byte_array([hash; 32])) + .unwrap(); + assert_eq!( + quorum.public_key.to_bytes().as_slice(), + hex::decode(public_key).unwrap() + ); + assert_eq!(quorum.index, index); + } + + #[test] + fn should_restore_current_and_previous_quorums_from_frozen_v0_storage() { + let bytes = hex::decode(include_str!("fixtures/quorum-storage-v0.hex").trim()).unwrap(); + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + let (stored, consumed): (SignatureVerificationQuorumSetForSaving, _) = + bincode::decode_from_slice(&bytes, config).unwrap(); + assert_eq!(consumed, bytes.len()); + assert!(matches!( + stored, + SignatureVerificationQuorumSetForSaving::V0(_) + )); + assert_eq!(bincode::encode_to_vec(&stored, config).unwrap(), bytes); + + let SignatureVerificationQuorumSet::V0(restored) = stored.into(); + assert_eq!(restored.config.quorum_type, QuorumType::Llmq400_60); + assert_eq!(restored.config.active_signers, 4); + assert!(!restored.config.rotation); + assert_eq!(restored.config.window, 288); + assert_eq!(restored.current_quorums.len(), 2); + assert_quorum( + &restored.current_quorums, + 0x11, + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + None, + ); + assert_quorum( + &restored.current_quorums, + 0x22, + "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", + Some(0), + ); + + let previous = restored.previous.unwrap(); + assert_eq!(previous.last_active_core_height, 1000); + assert_eq!(previous.updated_at_core_height, 1008); + assert_eq!(previous.previous_change_height, Some(900)); + assert_eq!(previous.quorums.len(), 2); + assert_quorum( + &previous.quorums, + 0x33, + "95fde78acd5f6886ddaf5d0056610167c513d09c1c0efabbc7cdcc69beea113779c4a81e2d24daafc5387dbf6ac5fe48", + Some(1), + ); + assert_quorum( + &previous.quorums, + 0x44, + "b7f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + None, + ); + } +}