mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 21:41:12 +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:
@@ -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