diff --git a/Cargo.lock b/Cargo.lock index eb21f6d0a..c8dcaba1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -712,7 +712,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -747,7 +747,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -910,7 +910,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -1077,6 +1077,43 @@ dependencies = [ "tracing", ] +[[package]] +name = "bls-primitives" +version = "0.1.0" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "blst", + "hex", + "log", + "parity-scale-codec", + "scale-info", + "serde_json", + "sha2 0.10.8", + "sp-application-crypto", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-std", + "substrate-bip39", + "tiny-bip39", +] + +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "borsh" version = "0.10.3" @@ -1487,7 +1524,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2252,7 +2289,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2571,7 +2608,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2611,7 +2648,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2628,7 +2665,7 @@ checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2676,7 +2713,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2698,7 +2735,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2943,7 +2980,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2984,7 +3021,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.38", + "syn 2.0.48", "termcolor", "toml 0.7.8", "walkdir", @@ -3196,7 +3233,7 @@ checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3207,7 +3244,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3318,7 +3355,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3607,7 +3644,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3734,7 +3771,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3746,7 +3783,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3756,7 +3793,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3924,7 +3961,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -5633,7 +5670,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -5647,7 +5684,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -5658,7 +5695,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -5669,7 +5706,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -7496,7 +7533,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -8131,7 +8168,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -8172,7 +8209,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -8246,6 +8283,7 @@ checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" name = "polkadex-client" version = "5.3.0" dependencies = [ + "bls-primitives", "frame-benchmarking", "node-polkadex-runtime", "sc-executor", @@ -9692,7 +9730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -9775,14 +9813,14 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -9821,7 +9859,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -9966,9 +10004,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -10178,7 +10216,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -10870,7 +10908,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -11869,7 +11907,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -12178,7 +12216,7 @@ checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -12226,7 +12264,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -12609,7 +12647,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -12848,7 +12886,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -12867,7 +12905,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -13084,7 +13122,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -13276,7 +13314,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -13644,7 +13682,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -13919,9 +13957,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -14144,9 +14182,9 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] @@ -14173,13 +14211,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -14350,7 +14388,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -14505,7 +14543,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -14549,7 +14587,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -14973,7 +15011,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -15007,7 +15045,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -16029,7 +16067,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -16078,7 +16116,7 @@ checksum = "020f3dfe25dfc38dfea49ce62d5d45ecdd7f0d8a724fa63eb36b6eba4ec76806" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -16098,7 +16136,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 62ceb599e..cdb6e19fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ "primitives/orderbook", "primitives/polkadex", "primitives/thea", + "primitives/bls", "pallets/thea", "pallets/liquidity", "pallets/thea-executor", @@ -65,6 +66,7 @@ default-members = [ "primitives/orderbook", "primitives/polkadex", "primitives/thea", + "primitives/bls", "pallets/thea", "pallets/liquidity", "pallets/thea-executor", @@ -86,7 +88,6 @@ static_assertions = "1.1.0" parity-scale-codec = { version = "3.1.5", default-features = false } rust_decimal = { git = "https://github.com/Polkadex-Substrate/rust-decimal.git", branch = "master", default-features = false } scale-info = { version = "2.1.2", default-features = false } -bls-primitives = { path = "primitives/bls-primitives", default-features = false } thea-primitives = { path = "primitives/thea", default-features = false } frame-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } diff --git a/client/Cargo.toml b/client/Cargo.toml index 5ae053329..6bb1156cb 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] sc-executor = { workspace = true } +bls-primitives = { path = "../primitives/bls" } node-polkadex-runtime = { path = "../runtimes/mainnet" } frame-benchmarking = { workspace = true } sp-statement-store = { workspace = true } diff --git a/client/src/lib.rs b/client/src/lib.rs index 81e786735..74bf25ff6 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -24,6 +24,9 @@ pub struct ExecutorDispatch; impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { type ExtendHostFunctions = ( frame_benchmarking::benchmarking::HostFunctions, + // NOTE: BLS host functions is a un-removable relic and should not be used or removed from + // here + bls_primitives::host_functions::bls_crypto_ext::HostFunctions, sp_statement_store::runtime_api::HostFunctions, ); diff --git a/primitives/bls/Cargo.toml b/primitives/bls/Cargo.toml new file mode 100644 index 000000000..872e9c0be --- /dev/null +++ b/primitives/bls/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "bls-primitives" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = { workspace = true, optional = true } +substrate-bip39 = { version = "0.4.4", optional = true } +tiny-bip39 = { version = "1.0.0", optional = true } +sp-runtime-interface = { workspace = true, default-features = false } +sp-application-crypto = { workspace = true, default-features = false } +sp-keystore = { workspace = true, default-features = false } +sp-externalities = { workspace = true, default-features = false } +sp-core = { workspace = true, default-features = false } +sp-std = { workspace = true, default-features = false } +serde_json = { workspace = true, optional = true } +blst = { version = "0.3.10", default-features = false, optional = true } +parity-scale-codec = { workspace = true, default-features = false, features = ["max-encoded-len"] } +scale-info = { workspace = true, default-features = false, features = ["derive"] } +hex = { workspace = true, optional = true } + +# Ark works +ark-bls12-381 = { version = "0.4.0", default-features = false, features = ["curve"] } +ark-ec = { version = "0.4.2", default-features = false } +ark-ff = { version = "0.4.2", default-features = false } +ark-serialize = { version = "0.4.2", default-features = false } +sha2 = { version = "0.10.6", default-features = false } + +[features] +default = ["std"] +std = [ + "sha2/std", + "ark-bls12-381/std", + "ark-ec/std", + "ark-ff/std", + "ark-serialize/std", + "log", + "hex", + "serde_json", + "parity-scale-codec/std", + "sp-application-crypto/std", + "sp-keystore/std", + "sp-externalities/std", + "scale-info/std", + "sp-runtime-interface/std", + "sp-core/full_crypto", + "sp-core/std", + "sp-std/std", + "substrate-bip39", + "tiny-bip39", + "blst", +] diff --git a/primitives/bls/src/application_crypto.rs b/primitives/bls/src/application_crypto.rs new file mode 100644 index 000000000..95146605f --- /dev/null +++ b/primitives/bls/src/application_crypto.rs @@ -0,0 +1,79 @@ +// This file is part of Polkadex. +// +// Copyright (c) 2023 Polkadex oü. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// DISCLAIMER: This module is deprecated and exists solely for the host function required during +// block sync. It will not be maintained and must not be used in production. + +#[cfg(feature = "std")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; +use sp_application_crypto::{KeyTypeId, RuntimePublic}; +use sp_std::vec::Vec; + +pub use crate::*; + +pub mod app { + use sp_core::crypto::KeyTypeId; + + pub const BLS: KeyTypeId = KeyTypeId(*b"blsk"); + + sp_application_crypto::app_crypto!(super, BLS); + + // impl sp_application_crypto::BoundToRuntimeAppPublic for Public { + // type Public = Self; + // } +} + +impl RuntimePublic for Public { + type Signature = Signature; + + fn all(_: KeyTypeId) -> Vec { + unimplemented!( + "BLS12-381 Host functions are not yet available in Polkadot,\ + so this will not work" + ) + } + + #[cfg(not(feature = "parachain"))] + fn generate_pair(key: KeyTypeId, seed: Option>) -> Self { + crate::host_functions::bls_crypto_ext::bls_generate_pair(key, seed) + } + + #[cfg(feature = "parachain")] + fn generate_pair(_: KeyTypeId, _: Option>) -> Self { + unimplemented!( + "BLS12-381 Host functions are not yet available in Polkadot,\ + so this will not work" + ) + } + + fn sign>(&self, _: KeyTypeId, _: &M) -> Option { + unimplemented!( + "BLS12-381 Host functions are not yet available in Polkadot,\ + so this will not work" + ) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + signature.verify(&[*self], msg.as_ref()) + } + + fn to_raw_vec(&self) -> Vec { + self.0.to_vec() + } +} diff --git a/primitives/bls/src/host_functions.rs b/primitives/bls/src/host_functions.rs new file mode 100644 index 000000000..a350c9880 --- /dev/null +++ b/primitives/bls/src/host_functions.rs @@ -0,0 +1,57 @@ +// This file is part of Polkadex. +// +// Copyright (c) 2023 Polkadex oü. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// DISCLAIMER: This module is deprecated and exists solely for the host function required during +// block sync. It will not be maintained and must not be used in production. + +use sp_application_crypto::RuntimePublic; +use sp_core::crypto::KeyTypeId; +#[cfg(feature = "std")] +use sp_core::Pair; +#[cfg(feature = "std")] +use sp_keystore::{Keystore, KeystoreExt}; +use sp_std::vec::Vec; + +use crate::Public; +use sp_runtime_interface::runtime_interface; + +#[cfg(feature = "std")] +use sp_externalities::ExternalitiesExt; + +#[runtime_interface] +pub trait BLSCryptoExt { + fn bls_generate_pair(&mut self, id: KeyTypeId, seed: Option>) -> Public { + let (pair, seed) = match seed { + None => { + let (pair, seed_string, _) = crate::Pair::generate_with_phrase(None); + (pair, seed_string) + }, + Some(seed) => { + let seed = String::from_utf8(seed).expect("expected seed to be Utf-8"); + (crate::Pair::from_string(seed.as_str(), None).expect("Seed not valid!"), seed) + }, + }; + let keystore = &***self + .extension::() + .expect("No `keystore` associated for the current context!"); + let public_key = pair.public().to_raw_vec(); + <(dyn Keystore + 'static)>::insert(keystore, id, seed.as_str(), public_key.as_slice()) + .unwrap(); + pair.public() + } +} diff --git a/primitives/bls/src/lib.rs b/primitives/bls/src/lib.rs new file mode 100644 index 000000000..ce5227e70 --- /dev/null +++ b/primitives/bls/src/lib.rs @@ -0,0 +1,432 @@ +// This file is part of Polkadex. +// +// Copyright (c) 2023 Polkadex oü. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! # BLS Primitives. +//! +//! In this crate defined BLS signature related low-level crypto operations and types. +//! +//! DISCLAIMER: This module is deprecated and exists solely for the host function required during +//! block sync. It will not be maintained and must not be used in production. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate core; + +pub mod application_crypto; + +#[cfg(not(feature = "parachain"))] +pub mod host_functions; + +use ark_bls12_381::{ + g1::Config as G1Config, Bls12_381, G1Affine, G1Projective, G2Affine, G2Projective, +}; +use ark_ec::{ + hashing::{ + curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve, + HashToCurveError, + }, + pairing::Pairing, + short_weierstrass::Projective, + AffineRepr, CurveGroup, +}; +use ark_ff::{field_hashers::DefaultFieldHasher, Zero}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; +#[cfg(feature = "std")] +use bip39::{Language, Mnemonic, MnemonicType}; +#[cfg(feature = "std")] +use blst::min_sig::{PublicKey, SecretKey, Signature as BLSSignature}; +#[cfg(feature = "std")] +use blst::BLST_ERROR; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sha2::Sha256; +use sp_core::crypto::{ByteArray, CryptoType, CryptoTypeId, Derive, Ss58Codec}; +use sp_std::ops::{Add, Neg}; + +#[cfg(feature = "std")] +use sp_core::crypto::SecretStringError; +#[cfg(feature = "std")] +use sp_core::DeriveJunction; + +use sp_runtime_interface::pass_by::PassByInner; +#[cfg(feature = "std")] +use substrate_bip39::seed_from_entropy; + +use sp_std::vec::Vec; + +/// An identifier used to match public keys against bls keys. +pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"blss"); + +/// Domain separation tag. +pub const DST: &str = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"; + +/// BLS Public Key. +#[cfg_attr(feature = "std", derive(Hash))] +#[derive( + Clone, + Copy, + Encode, + Decode, + MaxEncodedLen, + PassByInner, + TypeInfo, + Eq, + PartialEq, + PartialOrd, + Ord, + Debug, +)] +pub struct Public(pub [u8; 96]); + +/// BLS signature definition. +#[cfg_attr(feature = "std", derive(Hash))] +#[derive( + Encode, Decode, MaxEncodedLen, TypeInfo, PassByInner, PartialEq, Eq, Clone, Copy, Debug, +)] +pub struct Signature(pub [u8; 48]); + +impl Signature { + /// Aggregates two signatures. + /// + /// # Parameters + /// + /// * `signature`: Signature to aggregate. + pub fn add_signature(self, signature: &Signature) -> Result { + let sig1: G1Projective = G1Affine::deserialize_compressed(self.as_ref())?.into(); + let sig2: G1Projective = G1Affine::deserialize_compressed(signature.as_ref())?.into(); + let result: G1Projective = sig1.add(sig2); + let mut buffer = Vec::from([0u8; 48]); + result.serialize_compressed(buffer.as_mut_slice())?; + if buffer.len() == 48 { + Ok(Signature(buffer.try_into().unwrap())) + } else { + Err(Error::BLSSerilizationError(SerializationError::InvalidData)) + } + } + + /// Verifies message with provided public keys. + /// + /// # Parameters + /// + /// * `public_keys`: Public key to aggregate public key from. + /// * `message`: Message to verify. + pub fn verify(self, public_keys: &[Public], message: &[u8]) -> bool { + // Aggregate the public keys + let mut g2_points = Vec::new(); + for public_key in public_keys { + match G2Projective::deserialize_compressed(public_key.as_ref()) { + Ok(point) => g2_points.push(point), + Err(_) => return false, + } + } + let aggregated_pubk: G2Projective = g2_points.into_iter().sum::(); + // hash to curve g1 + let message = match hash_to_curve_g1(message) { + Ok(message) => message, + Err(_) => return false, + }; + // Convert signature to a G1 point + let signature: G1Affine = match G1Affine::deserialize_compressed(self.as_ref()) { + Ok(signatyre) => signatyre, + Err(_) => return false, + }; + // Compute the product of pairings + Bls12_381::multi_pairing( + [signature, message.into_affine()], + [G2Affine::generator().neg(), aggregated_pubk.into_affine()], + ) + .is_zero() + } +} + +/// Seed type. +type Seed = [u8; 32]; + +/// An error when deriving a key. +#[derive(Debug)] +pub enum Error { + /// Invalid Public key. + InvalidPublicKey, + /// BLS library specific error. + #[cfg(feature = "std")] + BLSError(BLST_ERROR), + /// Provided invalid seed. + InvalidSeed, + /// Error appeared in the process of BLS serialization. + BLSSerilizationError(SerializationError), + /// Invalid justification. + InvalidJunctionForDerivation, + /// Serde specific error. + #[cfg(feature = "std")] + SerdeError(serde_json::Error), + /// IO error. + #[cfg(feature = "std")] + IOError(std::io::Error), +} + +impl From for Error { + fn from(value: SerializationError) -> Self { + Self::BLSSerilizationError(value) + } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(value: std::io::Error) -> Self { + Self::IOError(value) + } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(value: serde_json::Error) -> Self { + Self::SerdeError(value) + } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(value: BLST_ERROR) -> Self { + Self::BLSError(value) + } +} + +/// The key pair. +#[cfg(feature = "std")] +#[derive(Clone)] +pub struct Pair { + public: Public, + secret: SecretKey, +} + +#[cfg(feature = "std")] +impl TryFrom for PublicKey { + type Error = Error; + + fn try_from(value: Public) -> Result { + Ok(PublicKey::from_bytes(&value.0)?) + } +} + +impl From<[u8; 96]> for Public { + fn from(value: [u8; 96]) -> Self { + Self(value) + } +} + +impl TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(value: &[u8]) -> Result { + if value.len() != 196 { + return Err(()) + } + Ok(Signature(value.try_into().unwrap())) + } +} + +#[cfg(feature = "std")] +impl From for Signature { + fn from(value: BLSSignature) -> Self { + Signature(value.compress()) + } +} + +#[cfg(feature = "std")] +impl CryptoType for Pair { + type Pair = Pair; +} + +impl ByteArray for Public { + const LEN: usize = 96; +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + self.0.as_slice() + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + self.0.as_mut() + } +} + +impl TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(value: &[u8]) -> Result { + if value.len() != 96 { + return Err(()) + } + Ok(Public(value.try_into().unwrap())) + } +} + +impl Derive for Public {} + +impl CryptoType for Public { + #[cfg(feature = "std")] + type Pair = Pair; +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +#[cfg(feature = "std")] +impl std::str::FromStr for Public { + type Err = sp_core::crypto::PublicError; + + fn from_str(s: &str) -> Result { + Self::from_ss58check(s) + } +} +use sp_core::crypto::Public as TraitPublic; +impl TraitPublic for Public {} + +#[cfg(feature = "std")] +impl sp_core::crypto::Pair for Pair { + type Public = Public; + type Seed = Seed; + type Signature = Signature; + + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { + let mnemonic = Mnemonic::new(MnemonicType::Words24, Language::English); + let phrase = mnemonic.phrase(); + let (pair, seed) = Self::from_phrase(phrase, password) + .expect("All phrases generated by Mnemonic are valid; qed"); + (pair, phrase.to_owned(), seed) + } + + fn from_phrase( + phrase: &str, + password: Option<&str>, + ) -> Result<(Pair, Seed), SecretStringError> { + let big_seed = seed_from_entropy( + Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase)? + .entropy(), + password.unwrap_or(""), + ) + .map_err(|_| SecretStringError::InvalidSeed)?; + let mut seed = Seed::default(); + seed.copy_from_slice(&big_seed[0..32]); + let secret = SecretKey::key_gen(&seed, &[]).unwrap(); + let pair = Pair { public: secret.sk_to_pk().compress().into(), secret }; + Ok((pair, seed)) + } + + #[cfg(feature = "std")] + fn derive>( + &self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), sp_core::crypto::DeriveError> { + let mut master_key = self.secret.clone(); + for junction in path { + let index_bytes = [ + junction.inner()[0], + junction.inner()[1], + junction.inner()[2], + junction.inner()[3], + ]; + master_key = master_key.derive_child_eip2333(u32::from_be_bytes(index_bytes)) + } + Ok((Pair { public: master_key.sk_to_pk().compress().into(), secret: master_key }, seed)) + } + + fn from_seed(seed: &Self::Seed) -> Self { + Self::from_seed_slice(&seed[..]).expect("seed needs to be of valid length; qed") + } + + fn from_seed_slice(seed: &[u8]) -> Result { + let secret = match SecretKey::key_gen(seed, &[]) { + Ok(secret) => secret, + Err(err) => { + log::error!(target:"bls","Error while computing secret from seed: {:?}",err); + return Err(SecretStringError::InvalidSeed) + }, + }; + + Ok(Pair { public: secret.sk_to_pk().compress().into(), secret }) + } + + fn sign(&self, message: &[u8]) -> Self::Signature { + self.secret.sign(message, DST.as_ref(), &[]).into() + } + + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + sig.verify(&[*pubkey], message.as_ref()) + } + + fn public(&self) -> Self::Public { + self.public + } + + fn to_raw_vec(&self) -> Vec { + self.secret.to_bytes().to_vec() + } +} + +pub fn hash_to_curve_g1(message: &[u8]) -> Result { + let wb_to_curve_hasher = MapToCurveBasedHasher::< + Projective, + DefaultFieldHasher, + WBMap, + >::new(DST.as_ref())?; + Ok(wb_to_curve_hasher.hash(message)?.into()) +} + +#[cfg(test)] +mod tests { + use crate::{Public, Signature, DST}; + use sp_application_crypto::RuntimePublic; + use sp_core::Pair; + + #[test] + pub fn test_signature_works() { + let pair = blst::min_sig::SecretKey::key_gen(&[1u8; 32], &[]).unwrap(); + let message = b"message"; + let signature = pair.sign(message, DST.as_ref(), &[]); + let public_key = pair.sk_to_pk(); + + let new_signature: crate::Signature = Signature(signature.compress()); + let new_public_key: crate::Public = Public(public_key.compress()); + + assert!(new_public_key.verify(&message, &new_signature)); + assert!(!new_public_key.verify(b"fake", &new_signature)) + } + + #[test] + pub fn test_aggregate_signature_works() { + let pair1 = crate::Pair::generate().0; + let pair2 = crate::Pair::generate().0; + let message = b"message"; + + let sig1 = pair1.sign(message); + let sig2 = pair2.sign(message); + + let aggregate_signature = sig1.add_signature(&sig2).unwrap(); + + assert!(aggregate_signature.verify(&[pair1.public(), pair2.public()], message)) + } +}