diff --git a/Cargo.lock b/Cargo.lock index 3a1d9561a..e6a30af95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,6 +266,124 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.6", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "array-bytes" version = "4.2.0" @@ -698,12 +816,17 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" 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.6", "sp-application-crypto", "sp-core", "sp-runtime-interface", @@ -6031,7 +6154,6 @@ checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" name = "polkadex-client" version = "0.1.0" dependencies = [ - "bls-primitives", "frame-benchmarking", "node-polkadex-runtime", "sc-executor", diff --git a/client/Cargo.toml b/client/Cargo.toml index ca7c7b7c0..be6f0caa7 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -9,4 +9,3 @@ edition = "2021" sc-executor = { workspace = true } node-polkadex-runtime = { path = "../runtime", version = "4.0.0" } frame-benchmarking = { workspace = true } -bls-primitives = { path = "../primitives/bls-primitives" } diff --git a/client/src/lib.rs b/client/src/lib.rs index f1ba2f8ab..8b6239656 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -4,10 +4,7 @@ pub struct ExecutorDispatch; impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - type ExtendHostFunctions = ( - frame_benchmarking::benchmarking::HostFunctions, - bls_primitives::crypto::bls_ext::HostFunctions, - ); + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; fn dispatch(method: &str, data: &[u8]) -> Option> { node_polkadex_runtime::api::dispatch(method, data) diff --git a/clients/orderbook/src/tests/mod.rs b/clients/orderbook/src/tests/mod.rs index 6ac0b9133..e60c86920 100644 --- a/clients/orderbook/src/tests/mod.rs +++ b/clients/orderbook/src/tests/mod.rs @@ -2,7 +2,6 @@ pub mod rpc; pub mod sync; use crate::protocol_standard_name; -use bls_primitives::BLS_DEV_PHRASE; use futures::{channel::mpsc::UnboundedSender, stream::FuturesUnordered, StreamExt}; use memory_db::{HashKey, MemoryDB}; use orderbook_primitives::{ diff --git a/clients/thea/src/error.rs b/clients/thea/src/error.rs index 0d854e86c..5fdec85af 100644 --- a/clients/thea/src/error.rs +++ b/clients/thea/src/error.rs @@ -67,8 +67,8 @@ impl From for Error { } } -impl From for Error { - fn from(value: blst::BLST_ERROR) -> Self { +impl From for Error { + fn from(value: bls_primitives::Error) -> Self { Self::BLSError(format!("{value:?}")) } } diff --git a/clients/thea/src/tests/mod.rs b/clients/thea/src/tests/mod.rs index 79bfd6ef2..7ea2727d7 100644 --- a/clients/thea/src/tests/mod.rs +++ b/clients/thea/src/tests/mod.rs @@ -19,6 +19,7 @@ use sp_consensus::SyncOracle; use sp_core::{Pair, H256}; use sp_keyring::AccountKeyring; use sp_keystore::CryptoStore; +use sp_runtime::traits::AppVerify; use crate::Client; use polkadex_primitives::utils::return_set_bits; @@ -87,12 +88,9 @@ impl TestApi { signatories.push((*auths.get(index).unwrap()).clone().into()); } + let bls_signature: bls_primitives::Signature = signature.into(); // Check signature - assert!(bls_primitives::crypto::verify_aggregate_( - &signatories[..], - &message.encode(), - &signature.into(), - )); + assert!(bls_signature.verify(&signatories, &message.encode())); self.incoming_nonce.write().insert(message.network, message.nonce); self.incoming_messages.write().insert((message.network, message.nonce), message); diff --git a/clients/thea/src/tests/withdrawal.rs b/clients/thea/src/tests/withdrawal.rs index 2293436d5..3876e0278 100644 --- a/clients/thea/src/tests/withdrawal.rs +++ b/clients/thea/src/tests/withdrawal.rs @@ -66,11 +66,7 @@ impl ForeignConnector for DummyForeignConnector { } // Check signature - assert!(bls_primitives::crypto::verify_aggregate_( - &signatories[..], - &message.encode(), - &payload.aggregate_signature.into(), - )); + assert!(payload.aggregate_signature.verify(&signatories, &message.encode())); *self.incoming_nonce.write() = message.nonce; self.incoming_messages.write().insert(message.nonce, message); diff --git a/pallets/ocex/Cargo.toml b/pallets/ocex/Cargo.toml index c6d7771dc..fa55ccf12 100644 --- a/pallets/ocex/Cargo.toml +++ b/pallets/ocex/Cargo.toml @@ -26,7 +26,6 @@ frame-benchmarking = { workspace = true, default-features = false, optional = tr sp-core = { workspace = true, default-features = false } liquidity = { path = "../liquidity", default-features = false } orderbook-primitives = { path = "../../primitives/orderbook", default-features = false } -bls-primitives = { path = "../../primitives/bls-primitives", default-features = false } sp-application-crypto = { workspace = true } [dev-dependencies] @@ -35,6 +34,7 @@ pallet-balances = { workspace = true, features = ["std"] } sp-application-crypto = { workspace = true } sp-keystore = { workspace = true } sp-io = { workspace = true } +bls-primitives = { path = "../../primitives/bls-primitives", default-features = false } [features] default = ["std"] diff --git a/pallets/ocex/src/lib.rs b/pallets/ocex/src/lib.rs index 3217ebc80..dc4cee415 100644 --- a/pallets/ocex/src/lib.rs +++ b/pallets/ocex/src/lib.rs @@ -1468,11 +1468,7 @@ impl>> Pallet return InvalidTransaction::Custom(12).into(), Some(signature) => { - if !bls_primitives::crypto::bls_ext::verify( - &authority.into(), - &snapshot_summary.sign_data(), - &signature, - ) { + if !signature.verify(&[authority.into()], &snapshot_summary.sign_data()) { return InvalidTransaction::Custom(13).into() } }, diff --git a/pallets/thea-message-handler/src/lib.rs b/pallets/thea-message-handler/src/lib.rs index 02bc02f19..36697a942 100644 --- a/pallets/thea-message-handler/src/lib.rs +++ b/pallets/thea-message-handler/src/lib.rs @@ -224,12 +224,10 @@ impl Pallet { Some(auth) => signatories.push((*auth).clone().into()), } } + // Verify the aggregate signature. - if !bls_primitives::crypto::bls_ext::verify_aggregate( - &signatories[..], - &payload.encode(), - &(*signature).clone().into(), - ) { + let bls_signature: bls_primitives::Signature = signature.clone().into(); + if !bls_signature.verify(&signatories, payload.encode().as_ref()) { return Err(InvalidTransaction::BadSigner.into()) } diff --git a/pallets/thea/src/lib.rs b/pallets/thea/src/lib.rs index 98b2e3661..71f2b18a2 100644 --- a/pallets/thea/src/lib.rs +++ b/pallets/thea/src/lib.rs @@ -226,11 +226,8 @@ impl Pallet { } } // Verify the aggregate signature. - if !bls_primitives::crypto::bls_ext::verify_aggregate( - &signatories[..], - &payload.encode(), - &(*signature).clone().into(), - ) { + let bls_signature: bls_primitives::Signature = signature.clone().into(); + if !bls_signature.verify(&signatories, payload.encode().as_ref()) { return Err(InvalidTransaction::BadSigner.into()) } diff --git a/primitives/bls-primitives/Cargo.toml b/primitives/bls-primitives/Cargo.toml index e6524740a..035fb4749 100644 --- a/primitives/bls-primitives/Cargo.toml +++ b/primitives/bls-primitives/Cargo.toml @@ -19,9 +19,22 @@ parity-scale-codec = { workspace = true, default-features = false, features = [" scale-info = { workspace = true, default-features = false, features = ["derive"] } hex = { version = "0.4.3", 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", diff --git a/primitives/bls-primitives/src/application_crypto.rs b/primitives/bls-primitives/src/application_crypto.rs index f136a14f5..9e9b93876 100644 --- a/primitives/bls-primitives/src/application_crypto.rs +++ b/primitives/bls-primitives/src/application_crypto.rs @@ -22,44 +22,22 @@ impl RuntimePublic for Public { type Signature = Signature; fn all(_: KeyTypeId) -> Vec { - crypto::bls_ext::all() + unimplemented!() } - fn generate_pair(_: KeyTypeId, seed: Option>) -> Self { - crypto::bls_ext::generate_pair_and_store(seed) + fn generate_pair(_: KeyTypeId, _: Option>) -> Self { + unimplemented!() } - fn sign>(&self, _: KeyTypeId, msg: &M) -> Option { - crypto::bls_ext::sign(self, msg.as_ref()) + fn sign>(&self, _: KeyTypeId, _: &M) -> Option { + unimplemented!() } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - crypto::bls_ext::verify(self, msg.as_ref(), signature) + signature.verify(&[*self], msg.as_ref()) } fn to_raw_vec(&self) -> Vec { self.0.to_vec() } } - -#[cfg(test)] -mod tests { - use crate::crypto::sign; - use sp_core::blake2_256; - - #[test] - pub fn test_generate_and_load_back() { - use super::*; - let key_type = KeyTypeId(*b"blsk"); - let public = Public::generate_pair(key_type, Some(b"owner word vocal dose decline sunset battle example forget excite gentle waste//1//orderbook".to_vec())); - let loaded_keys = Public::all(key_type); - assert_eq!(loaded_keys.len(), 1); - assert_eq!(loaded_keys[0], public); - let message = blake2_256(&vec![0, 1]); - - let signature = sign(&public, &message).unwrap(); - println!("Pubkey: {:?}", public.0); - println!("Signature: {:?}", signature.0); - assert!(crate::crypto::bls_ext::verify(&public, message.as_ref(), &signature)); - } -} diff --git a/primitives/bls-primitives/src/crypto.rs b/primitives/bls-primitives/src/crypto.rs deleted file mode 100644 index 072132845..000000000 --- a/primitives/bls-primitives/src/crypto.rs +++ /dev/null @@ -1,246 +0,0 @@ -#[cfg(feature = "std")] -use crate::{Error, Pair as BLSPair}; -use crate::{KeyStore, Public, Seed, Signature, DST}; -#[cfg(feature = "std")] -use blst::min_sig::*; -#[cfg(feature = "std")] -use blst::BLST_ERROR; - -#[cfg(feature = "std")] -use sp_core::crypto::{ExposeSecret, SecretUri}; -#[cfg(feature = "std")] -use sp_core::Pair; -use sp_runtime_interface::runtime_interface; - -use sp_std::vec::Vec; - -pub const BLS_KEYSTORE_PATH: &str = "polkadex/.keystore/"; - -#[runtime_interface] -pub trait BlsExt { - #[allow(clippy::result_unit_err)] - fn add_signature(agg_signature: &Signature, new: &Signature) -> Result { - add_signature(agg_signature, new) - } - - fn all() -> Vec { - // Load all available bls public keys from filesystem - match get_all_public_keys() { - Ok(keys) => keys, - Err(_) => Vec::new(), - } - } - - fn generate_pair(phrase: Option>) -> Public { - // generate a pair - let (pair, _seed, _derive_junctions) = generate_pair_(phrase); - pair.public() - } - - fn generate_pair_and_store(phrase: Option>) -> Public { - let (pair, seed, derive_junctions) = generate_pair_(phrase); - // create keystore - let keystore: KeyStore = KeyStore::new(seed, derive_junctions); - // store the private key in filesystem - let file_path = key_file_path(pair.public().as_ref()); - write_to_file(file_path, keystore.encode().as_ref()).expect("Unable to write seed to file"); - pair.public() - } - - fn sign(pubkey: &Public, msg: &[u8]) -> Option { - // load the private key from filesystem and sign with it - sign(pubkey, msg) - } - - fn verify(pubkey: &Public, msg: &[u8], signature: &Signature) -> bool { - let pubkey = match PublicKey::uncompress(pubkey.0.as_ref()) { - Ok(pubkey) => pubkey, - Err(_) => return false, - }; - let signature = match crate::BLSSignature::uncompress(signature.0.as_ref()) { - Ok(sig) => sig, - Err(_) => return false, - }; - // verify the signature - let err = signature.verify(true, msg, DST.as_ref(), &[], &pubkey, true); - err == BLST_ERROR::BLST_SUCCESS - } - - fn verify_aggregate(pubkey: &[Public], msg: &[u8], signature: &Signature) -> bool { - verify_aggregate_(pubkey, msg, signature) - } -} - -#[cfg(feature = "std")] -pub fn add_signature_(sig1: &Signature, sig2: &Signature) -> Result { - let agg_signature = crate::BLSSignature::from_bytes(sig1.0.as_ref())?; - let new = crate::BLSSignature::from_bytes(sig2.0.as_ref())?; - let mut agg_signature = AggregateSignature::from_signature(&agg_signature); - agg_signature.add_signature(&new, true)?; - Ok(Signature::from(crate::BLSSignature::from_aggregate(&agg_signature))) -} - -#[cfg(feature = "std")] -pub fn verify_aggregate_(pubkey: &[Public], msg: &[u8], signature: &Signature) -> bool { - let mut pubkeys = vec![]; - for key in pubkey { - let agg_pubkey = match PublicKey::uncompress(key.0.as_ref()) { - Ok(pubkey) => pubkey, - Err(_) => return false, - }; - pubkeys.push(agg_pubkey); - } - let pubkeys_ref = pubkeys.iter().collect::>(); - - let agg_signature = match crate::BLSSignature::uncompress(signature.0.as_ref()) { - Ok(sig) => sig, - Err(_) => return false, - }; - // verify the signature - let err = agg_signature.fast_aggregate_verify(true, msg, DST.as_ref(), &pubkeys_ref); - err == BLST_ERROR::BLST_SUCCESS -} - -#[cfg(feature = "std")] -use std::fs::File; -#[cfg(feature = "std")] -use std::io::Write; - -use parity_scale_codec::{Decode, Encode}; -#[cfg(feature = "std")] -use sp_core::DeriveJunction; -#[cfg(feature = "std")] -use std::path::PathBuf; -#[cfg(feature = "std")] -use std::str::FromStr; - -#[cfg(feature = "std")] -fn generate_pair_(phrase: Option>) -> (BLSPair, Seed, Vec) { - let (pair, seed, derive_junctions) = match phrase { - None => { - let (pair, seed) = BLSPair::generate(); - (pair, seed, vec![]) - }, - Some(phrase) => { - let phrase = String::from_utf8(phrase).expect("Invalid phrase"); - let uri = SecretUri::from_str(phrase.as_ref()).expect("expected a valid phrase"); - let (pair, seed) = BLSPair::from_phrase(uri.phrase.expose_secret(), None) - .expect("Phrase is not valid; qed"); - - let (pair, seed) = pair - .derive(uri.junctions.iter().cloned(), Some(seed)) - .expect("Expected to derive the pair here."); - (pair, seed.unwrap(), uri.junctions) - }, - }; - (pair, seed, derive_junctions) -} - -#[cfg(feature = "std")] -#[allow(dead_code)] -pub fn sign(pubkey: &Public, msg: &[u8]) -> Option { - let path = key_file_path(pubkey.as_ref()); - match std::fs::read(&path) { - Err(err) => { - log::error!(target:"bls","Error while reading keystore file: {:?}",err); - None - }, - Ok(data) => match serde_json::from_slice::>(&data) { - Ok(seed) => - return match KeyStore::decode(&mut seed.as_ref()) { - Ok(keystore) => { - if let Ok(secret_key) = - SecretKey::key_gen(keystore.get_seed().as_ref(), &[]) - { - let mut master_key = secret_key; - for junction in keystore.get_junctions() { - 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)) - } - return Some(Signature::from(master_key.sign(msg, DST.as_ref(), &[]))) - } else { - log::error!(target: "bls", "KeyStore has been corrupted, Unable to derive BLS Key"); - None - } - }, - Err(err) => { - log::error!(target:"bls","Error while loading keystore from storage {:?}",err); - None - }, - }, - Err(_) => None, - }, - } -} - -#[cfg(feature = "std")] -#[allow(dead_code)] -fn get_all_public_keys() -> Result, Error> { - let mut public_keys = vec![]; - for entry in std::fs::read_dir(BLS_KEYSTORE_PATH)? { - let entry = entry?; - let path = entry.path(); - - // skip directories and non-unicode file names (hex is unicode) - if let Some(name) = path.file_name().and_then(|n| n.to_str()) { - match hex::decode(name) { - Ok(ref hex) if hex.len() == 96 => { - let public = hex.to_vec(); - - match PublicKey::uncompress(public.as_ref()) { - Ok(public) => public_keys.push(Public::from(public.to_bytes())), - Err(_) => continue, - } - }, - _ => continue, - } - } - } - Ok(public_keys) -} - -/// Write the given `data` to `file`. -#[cfg(feature = "std")] -#[allow(dead_code)] -fn write_to_file(path: PathBuf, data: &[u8]) -> Result<(), Error> { - std::fs::create_dir_all(BLS_KEYSTORE_PATH)?; - let mut file = std::fs::OpenOptions::new().write(true).create(true).open(path)?; - use std::os::unix::fs::PermissionsExt; - file.metadata()?.permissions().set_mode(0o600); - serde_json::to_writer(&file, data)?; - file.flush()?; - Ok(()) -} - -/// Get the file path for the given public key and key type. -/// -/// Returns `None` if the keystore only exists in-memory and there isn't any path to provide. -#[cfg(feature = "std")] -#[allow(dead_code)] -fn key_file_path(public: &[u8]) -> PathBuf { - let mut buf = PathBuf::from(BLS_KEYSTORE_PATH); - let key = hex::encode(public); - buf.push(key.as_str()); - buf -} - -/// Get the key phrase for a given public key and key type. -#[cfg(feature = "std")] -#[allow(dead_code)] -fn key_phrase_by_type(public: &[u8]) -> Result, Error> { - let path = key_file_path(public); - - if path.exists() { - let file = File::open(path)?; - - serde_json::from_reader(&file).map_err(Into::into).map(Some) - } else { - Ok(None) - } -} diff --git a/primitives/bls-primitives/src/lib.rs b/primitives/bls-primitives/src/lib.rs index 3f8f5ac94..2978052ce 100644 --- a/primitives/bls-primitives/src/lib.rs +++ b/primitives/bls-primitives/src/lib.rs @@ -1,8 +1,21 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod application_crypto; -pub mod crypto; +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")] @@ -11,7 +24,9 @@ use blst::min_sig::{PublicKey, SecretKey, Signature as BLSSignature}; 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, CryptoTypePublicPair, Derive}; +use sp_std::ops::{Add, Neg}; #[cfg(feature = "std")] use sp_core::crypto::SecretStringError; @@ -22,8 +37,6 @@ use sp_runtime_interface::pass_by::PassByInner; #[cfg(feature = "std")] use substrate_bip39::seed_from_entropy; -#[cfg(feature = "std")] -use crate::crypto::add_signature_; use sp_std::vec::Vec; /// An identifier used to match public keys against bls keys @@ -31,13 +44,6 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"blss"); pub const DST: &str = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"; -pub const BLS_DEV_PHRASE: &str = - "forget flee list will tissue myself viable sleep cover lake summer \ -flat artefact hurry bronze salt fiber fog emotion loyal broken coach arch plastic"; - -pub const DEV_PHRASE: &str = - "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; - /// BLS Public Key #[cfg_attr(feature = "std", derive(Hash))] #[derive( @@ -62,48 +68,61 @@ pub struct Public(pub [u8; 96]); )] pub struct Signature(pub [u8; 48]); -// KeyStore for Storing Seed and Junctions -#[cfg_attr(feature = "std", derive(Hash))] -#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] -pub struct KeyStore { - seed: Seed, - #[cfg(feature = "std")] - junctions: Vec, -} - -#[cfg(feature = "std")] -impl KeyStore { - fn new(seed: Seed, junctions: Vec) -> Self { - Self { seed, junctions } - } - - fn get_seed(&self) -> Seed { - self.seed - } - - fn get_junctions(&self) -> Vec { - self.junctions.clone() - } -} - impl Signature { // Aggregates two signatures - #[cfg(feature = "std")] - pub fn add_signature(self, signature: &Signature) -> Result { - add_signature_(&self, signature) + 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)) + } + } + + 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() } } type Seed = [u8; 32]; /// An error when deriving a key. -#[cfg(feature = "std")] #[derive(Debug)] pub enum Error { /// Invalid Public key InvalidPublicKey, + #[cfg(feature = "std")] BLSError(BLST_ERROR), InvalidSeed, + BLSSerilizationError(SerializationError), InvalidJunctionForDerivation, #[cfg(feature = "std")] SerdeError(serde_json::Error), @@ -111,6 +130,12 @@ pub enum Error { 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 { @@ -306,18 +331,7 @@ impl sp_core::crypto::Pair for Pair { } fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - let pubkey = PublicKey::from_bytes(&pubkey.0).expect("Expected valid public key"); - let signature = - BLSSignature::from_bytes(sig.0.as_ref()).expect("Expected valid BLS signature"); - - signature.verify( - true, - message.as_ref(), - DST.as_ref(), - &[], // TODO: wtf is this? - &pubkey, - true, - ) == BLST_ERROR::BLST_SUCCESS + sig.verify(&[*pubkey], message.as_ref()) } fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { @@ -338,3 +352,47 @@ impl sp_core::crypto::Pair for Pair { 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::{hash_to_curve_g1, 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)) + } +} diff --git a/primitives/orderbook/src/lib.rs b/primitives/orderbook/src/lib.rs index d573352cc..6ceaba3b6 100644 --- a/primitives/orderbook/src/lib.rs +++ b/primitives/orderbook/src/lib.rs @@ -151,33 +151,11 @@ impl Default for SnapshotSummary { impl SnapshotSummary { // Add a new signature to the snapshot summary - - #[cfg(feature = "std")] - pub fn add_signature(&mut self, signature: Signature) -> Result<(), Signature> { - match bls_primitives::crypto::add_signature_( - &self.aggregate_signature.ok_or(signature)?, - &signature, - ) { - Ok(signature) => { - self.aggregate_signature = Some(signature); - Ok(()) - }, - Err(_) => Err(signature), - } - } - - #[cfg(not(feature = "std"))] pub fn add_signature(&mut self, signature: Signature) -> Result<(), Signature> { - match bls_primitives::crypto::bls_ext::add_signature( - &self.aggregate_signature.ok_or(signature)?, - &signature, - ) { - Ok(signature) => { - self.aggregate_signature = Some(signature); - Ok(()) - }, - Err(_) => Err(signature), - } + let aggregate_signature = self.aggregate_signature.ok_or(signature)?; + self.aggregate_signature = + Some(aggregate_signature.add_signature(&signature).map_err(|_| signature)?); + Ok(()) } pub fn get_fees(&self) -> Vec { @@ -202,8 +180,7 @@ impl SnapshotSummary { let msg = self.sign_data(); match self.aggregate_signature { None => false, - Some(sig) => - bls_primitives::crypto::bls_ext::verify_aggregate(&public_keys, &msg, &sig), + Some(sig) => sig.verify(&public_keys, msg.as_ref()), } }