referrerpolicy=no-referrer-when-downgrade

cumulus_pallet_aura_ext/
signature_verifier.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5//! V3 scheduling signature verifier backed by parachain Aura authorities.
6//!
7//! Implements [`VerifySchedulingSignature`] for parachains running Aura: maps the relay slot
8//! at `internal_scheduling_parent` (supplied by the caller) to the parachain slot, looks up the
9//! eligible Aura author from this pallet's cached authority set, and verifies the 64-byte
10//! signature in [`SignedSchedulingInfo`] over the encoded `SchedulingInfoPayload`.
11
12use crate::{Authorities, Config};
13use codec::{Decode, Encode};
14use cumulus_primitives_core::{
15	relay_chain::RELAY_CHAIN_SLOT_DURATION_MILLIS, SignedSchedulingInfo, VerifySchedulingSignature,
16};
17use sp_application_crypto::RuntimeAppPublic;
18use sp_consensus_aura::Slot;
19
20/// Verifier for V3 [`SignedSchedulingInfo`] against parachain Aura authorities.
21///
22/// Wired by the parachain runtime as
23/// `type SchedulingSignatureVerifier = AuraSchedulingVerifier<Runtime>;` on
24/// [`cumulus_pallet_parachain_system::Config`]. The Aura crypto is taken from
25/// [`pallet_aura::Config::AuthorityId`].
26pub struct AuraSchedulingVerifier<T>(core::marker::PhantomData<T>);
27
28impl<T> VerifySchedulingSignature for AuraSchedulingVerifier<T>
29where
30	T: Config,
31	T: pallet_timestamp::Config,
32{
33	const V3_SCHEDULING_ENABLED: bool = true;
34
35	/// Verify that `signed_info` was produced by the Aura author eligible at the parachain slot
36	/// derived from `relay_slot` (the slot of the internal scheduling parent).
37	///
38	/// Returns `true` only when every step succeeds; all error paths return `false` (fail-closed)
39	/// so the PVF rejects the candidate without panicking on adversarial input.
40	fn verify(signed_info: &SignedSchedulingInfo, relay_slot: Slot) -> bool {
41		// 1. The relay slot at the internal scheduling parent gives the para slot that determines
42		//    the valid author.
43		let para_slot_duration: u64 =
44			match TryInto::<u64>::try_into(pallet_aura::Pallet::<T>::slot_duration()) {
45				Ok(d) if d > 0 => d,
46				_ => return false,
47			};
48
49		let para_slot: u64 = match u64::from(relay_slot)
50			.checked_mul(RELAY_CHAIN_SLOT_DURATION_MILLIS)
51			.map(|product| product / para_slot_duration)
52		{
53			Some(s) => s,
54			None => return false,
55		};
56
57		// 2. Look up the eligible Aura author.
58		let authorities = Authorities::<T>::get();
59		let author_idx = match pallet_aura::Pallet::<T>::slot_author_index(Slot::from(para_slot)) {
60			Some(idx) => idx as usize,
61			None => return false,
62		};
63		let author = match authorities.get(author_idx) {
64			Some(author) => author,
65			None => return false,
66		};
67
68		// 3. Decode the 64-byte signature blob as the authority's expected signature type and
69		//    verify over the encoded SchedulingInfoPayload.
70		let signature = match <T::AuthorityId as RuntimeAppPublic>::Signature::decode(
71			&mut &signed_info.signature[..],
72		) {
73			Ok(sig) => sig,
74			Err(e) => {
75				log::error!(
76					target: "aura-ext::scheduling-verifier",
77					"failed to decode scheduling signature: {e}",
78				);
79				return false;
80			},
81		};
82
83		author.verify(&signed_info.payload.encode(), &signature)
84	}
85}