Add abstraction for the embedded elliptic curve keys

It's minimal but still pleasant.
This commit is contained in:
Luke Parker
2025-09-02 10:40:57 -04:00
parent 72fefb3d85
commit 74bad049a7
17 changed files with 286 additions and 228 deletions

View File

@@ -21,22 +21,22 @@ bitvec = { version = "1", default-features = false, features = ["alloc", "serde"
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
scale-info = { version = "2", default-features = false, features = ["derive", "bit-vec"] }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
serai-primitives = { path = "../primitives", default-features = false, features = ["non_canonical_scale_derivations"] }
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
[dev-dependencies]
#pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
#pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
#sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "74839cba4a7f48023080215e5194fd6ab7e270e5", default-features = false }
#sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "ece373ca1e8aaee67844eebcca28b5e016136dba", default-features = false }
#ciphersuite = { path = "../../../crypto/ciphersuite", default-features = false, features = ["std"] }
#dalek-ff-group = { path = "../../../crypto/dalek-ff-group", default-features = false, features = ["std"] }

View File

@@ -0,0 +1,53 @@
use sp_core::{Encode, sr25519::Public};
use serai_primitives::{crypto::SignedEmbeddedEllipticCurveKeys, network_id::*};
use frame_support::storage::StorageDoubleMap;
pub(crate) trait EmbeddedEllipticCurveKeysStorage {
/// An opaque map storing keys on an embedded elliptic curve.
type EmbeddedEllipticCurveKeys: StorageDoubleMap<
ExternalNetworkId,
Public,
serai_primitives::crypto::EmbeddedEllipticCurveKeys,
Query = Option<serai_primitives::crypto::EmbeddedEllipticCurveKeys>,
>;
}
/// An interface for managing validators' embedded elliptic curve keys.
pub(crate) trait EmbeddedEllipticCurveKeys {
/// Set a validator's embedded elliptic curve keys for an external network.
fn set_embedded_elliptic_curve_keys(
validator: Public,
keys: SignedEmbeddedEllipticCurveKeys,
) -> Result<(), ()>;
/// Check if a validator still needs to set embedded elliptic curve keys.
fn still_needs_to_set_embedded_elliptic_curve_keys(network: NetworkId, validator: Public)
-> bool;
}
impl<S: EmbeddedEllipticCurveKeysStorage> EmbeddedEllipticCurveKeys for S {
/// Set a validator's embedded elliptic curve keys, for an external network.
fn set_embedded_elliptic_curve_keys(
validator: Public,
keys: SignedEmbeddedEllipticCurveKeys,
) -> Result<(), ()> {
let keys = keys.verify(validator.into()).ok_or(())?;
S::EmbeddedEllipticCurveKeys::set(keys.network(), validator, Some(keys));
Ok(())
}
/// Check if a validator still needs to set embedded elliptic curve keys.
fn still_needs_to_set_embedded_elliptic_curve_keys(
network: NetworkId,
validator: Public,
) -> bool {
match network {
// Validators never need to set embedded elliptic curve keys for Serai
NetworkId::Serai => return false,
NetworkId::External(network) => {
!S::EmbeddedEllipticCurveKeys::contains_key(network, validator)
}
}
}
}

View File

@@ -4,6 +4,9 @@
extern crate alloc;
mod embedded_elliptic_curve_keys;
use embedded_elliptic_curve_keys::*;
mod allocations;
use allocations::*;
@@ -78,12 +81,7 @@ mod pallet {
use frame_support::pallet_prelude::*;
use serai_primitives::{
crypto::KeyPair,
network_id::*,
coin::*,
balance::*,
validator_sets::*,
address::SeraiAddress,
crypto::KeyPair, network_id::*, coin::*, balance::*, validator_sets::*, address::SeraiAddress,
};
use coins_pallet::Pallet as Coins;
@@ -91,8 +89,7 @@ mod pallet {
use super::*;
#[pallet::config]
#[pallet::disable_frame_system_supertrait_check]
pub trait Config: coins_pallet::Config {
pub trait Config: frame_system::Config + coins_pallet::Config {
type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;
// type ShouldEndSession: ShouldEndSession<BlockNumberFor<Self>>;
@@ -157,19 +154,24 @@ mod pallet {
}
*/
/// A key on an embedded elliptic curve.
struct Abstractions<T: Config>(PhantomData<T>);
// Satisfy the `EmbeddedEllipticCurveKeys` abstraction
#[pallet::storage]
pub type EmbeddedEllipticCurveKeys<T: Config> = StorageDoubleMap<
type EmbeddedEllipticCurveKeys<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
Public,
Identity,
ExternalNetworkId,
Blake2_128Concat,
Public,
serai_primitives::crypto::EmbeddedEllipticCurveKeys,
OptionQuery,
>;
struct Abstractions<T: Config>(PhantomData<T>);
impl<T: Config> EmbeddedEllipticCurveKeysStorage for Abstractions<T> {
type EmbeddedEllipticCurveKeys = EmbeddedEllipticCurveKeys<T>;
}
// Satisfy the `Allocations` abstraction
@@ -186,7 +188,7 @@ mod pallet {
type SortedAllocations = SortedAllocations<T>;
}
// Satisfy the `Sessions` API
// Satisfy the `Sessions` abstraction
// We use `Identity` as the hasher for `NetworkId` due to how constrained it is
#[pallet::storage]
@@ -809,12 +811,12 @@ mod pallet {
#[pallet::weight(0)] // TODO
pub fn set_embedded_elliptic_curve_keys(
origin: OriginFor<T>,
network: ExternalNetworkId,
keys: serai_primitives::crypto::EmbeddedEllipticCurveKeys,
keys: serai_primitives::crypto::SignedEmbeddedEllipticCurveKeys,
) -> DispatchResult {
let signer = ensure_signed(origin)?;
// TODO: Add PoKs and check validity
EmbeddedEllipticCurveKeys::<T>::set(signer, network, Some(keys));
<Abstractions<T> as crate::EmbeddedEllipticCurveKeys>::set_embedded_elliptic_curve_keys(
signer, keys,
)?;
Ok(())
}
@@ -824,10 +826,12 @@ mod pallet {
let validator = ensure_signed(origin)?;
// If this network utilizes embedded elliptic curve(s), require the validator to have set the
// appropriate key(s)
if let Ok(network) = ExternalNetworkId::try_from(network) {
if !EmbeddedEllipticCurveKeys::<T>::contains_key(validator, network) {
Err(Error::<T>::MissingEmbeddedEllipticCurveKey)?;
}
if <
Abstractions::<T>
as
crate::EmbeddedEllipticCurveKeys
>::still_needs_to_set_embedded_elliptic_curve_keys(network, validator) {
Err(Error::<T>::MissingEmbeddedEllipticCurveKey)?;
}
Coins::<T>::transfer_internal(
validator,

View File

@@ -44,7 +44,8 @@ pub(crate) trait SessionsStorage: AllocationsStorage {
///
/// This is opaque and to be exclusively read/write by `Sessions`.
// The value is how many key shares the validator has.
type SelectedValidators: StorageMap<SelectedValidatorsKey, u64> + StoragePrefixedMap<u64>;
type SelectedValidators: StorageMap<SelectedValidatorsKey, u64, Query = Option<u64>>
+ StoragePrefixedMap<u64>;
/// The total allocated stake for a network.
///