mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 22:41:02 +00:00
BEEFY: Define a BeefyVerify trait for signatures (#12299)
* Define CustomVerify trait Signed-off-by: Serban Iorga <serban@parity.io> * Use ECDSA CustomVerify for MultiSignature Signed-off-by: Serban Iorga <serban@parity.io> * beefy: small simplifications Signed-off-by: Serban Iorga <serban@parity.io> * Revert "Use ECDSA CustomVerify for MultiSignature" This reverts commit 136cff82505662dd92c864491814629d2bc349f0. * Revert "Define CustomVerify trait" This reverts commit adf91e9e6d1bdea6f00831f6067b74c3d945f9a2. * Define BeefyAuthorityId and BeefyVerify traits * Improve BeefyVerify unit tests Co-authored-by: Robert Hambrock <roberthambrock@gmail.com> * fmt & import sp_core::blake2_256 * Renamings * remove SignerToAccountId * fix Signed-off-by: Serban Iorga <serban@parity.io> Co-authored-by: Robert Hambrock <roberthambrock@gmail.com>
This commit is contained in:
Generated
+1
@@ -538,6 +538,7 @@ dependencies = [
|
|||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"sp-io",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"sp-mmr-primitives",
|
"sp-mmr-primitives",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
|||||||
@@ -19,12 +19,13 @@
|
|||||||
use sp_application_crypto::RuntimeAppPublic;
|
use sp_application_crypto::RuntimeAppPublic;
|
||||||
use sp_core::keccak_256;
|
use sp_core::keccak_256;
|
||||||
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||||
|
use sp_runtime::traits::Keccak256;
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use beefy_primitives::{
|
use beefy_primitives::{
|
||||||
crypto::{Public, Signature},
|
crypto::{Public, Signature},
|
||||||
KEY_TYPE,
|
BeefyVerify, KEY_TYPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
@@ -98,11 +99,7 @@ impl BeefyKeystore {
|
|||||||
///
|
///
|
||||||
/// Return `true` if the signature is authentic, `false` otherwise.
|
/// Return `true` if the signature is authentic, `false` otherwise.
|
||||||
pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool {
|
pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool {
|
||||||
let msg = keccak_256(message);
|
BeefyVerify::<Keccak256>::verify(sig, message, public)
|
||||||
let sig = sig.as_ref();
|
|
||||||
let public = public.as_ref();
|
|
||||||
|
|
||||||
sp_core::ecdsa::Pair::verify_prehashed(sig, &msg, public)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,12 +73,8 @@ where
|
|||||||
/// Convert BEEFY secp256k1 public keys into Ethereum addresses
|
/// Convert BEEFY secp256k1 public keys into Ethereum addresses
|
||||||
pub struct BeefyEcdsaToEthereum;
|
pub struct BeefyEcdsaToEthereum;
|
||||||
impl Convert<beefy_primitives::crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
impl Convert<beefy_primitives::crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
||||||
fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec<u8> {
|
fn convert(beefy_id: beefy_primitives::crypto::AuthorityId) -> Vec<u8> {
|
||||||
sp_core::ecdsa::Public::try_from(a.as_ref())
|
sp_core::ecdsa::Public::from(beefy_id)
|
||||||
.map_err(|_| {
|
|
||||||
log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!");
|
|
||||||
})
|
|
||||||
.unwrap_or(sp_core::ecdsa::Public::from_raw([0u8; 33]))
|
|
||||||
.to_eth_address()
|
.to_eth_address()
|
||||||
.map(|v| v.to_vec())
|
.map(|v| v.to_vec())
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
|
|||||||
sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" }
|
sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" }
|
||||||
sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" }
|
sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" }
|
||||||
sp-core = { version = "6.0.0", default-features = false, path = "../core" }
|
sp-core = { version = "6.0.0", default-features = false, path = "../core" }
|
||||||
|
sp-io = { version = "6.0.0", default-features = false, path = "../io" }
|
||||||
sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" }
|
sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" }
|
||||||
sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" }
|
sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" }
|
||||||
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
|
sp-std = { version = "4.0.0", default-features = false, path = "../std" }
|
||||||
@@ -34,6 +35,7 @@ std = [
|
|||||||
"sp-api/std",
|
"sp-api/std",
|
||||||
"sp-application-crypto/std",
|
"sp-application-crypto/std",
|
||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
|
"sp-io/std",
|
||||||
"sp-mmr-primitives/std",
|
"sp-mmr-primitives/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
|||||||
@@ -41,12 +41,30 @@ pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider};
|
|||||||
|
|
||||||
use codec::{Codec, Decode, Encode};
|
use codec::{Codec, Decode, Encode};
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
|
use sp_application_crypto::RuntimeAppPublic;
|
||||||
use sp_core::H256;
|
use sp_core::H256;
|
||||||
|
use sp_runtime::traits::Hash;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
/// Key type for BEEFY module.
|
/// Key type for BEEFY module.
|
||||||
pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef");
|
pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef");
|
||||||
|
|
||||||
|
/// Trait representing BEEFY authority id.
|
||||||
|
pub trait BeefyAuthorityId: RuntimeAppPublic {}
|
||||||
|
|
||||||
|
/// Means of verification for a BEEFY authority signature.
|
||||||
|
///
|
||||||
|
/// Accepts custom hashing fn for the message and custom convertor fn for the signer.
|
||||||
|
pub trait BeefyVerify<MsgHash: Hash> {
|
||||||
|
/// Type of the signer.
|
||||||
|
type Signer: BeefyAuthorityId;
|
||||||
|
|
||||||
|
/// Verify a signature.
|
||||||
|
///
|
||||||
|
/// Return `true` if signature is valid for the value.
|
||||||
|
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
/// BEEFY cryptographic types
|
/// BEEFY cryptographic types
|
||||||
///
|
///
|
||||||
/// This module basically introduces three crypto types:
|
/// This module basically introduces three crypto types:
|
||||||
@@ -60,7 +78,9 @@ pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::Ke
|
|||||||
/// The current underlying crypto scheme used is ECDSA. This can be changed,
|
/// The current underlying crypto scheme used is ECDSA. This can be changed,
|
||||||
/// without affecting code restricted against the above listed crypto types.
|
/// without affecting code restricted against the above listed crypto types.
|
||||||
pub mod crypto {
|
pub mod crypto {
|
||||||
|
use super::{BeefyAuthorityId, BeefyVerify, Hash};
|
||||||
use sp_application_crypto::{app_crypto, ecdsa};
|
use sp_application_crypto::{app_crypto, ecdsa};
|
||||||
|
use sp_core::crypto::Wraps;
|
||||||
app_crypto!(ecdsa, crate::KEY_TYPE);
|
app_crypto!(ecdsa, crate::KEY_TYPE);
|
||||||
|
|
||||||
/// Identity of a BEEFY authority using ECDSA as its crypto.
|
/// Identity of a BEEFY authority using ECDSA as its crypto.
|
||||||
@@ -68,6 +88,26 @@ pub mod crypto {
|
|||||||
|
|
||||||
/// Signature for a BEEFY authority using ECDSA as its crypto.
|
/// Signature for a BEEFY authority using ECDSA as its crypto.
|
||||||
pub type AuthoritySignature = Signature;
|
pub type AuthoritySignature = Signature;
|
||||||
|
|
||||||
|
impl BeefyAuthorityId for AuthorityId {}
|
||||||
|
|
||||||
|
impl<MsgHash: Hash> BeefyVerify<MsgHash> for AuthoritySignature
|
||||||
|
where
|
||||||
|
<MsgHash as Hash>::Output: Into<[u8; 32]>,
|
||||||
|
{
|
||||||
|
type Signer = AuthorityId;
|
||||||
|
|
||||||
|
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool {
|
||||||
|
let msg_hash = <MsgHash as Hash>::hash(msg).into();
|
||||||
|
match sp_io::crypto::secp256k1_ecdsa_recover_compressed(
|
||||||
|
self.as_inner_ref().as_ref(),
|
||||||
|
&msg_hash,
|
||||||
|
) {
|
||||||
|
Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(signer),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `ConsensusEngineId` of BEEFY.
|
/// The `ConsensusEngineId` of BEEFY.
|
||||||
@@ -180,7 +220,8 @@ sp_api::decl_runtime_apis! {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use sp_application_crypto::ecdsa::{self, Public};
|
use sp_application_crypto::ecdsa::{self, Public};
|
||||||
use sp_core::Pair;
|
use sp_core::{blake2_256, crypto::Wraps, keccak_256, Pair};
|
||||||
|
use sp_runtime::traits::{BlakeTwo256, Keccak256};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validator_set() {
|
fn validator_set() {
|
||||||
@@ -194,4 +235,36 @@ mod tests {
|
|||||||
assert_eq!(validators.id(), set_id);
|
assert_eq!(validators.id(), set_id);
|
||||||
assert_eq!(validators.validators(), &vec![alice.public()]);
|
assert_eq!(validators.validators(), &vec![alice.public()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn beefy_verify_works() {
|
||||||
|
let msg = &b"test-message"[..];
|
||||||
|
let (pair, _) = crypto::Pair::generate();
|
||||||
|
|
||||||
|
let keccak_256_signature: crypto::Signature =
|
||||||
|
pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into();
|
||||||
|
|
||||||
|
let blake2_256_signature: crypto::Signature =
|
||||||
|
pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into();
|
||||||
|
|
||||||
|
// Verification works if same hashing function is used when signing and verifying.
|
||||||
|
assert!(BeefyVerify::<Keccak256>::verify(&keccak_256_signature, msg, &pair.public()));
|
||||||
|
assert!(BeefyVerify::<BlakeTwo256>::verify(&blake2_256_signature, msg, &pair.public()));
|
||||||
|
// Verification fails if distinct hashing functions are used when signing and verifying.
|
||||||
|
assert!(!BeefyVerify::<Keccak256>::verify(&blake2_256_signature, msg, &pair.public()));
|
||||||
|
assert!(!BeefyVerify::<BlakeTwo256>::verify(&keccak_256_signature, msg, &pair.public()));
|
||||||
|
|
||||||
|
// Other public key doesn't work
|
||||||
|
let (other_pair, _) = crypto::Pair::generate();
|
||||||
|
assert!(!BeefyVerify::<Keccak256>::verify(
|
||||||
|
&keccak_256_signature,
|
||||||
|
msg,
|
||||||
|
&other_pair.public()
|
||||||
|
));
|
||||||
|
assert!(!BeefyVerify::<BlakeTwo256>::verify(
|
||||||
|
&blake2_256_signature,
|
||||||
|
msg,
|
||||||
|
&other_pair.public()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -984,6 +984,11 @@ pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
|
|||||||
pub trait Wraps: Sized {
|
pub trait Wraps: Sized {
|
||||||
/// The inner type it is wrapping.
|
/// The inner type it is wrapping.
|
||||||
type Inner: IsWrappedBy<Self>;
|
type Inner: IsWrappedBy<Self>;
|
||||||
|
|
||||||
|
/// Get a reference to the inner type that is wrapped.
|
||||||
|
fn as_inner_ref(&self) -> &Self::Inner {
|
||||||
|
Self::Inner::from_ref(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Outer> IsWrappedBy<Outer> for T
|
impl<T, Outer> IsWrappedBy<Outer> for T
|
||||||
|
|||||||
Reference in New Issue
Block a user