mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 17:51:09 +00:00
VRF refactory (#13889)
* First iteration to encapsulate schnorrkel and merlin usage * Remove schnorkel direct dependency from BABE pallet * Remove schnorrkel direct dependency from BABE client * Trivial renaming for VrfTranscript data and value * Better errors * Expose a function to get a schnorrkel friendly transcript * Keep the vrf signature stuff together (preventing some clones around) * Fix tests * Remove vrf agnostic transcript and define it as an associated type for VrfSigner and VrfVerifier * Fix babe pallet mock * Inner types are required to be public for polkadot * Update client/consensus/babe/src/verification.rs Co-authored-by: Koute <koute@users.noreply.github.com> * Nit * Remove Deref implementations * make_bytes as a method * Trigger CI --------- Co-authored-by: Koute <koute@users.noreply.github.com>
This commit is contained in:
@@ -18,8 +18,9 @@
|
||||
|
||||
//! Verification for BABE headers.
|
||||
use crate::{
|
||||
authorship::{calculate_primary_threshold, check_primary_threshold, secondary_slot_author},
|
||||
babe_err, find_pre_digest, BlockT, Epoch, Error, LOG_TARGET,
|
||||
authorship::{calculate_primary_threshold, secondary_slot_author},
|
||||
babe_err, find_pre_digest, BlockT, Epoch, Error, AUTHORING_SCORE_LENGTH,
|
||||
AUTHORING_SCORE_VRF_CONTEXT, LOG_TARGET,
|
||||
};
|
||||
use log::{debug, trace};
|
||||
use sc_consensus_epochs::Epoch as EpochT;
|
||||
@@ -32,7 +33,10 @@ use sp_consensus_babe::{
|
||||
make_transcript, AuthorityId, AuthorityPair, AuthoritySignature,
|
||||
};
|
||||
use sp_consensus_slots::Slot;
|
||||
use sp_core::{ByteArray, Pair};
|
||||
use sp_core::{
|
||||
crypto::{VrfVerifier, Wraps},
|
||||
Pair,
|
||||
};
|
||||
use sp_runtime::{traits::Header, DigestItem};
|
||||
|
||||
/// BABE verification parameters
|
||||
@@ -155,7 +159,7 @@ fn check_primary_header<B: BlockT + Sized>(
|
||||
epoch: &Epoch,
|
||||
c: (u64, u64),
|
||||
) -> Result<(), Error<B>> {
|
||||
let author = &epoch.authorities[pre_digest.authority_index as usize].0;
|
||||
let authority_id = &epoch.authorities[pre_digest.authority_index as usize].0;
|
||||
let mut epoch_index = epoch.epoch_index;
|
||||
|
||||
if epoch.end_slot() <= pre_digest.slot {
|
||||
@@ -163,28 +167,34 @@ fn check_primary_header<B: BlockT + Sized>(
|
||||
epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index;
|
||||
}
|
||||
|
||||
if AuthorityPair::verify(&signature, pre_hash, author) {
|
||||
let (inout, _) = {
|
||||
let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index);
|
||||
|
||||
schnorrkel::PublicKey::from_bytes(author.as_slice())
|
||||
.and_then(|p| {
|
||||
p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof)
|
||||
})
|
||||
.map_err(|s| babe_err(Error::VRFVerificationFailed(s)))?
|
||||
};
|
||||
|
||||
let threshold =
|
||||
calculate_primary_threshold(c, &epoch.authorities, pre_digest.authority_index as usize);
|
||||
|
||||
if !check_primary_threshold(&inout, threshold) {
|
||||
return Err(babe_err(Error::VRFVerificationOfBlockFailed(author.clone(), threshold)))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(babe_err(Error::BadSignature(pre_hash)))
|
||||
if !AuthorityPair::verify(&signature, pre_hash, authority_id) {
|
||||
return Err(babe_err(Error::BadSignature(pre_hash)))
|
||||
}
|
||||
|
||||
let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index);
|
||||
|
||||
if !authority_id.as_inner_ref().vrf_verify(&transcript, &pre_digest.vrf_signature) {
|
||||
return Err(babe_err(Error::VrfVerificationFailed))
|
||||
}
|
||||
|
||||
let threshold =
|
||||
calculate_primary_threshold(c, &epoch.authorities, pre_digest.authority_index as usize);
|
||||
|
||||
let score = authority_id
|
||||
.as_inner_ref()
|
||||
.make_bytes::<[u8; AUTHORING_SCORE_LENGTH]>(
|
||||
AUTHORING_SCORE_VRF_CONTEXT,
|
||||
&transcript,
|
||||
&pre_digest.vrf_signature.output,
|
||||
)
|
||||
.map(u128::from_le_bytes)
|
||||
.map_err(|_| babe_err(Error::VrfVerificationFailed))?;
|
||||
|
||||
if score >= threshold {
|
||||
return Err(babe_err(Error::VrfThresholdExceeded(threshold)))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check a secondary slot proposal header. We validate that the given header is
|
||||
@@ -197,8 +207,7 @@ fn check_secondary_plain_header<B: BlockT>(
|
||||
signature: AuthoritySignature,
|
||||
epoch: &Epoch,
|
||||
) -> Result<(), Error<B>> {
|
||||
// check the signature is valid under the expected authority and
|
||||
// chain state.
|
||||
// check the signature is valid under the expected authority and chain state.
|
||||
let expected_author =
|
||||
secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness)
|
||||
.ok_or(Error::NoSecondaryAuthorExpected)?;
|
||||
@@ -209,11 +218,11 @@ fn check_secondary_plain_header<B: BlockT>(
|
||||
return Err(Error::InvalidAuthor(expected_author.clone(), author.clone()))
|
||||
}
|
||||
|
||||
if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::BadSignature(pre_hash))
|
||||
if !AuthorityPair::verify(&signature, pre_hash.as_ref(), author) {
|
||||
return Err(Error::BadSignature(pre_hash))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check a secondary VRF slot proposal header.
|
||||
@@ -223,8 +232,7 @@ fn check_secondary_vrf_header<B: BlockT>(
|
||||
signature: AuthoritySignature,
|
||||
epoch: &Epoch,
|
||||
) -> Result<(), Error<B>> {
|
||||
// check the signature is valid under the expected authority and
|
||||
// chain state.
|
||||
// check the signature is valid under the expected authority and chain state.
|
||||
let expected_author =
|
||||
secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness)
|
||||
.ok_or(Error::NoSecondaryAuthorExpected)?;
|
||||
@@ -241,15 +249,15 @@ fn check_secondary_vrf_header<B: BlockT>(
|
||||
epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index;
|
||||
}
|
||||
|
||||
if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) {
|
||||
let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index);
|
||||
|
||||
schnorrkel::PublicKey::from_bytes(author.as_slice())
|
||||
.and_then(|p| p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof))
|
||||
.map_err(|s| babe_err(Error::VRFVerificationFailed(s)))?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::BadSignature(pre_hash))
|
||||
if !AuthorityPair::verify(&signature, pre_hash.as_ref(), author) {
|
||||
return Err(Error::BadSignature(pre_hash))
|
||||
}
|
||||
|
||||
let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index);
|
||||
|
||||
if !author.as_inner_ref().vrf_verify(&transcript, &pre_digest.vrf_signature) {
|
||||
return Err(Error::VrfVerificationFailed)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user