mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-06 06:48:01 +00:00
Support for multiple signature scheme for BEEFY primitves (#14373)
* Merged BEEFY primitives with generic signature and keyset commitment support from old pull to current code * - Add bls-experimental feature to application-crypto and beefy primitives - Fix remaining crypto -> ecdsa_crypto - code build but not tests * Make beefy primitive tests compile * move bls related beefy primitives code and test behind bls-experimental flag * Make BEEFY clients complies with BEEFY API depending on AuthorityId * - Rename `BeefyAuthoritySet.root` → `BeefyAuthoritySet.keyset_commitment`. - Remove apk proof keyset_commitment from `BeefyAuthoritySet`. - Fix failing signed commitment and signature to witness test. - Make client compatible with BeefyAPI generic on AuthorityId. - `crypto` → `ecdsa_crypto` in BEEFY client and frame. * Commit Cargo lock remove ark-serialize from BEEFY primitives * Use Codec instead of Encode + Decode in primitives/consensus/beefy/src/lib.rs Co-authored-by: Davide Galassi <davxy@datawok.net> * - Make `BeefyApi` generic over Signature type. - Make new `BeeyApi` functinos also generic over AuthorityId and Signature * Unmake BeefyAPI generic over Signature. Recover Signature type from AuthId. * - dont use hex or hex-literal use array-bytes instead in beefy primitives and bls crypto. - CamelCase ECDSA and BLS everywhere. * Move the definition of BEEFY key type from `primitives/beefy` to `crypto.rs` according to new convention. * - Add bls377_generate_new to `sp-io` and `application_crypto::bls`. - Add `bls-experimental` to `sp-io` Does not compile because PassByCodec can not derive PassBy using customly implemented PassByIner. * Implement PassBy for `bls::Public` manually * fix Beefy `KEY_TYPE` in `frame/beefy` tests to come from `sp-core::key_types` enum * specify both generic for `hex2array_unchecked` in `sp-core/bls.rs` * Rename `crypto`→`ecdsa_crypto` in `primitives/consensus/beefy/src/test_utils.rs` docs * remove commented-out code in `primitives/consensus/beefy/src/commitment.rs` Co-authored-by: Davide Galassi <davxy@datawok.net> * Fix inconsistency in panic message in `primitives/io/src/lib.rs` Co-authored-by: Davide Galassi <davxy@datawok.net> * Remove redundant feature activation in `primitives/io/Cargo.toml` Co-authored-by: Davide Galassi <davxy@datawok.net> * - make `w3f-bls` a dev-dependancy only for beefy primitives. - clean up comments. Co-authored-by: Davide Galassi <davxy@datawok.net> * export BEEFY KEY_TYPE from primitives/consensus/beefy make `frame/consensus/beefy` in dependent of sp_crypto_app use consistent naming in the beefy primitive tests. * - implement `BeefyAuthorityId` for `bls_crypto::AuthorityId`. - implement `bls_verify_works` test for BEEFY `bls_crypto`. * Remove BEEFY `ecdsa_n_bls_crypto` for now for later re-introduction * Make commitment and witness BEEFY tests not use Keystore. * put `bls_beefy_verify_works` test under `bls-experimental` flag. * bump up Runtime `BeefyAPI` to version 3 due to introducing generic AuthorityId. * reuse code and encapsulate w3f-bls backend in sp-core as most as possible Co-authored-by: Davide Galassi <davxy@datawok.net> * Make comments in primities BEEFY `commitment.rs` and `witness.rs``tests convention conforming * Use master dep versions * Trivial change. Mostly to trigger CI * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Fix Cargo.toml * Trigger CI with cumulus companion * Trigger CI after polkadot companion change --------- Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Generated
+1
-2
@@ -10614,11 +10614,11 @@ dependencies = [
|
||||
"sp-application-crypto",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-keystore",
|
||||
"sp-mmr-primitives",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
"strum",
|
||||
"w3f-bls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10675,7 +10675,6 @@ dependencies = [
|
||||
"futures",
|
||||
"hash-db",
|
||||
"hash256-std-hasher",
|
||||
"hex-literal",
|
||||
"impl-serde",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
|
||||
@@ -41,7 +41,7 @@ use crate::{
|
||||
LOG_TARGET,
|
||||
};
|
||||
use sp_consensus_beefy::{
|
||||
crypto::{AuthorityId, Signature},
|
||||
ecdsa_crypto::{AuthorityId, Signature},
|
||||
ValidatorSet, ValidatorSetId, VoteMessage,
|
||||
};
|
||||
|
||||
@@ -476,9 +476,10 @@ pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::keystore::BeefyKeystore;
|
||||
use sc_network_test::Block;
|
||||
use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE;
|
||||
use sp_consensus_beefy::{
|
||||
crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload,
|
||||
SignedCommitment, VoteMessage, KEY_TYPE,
|
||||
ecdsa_crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload,
|
||||
SignedCommitment, VoteMessage,
|
||||
};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
|
||||
@@ -536,7 +537,7 @@ pub(crate) mod tests {
|
||||
|
||||
pub fn sign_commitment<BN: Encode>(who: &Keyring, commitment: &Commitment<BN>) -> Signature {
|
||||
let store = MemoryKeystore::new();
|
||||
store.ecdsa_generate_new(KEY_TYPE, Some(&who.to_seed())).unwrap();
|
||||
store.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&who.to_seed())).unwrap();
|
||||
let beefy_keystore: BeefyKeystore = Some(store.into()).into();
|
||||
beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap()
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ use sc_network::{
|
||||
request_responses::{IfDisconnected, RequestFailure},
|
||||
NetworkRequest, PeerId, ProtocolName,
|
||||
};
|
||||
use sp_consensus_beefy::{crypto::AuthorityId, ValidatorSet};
|
||||
use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, ValidatorSet};
|
||||
use sp_runtime::traits::{Block, NumberFor};
|
||||
use std::{collections::VecDeque, result::Result, sync::Arc};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use log::debug;
|
||||
|
||||
use sp_api::{ProvideRuntimeApi, TransactionFor};
|
||||
use sp_consensus::Error as ConsensusError;
|
||||
use sp_consensus_beefy::{BeefyApi, BEEFY_ENGINE_ID};
|
||||
use sp_consensus_beefy::{ecdsa_crypto::AuthorityId, BeefyApi, BEEFY_ENGINE_ID};
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, Header as HeaderT, NumberFor},
|
||||
EncodedJustification,
|
||||
@@ -83,7 +83,7 @@ where
|
||||
Block: BlockT,
|
||||
BE: Backend<Block>,
|
||||
Runtime: ProvideRuntimeApi<Block>,
|
||||
Runtime::Api: BeefyApi<Block> + Send,
|
||||
Runtime::Api: BeefyApi<Block, AuthorityId> + Send,
|
||||
{
|
||||
fn decode_and_verify(
|
||||
&self,
|
||||
@@ -125,7 +125,7 @@ where
|
||||
> + Send
|
||||
+ Sync,
|
||||
Runtime: ProvideRuntimeApi<Block> + Send + Sync,
|
||||
Runtime::Api: BeefyApi<Block>,
|
||||
Runtime::Api: BeefyApi<Block, AuthorityId>,
|
||||
{
|
||||
type Error = ConsensusError;
|
||||
type Transaction = TransactionFor<Runtime, Block>;
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::keystore::BeefyKeystore;
|
||||
use codec::{DecodeAll, Encode};
|
||||
use sp_consensus::Error as ConsensusError;
|
||||
use sp_consensus_beefy::{
|
||||
crypto::{AuthorityId, Signature},
|
||||
ecdsa_crypto::{AuthorityId, Signature},
|
||||
ValidatorSet, ValidatorSetId, VersionedFinalityProof,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_application_crypto::RuntimeAppPublic;
|
||||
use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, RuntimeAppPublic};
|
||||
use sp_core::keccak_256;
|
||||
use sp_keystore::KeystorePtr;
|
||||
|
||||
use log::warn;
|
||||
|
||||
use sp_consensus_beefy::{
|
||||
crypto::{Public, Signature},
|
||||
BeefyAuthorityId, KEY_TYPE,
|
||||
ecdsa_crypto::{Public, Signature},
|
||||
BeefyAuthorityId,
|
||||
};
|
||||
|
||||
use crate::{error, LOG_TARGET};
|
||||
@@ -50,7 +50,7 @@ impl BeefyKeystore {
|
||||
// we do check for multiple private keys as a key store sanity check.
|
||||
let public: Vec<Public> = keys
|
||||
.iter()
|
||||
.filter(|k| store.has_keys(&[(k.to_raw_vec(), KEY_TYPE)]))
|
||||
.filter(|k| store.has_keys(&[(k.to_raw_vec(), BEEFY_KEY_TYPE)]))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
@@ -78,7 +78,7 @@ impl BeefyKeystore {
|
||||
let public = public.as_ref();
|
||||
|
||||
let sig = store
|
||||
.ecdsa_sign_prehashed(KEY_TYPE, public, &msg)
|
||||
.ecdsa_sign_prehashed(BEEFY_KEY_TYPE, public, &msg)
|
||||
.map_err(|e| error::Error::Keystore(e.to_string()))?
|
||||
.ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?;
|
||||
|
||||
@@ -96,7 +96,7 @@ impl BeefyKeystore {
|
||||
let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?;
|
||||
|
||||
let pk: Vec<Public> =
|
||||
store.ecdsa_public_keys(KEY_TYPE).drain(..).map(Public::from).collect();
|
||||
store.ecdsa_public_keys(BEEFY_KEY_TYPE).drain(..).map(Public::from).collect();
|
||||
|
||||
Ok(pk)
|
||||
}
|
||||
@@ -117,7 +117,7 @@ impl From<Option<KeystorePtr>> for BeefyKeystore {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use sp_consensus_beefy::{crypto, Keyring};
|
||||
use sp_consensus_beefy::{ecdsa_crypto, Keyring};
|
||||
use sp_core::{ecdsa, Pair};
|
||||
use sp_keystore::testing::MemoryKeystore;
|
||||
|
||||
@@ -156,35 +156,51 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn pair_works() {
|
||||
let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Alice", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Alice.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Bob", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Bob.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Charlie", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Charlie.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Dave", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Dave.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Eve", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Eve.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Ferdie", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Ferdie.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//One", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::One.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
|
||||
let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec();
|
||||
let want = ecdsa_crypto::Pair::from_string("//Two", None)
|
||||
.expect("Pair failed")
|
||||
.to_raw_vec();
|
||||
let got = Keyring::Two.pair().to_raw_vec();
|
||||
assert_eq!(want, got);
|
||||
}
|
||||
@@ -193,8 +209,8 @@ pub mod tests {
|
||||
fn authority_id_works() {
|
||||
let store = keystore();
|
||||
|
||||
let alice: crypto::Public = store
|
||||
.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
let alice: ecdsa_crypto::Public = store
|
||||
.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
.ok()
|
||||
.unwrap()
|
||||
.into();
|
||||
@@ -219,8 +235,8 @@ pub mod tests {
|
||||
fn sign_works() {
|
||||
let store = keystore();
|
||||
|
||||
let alice: crypto::Public = store
|
||||
.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
let alice: ecdsa_crypto::Public = store
|
||||
.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
.ok()
|
||||
.unwrap()
|
||||
.into();
|
||||
@@ -239,7 +255,10 @@ pub mod tests {
|
||||
fn sign_error() {
|
||||
let store = keystore();
|
||||
|
||||
store.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Bob.to_seed())).ok().unwrap();
|
||||
store
|
||||
.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Bob.to_seed()))
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let store: BeefyKeystore = Some(store).into();
|
||||
|
||||
@@ -268,8 +287,8 @@ pub mod tests {
|
||||
fn verify_works() {
|
||||
let store = keystore();
|
||||
|
||||
let alice: crypto::Public = store
|
||||
.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
let alice: ecdsa_crypto::Public = store
|
||||
.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&Keyring::Alice.to_seed()))
|
||||
.ok()
|
||||
.unwrap()
|
||||
.into();
|
||||
@@ -305,11 +324,11 @@ pub mod tests {
|
||||
let _ = add_key(TEST_TYPE, None);
|
||||
|
||||
// BEEFY keys
|
||||
let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str()));
|
||||
let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str()));
|
||||
let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Dave.to_seed().as_str()));
|
||||
let _ = add_key(BEEFY_KEY_TYPE, Some(Keyring::Eve.to_seed().as_str()));
|
||||
|
||||
let key1: crypto::Public = add_key(KEY_TYPE, None).into();
|
||||
let key2: crypto::Public = add_key(KEY_TYPE, None).into();
|
||||
let key1: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into();
|
||||
let key2: ecdsa_crypto::Public = add_key(BEEFY_KEY_TYPE, None).into();
|
||||
|
||||
let store: BeefyKeystore = Some(store).into();
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ use sp_blockchain::{
|
||||
};
|
||||
use sp_consensus::{Error as ConsensusError, SyncOracle};
|
||||
use sp_consensus_beefy::{
|
||||
crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID,
|
||||
ecdsa_crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet,
|
||||
BEEFY_ENGINE_ID,
|
||||
};
|
||||
use sp_keystore::KeystorePtr;
|
||||
use sp_mmr_primitives::MmrApi;
|
||||
@@ -142,7 +143,7 @@ where
|
||||
+ Send
|
||||
+ Sync,
|
||||
RuntimeApi: ProvideRuntimeApi<B> + Send + Sync,
|
||||
RuntimeApi::Api: BeefyApi<B>,
|
||||
RuntimeApi::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
// Voter -> RPC links
|
||||
let (to_rpc_justif_sender, from_voter_justif_stream) =
|
||||
@@ -224,7 +225,7 @@ pub async fn start_beefy_gadget<B, BE, C, N, P, R, S>(
|
||||
C: Client<B, BE> + BlockBackend<B>,
|
||||
P: PayloadProvider<B>,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash, NumberFor<B>>,
|
||||
R::Api: BeefyApi<B, AuthorityId> + MmrApi<B, MmrRootHash, NumberFor<B>>,
|
||||
N: GossipNetwork<B> + NetworkRequest + Send + Sync + 'static,
|
||||
S: GossipSyncing<B> + SyncOracle + 'static,
|
||||
{
|
||||
@@ -339,7 +340,7 @@ where
|
||||
B: Block,
|
||||
BE: Backend<B>,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B>,
|
||||
R::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
// Initialize voter state from AUX DB if compatible.
|
||||
crate::aux_schema::load_persistent(backend)?
|
||||
@@ -374,7 +375,7 @@ where
|
||||
B: Block,
|
||||
BE: Backend<B>,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B>,
|
||||
R::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
let beefy_genesis = runtime
|
||||
.runtime_api()
|
||||
@@ -478,7 +479,7 @@ async fn wait_for_runtime_pallet<B, R>(
|
||||
where
|
||||
B: Block,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B>,
|
||||
R::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available...");
|
||||
loop {
|
||||
@@ -518,7 +519,7 @@ fn expect_validator_set<B, R>(
|
||||
where
|
||||
B: Block,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B>,
|
||||
R::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
runtime
|
||||
.runtime_api()
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::LOG_TARGET;
|
||||
use codec::{Decode, Encode};
|
||||
use log::debug;
|
||||
use sp_consensus_beefy::{
|
||||
crypto::{AuthorityId, Signature},
|
||||
ecdsa_crypto::{AuthorityId, Signature},
|
||||
Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage,
|
||||
};
|
||||
use sp_runtime::traits::{Block, NumberFor};
|
||||
|
||||
@@ -48,14 +48,15 @@ use sc_network_test::{
|
||||
use sc_utils::notification::NotificationReceiver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_api::{ApiRef, ProvideRuntimeApi};
|
||||
use sp_application_crypto::key_types::BEEFY as BEEFY_KEY_TYPE;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_consensus_beefy::{
|
||||
crypto::{AuthorityId, Signature},
|
||||
ecdsa_crypto::{AuthorityId, Signature},
|
||||
known_payloads,
|
||||
mmr::{find_mmr_root_digest, MmrRootProvider},
|
||||
BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash,
|
||||
OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId,
|
||||
VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType,
|
||||
VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr};
|
||||
@@ -293,7 +294,7 @@ impl ProvideRuntimeApi<Block> for TestApi {
|
||||
}
|
||||
}
|
||||
sp_api::mock_impl_runtime_apis! {
|
||||
impl BeefyApi<Block> for RuntimeApi {
|
||||
impl BeefyApi<Block, AuthorityId> for RuntimeApi {
|
||||
fn beefy_genesis() -> Option<NumberFor<Block>> {
|
||||
Some(self.inner.beefy_genesis)
|
||||
}
|
||||
@@ -352,7 +353,7 @@ pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec<AuthorityId> {
|
||||
pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr {
|
||||
let keystore = MemoryKeystore::new();
|
||||
keystore
|
||||
.ecdsa_generate_new(BeefyKeyType, Some(&authority.to_seed()))
|
||||
.ecdsa_generate_new(BEEFY_KEY_TYPE, Some(&authority.to_seed()))
|
||||
.expect("Creates authority key");
|
||||
keystore.into()
|
||||
}
|
||||
@@ -386,7 +387,7 @@ fn initialize_beefy<API>(
|
||||
) -> impl Future<Output = ()>
|
||||
where
|
||||
API: ProvideRuntimeApi<Block> + Sync + Send,
|
||||
API::Api: BeefyApi<Block> + MmrApi<Block, MmrRootHash, NumberFor<Block>>,
|
||||
API::Api: BeefyApi<Block, AuthorityId> + MmrApi<Block, MmrRootHash, NumberFor<Block>>,
|
||||
{
|
||||
let tasks = FuturesUnordered::new();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ use sp_arithmetic::traits::{AtLeast32Bit, Saturating};
|
||||
use sp_consensus::SyncOracle;
|
||||
use sp_consensus_beefy::{
|
||||
check_equivocation_proof,
|
||||
crypto::{AuthorityId, Signature},
|
||||
ecdsa_crypto::{AuthorityId, Signature},
|
||||
BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet,
|
||||
VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID,
|
||||
};
|
||||
@@ -348,7 +348,7 @@ where
|
||||
P: PayloadProvider<B>,
|
||||
S: SyncOracle,
|
||||
R: ProvideRuntimeApi<B>,
|
||||
R::Api: BeefyApi<B>,
|
||||
R::Api: BeefyApi<B, AuthorityId>,
|
||||
{
|
||||
fn best_grandpa_block(&self) -> NumberFor<B> {
|
||||
*self.persisted_state.voting_oracle.best_grandpa_block_header.number()
|
||||
|
||||
@@ -73,8 +73,8 @@ where
|
||||
|
||||
/// Convert BEEFY secp256k1 public keys into Ethereum addresses
|
||||
pub struct BeefyEcdsaToEthereum;
|
||||
impl Convert<sp_consensus_beefy::crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
||||
fn convert(beefy_id: sp_consensus_beefy::crypto::AuthorityId) -> Vec<u8> {
|
||||
impl Convert<sp_consensus_beefy::ecdsa_crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
||||
fn convert(beefy_id: sp_consensus_beefy::ecdsa_crypto::AuthorityId) -> Vec<u8> {
|
||||
sp_core::ecdsa::Public::from(beefy_id)
|
||||
.to_eth_address()
|
||||
.map(|v| v.to_vec())
|
||||
@@ -200,11 +200,12 @@ impl<T: Config> Pallet<T> {
|
||||
.map(T::BeefyAuthorityToMerkleLeaf::convert)
|
||||
.collect::<Vec<_>>();
|
||||
let len = beefy_addresses.len() as u32;
|
||||
let root = binary_merkle_tree::merkle_root::<<T as pallet_mmr::Config>::Hashing, _>(
|
||||
beefy_addresses,
|
||||
)
|
||||
let keyset_commitment = binary_merkle_tree::merkle_root::<
|
||||
<T as pallet_mmr::Config>::Hashing,
|
||||
_,
|
||||
>(beefy_addresses)
|
||||
.into();
|
||||
BeefyAuthoritySet { id, len, root }
|
||||
BeefyAuthoritySet { id, len, keyset_commitment }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ use sp_runtime::{
|
||||
use crate as pallet_beefy_mmr;
|
||||
|
||||
pub use sp_consensus_beefy::{
|
||||
crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID,
|
||||
ecdsa_crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID,
|
||||
};
|
||||
|
||||
impl_opaque_keys! {
|
||||
|
||||
@@ -119,7 +119,7 @@ fn should_contain_valid_leaf_data() {
|
||||
beefy_next_authority_set: BeefyNextAuthoritySet {
|
||||
id: 2,
|
||||
len: 2,
|
||||
root: array_bytes::hex_n_into_unchecked(
|
||||
keyset_commitment: array_bytes::hex_n_into_unchecked(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5"
|
||||
)
|
||||
},
|
||||
@@ -144,7 +144,7 @@ fn should_contain_valid_leaf_data() {
|
||||
beefy_next_authority_set: BeefyNextAuthoritySet {
|
||||
id: 3,
|
||||
len: 2,
|
||||
root: array_bytes::hex_n_into_unchecked(
|
||||
keyset_commitment: array_bytes::hex_n_into_unchecked(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5"
|
||||
)
|
||||
},
|
||||
@@ -167,12 +167,12 @@ fn should_update_authorities() {
|
||||
let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>(
|
||||
"176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96",
|
||||
);
|
||||
assert_eq!(want, auth_set.root);
|
||||
assert_eq!(want, auth_set.keyset_commitment);
|
||||
|
||||
// next authority set should have same validators but different id
|
||||
assert_eq!(1, next_auth_set.id);
|
||||
assert_eq!(auth_set.len, next_auth_set.len);
|
||||
assert_eq!(auth_set.root, next_auth_set.root);
|
||||
assert_eq!(auth_set.keyset_commitment, next_auth_set.keyset_commitment);
|
||||
|
||||
let announced_set = next_auth_set;
|
||||
init_block(1);
|
||||
@@ -188,7 +188,7 @@ fn should_update_authorities() {
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5",
|
||||
);
|
||||
assert_eq!(2, next_auth_set.len);
|
||||
assert_eq!(want, next_auth_set.root);
|
||||
assert_eq!(want, next_auth_set.keyset_commitment);
|
||||
|
||||
let announced_set = next_auth_set;
|
||||
init_block(2);
|
||||
@@ -204,6 +204,6 @@ fn should_update_authorities() {
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5",
|
||||
);
|
||||
assert_eq!(2, next_auth_set.len);
|
||||
assert_eq!(want, next_auth_set.root);
|
||||
assert_eq!(want, next_auth_set.keyset_commitment);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ use frame_support::{
|
||||
};
|
||||
use frame_system::pallet_prelude::BlockNumberFor;
|
||||
use log::{error, info};
|
||||
use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE};
|
||||
use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE as BEEFY_KEY_TYPE};
|
||||
use sp_runtime::{
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
|
||||
@@ -172,7 +172,7 @@ where
|
||||
let (equivocation_proof, key_owner_proof) = evidence;
|
||||
|
||||
// Check the membership proof to extract the offender's id
|
||||
let key = (KEY_TYPE, equivocation_proof.offender_id().clone());
|
||||
let key = (BEEFY_KEY_TYPE, equivocation_proof.offender_id().clone());
|
||||
let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?;
|
||||
|
||||
// Check if the offence has already been reported, and if so then we can discard the report.
|
||||
@@ -206,7 +206,7 @@ where
|
||||
let validator_set_count = key_owner_proof.validator_count();
|
||||
|
||||
// Validate the key ownership proof extracting the id of the offender.
|
||||
let offender = P::check_proof((KEY_TYPE, offender), key_owner_proof)
|
||||
let offender = P::check_proof((BEEFY_KEY_TYPE, offender), key_owner_proof)
|
||||
.ok_or(Error::<T>::InvalidKeyOwnershipProof)?;
|
||||
|
||||
// Validate equivocation proof (check votes are different and signatures are valid).
|
||||
|
||||
@@ -39,7 +39,7 @@ use sp_staking::{EraIndex, SessionIndex};
|
||||
use crate as pallet_beefy;
|
||||
|
||||
pub use sp_consensus_beefy::{
|
||||
crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature},
|
||||
ecdsa_crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature},
|
||||
ConsensusLog, EquivocationProof, BEEFY_ENGINE_ID,
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::vec;
|
||||
use codec::Encode;
|
||||
use sp_consensus_beefy::{
|
||||
check_equivocation_proof, generate_equivocation_proof, known_payloads::MMR_ROOT_ID,
|
||||
Keyring as BeefyKeyring, Payload, ValidatorSet,
|
||||
Keyring as BeefyKeyring, Payload, ValidatorSet, KEY_TYPE as BEEFY_KEY_TYPE,
|
||||
};
|
||||
|
||||
use sp_runtime::DigestItem;
|
||||
@@ -297,8 +297,7 @@ fn report_equivocation_current_set_works() {
|
||||
);
|
||||
|
||||
// create the key ownership proof
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
// report the equivocation and the tx should be dispatched successfully
|
||||
assert_ok!(Beefy::report_equivocation_unsigned(
|
||||
@@ -354,8 +353,7 @@ fn report_equivocation_old_set_works() {
|
||||
let equivocation_key = &authorities[equivocation_authority_index];
|
||||
|
||||
// create the key ownership proof in the "old" set
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
start_era(2);
|
||||
|
||||
@@ -436,8 +434,7 @@ fn report_equivocation_invalid_set_id() {
|
||||
let equivocation_key = &authorities[equivocation_authority_index];
|
||||
let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap();
|
||||
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]);
|
||||
let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]);
|
||||
@@ -475,8 +472,7 @@ fn report_equivocation_invalid_session() {
|
||||
let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap();
|
||||
|
||||
// generate a key ownership proof at current era set id
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
start_era(2);
|
||||
|
||||
@@ -520,7 +516,7 @@ fn report_equivocation_invalid_key_owner_proof() {
|
||||
|
||||
// generate a key ownership proof for the authority at index 1
|
||||
let invalid_key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &invalid_owner_key)).unwrap();
|
||||
Historical::prove((BEEFY_KEY_TYPE, &invalid_owner_key)).unwrap();
|
||||
|
||||
let equivocation_authority_index = 0;
|
||||
let equivocation_key = &authorities[equivocation_authority_index];
|
||||
@@ -568,8 +564,7 @@ fn report_equivocation_invalid_equivocation_proof() {
|
||||
let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap();
|
||||
|
||||
// generate a key ownership proof at set id in era 1
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
let assert_invalid_equivocation_proof = |equivocation_proof| {
|
||||
assert_err!(
|
||||
@@ -649,8 +644,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() {
|
||||
(block_num, payload2, set_id, &equivocation_keyring),
|
||||
);
|
||||
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
let call = Call::report_equivocation_unsigned {
|
||||
equivocation_proof: Box::new(equivocation_proof.clone()),
|
||||
@@ -755,8 +749,7 @@ fn valid_equivocation_reports_dont_pay_fees() {
|
||||
);
|
||||
|
||||
// create the key ownership proof.
|
||||
let key_owner_proof =
|
||||
Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap();
|
||||
let key_owner_proof = Historical::prove((BEEFY_KEY_TYPE, &equivocation_key)).unwrap();
|
||||
|
||||
// check the dispatch info for the call.
|
||||
let info = Call::<Test>::report_equivocation_unsigned {
|
||||
|
||||
@@ -54,4 +54,7 @@ full_crypto = [
|
||||
|
||||
# This feature adds BLS crypto primitives. It should not be used in production since
|
||||
# the BLS implementation and interface may still be subject to significant change.
|
||||
bls-experimental = [ "sp-core/bls-experimental" ]
|
||||
bls-experimental = [
|
||||
"sp-core/bls-experimental",
|
||||
"sp-io/bls-experimental",
|
||||
]
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! BLS12-377 crypto applications.
|
||||
use crate::{KeyTypeId, RuntimePublic};
|
||||
|
||||
pub use sp_core::bls::bls377::*;
|
||||
|
||||
@@ -26,3 +27,30 @@ mod app {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub use app::Pair as AppPair;
|
||||
pub use app::{Public as AppPublic, Signature as AppSignature};
|
||||
|
||||
impl RuntimePublic for Public {
|
||||
type Signature = Signature;
|
||||
|
||||
/// Dummy implementation. Returns an empty vector.
|
||||
fn all(_key_type: KeyTypeId) -> Vec<Self> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn generate_pair(key_type: KeyTypeId, seed: Option<Vec<u8>>) -> Self {
|
||||
sp_io::crypto::bls377_generate(key_type, seed)
|
||||
}
|
||||
|
||||
/// Dummy implementation. Returns `None`.
|
||||
fn sign<M: AsRef<[u8]>>(&self, _key_type: KeyTypeId, _msg: &M) -> Option<Self::Signature> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Dummy implementation. Returns `false`.
|
||||
fn verify<M: AsRef<[u8]>>(&self, _msg: &M, _signature: &Self::Signature) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
sp_core::crypto::ByteArray::to_raw_vec(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ lazy_static = "1.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
array-bytes = "6.1"
|
||||
sp-keystore = { version = "0.27.0", path = "../../keystore" }
|
||||
w3f-bls = { version = "0.1.3", features = ["std"]}
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
@@ -42,7 +42,6 @@ std = [
|
||||
"sp-mmr-primitives/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"sp-keystore/std"
|
||||
]
|
||||
|
||||
# Serde support without relying on std features.
|
||||
@@ -53,3 +52,10 @@ serde = [
|
||||
"sp-core/serde",
|
||||
"sp-runtime/serde",
|
||||
]
|
||||
|
||||
# This feature adds BLS crypto primitives. It should not be used in production since
|
||||
# the BLS implementation and interface may still be subject to significant change.
|
||||
bls-experimental = [
|
||||
"sp-core/bls-experimental",
|
||||
"sp-application-crypto/bls-experimental",
|
||||
]
|
||||
|
||||
@@ -249,30 +249,60 @@ impl<N, S> From<SignedCommitment<N, S>> for VersionedFinalityProof<N, S> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::{crypto, known_payloads, KEY_TYPE};
|
||||
use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads};
|
||||
use codec::Decode;
|
||||
use sp_core::{keccak_256, Pair};
|
||||
use sp_keystore::{testing::MemoryKeystore, KeystorePtr};
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
use crate::bls_crypto::Signature as BlsSignature;
|
||||
|
||||
type TestCommitment = Commitment<u128>;
|
||||
type TestSignedCommitment = SignedCommitment<u128, crypto::Signature>;
|
||||
type TestVersionedFinalityProof = VersionedFinalityProof<u128, crypto::Signature>;
|
||||
|
||||
const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment");
|
||||
|
||||
// The mock signatures are equivalent to the ones produced by the BEEFY keystore
|
||||
fn mock_signatures() -> (crypto::Signature, crypto::Signature) {
|
||||
let store: KeystorePtr = MemoryKeystore::new().into();
|
||||
// Types for bls-less commitment
|
||||
type TestEcdsaSignedCommitment = SignedCommitment<u128, EcdsaSignature>;
|
||||
type TestVersionedFinalityProof = VersionedFinalityProof<u128, EcdsaSignature>;
|
||||
|
||||
// Types for commitment supporting aggregatable bls signature
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
#[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)]
|
||||
struct BlsAggregatableSignature(BlsSignature);
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
#[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)]
|
||||
struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature);
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
type TestBlsSignedCommitment = SignedCommitment<u128, EcdsaBlsSignaturePair>;
|
||||
|
||||
// Generates mock aggregatable ecdsa signature for generating test commitment
|
||||
// BLS signatures
|
||||
fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) {
|
||||
let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
|
||||
store.insert(KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap();
|
||||
|
||||
let msg = keccak_256(b"This is the first message");
|
||||
let sig1 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap();
|
||||
let sig1 = alice.sign_prehashed(&msg);
|
||||
|
||||
let msg = keccak_256(b"This is the second message");
|
||||
let sig2 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap();
|
||||
let sig2 = alice.sign_prehashed(&msg);
|
||||
|
||||
(sig1.into(), sig2.into())
|
||||
}
|
||||
|
||||
// Generates mock aggregatable bls signature for generating test commitment
|
||||
// BLS signatures
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn mock_bls_signatures() -> (BlsSignature, BlsSignature) {
|
||||
let alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap();
|
||||
|
||||
let msg = b"This is the first message";
|
||||
let sig1 = alice.sign(msg);
|
||||
|
||||
let msg = b"This is the second message";
|
||||
let sig2 = alice.sign(msg);
|
||||
|
||||
(sig1.into(), sig2.into())
|
||||
}
|
||||
@@ -300,26 +330,26 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_commitment_encode_decode() {
|
||||
fn signed_commitment_encode_decode_ecdsa() {
|
||||
// given
|
||||
let payload =
|
||||
Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode());
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let sigs = mock_signatures();
|
||||
let ecdsa_sigs = mock_ecdsa_signatures();
|
||||
|
||||
let signed = SignedCommitment {
|
||||
commitment,
|
||||
signatures: vec![None, None, Some(sigs.0), Some(sigs.1)],
|
||||
let ecdsa_signed = SignedCommitment {
|
||||
commitment: commitment.clone(),
|
||||
signatures: vec![None, None, Some(ecdsa_sigs.0.clone()), Some(ecdsa_sigs.1.clone())],
|
||||
};
|
||||
|
||||
// when
|
||||
let encoded = codec::Encode::encode(&signed);
|
||||
let decoded = TestSignedCommitment::decode(&mut &*encoded);
|
||||
let encoded = codec::Encode::encode(&ecdsa_signed);
|
||||
let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded);
|
||||
|
||||
// then
|
||||
assert_eq!(decoded, Ok(signed));
|
||||
assert_eq!(decoded, Ok(ecdsa_signed));
|
||||
assert_eq!(
|
||||
encoded,
|
||||
array_bytes::hex2bytes_unchecked(
|
||||
@@ -334,6 +364,44 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn signed_commitment_encode_decode_ecdsa_n_bls() {
|
||||
// given
|
||||
let payload =
|
||||
Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode());
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let ecdsa_sigs = mock_ecdsa_signatures();
|
||||
|
||||
//including bls signature
|
||||
let bls_signed_msgs = mock_bls_signatures();
|
||||
|
||||
let ecdsa_and_bls_signed = SignedCommitment {
|
||||
commitment,
|
||||
signatures: vec![
|
||||
None,
|
||||
None,
|
||||
Some(EcdsaBlsSignaturePair(ecdsa_sigs.0, bls_signed_msgs.0)),
|
||||
Some(EcdsaBlsSignaturePair(ecdsa_sigs.1, bls_signed_msgs.1)),
|
||||
],
|
||||
};
|
||||
|
||||
//when
|
||||
let encoded = codec::Encode::encode(&ecdsa_and_bls_signed);
|
||||
let decoded = TestBlsSignedCommitment::decode(&mut &*encoded);
|
||||
|
||||
// then
|
||||
assert_eq!(decoded, Ok(ecdsa_and_bls_signed));
|
||||
assert_eq!(
|
||||
encoded,
|
||||
array_bytes::hex2bytes_unchecked(
|
||||
"046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01667603fc041cf9d7147d22bf54b15e5778893d6986b71a929747befd3b4d233fbe668bc480e8865116b94db46ca25a01e03c71955f2582604e415da68f2c3c406b9d5f4ad416230ec5453f05ac16a50d8d0923dfb0413cc956ae3fa6334465bd1f2cacec8e9cd606438390fe2a29dc052d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a00df61d3b2be0963eb6caa243cc505d327aec73e1bb7ffe9a14b1354b0c406792ac6d6f47c06987c15dec9993f43eefa001d866fe0850d986702c414840f0d9ec0fdc04832ef91ae37c8d49e2f573ca50cb37f152801d489a19395cb04e5fc8f2ab6954b58a3bcc40ef9b6409d2ff7ef07"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_commitment_count_signatures() {
|
||||
// given
|
||||
@@ -342,7 +410,7 @@ mod tests {
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let sigs = mock_signatures();
|
||||
let sigs = mock_ecdsa_signatures();
|
||||
|
||||
let mut signed = SignedCommitment {
|
||||
commitment,
|
||||
@@ -389,7 +457,7 @@ mod tests {
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let sigs = mock_signatures();
|
||||
let sigs = mock_ecdsa_signatures();
|
||||
|
||||
let signed = SignedCommitment {
|
||||
commitment,
|
||||
@@ -416,7 +484,7 @@ mod tests {
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let sigs = mock_signatures();
|
||||
let sigs = mock_ecdsa_signatures();
|
||||
|
||||
let signatures: Vec<Option<_>> = (0..1024)
|
||||
.into_iter()
|
||||
@@ -426,7 +494,7 @@ mod tests {
|
||||
|
||||
// when
|
||||
let encoded = codec::Encode::encode(&signed);
|
||||
let decoded = TestSignedCommitment::decode(&mut &*encoded);
|
||||
let decoded = TestEcdsaSignedCommitment::decode(&mut &*encoded);
|
||||
|
||||
// then
|
||||
assert_eq!(decoded, Ok(signed));
|
||||
|
||||
@@ -51,7 +51,7 @@ use sp_runtime::traits::{Hash, Keccak256, NumberFor};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// Key type for BEEFY module.
|
||||
pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef");
|
||||
pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BEEFY;
|
||||
|
||||
/// Trait representing BEEFY authority id, including custom signature verification.
|
||||
///
|
||||
@@ -63,23 +63,21 @@ pub trait BeefyAuthorityId<MsgHash: Hash>: RuntimeAppPublic {
|
||||
fn verify(&self, signature: &<Self as RuntimeAppPublic>::Signature, msg: &[u8]) -> bool;
|
||||
}
|
||||
|
||||
/// BEEFY cryptographic types
|
||||
/// BEEFY cryptographic types for ECDSA crypto
|
||||
///
|
||||
/// This module basically introduces three crypto types:
|
||||
/// - `crypto::Pair`
|
||||
/// - `crypto::Public`
|
||||
/// - `crypto::Signature`
|
||||
/// This module basically introduces four crypto types:
|
||||
/// - `ecdsa_crypto::Pair`
|
||||
/// - `ecdsa_crypto::Public`
|
||||
/// - `ecdsa_crypto::Signature`
|
||||
/// - `ecdsa_crypto::AuthorityId`
|
||||
///
|
||||
/// Your code should use the above types as concrete types for all crypto related
|
||||
/// functionality.
|
||||
///
|
||||
/// The current underlying crypto scheme used is ECDSA. This can be changed,
|
||||
/// without affecting code restricted against the above listed crypto types.
|
||||
pub mod crypto {
|
||||
use super::{BeefyAuthorityId, Hash, RuntimeAppPublic};
|
||||
pub mod ecdsa_crypto {
|
||||
use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE};
|
||||
use sp_application_crypto::{app_crypto, ecdsa};
|
||||
use sp_core::crypto::Wraps;
|
||||
app_crypto!(ecdsa, crate::KEY_TYPE);
|
||||
app_crypto!(ecdsa, BEEFY_KEY_TYPE);
|
||||
|
||||
/// Identity of a BEEFY authority using ECDSA as its crypto.
|
||||
pub type AuthorityId = Public;
|
||||
@@ -104,6 +102,44 @@ pub mod crypto {
|
||||
}
|
||||
}
|
||||
|
||||
/// BEEFY cryptographic types for BLS crypto
|
||||
///
|
||||
/// This module basically introduces four crypto types:
|
||||
/// - `bls_crypto::Pair`
|
||||
/// - `bls_crypto::Public`
|
||||
/// - `bls_crypto::Signature`
|
||||
/// - `bls_crypto::AuthorityId`
|
||||
///
|
||||
/// Your code should use the above types as concrete types for all crypto related
|
||||
/// functionality.
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
pub mod bls_crypto {
|
||||
use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE};
|
||||
use sp_application_crypto::{app_crypto, bls377};
|
||||
use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _};
|
||||
app_crypto!(bls377, BEEFY_KEY_TYPE);
|
||||
|
||||
/// Identity of a BEEFY authority using BLS as its crypto.
|
||||
pub type AuthorityId = Public;
|
||||
|
||||
/// Signature for a BEEFY authority using BLS as its crypto.
|
||||
pub type AuthoritySignature = Signature;
|
||||
|
||||
impl<MsgHash: Hash> BeefyAuthorityId<MsgHash> for AuthorityId
|
||||
where
|
||||
<MsgHash as Hash>::Output: Into<[u8; 32]>,
|
||||
{
|
||||
fn verify(&self, signature: &<Self as RuntimeAppPublic>::Signature, msg: &[u8]) -> bool {
|
||||
// `w3f-bls` library uses IETF hashing standard and as such does not exposes
|
||||
// a choice of hash to field function.
|
||||
// We are directly calling into the library to avoid introducing new host call.
|
||||
// and because BeefyAuthorityId::verify is being called in the runtime so we don't have
|
||||
|
||||
BlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The `ConsensusEngineId` of BEEFY.
|
||||
pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF";
|
||||
|
||||
@@ -304,14 +340,15 @@ impl OpaqueKeyOwnershipProof {
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API necessary for BEEFY voters.
|
||||
#[api_version(2)]
|
||||
pub trait BeefyApi
|
||||
#[api_version(3)]
|
||||
pub trait BeefyApi<AuthorityId> where
|
||||
AuthorityId : Codec + RuntimeAppPublic,
|
||||
{
|
||||
/// Return the block number where BEEFY consensus is enabled/started
|
||||
fn beefy_genesis() -> Option<NumberFor<Block>>;
|
||||
|
||||
/// Return the current active BEEFY validator set
|
||||
fn validator_set() -> Option<ValidatorSet<crypto::AuthorityId>>;
|
||||
fn validator_set() -> Option<ValidatorSet<AuthorityId>>;
|
||||
|
||||
/// Submits an unsigned extrinsic to report an equivocation. The caller
|
||||
/// must provide the equivocation proof and a key ownership proof
|
||||
@@ -323,7 +360,7 @@ sp_api::decl_runtime_apis! {
|
||||
/// hardcoded to return `None`). Only useful in an offchain context.
|
||||
fn submit_report_equivocation_unsigned_extrinsic(
|
||||
equivocation_proof:
|
||||
EquivocationProof<NumberFor<Block>, crypto::AuthorityId, crypto::Signature>,
|
||||
EquivocationProof<NumberFor<Block>, AuthorityId, <AuthorityId as RuntimeAppPublic>::Signature>,
|
||||
key_owner_proof: OpaqueKeyOwnershipProof,
|
||||
) -> Option<()>;
|
||||
|
||||
@@ -340,9 +377,10 @@ sp_api::decl_runtime_apis! {
|
||||
/// older states to be available.
|
||||
fn generate_key_ownership_proof(
|
||||
set_id: ValidatorSetId,
|
||||
authority_id: crypto::AuthorityId,
|
||||
authority_id: AuthorityId,
|
||||
) -> Option<OpaqueKeyOwnershipProof>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -366,14 +404,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn beefy_verify_works() {
|
||||
fn ecdsa_beefy_verify_works() {
|
||||
let msg = &b"test-message"[..];
|
||||
let (pair, _) = crypto::Pair::generate();
|
||||
let (pair, _) = ecdsa_crypto::Pair::generate();
|
||||
|
||||
let keccak_256_signature: crypto::Signature =
|
||||
let keccak_256_signature: ecdsa_crypto::Signature =
|
||||
pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into();
|
||||
|
||||
let blake2_256_signature: crypto::Signature =
|
||||
let blake2_256_signature: ecdsa_crypto::Signature =
|
||||
pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into();
|
||||
|
||||
// Verification works if same hashing function is used when signing and verifying.
|
||||
@@ -392,7 +430,7 @@ mod tests {
|
||||
));
|
||||
|
||||
// Other public key doesn't work
|
||||
let (other_pair, _) = crypto::Pair::generate();
|
||||
let (other_pair, _) = ecdsa_crypto::Pair::generate();
|
||||
assert!(!BeefyAuthorityId::<Keccak256>::verify(
|
||||
&other_pair.public(),
|
||||
&keccak_256_signature,
|
||||
@@ -404,4 +442,20 @@ mod tests {
|
||||
msg,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn bls_beefy_verify_works() {
|
||||
let msg = &b"test-message"[..];
|
||||
let (pair, _) = bls_crypto::Pair::generate();
|
||||
|
||||
let signature: bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into();
|
||||
|
||||
// Verification works if same hashing function is used when signing and verifying.
|
||||
assert!(BeefyAuthorityId::<Keccak256>::verify(&pair.public(), &signature, msg));
|
||||
|
||||
// Other public key doesn't work
|
||||
let (other_pair, _) = bls_crypto::Pair::generate();
|
||||
assert!(!BeefyAuthorityId::<Keccak256>::verify(&other_pair.public(), &signature, msg,));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
//! but we imagine they will be useful for other chains that either want to bridge with Polkadot
|
||||
//! or are completely standalone, but heavily inspired by Polkadot.
|
||||
|
||||
use crate::{crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID};
|
||||
use crate::{ecdsa_crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
@@ -102,7 +102,7 @@ impl MmrLeafVersion {
|
||||
/// Details of a BEEFY authority set.
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct BeefyAuthoritySet<MerkleRoot> {
|
||||
pub struct BeefyAuthoritySet<AuthoritySetCommitment> {
|
||||
/// Id of the set.
|
||||
///
|
||||
/// Id is required to correlate BEEFY signed commitments with the validator set.
|
||||
@@ -115,12 +115,19 @@ pub struct BeefyAuthoritySet<MerkleRoot> {
|
||||
/// of signatures. We put set length here, so that these clients can verify the minimal
|
||||
/// number of required signatures.
|
||||
pub len: u32,
|
||||
/// Merkle Root Hash built from BEEFY AuthorityIds.
|
||||
|
||||
/// Commitment(s) to BEEFY AuthorityIds.
|
||||
///
|
||||
/// This is used by Light Clients to confirm that the commitments are signed by the correct
|
||||
/// validator set. Light Clients using interactive protocol, might verify only subset of
|
||||
/// signatures, hence don't require the full list here (will receive inclusion proofs).
|
||||
pub root: MerkleRoot,
|
||||
///
|
||||
/// This could be Merkle Root Hash built from BEEFY ECDSA public keys and/or
|
||||
/// polynomial commitment to the polynomial interpolating BLS public keys
|
||||
/// which is used by APK proof based light clients to verify the validity
|
||||
/// of aggregated BLS keys using APK proofs.
|
||||
/// Multiple commitments can be tupled together.
|
||||
pub keyset_commitment: AuthoritySetCommitment,
|
||||
}
|
||||
|
||||
/// Details of the next BEEFY authority set.
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
|
||||
#![cfg(feature = "std")]
|
||||
|
||||
use crate::{crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage};
|
||||
use crate::{ecdsa_crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage};
|
||||
use codec::Encode;
|
||||
use sp_core::{ecdsa, keccak_256, Pair};
|
||||
use std::collections::HashMap;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
/// Set of test accounts using [`crate::crypto`] types.
|
||||
/// Set of test accounts using [`crate::ecdsa_crypto`] types.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)]
|
||||
pub enum Keyring {
|
||||
@@ -39,19 +39,19 @@ pub enum Keyring {
|
||||
|
||||
impl Keyring {
|
||||
/// Sign `msg`.
|
||||
pub fn sign(self, msg: &[u8]) -> crypto::Signature {
|
||||
pub fn sign(self, msg: &[u8]) -> ecdsa_crypto::Signature {
|
||||
// todo: use custom signature hashing type
|
||||
let msg = keccak_256(msg);
|
||||
ecdsa::Pair::from(self).sign_prehashed(&msg).into()
|
||||
}
|
||||
|
||||
/// Return key pair.
|
||||
pub fn pair(self) -> crypto::Pair {
|
||||
pub fn pair(self) -> ecdsa_crypto::Pair {
|
||||
ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into()
|
||||
}
|
||||
|
||||
/// Return public key.
|
||||
pub fn public(self) -> crypto::Public {
|
||||
pub fn public(self) -> ecdsa_crypto::Public {
|
||||
self.pair().public()
|
||||
}
|
||||
|
||||
@@ -61,19 +61,19 @@ impl Keyring {
|
||||
}
|
||||
|
||||
/// Get Keyring from public key.
|
||||
pub fn from_public(who: &crypto::Public) -> Option<Keyring> {
|
||||
Self::iter().find(|&k| &crypto::Public::from(k) == who)
|
||||
pub fn from_public(who: &ecdsa_crypto::Public) -> Option<Keyring> {
|
||||
Self::iter().find(|&k| &ecdsa_crypto::Public::from(k) == who)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref PRIVATE_KEYS: HashMap<Keyring, crypto::Pair> =
|
||||
static ref PRIVATE_KEYS: HashMap<Keyring, ecdsa_crypto::Pair> =
|
||||
Keyring::iter().map(|i| (i, i.pair())).collect();
|
||||
static ref PUBLIC_KEYS: HashMap<Keyring, crypto::Public> =
|
||||
static ref PUBLIC_KEYS: HashMap<Keyring, ecdsa_crypto::Public> =
|
||||
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect();
|
||||
}
|
||||
|
||||
impl From<Keyring> for crypto::Pair {
|
||||
impl From<Keyring> for ecdsa_crypto::Pair {
|
||||
fn from(k: Keyring) -> Self {
|
||||
k.pair()
|
||||
}
|
||||
@@ -85,7 +85,7 @@ impl From<Keyring> for ecdsa::Pair {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for crypto::Public {
|
||||
impl From<Keyring> for ecdsa_crypto::Public {
|
||||
fn from(k: Keyring) -> Self {
|
||||
(*PUBLIC_KEYS).get(&k).cloned().unwrap()
|
||||
}
|
||||
@@ -95,7 +95,7 @@ impl From<Keyring> for crypto::Public {
|
||||
pub fn generate_equivocation_proof(
|
||||
vote1: (u64, Payload, ValidatorSetId, &Keyring),
|
||||
vote2: (u64, Payload, ValidatorSetId, &Keyring),
|
||||
) -> EquivocationProof<u64, crypto::Public, crypto::Signature> {
|
||||
) -> EquivocationProof<u64, ecdsa_crypto::Public, ecdsa_crypto::Signature> {
|
||||
let signed_vote = |block_number: u64,
|
||||
payload: Payload,
|
||||
validator_set_id: ValidatorSetId,
|
||||
|
||||
@@ -37,18 +37,21 @@ use crate::commitment::{Commitment, SignedCommitment};
|
||||
/// Ethereum Mainnet), in a commit-reveal like scheme, where first we submit only the signed
|
||||
/// commitment witness and later on, the client picks only some signatures to verify at random.
|
||||
#[derive(Debug, PartialEq, Eq, codec::Encode, codec::Decode)]
|
||||
pub struct SignedCommitmentWitness<TBlockNumber, TMerkleRoot> {
|
||||
pub struct SignedCommitmentWitness<TBlockNumber, TSignatureAccumulator> {
|
||||
/// The full content of the commitment.
|
||||
pub commitment: Commitment<TBlockNumber>,
|
||||
|
||||
/// The bit vector of validators who signed the commitment.
|
||||
pub signed_by: Vec<bool>, // TODO [ToDr] Consider replacing with bitvec crate
|
||||
|
||||
/// A merkle root of signatures in the original signed commitment.
|
||||
pub signatures_merkle_root: TMerkleRoot,
|
||||
/// Either a merkle root of signatures in the original signed commitment or a single aggregated
|
||||
/// BLS signature aggregating all original signatures.
|
||||
pub signature_accumulator: TSignatureAccumulator,
|
||||
}
|
||||
|
||||
impl<TBlockNumber, TMerkleRoot> SignedCommitmentWitness<TBlockNumber, TMerkleRoot> {
|
||||
impl<TBlockNumber, TSignatureAccumulator>
|
||||
SignedCommitmentWitness<TBlockNumber, TSignatureAccumulator>
|
||||
{
|
||||
/// Convert [SignedCommitment] into [SignedCommitmentWitness].
|
||||
///
|
||||
/// This takes a [SignedCommitment], which contains full signatures
|
||||
@@ -57,53 +60,85 @@ impl<TBlockNumber, TMerkleRoot> SignedCommitmentWitness<TBlockNumber, TMerkleRoo
|
||||
/// and a merkle root of all signatures.
|
||||
///
|
||||
/// Returns the full list of signatures along with the witness.
|
||||
pub fn from_signed<TMerkelize, TSignature>(
|
||||
pub fn from_signed<TSignatureAggregator, TSignature>(
|
||||
signed: SignedCommitment<TBlockNumber, TSignature>,
|
||||
merkelize: TMerkelize,
|
||||
aggregator: TSignatureAggregator,
|
||||
) -> (Self, Vec<Option<TSignature>>)
|
||||
where
|
||||
TMerkelize: FnOnce(&[Option<TSignature>]) -> TMerkleRoot,
|
||||
TSignatureAggregator: FnOnce(&[Option<TSignature>]) -> TSignatureAccumulator,
|
||||
{
|
||||
let SignedCommitment { commitment, signatures } = signed;
|
||||
let signed_by = signatures.iter().map(|s| s.is_some()).collect();
|
||||
let signatures_merkle_root = merkelize(&signatures);
|
||||
let signature_accumulator = aggregator(&signatures);
|
||||
|
||||
(Self { commitment, signed_by, signatures_merkle_root }, signatures)
|
||||
(Self { commitment, signed_by, signature_accumulator }, signatures)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sp_core::{keccak_256, Pair};
|
||||
use sp_keystore::{testing::MemoryKeystore, KeystorePtr};
|
||||
|
||||
use super::*;
|
||||
use codec::Decode;
|
||||
|
||||
use crate::{crypto, known_payloads, Payload, KEY_TYPE};
|
||||
use crate::{ecdsa_crypto::Signature as EcdsaSignature, known_payloads, Payload};
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
use crate::bls_crypto::Signature as BlsSignature;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
use w3f_bls::{
|
||||
single_pop_aggregator::SignatureAggregatorAssumingPoP, Message, SerializableToBytes,
|
||||
Signed, TinyBLS377,
|
||||
};
|
||||
|
||||
type TestCommitment = Commitment<u128>;
|
||||
type TestSignedCommitment = SignedCommitment<u128, crypto::Signature>;
|
||||
type TestSignedCommitmentWitness =
|
||||
SignedCommitmentWitness<u128, Vec<Option<crypto::Signature>>>;
|
||||
|
||||
// Types for ecdsa signed commitment.
|
||||
type TestEcdsaSignedCommitment = SignedCommitment<u128, EcdsaSignature>;
|
||||
type TestEcdsaSignedCommitmentWitness =
|
||||
SignedCommitmentWitness<u128, Vec<Option<EcdsaSignature>>>;
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
#[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)]
|
||||
struct EcdsaBlsSignaturePair(EcdsaSignature, BlsSignature);
|
||||
|
||||
// types for commitment containing bls signature along side ecdsa signature
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
type TestBlsSignedCommitment = SignedCommitment<u128, EcdsaBlsSignaturePair>;
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
type TestBlsSignedCommitmentWitness = SignedCommitmentWitness<u128, Vec<u8>>;
|
||||
|
||||
// The mock signatures are equivalent to the ones produced by the BEEFY keystore
|
||||
fn mock_signatures() -> (crypto::Signature, crypto::Signature) {
|
||||
let store: KeystorePtr = MemoryKeystore::new().into();
|
||||
|
||||
fn mock_ecdsa_signatures() -> (EcdsaSignature, EcdsaSignature) {
|
||||
let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
|
||||
store.insert(KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap();
|
||||
|
||||
let msg = keccak_256(b"This is the first message");
|
||||
let sig1 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap();
|
||||
let sig1 = alice.sign_prehashed(&msg);
|
||||
|
||||
let msg = keccak_256(b"This is the second message");
|
||||
let sig2 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap();
|
||||
let sig2 = alice.sign_prehashed(&msg);
|
||||
|
||||
(sig1.into(), sig2.into())
|
||||
}
|
||||
|
||||
fn signed_commitment() -> TestSignedCommitment {
|
||||
// Generates mock aggregatable bls signature for generating test commitment
|
||||
// BLS signatures
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn mock_bls_signatures() -> (BlsSignature, BlsSignature) {
|
||||
let alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap();
|
||||
|
||||
let msg = b"This is the first message";
|
||||
let sig1 = alice.sign(msg);
|
||||
|
||||
let msg = b"This is the second message";
|
||||
let sig2 = alice.sign(msg);
|
||||
|
||||
(sig1.into(), sig2.into())
|
||||
}
|
||||
|
||||
fn ecdsa_signed_commitment() -> TestEcdsaSignedCommitment {
|
||||
let payload = Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
"Hello World!".as_bytes().to_vec(),
|
||||
@@ -111,35 +146,97 @@ mod tests {
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let sigs = mock_signatures();
|
||||
let sigs = mock_ecdsa_signatures();
|
||||
|
||||
SignedCommitment { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)] }
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn ecdsa_and_bls_signed_commitment() -> TestBlsSignedCommitment {
|
||||
let payload = Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
"Hello World!".as_bytes().to_vec(),
|
||||
);
|
||||
let commitment: TestCommitment =
|
||||
Commitment { payload, block_number: 5, validator_set_id: 0 };
|
||||
|
||||
let ecdsa_sigs = mock_ecdsa_signatures();
|
||||
let bls_sigs = mock_bls_signatures();
|
||||
|
||||
SignedCommitment {
|
||||
commitment,
|
||||
signatures: vec![
|
||||
None,
|
||||
None,
|
||||
Some(EcdsaBlsSignaturePair(ecdsa_sigs.0, bls_sigs.0)),
|
||||
Some(EcdsaBlsSignaturePair(ecdsa_sigs.1, bls_sigs.1)),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_convert_signed_commitment_to_witness() {
|
||||
// given
|
||||
let signed = signed_commitment();
|
||||
let signed = ecdsa_signed_commitment();
|
||||
|
||||
// when
|
||||
let (witness, signatures) =
|
||||
TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec());
|
||||
TestEcdsaSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec());
|
||||
|
||||
// then
|
||||
assert_eq!(witness.signatures_merkle_root, signatures);
|
||||
assert_eq!(witness.signature_accumulator, signatures);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
fn should_convert_dually_signed_commitment_to_witness() {
|
||||
// given
|
||||
let signed = ecdsa_and_bls_signed_commitment();
|
||||
|
||||
// when
|
||||
let (witness, _signatures) =
|
||||
// from signed take a function as the aggregator
|
||||
TestBlsSignedCommitmentWitness::from_signed::<_, _>(signed, |sigs| {
|
||||
// we are going to aggregate the signatures here
|
||||
let mut aggregatedsigs: SignatureAggregatorAssumingPoP<TinyBLS377> =
|
||||
SignatureAggregatorAssumingPoP::new(Message::new(b"", b"mock payload"));
|
||||
|
||||
for sig in sigs {
|
||||
match sig {
|
||||
Some(sig) => {
|
||||
let serialized_sig : Vec<u8> = (*sig.1).to_vec();
|
||||
aggregatedsigs.add_signature(
|
||||
&w3f_bls::Signature::<TinyBLS377>::from_bytes(
|
||||
serialized_sig.as_slice()
|
||||
).unwrap()
|
||||
);
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
(&aggregatedsigs).signature().to_bytes()
|
||||
});
|
||||
|
||||
// We can't use BlsSignature::try_from because it expected 112Bytes (CP (64) + BLS 48)
|
||||
// single signature while we are having a BLS aggregated signature corresponding to no CP.
|
||||
w3f_bls::Signature::<TinyBLS377>::from_bytes(witness.signature_accumulator.as_slice())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_encode_and_decode_witness() {
|
||||
// given
|
||||
let signed = signed_commitment();
|
||||
let (witness, _) = TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec());
|
||||
// Given
|
||||
let signed = ecdsa_signed_commitment();
|
||||
let (witness, _) = TestEcdsaSignedCommitmentWitness::from_signed::<_, _>(
|
||||
signed,
|
||||
|sigs: &[std::option::Option<EcdsaSignature>]| sigs.to_vec(),
|
||||
);
|
||||
|
||||
// when
|
||||
// When
|
||||
let encoded = codec::Encode::encode(&witness);
|
||||
let decoded = TestSignedCommitmentWitness::decode(&mut &*encoded);
|
||||
let decoded = TestEcdsaSignedCommitmentWitness::decode(&mut &*encoded);
|
||||
|
||||
// then
|
||||
// Then
|
||||
assert_eq!(decoded, Ok(witness));
|
||||
assert_eq!(
|
||||
encoded,
|
||||
|
||||
@@ -60,7 +60,6 @@ w3f-bls = { version = "0.1.3", default-features = false, optional = true}
|
||||
criterion = "0.4.0"
|
||||
serde_json = "1.0"
|
||||
sp-core-hashing-proc-macro = { version = "9.0.0", path = "./hashing/proc-macro" }
|
||||
hex-literal = "0.3.4"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
|
||||
@@ -34,7 +34,7 @@ use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes,
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey};
|
||||
|
||||
use sp_runtime_interface::pass_by::PassByInner;
|
||||
use sp_runtime_interface::pass_by::{self, PassBy, PassByInner};
|
||||
use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref};
|
||||
|
||||
/// BLS-377 specialized types
|
||||
@@ -165,6 +165,10 @@ impl<T> PassByInner for Public<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PassBy for Public<T> {
|
||||
type PassBy = pass_by::Inner<Self, [u8; PUBLIC_KEY_SERIALIZED_SIZE]>;
|
||||
}
|
||||
|
||||
impl<T> AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public<T> {
|
||||
fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] {
|
||||
&self.inner
|
||||
@@ -514,7 +518,6 @@ mod test {
|
||||
use super::*;
|
||||
use crate::crypto::DEV_PHRASE;
|
||||
use bls377::{Pair, Signature};
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
fn default_phrase_should_be_used() {
|
||||
@@ -529,7 +532,9 @@ mod test {
|
||||
// Only passes if the seed = (seed mod ScalarField)
|
||||
#[test]
|
||||
fn seed_and_derive_should_work() {
|
||||
let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00");
|
||||
let seed = array_bytes::hex2array_unchecked(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00",
|
||||
);
|
||||
let pair = Pair::from_seed(&seed);
|
||||
// we are using hash to field so this is not going to work
|
||||
// assert_eq!(pair.seed(), seed);
|
||||
@@ -537,25 +542,27 @@ mod test {
|
||||
let derived = pair.derive(path.into_iter(), None).ok().unwrap().0;
|
||||
assert_eq!(
|
||||
derived.to_raw_vec(),
|
||||
hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")
|
||||
array_bytes::hex2array_unchecked::<_, 32>(
|
||||
"a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vector_should_work() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
let pair = Pair::from_seed(&array_bytes::hex2array_unchecked(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||
));
|
||||
let public = pair.public();
|
||||
assert_eq!(
|
||||
public,
|
||||
Public::unchecked_from(hex!(
|
||||
Public::unchecked_from(array_bytes::hex2array_unchecked(
|
||||
"7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400"
|
||||
))
|
||||
);
|
||||
let message = b"";
|
||||
let signature =
|
||||
hex!("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"
|
||||
array_bytes::hex2array_unchecked("d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"
|
||||
);
|
||||
let signature = Signature::unchecked_from(signature);
|
||||
assert!(pair.sign(&message[..]) == signature);
|
||||
@@ -572,13 +579,13 @@ mod test {
|
||||
let public = pair.public();
|
||||
assert_eq!(
|
||||
public,
|
||||
Public::unchecked_from(hex!(
|
||||
Public::unchecked_from(array_bytes::hex2array_unchecked(
|
||||
"6dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780"
|
||||
))
|
||||
);
|
||||
let message = b"";
|
||||
let signature =
|
||||
hex!("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"
|
||||
array_bytes::hex2array_unchecked("bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"
|
||||
);
|
||||
let expected_signature = Signature::unchecked_from(signature);
|
||||
println!("signature is {:?}", pair.sign(&message[..]));
|
||||
@@ -603,12 +610,12 @@ mod test {
|
||||
assert_eq!(
|
||||
public,
|
||||
Public::unchecked_from(
|
||||
hex!(
|
||||
array_bytes::hex2array_unchecked(
|
||||
"754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080")
|
||||
)
|
||||
);
|
||||
let message =
|
||||
hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"
|
||||
array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"
|
||||
);
|
||||
let signature = pair.sign(&message[..]);
|
||||
println!("Correct signature: {:?}", signature);
|
||||
|
||||
@@ -1144,6 +1144,8 @@ pub mod key_types {
|
||||
pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco");
|
||||
/// Key type for Aura module, built-in. Identified as `aura`.
|
||||
pub const AURA: KeyTypeId = KeyTypeId(*b"aura");
|
||||
/// Key type for BEEFY module.
|
||||
pub const BEEFY: KeyTypeId = KeyTypeId(*b"beef");
|
||||
/// Key type for ImOnline module, built-in. Identified as `imon`.
|
||||
pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
|
||||
/// Key type for AuthorityDiscovery module, built-in. Identified as `audi`.
|
||||
|
||||
@@ -92,3 +92,9 @@ disable_allocator = []
|
||||
# host function to be supported by the host. Do *not* enable it for your
|
||||
# runtime without first upgrading your host client!
|
||||
improved_panic_error_reporting = []
|
||||
|
||||
# This feature adds BLS crypto primitives. It should not be used in production since
|
||||
# the BLS implementation and interface may still be subject to significant change.
|
||||
bls-experimental = [
|
||||
"sp-keystore/bls-experimental",
|
||||
]
|
||||
|
||||
@@ -103,6 +103,9 @@ use sp_core::{
|
||||
LogLevel, LogLevelFilter, OpaquePeerId, H256,
|
||||
};
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
use sp_core::bls377;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration};
|
||||
|
||||
@@ -1186,6 +1189,21 @@ pub trait Crypto {
|
||||
.map_err(|_| EcdsaVerifyError::BadSignature)?;
|
||||
Ok(pubkey.serialize())
|
||||
}
|
||||
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
/// Generate an `bls12-377` key for the given key type using an optional `seed` and
|
||||
/// store it in the keystore.
|
||||
///
|
||||
/// The `seed` needs to be a valid utf8.
|
||||
///
|
||||
/// Returns the public key.
|
||||
fn bls377_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> bls377::Public {
|
||||
let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!"));
|
||||
self.extension::<KeystoreExt>()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.bls377_generate_new(id, seed)
|
||||
.expect("`bls377_generate` failed")
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface that provides functions for hashing with different algorithms.
|
||||
|
||||
Reference in New Issue
Block a user