mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 21:37:56 +00:00
Fix ecdsa_bls verify in BEEFY primitives (#2066)
BEEFY ECDSA signatures are on keccak has of the messages. As such we can not simply call `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` because that invokes ecdsa default verification which perfoms blake2 hash which we don't want. This bring up the second issue makes: This makes `sign` and `verify` function in `pair_crypto` useless, at least for BEEFY use case. Moreover, there is no obvious clean way to generate the signature given that pair_crypto does not exposes `sign_prehashed`. You could in theory query the keystore for the pair (could you?), invoke `to_raw` and re-generate each sub-pair and sign using each. But that sounds extremely anticlimactic and will be frow upon by auditors . So I appreciate any alternative suggestion. --------- Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: Robert Hambrock <roberthambrock@gmail.com>
This commit is contained in:
@@ -39,7 +39,13 @@ use sp_std::convert::TryFrom;
|
||||
/// ECDSA and BLS12-377 paired crypto scheme
|
||||
#[cfg(feature = "bls-experimental")]
|
||||
pub mod ecdsa_bls377 {
|
||||
use crate::{bls377, crypto::CryptoTypeId, ecdsa};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use crate::Hasher;
|
||||
use crate::{
|
||||
bls377,
|
||||
crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom},
|
||||
ecdsa,
|
||||
};
|
||||
|
||||
/// An identifier used to match public keys against BLS12-377 keys
|
||||
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7");
|
||||
@@ -71,6 +77,60 @@ pub mod ecdsa_bls377 {
|
||||
impl super::CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl Pair {
|
||||
/// Hashes the `message` with the specified [`Hasher`] before signing sith the ECDSA secret
|
||||
/// component.
|
||||
///
|
||||
/// The hasher does not affect the BLS12-377 component. This generates BLS12-377 Signature
|
||||
/// according to IETF standard.
|
||||
pub fn sign_with_hasher<H>(&self, message: &[u8]) -> Signature
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Into<[u8; 32]>,
|
||||
{
|
||||
let msg_hash = H::hash(message).into();
|
||||
|
||||
let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
|
||||
raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE]
|
||||
.copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref());
|
||||
raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..]
|
||||
.copy_from_slice(self.right.sign(message).as_ref());
|
||||
<Self as PairT>::Signature::unchecked_from(raw)
|
||||
}
|
||||
|
||||
/// Hashes the `message` with the specified [`Hasher`] before verifying with the ECDSA
|
||||
/// public component.
|
||||
///
|
||||
/// The hasher does not affect the the BLS12-377 component. This verifies whether the
|
||||
/// BLS12-377 signature was hashed and signed according to IETF standard
|
||||
pub fn verify_with_hasher<H>(sig: &Signature, message: &[u8], public: &Public) -> bool
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Into<[u8; 32]>,
|
||||
{
|
||||
let msg_hash = H::hash(message).into();
|
||||
|
||||
let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else {
|
||||
return false
|
||||
};
|
||||
let Ok(left_sig) = sig.0[0..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else {
|
||||
return false
|
||||
};
|
||||
if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) {
|
||||
return false
|
||||
}
|
||||
|
||||
let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else {
|
||||
return false
|
||||
};
|
||||
let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else {
|
||||
return false
|
||||
};
|
||||
bls377::Pair::verify(&right_sig, message.as_ref(), &right_pub)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Secure seed length.
|
||||
@@ -455,12 +515,12 @@ where
|
||||
#[cfg(all(test, feature = "bls-experimental"))]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::crypto::DEV_PHRASE;
|
||||
use crate::{crypto::DEV_PHRASE, KeccakHasher};
|
||||
use ecdsa_bls377::{Pair, Signature};
|
||||
|
||||
use crate::{bls377, ecdsa};
|
||||
#[test]
|
||||
|
||||
#[test]
|
||||
fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() {
|
||||
assert_eq!(
|
||||
<Pair as PairT>::Public::LEN,
|
||||
@@ -617,6 +677,16 @@ mod test {
|
||||
assert_eq!(cmp, public);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sign_and_verify_with_hasher_works() {
|
||||
let pair =
|
||||
Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
|
||||
let message = b"Something important";
|
||||
let signature = pair.sign_with_hasher::<KeccakHasher>(&message[..]);
|
||||
|
||||
assert!(Pair::verify_with_hasher::<KeccakHasher>(&signature, &message[..], &pair.public()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signature_serialization_works() {
|
||||
let pair =
|
||||
|
||||
Reference in New Issue
Block a user