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/Cargo.lock b/Cargo.lock index e17e6ece13a..3393eccb4e1 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,12 +2273,12 @@ dependencies = [ "async-trait", "base64 0.22.1", "bech32 0.11.1", - "blsful", "bs58", "byteorder", "chrono", "chrono-tz", "ciborium", + "dash-pkc", "dash-spv", "dashcore", "dashcore-rpc", @@ -2380,6 +2325,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tracing", + "zeroize", ] [[package]] @@ -2605,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" @@ -3103,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]] @@ -3225,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", ] @@ -3604,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" @@ -3677,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", ] @@ -4166,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]] @@ -4451,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" @@ -4547,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]] @@ -4785,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" @@ -4963,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" @@ -5068,8 +4911,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.6", - "serde", ] [[package]] @@ -5085,8 +4926,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", - "rand 0.8.6", - "serde", ] [[package]] @@ -5135,7 +4974,6 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "serde", ] [[package]] @@ -5313,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 +5605,7 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", - "heapless 0.7.17", + "heapless", "serde", ] @@ -5906,7 +5735,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 +6085,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 +7003,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 +7083,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 +7307,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 +7468,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 +7511,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 +8528,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 +8713,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 1e74169571d..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" } @@ -117,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 new file mode 100644 index 00000000000..f137030b63a --- /dev/null +++ b/packages/rs-dpp/examples/generate_bls_compatibility_vectors.rs @@ -0,0 +1,138 @@ +//! Emit deterministic compatibility fixtures from DPP's current BLS backend. +//! Run with `cargo run -p dpp --example generate_bls_compatibility_vectors`. + +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}; +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_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]> = [ + "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(&message).unwrap(); + basic.push(json!({ + "secret_key": hex::encode(bytes), "message": hex::encode(message), + "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()) + })); + } + } + 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(message).unwrap()) + .collect(); + 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.to_bytes())).collect::>(), + "signature": hex::encode(point.to_bytes()) + })); + } + 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); + 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().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 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/src/bls/bls_signatures.rs b/packages/rs-dpp/src/bls/bls_signatures.rs new file mode 100644 index 00000000000..a3f9d3bb2b6 --- /dev/null +++ b/packages/rs-dpp/src/bls/bls_signatures.rs @@ -0,0 +1,236 @@ +//! 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 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 validated G1 key, including the identity permitted by historical Platform parsing. +#[derive(Clone, Copy, Default, Eq, PartialEq)] +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] { + 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 PublicKeyPoint::Validated(key) = &self.0 else { + return Ok(infinity()); + }; + key.to_scheme::() + .map(|key| key.to_bytes()) + .map_err(|_| BlsError::InvalidInputs("Invalid byte sequence".into())) + } + + fn validated(&self) -> Result<&BlsPublicKey, BlsError> { + match &self.0 { + PublicKeyPoint::Infinity => Err(BlsError::InvalidSignature), + PublicKeyPoint::Validated(key) => Ok(key), + } + } +} + +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() { + return Ok(Self(PublicKeyPoint::Infinity)); + } + BlsPublicKey::from_bytes(&bytes) + .map(|key| Self(PublicKeyPoint::Validated(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.to_bytes())) + } +} + +impl fmt::Debug for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// 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(PublicKeyPoint::Validated(self.0.public_key())) + } + + /// Sign arbitrary message bytes with the Basic IETF domain separation tag. + pub fn sign(&self, message: &[u8]) -> Result { + Ok(Signature::from_validated(self.0.sign(message))) + } +} + +/// 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.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() { + return Some(Self(None)); + } + 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. + pub fn verify( + &self, + public_key: &PublicKey, + message: impl AsRef<[u8]>, + ) -> Result<(), BlsError> { + let signature = self + .0 + .as_ref() + .ok_or_else(|| BlsError::InvalidInputs("signature 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) + } + + /// Aggregate signatures with deterministic public-key weights. + pub fn aggregate_secure( + signatures: &[Self], + public_keys: &[PublicKey], + ) -> Result { + let signatures: Vec<_> = signatures + .iter() + .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, &keys) + .map(Self::from_validated) + .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 = self.0.as_ref().ok_or(BlsError::InvalidSignature)?; + signature + .secure_verify_aggregates(message.as_ref(), &keys) + .map_err(|_| BlsError::InvalidSignature) + } +} diff --git a/packages/rs-dpp/src/bls/mod.rs b/packages/rs-dpp/src/bls/mod.rs index a5501f4634d..44b95b4a2bb 100644 --- a/packages/rs-dpp/src/bls/mod.rs +++ b/packages/rs-dpp/src/bls/mod.rs @@ -1,5 +1,12 @@ #[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; +/// 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/bls/native_bls.rs b/packages/rs-dpp/src/bls/native_bls.rs index 3e1341bf9ab..2bcd1dd4273 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::{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/serde.rs b/packages/rs-dpp/src/bls/serde.rs new file mode 100644 index 00000000000..205a1e71b8a --- /dev/null +++ b/packages/rs-dpp/src/bls/serde.rs @@ -0,0 +1,281 @@ +//! 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::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 { + if bytes.len() != COMPRESSED_G1_LEN { + return Err(E::custom(format!( + "expected {COMPRESSED_G1_LEN} compressed-G1 bytes for public key, got {}", + bytes.len() + ))); + } + 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; + + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "a {}-char hex string or {} compressed-G1 bytes", + COMPRESSED_G1_LEN * 2, + COMPRESSED_G1_LEN + ) + } + + 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 {}", + COMPRESSED_G1_LEN * 2, + s.len() + ))); + } + let mut bytes = [0u8; COMPRESSED_G1_LEN]; + for (i, slot) in bytes.iter_mut().enumerate() { + let hi = hex_nibble(s.as_bytes()[i * 2]).map_err(E::custom)?; + let lo = hex_nibble(s.as_bytes()[i * 2 + 1]).map_err(E::custom)?; + *slot = (hi << 4) | lo; + } + from_compressed_g1_bytes(&bytes) + } + + fn visit_bytes(self, v: &[u8]) -> Result { + from_compressed_g1_bytes(v) + } + + 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)); + } + bytes.push(b); + } + from_compressed_g1_bytes(&bytes) + } +} + +fn hex_nibble(c: u8) -> Result { + match c { + b'0'..=b'9' => Ok(c - b'0'), + b'a'..=b'f' => Ok(c - b'a' + 10), + b'A'..=b'F' => Ok(c - b'A' + 10), + _ => Err("invalid hex character in compressed G1 public key"), + } +} + +/// `Option` variant for fields like +/// `Validator::public_key`. +pub mod option { + use super::*; + + pub fn serialize( + opt: &Option, + serializer: S, + ) -> Result { + // Option delegates to the DPP public key's Serialize implementation. + opt.serialize(serializer) + } + + pub fn deserialize<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result, D::Error> { + struct OptionVisitor; + + impl<'de> Visitor<'de> for OptionVisitor { + type Value = Option; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("Option") + } + + fn visit_none(self) -> Result { + Ok(None) + } + + fn visit_unit(self) -> Result { + Ok(None) + } + + fn visit_some>( + self, + inner: D2, + ) -> Result { + super::deserialize(inner).map(Some) + } + } + + deserializer.deserialize_option(OptionVisitor) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ::serde::{Deserialize, Serialize}; + use serde_json::json; + + // A known-valid compressed-G1 BLS public key (deterministic — the + // ValidatorSet fixture's seeded StdRng(42) threshold key). + const PK_HEX: &str = + "969c5d5873f49aa994c5f6a850924ca1840c4ad1791aaaecd90093d4a5c0c3799f2d98540f5366cfa0a33f143fd69263"; + + // Newtypes that drive the `with` module(s) through serde. + #[derive(Serialize, Deserialize)] + struct Wrap(#[serde(with = "super")] BlsPublicKey); + + #[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). + let pk: Wrap = serde_json::from_value(json!(PK_HEX)).expect("from hex"); + assert_eq!(serde_json::to_value(&pk).expect("to json"), json!(PK_HEX)); + } + + #[test] + fn json_borrowed_str_path_works() { + // 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)); + } + + #[test] + fn value_non_hr_byte_seq_round_trip() { + // Non-HR `platform_value` serializes the key as a 48-byte sequence; the + // 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"); + assert_eq!(serde_json::to_value(&pk2).expect("to json"), json!(PK_HEX)); + } + + #[test] + fn option_some_and_none_round_trip() { + let some: OptWrap = serde_json::from_value(json!(PK_HEX)).expect("some"); + assert_eq!(serde_json::to_value(&some).expect("to json"), json!(PK_HEX)); + let none: OptWrap = serde_json::from_value(json!(null)).expect("none"); + assert_eq!(serde_json::to_value(&none).expect("to json"), json!(null)); + } +} diff --git a/packages/rs-dpp/src/core_types/validator/mod.rs b/packages/rs-dpp/src/core_types/validator/mod.rs index 5cc5681b205..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::{Bls12381G2Impl, 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; @@ -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..eedbcb3dd1b 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::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") + serde(with = "crate::bls::serde::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; } @@ -274,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; @@ -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..0b517f4ed00 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::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::SecretKey; use crate::core_types::validator::v0::ValidatorV0; use crate::core_types::validator_set::v0::ValidatorSetV0; use dashcore::hashes::Hash; @@ -165,16 +165,12 @@ 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, - ) { + 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), @@ -204,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"; @@ -234,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 2384b186b22..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 @@ -1,5 +1,4 @@ -use crate::bls_signatures::Bls12381G2Impl; -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; @@ -33,14 +32,9 @@ 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). - #[cfg_attr( - feature = "serde-conversion", - serde(with = "crate::serialization::dashcore::bls_pubkey") - )] - pub threshold_public_key: BlsPublicKey, + // Tagged enum buffers can carry either hex strings or byte sequences. + #[cfg_attr(feature = "serde-conversion", serde(with = "crate::bls::serde"))] + pub threshold_public_key: BlsPublicKey, } impl Display for ValidatorSetV0 { @@ -67,7 +61,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 +85,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 +231,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 +245,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 +273,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 +295,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; } } @@ -309,7 +303,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; @@ -326,7 +320,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 +339,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/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 78ff0224abe..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, Bls12381G2Impl, BlsError}; +use crate::bls::{self, 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::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::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::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..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,3 +1,5 @@ +#[cfg(feature = "bls-signatures")] +use crate::bls; #[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::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::Signature; use crate::identity::{Purpose, SecurityLevel}; use dashcore::Network; use dpp::version::PlatformVersion; @@ -157,10 +156,9 @@ mod tests { .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"); + 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.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() @@ -174,18 +172,13 @@ mod tests { .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); + 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"); 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..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 use blsful as 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 deleted file mode 100644 index ccc6d8f852a..00000000000 --- a/packages/rs-dpp/src/serialization/dashcore/bls_pubkey.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! 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. - -use crate::bls_signatures::inner_types::{G1Affine, GroupEncoding, PrimeCurveAffine}; -use crate::bls_signatures::{Bls12381G2Impl, 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`). -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. - 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`). - deserializer.deserialize_any(BlsPublicKeyVisitor) -} - -fn from_compressed_g1_bytes( - bytes: &[u8], -) -> Result, E> { - 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())) -} - -struct BlsPublicKeyVisitor; - -impl<'de> Visitor<'de> for BlsPublicKeyVisitor { - type Value = BlsPublicKey; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "a {}-char hex string or {} compressed-G1 bytes", - COMPRESSED_G1_LEN * 2, - COMPRESSED_G1_LEN - ) - } - - 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 {}", - COMPRESSED_G1_LEN * 2, - s.len() - ))); - } - let mut bytes = [0u8; COMPRESSED_G1_LEN]; - for (i, slot) in bytes.iter_mut().enumerate() { - let hi = hex_nibble(s.as_bytes()[i * 2]).map_err(E::custom)?; - let lo = hex_nibble(s.as_bytes()[i * 2 + 1]).map_err(E::custom)?; - *slot = (hi << 4) | lo; - } - from_compressed_g1_bytes(&bytes) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - from_compressed_g1_bytes(v) - } - - 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)); - } - bytes.push(b); - } - from_compressed_g1_bytes(&bytes) - } -} - -fn hex_nibble(c: u8) -> Result { - match c { - b'0'..=b'9' => Ok(c - b'0'), - b'a'..=b'f' => Ok(c - b'a' + 10), - b'A'..=b'F' => Ok(c - b'A' + 10), - _ => Err("invalid hex character in compressed G1 public key"), - } -} - -/// `Option>` variant for fields like -/// `Validator::public_key`. -pub mod option { - use super::*; - - pub fn serialize( - opt: &Option>, - serializer: S, - ) -> Result { - // Option's built-in Serialize delegates to T's Serialize, which - // is the upstream BlsPublicKey impl — already correct. - opt.serialize(serializer) - } - - pub fn deserialize<'de, D: Deserializer<'de>>( - deserializer: D, - ) -> Result>, D::Error> { - struct OptionVisitor; - - impl<'de> Visitor<'de> for OptionVisitor { - type Value = Option>; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Option>") - } - - fn visit_none(self) -> Result { - Ok(None) - } - - fn visit_unit(self) -> Result { - Ok(None) - } - - fn visit_some>( - self, - inner: D2, - ) -> Result { - super::deserialize(inner).map(Some) - } - } - - deserializer.deserialize_option(OptionVisitor) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde::{Deserialize, Serialize}; - use serde_json::json; - - // A known-valid compressed-G1 BLS public key (deterministic — the - // ValidatorSet fixture's seeded StdRng(42) threshold key). - const PK_HEX: &str = - "969c5d5873f49aa994c5f6a850924ca1840c4ad1791aaaecd90093d4a5c0c3799f2d98540f5366cfa0a33f143fd69263"; - - // Newtypes that drive the `with` module(s) through serde. - #[derive(Serialize, Deserialize)] - struct Wrap(#[serde(with = "super")] BlsPublicKey); - - #[derive(Serialize, Deserialize)] - struct OptWrap(#[serde(with = "super::option")] Option>); - - #[test] - fn json_hr_round_trip_is_the_hex_string() { - // Human-readable (serde_json::Value): hex in, identical hex out (visit_str). - let pk: Wrap = serde_json::from_value(json!(PK_HEX)).expect("from hex"); - assert_eq!(serde_json::to_value(&pk).expect("to json"), json!(PK_HEX)); - } - - #[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. - 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)); - } - - #[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. - 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"); - assert_eq!(serde_json::to_value(&pk2).expect("to json"), json!(PK_HEX)); - } - - #[test] - fn option_some_and_none_round_trip() { - let some: OptWrap = serde_json::from_value(json!(PK_HEX)).expect("some"); - assert_eq!(serde_json::to_value(&some).expect("to json"), json!(PK_HEX)); - let none: OptWrap = serde_json::from_value(json!(null)).expect("none"); - assert_eq!(serde_json::to_value(&none).expect("to json"), json!(null)); - } -} diff --git a/packages/rs-dpp/src/serialization/dashcore/mod.rs b/packages/rs-dpp/src/serialization/dashcore/mod.rs index 14b8c22773e..c21d6baa443 100644 --- a/packages/rs-dpp/src/serialization/dashcore/mod.rs +++ b/packages/rs-dpp/src/serialization/dashcore/mod.rs @@ -1,18 +1,6 @@ -//! 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). +//! Compatibility re-exports for Serde field adapters. -/// 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; +#[deprecated(note = "use dpp::bls::serde instead")] +pub use crate::bls::serde as 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..ba2256dd17b 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::{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::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 new file mode 100644 index 00000000000..c14ff906f7b --- /dev/null +++ b/packages/rs-dpp/tests/bls_compatibility.rs @@ -0,0 +1,388 @@ +use dash_pkc::bls::{BlsPublicKey, BlsScChia, BlsScIetf, BlsSecretKey, BlsSignature}; +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; +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_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().to_bytes(), 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!( + 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() + .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(&message) + .unwrap() + }) + .collect(); + 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() + .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!(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); + 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()); + + 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] +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!(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); + 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 + ); + 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..752f676c763 --- /dev/null +++ b/packages/rs-dpp/tests/fixtures/bls_compatibility/README.md @@ -0,0 +1,37 @@ +# 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 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 +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" + } + ] +} 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 62f1cdfab8c..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::{Bls12381G2Impl, 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; @@ -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..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::{Bls12381G2Impl, SecretKey as BlsPrivateKey}; + use dpp::bls::SecretKey as BlsPrivateKey; use dpp::dashcore::hashes::Hash; use dpp::dashcore::ProTxHash; use dpp::dashcore::Txid; @@ -433,11 +433,13 @@ mod tests { .expect("expected to generate a private key") .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"), + 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(); + .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 { id: 0, @@ -976,11 +978,13 @@ mod tests { .expect("expected to generate a private key") .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"), + 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(); + .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 let masternode_list_item = MasternodeListItem { @@ -1072,15 +1076,13 @@ 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(); + .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( pro_tx_hash.as_byte_array(), @@ -1215,11 +1217,13 @@ mod tests { .expect("expected to generate a private key") .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"), + 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(); + .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 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..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::{Bls12381G2Impl, 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}; @@ -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..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::{Bls12381G2Impl, 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; @@ -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_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 1b0ab684cfe..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::{Bls12381G2Impl, PublicKey as BlsPublicKey}; +use dpp::bls::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..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::{Bls12381G2Impl, 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; @@ -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(); @@ -95,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 000d46582a2..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::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls::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!( @@ -51,16 +47,12 @@ 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(), + ))); } }; - let signature = Signature::Basic(decoded_sig); - // we attempt to verify the chain lock locally let chain_lock_height = chain_lock.block_height; @@ -237,7 +229,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::Signature; + use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; use dpp::dashcore::{BlockHash, ChainLock, QuorumSigningRequestId}; use dpp::version::PlatformVersion; @@ -327,11 +320,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..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::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls::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..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::{Bls12381G2Impl, 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; @@ -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..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::{ - Bls12381G2Impl, 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}; @@ -18,9 +16,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 +101,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 +272,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 +283,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..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,8 +3,8 @@ 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_signatures::Bls12381G2Impl; +use dpp::bls; + 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::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..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::{Bls12381G2Impl, BlsError, Pairing, 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( @@ -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[..] @@ -139,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/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 index a5b7a11c78d..8ad16315f56 100644 --- 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 @@ -1,5 +1,5 @@ #[cfg(feature = "bls-signatures")] -use dpp::bls_signatures::PublicKey; +use dpp::bls::PublicKey; use dpp::dashcore::{ProTxHash, PubkeyHash, QuorumHash}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; 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 2800dc0683b..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 @@ -114,7 +114,7 @@ impl From> for Quorums { QuorumHash::from_byte_array(quorum.hash.to_buffer()), VerificationQuorum { #[cfg(feature = "bls-signatures")] - public_key: dpp::bls_signatures::PublicKey::try_from( + public_key: dpp::bls::PublicKey::try_from( quorum.public_key.to_bytes().as_slice(), ) .expect("expected to convert between BLS key libraries (from chia)"), @@ -134,12 +134,86 @@ 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() } } + +#[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, + ); + } +} 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..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,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::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; - 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..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,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::bls; +pub use dpp::bls::PublicKey as ThresholdBlsPublicKey; + 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::SecretKey::from_be_bytes(&self.private_key).ok_or( + Error::BLSError(dpp::bls::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::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..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::{Bls12381G2Impl, 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}; @@ -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..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; @@ -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::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..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::{Bls12381G2Impl, SecretKey, SignatureSchemes}; + use dpp::bls::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::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::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..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::{Bls12381G2Impl, SecretKey as BlsPrivateKey, SignatureSchemes}; +use dpp::bls::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/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/masternode_list_item_helpers.rs b/packages/rs-drive-abci/tests/strategy_tests/masternode_list_item_helpers.rs index 3ada8f30353..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 @@ -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,13 @@ impl UpdateMasternodeListItem for MasternodeListItem { .expect("expected to generate a private key") .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"), + 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(); + .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; } 4 => { @@ -97,11 +98,13 @@ mod tests { .expect("expected to generate a private key") .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"), + 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(); + .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, 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..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::{Bls12381G2Impl, 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}; @@ -233,11 +233,13 @@ pub fn generate_test_masternodes( .expect("expected to generate a private key") .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"), + 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(); + .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 { node_type: MasternodeType::Regular, @@ -375,11 +377,13 @@ pub fn generate_test_masternodes( .expect("expected to generate a private key") .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"), + 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(); + .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, 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..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::{Bls12381G2Impl, BlsError, Pairing, 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<'_> { @@ -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..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::{Bls12381G2Impl, SecretKey}; + use dpp::bls::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..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::{Bls12381G2Impl, Pairing, Signature}; +use dpp::bls::Signature; use tenderdash_abci::{ proto::types::{CanonicalVote, SignedMsgType, StateId}, signatures::{Hashable, Signable}, @@ -134,8 +134,8 @@ 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(), })?; @@ -164,20 +164,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::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 +336,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::SecretKey, bls::PublicKey) { + let scalar = + hex::decode("659dc45452f29c17f96dda38ae1546e0e9e818423cdb8cc857f3728c518b4cb8") + .unwrap() + .try_into() + .unwrap(); + let sk = bls::SecretKey::from_be_bytes(&scalar).unwrap(); let pk = sk.public_key(); (sk, pk) } @@ -358,7 +357,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..81f482c7949 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::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..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::{Bls12381G2Impl, SecretKey as BlsSecretKey, SignatureSchemes}; +use dpp::bls::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, @@ -465,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}; @@ -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::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)]