use frame_support::{
ensure,
storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},
traits::Get,
};
use frame_system::pallet_prelude::BlockNumberFor;
use kilt_support::Deposit;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen, WrapperTypeEncode};
use scale_info::TypeInfo;
use sp_core::{ecdsa, ed25519, sr25519};
use sp_runtime::{
traits::{IdentifyAccount, Verify, Zero},
MultiSignature, RuntimeDebug, SaturatedConversion, Saturating,
};
use sp_std::{convert::TryInto, vec::Vec};
use crate::{
errors::{self, DidError},
utils, AccountIdOf, BalanceOf, Config, DidAuthorizedCallOperationOf, DidCreationDetailsOf, KeyIdOf, Payload,
};
#[derive(Clone, Copy, Decode, RuntimeDebug, Encode, Eq, Ord, PartialEq, PartialOrd, TypeInfo, MaxEncodedLen)]
pub enum DidVerificationKey<AccountId> {
Ed25519(ed25519::Public),
Sr25519(sr25519::Public),
Ecdsa(ecdsa::Public),
Account(AccountId),
}
impl<AccountId> DidVerificationKey<AccountId> {
pub fn verify_signature(&self, payload: &Payload, signature: &DidSignature) -> Result<(), errors::SignatureError> {
match (self, signature) {
(DidVerificationKey::Ed25519(public_key), DidSignature::Ed25519(sig)) => {
ensure!(sig.verify(payload, public_key), errors::SignatureError::InvalidData);
Ok(())
}
(DidVerificationKey::Sr25519(public_key), DidSignature::Sr25519(sig)) => {
ensure!(sig.verify(payload, public_key), errors::SignatureError::InvalidData);
Ok(())
}
(DidVerificationKey::Ecdsa(public_key), DidSignature::Ecdsa(sig)) => {
ensure!(sig.verify(payload, public_key), errors::SignatureError::InvalidData);
Ok(())
}
_ => Err(errors::SignatureError::InvalidFormat),
}
}
}
impl<AccountId> IdentifyAccount for DidVerificationKey<AccountId>
where
AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
{
type AccountId = AccountId;
fn into_account(self) -> Self::AccountId {
let bytes = match self {
DidVerificationKey::Ed25519(pub_key) => pub_key.0,
DidVerificationKey::Sr25519(pub_key) => pub_key.0,
DidVerificationKey::Ecdsa(pub_key) => sp_io::hashing::blake2_256(pub_key.as_ref()),
DidVerificationKey::Account(acc_id) => *acc_id.as_ref(),
};
bytes.into()
}
}
impl<AccountId> From<ed25519::Public> for DidVerificationKey<AccountId> {
fn from(key: ed25519::Public) -> Self {
DidVerificationKey::Ed25519(key)
}
}
impl<AccountId> From<sr25519::Public> for DidVerificationKey<AccountId> {
fn from(key: sr25519::Public) -> Self {
DidVerificationKey::Sr25519(key)
}
}
impl<AccountId> From<ecdsa::Public> for DidVerificationKey<AccountId> {
fn from(key: ecdsa::Public) -> Self {
DidVerificationKey::Ecdsa(key)
}
}
#[derive(Clone, Copy, Decode, RuntimeDebug, Encode, Eq, Ord, PartialEq, PartialOrd, TypeInfo, MaxEncodedLen)]
pub enum DidEncryptionKey {
X25519([u8; 32]),
}
#[derive(Clone, Copy, Decode, RuntimeDebug, Encode, Eq, Ord, PartialEq, PartialOrd, TypeInfo, MaxEncodedLen)]
pub enum DidPublicKey<AccountId> {
PublicVerificationKey(DidVerificationKey<AccountId>),
PublicEncryptionKey(DidEncryptionKey),
}
impl<AccountId> From<DidVerificationKey<AccountId>> for DidPublicKey<AccountId> {
fn from(verification_key: DidVerificationKey<AccountId>) -> Self {
Self::PublicVerificationKey(verification_key)
}
}
impl<AccountId> From<DidEncryptionKey> for DidPublicKey<AccountId> {
fn from(encryption_key: DidEncryptionKey) -> Self {
Self::PublicEncryptionKey(encryption_key)
}
}
#[derive(Clone, Copy, RuntimeDebug, Decode, Encode, PartialEq, Eq, TypeInfo, MaxEncodedLen, PartialOrd, Ord)]
pub enum DidVerificationKeyRelationship {
Authentication,
CapabilityDelegation,
CapabilityInvocation,
AssertionMethod,
}
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)]
pub enum DidSignature {
Ed25519(ed25519::Signature),
Sr25519(sr25519::Signature),
Ecdsa(ecdsa::Signature),
}
impl From<ed25519::Signature> for DidSignature {
fn from(sig: ed25519::Signature) -> Self {
DidSignature::Ed25519(sig)
}
}
impl From<sr25519::Signature> for DidSignature {
fn from(sig: sr25519::Signature) -> Self {
DidSignature::Sr25519(sig)
}
}
impl From<ecdsa::Signature> for DidSignature {
fn from(sig: ecdsa::Signature) -> Self {
DidSignature::Ecdsa(sig)
}
}
impl From<MultiSignature> for DidSignature {
fn from(sig: MultiSignature) -> Self {
match sig {
MultiSignature::Ed25519(sig) => Self::Ed25519(sig),
MultiSignature::Sr25519(sig) => Self::Sr25519(sig),
MultiSignature::Ecdsa(sig) => Self::Ecdsa(sig),
}
}
}
pub trait DidVerifiableIdentifier<AccountId> {
fn verify_and_recover_signature(
&self,
payload: &Payload,
signature: &DidSignature,
) -> Result<DidVerificationKey<AccountId>, errors::SignatureError>;
}
impl<I: AsRef<[u8; 32]>, AccountId> DidVerifiableIdentifier<AccountId> for I {
fn verify_and_recover_signature(
&self,
payload: &Payload,
signature: &DidSignature,
) -> Result<DidVerificationKey<AccountId>, errors::SignatureError> {
let raw_public_key: &[u8; 32] = self.as_ref();
match *signature {
DidSignature::Ed25519(_) => {
let ed25519_did_key = DidVerificationKey::Ed25519(ed25519::Public::from_raw(*raw_public_key));
ed25519_did_key
.verify_signature(payload, signature)
.map(|_| ed25519_did_key)
}
DidSignature::Sr25519(_) => {
let sr25519_did_key = DidVerificationKey::Sr25519(sr25519::Public::from_raw(*raw_public_key));
sr25519_did_key
.verify_signature(payload, signature)
.map(|_| sr25519_did_key)
}
DidSignature::Ecdsa(ref signature) => {
let ecdsa_signature: [u8; 65] = signature
.encode()
.try_into()
.map_err(|_| errors::SignatureError::InvalidData)?;
let hashed_message = sp_io::hashing::blake2_256(payload);
let recovered_pk: [u8; 33] =
sp_io::crypto::secp256k1_ecdsa_recover_compressed(&ecdsa_signature, &hashed_message)
.map_err(|_| errors::SignatureError::InvalidData)?;
let hashed_recovered_pk = sp_io::hashing::blake2_256(&recovered_pk);
ensure!(
&hashed_recovered_pk == raw_public_key,
errors::SignatureError::InvalidData
);
Ok(DidVerificationKey::from(ecdsa::Public(recovered_pk)))
}
}
}
}
#[derive(Clone, Copy, RuntimeDebug, Decode, Encode, PartialEq, Ord, PartialOrd, Eq, TypeInfo, MaxEncodedLen)]
pub struct DidPublicKeyDetails<BlockNumber, AccountId> {
pub key: DidPublicKey<AccountId>,
pub block_number: BlockNumber,
}
#[derive(Clone, Decode, Encode, PartialEq, TypeInfo, MaxEncodedLen, Debug)]
#[scale_info(skip_type_params(T))]
#[codec(mel_bound())]
pub struct DidDetails<T: Config> {
pub authentication_key: KeyIdOf<T>,
pub key_agreement_keys: DidKeyAgreementKeySetOf<T>,
pub delegation_key: Option<KeyIdOf<T>>,
pub attestation_key: Option<KeyIdOf<T>>,
pub public_keys: DidPublicKeyMapOf<T>,
pub last_tx_counter: u64,
pub deposit: Deposit<AccountIdOf<T>, BalanceOf<T>>,
}
impl<T: Config> DidDetails<T> {
pub fn new(
authentication_key: DidVerificationKey<AccountIdOf<T>>,
block_number: BlockNumberFor<T>,
deposit_owner: AccountIdOf<T>,
) -> Result<Self, errors::StorageError> {
let mut public_keys = DidPublicKeyMapOf::<T>::default();
let authentication_key_id = utils::calculate_key_id::<T>(&authentication_key.clone().into());
public_keys
.try_insert(
authentication_key_id,
DidPublicKeyDetails {
key: authentication_key.into(),
block_number,
},
)
.map_err(|_| errors::StorageError::MaxPublicKeysExceeded)?;
let deposit = Deposit {
owner: deposit_owner,
amount: Zero::zero(),
};
let mut new_did_details = Self {
authentication_key: authentication_key_id,
key_agreement_keys: DidKeyAgreementKeySetOf::<T>::default(),
attestation_key: None,
delegation_key: None,
public_keys,
last_tx_counter: 0u64,
deposit,
};
let deposit_amount = new_did_details.calculate_deposit(0);
new_did_details.deposit.amount = deposit_amount;
Ok(new_did_details)
}
pub fn calculate_deposit(&self, endpoint_count: u32) -> BalanceOf<T> {
let mut deposit: BalanceOf<T> = T::BaseDeposit::get();
let endpoint_count: BalanceOf<T> = endpoint_count.into();
deposit = deposit.saturating_add(endpoint_count.saturating_mul(T::ServiceEndpointDeposit::get()));
let key_agreement_count: BalanceOf<T> = self.key_agreement_keys.len().saturated_into();
deposit = deposit.saturating_add(key_agreement_count.saturating_mul(T::KeyDeposit::get()));
deposit = deposit.saturating_add(match self.attestation_key {
Some(_) => T::KeyDeposit::get(),
_ => Zero::zero(),
});
deposit = deposit.saturating_add(match self.delegation_key {
Some(_) => T::KeyDeposit::get(),
_ => Zero::zero(),
});
deposit
}
pub fn new_with_creation_details(
details: DidCreationDetailsOf<T>,
new_auth_key: DidVerificationKey<AccountIdOf<T>>,
) -> Result<Self, DidError> {
ensure!(
details.new_key_agreement_keys.len()
<= <<T as Config>::MaxNewKeyAgreementKeys>::get().saturated_into::<usize>(),
errors::InputError::MaxKeyAgreementKeysLimitExceeded
);
let current_block_number = frame_system::Pallet::<T>::block_number();
let mut new_did_details = DidDetails::new(new_auth_key, current_block_number, details.clone().submitter)?;
new_did_details.add_key_agreement_keys(details.clone().new_key_agreement_keys, current_block_number)?;
if let Some(attestation_key) = details.clone().new_attestation_key {
new_did_details.update_attestation_key(attestation_key, current_block_number)?;
}
if let Some(delegation_key) = details.new_delegation_key {
new_did_details.update_delegation_key(delegation_key, current_block_number)?;
}
let deposit_amount = new_did_details.calculate_deposit(0);
new_did_details.deposit.amount = deposit_amount;
Ok(new_did_details)
}
pub fn update_authentication_key(
&mut self,
new_authentication_key: DidVerificationKey<AccountIdOf<T>>,
block_number: BlockNumberFor<T>,
) -> Result<(), errors::StorageError> {
let old_authentication_key_id = self.authentication_key;
let new_authentication_key_id = utils::calculate_key_id::<T>(&new_authentication_key.clone().into());
self.authentication_key = new_authentication_key_id;
self.remove_key_if_unused(old_authentication_key_id);
self.public_keys
.try_insert(
new_authentication_key_id,
DidPublicKeyDetails {
key: new_authentication_key.into(),
block_number,
},
)
.map_err(|_| errors::StorageError::MaxPublicKeysExceeded)?;
Ok(())
}
pub fn add_key_agreement_keys(
&mut self,
new_key_agreement_keys: DidNewKeyAgreementKeySet<T::MaxNewKeyAgreementKeys>,
block_number: BlockNumberFor<T>,
) -> Result<(), errors::StorageError> {
for new_key_agreement_key in new_key_agreement_keys {
self.add_key_agreement_key(new_key_agreement_key, block_number)?;
}
Ok(())
}
pub fn add_key_agreement_key(
&mut self,
new_key_agreement_key: DidEncryptionKey,
block_number: BlockNumberFor<T>,
) -> Result<(), errors::StorageError> {
let new_key_agreement_id = utils::calculate_key_id::<T>(&new_key_agreement_key.into());
self.public_keys
.try_insert(
new_key_agreement_id,
DidPublicKeyDetails {
key: new_key_agreement_key.into(),
block_number,
},
)
.map_err(|_| errors::StorageError::MaxPublicKeysExceeded)?;
self.key_agreement_keys
.try_insert(new_key_agreement_id)
.map_err(|_| errors::StorageError::MaxTotalKeyAgreementKeysExceeded)?;
Ok(())
}
pub fn remove_key_agreement_key(&mut self, key_id: KeyIdOf<T>) -> Result<(), errors::StorageError> {
ensure!(
self.key_agreement_keys.remove(&key_id),
errors::StorageError::NotFound(errors::NotFoundKind::Key(errors::KeyType::KeyAgreement))
);
self.remove_key_if_unused(key_id);
Ok(())
}
pub fn update_attestation_key(
&mut self,
new_attestation_key: DidVerificationKey<AccountIdOf<T>>,
block_number: BlockNumberFor<T>,
) -> Result<(), errors::StorageError> {
let new_attestation_key_id = utils::calculate_key_id::<T>(&new_attestation_key.clone().into());
if let Some(old_attestation_key_id) = self.attestation_key.take() {
self.remove_key_if_unused(old_attestation_key_id);
}
self.attestation_key = Some(new_attestation_key_id);
self.public_keys
.try_insert(
new_attestation_key_id,
DidPublicKeyDetails {
key: new_attestation_key.into(),
block_number,
},
)
.map_err(|_| errors::StorageError::MaxPublicKeysExceeded)?;
Ok(())
}
pub fn remove_attestation_key(&mut self) -> Result<(), errors::StorageError> {
let old_key_id =
self.attestation_key
.take()
.ok_or(errors::StorageError::NotFound(errors::NotFoundKind::Key(
errors::KeyType::AssertionMethod,
)))?;
self.remove_key_if_unused(old_key_id);
Ok(())
}
pub fn update_delegation_key(
&mut self,
new_delegation_key: DidVerificationKey<AccountIdOf<T>>,
block_number: BlockNumberFor<T>,
) -> Result<(), errors::StorageError> {
let new_delegation_key_id = utils::calculate_key_id::<T>(&new_delegation_key.clone().into());
if let Some(old_delegation_key_id) = self.delegation_key.take() {
self.remove_key_if_unused(old_delegation_key_id);
}
self.delegation_key = Some(new_delegation_key_id);
self.public_keys
.try_insert(
new_delegation_key_id,
DidPublicKeyDetails {
key: new_delegation_key.into(),
block_number,
},
)
.map_err(|_| errors::StorageError::MaxPublicKeysExceeded)?;
Ok(())
}
pub fn remove_delegation_key(&mut self) -> Result<(), errors::StorageError> {
let old_key_id =
self.delegation_key
.take()
.ok_or(errors::StorageError::NotFound(errors::NotFoundKind::Key(
errors::KeyType::AssertionMethod,
)))?;
self.remove_key_if_unused(old_key_id);
Ok(())
}
pub fn remove_key_if_unused(&mut self, key_id: KeyIdOf<T>) {
if self.authentication_key != key_id
&& self.attestation_key != Some(key_id)
&& self.delegation_key != Some(key_id)
&& !self.key_agreement_keys.contains(&key_id)
{
self.public_keys.remove(&key_id);
}
}
pub fn get_verification_key_for_key_type(
&self,
key_type: DidVerificationKeyRelationship,
) -> Option<&DidVerificationKey<AccountIdOf<T>>> {
let key_id = match key_type {
DidVerificationKeyRelationship::AssertionMethod => self.attestation_key,
DidVerificationKeyRelationship::Authentication => Some(self.authentication_key),
DidVerificationKeyRelationship::CapabilityDelegation => self.delegation_key,
_ => None,
}?;
let key_details = self.public_keys.get(&key_id)?;
if let DidPublicKey::PublicVerificationKey(key) = &key_details.key {
Some(key)
} else {
None
}
}
pub fn increase_tx_counter(&mut self) -> u64 {
self.last_tx_counter = self.last_tx_counter.wrapping_add(1);
self.last_tx_counter
}
}
pub(crate) type DidNewKeyAgreementKeySet<MaxNewKeyAgreementKeys> =
BoundedBTreeSet<DidEncryptionKey, MaxNewKeyAgreementKeys>;
pub(crate) type DidKeyAgreementKeySetOf<T> = BoundedBTreeSet<KeyIdOf<T>, <T as Config>::MaxTotalKeyAgreementKeys>;
pub(crate) type DidPublicKeyMapOf<T> = BoundedBTreeMap<
KeyIdOf<T>,
DidPublicKeyDetails<BlockNumberFor<T>, AccountIdOf<T>>,
<T as Config>::MaxPublicKeysPerDid,
>;
#[derive(Clone, RuntimeDebug, Decode, Encode, PartialEq, TypeInfo)]
pub struct DidCreationDetails<DidIdentifier, AccountId, MaxNewKeyAgreementKeys, DidEndpoint>
where
MaxNewKeyAgreementKeys: Get<u32> + Clone,
{
pub did: DidIdentifier,
pub submitter: AccountId,
pub new_key_agreement_keys: DidNewKeyAgreementKeySet<MaxNewKeyAgreementKeys>,
pub new_attestation_key: Option<DidVerificationKey<AccountId>>,
pub new_delegation_key: Option<DidVerificationKey<AccountId>>,
pub new_service_details: Vec<DidEndpoint>,
}
#[derive(Clone, RuntimeDebug, Decode, Encode, Eq, PartialEq)]
pub enum RelationshipDeriveError {
NotCallableByDid,
InvalidCallParameter,
}
pub type DeriveDidCallKeyRelationshipResult = Result<DidVerificationKeyRelationship, RelationshipDeriveError>;
pub trait DeriveDidCallAuthorizationVerificationKeyRelationship {
fn derive_verification_key_relationship(&self) -> DeriveDidCallKeyRelationshipResult;
#[cfg(feature = "runtime-benchmarks")]
fn get_call_for_did_call_benchmark() -> Self;
}
#[derive(Clone, RuntimeDebug, Decode, Encode, PartialEq, TypeInfo)]
pub struct DidAuthorizedCallOperation<DidIdentifier, DidCallable, BlockNumber, AccountId, TxCounter> {
pub did: DidIdentifier,
pub tx_counter: TxCounter,
pub call: DidCallable,
pub block_number: BlockNumber,
pub submitter: AccountId,
}
#[derive(Clone, RuntimeDebug, PartialEq, TypeInfo)]
pub struct DidAuthorizedCallOperationWithVerificationRelationship<T: Config> {
pub operation: DidAuthorizedCallOperationOf<T>,
pub verification_key_relationship: DidVerificationKeyRelationship,
}
impl<T: Config> core::ops::Deref for DidAuthorizedCallOperationWithVerificationRelationship<T> {
type Target = DidAuthorizedCallOperationOf<T>;
fn deref(&self) -> &Self::Target {
&self.operation
}
}
impl<T: Config> WrapperTypeEncode for DidAuthorizedCallOperationWithVerificationRelationship<T> {}